diff --git a/README.md b/README.md index 2eb82a8..a60e845 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,33 @@ Features and Status: - [ ] Playback - Audio - [ ] Recording + - Implement digital demodulation supported by liquid-dsp: (http://liquidsdr.org/doc/modem.html) + - [ ] Demodulator Lab + - [ ] Toggle current demodulator exclusively into "Lab" mode + - [ ] Additional visualizations for audio and I/Q stream + - [ ] Audio Spectrum + - [ ] Constellation / X-Y Scope + - [ ] Digital demodulation status and controls + - [ ] Demodulator AGC, Equalization controls + - [ ] Lock AGC and Equalization when digital lock obtained + - [ ] Digital output + - [ ] Output console + - [ ] Capture file (auto?) + - [ ] Network output + - [ ] Block device output + - [ ] Digital modes available to implement + - [ ] PSK + - [ ] DPSK + - [ ] ASK + - [ ] QAM + - [ ] APSK + - [ ] BPSK + - [ ] QPSK + - [ ] OOK + - [ ] SQAM + - [ ] Star Modem + - [ ] MFSK + - [ ] CPFSK - Optimization - [x] Eliminate large waterfall texture uploads - [ ] Update visuals to OpenGL 3.x @@ -93,8 +120,9 @@ Features and Status: - [ ] Resolve driver/platform vertical sync issues - [ ] Group and divide IQ data distribution workload instead of 100% distribution per instance -Advanced Goals: ---------------- + +Advanced Goals and ideas: +------------------------ - Design a plan for expansion via modules (dylib/dll/lua) - Support shell-based stdin/stdout tools for direct output/playback to/from CLI audio processing apps (i.e. DSD on OSX) - Update visuals to support OpenGL ES @@ -102,8 +130,6 @@ Advanced Goals: - Support multiple simultaneous device usage * Categorize devices by antenna connections * Allow locked frequencies to activate unused devices to continue demodulation on same antenna - - Implement digital demodulation supported by liquid-dsp: (http://liquidsdr.org/doc/modem.html) - * PSK, DPSK, ASK, QAM, APSK, BPSK, QPSK, OOK, SQAM, Star Modem(?) - Integrate LUA * Expose liquid-dsp functionality * Scriptable liquid-dsp demodulation diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index 88df676..9b057ee 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -1,36 +1,76 @@ #include "AppConfig.h" +#include "CubicSDR.h" -DeviceConfig::DeviceConfig() : ppm(0), deviceId("") { - +DeviceConfig::DeviceConfig() : deviceId("") { + ppm.store(0); + directSampling.store(false); + offset.store(0); } -DeviceConfig::DeviceConfig(std::string deviceId) : ppm(0) { +DeviceConfig::DeviceConfig(std::string deviceId) : DeviceConfig() { this->deviceId = deviceId; } void DeviceConfig::setPPM(int ppm) { - this->ppm = ppm; + this->ppm.store(ppm); } int DeviceConfig::getPPM() { - return ppm; + return ppm.load(); +} + +void DeviceConfig::setDirectSampling(int mode) { + directSampling.store(mode); +} + +int DeviceConfig::getDirectSampling() { + return directSampling.load(); +} + +void DeviceConfig::setOffset(long long offset) { + this->offset.store(offset); +} + +long long DeviceConfig::getOffset() { + return offset.load(); +} + +void DeviceConfig::setIQSwap(bool iqSwap) { + this->iqSwap.store(iqSwap); +} + +bool DeviceConfig::getIQSwap() { + return iqSwap.load(); } void DeviceConfig::setDeviceId(std::string deviceId) { + busy_lock.lock(); this->deviceId = deviceId; + busy_lock.unlock(); } std::string DeviceConfig::getDeviceId() { - return deviceId; + std::string tmp; + + busy_lock.lock(); + tmp = deviceId; + busy_lock.unlock(); + + return tmp; } void DeviceConfig::save(DataNode *node) { - node->newChild("id")->element()->set(deviceId); - DataNode *ppm_node = node->newChild("ppm"); - ppm_node->element()->set((int)ppm); + busy_lock.lock(); + *node->newChild("id") = deviceId; + *node->newChild("ppm") = (int)ppm; + *node->newChild("iq_swap") = iqSwap; + *node->newChild("direct_sampling") = directSampling; + *node->newChild("offset") = offset; + busy_lock.unlock(); } void DeviceConfig::load(DataNode *node) { + busy_lock.lock(); if (node->hasAnother("ppm")) { DataNode *ppm_node = node->getNext("ppm"); int ppmValue = 0; @@ -38,11 +78,59 @@ void DeviceConfig::load(DataNode *node) { setPPM(ppmValue); std::cout << "Loaded PPM for device '" << deviceId << "' at " << ppmValue << "ppm" << std::endl; } + if (node->hasAnother("iq_swap")) { + DataNode *iq_swap_node = node->getNext("iq_swap"); + int iqSwapValue = 0; + iq_swap_node->element()->get(iqSwapValue); + setIQSwap(iqSwapValue?true:false); + std::cout << "Loaded I/Q Swap for device '" << deviceId << "' as " << (iqSwapValue?"swapped":"not swapped") << std::endl; + } + if (node->hasAnother("direct_sampling")) { + DataNode *direct_sampling_node = node->getNext("direct_sampling"); + int directSamplingValue = 0; + direct_sampling_node->element()->get(directSamplingValue); + setDirectSampling(directSamplingValue); + std::cout << "Loaded Direct Sampling Mode for device '" << deviceId << "': "; + switch (directSamplingValue) { + case 0: + std::cout << "off" << std::endl; + break; + case 1: + std::cout << "I-ADC" << std::endl; + break; + case 2: + std::cout << "Q-ADC" << std::endl; + break; + + } + } + if (node->hasAnother("offset")) { + DataNode *offset_node = node->getNext("offset"); + long long offsetValue = 0; + offset_node->element()->get(offsetValue); + setOffset(offsetValue); + std::cout << "Loaded offset for device '" << deviceId << "' at " << offsetValue << "Hz" << std::endl; + } + busy_lock.unlock(); +} + +AppConfig::AppConfig() { + winX.store(0); + winY.store(0); + winW.store(0); + winH.store(0); + winMax.store(false); + themeId.store(0); + snap.store(1); } + DeviceConfig *AppConfig::getDevice(std::string deviceId) { - DeviceConfig *conf = &deviceConfig[deviceId]; + if (deviceConfig.find(deviceId) == deviceConfig.end()) { + deviceConfig[deviceId] = new DeviceConfig(); + } + DeviceConfig *conf = deviceConfig[deviceId]; conf->setDeviceId(deviceId); return conf; } @@ -65,18 +153,76 @@ std::string AppConfig::getConfigDir() { return dataDir; } + +void AppConfig::setWindow(wxPoint winXY, wxSize winWH) { + winX.store(winXY.x); + winY.store(winXY.y); + winW.store(winWH.x); + winH.store(winWH.y); +} + +void AppConfig::setWindowMaximized(bool max) { + winMax.store(max); +} + +bool AppConfig::getWindowMaximized() { + return winMax.load(); +} + +wxRect *AppConfig::getWindow() { + wxRect *r = NULL; + if (winH.load() && winW.load()) { + r = new wxRect(winX.load(),winY.load(),winW.load(),winH.load()); + } + return r; +} + + +void AppConfig::setTheme(int themeId) { + this->themeId.store(themeId); +} + +int AppConfig::getTheme() { + return themeId.load(); +} + + +void AppConfig::setSnap(long long snapVal) { + this->snap.store(snapVal); +} + +long long AppConfig::getSnap() { + return snap.load(); +} + + bool AppConfig::save() { DataTree cfg; cfg.rootNode()->setName("cubicsdr_config"); + + if (winW.load() && winH.load()) { + DataNode *window_node = cfg.rootNode()->newChild("window"); + + *window_node->newChild("x") = winX.load(); + *window_node->newChild("y") = winY.load(); + *window_node->newChild("w") = winW.load(); + *window_node->newChild("h") = winH.load(); + + *window_node->newChild("max") = winMax.load(); + *window_node->newChild("theme") = themeId.load(); + *window_node->newChild("snap") = snap.load(); + } + DataNode *devices_node = cfg.rootNode()->newChild("devices"); - std::map::iterator device_config_i; + std::map::iterator device_config_i; for (device_config_i = deviceConfig.begin(); device_config_i != deviceConfig.end(); device_config_i++) { DataNode *device_node = devices_node->newChild("device"); - device_config_i->second.save(device_node); + device_config_i->second->save(device_node); } + std::string cfgFileDir = getConfigDir(); wxFileName cfgFile = wxFileName(cfgFileDir, "config.xml"); @@ -110,6 +256,42 @@ bool AppConfig::load() { return false; } + if (cfg.rootNode()->hasAnother("window")) { + int x,y,w,h; + int max; + + DataNode *win_node = cfg.rootNode()->getNext("window"); + + if (win_node->hasAnother("w") && win_node->hasAnother("h") && win_node->hasAnother("x") && win_node->hasAnother("y")) { + win_node->getNext("x")->element()->get(x); + win_node->getNext("y")->element()->get(y); + win_node->getNext("w")->element()->get(w); + win_node->getNext("h")->element()->get(h); + + winX.store(x); + winY.store(y); + winW.store(w); + winH.store(h); + } + + if (win_node->hasAnother("max")) { + win_node->getNext("max")->element()->get(max); + winMax.store(max?true:false); + } + + if (win_node->hasAnother("theme")) { + int theme; + win_node->getNext("theme")->element()->get(theme); + themeId.store(theme); + } + + if (win_node->hasAnother("snap")) { + long long snapVal; + win_node->getNext("snap")->element()->get(snapVal); + snap.store(snapVal); + } + } + if (cfg.rootNode()->hasAnother("devices")) { DataNode *devices_node = cfg.rootNode()->getNext("devices"); diff --git a/src/AppConfig.h b/src/AppConfig.h index 13e5ce1..9d13f49 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -3,10 +3,12 @@ #include #include #include +#include +#include +#include #include "DataTree.h" - class DeviceConfig { public: DeviceConfig(); @@ -14,7 +16,16 @@ public: void setPPM(int ppm); int getPPM(); + + void setDirectSampling(int mode); + int getDirectSampling(); + + void setOffset(long long offset); + long long getOffset(); + void setIQSwap(bool iqSwap); + bool getIQSwap(); + void setDeviceId(std::string deviceId); std::string getDeviceId(); @@ -23,18 +34,39 @@ public: private: std::string deviceId; - int ppm; + std::mutex busy_lock; + + std::atomic_int ppm, directSampling; + std::atomic_bool iqSwap; + std::atomic_llong offset; }; class AppConfig { public: + AppConfig(); std::string getConfigDir(); DeviceConfig *getDevice(std::string deviceId); + void setWindow(wxPoint winXY, wxSize winWH); + wxRect *getWindow(); + + void setWindowMaximized(bool max); + bool getWindowMaximized(); + + void setTheme(int themeId); + int getTheme(); + + void setSnap(long long snapVal); + long long getSnap(); + bool save(); bool load(); bool reset(); private: - std::map deviceConfig; + std::map deviceConfig; + std::atomic_int winX,winY,winW,winH; + std::atomic_bool winMax; + std::atomic_int themeId; + std::atomic_llong snap; }; diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index e94783f..fb1e690 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -31,7 +31,7 @@ wxBEGIN_EVENT_TABLE(AppFrame, wxFrame) //EVT_MENU(wxID_NEW, AppFrame::OnNewWindow) -EVT_MENU(wxID_CLOSE, AppFrame::OnClose) +EVT_CLOSE(AppFrame::OnClose) EVT_MENU(wxID_ANY, AppFrame::OnMenu) EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread) EVT_IDLE(AppFrame::OnIdle) @@ -57,6 +57,7 @@ AppFrame::AppFrame() : demodModeSelector->addChoice(DEMOD_TYPE_LSB, "LSB"); demodModeSelector->addChoice(DEMOD_TYPE_USB, "USB"); demodModeSelector->addChoice(DEMOD_TYPE_DSB, "DSB"); + demodModeSelector->addChoice(DEMOD_TYPE_RAW, "I/Q"); demodModeSelector->setSelection(DEMOD_TYPE_FM); demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band."); demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0); @@ -156,9 +157,9 @@ AppFrame::AppFrame() : wxMenu *dsMenu = new wxMenu; - dsMenu->AppendRadioItem(wxID_SET_DS_OFF, "Off"); - dsMenu->AppendRadioItem(wxID_SET_DS_I, "I-ADC"); - dsMenu->AppendRadioItem(wxID_SET_DS_Q, "Q-ADC"); + directSamplingMenuItems[0] = dsMenu->AppendRadioItem(wxID_SET_DS_OFF, "Off"); + directSamplingMenuItems[1] = dsMenu->AppendRadioItem(wxID_SET_DS_I, "I-ADC"); + directSamplingMenuItems[2] = dsMenu->AppendRadioItem(wxID_SET_DS_Q, "Q-ADC"); menu->AppendSubMenu(dsMenu, "Direct Sampling"); @@ -195,13 +196,15 @@ AppFrame::AppFrame() : menu = new wxMenu; - menu->AppendRadioItem(wxID_THEME_DEFAULT, "Default")->Check(true); - menu->AppendRadioItem(wxID_THEME_RADAR, "RADAR"); - menu->AppendRadioItem(wxID_THEME_BW, "Black & White"); - menu->AppendRadioItem(wxID_THEME_SHARP, "Sharp"); - menu->AppendRadioItem(wxID_THEME_RAD, "Rad"); - menu->AppendRadioItem(wxID_THEME_TOUCH, "Touch"); - menu->AppendRadioItem(wxID_THEME_HD, "HD"); + int themeId = wxGetApp().getConfig()->getTheme(); + + menu->AppendRadioItem(wxID_THEME_DEFAULT, "Default")->Check(themeId==COLOR_THEME_DEFAULT); + menu->AppendRadioItem(wxID_THEME_RADAR, "RADAR")->Check(themeId==COLOR_THEME_RADAR); + menu->AppendRadioItem(wxID_THEME_BW, "Black & White")->Check(themeId==COLOR_THEME_BW); + menu->AppendRadioItem(wxID_THEME_SHARP, "Sharp")->Check(themeId==COLOR_THEME_SHARP); + menu->AppendRadioItem(wxID_THEME_RAD, "Rad")->Check(themeId==COLOR_THEME_RAD); + menu->AppendRadioItem(wxID_THEME_TOUCH, "Touch")->Check(themeId==COLOR_THEME_TOUCH); + menu->AppendRadioItem(wxID_THEME_HD, "HD")->Check(themeId==COLOR_THEME_HD); menuBar->Append(menu, wxT("&Color Scheme")); @@ -307,8 +310,26 @@ AppFrame::AppFrame() : SetMenuBar(menuBar); CreateStatusBar(); - SetClientSize(1280, 600); - Centre(); + + wxRect *win = wxGetApp().getConfig()->getWindow(); + if (win) { + this->SetPosition(win->GetPosition()); + this->SetClientSize(win->GetSize()); + } else { + SetClientSize(1280, 600); + Centre(); + } + bool max = wxGetApp().getConfig()->getWindowMaximized(); + + if (max) { + this->Maximize(); + } + + long long freqSnap = wxGetApp().getConfig()->getSnap(); + wxGetApp().setFrequencySnap(freqSnap); + + ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme()); + Show(); #ifdef _WIN32 @@ -333,6 +354,22 @@ AppFrame::~AppFrame() { } + +void AppFrame::initDeviceParams(std::string deviceId) { + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId); + + int dsMode = devConfig->getDirectSampling(); + + if (dsMode > 0 && dsMode <= 2) { + directSamplingMenuItems[devConfig->getDirectSampling()]->Check(); + } + + if (devConfig->getIQSwap()) { + iqSwapMenuItem->Check(); + } +} + + void AppFrame::OnMenu(wxCommandEvent& event) { if (event.GetId() >= wxID_RT_AUDIO_DEVICE && event.GetId() < wxID_RT_AUDIO_DEVICE + devices.size()) { if (activeDemodulator) { @@ -344,16 +381,21 @@ void AppFrame::OnMenu(wxCommandEvent& event) { "Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this); if (ofs != -1) { wxGetApp().setOffset(ofs); + wxGetApp().saveConfig(); } } else if (event.GetId() == wxID_SET_DS_OFF) { wxGetApp().setDirectSampling(0); + wxGetApp().saveConfig(); } else if (event.GetId() == wxID_SET_DS_I) { wxGetApp().setDirectSampling(1); + wxGetApp().saveConfig(); } else if (event.GetId() == wxID_SET_DS_Q) { wxGetApp().setDirectSampling(2); + wxGetApp().saveConfig(); } else if (event.GetId() == wxID_SET_SWAP_IQ) { bool swap_state = !wxGetApp().getSwapIQ(); wxGetApp().setSwapIQ(swap_state); + wxGetApp().saveConfig(); iqSwapMenuItem->Check(swap_state); } else if (event.GetId() == wxID_SET_PPM) { long ofs = wxGetNumberFromUser("Frequency correction for device in PPM.\ni.e. -51 for -51 PPM\n\nNote: you can adjust PPM interactively\nby holding ALT over the frequency tuning bar.\n", "Parts per million (PPM)", @@ -453,7 +495,19 @@ void AppFrame::OnMenu(wxCommandEvent& event) { std::vector *devs = wxGetApp().getDevices(); if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID + devs->size()) { - wxGetApp().setDevice(event.GetId() - wxID_DEVICE_ID); + int devId = event.GetId() - wxID_DEVICE_ID; + wxGetApp().setDevice(devId); + + SDRDeviceInfo *dev = (*wxGetApp().getDevices())[devId]; + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); + + int dsMode = devConfig->getDirectSampling(); + + if (dsMode >= 0 && dsMode <= 2) { + directSamplingMenuItems[devConfig->getDirectSampling()]->Check(); + } + + iqSwapMenuItem->Check(devConfig->getIQSwap()); } if (event.GetId() >= wxID_AUDIO_BANDWIDTH_BASE) { @@ -483,8 +537,13 @@ void AppFrame::OnMenu(wxCommandEvent& event) { } -void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { - Close(false); +void AppFrame::OnClose(wxCloseEvent& event) { + wxGetApp().getConfig()->setWindow(this->GetPosition(), this->GetClientSize()); + wxGetApp().getConfig()->setWindowMaximized(this->IsMaximized()); + wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme()); + wxGetApp().getConfig()->setSnap(wxGetApp().getFrequencySnap()); + wxGetApp().getConfig()->save(); + event.Skip(); } void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) { @@ -622,7 +681,6 @@ void AppFrame::saveSession(std::string fileName) { DataNode *header = s.rootNode()->newChild("header"); *header->newChild("version") = std::string(CUBICSDR_VERSION); *header->newChild("center_freq") = wxGetApp().getFrequency(); - *header->newChild("offset") = wxGetApp().getOffset(); DataNode *demods = s.rootNode()->newChild("demodulators"); @@ -661,14 +719,11 @@ bool AppFrame::loadSession(std::string fileName) { std::string version(*header->getNext("version")); long long center_freq = *header->getNext("center_freq"); - long long offset = *header->getNext("offset"); std::cout << "Loading " << version << " session file" << std::endl; std::cout << "\tCenter Frequency: " << center_freq << std::endl; - std::cout << "\tOffset: " << offset << std::endl; wxGetApp().setFrequency(center_freq); - wxGetApp().setOffset(offset); DataNode *demodulators = l.rootNode()->getNext("demodulators"); @@ -716,7 +771,7 @@ bool AppFrame::loadSession(std::string fileName) { } newDemod->run(); - + newDemod->setActive(false); wxGetApp().bindDemodulator(newDemod); std::cout << "\tAdded demodulator at frequency " << freq << " type " << type << std::endl; diff --git a/src/AppFrame.h b/src/AppFrame.h index e3fcc5b..4d335a0 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -59,13 +59,14 @@ public: ~AppFrame(); void OnThread(wxCommandEvent& event); void OnEventInput(wxThreadEvent& event); + void initDeviceParams(std::string deviceId); void saveSession(std::string fileName); bool loadSession(std::string fileName); private: void OnMenu(wxCommandEvent& event); - void OnClose(wxCommandEvent& event); + void OnClose(wxCloseEvent& event); void OnNewWindow(wxCommandEvent& event); void OnIdle(wxIdleEvent& event); @@ -88,6 +89,7 @@ private: std::map outputDeviceMenuItems; std::map sampleRateMenuItems; std::map audioSampleRateMenuItems; + std::map directSamplingMenuItems; wxMenuItem *iqSwapMenuItem; std::string currentSessionFile; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 64432bc..1fa1e54 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -67,6 +67,7 @@ bool CubicSDR::OnInit() { std::vector::iterator devs_i; SDRThread::enumerate_rtl(&devs); + SDRDeviceInfo *dev = NULL; if (devs.size() > 1) { wxArrayString choices; @@ -84,16 +85,36 @@ bool CubicSDR::OnInit() { choices.Add(devName); } - int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices); + int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices); + if (devId == -1) { // User chose to cancel + return false; + } + + dev = devs[devId]; - std::cout << "Chosen: " << devId << std::endl; 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); 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; @@ -169,6 +190,9 @@ void CubicSDR::setOffset(long long ofs) { SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET); command.llong_value = ofs; threadCmdQueueSDR->push(command); + + SDRDeviceInfo *dev = (*getDevices())[getDevice()]; + config.getDevice(dev->getDeviceId())->setOffset(ofs); } void CubicSDR::setDirectSampling(int mode) { @@ -176,6 +200,9 @@ void CubicSDR::setDirectSampling(int mode) { SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING); command.llong_value = mode; threadCmdQueueSDR->push(command); + + SDRDeviceInfo *dev = (*getDevices())[getDevice()]; + config.getDevice(dev->getDeviceId())->setDirectSampling(mode); } int CubicSDR::getDirectSampling() { @@ -184,6 +211,8 @@ int CubicSDR::getDirectSampling() { void CubicSDR::setSwapIQ(bool swapIQ) { sdrPostThread->setSwapIQ(swapIQ); + SDRDeviceInfo *dev = (*getDevices())[getDevice()]; + config.getDevice(dev->getDeviceId())->setIQSwap(swapIQ); } bool CubicSDR::getSwapIQ() { @@ -244,11 +273,12 @@ void CubicSDR::setDevice(int deviceId) { threadCmdQueueSDR->push(command); SDRDeviceInfo *dev = (*getDevices())[deviceId]; + DeviceConfig *devConfig = config.getDevice(dev->getDeviceId()); - SDRThreadCommand command_ppm(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM); - ppm = config.getDevice(dev->getDeviceId())->getPPM(); - command_ppm.llong_value = ppm; - threadCmdQueueSDR->push(command_ppm); + setPPM(devConfig->getPPM()); + setDirectSampling(devConfig->getDirectSampling()); + setSwapIQ(devConfig->getIQSwap()); + setOffset(devConfig->getOffset()); } int CubicSDR::getDevice() { @@ -276,7 +306,6 @@ void CubicSDR::setPPM(int ppm_in) { SDRDeviceInfo *dev = (*getDevices())[getDevice()]; config.getDevice(dev->getDeviceId())->setPPM(ppm_in); - config.save(); } int CubicSDR::getPPM() { diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 9ed5c5b..fb9027b 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -22,7 +22,7 @@ class CubicSDR: public wxApp { public: CubicSDR() : - m_glContext(NULL), frequency(DEFAULT_FREQ), sdrThread(NULL), sdrPostThread(NULL), threadCmdQueueSDR(NULL), iqVisualQueue(NULL), iqPostDataQueue(NULL), audioVisualQueue(NULL), t_SDR(NULL), t_PostSDR(NULL), sampleRate(DEFAULT_SAMPLE_RATE), offset(0), snap(1) { + appframe(NULL), m_glContext(NULL), frequency(DEFAULT_FREQ), sdrThread(NULL), sdrPostThread(NULL), threadCmdQueueSDR(NULL), iqVisualQueue(NULL), iqPostDataQueue(NULL), audioVisualQueue(NULL), t_SDR(NULL), t_PostSDR(NULL), sampleRate(DEFAULT_SAMPLE_RATE), offset(0), snap(1), directSamplingMode(0), ppm(0) { } diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index c40a0b1..2656f85 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -53,5 +53,5 @@ public: return refCount.load(); } protected: - std::atomic refCount; + std::atomic_int refCount; }; diff --git a/src/FrequencyDialog.cpp b/src/FrequencyDialog.cpp index d7fd9a8..712739e 100644 --- a/src/FrequencyDialog.cpp +++ b/src/FrequencyDialog.cpp @@ -65,7 +65,7 @@ std::string FrequencyDialog::frequencyToStr(long long freq) { } long long FrequencyDialog::strToFrequency(std::string freqStr) { - std::string filterStr = filterChars(freqStr, std::string("0123456789.MKGmkg")); + std::string filterStr = filterChars(freqStr, std::string("0123456789.MKGHmkgh")); int numLen = filterStr.find_first_not_of("0123456789."); @@ -90,8 +90,10 @@ long long FrequencyDialog::strToFrequency(std::string freqStr) { freqTemp *= 1.0e6; } else if (suffixStr.find_first_of("Kk") != std::string::npos) { freqTemp *= 1.0e3; + } else if (suffixStr.find_first_of("Hh") != std::string::npos) { + // ... } - } else if (numPartStr.find_first_of(".") != std::string::npos) { + } else if (numPartStr.find_first_of(".") != std::string::npos || freqTemp <= 3000) { freqTemp *= 1.0e6; } diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h index 7adfa6f..2e2adbf 100644 --- a/src/audio/AudioThread.h +++ b/src/audio/AudioThread.h @@ -52,12 +52,12 @@ public: AudioThreadInput *currentInput; AudioThreadInputQueue *inputQueue; - std::atomic audioQueuePtr; - std::atomic underflowCount; - std::atomic terminated; - std::atomic initialized; - std::atomic active; - std::atomic outputDevice; + std::atomic_uint audioQueuePtr; + std::atomic_uint underflowCount; + std::atomic_bool terminated; + std::atomic_bool initialized; + std::atomic_bool active; + std::atomic_int outputDevice; std::atomic gain; AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify); diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index a3db3e0..c5381d0 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -13,6 +13,8 @@ #define DEMOD_TYPE_LSB 3 #define DEMOD_TYPE_USB 4 #define DEMOD_TYPE_DSB 5 +#define DEMOD_TYPE_RAW 6 + class DemodulatorThread; class DemodulatorThreadCommand { diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 0f16c68..ba58e7c 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -2,7 +2,7 @@ DemodulatorInstance::DemodulatorInstance() : t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(true), audioTerminated(true), demodTerminated( - true), preDemodTerminated(true), active(false), squelch(false), stereo(false), currentFrequency(0), currentBandwidth(0), currentOutputDevice(-1) { + true), preDemodTerminated(true), active(false), squelch(false), stereo(false), tracking(false), follow(false), currentAudioSampleRate(0), currentFrequency(0), currentBandwidth(0), currentOutputDevice(-1), currentAudioGain(1.0) { label = new std::string("Unnamed"); threadQueueDemod = new DemodulatorThreadInputQueue; @@ -220,13 +220,12 @@ void DemodulatorInstance::setOutputDevice(int device_id) { if (!active) { audioThread->setInitOutputDevice(device_id); } else if (audioThread) { - setAudioSampleRate(AudioThread::deviceSampleRate[device_id]); - AudioThreadCommand command; command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE; command.int_value = device_id; audioThread->getCommandQueue()->push(command); } + setAudioSampleRate(AudioThread::deviceSampleRate[device_id]); currentOutputDevice = device_id; } @@ -245,15 +244,28 @@ void DemodulatorInstance::checkBandwidth() { } void DemodulatorInstance::setDemodulatorType(int demod_type_in) { + currentDemodType = demod_type_in; + + if (currentDemodType == DEMOD_TYPE_RAW) { + if (currentAudioSampleRate) { + setBandwidth(currentAudioSampleRate); + } else { + setBandwidth(AudioThread::deviceSampleRate[getOutputDevice()]); + } + } else if (currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB || currentDemodType == DEMOD_TYPE_DSB || currentDemodType == DEMOD_TYPE_AM) { + demodulatorThread->setAGC(false); + } else { + demodulatorThread->setAGC(true); + } + setGain(getGain()); + if (!active) { - currentDemodType = demod_type_in; checkBandwidth(); demodulatorPreThread->getParams().demodType = currentDemodType; demodulatorThread->setDemodulatorType(currentDemodType); } else if (demodulatorThread && threadQueueControl) { DemodulatorThreadControlCommand command; command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE; - currentDemodType = demod_type_in; command.demodType = demod_type_in; checkBandwidth(); threadQueueControl->push(command); @@ -265,6 +277,13 @@ int DemodulatorInstance::getDemodulatorType() { } void DemodulatorInstance::setBandwidth(int bw) { + if (currentDemodType == DEMOD_TYPE_RAW) { + if (currentAudioSampleRate) { + bw = currentAudioSampleRate; + } else { + bw = AudioThread::deviceSampleRate[getOutputDevice()]; + } + } if (!active) { currentBandwidth = bw; checkBandwidth(); @@ -321,6 +340,9 @@ void DemodulatorInstance::setAudioSampleRate(int sampleRate) { command.llong_value = sampleRate; threadQueueCommand->push(command); } + if (currentDemodType == DEMOD_TYPE_RAW) { + setBandwidth(currentAudioSampleRate); + } } int DemodulatorInstance::getAudioSampleRate() { @@ -332,11 +354,23 @@ int DemodulatorInstance::getAudioSampleRate() { void DemodulatorInstance::setGain(float gain_in) { - audioThread->setGain(gain_in); + currentAudioGain = gain_in; + + if (currentDemodType == DEMOD_TYPE_RAW) { + if (gain_in < 0.25) { + audioThread->setGain(1.0); + demodulatorThread->setAGC(false); + } else { + audioThread->setGain(gain_in); + demodulatorThread->setAGC(true); + } + } else { + audioThread->setGain(gain_in); + } } float DemodulatorInstance::getGain() { - return audioThread->getGain(); + return currentAudioGain; } bool DemodulatorInstance::isFollow() { diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index bbb4841..b0b8682 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -87,18 +87,19 @@ private: void checkBandwidth(); std::atomic label; // - bool terminated; // - bool demodTerminated; // - bool audioTerminated; // - bool preDemodTerminated; - std::atomic active; - std::atomic squelch; - std::atomic stereo; + std::atomic_bool terminated; // + std::atomic_bool demodTerminated; // + std::atomic_bool audioTerminated; // + std::atomic_bool preDemodTerminated; + std::atomic_bool active; + std::atomic_bool squelch; + std::atomic_bool stereo; - long long currentFrequency; - int currentBandwidth; - int currentDemodType; - int currentOutputDevice; - int currentAudioSampleRate; - bool follow, tracking; + std::atomic_llong currentFrequency; + std::atomic_int currentBandwidth; + std::atomic_int currentDemodType; + std::atomic_int currentOutputDevice; + std::atomic_int currentAudioSampleRate; + std::atomic currentAudioGain; + std::atomic_bool follow, tracking; }; diff --git a/src/demod/DemodulatorPreThread.h b/src/demod/DemodulatorPreThread.h index 632c4c9..b5e5ec2 100644 --- a/src/demod/DemodulatorPreThread.h +++ b/src/demod/DemodulatorPreThread.h @@ -68,8 +68,8 @@ protected: nco_crcf freqShifter; int shiftFrequency; - std::atomic terminated; - std::atomic initialized; + std::atomic_bool terminated; + std::atomic_bool initialized; DemodulatorWorkerThread *workerThread; std::thread *t_Worker; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 160e04d..00df8a7 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -14,7 +14,7 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQueue, DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) : iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA( - 1), stereo(false), terminated( + 1), stereo(false), agcEnabled(true), terminated( false), demodulatorType(DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel( 0), squelchEnabled(false), audioSampleRate(0) { @@ -61,7 +61,7 @@ void DemodulatorThread::threadMain() { // Automatic IQ gain iqAutoGain = agc_crcf_create(); - agc_crcf_set_bandwidth(iqAutoGain, 0.9); + agc_crcf_set_bandwidth(iqAutoGain, 0.1); AudioThreadInput *ati_vis = new AudioThreadInput; ati_vis->data.reserve(DEMOD_VIS_SIZE); @@ -171,27 +171,37 @@ void DemodulatorThread::threadMain() { currentSignalLevel = agc_crcf_get_signal_level(iqAutoGain); } + std::vector *inputData; + + if (agcEnabled) { + inputData = &agcData; + } else { + inputData = &inp->data; + } + if (demodulatorType == DEMOD_TYPE_FM) { - freqdem_demodulate_block(demodFM, &agcData[0], bufSize, &demodOutputData[0]); + freqdem_demodulate_block(demodFM, &(*inputData)[0], bufSize, &demodOutputData[0]); + } else if (demodulatorType == DEMOD_TYPE_RAW) { + // do nothing here.. } else { float p; switch (demodulatorType.load()) { case DEMOD_TYPE_LSB: for (int i = 0; i < bufSize; i++) { // Reject upper band - resamp2_cccf_filter_execute(ssbFilt,inp->data[i],&x,&y); + resamp2_cccf_filter_execute(ssbFilt,(*inputData)[i],&x,&y); ampmodem_demodulate(demodAM, x, &demodOutputData[i]); } break; case DEMOD_TYPE_USB: for (int i = 0; i < bufSize; i++) { // Reject lower band - resamp2_cccf_filter_execute(ssbFilt,inp->data[i],&x,&y); + resamp2_cccf_filter_execute(ssbFilt,(*inputData)[i],&x,&y); ampmodem_demodulate(demodAM, y, &demodOutputData[i]); } break; case DEMOD_TYPE_AM: case DEMOD_TYPE_DSB: for (int i = 0; i < bufSize; i++) { - ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]); + ampmodem_demodulate(demodAM, (*inputData)[i], &demodOutputData[i]); } break; } @@ -222,6 +232,10 @@ void DemodulatorThread::threadMain() { } unsigned int numAudioWritten; + + if (demodulatorType == DEMOD_TYPE_RAW) { + numAudioWritten = bufSize; + } else { msresamp_rrrf_execute(audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten); if (stereo && inp->sampleRate >= 100000) { @@ -276,6 +290,7 @@ void DemodulatorThread::threadMain() { msresamp_rrrf_execute(stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten); } + } if (currentSignalLevel > signalLevel) { signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5; @@ -303,7 +318,17 @@ void DemodulatorThread::threadMain() { ati->sampleRate = audioSampleRate; ati->setRefCount(1); - if (stereo && inp->sampleRate >= 100000) { + if (demodulatorType == DEMOD_TYPE_RAW) { + ati->channels = 2; + if (ati->data.capacity() < (numAudioWritten * 2)) { + ati->data.reserve(numAudioWritten * 2); + } + ati->data.resize(numAudioWritten * 2); + for (int i = 0; i < numAudioWritten; i++) { + ati->data[i * 2] = (*inputData)[i].real; + ati->data[i * 2 + 1] = (*inputData)[i].imag; + } + } else if (stereo && inp->sampleRate >= 100000) { ati->channels = 2; if (ati->data.capacity() < (numAudioWritten * 2)) { ati->data.reserve(numAudioWritten * 2); @@ -334,8 +359,6 @@ void DemodulatorThread::threadMain() { ati->peak = p; } } - - audioOutputQueue->push(ati); } } @@ -344,18 +367,25 @@ void DemodulatorThread::threadMain() { ati_vis->busy_update.lock(); int num_vis = DEMOD_VIS_SIZE; - if (stereo && inp->sampleRate >= 100000) { + if (demodulatorType == DEMOD_TYPE_RAW || (stereo && inp->sampleRate >= 100000)) { ati_vis->channels = 2; int stereoSize = ati->data.size(); - if (stereoSize > DEMOD_VIS_SIZE) { - stereoSize = DEMOD_VIS_SIZE; + if (stereoSize > DEMOD_VIS_SIZE * 2) { + stereoSize = DEMOD_VIS_SIZE * 2; } ati_vis->data.resize(stereoSize); - for (int i = 0; i < stereoSize / 2; i++) { - ati_vis->data[i] = ati->data[i * 2]; - ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1]; + if (demodulatorType == DEMOD_TYPE_RAW) { + for (int i = 0; i < stereoSize / 2; i++) { + ati_vis->data[i] = agcData[i].real * 0.75; + ati_vis->data[i + stereoSize / 2] = agcData[i].imag * 0.75; + } + } else { + for (int i = 0; i < stereoSize / 2; i++) { + ati_vis->data[i] = ati->data[i * 2]; + ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1]; + } } } else { ati_vis->channels = 1; @@ -379,6 +409,11 @@ void DemodulatorThread::threadMain() { ati_vis->busy_update.unlock(); } + + if (ati != NULL) { + audioOutputQueue->push(ati); + } + if (!threadQueueControl->empty()) { int newDemodType = DEMOD_TYPE_NULL; @@ -489,16 +524,25 @@ void DemodulatorThread::terminate() { } void DemodulatorThread::setStereo(bool state) { - stereo = state; + stereo.store(state); std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl; } bool DemodulatorThread::isStereo() { - return stereo; + return stereo.load(); } +void DemodulatorThread::setAGC(bool state) { + agcEnabled.store(state); +} + +bool DemodulatorThread::getAGC() { + return agcEnabled.load(); +} + + float DemodulatorThread::getSignalLevel() { - return signalLevel; + return signalLevel.load(); } void DemodulatorThread::setSquelchLevel(float signal_level_in) { diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index f9d013b..be6cf69 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -31,6 +31,9 @@ public: void setStereo(bool state); bool isStereo(); + void setAGC(bool state); + bool getAGC(); + float getSignalLevel(); void setSquelchLevel(float signal_level_in); float getSquelchLevel(); @@ -72,9 +75,10 @@ protected: float amOutputCeilMA; float amOutputCeilMAA; - std::atomic stereo; - std::atomic terminated; - std::atomic demodulatorType; + std::atomic_bool stereo; + std::atomic_bool agcEnabled; + std::atomic_bool terminated; + std::atomic_int demodulatorType; int audioSampleRate; DemodulatorThreadCommandQueue* threadQueueNotify; diff --git a/src/demod/DemodulatorWorkerThread.h b/src/demod/DemodulatorWorkerThread.h index 989b048..86c5baf 100644 --- a/src/demod/DemodulatorWorkerThread.h +++ b/src/demod/DemodulatorWorkerThread.h @@ -93,5 +93,5 @@ protected: DemodulatorThreadWorkerCommandQueue *commandQueue; DemodulatorThreadWorkerResultQueue *resultQueue; - std::atomic terminated; + std::atomic_bool terminated; }; diff --git a/src/sdr/SDRPostThread.h b/src/sdr/SDRPostThread.h index 11d3f2f..a1aed7d 100644 --- a/src/sdr/SDRPostThread.h +++ b/src/sdr/SDRPostThread.h @@ -31,10 +31,10 @@ protected: std::mutex busy_demod; std::vector demodulators; - std::atomic terminated; + std::atomic_bool terminated; iirfilt_crcf dcFilter; int num_vis_samples; - std::atomic swapIQ; + std::atomic_bool swapIQ; private: std::vector _lut; diff --git a/src/sdr/SDRThread.cpp b/src/sdr/SDRThread.cpp index d6771e1..0d8a1bd 100644 --- a/src/sdr/SDRThread.cpp +++ b/src/sdr/SDRThread.cpp @@ -6,7 +6,7 @@ SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) : commandQueue(pQueue), iqDataOutQueue(NULL), terminated(false), offset(0), deviceId(-1) { dev = NULL; - sampleRate = DEFAULT_SAMPLE_RATE; + sampleRate.store(DEFAULT_SAMPLE_RATE); } SDRThread::~SDRThread() { @@ -122,6 +122,7 @@ void SDRThread::threadMain() { std::cout << "SDR thread initializing.." << std::endl; int devCount = rtlsdr_get_device_count(); + std::vector devs; if (deviceId == -1) { deviceId = enumerate_rtl(&devs); @@ -136,16 +137,20 @@ void SDRThread::threadMain() { std::cout << "Using device #" << deviceId << std::endl; } + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devs[deviceId]->getDeviceId()); + signed char buf[BUF_SIZE]; long long frequency = DEFAULT_FREQ; - int ppm = wxGetApp().getConfig()->getDevice(devs[deviceId]->getDeviceId())->getPPM(); - int direct_sampling_mode = 0; + int ppm = devConfig->getPPM(); + int direct_sampling_mode = devConfig->getDirectSampling();; int buf_size = BUF_SIZE; - + offset.store(devConfig->getOffset()); + wxGetApp().setSwapIQ(devConfig->getIQSwap()); + rtlsdr_open(&dev, deviceId); - rtlsdr_set_sample_rate(dev, sampleRate); - rtlsdr_set_center_freq(dev, frequency - offset); + rtlsdr_set_sample_rate(dev, sampleRate.load()); + rtlsdr_set_center_freq(dev, frequency - offset.load()); rtlsdr_set_freq_correction(dev, ppm); rtlsdr_set_agc_mode(dev, 1); rtlsdr_set_offset_tuning(dev, 0); @@ -153,7 +158,7 @@ void SDRThread::threadMain() { // sampleRate = rtlsdr_get_sample_rate(dev); - std::cout << "Sample Rate is: " << sampleRate << std::endl; + std::cout << "Sample Rate is: " << sampleRate.load() << std::endl; int n_read; double seconds = 0.0; @@ -174,8 +179,8 @@ void SDRThread::threadMain() { bool ppm_changed = false; bool direct_sampling_changed = false; long long new_freq = frequency; - long long new_offset = offset; - long long new_rate = sampleRate; + long long new_offset = offset.load(); + long long new_rate = sampleRate.load(); int new_device = deviceId; int new_ppm = ppm; @@ -187,8 +192,8 @@ void SDRThread::threadMain() { case SDRThreadCommand::SDR_THREAD_CMD_TUNE: freq_changed = true; new_freq = command.llong_value; - if (new_freq < sampleRate / 2) { - new_freq = sampleRate / 2; + if (new_freq < sampleRate.load() / 2) { + new_freq = sampleRate.load() / 2; } // std::cout << "Set frequency: " << new_freq << std::endl; break; @@ -231,8 +236,8 @@ void SDRThread::threadMain() { if (device_changed) { rtlsdr_close(dev); rtlsdr_open(&dev, new_device); - rtlsdr_set_sample_rate(dev, sampleRate); - rtlsdr_set_center_freq(dev, frequency - offset); + rtlsdr_set_sample_rate(dev, sampleRate.load()); + rtlsdr_set_center_freq(dev, frequency - offset.load()); rtlsdr_set_freq_correction(dev, ppm); rtlsdr_set_agc_mode(dev, 1); rtlsdr_set_offset_tuning(dev, 0); @@ -244,16 +249,16 @@ void SDRThread::threadMain() { new_freq = frequency; freq_changed = true; } - offset = new_offset; + offset.store(new_offset); } if (rate_changed) { rtlsdr_set_sample_rate(dev, new_rate); rtlsdr_reset_buffer(dev); - sampleRate = rtlsdr_get_sample_rate(dev); + sampleRate.store(rtlsdr_get_sample_rate(dev)); } if (freq_changed) { frequency = new_freq; - rtlsdr_set_center_freq(dev, frequency - offset); + rtlsdr_set_center_freq(dev, frequency - offset.load()); } if (ppm_changed) { ppm = new_ppm; @@ -283,7 +288,7 @@ void SDRThread::threadMain() { // std::lock_guard < std::mutex > lock(dataOut->m_mutex); dataOut->setRefCount(1); dataOut->frequency = frequency; - dataOut->sampleRate = sampleRate; + dataOut->sampleRate = sampleRate.load(); if (dataOut->data.capacity() < n_read) { dataOut->data.reserve(n_read); @@ -295,7 +300,7 @@ void SDRThread::threadMain() { memcpy(&dataOut->data[0], buf, n_read); - double time_slice = (double) n_read / (double) sampleRate; + double time_slice = (double) n_read / (double) sampleRate.load(); seconds += time_slice; if (iqDataOutQueue.load() != NULL) { diff --git a/src/sdr/SDRThread.h b/src/sdr/SDRThread.h index 135fb90..67318a9 100644 --- a/src/sdr/SDRThread.h +++ b/src/sdr/SDRThread.h @@ -140,19 +140,19 @@ public: void terminate(); int getDeviceId() const { - return deviceId; + return deviceId.load(); } void setDeviceId(int deviceId) { - this->deviceId = deviceId; + this->deviceId.store(deviceId); } protected: - uint32_t sampleRate; - long long offset; + std::atomic sampleRate; + std::atomic_llong offset; std::atomic commandQueue; std::atomic iqDataOutQueue; - std::atomic terminated; - int deviceId; + std::atomic_bool terminated; + std::atomic_int deviceId; }; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 59f7c21..abbcf0e 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -820,8 +820,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { demod = wxGetApp().getDemodMgr().newThread(); demod->setFrequency(freq); - demod->setBandwidth(mgr->getLastBandwidth()); demod->setDemodulatorType(mgr->getLastDemodulatorType()); + demod->setBandwidth(mgr->getLastBandwidth()); demod->setSquelchLevel(mgr->getLastSquelchLevel()); demod->setSquelchEnabled(mgr->isLastSquelchEnabled()); demod->setStereo(mgr->isLastStereo()); @@ -907,9 +907,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { } else { demod = wxGetApp().getDemodMgr().newThread(); demod->setFrequency(freq); - demod->setBandwidth(bw); - demod->setDemodulatorType(mgr->getLastDemodulatorType()); + demod->setBandwidth(bw); demod->setSquelchLevel(mgr->getLastSquelchLevel()); demod->setSquelchEnabled(mgr->isLastSquelchEnabled()); demod->setStereo(mgr->isLastStereo());