From 4ce8bc17813ada105c1e8961f746984f5a4e283e Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sat, 3 Oct 2015 21:35:11 -0400 Subject: [PATCH] SDR Thread rework, async device init. - Preparing for new device selection/configuration dialog. --- CMakeLists.txt | 33 +- src/AppFrame.cpp | 46 +- src/CubicSDR.cpp | 235 ++++---- src/CubicSDR.h | 7 +- src/forms/SDRDevices/SDRDevices.cpp | 4 + src/forms/SDRDevices/SDRDevices.fbp | 769 ++++++++++++++++++++++++ src/forms/SDRDevices/SDRDevices.h | 1 + src/forms/SDRDevices/SDRDevicesForm.cpp | 69 +++ src/forms/SDRDevices/SDRDevicesForm.h | 60 ++ src/sdr/SoapySDRThread.cpp | 454 +++++++------- src/sdr/SoapySDRThread.h | 73 ++- 11 files changed, 1340 insertions(+), 411 deletions(-) create mode 100644 src/forms/SDRDevices/SDRDevices.cpp create mode 100644 src/forms/SDRDevices/SDRDevices.fbp create mode 100644 src/forms/SDRDevices/SDRDevices.h create mode 100644 src/forms/SDRDevices/SDRDevicesForm.cpp create mode 100644 src/forms/SDRDevices/SDRDevicesForm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index df8b3f5..4634cb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,6 +234,7 @@ ENDIF(USE_AUDIO_OSS) ENDIF(UNIX AND NOT APPLE) IF (APPLE) + SET(CMAKE_OSX_DEPLOYMENT_TARGET, "10.9") IF (USE_RTL_SDR) SET(RTLSDR_INCLUDE "/opt/local/include" CACHE FILEPATH "RTL-SDR Include Path") SET(RTLSDR_LIB "/opt/local/lib" CACHE FILEPATH "RTL-SDR Lib Path") @@ -301,6 +302,8 @@ SET (cubicsdr_sources src/process/FFTDataDistributor.cpp src/process/SpectrumVisualDataThread.cpp src/ui/GLPanel.cpp + src/forms/SDRDevices/SDRDevices.cpp + src/forms/SDRDevices/SDRDevicesForm.cpp external/rtaudio/RtAudio.cpp external/lodepng/lodepng.cpp external/tinyxml/tinyxml.cpp @@ -360,6 +363,8 @@ SET (cubicsdr_headers src/ui/UITestCanvas.h src/ui/UITestContext.cpp src/ui/UITestContext.h + src/forms/SDRDevices/SDRDevices.h + src/forms/SDRDevices/SDRDevicesForm.h external/rtaudio/RtAudio.h external/lodepng/lodepng.h external/tinyxml/tinyxml.h @@ -392,21 +397,23 @@ ENDIF() set(REG_EXT "[^/]*([.]cpp|[.]c|[.]h|[.]hpp)$") -SOURCE_GROUP("Base" REGULAR_EXPRESSION src/${REG_EXT}) -SOURCE_GROUP("SDR" REGULAR_EXPRESSION src/sdr/${REG_EXT}) -SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION src/demod/${REG_EXT}) -SOURCE_GROUP("Audio" REGULAR_EXPRESSION src/audio/${REG_EXT}) -SOURCE_GROUP("Utility" REGULAR_EXPRESSION src/util/${REG_EXT}) -SOURCE_GROUP("Panel" REGULAR_EXPRESSION src/panel/${REG_EXT}) -SOURCE_GROUP("Visual" REGULAR_EXPRESSION src/visual/${REG_EXT}) -SOURCE_GROUP("Process" REGULAR_EXPRESSION src/process/${REG_EXT}) -SOURCE_GROUP("UI" REGULAR_EXPRESSION src/ui/${REG_EXT}) -SOURCE_GROUP("_ext-RTAudio" REGULAR_EXPRESSION external/rtaudio/.*${REG_EXT}) -SOURCE_GROUP("_ext-LodePNG" REGULAR_EXPRESSION external/lodepng/.*${REG_EXT}) -SOURCE_GROUP("_ext-TinyXML" REGULAR_EXPRESSION external/tinyxml/.*${REG_EXT}) -SOURCE_GROUP("_ext-CubicVR2" REGULAR_EXPRESSION external/cubicvr2/.*${REG_EXT}) +SOURCE_GROUP("Base" REGULAR_EXPRESSION "src/${REG_EXT}") +SOURCE_GROUP("Forms\\SDRDevices" REGULAR_EXPRESSION "src/forms/SDRDevices/${REG_EXT}") +SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}") +SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}") +SOURCE_GROUP("Audio" REGULAR_EXPRESSION "src/audio/${REG_EXT}") +SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}") +SOURCE_GROUP("Visual" REGULAR_EXPRESSION "src/visual/${REG_EXT}") +SOURCE_GROUP("Panel" REGULAR_EXPRESSION "src/panel/${REG_EXT}") +SOURCE_GROUP("Process" REGULAR_EXPRESSION "src/process/${REG_EXT}") +SOURCE_GROUP("UI" REGULAR_EXPRESSION "src/ui/${REG_EXT}") +SOURCE_GROUP("_ext-RTAudio" REGULAR_EXPRESSION "external/rtaudio/.*${REG_EXT}") +SOURCE_GROUP("_ext-LodePNG" REGULAR_EXPRESSION "external/lodepng/.*${REG_EXT}") +SOURCE_GROUP("_ext-TinyXML" REGULAR_EXPRESSION "external/tinyxml/.*${REG_EXT}") +SOURCE_GROUP("_ext-CubicVR2" REGULAR_EXPRESSION "external/cubicvr2/.*${REG_EXT}") include_directories ( + ${PROJECT_SOURCE_DIR}/src/forms/SDRDevices ${PROJECT_SOURCE_DIR}/src/sdr ${PROJECT_SOURCE_DIR}/src/demod ${PROJECT_SOURCE_DIR}/src/audio diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 837f680..6ffbb89 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -292,29 +292,29 @@ AppFrame::AppFrame() : std::vector *devs = wxGetApp().getDevices(); std::vector::iterator devs_i; - if (devs->size() > 1) { - - menu = new wxMenu; - - int p = 0; - for (devs_i = devs->begin(); devs_i != devs->end(); devs_i++) { - std::string devName = (*devs_i)->getName(); - if ((*devs_i)->isAvailable()) { - devName.append(": "); - devName.append((*devs_i)->getProduct()); - devName.append(" ["); - devName.append((*devs_i)->getSerial()); - devName.append("]"); - } else { - devName.append(" (In Use?)"); - } - - menu->AppendRadioItem(wxID_DEVICE_ID + p, devName)->Check(wxGetApp().getDevice() == p); - p++; - } - - menuBar->Append(menu, wxT("Input &Device")); - } +// if (devs->size() > 1) { +// +// menu = new wxMenu; +// +// int p = 0; +// for (devs_i = devs->begin(); devs_i != devs->end(); devs_i++) { +// std::string devName = (*devs_i)->getName(); +// if ((*devs_i)->isAvailable()) { +// devName.append(": "); +// devName.append((*devs_i)->getProduct()); +// devName.append(" ["); +// devName.append((*devs_i)->getSerial()); +// devName.append("]"); +// } else { +// devName.append(" (In Use?)"); +// } +// +// menu->AppendRadioItem(wxID_DEVICE_ID + p, devName); //->Check(wxGetApp().getDevice() == p); +// p++; +// } +// +// menuBar->Append(menu, wxT("Input &Device")); +// } menu = new wxMenu; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 8d02046..67cbdc4 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -21,7 +21,7 @@ IMPLEMENT_APP(CubicSDR) CubicSDR::CubicSDR() : appframe(NULL), m_glContext(NULL), frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE), directSamplingMode(0), - sdrThread(NULL), sdrPostThread(NULL), spectrumVisualThread(NULL), demodVisualThread(NULL), pipeSDRCommand(NULL), pipeSDRIQData(NULL), pipeIQVisualData(NULL), pipeAudioVisualData(NULL), t_SDR(NULL), t_PostSDR(NULL) { + sdrThread(NULL), sdrPostThread(NULL), spectrumVisualThread(NULL), demodVisualThread(NULL), pipeSDRIQData(NULL), pipeIQVisualData(NULL), pipeAudioVisualData(NULL), t_SDR(NULL), t_PostSDR(NULL) { } @@ -81,12 +81,9 @@ bool CubicSDR::OnInit() { // I/Q Data pipeSDRIQData = new SDRThreadIQDataQueue(); - pipeSDRCommand = new SDRThreadCommandQueue(); - pipeSDRIQData->set_max_num_items(100); sdrThread = new SDRThread(); - sdrThread->setInputQueue("SDRCommandQueue",pipeSDRCommand); sdrThread->setOutputQueue("IQDataOutput",pipeSDRIQData); sdrPostThread = new SDRPostThread(); @@ -95,60 +92,13 @@ bool CubicSDR::OnInit() { sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); - std::vector::iterator devs_i; - -// SDRThread::enumerate_rtl(&devs); - devs = SDRThread::enumerate_devices(); - SDRDeviceInfo *dev = NULL; - - if (devs->size() > 1) { - wxArrayString choices; - for (devs_i = devs->begin(); devs_i != devs->end(); devs_i++) { - std::string devName = (*devs_i)->getName(); - if ((*devs_i)->isAvailable()) { -// devName.append(": "); -// devName.append((*devs_i)->getProduct()); -// devName.append(" ["); -// devName.append((*devs_i)->getSerial()); -// devName.append("]"); - } else { - devName.append(" (In Use?)"); - } - choices.Add(devName); - } - - int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices); - if (devId == -1) { // User chose to cancel - return false; - } - - dev = (*devs)[devId]; - - sdrThread->setDeviceId(devId); - } else if (devs->size() == 1) { - dev = (*devs)[0]; - } - - if (!dev) { - wxMessageDialog *info; - info = new wxMessageDialog(NULL, wxT("\x28\u256F\xB0\u25A1\xB0\uFF09\u256F\uFE35\x20\u253B\u2501\u253B"), wxT("RTL-SDR device not found"), wxOK | wxICON_ERROR); - info->ShowModal(); - return false; - } - t_PostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread); - t_SDR = new std::thread(&SDRThread::threadMain, sdrThread); t_SpectrumVisual = new std::thread(&SpectrumVisualDataThread::threadMain, spectrumVisualThread); t_DemodVisual = new std::thread(&SpectrumVisualDataThread::threadMain, demodVisualThread); + t_SDR = new std::thread(&SDRThread::threadMain, sdrThread); + appframe = new AppFrame(); - if (dev != NULL) { - appframe->initDeviceParams(dev->getDeviceId()); - DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); - ppm = devConfig->getPPM(); - offset = devConfig->getOffset(); - directSamplingMode = devConfig->getDirectSampling(); - } #ifdef __APPLE__ int main_policy; @@ -167,9 +117,10 @@ int CubicSDR::OnExit() { demodMgr.terminateAll(); std::cout << "Terminating SDR thread.." << std::endl; - sdrThread->terminate(); - t_SDR->join(); - + if (!sdrThread->isTerminated()) { + sdrThread->terminate(); + t_SDR->join(); + } std::cout << "Terminating SDR post-processing thread.." << std::endl; sdrPostThread->terminate(); t_PostSDR->join(); @@ -182,7 +133,6 @@ int CubicSDR::OnExit() { t_DemodVisual->join(); delete sdrThread; - delete t_SDR; delete sdrPostThread; delete t_PostSDR; @@ -192,8 +142,6 @@ int CubicSDR::OnExit() { delete t_DemodVisual; delete demodVisualThread; - delete pipeSDRCommand; - delete pipeIQVisualData; delete pipeAudioVisualData; delete pipeSDRIQData; @@ -235,14 +183,85 @@ bool CubicSDR::OnCmdLineParsed(wxCmdLineParser& parser) { return true; } +SDRDeviceInfo *CubicSDR::deviceSelector() { + std::vector::iterator devs_i; + + SDRDeviceInfo *dev = NULL; + + devs = SDRThread::enumerate_devices(); + + if (devs->size() > 1) { + wxArrayString choices; + for (devs_i = devs->begin(); devs_i != devs->end(); devs_i++) { + std::string devName = (*devs_i)->getName(); + if ((*devs_i)->isAvailable()) { +// devName.append(": "); +// devName.append((*devs_i)->getProduct()); +// devName.append(" ["); +// devName.append((*devs_i)->getSerial()); +// devName.append("]"); + } else { + devName.append(" (In Use?)"); + } + choices.Add(devName); + } + + int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices); + if (devId == -1) { // User chose to cancel + return NULL; + } + + dev = (*devs)[devId]; + } else if (devs->size() == 1) { + dev = (*devs)[0]; + } + + if (dev == NULL) { + wxMessageDialog *info; + info = new wxMessageDialog(NULL, wxT("\x28\u256F\xB0\u25A1\xB0\uFF09\u256F\uFE35\x20\u253B\u2501\u253B"), wxT("RTL-SDR device not found"), wxOK | wxICON_ERROR); + info->ShowModal(); + return NULL; + } + + return dev; +} + +void CubicSDR::sdrThreadNotify(SDRThread::SDRThreadState state, std::string message) { + if (state == SDRThread::SDR_THREAD_DEVICES_READY) { + SDRDeviceInfo *dev = deviceSelector(); + if (dev) { + appframe->initDeviceParams(dev->getDeviceId()); + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); + ppm = devConfig->getPPM(); + offset = devConfig->getOffset(); + directSamplingMode = devConfig->getDirectSampling(); + sdrThread->setDevice(dev); + if (t_SDR) { + delete t_SDR; + } + t_SDR = new std::thread(&SDRThread::threadMain, sdrThread); + } + } + if (state == SDRThread::SDR_THREAD_NO_DEVICES) { + + } + if (state == SDRThread::SDR_THREAD_TERMINATED) { + t_SDR->join(); + delete t_SDR; + } + if (state == SDRThread::SDR_THREAD_FAILED) { + wxMessageDialog *info; + info = new wxMessageDialog(NULL, message, wxT("Error initializing device"), wxOK | wxICON_ERROR); + info->ShowModal(); + } +} + void CubicSDR::setFrequency(long long freq) { if (freq < sampleRate / 2) { freq = sampleRate / 2; } frequency = freq; - SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE); - command.llong_value = freq; - pipeSDRCommand->push(command); + sdrThread->setFrequency(freq); } long long CubicSDR::getOffset() { @@ -251,21 +270,16 @@ long long CubicSDR::getOffset() { void CubicSDR::setOffset(long long ofs) { offset = ofs; - SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET); - command.llong_value = ofs; - pipeSDRCommand->push(command); - - SDRDeviceInfo *dev = (*getDevices())[getDevice()]; + sdrThread->setOffset(offset); + SDRDeviceInfo *dev = getDevice(); config.getDevice(dev->getDeviceId())->setOffset(ofs); } void CubicSDR::setDirectSampling(int mode) { directSamplingMode = mode; - SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING); - command.llong_value = mode; - pipeSDRCommand->push(command); + sdrThread->setDirectSampling(mode); - SDRDeviceInfo *dev = (*getDevices())[getDevice()]; + SDRDeviceInfo *dev = getDevice(); config.getDevice(dev->getDeviceId())->setDirectSampling(mode); } @@ -275,7 +289,7 @@ int CubicSDR::getDirectSampling() { void CubicSDR::setSwapIQ(bool swapIQ) { sdrPostThread->setSwapIQ(swapIQ); - SDRDeviceInfo *dev = (*getDevices())[getDevice()]; + SDRDeviceInfo *dev = getDevice(); config.getDevice(dev->getDeviceId())->setIQSwap(swapIQ); } @@ -287,6 +301,29 @@ long long CubicSDR::getFrequency() { return frequency; } +void CubicSDR::setSampleRate(long long rate_in) { + sampleRate = rate_in; + sdrThread->setSampleRate(sampleRate); + setFrequency(frequency); +} + +void CubicSDR::setDevice(int deviceId) { + +// SDRDeviceInfo *dev = (*getDevices())[deviceId]; +// DeviceConfig *devConfig = config.getDevice(dev->getDeviceId()); + +// sdrThread->setDevice(devConfig); +// +// setPPM(devConfig->getPPM()); +// setDirectSampling(devConfig->getDirectSampling()); +// setSwapIQ(devConfig->getIQSwap()); +// setOffset(devConfig->getOffset()); +} + +SDRDeviceInfo *CubicSDR::getDevice() { + return sdrThread->getDevice(); +} + ScopeVisualProcessor *CubicSDR::getScopeProcessor() { return &scopeProcessor; } @@ -327,14 +364,6 @@ void CubicSDR::bindDemodulator(DemodulatorInstance *demod) { sdrPostThread->bindDemodulator(demod); } -void CubicSDR::setSampleRate(long long rate_in) { - sampleRate = rate_in; - SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE); - command.llong_value = rate_in; - pipeSDRCommand->push(command); - setFrequency(frequency); -} - long long CubicSDR::getSampleRate() { return sampleRate; } @@ -351,57 +380,31 @@ std::vector* CubicSDR::getDevices() { return devs; } -void CubicSDR::setDevice(int deviceId) { - sdrThread->setDeviceId(deviceId); - SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE); - command.llong_value = deviceId; - pipeSDRCommand->push(command); - - SDRDeviceInfo *dev = (*getDevices())[deviceId]; - DeviceConfig *devConfig = config.getDevice(dev->getDeviceId()); - - setPPM(devConfig->getPPM()); - setDirectSampling(devConfig->getDirectSampling()); - setSwapIQ(devConfig->getIQSwap()); - setOffset(devConfig->getOffset()); -} - -int CubicSDR::getDevice() { - return sdrThread->getDeviceId(); -} AppConfig *CubicSDR::getConfig() { return &config; } void CubicSDR::saveConfig() { - config.save(); +#warning Configuration Save Disabled +// config.save(); } void CubicSDR::setPPM(int ppm_in) { - if (sdrThread->getDeviceId() < 0) { - return; - } ppm = ppm_in; + sdrThread->setPPM(ppm); - SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM); - command.llong_value = ppm; - pipeSDRCommand->push(command); - - SDRDeviceInfo *dev = (*getDevices())[getDevice()]; - - config.getDevice(dev->getDeviceId())->setPPM(ppm_in); + SDRDeviceInfo *dev = getDevice(); + if (dev) { + config.getDevice(dev->getDeviceId())->setPPM(ppm_in); + } } int CubicSDR::getPPM() { - if (sdrThread->getDeviceId() < 0) { - return 0; + SDRDeviceInfo *dev = sdrThread->getDevice(); + if (dev) { + ppm = config.getDevice(dev->getDeviceId())->getPPM(); } - SDRDeviceInfo *dev = (*getDevices())[getDevice()]; - - SDRThreadCommand command_ppm(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM); - ppm = config.getDevice(dev->getDeviceId())->getPPM(); - return ppm; } diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 2b53970..d7ae7fd 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -42,6 +42,9 @@ public: virtual void OnInitCmdLine(wxCmdLineParser& parser); virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + SDRDeviceInfo *deviceSelector(); + void sdrThreadNotify(SDRThread::SDRThreadState state, std::string message); + void setFrequency(long long freq); long long getFrequency(); @@ -59,7 +62,7 @@ public: std::vector *getDevices(); void setDevice(int deviceId); - int getDevice(); + SDRDeviceInfo * getDevice(); ScopeVisualProcessor *getScopeProcessor(); SpectrumVisualProcessor *getSpectrumProcessor(); @@ -105,7 +108,7 @@ private: SpectrumVisualDataThread *spectrumVisualThread; SpectrumVisualDataThread *demodVisualThread; - SDRThreadCommandQueue* pipeSDRCommand; +// SDRThreadCommandQueue* pipeSDRCommand; SDRThreadIQDataQueue* pipeSDRIQData; DemodulatorThreadInputQueue* pipeIQVisualData; DemodulatorThreadOutputQueue* pipeAudioVisualData; diff --git a/src/forms/SDRDevices/SDRDevices.cpp b/src/forms/SDRDevices/SDRDevices.cpp new file mode 100644 index 0000000..a76f317 --- /dev/null +++ b/src/forms/SDRDevices/SDRDevices.cpp @@ -0,0 +1,4 @@ + +#include "SDRDevices.h" + +#include "SDRDevicesForm.h" \ No newline at end of file diff --git a/src/forms/SDRDevices/SDRDevices.fbp b/src/forms/SDRDevices/SDRDevices.fbp new file mode 100644 index 0000000..fd35de0 --- /dev/null +++ b/src/forms/SDRDevices/SDRDevices.fbp @@ -0,0 +1,769 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + SDRDevicesForm + 1000 + none + 0 + SDRDevicesForm + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + devFrame + + 692,467 + wxDEFAULT_FRAME_STYLE + + CubicSDR :: SDR Devices + + + + wxTAB_TRAVERSAL + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + 1 + + 0 + wxID_ANY + + + devStatusBar + protected + + + wxST_SIZEGRIP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + devFrameSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + devTree + 1 + + + protected + 1 + + Resizable + 1 + + wxTR_DEFAULT_STYLE + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 2 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 0 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + devTabs + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Device + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 0 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + devInfoPanel + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + devInfoSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_DevInfoList + 1 + + + protected + 1 + + Resizable + 1 + + wxLC_ICON + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Parameters + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + devParamsPanel + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + devParamsSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_ParamInfoList + 1 + + + protected + 1 + + Resizable + 1 + + wxLC_ICON + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + + 0 + wxID_ANY + dMenu + + + devMenuBar + protected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + File + devFileMenu + protected + + + Edit + devEditMenu + protected + + + + + diff --git a/src/forms/SDRDevices/SDRDevices.h b/src/forms/SDRDevices/SDRDevices.h new file mode 100644 index 0000000..7b9637e --- /dev/null +++ b/src/forms/SDRDevices/SDRDevices.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/src/forms/SDRDevices/SDRDevicesForm.cpp b/src/forms/SDRDevices/SDRDevicesForm.cpp new file mode 100644 index 0000000..3794d03 --- /dev/null +++ b/src/forms/SDRDevices/SDRDevicesForm.cpp @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Aug 23 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "SDRDevicesForm.h" + +/////////////////////////////////////////////////////////////////////////// + +devFrame::devFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + devStatusBar = this->CreateStatusBar( 1, wxST_SIZEGRIP, wxID_ANY ); + wxBoxSizer* devFrameSizer; + devFrameSizer = new wxBoxSizer( wxHORIZONTAL ); + + devTree = new wxTreeCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE ); + devFrameSizer->Add( devTree, 1, wxEXPAND, 5 ); + + devTabs = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + devInfoPanel = new wxPanel( devTabs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* devInfoSizer; + devInfoSizer = new wxBoxSizer( wxVERTICAL ); + + m_DevInfoList = new wxListCtrl( devInfoPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ICON ); + devInfoSizer->Add( m_DevInfoList, 1, wxEXPAND, 5 ); + + + devInfoPanel->SetSizer( devInfoSizer ); + devInfoPanel->Layout(); + devInfoSizer->Fit( devInfoPanel ); + devTabs->AddPage( devInfoPanel, wxT("Device"), false ); + devParamsPanel = new wxPanel( devTabs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* devParamsSizer; + devParamsSizer = new wxBoxSizer( wxVERTICAL ); + + m_ParamInfoList = new wxListCtrl( devParamsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ICON ); + devParamsSizer->Add( m_ParamInfoList, 1, wxEXPAND, 5 ); + + + devParamsPanel->SetSizer( devParamsSizer ); + devParamsPanel->Layout(); + devParamsSizer->Fit( devParamsPanel ); + devTabs->AddPage( devParamsPanel, wxT("Parameters"), false ); + + devFrameSizer->Add( devTabs, 2, wxEXPAND, 5 ); + + + this->SetSizer( devFrameSizer ); + this->Layout(); + devMenuBar = new wxMenuBar( 0 ); + devFileMenu = new wxMenu(); + devMenuBar->Append( devFileMenu, wxT("File") ); + + devEditMenu = new wxMenu(); + devMenuBar->Append( devEditMenu, wxT("Edit") ); + + this->SetMenuBar( devMenuBar ); + + + this->Centre( wxBOTH ); +} + +devFrame::~devFrame() +{ +} diff --git a/src/forms/SDRDevices/SDRDevicesForm.h b/src/forms/SDRDevices/SDRDevicesForm.h new file mode 100644 index 0000000..7e196b7 --- /dev/null +++ b/src/forms/SDRDevices/SDRDevicesForm.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Aug 23 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __SDRDEVICESFORM_H__ +#define __SDRDEVICESFORM_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class devFrame +/////////////////////////////////////////////////////////////////////////////// +class devFrame : public wxFrame +{ + private: + + protected: + wxStatusBar* devStatusBar; + wxTreeCtrl* devTree; + wxNotebook* devTabs; + wxPanel* devInfoPanel; + wxListCtrl* m_DevInfoList; + wxPanel* devParamsPanel; + wxListCtrl* m_ParamInfoList; + wxMenuBar* devMenuBar; + wxMenu* devFileMenu; + wxMenu* devEditMenu; + + public: + + devFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("CubicSDR :: SDR Devices"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 692,467 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); + + ~devFrame(); + +}; + +#endif //__SDRDEVICESFORM_H__ diff --git a/src/sdr/SoapySDRThread.cpp b/src/sdr/SoapySDRThread.cpp index 562a193..710547b 100644 --- a/src/sdr/SoapySDRThread.cpp +++ b/src/sdr/SoapySDRThread.cpp @@ -4,10 +4,6 @@ #include "CubicSDR.h" #include -#include -#include -#include -#include std::vector SDRThread::factories; std::vector SDRThread::modules; @@ -15,14 +11,32 @@ std::vector SDRThread::devs; SDRThread::SDRThread() : IOThread() { - offset.store(0); - deviceId.store(-1); -// dev = NULL; + device = NULL; + + deviceConfig.store(NULL); + deviceInfo.store(NULL); + sampleRate.store(DEFAULT_SAMPLE_RATE); + frequency.store(0); + offset.store(0); + ppm.store(0); + direct_sampling_mode.store(0); + + numElems.store(0); + + rate_changed.store(false); + freq_changed.store(false); + offset_changed.store(false); + ppm_changed .store(false); + direct_sampling_changed.store(false); + device_changed.store(false); + + hasPPM.store(false); + hasHardwareDC.store(false); } SDRThread::~SDRThread() { -// rtlsdr_close(dev); + } @@ -145,6 +159,130 @@ std::vector *SDRThread::enumerate_devices() { return &SDRThread::devs; } +void SDRThread::init() { + SDRDeviceInfo *devInfo = deviceInfo.load(); + deviceConfig.store(wxGetApp().getConfig()->getDevice(devInfo->getDeviceId())); + DeviceConfig *devConfig = deviceConfig.load(); + + frequency = wxGetApp().getConfig()->getCenterFreq(); + ppm.store(devConfig->getPPM()); + direct_sampling_mode.store(devConfig->getDirectSampling()); + + std::string driverName = devInfo->getDriver(); + + offset = devConfig->getOffset(); + wxGetApp().setSwapIQ(devConfig->getIQSwap()); + + SoapySDR::Kwargs args = devInfo->getDeviceArgs(); + + args["direct_samp"] = std::to_string(devConfig->getDirectSampling()); + + if (driverName == "rtl" || driverName == "rtlsdr") { + args["buffers"] = "6"; + args["buflen"] = "16384"; + hasPPM = true; + } else { + hasPPM = false; + } + + device = SoapySDR::Device::make(args); + stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector(), devInfo->getStreamArgs()); + + device->activateStream(stream); + device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); + device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); + if (hasPPM) { + device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); + } + device->setGainMode(SOAPY_SDR_RX,0,true); + hasHardwareDC = devInfo->hasHardwareDC(); + + numElems = getOptimalElementCount(sampleRate.load(), 60); + + buffs[0] = malloc(numElems * 2 * sizeof(float)); +} + +void SDRThread::deinit() { + device->deactivateStream(stream); + device->closeStream(stream); + SoapySDR::Device::unmake(device); + free(buffs[0]); +} + +void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) { + int flags; + long long timeNs; + + SDRThreadIQData *dataOut = buffers.getBuffer(); + if (dataOut->data.size() != numElems * 2) { + dataOut->data.resize(numElems * 2); + } + + int n_read = 0; + while (n_read != numElems) { + int n_stream_read = device->readStream(stream, buffs, numElems-n_read, flags, timeNs); + if (n_stream_read > 0) { + memcpy(&dataOut->data[n_read * 2], buffs[0], n_stream_read * sizeof(float) * 2); + n_read += n_stream_read; + } else { + dataOut->data.resize(n_read); + break; + } + } + + // std::cout << n_read << std::endl; + + if (n_read > 0) { + dataOut->setRefCount(1); + dataOut->frequency = frequency; + dataOut->sampleRate = sampleRate.load(); + dataOut->dcCorrected = hasHardwareDC; + + iqDataOutQueue->push(dataOut); + } +} + +void SDRThread::readLoop() { + SDRThreadIQDataQueue* iqDataOutQueue = (SDRThreadIQDataQueue*) getOutputQueue("IQDataOutput"); + + if (iqDataOutQueue == NULL) { + return; + } + + while (!terminated.load()) { + if (offset_changed.load()) { + if (!freq_changed.load()) { + frequency.store(frequency.load()); + freq_changed.store(true); + } + offset_changed.store(false); + } + if (rate_changed.load()) { + device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); + sampleRate.store(device->getSampleRate(SOAPY_SDR_RX,0)); + numElems.store(getOptimalElementCount(sampleRate.load(), 60)); + free(buffs[0]); + buffs[0] = malloc(numElems.load() * 2 * sizeof(float)); + rate_changed.store(false); + } + if (ppm_changed.load() && hasPPM.load()) { + device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load()); + direct_sampling_changed.store(false); + } + if (freq_changed.load()) { + device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load()); + freq_changed.store(false); + } + if (direct_sampling_changed.load()) { + // rtlsdr_set_direct_sampling(dev, direct_sampling_mode); + } + + readStream(iqDataOutQueue); + } + buffers.purge(); +} + + void SDRThread::run() { //#ifdef __APPLE__ // pthread_t tID = pthread_self(); // ID of this thread @@ -153,242 +291,98 @@ void SDRThread::run() { // pthread_setschedparam(tID, SCHED_FIFO, &prio); //#endif - std::cout << "SDR thread initializing.." << std::endl; + std::cout << "SDR thread starting." << std::endl; + terminated.store(false); - if (deviceId == -1 && devs.size() == 0) { - std::cout << "No devices found.. SDR Thread exiting.." << std::endl; - return; + if (deviceInfo.load() != NULL) { + std::cout << "device init()" << std::endl; + init(); + std::cout << "starting readLoop()" << std::endl; + readLoop(); + std::cout << "readLoop() ended." << std::endl; + deinit(); + std::cout << "device deinit()" << std::endl; } else { - if (deviceId == -1) { - deviceId = 0; - } - std::cout << "Using device #" << deviceId << std::endl; - } - - DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devs[deviceId]->getDeviceId()); - - long long frequency = wxGetApp().getConfig()->getCenterFreq(); - int ppm = devConfig->getPPM(); - int direct_sampling_mode = devConfig->getDirectSampling(); - int numElems = 0; - bool hasPPM = false; - bool hasHardwareDC = false; - - offset.store(devConfig->getOffset()); - wxGetApp().setSwapIQ(devConfig->getIQSwap()); - - - SDRDeviceInfo *dev = devs[deviceId]; - SoapySDR::Kwargs args = dev->getDeviceArgs(); - - std::string driverName = dev->getDriver(); - - if (driverName == "rtl" || driverName == "rtlsdr") { - hasPPM = true; + std::cout << "Device setting not found, enumerating." << std::endl; + SDRThread::enumerate_devices(); + std::cout << "Reporting enumeration complete." << std::endl; + wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_DEVICES_READY, "Devices Ready."); + terminated.store(true); + return; } - args["direct_samp"] = std::to_string(devConfig->getDirectSampling()); - args["buffers"] = "6"; - args["buflen"] = "16384"; - SoapySDR::Device *device = SoapySDR::Device::make(args); - - SoapySDR::Stream *stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector(), dev->getStreamArgs()); - - device->activateStream(stream); - device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); - device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); - if (hasPPM) { - device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); - } - - device->setGainMode(SOAPY_SDR_RX,0,true); - hasHardwareDC = dev->hasHardwareDC(); - - numElems = getOptimalElementCount(sampleRate.load(), 60); - - void *buffs[1]; - buffs[0] = malloc(numElems * 2 * sizeof(float)); - - int flags; - long long timeNs; - - ReBuffer buffers; - - SDRThreadIQDataQueue* iqDataOutQueue = (SDRThreadIQDataQueue*) getOutputQueue("IQDataOutput"); - SDRThreadCommandQueue* cmdQueue = (SDRThreadCommandQueue*) getInputQueue("SDRCommandQueue"); - - while (!terminated) { - if (!cmdQueue->empty()) { - bool freq_changed = false; - bool offset_changed = false; - bool rate_changed = false; - bool device_changed = false; - bool ppm_changed = false; - bool direct_sampling_changed = false; - long long new_freq = frequency; - long long new_offset = offset.load(); - long long new_rate = sampleRate.load(); - int new_device = deviceId; - int new_ppm = ppm; - - while (!cmdQueue->empty()) { - SDRThreadCommand command; - cmdQueue->pop(command); - - switch (command.cmd) { - case SDRThreadCommand::SDR_THREAD_CMD_TUNE: - freq_changed = true; - new_freq = command.llong_value; - if (new_freq < sampleRate.load() / 2) { - new_freq = sampleRate.load() / 2; - } - break; - case SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET: - offset_changed = true; - new_offset = command.llong_value; - std::cout << "Set offset: " << new_offset << std::endl; - break; - case SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE: - rate_changed = true; - new_rate = command.llong_value; - std::cout << "Set sample rate: " << new_rate << std::endl; - break; - case SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE: - device_changed = true; - new_device = (int) command.llong_value; - std::cout << "Set device: " << new_device << std::endl; - break; - case SDRThreadCommand::SDR_THREAD_CMD_SET_PPM: - ppm_changed = true; - new_ppm = (int) command.llong_value; - //std::cout << "Set PPM: " << new_ppm << std::endl; - break; - case SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING: - direct_sampling_mode = (int)command.llong_value; - direct_sampling_changed = true; - break; - default: - break; - } - } - - if (device_changed) { - device->deactivateStream(stream); - device->closeStream(stream); - SoapySDR::Device::unmake(device); - - deviceId = new_device; - dev = devs[deviceId]; - device_changed = false; - - SoapySDR::Kwargs args = dev->getDeviceArgs(); - args["direct_samp"] = std::to_string(devConfig->getDirectSampling()); - args["buffers"] = "6"; - args["buflen"] = "16384"; - - device = SoapySDR::Device::make(args); - - device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); - device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); - if (hasPPM) { - device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); - } - device->setGainMode(SOAPY_SDR_RX,0, true); - hasHardwareDC = dev->hasHardwareDC(); - if (hasHardwareDC) { - device->setDCOffsetMode(SOAPY_SDR_RX, 0, true); - std::cout << "Hardware DC offset support detected; internal DC offset compensation disabled." << std::endl; - } - - SoapySDR::Stream *stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector(), dev->getStreamArgs()); - device->activateStream(stream); - - } - - if (offset_changed) { - if (!freq_changed) { - new_freq = frequency; - freq_changed = true; - } - offset.store(new_offset); - } - if (rate_changed) { - device->setSampleRate(SOAPY_SDR_RX,0,new_rate); - sampleRate.store(device->getSampleRate(SOAPY_SDR_RX,0)); - - numElems = getOptimalElementCount(sampleRate.load(), 60); - free(buffs[0]); - buffs[0] = malloc(numElems * 2 * sizeof(float)); - } - if (freq_changed) { - frequency = new_freq; - device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); - } - if (ppm_changed && hasPPM) { - ppm = new_ppm; - device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); - } - if (direct_sampling_changed) { -// rtlsdr_set_direct_sampling(dev, direct_sampling_mode); - } - } - - - SDRThreadIQData *dataOut = buffers.getBuffer(); - if (dataOut->data.size() != numElems * 2) { - dataOut->data.resize(numElems * 2); - } - - int n_read = 0; - while (n_read != numElems) { - int n_stream_read = device->readStream(stream, buffs, numElems-n_read, flags, timeNs); - if (n_stream_read > 0) { - memcpy(&dataOut->data[n_read * 2], buffs[0], n_stream_read * sizeof(float) * 2); - n_read += n_stream_read; - } else { - dataOut->data.resize(n_read); - break; - } - } - -// std::cout << n_read << std::endl; - - if (n_read > 0) { - dataOut->setRefCount(1); - dataOut->frequency = frequency; - dataOut->sampleRate = sampleRate.load(); - dataOut->dcCorrected = hasHardwareDC; - - if (iqDataOutQueue != NULL) { - iqDataOutQueue->push(dataOut); - } else { - dataOut->setRefCount(0); - } - } else { - dataOut->setRefCount(0); - } - } - device->deactivateStream(stream); - device->closeStream(stream); - SoapySDR::Device::unmake(device); - free(buffs[0]); - - buffers.purge(); std::cout << "SDR thread done." << std::endl; + + if (!terminated.load()) { + terminated.store(true); + wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_TERMINATED, "Done."); + } } -int SDRThread::getDeviceId() const { - return deviceId.load(); +SDRDeviceInfo *SDRThread::getDevice() { + return deviceInfo.load(); } -void SDRThread::setDeviceId(int deviceId) { - this->deviceId.store(deviceId); +void SDRThread::setDevice(SDRDeviceInfo *dev) { + deviceInfo.store(dev); + deviceConfig.store(wxGetApp().getConfig()->getDevice(dev->getDeviceId())); } int SDRThread::getOptimalElementCount(long long sampleRate, int fps) { int elemCount = (int)floor((double)sampleRate/(double)fps); elemCount = int(ceil((double)elemCount/512.0)*512.0); - std::cout << "calculated optimal element count of " << elemCount << std::endl; + std::cout << "Calculated optimal element count of " << elemCount << std::endl; return elemCount; } + +void SDRThread::setFrequency(long long freq) { + if (freq < sampleRate.load() / 2) { + freq = sampleRate.load() / 2; + } + frequency.store(freq); + freq_changed.store(true); +} + +long long SDRThread::getFrequency() { + return frequency.load(); +} + +void SDRThread::setOffset(long long ofs) { + offset.store(ofs); + offset_changed.store(true); + std::cout << "Set offset: " << offset.load() << std::endl; +} + +long long SDRThread::getOffset() { + return offset.load(); +} + +void SDRThread::setSampleRate(int rate) { + sampleRate.store(rate); + rate_changed = true; + std::cout << "Set sample rate: " << sampleRate.load() << std::endl; +} +int SDRThread::getSampleRate() { + return sampleRate.load(); +} + +void SDRThread::setPPM(int ppm) { + this->ppm.store(ppm); + ppm_changed.store(true); + std::cout << "Set PPM: " << this->ppm.load() << std::endl; +} + +int SDRThread::getPPM() { + return ppm.load(); +} + +void SDRThread::setDirectSampling(int dsMode) { + direct_sampling_mode.store(dsMode); + direct_sampling_changed.store(true); + std::cout << "Set direct sampling mode: " << this->direct_sampling_mode.load() << std::endl; +} + +int SDRThread::getDirectSampling() { + return direct_sampling_mode.load(); +} diff --git a/src/sdr/SoapySDRThread.h b/src/sdr/SoapySDRThread.h index f75c575..327f25d 100644 --- a/src/sdr/SoapySDRThread.h +++ b/src/sdr/SoapySDRThread.h @@ -5,33 +5,19 @@ #include "ThreadQueue.h" #include "DemodulatorMgr.h" #include "SDRDeviceInfo.h" +#include "AppConfig.h" -class SDRThreadCommand { -public: - enum SDRThreadCommandEnum { - SDR_THREAD_CMD_NULL, SDR_THREAD_CMD_TUNE, SDR_THREAD_CMD_SET_OFFSET, SDR_THREAD_CMD_SET_SAMPLERATE, SDR_THREAD_CMD_SET_PPM, SDR_THREAD_CMD_SET_DEVICE, SDR_THREAD_CMD_SET_DIRECT_SAMPLING - }; +#include +#include +#include +#include - SDRThreadCommand() : - cmd(SDR_THREAD_CMD_NULL), llong_value(0) { - - } - - SDRThreadCommand(SDRThreadCommandEnum cmd) : - cmd(cmd), llong_value(0) { - - } - - SDRThreadCommandEnum cmd; - long long llong_value; -}; class SDRThreadIQData: public ReferenceCounter { public: long long frequency; long long sampleRate; bool dcCorrected; -// std::vector data; std::vector data; SDRThreadIQData() : @@ -49,27 +35,60 @@ public: } }; -typedef ThreadQueue SDRThreadCommandQueue; typedef ThreadQueue SDRThreadIQDataQueue; class SDRThread : public IOThread { +private: + void init(); + void deinit(); + void readStream(SDRThreadIQDataQueue* iqDataOutQueue); + void readLoop(); + public: SDRThread(); ~SDRThread(); - + enum SDRThreadState { SDR_THREAD_DEVICES_READY, SDR_THREAD_NO_DEVICES, SDR_THREAD_TERMINATED, SDR_THREAD_FAILED }; + static std::vector *enumerate_devices(); void run(); - - int getDeviceId() const; - void setDeviceId(int deviceId); - int getOptimalElementCount(long long sampleRate, int fps); + SDRDeviceInfo *getDevice(); + void setDevice(SDRDeviceInfo *dev); + int getOptimalElementCount(long long sampleRate, int fps); + + void setFrequency(long long freq); + long long getFrequency(); + + void setOffset(long long ofs); + long long getOffset(); + + void setSampleRate(int rate); + int getSampleRate(); + + void setPPM(int ppm); + int getPPM(); + + void setDirectSampling(int dsMode); + int getDirectSampling(); + protected: static std::vector factories; static std::vector modules; static std::vector devs; + SoapySDR::Stream *stream; + SoapySDR::Device *device; + void *buffs[1]; + ReBuffer buffers; + + std::atomic deviceConfig; + std::atomic deviceInfo; + std::atomic sampleRate; - std::atomic_llong offset; - std::atomic_int deviceId; + std::atomic_llong frequency, offset; + std::atomic_int ppm, direct_sampling_mode, numElems; + std::atomic_bool hasPPM, hasHardwareDC; + + std::atomic_bool rate_changed, freq_changed, offset_changed, + ppm_changed, direct_sampling_changed, device_changed; };