RSP2 Scanning Application for Pi2

Add useful snippets of code or links to entire SDR projects.
StevenP
Posts: 3
Joined: Tue Jan 16, 2018 4:26 pm

RSP2 Scanning Application for Pi2

Postby StevenP » Fri Jan 19, 2018 10:50 pm

I've been developing a C++ program that scans and stores frequency and power information. Eventually it is going to be put on a drone for RF surveillance. In my code, which is admittedly very much in the alpha stage, I'm running into a USB Buffer Overflow Error when executing it on the Pi. Could you point me in the direction of a possible solution?

Code: Select all

#include <unistd.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sstream>
#include <iostream>
#include <fstream>
#include <sstream>
#include <fftw3.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <sqlite3.h>
#include "mirsdrapi-rsp.h"

static int do_exit = 0;


sem_t s;                   // Semaphore 1
void *cbContext = NULL;         // SDR Callback context variable initially set to null
short *i_buffer;            // Pointers to where i data will be stored
short *q_buffer;            // Pointers to where q data will be stored
unsigned int _firstSample;      // index of first sample in packet buffer received from SDR
int _samplesPerPacket;         // samples per packet from SDR based on samplerate
int _grChanged;             // gain reduction setting from callback function
int _fsChanged;             // sample frequency setting from callback function
int _rfChanged;               // center frequency setting from callback function
int _firstcallback = 1;         // variable for tracking initial callback function


std::vector<double> _spectrum;                        // power spectrum vector
std::vector<double> _freq_index;                     // frequency index vector
std::string database = "/home/pi/raven/Velociraptor.db";     // database path variable for sqlite

void callback(short *xi, short *xq, unsigned int firstSampleNum, int grChanged, int rfChanged,
           int fsChanged, unsigned int numSamples, unsigned int reset, void *cbContext)
{

   // Set global variables to data received in callback function
   _firstSample = firstSampleNum;
   _samplesPerPacket = numSamples;
   _grChanged = grChanged;
   _rfChanged = rfChanged;
   _fsChanged = fsChanged;

   
   // allocate appropriate amount of memory for IQ buffer if first callback
   if(_firstcallback == 1)
   {
      i_buffer = (short*)malloc(numSamples * sizeof(short));
      q_buffer = (short*)malloc(numSamples * sizeof(short));
      _firstcallback = 0;

   }

   // Write iq data to buffer
   for (int i = 0; i < numSamples; i++)
   {
      i_buffer[i] = xi[i];
      q_buffer[i] = xq[i];
   }

   // signal sempahore 1
   sem_post(&s);

   return;
}

static int callbackDB(void *NotUsed, int argc, char **argv, char **azColName)
{
   int i;
   for(i = 0; i<argc; i++)
   {
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

void callbackGC(unsigned int grdB, unsigned int lnaGRdB, void *cbContext)
{
   // do something with updated gain information
   // NOT USED CURRENTLY
   return;
}

void FFT(short *ij, short *qj)
{
   // FFTW Variable Initialization
   const int N = _samplesPerPacket;            // Number of bins in data being passed to FFT, int type
   const double NFFT = (double)_samplesPerPacket;   // Number of bins in data being passed to FFT, double type
   const double fs = 2.048;                  // sample rate, hardcoded
   double rI[N] = {0};                        // raw I data storage
   double rQ[N] = {0};                        // raw Q data storage
   double fft_out[N] = {0};                  // Array of doubles to store output of FFT
   double p, q, x, z;                         // Variables used in math below
   fftw_complex *in, *out;                   // FFTW input/output and spectrum variables
   fftw_plan plan;                         // FFTW plan variable


   in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);         // Allocate memory for FFTW input based on size of input
   out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);      // Allocate memory for FFTW output based on size of input
   plan = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);   // Set FFTW plan parameters


   // First, convert values in xi and xq to double, and store in rI and rQ.
   for (int i = 0; i < _samplesPerPacket; i++)
    {

        rI[i] = (double)ij[i];
        rQ[i] = (double)qj[i];

   }

   // Second, divide all values which are now doubles by 2^12 (Since SDR Play has a 12 bit ADC). Store new values in FFTW input array
   for(int e = 0; e < N; ++e)
   {
      in[e][0] = rI[e]/4096; // 2^12
      in[e][1] = rQ[e]/4096; // 2^12
   }


   // Third, execute the FFT
   fftw_execute(plan);

   // Fourth, perform necessary math to get power information in dBm
   for(int e = 0; e < N; ++e)
   {
      // Divide every value by size of FFT (NFFT)
      p = out[e][0];
      p = p / NFFT;
      q = out[e][1];
      q = q / NFFT;

      // Combine 2D output into 1D by squaring and adding matching elements
      x = p*p + q*q;

      // Multiply by 2, and divide by the resistance
      x = x * 2 / 50;       // 50 ohm resistance
      x = x / .001;          // 10 ^ -3

      z = 10 * log10(x);

      // Adjust for LNA Gain Reduction of 48
      fft_out[e] = z - 48;
   }

   // Finally, add power values to the spectrum in order
   for (int i = 0; i < _samplesPerPacket; i++)
    {

      _spectrum.push_back (fft_out[i]);         

   }
   

   fftw_destroy_plan(plan);    // Must be done everytime to prevent artifacting

   return;

}

int main(int argc, char **argv){

   int vel_id = 29;      // Velociraptor ID number
   int sps;            // Packet size variable used in ReInit API function
   int done = 0;         // Flag for completion of scan
   int syncUpdate = 0;    // Initially use asynchronus updates
   int newGr = 0;         // Gain Reduction Initialization (0 dBm)
   int sysGr = 0;         // Gain Reduction Initialization (0 dBm)
   int debug_mode = 0;      // Debug mode (0=off, 1=on)
   float ver;            // Version of API, returned in ApiVersion API function
   double min_rf = 0;      // Lower bound of scan (MHz)
   double max_rf = 0;      // Upper Bound of scan (MHz)
   double threshold = 0;   // Power threshold for what is sent to database after scan is complete (dBm)
   double fs_in = 8.192;   // Sample frequency before downconverting (MHz)
   double fs_out = 2.048;   // Sample frequency after downconverting (MHz)
   double rf;            // Center frequency
   double lat = 0;         // Latitude
   double lon = 0;         // Longitude

   mir_sdr_ErrT err;                                 // Error message storage
   mir_sdr_Bw_MHzT bwType = mir_sdr_BW_1_536;               // Set IF Bandwidth to 1.536 MHz
   mir_sdr_If_kHzT ifType = mir_sdr_IF_2_048;               // Set IF Frequency to 2.048 MHz
   mir_sdr_SetGrModeT grMode = mir_sdr_USE_SET_GR;            // Set Gain Reduction mode to manual
   mir_sdr_ReasonForReinitT rfChange = mir_sdr_CHANGE_RF_FREQ;   // Reason for performing Reinitialization of the SDRPlay
   mir_sdr_LoModeT loMode = mir_sdr_LO_Undefined;            // LO mode not used

   sqlite3 *db;      // SQLite database pointer
   char *zErrMsg = 0;   // SQLite error message pointer
   int rc;            // SQLite return status
   std::ostringstream temp;
   std::string sql;

   // If scan settings are given, use them, otherwise use default settings.
   if (argc<5) {
      min_rf = 30;       // scan lower bound (MHz)
      max_rf = 512;       // scan upper bound (MHz)
      threshold = -70;   // no threshold
      debug_mode = 0;      // debug off

   }
   else {
      min_rf = atof(argv[1]);    // scan lower bound (MHz)
      max_rf = atof(argv[2]);    // scan upper bound (MHz)
      threshold = atof(argv[3]);   // threshold (dBm)
      debug_mode = atoi(argv[4]); // debug mode (1=on, 0=off)
   }

   double freq_resolution;         // initialize frequency resolution variable
   double freq = min_rf;         // start frequency index at lower bound

   // create semaphore
   sem_init(&s, 0, 0);

   // Check API version
   err = mir_sdr_ApiVersion(&ver);
   if (ver != MIR_SDR_API_VERSION)
   {
      fprintf(stderr, "API VERSION DOES NOT MATCH: Error %d\n", err);
      exit(1);
   }

   // enable debug output
   if (debug_mode == 1)
   {
      mir_sdr_DebugEnable(1);
   }
   

   // Determine initial frequency to tune to [Add fs/2 to the lower bound to get first center frequency]
   rf = min_rf + fs_out/2;

   // Initialize API and hardware
   err = mir_sdr_StreamInit(&newGr, fs_in, rf, bwType, ifType, 0, &sysGr, grMode, &sps, callback, callbackGC, (void *)NULL);
   if (err != mir_sdr_Success)
   {
      fprintf(stderr, "mir_sdr_StreamInit: Error %d\n", err);
      exit(1);
   }


   // TODO: Query GPS for location

   // Configure DC Tracking in tuner, this will perform DC offset correction when configured correctly
   err = mir_sdr_SetDcMode(4, 1);       // 4 = One shot DC offset correction
                              // 1 = Maximum speedup
   if (err != mir_sdr_Success)
   {
      fprintf(stderr, "mir_sdr_SetDCMode: Error %d\n", err);
      exit(1);
   }
   err = mir_sdr_SetDcTrackTime(63);    // 63 = Tracking time in ms (0-63)
   if (err != mir_sdr_Success)
   {
      fprintf(stderr, "mir_sdr_SetDcTrackTime: Error %d\n", err);
      exit(1);
   }

   // Main Processing Loop
   while(!done)
   {
      
      sem_wait(&s);            // wait on semaphore for samples to be received in callback
      FFT(i_buffer, q_buffer);   // get data from buffer, pass it through FFT
      rf = rf + fs_out;         // move center frequency for next IQ collection (increment by fs)

      // update SDR center frequency by performing ReInit
      err = mir_sdr_Reinit(&newGr, fs_in, rf, bwType, ifType, loMode, 1, &sysGr, grMode, &sps, rfChange);
      if (err != mir_sdr_Success)
      {
         fprintf(stderr, "mir_sdr_Reinit: Error %d\n", err);
         exit(1);
      }

      // signal sempahore 2
      sem_post(&z);

      // TODO: Query GPS for location

      // set update period in IQ buffer
      err = mir_sdr_SetSyncUpdatePeriod(_samplesPerPacket);
         if (err != mir_sdr_Success)
      {
         fprintf(stderr, "mir_sdr_SetSyncUpdatePeriod: Error %d\n", err);
         exit(1);
      }
      // set sample to start update period from in IQ buffer
      err = mir_sdr_SetSyncUpdateSampleNum(_firstSample);
      if (err != mir_sdr_Success)
      {
         fprintf(stderr, "mir_sdr_SetSyncUpdateSampleNum: Error %d\n", err);
         exit(1);
      }
 
      syncUpdate = 1;    // set syncupdate mode to synchronous
      
      // when current frequency exceeds max frequency, scan is complete
      if(rf > max_rf)
      {
         fprintf(stderr, "Scan Complete!\n");
         done = 1;   
      }
      
   }

   freq_resolution = fs_out / _samplesPerPacket;   // set freq resolution based on settings [fs/N]

   for (int i = 0; i < (int)_spectrum.size(); i++)
   {
      freq = freq + freq_resolution;                  // create frequency indecies by incrementing freq with the freq resolution
      _freq_index.push_back (freq);                  // populate frequency index array in order
   }


   // TEMPORARY LOGIC TO WRITE OUTPUT DIRECTLY TO CSV, WILL BE REMOVED ONCE DATABASE WRITING IS SUCCESSFULLY IMPLEMENTED
   std::ofstream outfile;
   outfile.open("spectrum.csv");
   for (int i = 0; i < (int)_spectrum.size(); i++)
   {
      // Threshold determines what gets written to database
      if (_spectrum[i] > threshold)
      {
         outfile << _freq_index[i] << "," << _spectrum[i];
         outfile << std::endl;
      }
   }
   outfile.close();
   

   // Database Writing using sqlite3
   rc = sqlite3_open("Velociraptor.db", &db);
   if(rc)
   {
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      return(0);
   } else {
      fprintf(stderr, "Opened database successfully\n");
   }

   for (int i = 0; i < (int)_spectrum.size(); i++)
   {
      // Threshold determines what gets written to database
      if (_spectrum[i] > threshold)
      {
         temp.str("");
         temp << "INSERT INTO scan (id, freq, power, latitude, longitude) " << "VALUES(" << vel_id << ", " << _freq_index[i] << ", " << _spectrum[i] << ", " << lat << ", " << lon << " ); " ;
         sql = temp.str();
         rc = sqlite3_exec(db, sql.c_str(), callbackDB, 0, &zErrMsg);

         if(rc != SQLITE_OK)
         {
            fprintf(stderr, "SQL error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
         }
               
      }
   }

   // At exit
   free(i_buffer);            // release memory allocated to i buffer
   free(q_buffer);            // release memory allocated to q buffer
   fprintf(stderr, "Uninitializing SDR and closing database...\n");
   sqlite3_close(db);
   mir_sdr_StreamUninit();
   fprintf(stderr, "Done\n");
   return 0;

}
Last edited by StevenP on Thu Jan 01, 1970 12:00 am, edited 0 times in total.
Reason: No reason

Return to “Code Corner”

Who is online

Users browsing this forum: No registered users and 2 guests