├── src ├── signal_processing │ ├── cfar.h │ ├── correlator.h │ ├── cfar.cpp │ ├── correlator.cpp │ ├── fft.h │ ├── tuneFilter.h │ ├── fft.cpp │ └── tuneFilter.cpp ├── waveform │ ├── LFM.h │ └── LFM.cpp ├── util │ ├── plotting │ │ ├── plot.h │ │ ├── plot.cpp │ │ └── matplotlibcpp.h │ ├── radarDataTypes.h │ └── math │ │ ├── volk_math.h │ │ └── volk_math.cpp └── hardware │ └── hackrf │ ├── scheduler.h │ ├── driver │ ├── device_setup.h │ ├── hackrf.h │ └── hackrf.c │ ├── proc.h │ ├── scheduler.cpp │ └── proc.cpp ├── .gitignore ├── main_radar.cpp ├── filt_taps_0_3_to_0_33_80_dB_atten_0_1_dB_ripple ├── CMakeLists.txt └── profiling └── main_filter_timing.cpp /src/signal_processing/cfar.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/signal_processing/correlator.h: -------------------------------------------------------------------------------- 1 | //generic header file -------------------------------------------------------------------------------- /src/signal_processing/cfar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Constant false alarm rate (CFAR) detector 3 | * 4 | */ 5 | -------------------------------------------------------------------------------- /src/signal_processing/correlator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Simple FFT based correlator for matched filtering 4 | * 5 | */ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | #.pyc 10 | 11 | # Packages # 12 | ############ 13 | # it's better to unpack these files and commit the raw source 14 | # git has its own built in compression methods 15 | *.7z 16 | *.dmg 17 | *.gz 18 | *.iso 19 | *.jar 20 | *.rar 21 | *.tar 22 | *.zip 23 | 24 | # Logs and databases # 25 | ###################### 26 | *.log 27 | *.sql 28 | *.sqlite 29 | *.cmake 30 | # OS generated files # 31 | ###################### 32 | .DS_Store 33 | .DS_Store? 34 | ._* 35 | .Spotlight-V100 36 | .Trashes 37 | ehthumbs.db 38 | Thumbs.db 39 | *build 40 | *kdev4 41 | 42 | -------------------------------------------------------------------------------- /src/signal_processing/fft.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FFT object 3 | */ 4 | 5 | #ifndef __fft__ 6 | #define __fft__ 7 | 8 | #include 9 | #include //fft library 10 | 11 | #include "../util/radarDataTypes.h" 12 | 13 | class FFT{ 14 | public: 15 | FFT(int fftSize,int inputSize); 16 | ~FFT(); 17 | 18 | void resetFFTSize(int newSize,int inputSize); 19 | void getFFT(radar::complexFloat* input, radar::complexFloat* output); 20 | void getIFFT(radar::complexFloat* input, radar::complexFloat* output); 21 | void setWindow(); 22 | 23 | private: 24 | fftwf_complex* outputMem; 25 | fftwf_complex* tmp; 26 | radar::complexFloat* window; 27 | int fftSize; 28 | fftwf_plan forwardDFT; 29 | fftwf_plan inverseDFT; 30 | 31 | 32 | }; 33 | 34 | #endif -------------------------------------------------------------------------------- /src/waveform/LFM.h: -------------------------------------------------------------------------------- 1 | #ifndef __LFM__ 2 | #define __LFM__ 3 | /* 4 | *LFM chirp class 5 | */ 6 | #include 7 | #include 8 | 9 | #include "../util/radarDataTypes.h" 10 | 11 | using namespace radar; 12 | 13 | class LFM{ 14 | public: 15 | LFM(float sample_rate,int chirp_length,float band_width,float center_frequency); 16 | ~LFM(); 17 | void genWave(); 18 | complexFloatBuffPtr getFloatBuff(); 19 | charBuffPtr getCharBuff(); 20 | 21 | private: 22 | complexFloatBuffPtr waveBuff; 23 | charBuffPtr charWave; 24 | 25 | float d_sampRate; 26 | float d_numSamps; 27 | float d_bandWidth; 28 | float d_centerFreq; 29 | float d_time; 30 | 31 | float startFreq; 32 | float rate; 33 | float PI_PI = 6.283185307179586; 34 | 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/util/plotting/plot.h: -------------------------------------------------------------------------------- 1 | #ifndef __PLOT__ 2 | #define __PLOT__ 3 | 4 | #include 5 | 6 | #include "../radarDataTypes.h" 7 | 8 | //plotting library 9 | #include "matplotlibcpp.h" 10 | namespace util{ 11 | class plot{ 12 | public: 13 | plot(int buffLength); 14 | ~plot(); 15 | void init(); 16 | void plotComplex2d(float* xData,radar::complexFloat* yData); 17 | void plot2d(float* xData,float* yData); 18 | void plot3d(float* xData,float* yData,float* zData); 19 | void image(float* xData,float* yData,float* imageData); 20 | void clearFigure(); 21 | void makeVector(float* floatData, radar::complexFloat* complexData, int type); 22 | void clearVector(); 23 | private: 24 | std::mutex plotProtect; //may or may not need this.. 25 | std::vector> floatVec; 26 | std::vector> complexFloatVec; 27 | 28 | int buffLength; 29 | }; 30 | }; 31 | #endif -------------------------------------------------------------------------------- /src/signal_processing/tuneFilter.h: -------------------------------------------------------------------------------- 1 | //generic header file 2 | #include 3 | 4 | #include "fft.h" 5 | #include "../util/math/volk_math.h" 6 | #include "../util/radarDataTypes.h" 7 | 8 | class tuneFilter{ 9 | public: 10 | tuneFilter(std::vector &taps_, float frequencyOffset, float sampRate, int inputSize,int fftSize=0); 11 | ~tuneFilter(); 12 | void fftFilterTune(radar::complexFloat* fftInput, radar::complexFloat* filteredOutput); 13 | void fftFilterTune(radar::complexFloat* fftInput); 14 | 15 | void timeFilterTune(radar::complexFloat* iqInput, radar::complexFloat* filteredOutput); 16 | void timeFilterTune(radar::complexFloat* iqInput); 17 | private: 18 | float* taps; 19 | float frequencyOffset; 20 | radar::complexFloatBuffPtr expTable; 21 | radar::complexFloatBuffPtr fftTaps; 22 | radar::complexFloatBuffPtr swapBuff; 23 | 24 | 25 | math* mathHandle; 26 | 27 | int inputSize; 28 | int nShiftSamples; 29 | int shiftDir; 30 | int fftSize; 31 | float PI_PI = 6.283185307179586; 32 | 33 | }; -------------------------------------------------------------------------------- /src/util/radarDataTypes.h: -------------------------------------------------------------------------------- 1 | //typedefs 2 | 3 | #ifndef __radar_data__ 4 | #define __radar_data__ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | //IQ data types 11 | namespace radar{ 12 | typedef std::complex complexFloat; 13 | typedef uint8_t charBuff; 14 | 15 | typedef std::shared_ptr complexFloatBuffPtr; 16 | typedef std::shared_ptr charBuffPtr; 17 | }; 18 | 19 | 20 | //util datatypes 21 | namespace util{ 22 | typedef struct{ 23 | int buffSize; 24 | std::vector xlim; 25 | std::vector ylim; 26 | std::string xlabel; 27 | std::string ylabel; 28 | std::string zlabel; 29 | std::string title; 30 | std::string legend; 31 | std::string saveName; 32 | bool grid; 33 | }plotParams; 34 | } 35 | 36 | //hardware data types 37 | namespace hackrf{ 38 | typedef struct{ 39 | uint64_t centerFreq; 40 | uint32_t sampRate; 41 | uint32_t baseBandFiltBw; 42 | uint32_t rxVgaGain; 43 | uint32_t rxLnaGain; 44 | uint32_t txVgaGain; 45 | }device_params; 46 | }; 47 | #endif -------------------------------------------------------------------------------- /src/util/math/volk_math.h: -------------------------------------------------------------------------------- 1 | //util for wrapping calls to volk functions 2 | #ifndef __VOLK_MATH__ 3 | #define __VOLK_MATH__ 4 | 5 | #include "../radarDataTypes.h" 6 | 7 | class math{ 8 | public: 9 | math(int numSamps); 10 | ~math(); 11 | void normalize(radar::complexFloat* input,float normConst); 12 | void add(radar::complexFloat* input1,radar::complexFloat* input2); 13 | void magSqrd(radar::complexFloat* input,float* output); 14 | void add_const(radar::complexFloat* input,float addConst); 15 | void multiply(radar::complexFloat* input1,radar::complexFloat* input2, radar::complexFloat* output); 16 | void multiply(radar::complexFloat* input1,radar::complexFloat* input2, radar::complexFloat* output,int numSamps); 17 | void abs(radar::complexFloat* input,float* output); 18 | void filter(radar::complexFloat* input, radar::complexFloat* output); 19 | void initFilter(float* taps, int tapsSize); 20 | 21 | private: 22 | unsigned int alignment;//memory alignment for volk 23 | int buffSize; 24 | bool filterInit; 25 | 26 | float* internalFloatBuff; //for kernels that require a float input 27 | radar::complexFloat* internalComplexFloatBuff; 28 | radar::complexFloat* internalFilterHistory; 29 | radar::complexFloat* complexZeros; 30 | float* aligned_taps; 31 | int numTaps; 32 | }; 33 | #endif -------------------------------------------------------------------------------- /src/waveform/LFM.cpp: -------------------------------------------------------------------------------- 1 | #include "LFM.h" 2 | #include 3 | 4 | // #define PI_PI 6.283185307179586 //two pi 5 | 6 | /* 7 | * TODO 8 | * -add pri - pretty sure this is pulse repition index => number of pulses in the buffer 9 | * -add pulse width - obvious 10 | * -add duty cycle - also obvious 11 | * 12 | */ 13 | 14 | LFM::LFM(float sample_rate,int chirp_length,float band_width,float center_frequency):d_sampRate(sample_rate),d_numSamps(chirp_length),d_bandWidth(band_width),d_centerFreq(center_frequency) 15 | { 16 | d_time = (float)d_numSamps/d_sampRate; 17 | startFreq = d_centerFreq - d_bandWidth/2; 18 | rate = 10*d_time; 19 | 20 | waveBuff = std::shared_ptr(new complexFloat[(int)d_numSamps],std::default_delete()); 21 | charWave = std::shared_ptr(new charBuff[2*(int)d_numSamps],std::default_delete()); 22 | } 23 | 24 | LFM::~LFM(){} 25 | 26 | void LFM::genWave(){ 27 | for (int i = 0;ifftSize = fftSize; 21 | tmp = fftwf_alloc_complex(inputSize*sizeof(fftw_complex)); 22 | forwardDFT = fftwf_plan_dft_1d(fftSize,tmp,outputMem,FFTW_FORWARD,FFTW_ESTIMATE); 23 | inverseDFT = fftwf_plan_dft_1d(fftSize,tmp,outputMem,FFTW_BACKWARD,FFTW_ESTIMATE); 24 | 25 | //free tmp 26 | fftwf_free(tmp); 27 | }; 28 | 29 | void FFT::getFFT(radar::complexFloat* input, radar::complexFloat* output){ 30 | fftwf_complex* inputTMP = reinterpret_cast(input); 31 | fftwf_complex* outputTMP = reinterpret_cast(output); 32 | fftwf_execute_dft(forwardDFT,inputTMP,outputTMP); 33 | }; 34 | 35 | void FFT::getIFFT(radar::complexFloat* input, radar::complexFloat* output){ 36 | fftwf_complex* inputTMP = reinterpret_cast(input); 37 | fftwf_complex* outputTMP = reinterpret_cast(output); 38 | fftwf_execute_dft(inverseDFT,inputTMP,outputTMP); 39 | }; 40 | 41 | void FFT::setWindow(){ 42 | //TODO: add windowing to the FFT 43 | }; -------------------------------------------------------------------------------- /src/hardware/hackrf/scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef __HACKRF_SCHED_H__ 2 | #define __HACKRF_SCHED_H__ 3 | 4 | #include 5 | #include 6 | 7 | 8 | #include "driver/hackrf.h" 9 | #include "driver/device_setup.h" 10 | #include "proc.h" 11 | #include "../../waveform/LFM.h" //wow that is really annoying 12 | #include "../../util/radarDataTypes.h" 13 | 14 | //TODO: implement some kind of common time base, could use the system time but it seems bad... 15 | //could be worth it to write a wrapper that waits until its time to transmit/record simular to uhd::transmit/recv processes 16 | namespace hackrf{ 17 | class sched{ 18 | public: 19 | sched(const device_params* device_options); 20 | ~sched(); 21 | void init(); //init hardware 22 | void start(); //start threads 23 | void stop(); //stop threads 24 | 25 | private: 26 | //private methods 27 | void tx_callback_control(); //handle tx 28 | static int tx_callback(hackrf_transfer* transfer); 29 | void rx_callback_control(); //handle rx 30 | static int rx_callback(hackrf_transfer* transfer); 31 | void reopen_device(); 32 | void switch_rx_tx(); //switch the hardware to either transmit or receive 33 | 34 | 35 | //hackrf variables 36 | const device_params* frontEnd; 37 | hackrf_device* hackrf; //device pointer 38 | 39 | //buffers and things... 40 | static proc* pro; 41 | LFM* waveGen; 42 | static std::vector tx_wave; 43 | static radar::charBuff* rx_buff; 44 | std::atomic enabled,transmitting; //thread controls 45 | std::thread rx_thread,tx_thread,proc_thread; 46 | 47 | static std::atomic newBuff; 48 | }; 49 | } 50 | 51 | 52 | 53 | #endif -------------------------------------------------------------------------------- /src/hardware/hackrf/driver/device_setup.h: -------------------------------------------------------------------------------- 1 | #ifndef __HACKRF_DEVICE_SETUP__ 2 | #define __HACKRF_DEVICE_SETUP__ 3 | 4 | #include 5 | 6 | #include "hackrf.h" 7 | #include "../../../util/radarDataTypes.h" 8 | namespace hackrf{ 9 | inline int set_up_device(const device_params* frontEnd,hackrf_device* device){ 10 | //set sample rate 11 | int ret = hackrf_set_sample_rate_manual(device,frontEnd->sampRate,1); 12 | if (ret != HACKRF_SUCCESS){ 13 | std::cout << "Failed to set sample rate with error code: " << hackrf_error(ret) << std::endl; 14 | return -1; 15 | } 16 | // //set filter bandwidth 17 | // ret = hackrf_set_baseband_filter_bandwidth(device, frontEnd->baseBandFiltBw); 18 | // if (ret != HACKRF_SUCCESS){ 19 | // std::cout << "Failed to set filter bandwidth with error code: " << hackrf_error(ret) << std::endl; 20 | // return -1; 21 | // } 22 | 23 | //set center frequency 24 | ret = hackrf_set_freq(device, frontEnd->centerFreq); 25 | if (ret != HACKRF_SUCCESS){ 26 | std::cout << "Failed to set center frequency error code: " << hackrf_error(ret) << std::endl; 27 | return -1; 28 | } 29 | 30 | //set rx gains 31 | ret = hackrf_set_vga_gain(device, frontEnd->rxVgaGain); 32 | ret |= hackrf_set_lna_gain(device, frontEnd->rxLnaGain); 33 | if (ret != HACKRF_SUCCESS){ 34 | std::cout << "Failed to set front end gain with error code: " << hackrf_error(ret) << std::endl; 35 | return -1; 36 | } 37 | 38 | //set tx gain 39 | ret = hackrf_set_txvga_gain(device, frontEnd->txVgaGain); 40 | if (ret != HACKRF_SUCCESS){ 41 | std::cout << "Failed to set tx front end gain with error code: " << hackrf_error(ret) << std::endl; 42 | return -1; 43 | } 44 | 45 | return 0; 46 | }; 47 | }; 48 | 49 | #endif -------------------------------------------------------------------------------- /main_radar.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "src/hardware/hackrf/driver/device_setup.h" 7 | #include "src/waveform/LFM.h" 8 | #include "src/util/plotting/matplotlibcpp.h" 9 | #include "src/util/radarDataTypes.h" 10 | #include "src/hardware/hackrf/scheduler.h" 11 | 12 | namespace po = boost::program_options; 13 | namespace plt = matplotlibcpp; 14 | using namespace radar; 15 | int main(int argc, char **argv) { 16 | //variables to be set by po 17 | std::string args; 18 | double duration; 19 | uint32_t rate,filterBw,rxVgaGain,rxLnaGain,txVgaGain; 20 | uint64_t centerFreq; 21 | //setup the program options 22 | po::options_description desc("Allowed options"); 23 | desc.add_options() 24 | ("help", "help message") 25 | ("args", po::value(&args)->default_value(""), "single device address args") 26 | ("duration", po::value(&duration)->default_value(0.0001), "duration for the tx waveform in seconds") 27 | ("rate", po::value(&rate)->default_value(10000000), "sample rate (sps)") 28 | ("baseBandFilerBw", po::value(&filterBw)->default_value(rate/2), "baseband filter bandwidth (Hz)") 29 | ("rxVgaGain", po::value(&rxVgaGain)->default_value(8), "rx gain") 30 | ("rxLnaGain", po::value(&rxLnaGain)->default_value(8), "rx lna gain") 31 | ("txVgaGain", po::value(&txVgaGain)->default_value(32), "tx gain") 32 | ("centerFreq", po::value(¢erFreq)->default_value(94.3e6), "center frequency (Hz)") 33 | ; 34 | po::variables_map vm; 35 | po::store(po::parse_command_line(argc, argv, desc), vm); 36 | po::notify(vm); 37 | 38 | const hackrf::device_params frontEnd = hackrf::device_params{centerFreq, 39 | rate, 40 | filterBw, 41 | rxVgaGain, 42 | rxLnaGain, 43 | txVgaGain}; 44 | 45 | //start radar class 46 | hackrf::sched* radarSched = new hackrf::sched(&frontEnd); 47 | radarSched->init(); 48 | radarSched->start(); 49 | 50 | usleep(3000000); 51 | 52 | delete radarSched; 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/hardware/hackrf/proc.h: -------------------------------------------------------------------------------- 1 | #ifndef __HACKRF_PROC_H__ 2 | #define __HACKRF_PROC_H__ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../../signal_processing/correlator.h" 11 | #include "../../signal_processing/cfar.h" 12 | #include "../../signal_processing/fft.h" 13 | #include "driver/hackrf.h" 14 | #include "../../util/radarDataTypes.h" 15 | #include "../../util/plotting/plot.h" 16 | #include "../../signal_processing/tuneFilter.h" 17 | #include "../../util/math/volk_math.h" 18 | 19 | namespace hackrf{ 20 | class proc{ 21 | public: 22 | proc(std::string debugFile, std::string spectrogramBinFile, std::string timeDisMapBinFile); 23 | ~proc(); 24 | void init(int fftSize,int inputSize); //init processors...filters and the like 25 | void rx_monitor(radar::charBuff* rx_buff); //wait for samples to come from the hardware 26 | void stop(); 27 | 28 | private: 29 | void signal_int(); //handle possible iq imbalance, frequency tuning, image rejection, and signal detection 30 | void corr_proc(); //correlate the samples against a matched filter and look for peaks 31 | void time_freq_map(); //spectrogram 32 | void time_dis_map(); //when and where are the detections 33 | void write_bin(); 34 | 35 | 36 | //file stuff 37 | std::ofstream binDump; //file stream for debugging 38 | std::string debugFile; 39 | std::string spectrogramBinFile; 40 | std::string timeDisMapBinFile; 41 | 42 | //signal processing classes 43 | FFT* fftProc; 44 | math* simdMath; 45 | tuneFilter* filt; 46 | 47 | //threads 48 | std::thread corrThread; //runs the correlator 49 | std::thread specThread; //creates the spectrogram 50 | std::thread detThread; 51 | 52 | //variables 53 | std::vector charBuffs; 54 | std::vector floatBuffs,fftBuffs; 55 | 56 | std::vector> absBuffs; 57 | std::vector taps; 58 | 59 | std::atomic buffRdy,corrRdy,specRdy,enabled; 60 | 61 | 62 | int buffNum; 63 | int buffLen; 64 | 65 | util::plot* plothandler; 66 | }; 67 | } 68 | #endif -------------------------------------------------------------------------------- /filt_taps_0_3_to_0_33_80_dB_atten_0_1_dB_ripple: -------------------------------------------------------------------------------- 1 | restype,fir 2 | fs,1.0 3 | pbend,0.3 4 | gain,1.0 5 | sbstart,0.33 6 | filttype,lpf 7 | ripple,0.1 8 | atten,80.0 9 | wintype,6 10 | ntaps,114 11 | taps,8.649797451192497e-05,-0.0006979612155341148,-0.0018484454263496689,-0.0009282143734232276,0.0008796800008959142,8.466039026224879e-05,-0.0009094903513823273,0.0006223477624645603,0.0005519797428052186,-0.0011819008580283164,0.00028108428254695585,0.0012074014446693741,-0.0013072698654694108,-0.0004180086118381536,0.00191678196031249,-0.001031040965368092,-0.0014795766881625532,0.002423632366043592,-0.00017733651293269493,-0.002746141034134298,0.0024193859464811157,0.0013070491704791885,-0.003912264985291096,0.0016119946406068547,0.0033023593293729993,-0.004557170412125548,-0.00018999934966755651,0.005484472771108847,-0.004212018362970485,-0.0029913950981309803,0.007331374706590945,-0.0024554978803907807,-0.0065445324628450935,0.008171081008261458,0.0009806232682532184,-0.010319981676856719,0.0072637045271249185,0.006132164367337955,-0.013507201387463063,0.0038696457244802728,0.012723233919863887,-0.015045142505179075,-0.0026882680637936173,0.020203333446367554,-0.013584220901163175,-0.013170480975433415,0.027782876860020754,-0.00718945852325898,-0.029049259979041963,0.03455775970558269,0.008231898005105001,-0.05539859441549525,0.03965655389892246,0.049213033586926025,-0.12455963299027156,0.042394282464222874,0.5286408441925461,0.5286408441925461,0.042394282464222874,-0.12455963299027156,0.049213033586926025,0.03965655389892246,-0.05539859441549525,0.008231898005105001,0.03455775970558269,-0.029049259979041963,-0.00718945852325898,0.027782876860020754,-0.013170480975433415,-0.013584220901163175,0.020203333446367554,-0.0026882680637936173,-0.015045142505179075,0.012723233919863887,0.0038696457244802728,-0.013507201387463063,0.006132164367337955,0.0072637045271249185,-0.010319981676856719,0.0009806232682532184,0.008171081008261458,-0.0065445324628450935,-0.0024554978803907807,0.007331374706590945,-0.0029913950981309803,-0.004212018362970485,0.005484472771108847,-0.00018999934966755651,-0.004557170412125548,0.0033023593293729993,0.0016119946406068547,-0.003912264985291096,0.0013070491704791885,0.0024193859464811157,-0.002746141034134298,-0.00017733651293269493,0.002423632366043592,-0.0014795766881625532,-0.001031040965368092,0.00191678196031249,-0.0004180086118381536,-0.0013072698654694108,0.0012074014446693741,0.00028108428254695585,-0.0011819008580283164,0.0005519797428052186,0.0006223477624645603,-0.0009094903513823273,8.466039026224879e-05,0.0008796800008959142,-0.0009282143734232276,-0.0018484454263496689,-0.0006979612155341148,8.649797451192497e-05 12 | -------------------------------------------------------------------------------- /src/util/plotting/plot.cpp: -------------------------------------------------------------------------------- 1 | #include "plot.h" 2 | 3 | #include 4 | 5 | namespace plt = matplotlibcpp; 6 | 7 | 8 | /* 9 | * Constructor 10 | */ 11 | util::plot::plot(int buffLength_):buffLength(buffLength_){}; 12 | 13 | /* 14 | * Destructor 15 | */ 16 | util::plot::~plot(){ 17 | // clearVector(); 18 | }; 19 | 20 | /* 21 | * Initialize things 22 | */ 23 | void util::plot::init(){}; 24 | 25 | /* 26 | * Plot complex 2d data, plots the real and imaginary parts as two seperate lines 27 | */ 28 | void util::plot::plotComplex2d(float* xData,radar::complexFloat* yData){}; 29 | 30 | /* 31 | * Plot 2d data 32 | */ 33 | void util::plot::plot2d(float* xData,float* yData){ 34 | //get vectors 35 | // makeVector(xData,nullptr,1); 36 | std::cout << "Plotting abs(FFT)" << std::endl; 37 | makeVector(yData,nullptr,1); 38 | std::cout << "making call to matplotlib.pyplot.plot" << std::endl; 39 | std::cout << "**** plot.cpp | plot2d : floatVec size is " << floatVec.size() << " ****" << std::endl; 40 | std::cout << "**** plot.cpp | plot2d : data size is " << floatVec[0].size() << " ****" << std::endl; 41 | //call plotting 42 | plt::plot(floatVec[0],"g-"); 43 | std::cout << "saving plot" << std::endl; 44 | plt::save("./plot_test.png"); 45 | clearVector(); 46 | }; 47 | 48 | /* 49 | * plot 3d data 50 | */ 51 | void util::plot::plot3d(float* xData,float* yData,float* zData){}; 52 | 53 | /* 54 | * plot an image, not implemented 55 | */ 56 | void util::plot::image(float* xData,float* yData,float* imageData){}; 57 | 58 | //-------------------------------------------------------------------- 59 | //plotting utils 60 | //-------------------------------------------------------------------- 61 | /* 62 | * Plotting utils 63 | */ 64 | void util::plot::clearFigure(){}; 65 | 66 | void util::plot::makeVector(float* floatData, radar::complexFloat* complexData, int type){ 67 | switch(type){ 68 | case 1: 69 | { 70 | //float 71 | floatVec.push_back(std::vector(buffLength,0)); 72 | std::cout << "**** plot.cpp : floatVec size is " << floatVec.size() << " ****" << std::endl; 73 | std::cout << "**** plot.cpp : data size is " << floatVec[0].size() << " ****" << std::endl; 74 | int index = floatVec.size() -1; 75 | for(int i=0;i(buffLength,0)); 83 | int index = complexFloatVec.size() -1; 84 | for(int i=0;i 4 | #include 5 | #include 6 | 7 | 8 | math::math(int numSamps):buffSize(numSamps){ 9 | alignment = volk_get_alignment(); 10 | internalFloatBuff = (float*)volk_malloc(numSamps*sizeof(float),alignment); 11 | internalComplexFloatBuff = (radar::complexFloat*)volk_malloc(numSamps*sizeof(radar::complexFloat),alignment); 12 | 13 | filterInit = false; 14 | }; 15 | 16 | math::~math(){ 17 | volk_free(internalFloatBuff); 18 | volk_free(internalComplexFloatBuff); 19 | if(filterInit){ 20 | volk_free(internalFilterHistory); 21 | volk_free(aligned_taps); 22 | volk_free(complexZeros); 23 | } 24 | }; 25 | 26 | void math::normalize(radar::complexFloat* input, float normConst){ 27 | volk_32f_s32f_normalize((float*)input, normConst, 2*buffSize); 28 | } 29 | 30 | void math::abs(radar::complexFloat* input,float* output){ 31 | volk_32fc_magnitude_32f(internalFloatBuff, input, buffSize); 32 | std::memcpy(output,internalFloatBuff,buffSize*sizeof(float)); 33 | } 34 | 35 | void math::magSqrd(radar::complexFloat* input,float* output){ 36 | volk_32fc_magnitude_squared_32f(internalFloatBuff, input, buffSize); 37 | std::memcpy(output,internalFloatBuff,buffSize*sizeof(radar::complexFloat)); 38 | } 39 | 40 | void math::multiply(radar::complexFloat* input1,radar::complexFloat* input2, radar::complexFloat* output){ 41 | volk_32fc_x2_multiply_32fc(output,input1,input2,buffSize); 42 | // std::memcpy(output,internalComplexFloatBuff,buffSize*sizeof(radar::complexFloat)); 43 | } 44 | 45 | void math::multiply(radar::complexFloat* input1,radar::complexFloat* input2, radar::complexFloat* output,int numSamps){ 46 | volk_32fc_x2_multiply_32fc(output,input1,input2,numSamps); 47 | } 48 | 49 | void math::initFilter(float* taps, int tapsSize){ 50 | if(!filterInit){ 51 | filterInit = true; 52 | numTaps = tapsSize; 53 | //set up filter history buffer 54 | internalFilterHistory = (radar::complexFloat*)volk_malloc(tapsSize*sizeof(radar::complexFloat),alignment); 55 | complexZeros = (radar::complexFloat*)volk_malloc(tapsSize*sizeof(radar::complexFloat),alignment); 56 | 57 | for(int i = 0;i 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../signal_processing/fft.h" 10 | #include "../util/radarDataTypes.h" 11 | 12 | 13 | tuneFilter::tuneFilter(std::vector &taps_, float frequencyOffset, float sampRate, int inputSize, int fftSize):inputSize(inputSize),fftSize(fftSize){ 14 | //copy taps into local storage 15 | taps = new float[taps_.size()]; 16 | 17 | FFT* localFFT; 18 | //get fft size 19 | if(fftSize==0){ 20 | //fft size is input size 21 | this->fftSize = inputSize; 22 | nShiftSamples = (frequencyOffset < 0 ? -frequencyOffset:frequencyOffset)*inputSize/sampRate; 23 | shiftDir = frequencyOffset < 0 ? 0:1; // 0 = left shift, 1 = right shift 24 | nShiftSamples = shiftDir==1?inputSize-nShiftSamples:nShiftSamples; 25 | //fft of taps 26 | radar::complexFloat* complexTaps = new radar::complexFloat[inputSize]; 27 | std::memcpy(taps,&taps_.front(),sizeof(float)*taps_.size()); 28 | for(uint i=0;i(new radar::complexFloat[(int)inputSize],std::default_delete()); 34 | localFFT->getFFT(complexTaps,fftTaps.get()); 35 | delete[] complexTaps; 36 | } 37 | else{ 38 | std::cout << fftSize << std::endl; 39 | //fft size is not input size 40 | nShiftSamples = frequencyOffset*fftSize/sampRate; 41 | shiftDir = frequencyOffset < 0 ? 0:1; // 0 = left shift, 1 = right shift 42 | nShiftSamples = shiftDir==1?fftSize-nShiftSamples:nShiftSamples; 43 | //fft of taps 44 | radar::complexFloat* complexTaps = new radar::complexFloat[fftSize]; 45 | std::memcpy(taps,&taps_.front(),sizeof(float)*taps_.size()); 46 | for(uint i=0;i(new radar::complexFloat[(int)fftSize],std::default_delete()); 52 | localFFT->getFFT(complexTaps,fftTaps.get()); 53 | delete[] complexTaps; 54 | } 55 | 56 | swapBuff = std::shared_ptr(new radar::complexFloat[(int)nShiftSamples],std::default_delete()); 57 | 58 | //class instatiations 59 | mathHandle = new math(inputSize); 60 | 61 | //get exp table 62 | expTable = std::shared_ptr(new radar::complexFloat[(int)inputSize],std::default_delete()); 63 | for(int i = 0;iinitFilter(taps,taps_.size()); 70 | 71 | //get rid of fft object 72 | delete localFFT; 73 | delete[] taps; 74 | } 75 | 76 | tuneFilter::~tuneFilter(){ 77 | delete mathHandle; 78 | } 79 | 80 | void tuneFilter::fftFilterTune(radar::complexFloat* fftInput, radar::complexFloat* filteredOutput){ 81 | //circular shift the buffer to the right or left 82 | //move the end samples into the swap buffer 83 | std::memcpy(swapBuff.get(),&fftInput[nShiftSamples],(nShiftSamples)*sizeof(radar::complexFloat)); 84 | //shift the input array 85 | std::memmove(&fftInput[nShiftSamples],&fftInput[0],(inputSize-nShiftSamples)*sizeof(radar::complexFloat)); 86 | //append samples to the front of the buffer 87 | std::memcpy(&fftInput[0],swapBuff.get(),(nShiftSamples)*sizeof(radar::complexFloat)); 88 | //filter 89 | mathHandle->multiply(fftTaps.get(),fftInput,filteredOutput,fftSize); 90 | } 91 | 92 | void tuneFilter::fftFilterTune(radar::complexFloat* fftInput){ 93 | //circular shift the buffer to the right or left 94 | //move the end samples into the swap buffer 95 | std::memcpy(swapBuff.get(),&fftInput[nShiftSamples],(nShiftSamples)*sizeof(radar::complexFloat)); 96 | //shift the input array 97 | std::memmove(&fftInput[nShiftSamples],&fftInput[0],(inputSize-nShiftSamples)*sizeof(radar::complexFloat)); 98 | //append samples to the front of the buffer 99 | std::memcpy(&fftInput[0],swapBuff.get(),(nShiftSamples)*sizeof(radar::complexFloat)); 100 | //filter 101 | mathHandle->multiply(fftTaps.get(),fftInput,fftInput,fftSize); 102 | } 103 | 104 | void tuneFilter::timeFilterTune(radar::complexFloat* iqInput, radar::complexFloat* filteredOutput){ 105 | //frequency translate 106 | mathHandle->multiply(expTable.get(),iqInput,filteredOutput); 107 | //filter 108 | mathHandle->filter(filteredOutput,filteredOutput); 109 | } 110 | 111 | void tuneFilter::timeFilterTune(radar::complexFloat* iqInput){ 112 | //frequency translate 113 | mathHandle->multiply(expTable.get(),iqInput,iqInput); 114 | //filter 115 | mathHandle->filter(iqInput,iqInput); 116 | } 117 | 118 | -------------------------------------------------------------------------------- /profiling/main_filter_timing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../src/util/plotting/plot.h" 6 | #include "../src/util/radarDataTypes.h" 7 | #include "../src/signal_processing/tuneFilter.h" 8 | #include "../src/waveform/LFM.h" 9 | namespace plt = matplotlibcpp; 10 | 11 | int main(){ 12 | //HACK hard coding the taps, can add some ability to parse a file or somthing 13 | std::vector taps = {0.0008302388596348464, 0.000955868570599705, -0.0020353347063064575, 3.3073416789746066e-18, 0.004050636198371649, -0.0035107277799397707, 14 | -0.004825763404369354, 0.010514914989471436, -1.0744886732703555e-17, -0.01813529059290886, 0.014474445022642612, 0.018609102815389633, -0.03878936544060707, 15 | 1.9515073313200094e-17, 0.06743156164884567, -0.058430444449186325, -0.09081077575683594, 0.3001424968242645, 0.5990568399429321, 0.3001424968242645, 16 | -0.09081077575683594, -0.058430444449186325, 0.06743156164884567, 1.9515073313200094e-17, -0.03878936544060707, 0.018609102815389633, 0.014474445022642612, 17 | -0.01813529059290886, -1.0744886732703555e-17, 0.010514914989471436, -0.004825763404369354, -0.0035107277799397707, 0.004050636198371649, 3.3073416789746066e-18, 18 | -0.0020353347063064575, 0.000955868570599705, 0.0008302388596348464}; 19 | 20 | int numIter = 1000; 21 | std::vector data(numIter,0); 22 | std::vector data2(numIter,0); 23 | std::vector data3(numIter,0); 24 | std::vector data4(10000,0); 25 | 26 | // { 27 | // //filter object 28 | // tuneFilter* filt = new tuneFilter(taps,5000000, 10000000.0, 10000); 29 | // 30 | // //data 31 | // LFM* waveGen = new LFM(10000000.0, //sample rate 32 | // (int) 10000, //number of samples 33 | // (float) 50000, //bandwidth 34 | // (float) 100000); //center frequency 35 | // waveGen->genWave(); 36 | // radar::complexFloatBuffPtr tx_wave = waveGen->getFloatBuff(); 37 | // 38 | // 39 | // //run tests 40 | // for(int i = 0;itimeFilterTune(tx_wave.get(),tx_wave.get()); 43 | // auto duration = std::chrono::duration_cast< 44 | // std::chrono::duration >(std::chrono::system_clock::now() - start); 45 | // data[i] = (duration.count()); 46 | // } 47 | // 48 | // delete filt; 49 | // delete waveGen; 50 | // 51 | // } 52 | // 53 | // 54 | // { 55 | // //filter object 56 | // tuneFilter* filt = new tuneFilter(taps,5000000, 10000000.0, 100000); 57 | // 58 | // //data 59 | // LFM* waveGen = new LFM(10000000.0, //sample rate 60 | // (int) 100000, //number of samples 61 | // (float) 50000, //bandwidth 62 | // (float) 100000); //center frequency 63 | // waveGen->genWave(); 64 | // radar::complexFloatBuffPtr tx_wave = waveGen->getFloatBuff(); 65 | // 66 | // 67 | // //run tests 68 | // for(int i = 0;itimeFilterTune(tx_wave.get(),tx_wave.get()); 71 | // auto duration = std::chrono::duration_cast< 72 | // std::chrono::duration >(std::chrono::system_clock::now() - start); 73 | // data2[i] = (duration.count()); 74 | // } 75 | // 76 | // delete filt; 77 | // delete waveGen; 78 | // 79 | // } 80 | 81 | 82 | // { 83 | //filter object 84 | tuneFilter* filt = new tuneFilter(taps,5000000, 10000000.0, 10000); 85 | 86 | //data 87 | radar::complexFloatBuffPtr expTable = std::shared_ptr(new radar::complexFloat[10000],std::default_delete()); 88 | radar::complexFloatBuffPtr fftTable = std::shared_ptr(new radar::complexFloat[10000],std::default_delete()); 89 | radar::complexFloatBuffPtr outTable = std::shared_ptr(new radar::complexFloat[10000],std::default_delete()); 90 | 91 | for(int i = 0;i<10000;++i){ 92 | float arg = 6.283185307179586*100000*i/10000000.0; 93 | expTable.get()[i] = radar::complexFloat(std::cos(arg),std::sin(arg)); 94 | } 95 | 96 | //get fft 97 | FFT* localFFT = new FFT(10000,10000); 98 | localFFT->getFFT(expTable.get(),fftTable.get()); 99 | 100 | //run tests 101 | // for(int i = 0;ifftFilterTune(fftTable.get()); 104 | auto duration = std::chrono::duration_cast< 105 | std::chrono::duration >(std::chrono::system_clock::now() - start); 106 | // data3[i] = (duration.count()); 107 | // } 108 | 109 | delete filt; 110 | delete localFFT; 111 | // } 112 | 113 | 114 | // plt::figure(); 115 | // plt::xlabel("Iteration"); 116 | // plt::ylabel("Time (s)"); 117 | // plt::title("30 Tap FIR filter run times"); 118 | // plt::plot(data,"-b*"); 119 | // plt::plot(data2,"-g*"); 120 | // plt::plot(data3,"-r*"); 121 | // plt::legend("10000 samples","100000 samples"); 122 | 123 | 124 | for(int i=0;i<10000;++i){ 125 | float r = fftTable.get()[i].real(); 126 | float j = fftTable.get()[i].imag(); 127 | // std::cout << outTable.get()[i] << std::endl; 128 | data4[i] = r*r + j*j; 129 | } 130 | 131 | 132 | plt::figure(); 133 | plt::xlabel("fft bin"); 134 | plt::ylabel("amp"); 135 | plt::title("FFT"); 136 | plt::plot(data4,"-r*"); 137 | 138 | 139 | plt::show(); 140 | 141 | 142 | 143 | } -------------------------------------------------------------------------------- /src/hardware/hackrf/scheduler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Handles the rx and tx schduling, also passes rx buffers to the processing thread 5 | * 6 | * 7 | */ 8 | 9 | #include "scheduler.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace hackrf; 17 | 18 | //forward declaration of static members 19 | std::vector sched::tx_wave; 20 | radar::charBuff* sched::rx_buff; 21 | std::atomic sched::newBuff; 22 | proc* sched::pro; 23 | 24 | sched::sched(const device_params* device_options){ 25 | //TODO: add ability to specify number of IQ buffers 26 | tx_wave.resize(1); 27 | 28 | frontEnd = device_options; 29 | 30 | //get the tx waveform, narrow band chirp 31 | waveGen = new LFM((float) device_options->sampRate, //sample rate 32 | (int) 10000, //number of samples 33 | (float) 50000, //bandwidth 34 | (float) 100000); //center frequency 35 | waveGen->genWave(); 36 | tx_wave[0] = waveGen->getCharBuff(); 37 | 38 | //processor 39 | pro = new proc("proc.bin","proc.bin","proc.bin"); 40 | } 41 | 42 | sched::~sched(){ 43 | std::cout << "::STOPPING RADAR::" << std::endl; 44 | 45 | //check threads have joined 46 | if (enabled) 47 | this->stop(); //join threads 48 | 49 | //stop hackrf device 50 | hackrf_close(hackrf); 51 | hackrf_exit(); 52 | 53 | //call delete 54 | pro->~proc(); 55 | waveGen->~LFM(); 56 | } 57 | 58 | //init hardware 59 | void sched::init(){ 60 | std::cout << "In init" << std::endl; 61 | 62 | //enable and check the hardware 63 | int result = hackrf_init(); 64 | if (result != HACKRF_SUCCESS){ 65 | std::cout << "No device found...stopping..." << std::endl; 66 | std::exit(-1); 67 | }else{ 68 | std::cout << "Found hackrf" << std::endl; 69 | } 70 | 71 | result = hackrf_open(&hackrf); 72 | if (result != HACKRF_SUCCESS){ 73 | std::cout << "Failed to open the device...stopping..." << std::endl; 74 | std::exit(-1); 75 | }else{ 76 | std::cout << "opened hackrf" << std::endl; 77 | } 78 | 79 | //set up device front end 80 | result = set_up_device(this->frontEnd,hackrf); 81 | if (result == -1){std::cout << "Device set up failed" << std::endl;std::exit(-1);} 82 | std::cout << "Return from device setup: " << result << std::endl; 83 | 84 | pro->init(10000,10000); 85 | } 86 | 87 | //start hardware 88 | void sched::start(){ 89 | //things 90 | //start all threads 91 | //thread execution will be controlled with spin locks and atomic variables 92 | int ret = hackrf_start_rx(hackrf, &sched::tx_callback, (void *) this); 93 | if (ret != HACKRF_SUCCESS){ 94 | std::cout << "Failed to start tx with error code: " << ret << " stopping" << std::endl; 95 | hackrf_exit(); 96 | std::exit(-1); 97 | }; 98 | 99 | 100 | //init thread controls 101 | enabled = true; 102 | transmitting = true; //always begin by transmitting 103 | newBuff = false; 104 | 105 | //init threads 106 | this->rx_thread = std::thread(std::bind(&sched::rx_callback_control, this)); 107 | this->tx_thread = std::thread(std::bind(&sched::tx_callback_control, this)); 108 | 109 | std::cout << "::STARTED RADAR::" << std::endl; 110 | } 111 | 112 | 113 | 114 | //stop hardware 115 | void sched::stop(){ 116 | //join threads 117 | enabled = false; 118 | rx_thread.join(); 119 | tx_thread.join(); 120 | } 121 | 122 | //---------------------Transmitter------------------------- 123 | void sched::tx_callback_control(){ 124 | while(enabled){ 125 | while(!transmitting.load()){usleep(1);}; //spin lock, wait transmit signal 126 | std::this_thread::sleep_for(std::chrono::seconds(1)); 127 | switch_rx_tx(); //start receiving 128 | } 129 | } 130 | 131 | int sched::tx_callback(hackrf_transfer* transfer){ 132 | // std::cout << "In tx_callback" << std::endl; 133 | int numSamps = transfer->valid_length < 10000 ? transfer->valid_length : 10000; 134 | std::memcpy(&transfer->buffer[0],tx_wave[0].get(),numSamps); 135 | return 0; 136 | } 137 | 138 | 139 | //---------------------Receiver------------------------- 140 | void sched::rx_callback_control(){ 141 | while(enabled){ 142 | while(transmitting.load()){usleep(1);}; //spin lock 143 | std::this_thread::sleep_for(std::chrono::seconds(1)); 144 | 145 | //check for new buffer 146 | if(newBuff){ 147 | pro->rx_monitor(rx_buff); 148 | newBuff = false; 149 | } 150 | switch_rx_tx(); //start transmitting again 151 | } 152 | } 153 | 154 | int sched::rx_callback(hackrf_transfer* transfer){ 155 | //do stuff 156 | std::cout << "In rx_callback" << std::endl; 157 | 158 | if(newBuff){ 159 | //not consuming fast enough, drop samples on the floor 160 | std::cout << "****Rx Overflow****" << std::endl; 161 | } 162 | else{ 163 | //copy transfer buffer into local storage 164 | rx_buff = (transfer->buffer); 165 | newBuff = true; 166 | } 167 | return 1; 168 | } 169 | 170 | 171 | //------------------Hardware specific helper methods--------------- 172 | void sched::reopen_device(){ 173 | int result = hackrf_open(&hackrf); 174 | if (result != HACKRF_SUCCESS){ 175 | std::cout << "Failed to reopen device with error code: " << result << " stopping" << std::endl; 176 | hackrf_exit(); 177 | std::exit(-1); 178 | }; 179 | } 180 | 181 | void sched::switch_rx_tx(){ 182 | //switch 183 | transmitting.store(!transmitting.load()); 184 | //need to make calls to the hackrf driver to stop rx/tx and start the other one 185 | if(!transmitting.load()){ 186 | //might drop samples... 187 | hackrf_stop_tx(hackrf); 188 | std::cout << "Stopped tx" << std::endl; 189 | hackrf_close(hackrf); 190 | this->reopen_device(); 191 | int ret = hackrf_start_rx(hackrf, &sched::rx_callback, (void *) this); 192 | if (ret != HACKRF_SUCCESS){ 193 | std::cout << "Failed to start rx with error code: " << ret << " stopping" << std::endl; 194 | hackrf_exit(); 195 | std::exit(-1); 196 | } 197 | std::cout << "started rx" << std::endl; 198 | } 199 | else{ 200 | //might drop samples 201 | hackrf_stop_rx(hackrf); 202 | std::cout << "Stopped rx" << std::endl; 203 | hackrf_close(hackrf); 204 | this->reopen_device(); 205 | int ret = hackrf_start_tx(hackrf, &sched::tx_callback, (void *) this); 206 | if(ret != HACKRF_SUCCESS){ 207 | std::cout << "Failed to start tx with error code: " << ret << " stopping" << std::endl; 208 | hackrf_exit(); 209 | std::exit(-1); 210 | } 211 | std::cout << "started tx" << std::endl; 212 | } 213 | std::cout << "Switched" << std::endl; 214 | } 215 | 216 | -------------------------------------------------------------------------------- /src/hardware/hackrf/proc.cpp: -------------------------------------------------------------------------------- 1 | #include "proc.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | 11 | #include "../../signal_processing/fft.h" 12 | #include "../../waveform/LFM.h" //wow that is really annoying 13 | // 14 | 15 | using namespace hackrf; 16 | 17 | proc::proc(std::string debugFile, std::string spectrogramBinFile, std::string timeDisMapBinFile):debugFile(debugFile),spectrogramBinFile(spectrogramBinFile),timeDisMapBinFile(timeDisMapBinFile){ 18 | absBuffs.resize(10); 19 | charBuffs.resize(10); 20 | floatBuffs.resize(10); 21 | fftBuffs.resize(10); 22 | 23 | //HACK hard coding the taps, can add some ability to parse a file or somthing 24 | taps = {8.649797451192497e-05,-0.0006979612155341148,-0.0018484454263496689,-0.0009282143734232276,0.0008796800008959142, 25 | 8.466039026224879e-05,-0.0009094903513823273,0.0006223477624645603,0.0005519797428052186,-0.0011819008580283164, 26 | 0.00028108428254695585,0.0012074014446693741,-0.0013072698654694108,-0.0004180086118381536,0.00191678196031249, 27 | -0.001031040965368092,-0.0014795766881625532,0.002423632366043592,-0.00017733651293269493,-0.002746141034134298, 28 | 0.0024193859464811157,0.0013070491704791885,-0.003912264985291096,0.0016119946406068547,0.0033023593293729993, 29 | -0.004557170412125548,-0.00018999934966755651,0.005484472771108847,-0.004212018362970485,-0.0029913950981309803, 30 | 0.007331374706590945,-0.0024554978803907807,-0.0065445324628450935,0.008171081008261458,0.0009806232682532184, 31 | -0.010319981676856719,0.0072637045271249185,0.006132164367337955,-0.013507201387463063,0.0038696457244802728, 32 | 0.012723233919863887,-0.015045142505179075,-0.0026882680637936173,0.020203333446367554,-0.013584220901163175, 33 | -0.013170480975433415,0.027782876860020754,-0.00718945852325898,-0.029049259979041963,0.03455775970558269, 34 | 0.008231898005105001,-0.05539859441549525,0.03965655389892246,0.049213033586926025,-0.12455963299027156, 35 | 0.042394282464222874,0.5286408441925461,0.5286408441925461,0.042394282464222874,-0.12455963299027156, 36 | 0.049213033586926025,0.03965655389892246,-0.05539859441549525,0.008231898005105001,0.03455775970558269, 37 | -0.029049259979041963,-0.00718945852325898,0.027782876860020754,-0.013170480975433415,-0.013584220901163175, 38 | 0.020203333446367554,-0.0026882680637936173,-0.015045142505179075,0.012723233919863887,0.0038696457244802728, 39 | -0.013507201387463063,0.006132164367337955,0.0072637045271249185,-0.010319981676856719,0.0009806232682532184, 40 | 0.008171081008261458,-0.0065445324628450935,-0.0024554978803907807,0.007331374706590945,-0.0029913950981309803, 41 | -0.004212018362970485,0.005484472771108847,-0.00018999934966755651,-0.004557170412125548,0.0033023593293729993, 42 | 0.0016119946406068547,-0.003912264985291096,0.0013070491704791885,0.0024193859464811157,-0.002746141034134298, 43 | -0.00017733651293269493,0.002423632366043592,-0.0014795766881625532,-0.001031040965368092,0.00191678196031249, 44 | -0.0004180086118381536,-0.0013072698654694108,0.0012074014446693741,0.00028108428254695585,-0.0011819008580283164, 45 | 0.0005519797428052186,0.0006223477624645603,-0.0009094903513823273,8.466039026224879e-05,0.0008796800008959142, 46 | -0.0009282143734232276,-0.0018484454263496689,-0.0006979612155341148,8.649797451192497e-05}; 47 | 48 | 49 | } 50 | 51 | proc::~proc(){ 52 | if(enabled) 53 | stop(); 54 | 55 | fftProc->~FFT(); 56 | simdMath->~math(); 57 | plothandler->~plot(); 58 | } 59 | 60 | void proc::stop(){ 61 | this->enabled = false; 62 | this->buffRdy = true; 63 | //join threads 64 | this->corrThread.join(); 65 | this->specThread.join(); 66 | this->detThread.join(); 67 | } 68 | 69 | 70 | void proc::init(int fftSize,int inputSize) 71 | { 72 | this->enabled = true; 73 | this->buffLen = inputSize; 74 | 75 | fftProc = new FFT(fftSize,inputSize); 76 | simdMath = new math(inputSize); 77 | plothandler = new util::plot(inputSize); 78 | filt = new tuneFilter(taps,5000000, 10000000.0, inputSize); 79 | 80 | buffRdy = false; 81 | corrRdy = false; 82 | specRdy = false; 83 | buffNum = 0; 84 | 85 | //bind threads 86 | this->corrThread = std::thread(std::bind(&proc::corr_proc, this)); 87 | this->specThread = std::thread(std::bind(&proc::time_freq_map, this)); 88 | this->detThread = std::thread(std::bind(&proc::signal_int, this)); 89 | 90 | 91 | //preallocate and initialize the buffers 92 | for(int allocLoop = 0;allocLoop<(int)charBuffs.size();allocLoop++){ 93 | absBuffs[allocLoop] = std::shared_ptr((float*)std::malloc(inputSize*sizeof(float)),std::default_delete()); 94 | floatBuffs[allocLoop] = std::shared_ptr((radar::complexFloat*)std::malloc(inputSize*sizeof(radar::complexFloat)),std::default_delete()); 95 | fftBuffs[allocLoop] = std::shared_ptr((radar::complexFloat*)std::malloc(fftSize*sizeof(radar::complexFloat)),std::default_delete()); 96 | } 97 | 98 | } 99 | 100 | void proc::rx_monitor(radar::charBuff* rx_buff) 101 | { 102 | //things 103 | buffNum = (buffNum + 1)%10; 104 | charBuffs[buffNum] = std::make_shared(*rx_buff); 105 | buffRdy = true; 106 | } 107 | 108 | void proc::signal_int() 109 | { 110 | while(enabled){ 111 | //convert buffer to floating point 112 | while(!buffRdy){usleep(1);}; 113 | //got a buffer, convert to complex float and get fft 114 | for(int i=0,j=0;igetFFT(floatBuffs[buffNum].get(),fftBuffs[buffNum].get()); 122 | //tune filter 123 | filt->fftFilterTune(fftBuffs[buffNum].get()); 124 | std::cout << "**** proc.cpp | signal_int: filtered data ****" << std::endl; 125 | simdMath->abs(fftBuffs[buffNum].get(),absBuffs[buffNum].get()); //get magnitude of fft 126 | 127 | //******************************************* 128 | write_bin(); //debug 129 | plothandler->plot2d(nullptr,absBuffs[buffNum].get()); 130 | //******************************************* 131 | buffRdy = false; 132 | } 133 | } 134 | 135 | void proc::corr_proc() 136 | { 137 | //things 138 | } 139 | 140 | void proc::time_freq_map() 141 | { 142 | //Short time fourier analysis 143 | //things 144 | } 145 | 146 | void proc::time_dis_map() 147 | { 148 | //things 149 | } 150 | 151 | void proc::write_bin() 152 | { 153 | std::cout << "Writing file" << std::endl; 154 | binDump.open(debugFile,std::ios::binary); 155 | binDump.write(reinterpret_cast(absBuffs[buffNum].get()),buffLen*sizeof(float)); 156 | binDump.close(); 157 | binDump.open("procFFt.bin",std::ios::binary); 158 | binDump.write(reinterpret_cast(fftBuffs[buffNum].get()),buffLen*sizeof(radar::complexFloat)); 159 | binDump.close(); 160 | std::cout << "Wrote file" << std::endl; 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/hardware/hackrf/driver/hackrf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012, Jared Boone 3 | Copyright (c) 2013, Benjamin Vernoux 4 | Copyright (c) 2013, Michael Ossmann 5 | 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | Neither the name of Great Scott Gadgets nor the names of its contributors may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #ifndef __HACKRF_H__ 25 | #define __HACKRF_H__ 26 | 27 | #include 28 | 29 | #ifdef _WIN32 30 | #define ADD_EXPORTS 31 | 32 | /* You should define ADD_EXPORTS *only* when building the DLL. */ 33 | #ifdef ADD_EXPORTS 34 | #define ADDAPI __declspec(dllexport) 35 | #else 36 | #define ADDAPI __declspec(dllimport) 37 | #endif 38 | 39 | /* Define calling convention in one place, for convenience. */ 40 | #define ADDCALL __cdecl 41 | 42 | #else /* _WIN32 not defined. */ 43 | 44 | /* Define with no value on non-Windows OSes. */ 45 | #define ADDAPI 46 | #define ADDCALL 47 | 48 | #endif 49 | 50 | enum hackrf_error { 51 | HACKRF_SUCCESS = 0, 52 | HACKRF_TRUE = 1, 53 | HACKRF_ERROR_INVALID_PARAM = -2, 54 | HACKRF_ERROR_NOT_FOUND = -5, 55 | HACKRF_ERROR_BUSY = -6, 56 | HACKRF_ERROR_NO_MEM = -11, 57 | HACKRF_ERROR_LIBUSB = -1000, 58 | HACKRF_ERROR_THREAD = -1001, 59 | HACKRF_ERROR_STREAMING_THREAD_ERR = -1002, 60 | HACKRF_ERROR_STREAMING_STOPPED = -1003, 61 | HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004, 62 | HACKRF_ERROR_OTHER = -9999, 63 | }; 64 | 65 | enum hackrf_board_id { 66 | BOARD_ID_JELLYBEAN = 0, 67 | BOARD_ID_JAWBREAKER = 1, 68 | BOARD_ID_HACKRF_ONE = 2, 69 | BOARD_ID_RAD1O = 3, 70 | BOARD_ID_INVALID = 0xFF, 71 | }; 72 | 73 | enum hackrf_usb_board_id { 74 | USB_BOARD_ID_JAWBREAKER = 0x604B, 75 | USB_BOARD_ID_HACKRF_ONE = 0x6089, 76 | USB_BOARD_ID_RAD1O = 0xCC15, 77 | USB_BOARD_ID_INVALID = 0xFFFF, 78 | }; 79 | 80 | enum rf_path_filter { 81 | RF_PATH_FILTER_BYPASS = 0, 82 | RF_PATH_FILTER_LOW_PASS = 1, 83 | RF_PATH_FILTER_HIGH_PASS = 2, 84 | }; 85 | 86 | typedef struct hackrf_device hackrf_device; 87 | 88 | typedef struct { 89 | hackrf_device* device; 90 | uint8_t* buffer; 91 | int buffer_length; 92 | int valid_length; 93 | void* rx_ctx; 94 | void* tx_ctx; 95 | } hackrf_transfer; 96 | 97 | typedef struct { 98 | uint32_t part_id[2]; 99 | uint32_t serial_no[4]; 100 | } read_partid_serialno_t; 101 | 102 | 103 | struct hackrf_device_list { 104 | char **serial_numbers; 105 | enum hackrf_usb_board_id *usb_board_ids; 106 | int *usb_device_index; 107 | int devicecount; 108 | 109 | void **usb_devices; 110 | int usb_devicecount; 111 | }; 112 | typedef struct hackrf_device_list hackrf_device_list_t; 113 | 114 | typedef int (*hackrf_sample_block_cb_fn)(hackrf_transfer* transfer); 115 | 116 | #ifdef __cplusplus 117 | extern "C" 118 | { 119 | #endif 120 | 121 | extern ADDAPI int ADDCALL hackrf_init(); 122 | extern ADDAPI int ADDCALL hackrf_exit(); 123 | 124 | extern ADDAPI hackrf_device_list_t* ADDCALL hackrf_device_list(); 125 | extern ADDAPI int ADDCALL hackrf_device_list_open(hackrf_device_list_t *list, int idx, hackrf_device** device); 126 | extern ADDAPI void ADDCALL hackrf_device_list_free(hackrf_device_list_t *list); 127 | 128 | extern ADDAPI int ADDCALL hackrf_open(hackrf_device** device); 129 | extern ADDAPI int ADDCALL hackrf_open_by_serial(const char* const desired_serial_number, hackrf_device** device); 130 | extern ADDAPI int ADDCALL hackrf_close(hackrf_device* device); 131 | 132 | extern ADDAPI int ADDCALL hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* rx_ctx); 133 | extern ADDAPI int ADDCALL hackrf_stop_rx(hackrf_device* device); 134 | 135 | extern ADDAPI int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx); 136 | extern ADDAPI int ADDCALL hackrf_stop_tx(hackrf_device* device); 137 | 138 | /* return HACKRF_TRUE if success */ 139 | extern ADDAPI int ADDCALL hackrf_is_streaming(hackrf_device* device); 140 | 141 | extern ADDAPI int ADDCALL hackrf_max2837_read(hackrf_device* device, uint8_t register_number, uint16_t* value); 142 | extern ADDAPI int ADDCALL hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_t value); 143 | 144 | extern ADDAPI int ADDCALL hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value); 145 | extern ADDAPI int ADDCALL hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value); 146 | 147 | extern ADDAPI int ADDCALL hackrf_set_baseband_filter_bandwidth(hackrf_device* device, const uint32_t bandwidth_hz); 148 | 149 | extern ADDAPI int ADDCALL hackrf_rffc5071_read(hackrf_device* device, uint8_t register_number, uint16_t* value); 150 | extern ADDAPI int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value); 151 | 152 | extern ADDAPI int ADDCALL hackrf_spiflash_erase(hackrf_device* device); 153 | extern ADDAPI int ADDCALL hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data); 154 | extern ADDAPI int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data); 155 | 156 | /* device will need to be reset after hackrf_cpld_write */ 157 | extern ADDAPI int ADDCALL hackrf_cpld_write(hackrf_device* device, 158 | unsigned char* const data, const unsigned int total_length); 159 | 160 | extern ADDAPI int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value); 161 | extern ADDAPI int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length); 162 | 163 | extern ADDAPI int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz); 164 | extern ADDAPI int ADDCALL hackrf_set_freq_explicit(hackrf_device* device, 165 | const uint64_t if_freq_hz, const uint64_t lo_freq_hz, 166 | const enum rf_path_filter path); 167 | 168 | /* currently 8-20Mhz - either as a fraction, i.e. freq 20000000hz divider 2 -> 10Mhz or as plain old 10000000hz (double) 169 | preferred rates are 8, 10, 12.5, 16, 20Mhz due to less jitter */ 170 | extern ADDAPI int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device, const uint32_t freq_hz, const uint32_t divider); 171 | extern ADDAPI int ADDCALL hackrf_set_sample_rate(hackrf_device* device, const double freq_hz); 172 | 173 | /* external amp, bool on/off */ 174 | extern ADDAPI int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value); 175 | 176 | extern ADDAPI int ADDCALL hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno); 177 | 178 | /* range 0-40 step 8d, IF gain in osmosdr */ 179 | extern ADDAPI int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value); 180 | 181 | /* range 0-62 step 2db, BB gain in osmosdr */ 182 | extern ADDAPI int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value); 183 | 184 | /* range 0-47 step 1db */ 185 | extern ADDAPI int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t value); 186 | 187 | /* antenna port power control */ 188 | extern ADDAPI int ADDCALL hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value); 189 | 190 | extern ADDAPI const char* ADDCALL hackrf_error_name(enum hackrf_error errcode); 191 | extern ADDAPI const char* ADDCALL hackrf_board_id_name(enum hackrf_board_id board_id); 192 | extern ADDAPI const char* ADDCALL hackrf_usb_board_id_name(enum hackrf_usb_board_id usb_board_id); 193 | extern ADDAPI const char* ADDCALL hackrf_filter_path_name(const enum rf_path_filter path); 194 | 195 | /* Compute nearest freq for bw filter (manual filter) */ 196 | extern ADDAPI uint32_t ADDCALL hackrf_compute_baseband_filter_bw_round_down_lt(const uint32_t bandwidth_hz); 197 | /* Compute best default value depending on sample rate (auto filter) */ 198 | extern ADDAPI uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t bandwidth_hz); 199 | 200 | #ifdef __cplusplus 201 | } // __cplusplus defined. 202 | #endif 203 | 204 | #endif /*__HACKRF_H__*/ 205 | -------------------------------------------------------------------------------- /src/util/plotting/matplotlibcpp.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATPLOTLIBINTEHCPP__ 2 | #define __MATPLOTLIBINTEHCPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if __cplusplus > 199711L 11 | #include 12 | #endif 13 | 14 | #include 15 | 16 | namespace matplotlibcpp { 17 | 18 | namespace detail { 19 | struct _interpreter { 20 | PyObject *s_python_function_show; 21 | PyObject *s_python_function_save; 22 | PyObject *s_python_function_figure; 23 | PyObject *s_python_function_plot; 24 | PyObject *s_python_function_hist; 25 | PyObject *s_python_function_subplot; 26 | PyObject *s_python_function_legend; 27 | PyObject *s_python_function_xlim; 28 | PyObject *s_python_function_ylim; 29 | PyObject *s_python_function_title; 30 | PyObject *s_python_function_axis; 31 | PyObject *s_python_function_xlabel; 32 | PyObject *s_python_function_ylabel; 33 | PyObject *s_python_function_grid; 34 | PyObject *s_python_function_clf; 35 | PyObject *s_python_function_errorbar; 36 | PyObject *s_python_empty_tuple; 37 | PyObject *s_python_function_annotate; 38 | PyObject *s_python_function_interactive; 39 | PyObject *s_python_function_draw; 40 | 41 | /* For now, _interpreter is implemented as a singleton since its currently not possible to have 42 | multiple independent embedded python interpreters without patching the python source code 43 | or starting a separate process for each. 44 | http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program 45 | */ 46 | 47 | static _interpreter& get() { 48 | static _interpreter ctx; 49 | return ctx; 50 | } 51 | 52 | private: 53 | _interpreter() { 54 | char name[] = "plotting"; // silence compiler warning about const strings 55 | Py_SetProgramName(name); // optional but recommended 56 | Py_Initialize(); 57 | 58 | PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); 59 | PyObject* pylabname = PyString_FromString("pylab"); 60 | if(!pyplotname || !pylabname) { throw std::runtime_error("couldnt create string"); } 61 | 62 | PyObject* pymod = PyImport_Import(pyplotname); 63 | Py_DECREF(pyplotname); 64 | if(!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } 65 | 66 | PyObject* pylabmod = PyImport_Import(pylabname); 67 | Py_DECREF(pylabname); 68 | if(!pymod) { throw std::runtime_error("Error loading module pylab!"); } 69 | 70 | s_python_function_show = PyObject_GetAttrString(pymod, "show"); 71 | s_python_function_figure = PyObject_GetAttrString(pymod, "figure"); 72 | s_python_function_plot = PyObject_GetAttrString(pymod, "plot"); 73 | s_python_function_hist = PyObject_GetAttrString(pymod,"hist"); 74 | s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot"); 75 | s_python_function_legend = PyObject_GetAttrString(pymod, "legend"); 76 | s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim"); 77 | s_python_function_title = PyObject_GetAttrString(pymod, "title"); 78 | s_python_function_axis = PyObject_GetAttrString(pymod, "axis"); 79 | s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel"); 80 | s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel"); 81 | s_python_function_grid = PyObject_GetAttrString(pymod, "grid"); 82 | s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim"); 83 | s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig"); 84 | s_python_function_annotate = PyObject_GetAttrString(pymod,"annotate"); 85 | s_python_function_clf = PyObject_GetAttrString(pymod, "clf"); 86 | s_python_function_errorbar = PyObject_GetAttrString(pymod, "errorbar"); 87 | s_python_function_interactive = PyObject_GetAttrString(pymod, "interactive"); 88 | s_python_function_draw = PyObject_GetAttrString(pymod, "draw"); 89 | 90 | 91 | if( !s_python_function_show 92 | || !s_python_function_figure 93 | || !s_python_function_plot 94 | || !s_python_function_subplot 95 | || !s_python_function_legend 96 | || !s_python_function_ylim 97 | || !s_python_function_title 98 | || !s_python_function_axis 99 | || !s_python_function_xlabel 100 | || !s_python_function_ylabel 101 | || !s_python_function_grid 102 | || !s_python_function_xlim 103 | || !s_python_function_save 104 | || !s_python_function_clf 105 | || !s_python_function_annotate 106 | || !s_python_function_errorbar 107 | || !s_python_function_interactive 108 | || !s_python_function_draw 109 | ) { throw std::runtime_error("Couldn't find required function!"); } 110 | 111 | if ( !PyFunction_Check(s_python_function_show) 112 | || !PyFunction_Check(s_python_function_figure) 113 | || !PyFunction_Check(s_python_function_plot) 114 | || !PyFunction_Check(s_python_function_subplot) 115 | || !PyFunction_Check(s_python_function_legend) 116 | || !PyFunction_Check(s_python_function_annotate) 117 | || !PyFunction_Check(s_python_function_ylim) 118 | || !PyFunction_Check(s_python_function_title) 119 | || !PyFunction_Check(s_python_function_axis) 120 | || !PyFunction_Check(s_python_function_xlabel) 121 | || !PyFunction_Check(s_python_function_ylabel) 122 | || !PyFunction_Check(s_python_function_grid) 123 | || !PyFunction_Check(s_python_function_xlim) 124 | || !PyFunction_Check(s_python_function_save) 125 | || !PyFunction_Check(s_python_function_clf) 126 | || !PyFunction_Check(s_python_function_errorbar) 127 | || !PyFunction_Check(s_python_function_interactive) 128 | || !PyFunction_Check(s_python_function_draw) 129 | ) { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); } 130 | 131 | s_python_empty_tuple = PyTuple_New(0); 132 | } 133 | 134 | ~_interpreter() { 135 | Py_Finalize(); 136 | } 137 | }; 138 | } 139 | 140 | inline bool annotate(std::string annotation, double x, double y) 141 | { 142 | PyObject * xy = PyTuple_New(2); 143 | PyObject * str = PyString_FromString(annotation.c_str()); 144 | 145 | PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); 146 | PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); 147 | 148 | PyObject* kwargs = PyDict_New(); 149 | PyDict_SetItemString(kwargs, "xy", xy); 150 | 151 | PyObject* args = PyTuple_New(1); 152 | PyTuple_SetItem(args, 0, str); 153 | 154 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); 155 | 156 | Py_DECREF(args); 157 | Py_DECREF(kwargs); 158 | 159 | if(res) Py_DECREF(res); 160 | 161 | return res; 162 | } 163 | 164 | template 165 | bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) 166 | { 167 | assert(x.size() == y.size()); 168 | 169 | // using python lists 170 | PyObject* xlist = PyList_New(x.size()); 171 | PyObject* ylist = PyList_New(y.size()); 172 | 173 | for(size_t i = 0; i < x.size(); ++i) { 174 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 175 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 176 | } 177 | 178 | // construct positional args 179 | PyObject* args = PyTuple_New(2); 180 | PyTuple_SetItem(args, 0, xlist); 181 | PyTuple_SetItem(args, 1, ylist); 182 | 183 | // construct keyword args 184 | PyObject* kwargs = PyDict_New(); 185 | for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) 186 | { 187 | PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); 188 | } 189 | 190 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); 191 | 192 | Py_DECREF(args); 193 | Py_DECREF(kwargs); 194 | if(res) Py_DECREF(res); 195 | 196 | return res; 197 | } 198 | 199 | template< typename Numeric> 200 | bool hist(const std::vector& y, long bins=10,std::string color="b", double alpha=1.0) 201 | { 202 | PyObject* ylist = PyList_New(y.size()); 203 | 204 | PyObject* kwargs = PyDict_New(); 205 | PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); 206 | PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); 207 | PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); 208 | 209 | for(size_t i = 0; i < y.size(); ++i) { 210 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 211 | } 212 | 213 | PyObject* plot_args = PyTuple_New(1); 214 | 215 | PyTuple_SetItem(plot_args, 0, ylist); 216 | 217 | 218 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); 219 | 220 | 221 | Py_DECREF(plot_args); 222 | Py_DECREF(kwargs); 223 | if(res) Py_DECREF(res); 224 | 225 | return res; 226 | } 227 | 228 | template< typename Numeric> 229 | bool named_hist(std::string label,const std::vector& y, long bins=10, std::string color="b", double alpha=1.0) 230 | { 231 | PyObject* ylist = PyList_New(y.size()); 232 | PyObject* kwargs = PyDict_New(); 233 | PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); 234 | PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); 235 | PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); 236 | PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); 237 | 238 | for(size_t i = 0; i < y.size(); ++i) { 239 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 240 | } 241 | 242 | PyObject* plot_args = PyTuple_New(1); 243 | PyTuple_SetItem(plot_args, 0, ylist); 244 | 245 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); 246 | 247 | Py_DECREF(plot_args); 248 | Py_DECREF(kwargs); 249 | if(res) Py_DECREF(res); 250 | 251 | return res; 252 | } 253 | 254 | template 255 | bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") 256 | { 257 | assert(x.size() == y.size()); 258 | PyObject* xlist = PyList_New(x.size()); 259 | PyObject* ylist = PyList_New(y.size()); 260 | PyObject* pystring = PyString_FromString(s.c_str()); 261 | 262 | for(size_t i = 0; i < x.size(); i++) { 263 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 264 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 265 | } 266 | 267 | PyObject* plot_args = PyTuple_New(3); 268 | PyTuple_SetItem(plot_args, 0, xlist); 269 | PyTuple_SetItem(plot_args, 1, ylist); 270 | PyTuple_SetItem(plot_args, 2, pystring); 271 | 272 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); 273 | 274 | Py_DECREF(plot_args); 275 | if(res) Py_DECREF(res); 276 | 277 | return res; 278 | } 279 | 280 | template 281 | bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::string &s = "") 282 | { 283 | assert(x.size() == y.size()); 284 | 285 | PyObject *kwargs = PyDict_New(); 286 | PyObject *xlist = PyList_New(x.size()); 287 | PyObject *ylist = PyList_New(y.size()); 288 | PyObject *yerrlist = PyList_New(yerr.size()); 289 | 290 | for (size_t i = 0; i < yerr.size(); ++i) 291 | PyList_SetItem(yerrlist, i, PyFloat_FromDouble(yerr.at(i))); 292 | 293 | PyDict_SetItemString(kwargs, "yerr", yerrlist); 294 | 295 | PyObject *pystring = PyString_FromString(s.c_str()); 296 | 297 | for (size_t i = 0; i < x.size(); ++i) { 298 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 299 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 300 | } 301 | 302 | PyObject *plot_args = PyTuple_New(2); 303 | PyTuple_SetItem(plot_args, 0, xlist); 304 | PyTuple_SetItem(plot_args, 1, ylist); 305 | 306 | PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); 307 | 308 | Py_DECREF(kwargs); 309 | Py_DECREF(plot_args); 310 | 311 | if (res) 312 | Py_DECREF(res); 313 | else 314 | throw std::runtime_error("Call to errorbar() failed."); 315 | 316 | return res; 317 | } 318 | 319 | template 320 | bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") 321 | { 322 | PyObject* kwargs = PyDict_New(); 323 | PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); 324 | 325 | PyObject* ylist = PyList_New(y.size()); 326 | PyObject* pystring = PyString_FromString(format.c_str()); 327 | 328 | for(size_t i = 0; i < y.size(); ++i) { 329 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 330 | } 331 | 332 | PyObject* plot_args = PyTuple_New(2); 333 | 334 | PyTuple_SetItem(plot_args, 0, ylist); 335 | PyTuple_SetItem(plot_args, 1, pystring); 336 | 337 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); 338 | 339 | Py_DECREF(kwargs); 340 | Py_DECREF(plot_args); 341 | if(res) Py_DECREF(res); 342 | 343 | return res; 344 | } 345 | 346 | template 347 | bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") 348 | { 349 | PyObject* kwargs = PyDict_New(); 350 | PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); 351 | 352 | PyObject* xlist = PyList_New(x.size()); 353 | PyObject* ylist = PyList_New(y.size()); 354 | PyObject* pystring = PyString_FromString(format.c_str()); 355 | 356 | for(size_t i = 0; i < x.size(); ++i) { 357 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 358 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 359 | } 360 | 361 | PyObject* plot_args = PyTuple_New(3); 362 | PyTuple_SetItem(plot_args, 0, xlist); 363 | PyTuple_SetItem(plot_args, 1, ylist); 364 | PyTuple_SetItem(plot_args, 2, pystring); 365 | 366 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); 367 | 368 | Py_DECREF(kwargs); 369 | Py_DECREF(plot_args); 370 | if(res) Py_DECREF(res); 371 | 372 | return res; 373 | } 374 | 375 | template 376 | bool plot(const std::vector& y, const std::string& format = "") 377 | { 378 | std::vector x(y.size()); 379 | for(size_t i=0; i 407 | void ylim(Numeric left, Numeric right) 408 | { 409 | PyObject* list = PyList_New(2); 410 | PyList_SetItem(list, 0, PyFloat_FromDouble(left)); 411 | PyList_SetItem(list, 1, PyFloat_FromDouble(right)); 412 | 413 | PyObject* args = PyTuple_New(1); 414 | PyTuple_SetItem(args, 0, list); 415 | 416 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); 417 | if(!res) throw std::runtime_error("Call to ylim() failed."); 418 | 419 | Py_DECREF(args); 420 | Py_DECREF(res); 421 | } 422 | 423 | template 424 | void xlim(Numeric left, Numeric right) 425 | { 426 | PyObject* list = PyList_New(2); 427 | PyList_SetItem(list, 0, PyFloat_FromDouble(left)); 428 | PyList_SetItem(list, 1, PyFloat_FromDouble(right)); 429 | 430 | PyObject* args = PyTuple_New(1); 431 | PyTuple_SetItem(args, 0, list); 432 | 433 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); 434 | if(!res) throw std::runtime_error("Call to xlim() failed."); 435 | 436 | Py_DECREF(args); 437 | Py_DECREF(res); 438 | } 439 | 440 | 441 | inline double* xlim() 442 | { 443 | PyObject* args = PyTuple_New(0); 444 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); 445 | PyObject* left = PyTuple_GetItem(res,0); 446 | PyObject* right = PyTuple_GetItem(res,1); 447 | 448 | double* arr = new double[2]; 449 | arr[0] = PyFloat_AsDouble(left); 450 | arr[1] = PyFloat_AsDouble(right); 451 | 452 | if(!res) throw std::runtime_error("Call to xlim() failed."); 453 | 454 | Py_DECREF(res); 455 | return arr; 456 | } 457 | 458 | 459 | inline double* ylim() 460 | { 461 | PyObject* args = PyTuple_New(0); 462 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); 463 | PyObject* left = PyTuple_GetItem(res,0); 464 | PyObject* right = PyTuple_GetItem(res,1); 465 | 466 | double* arr = new double[2]; 467 | arr[0] = PyFloat_AsDouble(left); 468 | arr[1] = PyFloat_AsDouble(right); 469 | 470 | if(!res) throw std::runtime_error("Call to ylim() failed."); 471 | 472 | Py_DECREF(res); 473 | return arr; 474 | } 475 | 476 | inline void subplot(long nrows, long ncols, long plot_number) 477 | { 478 | // construct positional args 479 | PyObject* args = PyTuple_New(3); 480 | PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); 481 | PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); 482 | PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); 483 | 484 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); 485 | if(!res) throw std::runtime_error("Call to subplot() failed."); 486 | 487 | Py_DECREF(args); 488 | Py_DECREF(res); 489 | } 490 | 491 | inline void title(const std::string &titlestr) 492 | { 493 | PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); 494 | PyObject* args = PyTuple_New(1); 495 | PyTuple_SetItem(args, 0, pytitlestr); 496 | 497 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args); 498 | if(!res) throw std::runtime_error("Call to title() failed."); 499 | 500 | // if PyDeCRFF, the function doesn't work on Mac OS 501 | } 502 | 503 | inline void axis(const std::string &axisstr) 504 | { 505 | PyObject* str = PyString_FromString(axisstr.c_str()); 506 | PyObject* args = PyTuple_New(1); 507 | PyTuple_SetItem(args, 0, str); 508 | 509 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); 510 | if(!res) throw std::runtime_error("Call to title() failed."); 511 | 512 | // if PyDeCRFF, the function doesn't work on Mac OS 513 | } 514 | 515 | inline void xlabel(const std::string &str) 516 | { 517 | PyObject* pystr = PyString_FromString(str.c_str()); 518 | PyObject* args = PyTuple_New(1); 519 | PyTuple_SetItem(args, 0, pystr); 520 | 521 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args); 522 | if(!res) throw std::runtime_error("Call to xlabel() failed."); 523 | 524 | // if PyDeCRFF, the function doesn't work on Mac OS 525 | } 526 | 527 | inline void ylabel(const std::string &str) 528 | { 529 | PyObject* pystr = PyString_FromString(str.c_str()); 530 | PyObject* args = PyTuple_New(1); 531 | PyTuple_SetItem(args, 0, pystr); 532 | 533 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args); 534 | if(!res) throw std::runtime_error("Call to ylabel() failed."); 535 | 536 | // if PyDeCRFF, the function doesn't work on Mac OS 537 | } 538 | 539 | inline void grid(bool flag) 540 | { 541 | PyObject* pyflag = flag ? Py_True : Py_False; 542 | 543 | PyObject* args = PyTuple_New(1); 544 | PyTuple_SetItem(args, 0, pyflag); 545 | 546 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); 547 | if(!res) throw std::runtime_error("Call to grid() failed."); 548 | 549 | // if PyDeCRFF, the function doesn't work on Mac OS 550 | } 551 | 552 | inline void show() 553 | { 554 | PyObject* res = PyObject_CallObject( 555 | detail::_interpreter::get().s_python_function_show, 556 | detail::_interpreter::get().s_python_empty_tuple); 557 | 558 | if (!res) throw std::runtime_error("Call to show() failed."); 559 | 560 | Py_DECREF(res); 561 | } 562 | 563 | inline void save(const std::string& filename) 564 | { 565 | PyObject* pyfilename = PyString_FromString(filename.c_str()); 566 | 567 | PyObject* args = PyTuple_New(1); 568 | PyTuple_SetItem(args, 0, pyfilename); 569 | 570 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args); 571 | if (!res) throw std::runtime_error("Call to save() failed."); 572 | 573 | Py_DECREF(args); 574 | Py_DECREF(res); 575 | } 576 | 577 | inline void clf() { 578 | PyObject *res = PyObject_CallObject( 579 | detail::_interpreter::get().s_python_function_clf, 580 | detail::_interpreter::get().s_python_empty_tuple); 581 | 582 | if (!res) throw std::runtime_error("Call to clf() failed."); 583 | 584 | Py_DECREF(res); 585 | } 586 | 587 | // //----------------------------------------------------------------------------------- 588 | // //------------------Adding the ability to call draw() ------------------------------- 589 | // //----------------------------------------------------------------------------------- 590 | inline void interactive(bool flag) 591 | { 592 | PyObject* pyflag = flag ? Py_True : Py_False; 593 | 594 | PyObject* args = PyTuple_New(1); 595 | PyTuple_SetItem(args, 0, pyflag); 596 | 597 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_interactive, args); 598 | if(!res) throw std::runtime_error("Call to interactive() failed."); 599 | 600 | // if PyDeCRFF, the function doesn't work on Mac OS 601 | } 602 | 603 | inline void draw() 604 | { 605 | 606 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_draw, detail::_interpreter::get().s_python_empty_tuple); 607 | if(!res) throw std::runtime_error("Call to interactive() failed."); 608 | 609 | // if PyDeCRFF, the function doesn't work on Mac OS 610 | } 611 | 612 | #if __cplusplus > 199711L 613 | // C++11-exclusive content starts here (variadic plot() and initializer list support) 614 | 615 | namespace detail { 616 | template 617 | using is_function = typename std::is_function>>::type; 618 | 619 | template 620 | struct is_callable_impl; 621 | 622 | template 623 | struct is_callable_impl 624 | { 625 | typedef is_function type; 626 | }; // a non-object is callable iff it is a function 627 | 628 | template 629 | struct is_callable_impl 630 | { 631 | struct Fallback { void operator()(); }; 632 | struct Derived : T, Fallback { }; 633 | 634 | template struct Check; 635 | 636 | template 637 | static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match 638 | 639 | template 640 | static std::false_type test( Check* ); 641 | 642 | public: 643 | typedef decltype(test(nullptr)) type; 644 | typedef decltype(&Fallback::operator()) dtype; 645 | static constexpr bool value = type::value; 646 | }; // an object is callable iff it defines operator() 647 | 648 | template 649 | struct is_callable 650 | { 651 | // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not 652 | typedef typename is_callable_impl::value, T>::type type; 653 | }; 654 | 655 | template 656 | struct plot_impl { }; 657 | 658 | template<> 659 | struct plot_impl 660 | { 661 | template 662 | bool operator()(const IterableX& x, const IterableY& y, const std::string& format) 663 | { 664 | // 2-phase lookup for distance, begin, end 665 | using std::distance; 666 | using std::begin; 667 | using std::end; 668 | 669 | auto xs = distance(begin(x), end(x)); 670 | auto ys = distance(begin(y), end(y)); 671 | assert(xs == ys && "x and y data must have the same number of elements!"); 672 | 673 | PyObject* xlist = PyList_New(xs); 674 | PyObject* ylist = PyList_New(ys); 675 | PyObject* pystring = PyString_FromString(format.c_str()); 676 | 677 | auto itx = begin(x), ity = begin(y); 678 | for(size_t i = 0; i < xs; ++i) { 679 | PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); 680 | PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); 681 | } 682 | 683 | PyObject* plot_args = PyTuple_New(3); 684 | PyTuple_SetItem(plot_args, 0, xlist); 685 | PyTuple_SetItem(plot_args, 1, ylist); 686 | PyTuple_SetItem(plot_args, 2, pystring); 687 | 688 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); 689 | 690 | Py_DECREF(plot_args); 691 | if(res) Py_DECREF(res); 692 | 693 | return res; 694 | } 695 | }; 696 | 697 | template<> 698 | struct plot_impl 699 | { 700 | template 701 | bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) 702 | { 703 | //std::cout << "Callable impl called" << std::endl; 704 | 705 | if(begin(ticks) == end(ticks)) return true; 706 | 707 | // We could use additional meta-programming to deduce the correct element type of y, 708 | // but all values have to be convertible to double anyways 709 | std::vector y; 710 | for(auto x : ticks) y.push_back(f(x)); 711 | return plot_impl()(ticks,y,format); 712 | } 713 | }; 714 | } 715 | 716 | // recursion stop for the above 717 | template 718 | bool plot() { return true; } 719 | 720 | template 721 | bool plot(const A& a, const B& b, const std::string& format, Args... args) 722 | { 723 | return detail::plot_impl::type>()(a,b,format) && plot(args...); 724 | } 725 | 726 | /* 727 | * This group of plot() functions is needed to support initializer lists, i.e. calling 728 | * plot( {1,2,3,4} ) 729 | */ 730 | inline bool plot(const std::vector& x, const std::vector& y, const std::string& format = "") { 731 | return plot(x,y,format); 732 | } 733 | 734 | inline bool plot(const std::vector& y, const std::string& format = "") { 735 | return plot(y,format); 736 | } 737 | 738 | inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { 739 | return plot(x,y,keywords); 740 | } 741 | 742 | inline bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { 743 | return named_plot(name,x,y,format); 744 | } 745 | 746 | #endif 747 | 748 | } 749 | 750 | #endif -------------------------------------------------------------------------------- /src/hardware/hackrf/driver/hackrf.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012, Jared Boone 3 | Copyright (c) 2013, Benjamin Vernoux 4 | Copyright (c) 2013, Michael Ossmann 5 | 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | Neither the name of Great Scott Gadgets nor the names of its contributors may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "hackrf.h" 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #ifndef bool 32 | typedef int bool; 33 | #define true 1 34 | #define false 0 35 | #endif 36 | 37 | #ifdef HACKRF_BIG_ENDIAN 38 | #define TO_LE(x) __builtin_bswap32(x) 39 | #define TO_LE64(x) __builtin_bswap64(x) 40 | #else 41 | #define TO_LE(x) x 42 | #define TO_LE64(x) x 43 | #endif 44 | 45 | // TODO: Factor this into a shared #include so that firmware can use 46 | // the same values. 47 | typedef enum { 48 | HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE = 1, 49 | HACKRF_VENDOR_REQUEST_MAX2837_WRITE = 2, 50 | HACKRF_VENDOR_REQUEST_MAX2837_READ = 3, 51 | HACKRF_VENDOR_REQUEST_SI5351C_WRITE = 4, 52 | HACKRF_VENDOR_REQUEST_SI5351C_READ = 5, 53 | HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET = 6, 54 | HACKRF_VENDOR_REQUEST_BASEBAND_FILTER_BANDWIDTH_SET = 7, 55 | HACKRF_VENDOR_REQUEST_RFFC5071_WRITE = 8, 56 | HACKRF_VENDOR_REQUEST_RFFC5071_READ = 9, 57 | HACKRF_VENDOR_REQUEST_SPIFLASH_ERASE = 10, 58 | HACKRF_VENDOR_REQUEST_SPIFLASH_WRITE = 11, 59 | HACKRF_VENDOR_REQUEST_SPIFLASH_READ = 12, 60 | HACKRF_VENDOR_REQUEST_BOARD_ID_READ = 14, 61 | HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15, 62 | HACKRF_VENDOR_REQUEST_SET_FREQ = 16, 63 | HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17, 64 | HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ = 18, 65 | HACKRF_VENDOR_REQUEST_SET_LNA_GAIN = 19, 66 | HACKRF_VENDOR_REQUEST_SET_VGA_GAIN = 20, 67 | HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21, 68 | HACKRF_VENDOR_REQUEST_ANTENNA_ENABLE = 23, 69 | HACKRF_VENDOR_REQUEST_SET_FREQ_EXPLICIT = 24, 70 | } hackrf_vendor_request; 71 | 72 | typedef enum { 73 | USB_CONFIG_STANDARD = 0x1, 74 | USB_CONFIG_CPLD_UPDATE = 0x2, 75 | } hackrf_usb_configurations; 76 | 77 | typedef enum { 78 | HACKRF_TRANSCEIVER_MODE_OFF = 0, 79 | HACKRF_TRANSCEIVER_MODE_RECEIVE = 1, 80 | HACKRF_TRANSCEIVER_MODE_TRANSMIT = 2, 81 | HACKRF_TRANSCEIVER_MODE_SS = 3, 82 | TRANSCEIVER_MODE_CPLD_UPDATE = 4, 83 | } hackrf_transceiver_mode; 84 | 85 | struct hackrf_device { 86 | libusb_device_handle* usb_device; 87 | struct libusb_transfer** transfers; 88 | hackrf_sample_block_cb_fn callback; 89 | volatile bool transfer_thread_started; /* volatile shared between threads (read only) */ 90 | pthread_t transfer_thread; 91 | uint32_t transfer_count; 92 | uint32_t buffer_size; 93 | volatile bool streaming; /* volatile shared between threads (read only) */ 94 | void* rx_ctx; 95 | void* tx_ctx; 96 | }; 97 | 98 | typedef struct { 99 | uint32_t bandwidth_hz; 100 | } max2837_ft_t; 101 | 102 | static const max2837_ft_t max2837_ft[] = { 103 | { 1750000 }, 104 | { 2500000 }, 105 | { 3500000 }, 106 | { 5000000 }, 107 | { 5500000 }, 108 | { 6000000 }, 109 | { 7000000 }, 110 | { 8000000 }, 111 | { 9000000 }, 112 | { 10000000 }, 113 | { 12000000 }, 114 | { 14000000 }, 115 | { 15000000 }, 116 | { 20000000 }, 117 | { 24000000 }, 118 | { 28000000 }, 119 | { 0 } 120 | }; 121 | 122 | static volatile bool do_exit = false; 123 | 124 | static const uint16_t hackrf_usb_vid = 0x1d50; 125 | static const uint16_t hackrf_jawbreaker_usb_pid = 0x604b; 126 | static const uint16_t hackrf_one_usb_pid = 0x6089; 127 | static const uint16_t rad1o_usb_pid = 0xcc15; 128 | 129 | static libusb_context* g_libusb_context = NULL; 130 | 131 | static void request_exit(void) 132 | { 133 | do_exit = true; 134 | } 135 | 136 | static int cancel_transfers(hackrf_device* device) 137 | { 138 | uint32_t transfer_index; 139 | 140 | if( device->transfers != NULL ) 141 | { 142 | for(transfer_index=0; transfer_indextransfer_count; transfer_index++) 143 | { 144 | if( device->transfers[transfer_index] != NULL ) 145 | { 146 | libusb_cancel_transfer(device->transfers[transfer_index]); 147 | } 148 | } 149 | return HACKRF_SUCCESS; 150 | } else { 151 | return HACKRF_ERROR_OTHER; 152 | } 153 | } 154 | 155 | static int free_transfers(hackrf_device* device) 156 | { 157 | uint32_t transfer_index; 158 | 159 | if( device->transfers != NULL ) 160 | { 161 | // libusb_close() should free all transfers referenced from this array. 162 | for(transfer_index=0; transfer_indextransfer_count; transfer_index++) 163 | { 164 | if( device->transfers[transfer_index] != NULL ) 165 | { 166 | libusb_free_transfer(device->transfers[transfer_index]); 167 | device->transfers[transfer_index] = NULL; 168 | } 169 | } 170 | free(device->transfers); 171 | device->transfers = NULL; 172 | } 173 | return HACKRF_SUCCESS; 174 | } 175 | 176 | static int allocate_transfers(hackrf_device* const device) 177 | { 178 | if( device->transfers == NULL ) 179 | { 180 | uint32_t transfer_index; 181 | device->transfers = (struct libusb_transfer**) calloc(device->transfer_count, sizeof(struct libusb_transfer)); 182 | if( device->transfers == NULL ) 183 | { 184 | return HACKRF_ERROR_NO_MEM; 185 | } 186 | 187 | for(transfer_index=0; transfer_indextransfer_count; transfer_index++) 188 | { 189 | device->transfers[transfer_index] = libusb_alloc_transfer(0); 190 | if( device->transfers[transfer_index] == NULL ) 191 | { 192 | return HACKRF_ERROR_LIBUSB; 193 | } 194 | 195 | libusb_fill_bulk_transfer( 196 | device->transfers[transfer_index], 197 | device->usb_device, 198 | 0, 199 | (unsigned char*)malloc(device->buffer_size), 200 | device->buffer_size, 201 | NULL, 202 | device, 203 | 0 204 | ); 205 | 206 | if( device->transfers[transfer_index]->buffer == NULL ) 207 | { 208 | return HACKRF_ERROR_NO_MEM; 209 | } 210 | } 211 | return HACKRF_SUCCESS; 212 | } else { 213 | return HACKRF_ERROR_BUSY; 214 | } 215 | } 216 | 217 | static int prepare_transfers( 218 | hackrf_device* device, 219 | const uint_fast8_t endpoint_address, 220 | libusb_transfer_cb_fn callback) 221 | { 222 | int error; 223 | uint32_t transfer_index; 224 | if( device->transfers != NULL ) 225 | { 226 | for(transfer_index=0; transfer_indextransfer_count; transfer_index++) 227 | { 228 | device->transfers[transfer_index]->endpoint = endpoint_address; 229 | device->transfers[transfer_index]->callback = callback; 230 | 231 | error = libusb_submit_transfer(device->transfers[transfer_index]); 232 | if( error != 0 ) 233 | { 234 | return HACKRF_ERROR_LIBUSB; 235 | } 236 | } 237 | return HACKRF_SUCCESS; 238 | } else { 239 | // This shouldn't happen. 240 | return HACKRF_ERROR_OTHER; 241 | } 242 | } 243 | 244 | static int detach_kernel_drivers(libusb_device_handle* usb_device_handle) 245 | { 246 | int i, num_interfaces, result; 247 | libusb_device* dev; 248 | struct libusb_config_descriptor* config; 249 | 250 | dev = libusb_get_device(usb_device_handle); 251 | result = libusb_get_active_config_descriptor(dev, &config); 252 | if( result < 0 ) 253 | { 254 | return HACKRF_ERROR_LIBUSB; 255 | } 256 | 257 | num_interfaces = config->bNumInterfaces; 258 | libusb_free_config_descriptor(config); 259 | for(i=0; i 343 | #include 344 | 345 | hackrf_device_list_t* ADDCALL hackrf_device_list() 346 | { 347 | ssize_t i; 348 | libusb_device_handle* usb_device = NULL; 349 | uint_fast8_t serial_descriptor_index; 350 | char serial_number[64]; 351 | int serial_number_length; 352 | 353 | hackrf_device_list_t* list = calloc(1, sizeof(*list)); 354 | if ( list == NULL ) 355 | return NULL; 356 | 357 | list->usb_devicecount = libusb_get_device_list(g_libusb_context, (libusb_device ***)&list->usb_devices); 358 | 359 | list->serial_numbers = calloc(list->usb_devicecount, sizeof(void *)); 360 | list->usb_board_ids = calloc(list->usb_devicecount, sizeof(enum hackrf_usb_board_id)); 361 | list->usb_device_index = calloc(list->usb_devicecount, sizeof(int)); 362 | 363 | if ( list->serial_numbers == NULL || list->usb_board_ids == NULL || list->usb_device_index == NULL) { 364 | hackrf_device_list_free(list); 365 | return NULL; 366 | } 367 | 368 | for (i=0; iusb_devicecount; i++) { 369 | struct libusb_device_descriptor device_descriptor; 370 | libusb_get_device_descriptor(list->usb_devices[i], &device_descriptor); 371 | 372 | if( device_descriptor.idVendor == hackrf_usb_vid ) { 373 | if((device_descriptor.idProduct == hackrf_one_usb_pid) || 374 | (device_descriptor.idProduct == hackrf_jawbreaker_usb_pid) || 375 | (device_descriptor.idProduct == rad1o_usb_pid)) { 376 | int idx = list->devicecount++; 377 | list->usb_board_ids[idx] = device_descriptor.idProduct; 378 | list->usb_device_index[idx] = i; 379 | 380 | serial_descriptor_index = device_descriptor.iSerialNumber; 381 | if( serial_descriptor_index > 0 ) { 382 | if( libusb_open(list->usb_devices[i], &usb_device) != 0 ) { 383 | usb_device = NULL; 384 | continue; 385 | } 386 | serial_number_length = libusb_get_string_descriptor_ascii(usb_device, serial_descriptor_index, (unsigned char*)serial_number, sizeof(serial_number)); 387 | if( serial_number_length == 32 ) { 388 | serial_number[32] = 0; 389 | list->serial_numbers[idx] = strdup(serial_number); 390 | } 391 | 392 | libusb_close(usb_device); 393 | usb_device = NULL; 394 | } 395 | } 396 | } 397 | } 398 | 399 | return list; 400 | } 401 | 402 | void ADDCALL hackrf_device_list_free(hackrf_device_list_t *list) 403 | { 404 | int i; 405 | 406 | libusb_free_device_list((libusb_device **)list->usb_devices, 1); 407 | 408 | for (i = 0; i < list->devicecount; i++) { 409 | if (list->serial_numbers[i]) 410 | free(list->serial_numbers[i]); 411 | } 412 | 413 | free(list->serial_numbers); 414 | free(list->usb_board_ids); 415 | free(list->usb_device_index); 416 | free(list); 417 | } 418 | 419 | libusb_device_handle* hackrf_open_usb(const char* const desired_serial_number) 420 | { 421 | libusb_device_handle* usb_device = NULL; 422 | libusb_device** devices = NULL; 423 | const ssize_t list_length = libusb_get_device_list(g_libusb_context, &devices); 424 | int match_len = 0; 425 | ssize_t i; 426 | char serial_number[64]; 427 | int serial_number_length; 428 | 429 | printf("Number of USB devices: %ld\n", list_length); 430 | 431 | if( desired_serial_number ) { 432 | /* If a shorter serial number is specified, only match against the suffix. 433 | * Should probably complain if the match is not unique, currently doesn't. 434 | */ 435 | match_len = strlen(desired_serial_number); 436 | if ( match_len > 32 ) 437 | return NULL; 438 | } 439 | 440 | for (i=0; i 0 ) { 453 | if( libusb_open(devices[i], &usb_device) != 0 ) { 454 | usb_device = NULL; 455 | continue; 456 | } 457 | serial_number_length = libusb_get_string_descriptor_ascii(usb_device, serial_descriptor_index, (unsigned char*)serial_number, sizeof(serial_number)); 458 | if( serial_number_length == 32 ) { 459 | serial_number[32] = 0; 460 | printf(" %s", serial_number); 461 | if( strncmp(serial_number + 32-match_len, desired_serial_number, match_len) == 0 ) { 462 | printf(" match\n"); 463 | break; 464 | } else { 465 | printf(" skip\n"); 466 | libusb_close(usb_device); 467 | usb_device = NULL; 468 | } 469 | } else { 470 | printf(" wrong length of serial number: %d\n", serial_number_length); 471 | libusb_close(usb_device); 472 | usb_device = NULL; 473 | } 474 | } 475 | } else { 476 | printf(" default\n"); 477 | libusb_open(devices[i], &usb_device); 478 | break; 479 | } 480 | } 481 | } 482 | } 483 | 484 | libusb_free_device_list(devices, 1); 485 | 486 | return usb_device; 487 | } 488 | 489 | static int hackrf_open_setup(libusb_device_handle* usb_device, hackrf_device** device) 490 | { 491 | int result; 492 | hackrf_device* lib_device; 493 | 494 | //int speed = libusb_get_device_speed(usb_device); 495 | // TODO: Error or warning if not high speed USB? 496 | 497 | result = set_hackrf_configuration(usb_device, USB_CONFIG_STANDARD); 498 | if( result != LIBUSB_SUCCESS ) 499 | { 500 | libusb_close(usb_device); 501 | return result; 502 | } 503 | 504 | result = libusb_claim_interface(usb_device, 0); 505 | if( result != LIBUSB_SUCCESS ) 506 | { 507 | libusb_close(usb_device); 508 | return HACKRF_ERROR_LIBUSB; 509 | } 510 | 511 | lib_device = NULL; 512 | lib_device = (hackrf_device*)malloc(sizeof(*lib_device)); 513 | if( lib_device == NULL ) 514 | { 515 | libusb_release_interface(usb_device, 0); 516 | libusb_close(usb_device); 517 | return HACKRF_ERROR_NO_MEM; 518 | } 519 | 520 | lib_device->usb_device = usb_device; 521 | lib_device->transfers = NULL; 522 | lib_device->callback = NULL; 523 | lib_device->transfer_thread_started = false; 524 | /* 525 | lib_device->transfer_count = 1024; 526 | lib_device->buffer_size = 16384; 527 | */ 528 | lib_device->transfer_count = 4; 529 | lib_device->buffer_size = 262144; /* 1048576; */ 530 | lib_device->streaming = false; 531 | do_exit = false; 532 | 533 | result = allocate_transfers(lib_device); 534 | if( result != 0 ) 535 | { 536 | free(lib_device); 537 | libusb_release_interface(usb_device, 0); 538 | libusb_close(usb_device); 539 | return HACKRF_ERROR_NO_MEM; 540 | } 541 | 542 | *device = lib_device; 543 | 544 | return HACKRF_SUCCESS; 545 | } 546 | 547 | int ADDCALL hackrf_open(hackrf_device** device) 548 | { 549 | libusb_device_handle* usb_device; 550 | 551 | if( device == NULL ) 552 | { 553 | return HACKRF_ERROR_INVALID_PARAM; 554 | } 555 | 556 | usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, hackrf_one_usb_pid); 557 | 558 | if( usb_device == NULL ) 559 | { 560 | usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, hackrf_jawbreaker_usb_pid); 561 | } 562 | 563 | if( usb_device == NULL ) 564 | { 565 | usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, rad1o_usb_pid); 566 | } 567 | 568 | if( usb_device == NULL ) 569 | { 570 | return HACKRF_ERROR_NOT_FOUND; 571 | } 572 | 573 | return hackrf_open_setup(usb_device, device); 574 | } 575 | 576 | int ADDCALL hackrf_open_by_serial(const char* const desired_serial_number, hackrf_device** device) 577 | { 578 | libusb_device_handle* usb_device; 579 | 580 | if( desired_serial_number == NULL ) 581 | { 582 | return hackrf_open(device); 583 | } 584 | 585 | if( device == NULL ) 586 | { 587 | return HACKRF_ERROR_INVALID_PARAM; 588 | } 589 | 590 | usb_device = hackrf_open_usb(desired_serial_number); 591 | 592 | if( usb_device == NULL ) 593 | { 594 | return HACKRF_ERROR_NOT_FOUND; 595 | } 596 | 597 | return hackrf_open_setup(usb_device, device); 598 | } 599 | 600 | int ADDCALL hackrf_device_list_open(hackrf_device_list_t *list, int idx, hackrf_device** device) 601 | { 602 | libusb_device_handle* usb_device; 603 | int i; 604 | 605 | if( device == NULL || list == NULL || idx < 0 || idx >= list->devicecount ) 606 | { 607 | return HACKRF_ERROR_INVALID_PARAM; 608 | } 609 | 610 | i = list->usb_device_index[idx]; 611 | 612 | if( libusb_open(list->usb_devices[i], &usb_device) != 0 ) { 613 | usb_device = NULL; 614 | return HACKRF_ERROR_LIBUSB; 615 | } 616 | 617 | return hackrf_open_setup(usb_device, device); 618 | } 619 | 620 | int ADDCALL hackrf_set_transceiver_mode(hackrf_device* device, hackrf_transceiver_mode value) 621 | { 622 | int result; 623 | result = libusb_control_transfer( 624 | device->usb_device, 625 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 626 | HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE, 627 | value, 628 | 0, 629 | NULL, 630 | 0, 631 | 0 632 | ); 633 | 634 | if( result != 0 ) 635 | { 636 | printf("Libusb error code: %d\n",result); 637 | return HACKRF_ERROR_LIBUSB; 638 | } else { 639 | return HACKRF_SUCCESS; 640 | } 641 | } 642 | 643 | int ADDCALL hackrf_max2837_read(hackrf_device* device, uint8_t register_number, uint16_t* value) 644 | { 645 | int result; 646 | 647 | if( register_number >= 32 ) 648 | { 649 | return HACKRF_ERROR_INVALID_PARAM; 650 | } 651 | 652 | result = libusb_control_transfer( 653 | device->usb_device, 654 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 655 | HACKRF_VENDOR_REQUEST_MAX2837_READ, 656 | 0, 657 | register_number, 658 | (unsigned char*)value, 659 | 2, 660 | 0 661 | ); 662 | 663 | if( result < 2 ) 664 | { 665 | return HACKRF_ERROR_LIBUSB; 666 | } else { 667 | return HACKRF_SUCCESS; 668 | } 669 | } 670 | 671 | int ADDCALL hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_t value) 672 | { 673 | int result; 674 | 675 | if( register_number >= 32 ) 676 | { 677 | return HACKRF_ERROR_INVALID_PARAM; 678 | } 679 | if( value >= 0x400 ) 680 | { 681 | return HACKRF_ERROR_INVALID_PARAM; 682 | } 683 | 684 | result = libusb_control_transfer( 685 | device->usb_device, 686 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 687 | HACKRF_VENDOR_REQUEST_MAX2837_WRITE, 688 | value, 689 | register_number, 690 | NULL, 691 | 0, 692 | 0 693 | ); 694 | 695 | if( result != 0 ) 696 | { 697 | return HACKRF_ERROR_LIBUSB; 698 | } else { 699 | return HACKRF_SUCCESS; 700 | } 701 | } 702 | 703 | int ADDCALL hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value) 704 | { 705 | uint8_t temp_value; 706 | int result; 707 | 708 | if( register_number >= 256 ) 709 | { 710 | return HACKRF_ERROR_INVALID_PARAM; 711 | } 712 | 713 | temp_value = 0; 714 | result = libusb_control_transfer( 715 | device->usb_device, 716 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 717 | HACKRF_VENDOR_REQUEST_SI5351C_READ, 718 | 0, 719 | register_number, 720 | (unsigned char*)&temp_value, 721 | 1, 722 | 0 723 | ); 724 | 725 | if( result < 1 ) 726 | { 727 | return HACKRF_ERROR_LIBUSB; 728 | } else { 729 | *value = temp_value; 730 | return HACKRF_SUCCESS; 731 | } 732 | } 733 | 734 | int ADDCALL hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value) 735 | { 736 | int result; 737 | 738 | if( register_number >= 256 ) 739 | { 740 | return HACKRF_ERROR_INVALID_PARAM; 741 | } 742 | if( value >= 256 ) { 743 | return HACKRF_ERROR_INVALID_PARAM; 744 | } 745 | 746 | result = libusb_control_transfer( 747 | device->usb_device, 748 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 749 | HACKRF_VENDOR_REQUEST_SI5351C_WRITE, 750 | value, 751 | register_number, 752 | NULL, 753 | 0, 754 | 0 755 | ); 756 | 757 | if( result != 0 ) 758 | { 759 | return HACKRF_ERROR_LIBUSB; 760 | } else { 761 | return HACKRF_SUCCESS; 762 | } 763 | } 764 | 765 | int ADDCALL hackrf_set_baseband_filter_bandwidth(hackrf_device* device, const uint32_t bandwidth_hz) 766 | { 767 | int result; 768 | result = libusb_control_transfer( 769 | device->usb_device, 770 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 771 | HACKRF_VENDOR_REQUEST_BASEBAND_FILTER_BANDWIDTH_SET, 772 | bandwidth_hz & 0xffff, 773 | bandwidth_hz >> 16, 774 | NULL, 775 | 0, 776 | 0 777 | ); 778 | 779 | if( result != 0 ) 780 | { 781 | return HACKRF_ERROR_LIBUSB; 782 | } else { 783 | return HACKRF_SUCCESS; 784 | } 785 | } 786 | 787 | 788 | int ADDCALL hackrf_rffc5071_read(hackrf_device* device, uint8_t register_number, uint16_t* value) 789 | { 790 | int result; 791 | 792 | if( register_number >= 31 ) 793 | { 794 | return HACKRF_ERROR_INVALID_PARAM; 795 | } 796 | 797 | result = libusb_control_transfer( 798 | device->usb_device, 799 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 800 | HACKRF_VENDOR_REQUEST_RFFC5071_READ, 801 | 0, 802 | register_number, 803 | (unsigned char*)value, 804 | 2, 805 | 0 806 | ); 807 | 808 | if( result < 2 ) 809 | { 810 | return HACKRF_ERROR_LIBUSB; 811 | } else { 812 | return HACKRF_SUCCESS; 813 | } 814 | } 815 | 816 | int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value) 817 | { 818 | int result; 819 | 820 | if( register_number >= 31 ) 821 | { 822 | return HACKRF_ERROR_INVALID_PARAM; 823 | } 824 | 825 | result = libusb_control_transfer( 826 | device->usb_device, 827 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 828 | HACKRF_VENDOR_REQUEST_RFFC5071_WRITE, 829 | value, 830 | register_number, 831 | NULL, 832 | 0, 833 | 0 834 | ); 835 | 836 | if( result != 0 ) 837 | { 838 | return HACKRF_ERROR_LIBUSB; 839 | } else { 840 | return HACKRF_SUCCESS; 841 | } 842 | } 843 | 844 | int ADDCALL hackrf_spiflash_erase(hackrf_device* device) 845 | { 846 | int result; 847 | result = libusb_control_transfer( 848 | device->usb_device, 849 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 850 | HACKRF_VENDOR_REQUEST_SPIFLASH_ERASE, 851 | 0, 852 | 0, 853 | NULL, 854 | 0, 855 | 0 856 | ); 857 | 858 | if (result != 0) 859 | { 860 | return HACKRF_ERROR_LIBUSB; 861 | } else { 862 | return HACKRF_SUCCESS; 863 | } 864 | } 865 | 866 | int ADDCALL hackrf_spiflash_write(hackrf_device* device, const uint32_t address, 867 | const uint16_t length, unsigned char* const data) 868 | { 869 | int result; 870 | 871 | if (address > 0x0FFFFF) 872 | { 873 | return HACKRF_ERROR_INVALID_PARAM; 874 | } 875 | 876 | result = libusb_control_transfer( 877 | device->usb_device, 878 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 879 | HACKRF_VENDOR_REQUEST_SPIFLASH_WRITE, 880 | address >> 16, 881 | address & 0xFFFF, 882 | data, 883 | length, 884 | 0 885 | ); 886 | 887 | if (result < length) 888 | { 889 | return HACKRF_ERROR_LIBUSB; 890 | } else { 891 | return HACKRF_SUCCESS; 892 | } 893 | } 894 | 895 | int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address, 896 | const uint16_t length, unsigned char* data) 897 | { 898 | int result; 899 | 900 | if (address > 0x0FFFFF) 901 | { 902 | return HACKRF_ERROR_INVALID_PARAM; 903 | } 904 | 905 | result = libusb_control_transfer( 906 | device->usb_device, 907 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 908 | HACKRF_VENDOR_REQUEST_SPIFLASH_READ, 909 | address >> 16, 910 | address & 0xFFFF, 911 | data, 912 | length, 913 | 0 914 | ); 915 | 916 | if (result < length) 917 | { 918 | return HACKRF_ERROR_LIBUSB; 919 | } else { 920 | return HACKRF_SUCCESS; 921 | } 922 | } 923 | 924 | int ADDCALL hackrf_cpld_write(hackrf_device* device, 925 | unsigned char* const data, const unsigned int total_length) 926 | { 927 | const unsigned int chunk_size = 512; 928 | unsigned int i; 929 | int result, transferred = 0; 930 | 931 | result = hackrf_set_transceiver_mode(device, TRANSCEIVER_MODE_CPLD_UPDATE); 932 | if (result != 0) 933 | return result; 934 | 935 | for (i = 0; i < total_length; i += chunk_size) 936 | { 937 | result = libusb_bulk_transfer( 938 | device->usb_device, 939 | LIBUSB_ENDPOINT_OUT | 2, 940 | &data[i], 941 | chunk_size, 942 | &transferred, 943 | 10000 // long timeout to allow for CPLD programming 944 | ); 945 | 946 | if (result != LIBUSB_SUCCESS) { 947 | return HACKRF_ERROR_LIBUSB; 948 | } 949 | } 950 | 951 | return HACKRF_SUCCESS; 952 | } 953 | 954 | int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value) 955 | { 956 | int result; 957 | result = libusb_control_transfer( 958 | device->usb_device, 959 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 960 | HACKRF_VENDOR_REQUEST_BOARD_ID_READ, 961 | 0, 962 | 0, 963 | value, 964 | 1, 965 | 0 966 | ); 967 | 968 | if (result < 1) 969 | { 970 | return HACKRF_ERROR_LIBUSB; 971 | } else { 972 | return HACKRF_SUCCESS; 973 | } 974 | } 975 | 976 | int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version, 977 | uint8_t length) 978 | { 979 | int result; 980 | result = libusb_control_transfer( 981 | device->usb_device, 982 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 983 | HACKRF_VENDOR_REQUEST_VERSION_STRING_READ, 984 | 0, 985 | 0, 986 | (unsigned char*)version, 987 | length, 988 | 0 989 | ); 990 | 991 | if (result < 0) 992 | { 993 | return HACKRF_ERROR_LIBUSB; 994 | } else { 995 | version[result] = '\0'; 996 | return HACKRF_SUCCESS; 997 | } 998 | } 999 | 1000 | typedef struct { 1001 | uint32_t freq_mhz; /* From 0 to 6000+MHz */ 1002 | uint32_t freq_hz; /* From 0 to 999999Hz */ 1003 | /* Final Freq = freq_mhz+freq_hz */ 1004 | } set_freq_params_t; 1005 | #define FREQ_ONE_MHZ (1000*1000ull) 1006 | 1007 | int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz) 1008 | { 1009 | uint32_t l_freq_mhz; 1010 | uint32_t l_freq_hz; 1011 | set_freq_params_t set_freq_params; 1012 | uint8_t length; 1013 | int result; 1014 | 1015 | /* Convert Freq Hz 64bits to Freq MHz (32bits) & Freq Hz (32bits) */ 1016 | l_freq_mhz = (uint32_t)(freq_hz / FREQ_ONE_MHZ); 1017 | l_freq_hz = (uint32_t)(freq_hz - (((uint64_t)l_freq_mhz) * FREQ_ONE_MHZ)); 1018 | set_freq_params.freq_mhz = TO_LE(l_freq_mhz); 1019 | set_freq_params.freq_hz = TO_LE(l_freq_hz); 1020 | length = sizeof(set_freq_params_t); 1021 | 1022 | result = libusb_control_transfer( 1023 | device->usb_device, 1024 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1025 | HACKRF_VENDOR_REQUEST_SET_FREQ, 1026 | 0, 1027 | 0, 1028 | (unsigned char*)&set_freq_params, 1029 | length, 1030 | 0 1031 | ); 1032 | 1033 | if (result < length) 1034 | { 1035 | return HACKRF_ERROR_LIBUSB; 1036 | } else { 1037 | return HACKRF_SUCCESS; 1038 | } 1039 | } 1040 | 1041 | struct set_freq_explicit_params { 1042 | uint64_t if_freq_hz; /* intermediate frequency */ 1043 | uint64_t lo_freq_hz; /* front-end local oscillator frequency */ 1044 | uint8_t path; /* image rejection filter path */ 1045 | }; 1046 | 1047 | int ADDCALL hackrf_set_freq_explicit(hackrf_device* device, 1048 | const uint64_t if_freq_hz, const uint64_t lo_freq_hz, 1049 | const enum rf_path_filter path) 1050 | { 1051 | struct set_freq_explicit_params params; 1052 | uint8_t length; 1053 | int result; 1054 | 1055 | if (if_freq_hz < 2150000000 || if_freq_hz > 2750000000) { 1056 | return HACKRF_ERROR_INVALID_PARAM; 1057 | } 1058 | 1059 | if ((path != RF_PATH_FILTER_BYPASS) && 1060 | (lo_freq_hz < 84375000 || lo_freq_hz > 5400000000)) { 1061 | return HACKRF_ERROR_INVALID_PARAM; 1062 | } 1063 | 1064 | if (path > 2) { 1065 | return HACKRF_ERROR_INVALID_PARAM; 1066 | } 1067 | 1068 | params.if_freq_hz = TO_LE(if_freq_hz); 1069 | params.lo_freq_hz = TO_LE(lo_freq_hz); 1070 | params.path = (uint8_t)path; 1071 | length = sizeof(struct set_freq_explicit_params); 1072 | 1073 | result = libusb_control_transfer( 1074 | device->usb_device, 1075 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1076 | HACKRF_VENDOR_REQUEST_SET_FREQ_EXPLICIT, 1077 | 0, 1078 | 0, 1079 | (unsigned char*)¶ms, 1080 | length, 1081 | 0 1082 | ); 1083 | 1084 | if (result < length) 1085 | { 1086 | return HACKRF_ERROR_LIBUSB; 1087 | } else { 1088 | return HACKRF_SUCCESS; 1089 | } 1090 | } 1091 | 1092 | typedef struct { 1093 | uint32_t freq_hz; 1094 | uint32_t divider; 1095 | } set_fracrate_params_t; 1096 | 1097 | 1098 | int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device, 1099 | const uint32_t freq_hz, uint32_t divider) 1100 | { 1101 | set_fracrate_params_t set_fracrate_params; 1102 | uint8_t length; 1103 | int result; 1104 | 1105 | set_fracrate_params.freq_hz = TO_LE(freq_hz); 1106 | set_fracrate_params.divider = TO_LE(divider); 1107 | length = sizeof(set_fracrate_params_t); 1108 | 1109 | result = libusb_control_transfer( 1110 | device->usb_device, 1111 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1112 | HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET, 1113 | 0, 1114 | 0, 1115 | (unsigned char*)&set_fracrate_params, 1116 | length, 1117 | 0 1118 | ); 1119 | 1120 | if (result < length) 1121 | { 1122 | return HACKRF_ERROR_LIBUSB; 1123 | } else { 1124 | return HACKRF_SUCCESS; 1125 | } 1126 | } 1127 | 1128 | int ADDCALL hackrf_set_sample_rate(hackrf_device* device, const double freq) 1129 | { 1130 | const int MAX_N = 32; 1131 | uint32_t freq_hz, divider; 1132 | double freq_frac = 1.0 + freq - (int)freq; 1133 | uint64_t a, m; 1134 | int i, e; 1135 | 1136 | union { 1137 | uint64_t u64; 1138 | double d; 1139 | } v; 1140 | v.d = freq; 1141 | 1142 | e = (v.u64 >> 52) - 1023; 1143 | 1144 | m = ((1ULL << 52) - 1); 1145 | 1146 | v.d = freq_frac; 1147 | v.u64 &= m; 1148 | 1149 | m &= ~((1 << (e+4)) - 1); 1150 | 1151 | a = 0; 1152 | 1153 | for (i=1; iusb_device, 1173 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1174 | HACKRF_VENDOR_REQUEST_AMP_ENABLE, 1175 | value, 1176 | 0, 1177 | NULL, 1178 | 0, 1179 | 0 1180 | ); 1181 | 1182 | if (result != 0) 1183 | { 1184 | return HACKRF_ERROR_LIBUSB; 1185 | } else { 1186 | return HACKRF_SUCCESS; 1187 | } 1188 | } 1189 | 1190 | int ADDCALL hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno) 1191 | { 1192 | uint8_t length; 1193 | int result; 1194 | 1195 | length = sizeof(read_partid_serialno_t); 1196 | result = libusb_control_transfer( 1197 | device->usb_device, 1198 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1199 | HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ, 1200 | 0, 1201 | 0, 1202 | (unsigned char*)read_partid_serialno, 1203 | length, 1204 | 0 1205 | ); 1206 | 1207 | if (result < length) 1208 | { 1209 | return HACKRF_ERROR_LIBUSB; 1210 | } else { 1211 | 1212 | read_partid_serialno->part_id[0] = TO_LE(read_partid_serialno->part_id[0]); 1213 | read_partid_serialno->part_id[1] = TO_LE(read_partid_serialno->part_id[1]); 1214 | read_partid_serialno->serial_no[0] = TO_LE(read_partid_serialno->serial_no[0]); 1215 | read_partid_serialno->serial_no[1] = TO_LE(read_partid_serialno->serial_no[1]); 1216 | read_partid_serialno->serial_no[2] = TO_LE(read_partid_serialno->serial_no[2]); 1217 | read_partid_serialno->serial_no[3] = TO_LE(read_partid_serialno->serial_no[3]); 1218 | 1219 | return HACKRF_SUCCESS; 1220 | } 1221 | } 1222 | 1223 | int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value) 1224 | { 1225 | int result; 1226 | uint8_t retval; 1227 | 1228 | if( value > 40 ) 1229 | { 1230 | return HACKRF_ERROR_INVALID_PARAM; 1231 | } 1232 | 1233 | value &= ~0x07; 1234 | result = libusb_control_transfer( 1235 | device->usb_device, 1236 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1237 | HACKRF_VENDOR_REQUEST_SET_LNA_GAIN, 1238 | 0, 1239 | value, 1240 | &retval, 1241 | 1, 1242 | 0 1243 | ); 1244 | 1245 | if( result != 1 || !retval ) 1246 | { 1247 | return HACKRF_ERROR_INVALID_PARAM; 1248 | } else { 1249 | return HACKRF_SUCCESS; 1250 | } 1251 | } 1252 | 1253 | int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value) 1254 | { 1255 | int result; 1256 | uint8_t retval; 1257 | 1258 | if( value > 62 ) 1259 | { 1260 | return HACKRF_ERROR_INVALID_PARAM; 1261 | } 1262 | 1263 | value &= ~0x01; 1264 | result = libusb_control_transfer( 1265 | device->usb_device, 1266 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1267 | HACKRF_VENDOR_REQUEST_SET_VGA_GAIN, 1268 | 0, 1269 | value, 1270 | &retval, 1271 | 1, 1272 | 0 1273 | ); 1274 | 1275 | if( result != 1 || !retval ) 1276 | { 1277 | return HACKRF_ERROR_INVALID_PARAM; 1278 | } else { 1279 | return HACKRF_SUCCESS; 1280 | } 1281 | } 1282 | 1283 | int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t value) 1284 | { 1285 | int result; 1286 | uint8_t retval; 1287 | 1288 | if( value > 47 ) 1289 | { 1290 | return HACKRF_ERROR_INVALID_PARAM; 1291 | } 1292 | 1293 | result = libusb_control_transfer( 1294 | device->usb_device, 1295 | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1296 | HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN, 1297 | 0, 1298 | value, 1299 | &retval, 1300 | 1, 1301 | 0 1302 | ); 1303 | 1304 | if( result != 1 || !retval ) 1305 | { 1306 | return HACKRF_ERROR_INVALID_PARAM; 1307 | } else { 1308 | return HACKRF_SUCCESS; 1309 | } 1310 | } 1311 | 1312 | int ADDCALL hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value) 1313 | { 1314 | int result; 1315 | result = libusb_control_transfer( 1316 | device->usb_device, 1317 | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 1318 | HACKRF_VENDOR_REQUEST_ANTENNA_ENABLE, 1319 | value, 1320 | 0, 1321 | NULL, 1322 | 0, 1323 | 0 1324 | ); 1325 | 1326 | if (result != 0) 1327 | { 1328 | return HACKRF_ERROR_LIBUSB; 1329 | } else { 1330 | return HACKRF_SUCCESS; 1331 | } 1332 | } 1333 | 1334 | static void* transfer_threadproc(void* arg) 1335 | { 1336 | hackrf_device* device = (hackrf_device*)arg; 1337 | int error; 1338 | struct timeval timeout = { 0, 500000 }; 1339 | 1340 | while( (device->streaming) && (do_exit == false) ) 1341 | { 1342 | error = libusb_handle_events_timeout(g_libusb_context, &timeout); 1343 | if( (error != 0) && (error != LIBUSB_ERROR_INTERRUPTED) ) 1344 | { 1345 | device->streaming = false; 1346 | } 1347 | } 1348 | 1349 | return NULL; 1350 | } 1351 | 1352 | static void hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer) 1353 | { 1354 | hackrf_device* device = (hackrf_device*)usb_transfer->user_data; 1355 | 1356 | if(usb_transfer->status == LIBUSB_TRANSFER_COMPLETED) 1357 | { 1358 | hackrf_transfer transfer = { 1359 | transfer.device = device, 1360 | transfer.buffer = usb_transfer->buffer, 1361 | transfer.buffer_length = usb_transfer->length, 1362 | transfer.valid_length = usb_transfer->actual_length, 1363 | transfer.rx_ctx = device->rx_ctx, 1364 | transfer.tx_ctx = device->tx_ctx 1365 | }; 1366 | 1367 | if( device->callback(&transfer) == 0 ) 1368 | { 1369 | if( libusb_submit_transfer(usb_transfer) < 0) 1370 | { 1371 | request_exit(); 1372 | }else { 1373 | return; 1374 | } 1375 | }else { 1376 | request_exit(); 1377 | } 1378 | } else { 1379 | /* Other cases LIBUSB_TRANSFER_NO_DEVICE 1380 | LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_TIMED_OUT 1381 | LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_OVERFLOW 1382 | LIBUSB_TRANSFER_CANCELLED ... 1383 | */ 1384 | request_exit(); /* Fatal error stop transfer */ 1385 | } 1386 | } 1387 | 1388 | static int kill_transfer_thread(hackrf_device* device) 1389 | { 1390 | void* value; 1391 | int result; 1392 | 1393 | request_exit(); 1394 | 1395 | if( device->transfer_thread_started != false ) 1396 | { 1397 | value = NULL; 1398 | result = pthread_join(device->transfer_thread, &value); 1399 | if( result != 0 ) 1400 | { 1401 | return HACKRF_ERROR_THREAD; 1402 | } 1403 | device->transfer_thread_started = false; 1404 | 1405 | /* Cancel all transfers */ 1406 | cancel_transfers(device); 1407 | } 1408 | 1409 | return HACKRF_SUCCESS; 1410 | } 1411 | 1412 | static int create_transfer_thread(hackrf_device* device, 1413 | const uint8_t endpoint_address, 1414 | hackrf_sample_block_cb_fn callback) 1415 | { 1416 | int result; 1417 | 1418 | if( device->transfer_thread_started == false ) 1419 | { 1420 | device->streaming = false; 1421 | 1422 | result = prepare_transfers( 1423 | device, endpoint_address, 1424 | (libusb_transfer_cb_fn)hackrf_libusb_transfer_callback 1425 | ); 1426 | 1427 | if( result != HACKRF_SUCCESS ) 1428 | { 1429 | return result; 1430 | } 1431 | 1432 | device->streaming = true; 1433 | device->callback = callback; 1434 | result = pthread_create(&device->transfer_thread, 0, transfer_threadproc, device); 1435 | if( result == 0 ) 1436 | { 1437 | device->transfer_thread_started = true; 1438 | }else { 1439 | return HACKRF_ERROR_THREAD; 1440 | } 1441 | } else { 1442 | return HACKRF_ERROR_BUSY; 1443 | } 1444 | 1445 | return HACKRF_SUCCESS; 1446 | } 1447 | 1448 | int ADDCALL hackrf_is_streaming(hackrf_device* device) 1449 | { 1450 | /* return hackrf is streaming only when streaming, transfer_thread_started are true and do_exit equal false */ 1451 | 1452 | if( (device->transfer_thread_started == true) && 1453 | (device->streaming == true) && 1454 | (do_exit == false) ) 1455 | { 1456 | return HACKRF_TRUE; 1457 | } else { 1458 | 1459 | if(device->transfer_thread_started == false) 1460 | { 1461 | return HACKRF_ERROR_STREAMING_THREAD_ERR; 1462 | } 1463 | 1464 | if(device->streaming == false) 1465 | { 1466 | return HACKRF_ERROR_STREAMING_STOPPED; 1467 | } 1468 | 1469 | return HACKRF_ERROR_STREAMING_EXIT_CALLED; 1470 | } 1471 | } 1472 | 1473 | int ADDCALL hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* rx_ctx) 1474 | { 1475 | int result; 1476 | const uint8_t endpoint_address = LIBUSB_ENDPOINT_IN | 1; 1477 | result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_RECEIVE); 1478 | 1479 | if( result == HACKRF_SUCCESS ) 1480 | { 1481 | device->rx_ctx = rx_ctx; 1482 | result = create_transfer_thread(device, endpoint_address, callback); 1483 | } 1484 | return result; 1485 | } 1486 | 1487 | int ADDCALL hackrf_stop_rx(hackrf_device* device) 1488 | { 1489 | int result; 1490 | result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF); 1491 | if (result != HACKRF_SUCCESS) 1492 | { 1493 | return result; 1494 | } 1495 | return kill_transfer_thread(device); 1496 | } 1497 | 1498 | int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx) 1499 | { 1500 | int result; 1501 | const uint8_t endpoint_address = LIBUSB_ENDPOINT_OUT | 2; 1502 | result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_TRANSMIT); 1503 | if( result == HACKRF_SUCCESS ) 1504 | { 1505 | device->tx_ctx = tx_ctx; 1506 | result = create_transfer_thread(device, endpoint_address, callback); 1507 | } 1508 | return result; 1509 | } 1510 | 1511 | int ADDCALL hackrf_stop_tx(hackrf_device* device) 1512 | { 1513 | int result1, result2; 1514 | result1 = kill_transfer_thread(device); 1515 | result2 = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF); 1516 | if (result2 != HACKRF_SUCCESS) 1517 | { 1518 | return result2; 1519 | } 1520 | return result1; 1521 | } 1522 | 1523 | int ADDCALL hackrf_close(hackrf_device* device) 1524 | { 1525 | int result1, result2; 1526 | 1527 | result1 = HACKRF_SUCCESS; 1528 | result2 = HACKRF_SUCCESS; 1529 | 1530 | if( device != NULL ) 1531 | { 1532 | result1 = hackrf_stop_rx(device); 1533 | result2 = hackrf_stop_tx(device); 1534 | if( device->usb_device != NULL ) 1535 | { 1536 | libusb_release_interface(device->usb_device, 0); 1537 | libusb_close(device->usb_device); 1538 | device->usb_device = NULL; 1539 | } 1540 | 1541 | free_transfers(device); 1542 | 1543 | free(device); 1544 | } 1545 | 1546 | if (result2 != HACKRF_SUCCESS) 1547 | { 1548 | return result2; 1549 | } 1550 | return result1; 1551 | } 1552 | 1553 | const char* ADDCALL hackrf_error_name(enum hackrf_error errcode) 1554 | { 1555 | switch(errcode) 1556 | { 1557 | case HACKRF_SUCCESS: 1558 | return "HACKRF_SUCCESS"; 1559 | 1560 | case HACKRF_TRUE: 1561 | return "HACKRF_TRUE"; 1562 | 1563 | case HACKRF_ERROR_INVALID_PARAM: 1564 | return "HACKRF_ERROR_INVALID_PARAM"; 1565 | 1566 | case HACKRF_ERROR_NOT_FOUND: 1567 | return "HACKRF_ERROR_NOT_FOUND"; 1568 | 1569 | case HACKRF_ERROR_BUSY: 1570 | return "HACKRF_ERROR_BUSY"; 1571 | 1572 | case HACKRF_ERROR_NO_MEM: 1573 | return "HACKRF_ERROR_NO_MEM"; 1574 | 1575 | case HACKRF_ERROR_LIBUSB: 1576 | return "HACKRF_ERROR_LIBUSB"; 1577 | 1578 | case HACKRF_ERROR_THREAD: 1579 | return "HACKRF_ERROR_THREAD"; 1580 | 1581 | case HACKRF_ERROR_STREAMING_THREAD_ERR: 1582 | return "HACKRF_ERROR_STREAMING_THREAD_ERR"; 1583 | 1584 | case HACKRF_ERROR_STREAMING_STOPPED: 1585 | return "HACKRF_ERROR_STREAMING_STOPPED"; 1586 | 1587 | case HACKRF_ERROR_STREAMING_EXIT_CALLED: 1588 | return "HACKRF_ERROR_STREAMING_EXIT_CALLED"; 1589 | 1590 | case HACKRF_ERROR_OTHER: 1591 | return "HACKRF_ERROR_OTHER"; 1592 | 1593 | default: 1594 | return "HACKRF unknown error"; 1595 | } 1596 | } 1597 | 1598 | const char* ADDCALL hackrf_board_id_name(enum hackrf_board_id board_id) 1599 | { 1600 | switch(board_id) 1601 | { 1602 | case BOARD_ID_JELLYBEAN: 1603 | return "Jellybean"; 1604 | 1605 | case BOARD_ID_JAWBREAKER: 1606 | return "Jawbreaker"; 1607 | 1608 | case BOARD_ID_HACKRF_ONE: 1609 | return "HackRF One"; 1610 | 1611 | case BOARD_ID_RAD1O: 1612 | return "rad1o"; 1613 | 1614 | case BOARD_ID_INVALID: 1615 | return "Invalid Board ID"; 1616 | 1617 | default: 1618 | return "Unknown Board ID"; 1619 | } 1620 | } 1621 | 1622 | extern ADDAPI const char* ADDCALL hackrf_usb_board_id_name(enum hackrf_usb_board_id usb_board_id) 1623 | { 1624 | switch(usb_board_id) 1625 | { 1626 | case USB_BOARD_ID_JAWBREAKER: 1627 | return "Jawbreaker"; 1628 | 1629 | case USB_BOARD_ID_HACKRF_ONE: 1630 | return "HackRF One"; 1631 | 1632 | case USB_BOARD_ID_RAD1O: 1633 | return "rad1o"; 1634 | 1635 | case USB_BOARD_ID_INVALID: 1636 | return "Invalid Board ID"; 1637 | 1638 | default: 1639 | return "Unknown Board ID"; 1640 | } 1641 | } 1642 | 1643 | const char* ADDCALL hackrf_filter_path_name(const enum rf_path_filter path) 1644 | { 1645 | switch(path) { 1646 | case RF_PATH_FILTER_BYPASS: 1647 | return "mixer bypass"; 1648 | case RF_PATH_FILTER_LOW_PASS: 1649 | return "low pass filter"; 1650 | case RF_PATH_FILTER_HIGH_PASS: 1651 | return "high pass filter"; 1652 | default: 1653 | return "invalid filter path"; 1654 | } 1655 | } 1656 | 1657 | /* Return final bw round down and less than expected bw. */ 1658 | uint32_t ADDCALL hackrf_compute_baseband_filter_bw_round_down_lt(const uint32_t bandwidth_hz) 1659 | { 1660 | const max2837_ft_t* p = max2837_ft; 1661 | while( p->bandwidth_hz != 0 ) 1662 | { 1663 | if( p->bandwidth_hz >= bandwidth_hz ) 1664 | { 1665 | break; 1666 | } 1667 | p++; 1668 | } 1669 | /* Round down (if no equal to first entry) */ 1670 | if(p != max2837_ft) 1671 | { 1672 | p--; 1673 | } 1674 | return p->bandwidth_hz; 1675 | } 1676 | 1677 | /* Return final bw. */ 1678 | uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t bandwidth_hz) 1679 | { 1680 | const max2837_ft_t* p = max2837_ft; 1681 | while( p->bandwidth_hz != 0 ) 1682 | { 1683 | if( p->bandwidth_hz >= bandwidth_hz ) 1684 | { 1685 | break; 1686 | } 1687 | p++; 1688 | } 1689 | 1690 | /* Round down (if no equal to first entry) and if > bandwidth_hz */ 1691 | if(p != max2837_ft) 1692 | { 1693 | if(p->bandwidth_hz > bandwidth_hz) 1694 | p--; 1695 | } 1696 | 1697 | return p->bandwidth_hz; 1698 | } 1699 | 1700 | #ifdef __cplusplus 1701 | } // __cplusplus defined. 1702 | #endif 1703 | 1704 | --------------------------------------------------------------------------------