diff --git a/CMakeLists.txt b/CMakeLists.txt index a09cb5c..1785448 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ SET(CPACK_PACKAGE_VERSION_PATCH ${CUBICSDR_VERSION_PATCH}) SET (VERSION_SUFFIX "" CACHE STRING "Add custom version suffix to CubicSDR application title.") ADD_DEFINITIONS( - -DCUBICSDR_VERSION="${CUBICSDR_VERSION}-${VERSION_SUFFIX}" + -DCUBICSDR_VERSION="${CUBICSDR_VERSION}${VERSION_SUFFIX}" ) SET (ENABLE_DIGITAL_LAB OFF CACHE BOOL "Enable 'Digital Lab' testing features.") @@ -22,6 +22,16 @@ IF(ENABLE_DIGITAL_LAB) ADD_DEFINITIONS( -DENABLE_DIGITAL_LAB=1 ) +IF(MSVC) + SET (ENABLE_LIQUID_EXPERIMENTAL OFF CACHE BOOL "Enable experimental liquid-dsp features (requires latest liquid-dsp installed)") +ELSE() + SET (ENABLE_LIQUID_EXPERIMENTAL ON CACHE BOOL "Enable experimental liquid-dsp features (requires latest liquid-dsp installed)") +ENDIF() +IF(ENABLE_LIQUID_EXPERIMENTAL) +ADD_DEFINITIONS( + -DENABLE_LIQUID_EXPERIMENTAL=1 +) +ENDIF() ENDIF() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") @@ -225,6 +235,7 @@ SET (cubicsdr_sources src/AppConfig.cpp src/FrequencyDialog.cpp src/IOThread.cpp + src/ModemProperties.cpp src/sdr/SDRDeviceInfo.cpp src/sdr/SDRPostThread.cpp src/sdr/SDREnumerator.cpp @@ -237,16 +248,6 @@ SET (cubicsdr_sources src/modules/modem/Modem.cpp src/modules/modem/ModemAnalog.cpp src/modules/modem/ModemDigital.cpp - src/modules/modem/digital/ModemASK.cpp - src/modules/modem/digital/ModemAPSK.cpp - src/modules/modem/digital/ModemBPSK.cpp - src/modules/modem/digital/ModemDPSK.cpp - src/modules/modem/digital/ModemPSK.cpp - src/modules/modem/digital/ModemOOK.cpp - src/modules/modem/digital/ModemST.cpp - src/modules/modem/digital/ModemSQAM.cpp - src/modules/modem/digital/ModemQAM.cpp - src/modules/modem/digital/ModemQPSK.cpp src/modules/modem/analog/ModemAM.cpp src/modules/modem/analog/ModemDSB.cpp src/modules/modem/analog/ModemFM.cpp @@ -296,6 +297,31 @@ SET (cubicsdr_sources external/cubicvr2/math/cubic_math.cpp ) +IF(ENABLE_DIGITAL_LAB) + SET (cubicsdr_sources + ${cubicsdr_sources} + src/forms/DigitalConsole/DigitalConsole.cpp + src/forms/DigitalConsole/DigitalConsoleFrame.cpp + src/modules/modem/digital/ModemASK.cpp + src/modules/modem/digital/ModemAPSK.cpp + src/modules/modem/digital/ModemBPSK.cpp + src/modules/modem/digital/ModemDPSK.cpp + src/modules/modem/digital/ModemGMSK.cpp + src/modules/modem/digital/ModemPSK.cpp + src/modules/modem/digital/ModemOOK.cpp + src/modules/modem/digital/ModemST.cpp + src/modules/modem/digital/ModemSQAM.cpp + src/modules/modem/digital/ModemQAM.cpp + src/modules/modem/digital/ModemQPSK.cpp + ) + IF(ENABLE_LIQUID_EXPERIMENTAL) + SET (cubicsdr_sources + ${cubicsdr_sources} + src/modules/modem/digital/ModemFSK.cpp + ) + ENDIF() +ENDIF() + SET (cubicsdr_headers src/CubicSDRDefs.h src/CubicSDR.h @@ -303,6 +329,7 @@ SET (cubicsdr_headers src/AppConfig.h src/FrequencyDialog.h src/IOThread.h + src/ModemProperties.h src/sdr/SDRDeviceInfo.h src/sdr/SDRPostThread.h src/sdr/SDREnumerator.h @@ -316,16 +343,6 @@ SET (cubicsdr_headers src/modules/modem/Modem.h src/modules/modem/ModemAnalog.h src/modules/modem/ModemDigital.h - src/modules/modem/digital/ModemASK.h - src/modules/modem/digital/ModemAPSK.h - src/modules/modem/digital/ModemBPSK.h - src/modules/modem/digital/ModemDPSK.h - src/modules/modem/digital/ModemPSK.h - src/modules/modem/digital/ModemOOK.h - src/modules/modem/digital/ModemST.h - src/modules/modem/digital/ModemSQAM.h - src/modules/modem/digital/ModemQAM.h - src/modules/modem/digital/ModemQPSK.h src/modules/modem/analog/ModemAM.h src/modules/modem/analog/ModemDSB.h src/modules/modem/analog/ModemFM.h @@ -391,6 +408,31 @@ SET (cubicsdr_headers external/cubicvr2/math/vec4.h ) +IF(ENABLE_DIGITAL_LAB) +SET (cubicsdr_headers + ${cubicsdr_headers} + src/forms/DigitalConsole/DigitalConsole.h + src/forms/DigitalConsole/DigitalConsoleFrame.h + src/modules/modem/digital/ModemASK.h + src/modules/modem/digital/ModemAPSK.h + src/modules/modem/digital/ModemBPSK.h + src/modules/modem/digital/ModemDPSK.h + src/modules/modem/digital/ModemGMSK.h + src/modules/modem/digital/ModemPSK.h + src/modules/modem/digital/ModemOOK.h + src/modules/modem/digital/ModemST.h + src/modules/modem/digital/ModemSQAM.h + src/modules/modem/digital/ModemQAM.h + src/modules/modem/digital/ModemQPSK.h +) +IF(ENABLE_LIQUID_EXPERIMENTAL) + SET (cubicsdr_sources + ${cubicsdr_sources} + src/modules/modem/digital/ModemFSK.h + ) +ENDIF() +ENDIF() + SET (CUBICSDR_RESOURCES ${PROJECT_SOURCE_DIR}/font/vera_sans_mono12.fnt ${PROJECT_SOURCE_DIR}/font/vera_sans_mono16.fnt @@ -413,8 +455,11 @@ SOURCE_GROUP("Forms\\SDRDevices" REGULAR_EXPRESSION "src/forms/SDRDevices/${REG_ SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}") SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}") SOURCE_GROUP("Modem" REGULAR_EXPRESSION "src/modules/modem/${REG_EXT}") -SOURCE_GROUP("Modem-Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}") -SOURCE_GROUP("Modem-Digital" REGULAR_EXPRESSION "src/modules/modem/digital/${REG_EXT}") +SOURCE_GROUP("Modem\\Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}") +IF(ENABLE_DIGITAL_LAB) +SOURCE_GROUP("Modem\\Digital" REGULAR_EXPRESSION "src/modules/modem/digital/${REG_EXT}") +SOURCE_GROUP("Forms\\DigitalConsole" REGULAR_EXPRESSION "src/forms/DigitalConsole/${REG_EXT}") +ENDIF() 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}") @@ -428,6 +473,7 @@ SOURCE_GROUP("_ext-CubicVR2" REGULAR_EXPRESSION "external/cubicvr2/.*${REG_EXT}" include_directories ( ${PROJECT_SOURCE_DIR}/src/forms/SDRDevices + ${PROJECT_SOURCE_DIR}/src/forms/DigitalConsole ${PROJECT_SOURCE_DIR}/src/sdr ${PROJECT_SOURCE_DIR}/src/demod ${PROJECT_SOURCE_DIR}/src/modules diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 5b3daa2..69cf74e 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -67,46 +67,47 @@ AppFrame::AppFrame() : gainSpacerItem->Show(false); demodModeSelector = new ModeSelectorCanvas(demodPanel, attribList); - demodModeSelector->addChoice(0, "FM"); - demodModeSelector->addChoice(1, "FMS"); - demodModeSelector->addChoice(2, "AM"); - demodModeSelector->addChoice(3, "LSB"); - demodModeSelector->addChoice(4, "USB"); - demodModeSelector->addChoice(5, "DSB"); - demodModeSelector->addChoice(6, "I/Q"); + demodModeSelector->addChoice("FM"); + demodModeSelector->addChoice("FMS"); + demodModeSelector->addChoice("AM"); + demodModeSelector->addChoice("LSB"); + demodModeSelector->addChoice("USB"); + demodModeSelector->addChoice("DSB"); + demodModeSelector->addChoice("I/Q"); demodModeSelector->setSelection("FM"); demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band."); + demodModeSelector->SetMinSize(wxSize(40,-1)); + demodModeSelector->SetMaxSize(wxSize(40,-1)); demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0); #ifdef ENABLE_DIGITAL_LAB - demodModeSelectorAdv = new ModeSelectorCanvas(this, attribList); - demodModeSelectorAdv->addChoice(0, "ASK"); - demodModeSelectorAdv->addChoice(1, "APSK"); - demodModeSelectorAdv->addChoice(2, "BPSK"); - demodModeSelectorAdv->addChoice(3, "DPSK"); - demodModeSelectorAdv->addChoice(4, "PSK"); - demodModeSelectorAdv->addChoice(5, "OOK"); - demodModeSelectorAdv->addChoice(6, "ST"); - demodModeSelectorAdv->addChoice(7, "SQAM"); - demodModeSelectorAdv->addChoice(8, "QAM"); - demodModeSelectorAdv->addChoice(9, "QPSK"); + demodModeSelectorAdv = new ModeSelectorCanvas(demodPanel, attribList); + demodModeSelectorAdv->addChoice("ASK"); + demodModeSelectorAdv->addChoice("APSK"); + demodModeSelectorAdv->addChoice("BPSK"); + demodModeSelectorAdv->addChoice("DPSK"); + demodModeSelectorAdv->addChoice("PSK"); + demodModeSelectorAdv->addChoice("FSK"); + demodModeSelectorAdv->addChoice("GMSK"); + demodModeSelectorAdv->addChoice("OOK"); + demodModeSelectorAdv->addChoice("ST"); + demodModeSelectorAdv->addChoice("SQAM"); + demodModeSelectorAdv->addChoice("QAM"); + demodModeSelectorAdv->addChoice("QPSK"); demodModeSelectorAdv->setHelpTip("Choose advanced modulation types."); + demodModeSelectorAdv->SetMinSize(wxSize(40,-1)); + demodModeSelectorAdv->SetMaxSize(wxSize(40,-1)); demodTray->Add(demodModeSelectorAdv, 3, wxEXPAND | wxALL, 0); - - demodModeSelectorCons = new ModeSelectorCanvas(this, attribList); - demodModeSelectorCons->addChoice(1, "auto"); - demodModeSelectorCons->addChoice(2, "2"); - demodModeSelectorCons->addChoice(4, "4"); - demodModeSelectorCons->addChoice(8, "8"); - demodModeSelectorCons->addChoice(16, "16"); - demodModeSelectorCons->addChoice(32, "32"); - demodModeSelectorCons->addChoice(64, "64"); - demodModeSelectorCons->addChoice(128, "128"); - demodModeSelectorCons->addChoice(256, "256"); - demodModeSelectorCons->setHelpTip("Choose number of constallations types."); - demodTray->Add(demodModeSelectorCons, 2, wxEXPAND | wxALL, 0); #endif + modemPropertiesUpdated.store(false); + modemProps = new ModemProperties(demodPanel, wxID_ANY); + modemProps->SetMinSize(wxSize(200,-1)); + modemProps->SetMaxSize(wxSize(200,-1)); + + modemProps->Hide(); + demodTray->Add(modemProps, 15, wxEXPAND | wxALL, 0); + wxGetApp().getDemodSpectrumProcessor()->setup(1024); demodSpectrumCanvas = new SpectrumCanvas(demodPanel, attribList); demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); @@ -119,11 +120,14 @@ AppFrame::AppFrame() : demodWaterfallCanvas->setup(1024, 128); demodWaterfallCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas); + demodWaterfallCanvas->setMinBandwidth(8000); demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0); wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue()); demodWaterfallCanvas->getVisualDataQueue()->set_max_num_items(3); + demodVisuals->SetMinSize(wxSize(128,-1)); + demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); demodTray->AddSpacer(1); @@ -142,6 +146,7 @@ AppFrame::AppFrame() : scopeCanvas = new ScopeCanvas(demodPanel, attribList); scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum."); + scopeCanvas->SetMinSize(wxSize(128,-1)); demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0); wxGetApp().getScopeProcessor()->setup(2048); wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue()); @@ -833,7 +838,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); - if (demod) { + if (demod && demod->isModemInitialized()) { if (demod->isTracking()) { if (spectrumCanvas->getViewState()) { long long diff = abs(demod->getFrequency() - spectrumCanvas->getCenterFrequency()) + (demod->getBandwidth()/2) + (demod->getBandwidth()/4); @@ -851,6 +856,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demod->setTracking(false); } } + + if (demod->getBandwidth() != wxGetApp().getDemodMgr().getLastBandwidth()) { + wxGetApp().getDemodMgr().setLastBandwidth(demod->getBandwidth()); + } if (demod != activeDemodulator) { demodSignalMeter->setInputValue(demod->getSquelchLevel()); @@ -861,11 +870,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) { std::string dType = demod->getDemodulatorType(); demodModeSelector->setSelection(dType); #ifdef ENABLE_DIGITAL_LAB - int dCons = demod->getDemodulatorCons(); demodModeSelectorAdv->setSelection(dType); - demodModeSelectorCons->setSelection(dCons); #endif demodMuteButton->setSelection(demod->isMuted()?1:-1); + modemPropertiesUpdated.store(true); } if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { long long centerFreq = demod->getFrequency(); @@ -895,7 +903,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) { std::string dSelection = demodModeSelector->getSelectionLabel(); #ifdef ENABLE_DIGITAL_LAB std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel(); - int dSelectionCons = demodModeSelectorCons->getSelection(); // basic demodulators if (dSelection != "" && dSelection != demod->getDemodulatorType()) { @@ -907,11 +914,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demod->setDemodulatorType(dSelectionadv); demodModeSelector->setSelection(-1); } - - // set constellations - if (dSelectionCons != demod->getDemodulatorCons()) { - demod->setDemodulatorCons(dSelectionCons); - } #else // basic demodulators if (dSelection != "" && dSelection != demod->getDemodulatorType()) { @@ -951,13 +953,14 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demodGainMeter->setLevel(demodGainMeter->getInputValue()); } activeDemodulator = demod; + } else if (demod) { + // Wait state for current demodulator modem to activate.. } else { DemodulatorMgr *mgr = &wxGetApp().getDemodMgr(); std::string dSelection = demodModeSelector->getSelectionLabel(); #ifdef ENABLE_DIGITAL_LAB std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel(); - int dSelectionCons = demodModeSelectorCons->getSelection(); // basic demodulators if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) { @@ -969,11 +972,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) { mgr->setLastDemodulatorType(dSelectionadv); demodModeSelector->setSelection(-1); } - - // set constellations - if (dSelectionCons != mgr->getLastDemodulatorCons()) { - mgr->setLastDemodulatorCons(dSelectionCons); - } #else // basic demodulators if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) { @@ -1012,7 +1010,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { if (!demodTuner->HasFocus()) { demodTuner->SetFocus(); } - } else if (!wxGetApp().isDeviceSelectorOpen()) { + } else if (!wxGetApp().isDeviceSelectorOpen() && (!modemProps || !modemProps->isMouseInView())) { if (!waterfallCanvas->HasFocus()) { waterfallCanvas->SetFocus(); } @@ -1026,7 +1024,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wxGetApp().getAudioVisualQueue()->set_max_num_items((scopeCanvas->scopeVisible()?1:0) + (scopeCanvas->spectrumVisible()?1:0)); wxGetApp().getScopeProcessor()->run(); -// wxGetApp().getSpectrumDistributor()->run(); SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor(); @@ -1069,11 +1066,24 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); wxGetApp().getSDRPostThread()->setIQVisualRange(waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth()); -// waterfallCanvas->processInputQueue(); -// waterfallCanvas->Refresh(); -// demodWaterfallCanvas->processInputQueue(); -// demodWaterfallCanvas->Refresh(); - + demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); + + if (modemPropertiesUpdated.load() && demod && demod->isModemInitialized()) { + modemProps->initProperties(demod->getModemArgs()); + modemPropertiesUpdated.store(false); + demodTray->Layout(); +#if ENABLE_DIGITAL_LAB + if (demod->getModemType() == "digital") { + ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)demod->getOutput(); + if (!outp->getDialog()) { + outp->setTitle(demod->getDemodulatorType() + ": " + frequencyToStr(demod->getFrequency())); + outp->setDialog(new DigitalConsole(this, outp)); + } + demod->showOutput(); + } +#endif + } + if (!this->IsActive()) { std::this_thread::sleep_for(std::chrono::milliseconds(25)); } @@ -1134,6 +1144,14 @@ void AppFrame::saveSession(std::string fileName) { *demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; *demod->newChild("gain") = (*instance_i)->getGain(); *demod->newChild("muted") = (*instance_i)->isMuted() ? 1 : 0; + + ModemSettings saveSettings = (*instance_i)->readModemSettings(); + if (saveSettings.size()) { + DataNode *settingsNode = demod->newChild("settings"); + for (ModemSettings::const_iterator msi = saveSettings.begin(); msi != saveSettings.end(); msi++) { + *settingsNode->newChild(msi->first.c_str()) = msi->second; + } + } } s.SaveToFileXML(fileName); @@ -1177,35 +1195,79 @@ bool AppFrame::loadSession(std::string fileName) { long bandwidth = *demod->getNext("bandwidth"); long long freq = *demod->getNext("frequency"); - std::string type = demod->hasAnother("type") ? string(*demod->getNext("type")) : "FM"; float squelch_level = demod->hasAnother("squelch_level") ? (float) *demod->getNext("squelch_level") : 0; int squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0; int muted = demod->hasAnother("muted") ? (int) *demod->getNext("muted") : 0; std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : ""; float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0; - // TODO: Check if "type" is numeric and perform update to new values - //#define DEMOD_TYPE_NULL 0 - //#define DEMOD_TYPE_FM 1 - //#define DEMOD_TYPE_AM 2 - //#define DEMOD_TYPE_LSB 3 - //#define DEMOD_TYPE_USB 4 - //#define DEMOD_TYPE_DSB 5 - //#define DEMOD_TYPE_ASK 6 - //#define DEMOD_TYPE_APSK 7 - //#define DEMOD_TYPE_BPSK 8 - //#define DEMOD_TYPE_DPSK 9 - //#define DEMOD_TYPE_PSK 10 - //#define DEMOD_TYPE_OOK 11 - //#define DEMOD_TYPE_ST 12 - //#define DEMOD_TYPE_SQAM 13 - //#define DEMOD_TYPE_QAM 14 - //#define DEMOD_TYPE_QPSK 15 - //#define DEMOD_TYPE_RAW 16 + std::string type = "FM"; + DataNode *demodTypeNode = demod->hasAnother("type")?demod->getNext("type"):nullptr; + + if (demodTypeNode->element()->getDataType() == DATA_INT) { + int legacyType = *demodTypeNode; + int legacyStereo = demod->hasAnother("stereo") ? (int) *demod->getNext("stereo") : 0; + switch (legacyType) { // legacy demod ID + case 1: type = legacyStereo?"FMS":"FM"; break; + case 2: type = "AM"; break; + case 3: type = "LSB"; break; + case 4: type = "USB"; break; + case 5: type = "DSB"; break; + case 6: type = "ASK"; break; + case 7: type = "APSK"; break; + case 8: type = "BPSK"; break; + case 9: type = "DPSK"; break; + case 10: type = "PSK"; break; + case 11: type = "OOK"; break; + case 12: type = "ST"; break; + case 13: type = "SQAM"; break; + case 14: type = "QAM"; break; + case 15: type = "QPSK"; break; + case 16: type = "I/Q"; break; + default: type = "FM"; break; + } + } else if (demodTypeNode->element()->getDataType() == DATA_STRING) { + demodTypeNode->element()->get(type); + } + + ModemSettings mSettings; + + if (demod->hasAnother("settings")) { + DataNode *modemSettings = demod->getNext("settings"); + for (int msi = 0, numSettings = modemSettings->numChildren(); msi < numSettings; msi++) { + DataNode *settingNode = modemSettings->child(msi); + std::string keyName = settingNode->getName(); + std::string strSettingValue = ""; + + int dataType = settingNode->element()->getDataType(); + + try { + if (dataType == DATA_STRING) { + settingNode->element()->get(strSettingValue); + } else if (dataType == DATA_INT || dataType == DATA_LONG || dataType == DATA_LONGLONG) { + long long intSettingValue = *settingNode; + strSettingValue = std::to_string(intSettingValue); + } else if (dataType == DATA_FLOAT || dataType == DATA_DOUBLE) { + double floatSettingValue = *settingNode; + strSettingValue = std::to_string(floatSettingValue); + } else { + std::cout << "Unhandled setting data type: " << dataType << std::endl; + } + } catch (DataTypeMismatchException e) { + std::cout << "Setting data type mismatch: " << dataType << std::endl; + } + + if (keyName != "" && strSettingValue != "") { + mSettings[keyName] = strSettingValue; + } + } + } + DemodulatorInstance *newDemod = wxGetApp().getDemodMgr().newThread(); loadedDemod = newDemod; numDemodulators++; + newDemod->writeModemSettings(mSettings); newDemod->setDemodulatorType(type); newDemod->setBandwidth(bandwidth); newDemod->setFrequency(freq); @@ -1269,3 +1331,8 @@ FFTVisualDataThread *AppFrame::getWaterfallDataThread() { return waterfallDataThread; } +void AppFrame::updateModemProperties(ModemArgInfoList args) { + newModemArgs = args; + modemPropertiesUpdated.store(true); +} + diff --git a/src/AppFrame.h b/src/AppFrame.h index 694d8c7..454b5e4 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -16,6 +16,7 @@ #include "GainCanvas.h" #include "FFTVisualDataThread.h" #include "SDRDeviceInfo.h" +#include "ModemProperties.h" //#include "UITestCanvas.h" #include @@ -67,6 +68,8 @@ public: FFTVisualDataThread *getWaterfallDataThread(); + void updateModemProperties(ModemArgInfoList args); + private: void OnMenu(wxCommandEvent& event); void OnClose(wxCloseEvent& event); @@ -81,7 +84,6 @@ private: ModeSelectorCanvas *demodModeSelector; #ifdef ENABLE_DIGITAL_LAB ModeSelectorCanvas *demodModeSelectorAdv; - ModeSelectorCanvas *demodModeSelectorCons; #endif SpectrumCanvas *demodSpectrumCanvas; WaterfallCanvas *demodWaterfallCanvas; @@ -121,6 +123,10 @@ private: std::thread *t_FFTData; SDRDeviceInfo *devInfo; std::atomic_bool deviceChanged; + + ModemProperties *modemProps; + std::atomic_bool modemPropertiesUpdated; + ModemArgInfoList newModemArgs; wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 4227bdf..23eebec 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -20,20 +20,20 @@ IMPLEMENT_APP(CubicSDR) -#ifdef ENABLE_DIGITAL_LAB -// console output buffer for windows -#ifdef _WINDOWS -class outbuf : public std::streambuf { - public: - outbuf() { - setp(0, 0); - } - virtual int_type overflow(int_type c = traits_type::eof()) { - return fputc(c, stdout) == EOF ? traits_type::eof() : c; - } -}; -#endif -#endif +//#ifdef ENABLE_DIGITAL_LAB +//// console output buffer for windows +//#ifdef _WINDOWS +//class outbuf : public std::streambuf { +// public: +// outbuf() { +// setp(0, 0); +// } +// virtual int_type overflow(int_type c = traits_type::eof()) { +// return fputc(c, stdout) == EOF ? traits_type::eof() : c; +// } +//}; +//#endif +//#endif #ifdef MINGW_PATCH FILE _iob[] = { *stdin, *stdout, *stderr }; @@ -149,18 +149,18 @@ bool CubicSDR::OnInit() { return false; } -#ifdef ENABLE_DIGITAL_LAB - // console output for windows - #ifdef _WINDOWS - if (AllocConsole()) { - freopen("CONOUT$", "w", stdout); - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); - } - outbuf ob; - std::streambuf *sb = std::cout.rdbuf(&ob); - std::cout.rdbuf(sb); - #endif -#endif +//#ifdef ENABLE_DIGITAL_LAB +// // console output for windows +// #ifdef _WINDOWS +// if (AllocConsole()) { +// freopen("CONOUT$", "w", stdout); +// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); +// } +// outbuf ob; +// std::streambuf *sb = std::cout.rdbuf(&ob); +// std::cout.rdbuf(sb); +// #endif +//#endif wxApp::SetAppName("CubicSDR"); @@ -172,17 +172,23 @@ bool CubicSDR::OnInit() { Modem::addModemFactory(new ModemDSB); Modem::addModemFactory(new ModemIQ); +#ifdef ENABLE_DIGITAL_LAB Modem::addModemFactory(new ModemAPSK); Modem::addModemFactory(new ModemASK); Modem::addModemFactory(new ModemBPSK); Modem::addModemFactory(new ModemDPSK); +#if ENABLE_LIQUID_EXPERIMENTAL + Modem::addModemFactory(new ModemFSK); +#endif + Modem::addModemFactory(new ModemGMSK); Modem::addModemFactory(new ModemOOK); Modem::addModemFactory(new ModemPSK); Modem::addModemFactory(new ModemQAM); Modem::addModemFactory(new ModemQPSK); Modem::addModemFactory(new ModemSQAM); Modem::addModemFactory(new ModemST); - +#endif + frequency = wxGetApp().getConfig()->getCenterFreq(); offset = 0; ppm = 0; diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 54bb4b0..5895f6b 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -37,16 +37,22 @@ #include "ModemDSB.h" #include "ModemIQ.h" +#ifdef ENABLE_DIGITAL_LAB #include "ModemAPSK.h" #include "ModemASK.h" #include "ModemBPSK.h" #include "ModemDPSK.h" +#if ENABLE_LIQUID_EXPERIMENTAL +#include "ModemFSK.h" +#endif +#include "ModemGMSK.h" #include "ModemOOK.h" #include "ModemPSK.h" #include "ModemQAM.h" #include "ModemQPSK.h" #include "ModemSQAM.h" #include "ModemST.h" +#endif #include @@ -123,7 +129,6 @@ public: void setDeviceSelectorClosed(); bool isDeviceSelectorOpen(); void closeDeviceSelector(); - void setAGCMode(bool mode); bool getAGCMode(); diff --git a/src/ModemProperties.cpp b/src/ModemProperties.cpp new file mode 100644 index 0000000..0472bff --- /dev/null +++ b/src/ModemProperties.cpp @@ -0,0 +1,179 @@ +#include "ModemProperties.h" +#include "CubicSDR.h" + +ModemProperties::ModemProperties(wxWindow *parent, wxWindowID winid, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxPanel(parent, winid, pos, size, style, name) { + + m_propertyGrid = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE); + + bSizer = new wxBoxSizer( wxVERTICAL ); + + bSizer->Add(m_propertyGrid, 1, wxEXPAND, 5); + + this->SetSizer(bSizer); + + m_propertyGrid->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( ModemProperties::OnChange ), NULL, this ); + this->Connect( wxEVT_SHOW, wxShowEventHandler( ModemProperties::OnShow ), NULL, this ); + + this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseEnter ), NULL, this); + this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseLeave ), NULL, this); + + mouseInView = false; +} + +void ModemProperties::OnShow(wxShowEvent &event) { +} + +ModemProperties::~ModemProperties() { + +} + +void ModemProperties::initProperties(ModemArgInfoList newArgs) { + args = newArgs; + + bSizer->Layout(); + m_propertyGrid->Clear(); + + if (newArgs.size() == 0) { + Hide(); + return; + } else { + Show(); + } + + m_propertyGrid->Append(new wxPropertyCategory("Modem Settings")); + + ModemArgInfoList::const_iterator args_i; + + for (args_i = args.begin(); args_i != args.end(); args_i++) { + ModemArgInfo arg = (*args_i); + props[arg.key] = addArgInfoProperty(m_propertyGrid, arg); + } + + m_propertyGrid->FitColumns(); +} + +wxPGProperty *ModemProperties::addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg) { + wxPGProperty *prop = nullptr; + + int intVal; + double floatVal; + std::vector::iterator stringIter; + + switch (arg.type) { + case ModemArgInfo::INT: + try { + intVal = std::stoi(arg.value); + } catch (std::invalid_argument e) { + intVal = 0; + } + prop = pg->Append( new wxIntProperty(arg.name, wxPG_LABEL, intVal) ); + if (arg.range.minimum() != arg.range.maximum()) { + pg->SetPropertyAttribute( prop, wxPG_ATTR_MIN, arg.range.minimum()); + pg->SetPropertyAttribute( prop, wxPG_ATTR_MAX, arg.range.maximum()); + } + break; + case ModemArgInfo::FLOAT: + try { + floatVal = std::stod(arg.value); + } catch (std::invalid_argument e) { + floatVal = 0; + } + prop = pg->Append( new wxFloatProperty(arg.name, wxPG_LABEL, floatVal) ); + if (arg.range.minimum() != arg.range.maximum()) { + pg->SetPropertyAttribute( prop, wxPG_ATTR_MIN, arg.range.minimum()); + pg->SetPropertyAttribute( prop, wxPG_ATTR_MAX, arg.range.maximum()); + } + break; + case ModemArgInfo::BOOL: + prop = pg->Append( new wxBoolProperty(arg.name, wxPG_LABEL, (arg.value=="true")) ); + break; + case ModemArgInfo::STRING: + if (arg.options.size()) { + intVal = 0; + prop = pg->Append( new wxEnumProperty(arg.name, wxPG_LABEL) ); + for (stringIter = arg.options.begin(); stringIter != arg.options.end(); stringIter++) { + std::string optName = (*stringIter); + std::string displayName = optName; + if (arg.optionNames.size()) { + displayName = arg.optionNames[intVal]; + } + + prop->AddChoice(displayName); + if ((*stringIter)==arg.value) { + prop->SetChoiceSelection(intVal); + } + + intVal++; + } + } else { + prop = pg->Append( new wxStringProperty(arg.name, wxPG_LABEL, arg.value) ); + } + break; + case ModemArgInfo::PATH_DIR: + break; + case ModemArgInfo::PATH_FILE: + break; + case ModemArgInfo::COLOR: + break; + } + + if (prop != NULL) { + prop->SetHelpString(arg.key + ": " + arg.description); + } + + return prop; +} + +std::string ModemProperties::readProperty(std::string key) { + int i = 0; + ModemArgInfoList::const_iterator args_i; + + for (args_i = args.begin(); args_i != args.end(); args_i++) { + ModemArgInfo arg = (*args_i); + if (arg.key == key) { + wxPGProperty *prop = props[key]; + + std::string result = ""; + if (arg.type == ModemArgInfo::STRING && arg.options.size()) { + return arg.options[prop->GetChoiceSelection()]; + } else if (arg.type == ModemArgInfo::BOOL) { + return (prop->GetValueAsString()=="True")?"true":"false"; + } else { + return prop->GetValueAsString().ToStdString(); + } + } + i++; + } + return ""; +} + +void ModemProperties::OnChange(wxPropertyGridEvent &event) { + DemodulatorInstance *inst = wxGetApp().getDemodMgr().getLastActiveDemodulator(); + + if (!inst) { + return; + } + + std::map::const_iterator prop_i; + for (prop_i = props.begin(); prop_i != props.end(); prop_i++) { + if (prop_i->second == event.m_property) { + std::string key = prop_i->first; + std::string value = readProperty(prop_i->first); + inst->writeModemSetting(key, value); + return; + } + } +} + +void ModemProperties::OnMouseEnter(wxMouseEvent &event) { + mouseInView = true; +} + +void ModemProperties::OnMouseLeave(wxMouseEvent &event) { + mouseInView = false; +} + +bool ModemProperties::isMouseInView() { + return mouseInView; +} diff --git a/src/ModemProperties.h b/src/ModemProperties.h new file mode 100644 index 0000000..326c947 --- /dev/null +++ b/src/ModemProperties.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include + +#include "Modem.h" + +class ModemProperties : public wxPanel { +public: + ModemProperties( + wxWindow *parent, + wxWindowID winid = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL | wxNO_BORDER, + const wxString& name = wxPanelNameStr + ); + ~ModemProperties(); + + void initProperties(ModemArgInfoList newArgs); + bool isMouseInView(); + +private: + wxPGProperty *addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg); + std::string readProperty(std::string); + void OnChange(wxPropertyGridEvent &event); + void OnShow(wxShowEvent &event); + + void OnMouseEnter(wxMouseEvent &event); + void OnMouseLeave(wxMouseEvent &event); + + wxBoxSizer* bSizer; + wxPropertyGrid* m_propertyGrid; + ModemArgInfoList args; + std::map props; + bool mouseInView; +}; \ No newline at end of file diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h index 01ebda5..7af40b3 100644 --- a/src/audio/AudioThread.h +++ b/src/audio/AudioThread.h @@ -18,6 +18,7 @@ public: int sampleRate; int channels; float peak; + int type; std::vector data; std::mutex busy_update; diff --git a/src/demod/DemodDefs.h b/src/demod/DemodDefs.h index 52f1050..b7d78a3 100644 --- a/src/demod/DemodDefs.h +++ b/src/demod/DemodDefs.h @@ -14,9 +14,6 @@ class DemodulatorThreadCommand { public: enum DemodulatorThreadCommandEnum { DEMOD_THREAD_CMD_NULL, - DEMOD_THREAD_CMD_SET_BANDWIDTH, - DEMOD_THREAD_CMD_SET_FREQUENCY, - DEMOD_THREAD_CMD_SET_AUDIO_RATE, DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED, DEMOD_THREAD_CMD_DEMOD_TERMINATED, DEMOD_THREAD_CMD_AUDIO_TERMINATED @@ -82,6 +79,7 @@ class DemodulatorThreadPostIQData: public ReferenceCounter { public: std::vector data; long long sampleRate; + std::string modemName; std::string modemType; Modem *modem; ModemKit *modemKit; @@ -124,23 +122,3 @@ typedef ThreadQueue DemodulatorThreadInputQueue; typedef ThreadQueue DemodulatorThreadPostInputQueue; typedef ThreadQueue DemodulatorThreadCommandQueue; typedef ThreadQueue DemodulatorThreadControlCommandQueue; - -class DemodulatorThreadParameters { -public: - long long frequency; - long long sampleRate; - unsigned int bandwidth; // set equal to disable second stage re-sampling? - unsigned int audioSampleRate; - - std::string demodType; - - DemodulatorThreadParameters() : - frequency(0), sampleRate(DEFAULT_SAMPLE_RATE), bandwidth(200000), audioSampleRate(0), - demodType("FM") { - - } - - ~DemodulatorThreadParameters() { - - } -}; diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 88139be..f3da7fb 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -1,8 +1,12 @@ #include "DemodulatorInstance.h" +#include "CubicSDR.h" DemodulatorInstance::DemodulatorInstance() : - t_PreDemod(NULL), t_Demod(NULL), t_Audio(NULL) { + t_PreDemod(nullptr), t_Demod(nullptr), t_Audio(nullptr) { +#if ENABLE_DIGITAL_LAB + activeOutput = nullptr; +#endif terminated.store(true); audioTerminated.store(true); demodTerminated.store(true); @@ -12,23 +16,20 @@ DemodulatorInstance::DemodulatorInstance() : muted.store(false); tracking.store(false); follow.store(false); - currentAudioSampleRate.store(0); - currentFrequency.store(0); - currentBandwidth.store(0); currentOutputDevice.store(-1); currentAudioGain.store(1.0); label = new std::string("Unnamed"); pipeIQInputData = new DemodulatorThreadInputQueue; pipeIQDemodData = new DemodulatorThreadPostInputQueue; - pipeDemodCommand = new DemodulatorThreadCommandQueue; pipeDemodNotify = new DemodulatorThreadCommandQueue; - demodulatorPreThread = new DemodulatorPreThread(); + audioThread = new AudioThread(); + + demodulatorPreThread = new DemodulatorPreThread(this); demodulatorPreThread->setInputQueue("IQDataInput",pipeIQInputData); demodulatorPreThread->setOutputQueue("IQDataOutput",pipeIQDemodData); demodulatorPreThread->setOutputQueue("NotifyQueue",pipeDemodNotify); - demodulatorPreThread->setInputQueue("CommandQueue",pipeDemodCommand); pipeAudioData = new AudioThreadInputQueue; threadQueueControl = new DemodulatorThreadControlCommandQueue; @@ -39,20 +40,19 @@ DemodulatorInstance::DemodulatorInstance() : demodulatorThread->setOutputQueue("NotifyQueue",pipeDemodNotify); demodulatorThread->setOutputQueue("AudioDataOutput", pipeAudioData); - audioThread = new AudioThread(); audioThread->setInputQueue("AudioDataInput", pipeAudioData); audioThread->setOutputQueue("NotifyQueue", pipeDemodNotify); - - currentDemodType = demodulatorPreThread->getParams().demodType; } DemodulatorInstance::~DemodulatorInstance() { +#if ENABLE_DIGITAL_LAB + delete activeOutput; +#endif delete audioThread; delete demodulatorThread; delete demodulatorPreThread; delete pipeIQInputData; delete pipeIQDemodData; - delete pipeDemodCommand; delete pipeDemodNotify; delete threadQueueControl; delete pipeAudioData; @@ -67,17 +67,8 @@ void DemodulatorInstance::run() { return; } -// while (!isTerminated()) { -// std::this_thread::sleep_for(std::chrono::milliseconds(1)); -// } - - currentFrequency = demodulatorPreThread->getParams().frequency; - currentAudioSampleRate = AudioThread::deviceSampleRate[getOutputDevice()]; - demodulatorPreThread->getParams().audioSampleRate = currentAudioSampleRate; - setDemodulatorType(demodulatorPreThread->getParams().demodType); - t_Audio = new std::thread(&AudioThread::threadMain, audioThread); - + #ifdef __APPLE__ // Already using pthreads, might as well do some custom init.. pthread_attr_t attr; size_t size; @@ -113,10 +104,6 @@ void DemodulatorInstance::updateLabel(long long freq) { setLabel(newLabel.str()); } -DemodulatorThreadCommandQueue *DemodulatorInstance::getCommandQueue() { - return pipeDemodCommand; -} - void DemodulatorInstance::terminate() { std::cout << "Terminating demodulator audio thread.." << std::endl; audioThread->terminate(); @@ -156,6 +143,11 @@ bool DemodulatorInstance::isTerminated() { #else t_Demod->join(); delete t_Demod; +#endif +#if ENABLE_DIGITAL_LAB + if (activeOutput) { + closeOutput(); + } #endif demodTerminated = true; break; @@ -184,8 +176,18 @@ bool DemodulatorInstance::isActive() { void DemodulatorInstance::setActive(bool state) { if (active && !state) { +#if ENABLE_DIGITAL_LAB + if (activeOutput && !isTerminated()) { + activeOutput->Hide(); + } +#endif audioThread->setActive(state); } else if (!active && state) { +#if ENABLE_DIGITAL_LAB + if (activeOutput && getModemType() == "digital") { + activeOutput->Show(); + } +#endif audioThread->setActive(state); } if (!state) { @@ -225,6 +227,8 @@ float DemodulatorInstance::getSignalLevel() { void DemodulatorInstance::setSquelchLevel(float signal_level_in) { demodulatorThread->setSquelchLevel(signal_level_in); + wxGetApp().getDemodMgr().setLastSquelchLevel(signal_level_in); + wxGetApp().getDemodMgr().setLastSquelchEnabled(true); } float DemodulatorInstance::getSquelchLevel() { @@ -254,35 +258,36 @@ int DemodulatorInstance::getOutputDevice() { return currentOutputDevice; } -void DemodulatorInstance::checkBandwidth() { -// if ((currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB) && (getBandwidth() % 2)) { -// setBandwidth(getBandwidth()+1); -// } -} - void DemodulatorInstance::setDemodulatorType(std::string demod_type_in) { - currentDemodType = demod_type_in; - - if (currentDemodType == "I/Q") { - if (currentAudioSampleRate) { - setBandwidth(currentAudioSampleRate); - } else { - setBandwidth(AudioThread::deviceSampleRate[getOutputDevice()]); - } - } setGain(getGain()); + if (demodulatorPreThread) { + std::string currentDemodType = demodulatorPreThread->getDemodType(); + if ((currentDemodType != "") && (currentDemodType != demod_type_in)) { + lastModemSettings[currentDemodType] = demodulatorPreThread->readModemSettings(); + lastModemBandwidth[currentDemodType] = demodulatorPreThread->getBandwidth(); + } +#if ENABLE_DIGITAL_LAB + if (activeOutput) { + activeOutput->Hide(); + } +#endif - demodulatorPreThread->getParams().demodType = currentDemodType; - if (!active) { - checkBandwidth(); - demodulatorPreThread->setDemodType(currentDemodType); - } else if (demodulatorThread && threadQueueControl) { - demodulatorPreThread->setDemodType(currentDemodType); + demodulatorPreThread->setDemodType(demod_type_in); + int lastbw = 0; + if (currentDemodType != "" && lastModemBandwidth.find(demod_type_in) != lastModemBandwidth.end()) { + lastbw = lastModemBandwidth[demod_type_in]; + } + if (!lastbw) { + lastbw = Modem::getModemDefaultSampleRate(demod_type_in); + } + if (lastbw) { + setBandwidth(lastbw); + } } } std::string DemodulatorInstance::getDemodulatorType() { - return currentDemodType; + return demodulatorPreThread->getDemodType(); } void DemodulatorInstance::setDemodulatorLock(bool demod_lock_in) { @@ -302,101 +307,50 @@ int DemodulatorInstance::getDemodulatorLock() { return 0; } -void DemodulatorInstance::setDemodulatorCons(int demod_cons_in) { - Modem *cModem = demodulatorPreThread->getModem(); - if (cModem && cModem->getType() == "digital") { - ((ModemDigital *)cModem)->setDemodulatorCons(demod_cons_in); - } -} - -int DemodulatorInstance::getDemodulatorCons() { - Modem *cModem = demodulatorPreThread->getModem(); - if (cModem && cModem->getType() == "digital") { - return ((ModemDigital *)cModem)->getDemodulatorCons(); - } - return 0; -} - void DemodulatorInstance::setBandwidth(int bw) { - if (currentDemodType == "I/Q") { - if (currentAudioSampleRate) { - bw = currentAudioSampleRate; - } else { - bw = AudioThread::deviceSampleRate[getOutputDevice()]; - } - } - if (!active && demodulatorPreThread != NULL) { - currentBandwidth = bw; - checkBandwidth(); - demodulatorPreThread->getParams().bandwidth = currentBandwidth; - } else if (demodulatorPreThread && pipeDemodCommand) { - DemodulatorThreadCommand command; - command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH; - currentBandwidth = bw; - checkBandwidth(); - command.llong_value = currentBandwidth; - pipeDemodCommand->push(command); - } + demodulatorPreThread->setBandwidth(bw); } int DemodulatorInstance::getBandwidth() { - if (!currentBandwidth) { - currentBandwidth = demodulatorPreThread->getParams().bandwidth; - } - return currentBandwidth; + return demodulatorPreThread->getBandwidth(); } void DemodulatorInstance::setFrequency(long long freq) { if ((freq - getBandwidth() / 2) <= 0) { freq = getBandwidth() / 2; } - if (!active) { - currentFrequency = freq; - demodulatorPreThread->getParams().frequency = currentFrequency; - } else if (demodulatorPreThread && pipeDemodCommand) { - DemodulatorThreadCommand command; - command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY; - currentFrequency = freq; - command.llong_value = freq; - pipeDemodCommand->push(command); + + demodulatorPreThread->setFrequency(freq); +#if ENABLE_DIGITAL_LAB + if (activeOutput) { + if (isModemInitialized() && getModemType() == "digital") { + ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)getOutput(); + outp->setTitle(getDemodulatorType() + ": " + frequencyToStr(getFrequency())); + } } +#endif } long long DemodulatorInstance::getFrequency() { - if (!currentFrequency) { - currentFrequency = demodulatorPreThread->getParams().frequency; - } - return currentFrequency; + return demodulatorPreThread->getFrequency(); } - void DemodulatorInstance::setAudioSampleRate(int sampleRate) { - if (terminated) { - currentAudioSampleRate = sampleRate; - demodulatorPreThread->getParams().audioSampleRate = sampleRate; - } else if (demodulatorPreThread && pipeDemodCommand) { - DemodulatorThreadCommand command; - command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE; - currentAudioSampleRate = sampleRate; - command.llong_value = sampleRate; - pipeDemodCommand->push(command); - } - if (currentDemodType == "I/Q") { - setBandwidth(currentAudioSampleRate); - } + demodulatorPreThread->setSampleRate(sampleRate); } int DemodulatorInstance::getAudioSampleRate() { - if (!currentAudioSampleRate) { - currentAudioSampleRate = audioThread->getSampleRate(); + if (!audioThread) { + return 0; } - return currentAudioSampleRate; + return audioThread->getSampleRate(); } void DemodulatorInstance::setGain(float gain_in) { currentAudioGain = gain_in; audioThread->setGain(gain_in); + wxGetApp().getDemodMgr().setLastGain(gain_in); } float DemodulatorInstance::getGain() { @@ -426,8 +380,91 @@ bool DemodulatorInstance::isMuted() { void DemodulatorInstance::setMuted(bool muted) { this->muted = muted; demodulatorThread->setMuted(muted); + wxGetApp().getDemodMgr().setLastMuted(muted); } DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() { return pipeIQInputData; } + +ModemArgInfoList DemodulatorInstance::getModemArgs() { + Modem *m = demodulatorPreThread->getModem(); + + ModemArgInfoList args; + if (m != nullptr) { + args = m->getSettings(); + } + return args; +} + +std::string DemodulatorInstance::readModemSetting(std::string setting) { + return demodulatorPreThread->readModemSetting(setting); +} + +void DemodulatorInstance::writeModemSetting(std::string setting, std::string value) { + demodulatorPreThread->writeModemSetting(setting, value); +} + +ModemSettings DemodulatorInstance::readModemSettings() { + return demodulatorPreThread->readModemSettings(); +} + +void DemodulatorInstance::writeModemSettings(ModemSettings settings) { + demodulatorPreThread->writeModemSettings(settings); +} + +bool DemodulatorInstance::isModemInitialized() { + if (!demodulatorPreThread || isTerminated()) { + return false; + } + return demodulatorPreThread->isInitialized(); +} + +std::string DemodulatorInstance::getModemType() { + if (isModemInitialized()) { + return demodulatorPreThread->getModem()->getType(); + } + return ""; +} + +ModemSettings DemodulatorInstance::getLastModemSettings(std::string demodType) { + if (lastModemSettings.find(demodType) != lastModemSettings.end()) { + return lastModemSettings[demodType]; + } else { + ModemSettings mods; + return mods; + } +} + +#if ENABLE_DIGITAL_LAB +ModemDigitalOutput *DemodulatorInstance::getOutput() { + if (activeOutput == nullptr) { + activeOutput = new ModemDigitalOutputConsole(); + } + return activeOutput; +} + +void DemodulatorInstance::showOutput() { + if (activeOutput != nullptr) { + activeOutput->Show(); + } +} + +void DemodulatorInstance::hideOutput() { + if (activeOutput != nullptr) { + activeOutput->Hide(); + } +} + +void DemodulatorInstance::closeOutput() { + if (isModemInitialized()) { + if (getModemType() == "digital") { + ModemDigital *dModem = (ModemDigital *)demodulatorPreThread->getModem(); + dModem->setOutput(nullptr); + } + } + if (activeOutput) { + activeOutput->Close(); + } +} +#endif \ No newline at end of file diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index 818d72b..b03184e 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -10,6 +10,10 @@ #include "ModemDigital.h" #include "ModemAnalog.h" +#if ENABLE_DIGITAL_LAB +#include "DigitalConsole.h" +#endif + class DemodulatorInstance { public: @@ -58,9 +62,6 @@ public: void setDemodulatorLock(bool demod_lock_in); int getDemodulatorLock(); - - void setDemodulatorCons(int demod_cons_in); - int getDemodulatorCons(); void setBandwidth(int bw); int getBandwidth(); @@ -73,7 +74,7 @@ public: void setAudioSampleRate(int sampleRate); int getAudioSampleRate(); - + bool isFollow(); void setFollow(bool follow); @@ -85,11 +86,27 @@ public: DemodulatorThreadInputQueue *getIQInputDataPipe(); + ModemArgInfoList getModemArgs(); + std::string readModemSetting(std::string setting); + ModemSettings readModemSettings(); + void writeModemSetting(std::string setting, std::string value); + void writeModemSettings(ModemSettings settings); + + bool isModemInitialized(); + std::string getModemType(); + ModemSettings getLastModemSettings(std::string demodType); + +#if ENABLE_DIGITAL_LAB + ModemDigitalOutput *getOutput(); + void showOutput(); + void hideOutput(); + void closeOutput(); +#endif + protected: DemodulatorThreadInputQueue* pipeIQInputData; DemodulatorThreadPostInputQueue* pipeIQDemodData; AudioThreadInputQueue *pipeAudioData; - DemodulatorThreadCommandQueue* pipeDemodCommand; DemodulatorThreadCommandQueue* pipeDemodNotify; DemodulatorPreThread *demodulatorPreThread; DemodulatorThread *demodulatorThread; @@ -97,8 +114,6 @@ protected: private: - void checkBandwidth(); - std::atomic label; // std::atomic_bool terminated; // std::atomic_bool demodTerminated; // @@ -108,11 +123,12 @@ private: std::atomic_bool squelch; std::atomic_bool muted; - std::atomic_llong currentFrequency; - std::atomic_int currentBandwidth; - std::string currentDemodType; std::atomic_int currentOutputDevice; - std::atomic_int currentAudioSampleRate; std::atomic currentAudioGain; std::atomic_bool follow, tracking; - }; + std::map lastModemSettings; + std::map lastModemBandwidth; +#if ENABLE_DIGITAL_LAB + ModemDigitalOutput *activeOutput; +#endif +}; diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index fc6c4e1..106d31a 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -8,7 +8,6 @@ DemodulatorMgr::DemodulatorMgr() : activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType( DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(-100), lastGain(1.0), lastMuted(false) { - } DemodulatorMgr::~DemodulatorMgr() { @@ -88,6 +87,7 @@ void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool tempo if (!temporary) { if (activeDemodulator != NULL) { lastActiveDemodulator = activeDemodulator; + updateLastState(); } else { lastActiveDemodulator = demod; } @@ -121,8 +121,6 @@ DemodulatorInstance *DemodulatorMgr::getActiveDemodulator() { } DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() { - updateLastState(); - return lastActiveDemodulator; } @@ -162,10 +160,10 @@ void DemodulatorMgr::updateLastState() { lastBandwidth = lastActiveDemodulator->getBandwidth(); lastDemodType = lastActiveDemodulator->getDemodulatorType(); lastDemodLock = lastActiveDemodulator->getDemodulatorLock(); - lastDemodCons = lastActiveDemodulator->getDemodulatorCons(); lastSquelchEnabled = lastActiveDemodulator->isSquelchEnabled(); lastSquelch = lastActiveDemodulator->getSquelchLevel(); lastGain = lastActiveDemodulator->getGain(); + lastModemSettings[lastDemodType] = lastActiveDemodulator->readModemSettings(); } } @@ -175,8 +173,8 @@ int DemodulatorMgr::getLastBandwidth() const { } void DemodulatorMgr::setLastBandwidth(int lastBandwidth) { - if (lastBandwidth < 1500) { - lastBandwidth = 1500; + if (lastBandwidth < MIN_BANDWIDTH) { + lastBandwidth = MIN_BANDWIDTH; } else if (lastBandwidth > wxGetApp().getSampleRate()) { lastBandwidth = wxGetApp().getSampleRate(); } @@ -191,14 +189,6 @@ void DemodulatorMgr::setLastDemodulatorType(std::string lastDemodType) { this->lastDemodType = lastDemodType; } -int DemodulatorMgr::getLastDemodulatorCons() const { - return lastDemodCons; -} - -void DemodulatorMgr::setLastDemodulatorCons(int lastDemodCons) { - this->lastDemodCons = lastDemodCons; -} - float DemodulatorMgr::getLastGain() const { return lastGain; } @@ -231,3 +221,10 @@ void DemodulatorMgr::setLastMuted(bool lastMuted) { this->lastMuted = lastMuted; } +ModemSettings DemodulatorMgr::getLastModemSettings(std::string modemType) { + return lastModemSettings[modemType]; +} + +void DemodulatorMgr::setLastModemSettings(std::string modemType, ModemSettings settings) { + lastModemSettings[modemType] = settings; +} diff --git a/src/demod/DemodulatorMgr.h b/src/demod/DemodulatorMgr.h index c57386a..4e8f496 100644 --- a/src/demod/DemodulatorMgr.h +++ b/src/demod/DemodulatorMgr.h @@ -27,9 +27,6 @@ public: std::string getLastDemodulatorType() const; void setLastDemodulatorType(std::string lastDemodType); - - int getLastDemodulatorCons() const; - void setLastDemodulatorCons(int lastDemodCons); float getLastGain() const; void setLastGain(float lastGain); @@ -43,9 +40,13 @@ public: bool isLastMuted() const; void setLastMuted(bool lastMuted); + ModemSettings getLastModemSettings(std::string); + void setLastModemSettings(std::string, ModemSettings); + + void updateLastState(); + private: void garbageCollect(); - void updateLastState(); std::vector demods; std::vector demods_deleted; @@ -56,9 +57,10 @@ private: int lastBandwidth; std::string lastDemodType; bool lastDemodLock; - int lastDemodCons; bool lastSquelchEnabled; float lastSquelch; float lastGain; bool lastMuted; + + std::map lastModemSettings; }; diff --git a/src/demod/DemodulatorPreThread.cpp b/src/demod/DemodulatorPreThread.cpp index 86bac7f..f79eebf 100644 --- a/src/demod/DemodulatorPreThread.cpp +++ b/src/demod/DemodulatorPreThread.cpp @@ -7,10 +7,12 @@ #include "DemodulatorPreThread.h" #include "CubicSDR.h" +#include "DemodulatorInstance.h" -DemodulatorPreThread::DemodulatorPreThread() : IOThread(), iqResampler(NULL), iqResampleRatio(1), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), iqOutputQueue(NULL), threadQueueNotify(NULL), commandQueue(NULL) +DemodulatorPreThread::DemodulatorPreThread(DemodulatorInstance *parent) : IOThread(), iqResampler(NULL), iqResampleRatio(1), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), iqOutputQueue(NULL), threadQueueNotify(NULL) { initialized.store(false); + this->parent = parent; freqShifter = nco_crcf_create(LIQUID_VCO); shiftFrequency = 0; @@ -21,18 +23,21 @@ DemodulatorPreThread::DemodulatorPreThread() : IOThread(), iqResampler(NULL), iq workerThread = new DemodulatorWorkerThread(); workerThread->setInputQueue("WorkerCommandQueue",workerQueue); workerThread->setOutputQueue("WorkerResultQueue",workerResults); + + newSampleRate = currentSampleRate = 0; + newBandwidth = currentBandwidth = 0; + newAudioSampleRate = currentAudioSampleRate = 0; + newFrequency = currentFrequency = 0; + + sampleRateChanged.store(false); + frequencyChanged.store(false); + bandwidthChanged.store(false); + audioSampleRateChanged.store(false); + modemSettingsChanged.store(false); } -void DemodulatorPreThread::initialize() { - iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate; - - float As = 60.0f; // stop-band attenuation [dB] - - iqResampler = msresamp_crcf_create(iqResampleRatio, As); - - initialized.store(true); - - lastParams = params; +bool DemodulatorPreThread::isInitialized() { + return initialized.load(); } DemodulatorPreThread::~DemodulatorPreThread() { @@ -46,10 +51,6 @@ void DemodulatorPreThread::run() { pthread_setschedparam(tID, SCHED_FIFO, &prio); #endif - if (!initialized) { - initialize(); - } - std::cout << "Demodulator preprocessor thread started.." << std::endl; ReBuffer buffers; @@ -57,87 +58,103 @@ void DemodulatorPreThread::run() { iqInputQueue = (DemodulatorThreadInputQueue*)getInputQueue("IQDataInput"); iqOutputQueue = (DemodulatorThreadPostInputQueue*)getOutputQueue("IQDataOutput"); threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue"); - commandQueue = ( DemodulatorThreadCommandQueue*)getInputQueue("CommandQueue"); std::vector in_buf_data; std::vector out_buf_data; - setDemodType(params.demodType); t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread); while (!terminated) { DemodulatorThreadIQData *inp; iqInputQueue->pop(inp); - - bool bandwidthChanged = false; - bool rateChanged = false; - DemodulatorThreadParameters tempParams = params; - - if (!commandQueue->empty()) { - while (!commandQueue->empty()) { - DemodulatorThreadCommand command; - commandQueue->pop(command); - switch (command.cmd) { - case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH: - if (command.llong_value < 1500) { - command.llong_value = 1500; - } - if (command.llong_value > params.sampleRate) { - tempParams.bandwidth = params.sampleRate; - } else { - tempParams.bandwidth = command.llong_value; - } - bandwidthChanged = true; - break; - case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY: - params.frequency = tempParams.frequency = command.llong_value; - break; - case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE: - tempParams.audioSampleRate = (int)command.llong_value; - rateChanged = true; - break; - default: - break; - } + + if (frequencyChanged.load()) { + currentFrequency = newFrequency; + frequencyChanged.store(false); + } + + if (inp->sampleRate != currentSampleRate) { + newSampleRate = inp->sampleRate; + if (newSampleRate) { + sampleRateChanged.store(true); } } - - if (inp->sampleRate != tempParams.sampleRate && inp->sampleRate) { - tempParams.sampleRate = inp->sampleRate; - rateChanged = true; + + if (!newAudioSampleRate) { + newAudioSampleRate = parent->getAudioSampleRate(); + if (newAudioSampleRate) { + audioSampleRateChanged.store(true); + } + } else if (parent->getAudioSampleRate() != newAudioSampleRate) { + int newRate; + if ((newRate = parent->getAudioSampleRate())) { + newAudioSampleRate = parent->getAudioSampleRate(); + audioSampleRateChanged.store(true); + } } - - if (bandwidthChanged || rateChanged) { + + if (demodTypeChanged.load() && (newSampleRate && newAudioSampleRate && newBandwidth)) { + DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD); + command.frequency = newFrequency; + command.sampleRate = newSampleRate; + command.demodType = newDemodType; + command.bandwidth = newBandwidth; + command.audioSampleRate = newAudioSampleRate; + demodType = newDemodType; + sampleRateChanged.store(false); + audioSampleRateChanged.store(false); + ModemSettings lastSettings = parent->getLastModemSettings(newDemodType); + if (lastSettings.size() != 0) { + command.settings = lastSettings; + if (modemSettingsBuffered.size()) { + for (ModemSettings::const_iterator msi = modemSettingsBuffered.begin(); msi != modemSettingsBuffered.end(); msi++) { + command.settings[msi->first] = msi->second; + } + } + } else { + command.settings = modemSettingsBuffered; + } + modemSettingsBuffered.clear(); + modemSettingsChanged.store(false); + workerQueue->push(command); + cModem = nullptr; + cModemKit = nullptr; + demodTypeChanged.store(false); + initialized.store(false); + } + else if ( + cModemKit && cModem && + (bandwidthChanged.load() || sampleRateChanged.load() || audioSampleRateChanged.load() || cModem->shouldRebuildKit()) && + (newSampleRate && newAudioSampleRate && newBandwidth) + ) { DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS); - command.sampleRate = tempParams.sampleRate; - command.audioSampleRate = tempParams.audioSampleRate; - command.bandwidth = tempParams.bandwidth; - command.frequency = tempParams.frequency; - + command.frequency = newFrequency; + command.sampleRate = newSampleRate; + command.bandwidth = newBandwidth; + command.audioSampleRate = newAudioSampleRate; + bandwidthChanged.store(false); + sampleRateChanged.store(false); + audioSampleRateChanged.store(false); + modemSettingsBuffered.clear(); workerQueue->push(command); } - - if (!initialized) { - inp->decRefCount(); - continue; - } - + // Requested frequency is not center, shift it into the center! - if ((params.frequency - inp->frequency) != shiftFrequency || rateChanged) { - shiftFrequency = params.frequency - inp->frequency; + if ((currentFrequency - inp->frequency) != shiftFrequency) { + shiftFrequency = currentFrequency - inp->frequency; if (abs(shiftFrequency) <= (int) ((double) (inp->sampleRate / 2) * 1.5)) { nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) inp->sampleRate))); } } - if (abs(shiftFrequency) > (int) ((double) (inp->sampleRate / 2) * 1.5)) { + if (cModem && cModemKit && abs(shiftFrequency) > (int) ((double) (inp->sampleRate / 2) * 1.5)) { inp->decRefCount(); continue; } // std::lock_guard < std::mutex > lock(inp->m_mutex); std::vector *data = &inp->data; - if (data->size() && (inp->sampleRate == params.sampleRate)) { + if (data->size() && (inp->sampleRate == currentSampleRate) && cModem && cModemKit) { int bufSize = data->size(); if (in_buf_data.size() != bufSize) { @@ -183,10 +200,11 @@ void DemodulatorPreThread::run() { resamp->setRefCount(1); resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten); - resamp->modemType = demodType; + resamp->modemType = cModem->getType(); + resamp->modemName = cModem->getName(); resamp->modem = cModem; resamp->modemKit = cModemKit; - resamp->sampleRate = params.bandwidth; + resamp->sampleRate = currentBandwidth; iqOutputQueue->push(resamp); } @@ -200,7 +218,6 @@ void DemodulatorPreThread::run() { switch (result.cmd) { case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS: - if (result.iqResampler) { if (iqResampler) { msresamp_crcf_destroy(iqResampler); @@ -211,31 +228,46 @@ void DemodulatorPreThread::run() { if (result.modem != nullptr) { cModem = result.modem; +#if ENABLE_DIGITAL_LAB + if (cModem->getType() == "digital") { + ModemDigital *mDigi = (ModemDigital *)cModem; + mDigi->setOutput(parent->getOutput()); + } +#endif } if (result.modemKit != nullptr) { cModemKit = result.modemKit; + currentAudioSampleRate = cModemKit->audioSampleRate; } if (result.bandwidth) { - params.bandwidth = result.bandwidth; + currentBandwidth = result.bandwidth; } if (result.sampleRate) { - params.sampleRate = result.sampleRate; + currentSampleRate = result.sampleRate; } - if (result.modemType != "") { - demodType = result.modemType; - params.demodType = result.modemType; + if (result.modemName != "") { + demodType = result.modemName; demodTypeChanged.store(false); } + + shiftFrequency = inp->frequency-1; + initialized.store(cModem != nullptr); break; default: break; } } } + + if ((cModem != nullptr) && modemSettingsChanged.load()) { + cModem->writeSettings(modemSettingsBuffered); + modemSettingsBuffered.clear(); + modemSettingsChanged.store(false); + } } buffers.purge(); @@ -246,21 +278,8 @@ void DemodulatorPreThread::run() { std::cout << "Demodulator preprocessor thread done." << std::endl; } -DemodulatorThreadParameters &DemodulatorPreThread::getParams() { - return params; -} - -void DemodulatorPreThread::setParams(DemodulatorThreadParameters ¶ms_in) { - params = params_in; -} - void DemodulatorPreThread::setDemodType(std::string demodType) { - this->newDemodType = demodType; - DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD); - command.demodType = demodType; - command.bandwidth = params.bandwidth; - command.audioSampleRate = params.audioSampleRate; - workerQueue->push(command); + newDemodType = demodType; demodTypeChanged.store(true); } @@ -271,6 +290,51 @@ std::string DemodulatorPreThread::getDemodType() { return demodType; } +void DemodulatorPreThread::setFrequency(long long freq) { + frequencyChanged.store(true); + newFrequency = freq; +} + +long long DemodulatorPreThread::getFrequency() { + if (frequencyChanged.load()) { + return newFrequency; + } + return currentFrequency; +} + +void DemodulatorPreThread::setSampleRate(long long sampleRate) { + sampleRateChanged.store(true); + newSampleRate = sampleRate; +} + +long long DemodulatorPreThread::getSampleRate() { + if (sampleRateChanged.load()) { + return newSampleRate; + } + return currentSampleRate; +} + +void DemodulatorPreThread::setBandwidth(int bandwidth) { + bandwidthChanged.store(true); + newBandwidth = bandwidth; +} + +int DemodulatorPreThread::getBandwidth() { + return currentBandwidth; +} + +void DemodulatorPreThread::setAudioSampleRate(int rate) { + audioSampleRateChanged.store(true); + newAudioSampleRate = rate; +} + +int DemodulatorPreThread::getAudioSampleRate() { + if (audioSampleRateChanged.load()) { + return newAudioSampleRate; + } + return currentAudioSampleRate; +} + void DemodulatorPreThread::terminate() { terminated = true; DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue @@ -285,7 +349,6 @@ void DemodulatorPreThread::terminate() { delete workerQueue; } - Modem *DemodulatorPreThread::getModem() { return cModem; } @@ -293,3 +356,31 @@ Modem *DemodulatorPreThread::getModem() { ModemKit *DemodulatorPreThread::getModemKit() { return cModemKit; } + + +std::string DemodulatorPreThread::readModemSetting(std::string setting) { + if (cModem) { + return cModem->readSetting(setting); + } else if (modemSettingsBuffered.find(setting) != modemSettingsBuffered.end()) { + return modemSettingsBuffered[setting]; + } + return ""; +} + +void DemodulatorPreThread::writeModemSetting(std::string setting, std::string value) { + modemSettingsBuffered[setting] = value; + modemSettingsChanged.store(true); +} + +ModemSettings DemodulatorPreThread::readModemSettings() { + if (cModem) { + return cModem->readSettings(); + } else { + return modemSettingsBuffered; + } +} + +void DemodulatorPreThread::writeModemSettings(ModemSettings settings) { + modemSettingsBuffered = settings; + modemSettingsChanged.store(true); +} diff --git a/src/demod/DemodulatorPreThread.h b/src/demod/DemodulatorPreThread.h index f339a70..e8c8879 100644 --- a/src/demod/DemodulatorPreThread.h +++ b/src/demod/DemodulatorPreThread.h @@ -7,37 +7,62 @@ #include "DemodDefs.h" #include "DemodulatorWorkerThread.h" +class DemodulatorInstance; + class DemodulatorPreThread : public IOThread { public: - DemodulatorPreThread(); + DemodulatorPreThread(DemodulatorInstance *parent); ~DemodulatorPreThread(); void run(); - - DemodulatorThreadParameters &getParams(); - void setParams(DemodulatorThreadParameters ¶ms_in); void setDemodType(std::string demodType); std::string getDemodType(); - void initialize(); + void setFrequency(long long sampleRate); + long long getFrequency(); + + void setSampleRate(long long sampleRate); + long long getSampleRate(); + + void setBandwidth(int bandwidth); + int getBandwidth(); + + void setAudioSampleRate(int rate); + int getAudioSampleRate(); + + bool isInitialized(); + void terminate(); Modem *getModem(); ModemKit *getModemKit(); + std::string readModemSetting(std::string setting); + void writeModemSetting(std::string setting, std::string value); + ModemSettings readModemSettings(); + void writeModemSettings(ModemSettings settings); + protected: + DemodulatorInstance *parent; msresamp_crcf iqResampler; double iqResampleRatio; std::vector resampledData; Modem *cModem; ModemKit *cModemKit; + + long long currentSampleRate, newSampleRate; + long long currentFrequency, newFrequency; + int currentBandwidth, newBandwidth; + int currentAudioSampleRate, newAudioSampleRate; - DemodulatorThreadParameters params; - DemodulatorThreadParameters lastParams; + std::atomic_bool sampleRateChanged, frequencyChanged, bandwidthChanged, audioSampleRateChanged; + ModemSettings modemSettingsBuffered; + std::atomic_bool modemSettingsChanged; + nco_crcf freqShifter; int shiftFrequency; @@ -55,5 +80,4 @@ protected: DemodulatorThreadInputQueue* iqInputQueue; DemodulatorThreadPostInputQueue* iqOutputQueue; DemodulatorThreadCommandQueue* threadQueueNotify; - DemodulatorThreadCommandQueue* commandQueue; }; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index b16dd27..a7db28e 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -12,7 +12,7 @@ #include #endif -DemodulatorThread::DemodulatorThread(DemodulatorInstance *parent) : IOThread(), audioSampleRate(0), squelchLevel(-100), signalLevel(-100), squelchEnabled(false), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) { +DemodulatorThread::DemodulatorThread(DemodulatorInstance *parent) : IOThread(), squelchLevel(-100), signalLevel(-100), squelchEnabled(false), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) { demodInstance = parent; muted.store(false); @@ -73,8 +73,6 @@ void DemodulatorThread::run() { iqInputQueue->pop(inp); // std::lock_guard < std::mutex > lock(inp->m_mutex); - audioSampleRate = demodInstance->getAudioSampleRate(); - int bufSize = inp->data.size(); if (!bufSize) { @@ -122,15 +120,22 @@ void DemodulatorThread::run() { AudioThreadInput *ati = NULL; ModemAnalog *modemAnalog = (cModem->getType() == "analog")?((ModemAnalog *)cModem):nullptr; -// ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr; + ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr; if (modemAnalog != nullptr) { ati = outputBuffers.getBuffer(); - ati->sampleRate = audioSampleRate; + ati->sampleRate = cModemKit->audioSampleRate; + ati->inputRate = inp->sampleRate; + ati->setRefCount(1); + } else if (modemDigital != nullptr) { + ati = outputBuffers.getBuffer(); + + ati->sampleRate = cModemKit->sampleRate; ati->inputRate = inp->sampleRate; ati->setRefCount(1); } + cModem->demodulate(cModemKit, &modemData, ati); if (currentSignalLevel > signalLevel) { @@ -162,7 +167,15 @@ void DemodulatorThread::run() { ati_vis->inputRate = inp->sampleRate; int num_vis = DEMOD_VIS_SIZE; - if (ati->channels==2) { + if (modemDigital) { + ati_vis->data.resize(inputData->size()); + ati_vis->channels = 2; + for (int i = 0, iMax = inputData->size() / 2; i < iMax; i++) { + ati_vis->data[i * 2] = (*inputData)[i].real; + ati_vis->data[i * 2 + 1] = (*inputData)[i].imag; + } + ati_vis->type = 2; + } else if (ati->channels==2) { ati_vis->channels = 2; int stereoSize = ati->data.size(); if (stereoSize > DEMOD_VIS_SIZE * 2) { @@ -171,25 +184,26 @@ void DemodulatorThread::run() { ati_vis->data.resize(stereoSize); - if (inp->modemType == "I/Q") { + if (inp->modemName == "I/Q") { for (int i = 0; i < stereoSize / 2; i++) { ati_vis->data[i] = (*inputData)[i].real * 0.75; ati_vis->data[i + stereoSize / 2] = (*inputData)[i].imag * 0.75; } } else { for (int i = 0; i < stereoSize / 2; i++) { - ati_vis->inputRate = audioSampleRate; + ati_vis->inputRate = cModemKit->audioSampleRate; ati_vis->sampleRate = 36000; ati_vis->data[i] = ati->data[i * 2]; ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1]; } } + ati_vis->type = 1; } else { int numAudioWritten = ati->data.size(); ati_vis->channels = 1; std::vector *demodOutData = (modemAnalog != nullptr)?modemAnalog->getDemodOutputData():nullptr; if ((numAudioWritten > bufSize) || (demodOutData == nullptr)) { - ati_vis->inputRate = audioSampleRate; + ati_vis->inputRate = cModemKit->audioSampleRate; if (num_vis > numAudioWritten) { num_vis = numAudioWritten; } @@ -200,7 +214,7 @@ void DemodulatorThread::run() { } ati_vis->data.assign(demodOutData->begin(), demodOutData->begin() + num_vis); } - + ati_vis->type = 0; } audioVisOutputQueue->push(ati_vis); diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index 9cc2ecf..06a81ea 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -43,7 +43,6 @@ protected: ReBuffer outputBuffers; std::atomic_bool muted; - int audioSampleRate; std::atomic squelchLevel; std::atomic signalLevel; diff --git a/src/demod/DemodulatorWorkerThread.cpp b/src/demod/DemodulatorWorkerThread.cpp index df7fab2..492b439 100644 --- a/src/demod/DemodulatorWorkerThread.cpp +++ b/src/demod/DemodulatorWorkerThread.cpp @@ -1,5 +1,6 @@ #include "DemodulatorWorkerThread.h" #include "CubicSDRDefs.h" +#include "CubicSDR.h" #include DemodulatorWorkerThread::DemodulatorWorkerThread() : IOThread(), @@ -26,63 +27,72 @@ void DemodulatorWorkerThread::run() { while (!done) { commandQueue->pop(command); switch (command.cmd) { - case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS: - filterChanged = true; - filterCommand = command; - break; - case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD: - makeDemod = true; - demodCommand = command; - break; - default: - break; + case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS: + filterChanged = true; + filterCommand = command; + break; + case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD: + makeDemod = true; + demodCommand = command; + break; + default: + break; } done = commandQueue->empty(); } - if ((makeDemod || filterChanged) && !terminated) { DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS); - - float As = 60.0f; // stop-band attenuation [dB] - - if (filterCommand.sampleRate && filterCommand.bandwidth) { - result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate; - result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As); + + + if (filterCommand.sampleRate) { + result.sampleRate = filterCommand.sampleRate; } - + if (makeDemod) { cModem = Modem::makeModem(demodCommand.demodType); - cModemType = demodCommand.demodType; + cModemName = cModem->getName(); + cModemType = cModem->getType(); + if (demodCommand.settings.size()) { + cModem->writeSettings(demodCommand.settings); + } + result.sampleRate = demodCommand.sampleRate; + wxGetApp().getAppFrame()->updateModemProperties(cModem->getSettings()); } result.modem = cModem; if (makeDemod && demodCommand.bandwidth && demodCommand.audioSampleRate) { if (cModem != nullptr) { - cModemKit = cModem->buildKit(demodCommand.bandwidth, demodCommand.audioSampleRate); + result.bandwidth = cModem->checkSampleRate(demodCommand.bandwidth, demodCommand.audioSampleRate); + cModemKit = cModem->buildKit(result.bandwidth, demodCommand.audioSampleRate); } else { cModemKit = nullptr; } } else if (filterChanged && filterCommand.bandwidth && filterCommand.audioSampleRate) { if (cModem != nullptr) { - cModemKit = cModem->buildKit(filterCommand.bandwidth, filterCommand.audioSampleRate); + result.bandwidth = cModem->checkSampleRate(filterCommand.bandwidth, filterCommand.audioSampleRate); + cModemKit = cModem->buildKit(result.bandwidth, filterCommand.audioSampleRate); } else { cModemKit = nullptr; } } else if (makeDemod) { cModemKit = nullptr; } + if (cModem != nullptr) { + cModem->clearRebuildKit(); + } + + float As = 60.0f; // stop-band attenuation [dB] + + if (result.sampleRate && result.bandwidth) { + result.bandwidth = cModem->checkSampleRate(result.bandwidth, makeDemod?demodCommand.audioSampleRate:filterCommand.audioSampleRate); + result.iqResampleRatio = (double) (result.bandwidth) / (double) result.sampleRate; + result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As); + } + result.modemKit = cModemKit; - - if (filterCommand.bandwidth) { - result.bandwidth = filterCommand.bandwidth; - } - - if (filterCommand.sampleRate) { - result.sampleRate = filterCommand.sampleRate; - } - result.modemType = cModemType; + result.modemName = cModemName; resultQueue->push(result); } diff --git a/src/demod/DemodulatorWorkerThread.h b/src/demod/DemodulatorWorkerThread.h index 5455a5f..d2a8b4c 100644 --- a/src/demod/DemodulatorWorkerThread.h +++ b/src/demod/DemodulatorWorkerThread.h @@ -37,6 +37,7 @@ public: Modem *modem; ModemKit *modemKit; std::string modemType; + std::string modemName; }; class DemodulatorWorkerThreadCommand { @@ -62,6 +63,7 @@ public: unsigned int bandwidth; unsigned int audioSampleRate; std::string demodType; + ModemSettings settings; }; typedef ThreadQueue DemodulatorThreadWorkerCommandQueue; @@ -92,4 +94,5 @@ protected: Modem *cModem; ModemKit *cModemKit; std::string cModemType; + std::string cModemName; }; diff --git a/src/forms/DigitalConsole/DigitalConsole.cpp b/src/forms/DigitalConsole/DigitalConsole.cpp new file mode 100644 index 0000000..f472ca1 --- /dev/null +++ b/src/forms/DigitalConsole/DigitalConsole.cpp @@ -0,0 +1,138 @@ +#include "DigitalConsole.h" +#include "CubicSDR.h" +#include + +DigitalConsole::DigitalConsole( wxWindow* parent, ModemDigitalOutputConsole *doParent ): DigitalConsoleFrame( parent ), doParent(doParent) { + streamWritten.store(false); + streamPaused.store(false); +} + +DigitalConsole::~DigitalConsole() { + doParent->setDialog(nullptr); +} + +void DigitalConsole::OnClose( wxCloseEvent& event ) { + doParent->setDialog(nullptr); +} + +void DigitalConsole::OnCopy( wxCommandEvent& event ) { + m_dataView->SelectAll(); + m_dataView->Copy(); +} + +void DigitalConsole::OnPause( wxCommandEvent& event ) { + if (streamPaused.load()) { + m_pauseButton->SetLabel("Stop"); + streamPaused.store(false); + } else { + m_pauseButton->SetLabel("Run"); + streamPaused.store(true); + } +} + +void DoRefresh( wxTimerEvent& event ) { + event.Skip(); +} + +void DigitalConsole::DoRefresh( wxTimerEvent& event ) { + if (streamWritten.load()) { + stream_busy.lock(); + m_dataView->AppendText(streamBuf.str()); + streamBuf.str(""); + streamWritten.store(false); + stream_busy.unlock(); + } +} + +void DigitalConsole::OnClear( wxCommandEvent& event ) { + m_dataView->Clear(); +} + +void DigitalConsole::write(std::string outp) { + if (streamPaused.load()) { + return; + } + stream_busy.lock(); + streamBuf << outp; + streamWritten.store(true); + stream_busy.unlock(); +} + +void DigitalConsole::write(char outc) { + if (streamPaused.load()) { + return; + } + stream_busy.lock(); + streamBuf << outc; + streamWritten.store(true); + stream_busy.unlock(); +} + + +ModemDigitalOutputConsole::ModemDigitalOutputConsole(): ModemDigitalOutput(), dialog(nullptr) { + streamWritten.store(false); +} + +ModemDigitalOutputConsole::~ModemDigitalOutputConsole() { + +} + +void ModemDigitalOutputConsole::setDialog(DigitalConsole *dialog_in) { + dialog = dialog_in; + if (dialog && dialogTitle != "") { + dialog->SetTitle(dialogTitle); + } +} + +DigitalConsole *ModemDigitalOutputConsole::getDialog() { + return dialog; +} + +void ModemDigitalOutputConsole::Show() { + if (!dialog) { + return; + } + if (!dialog->IsShown()) { + dialog->Show(); + } +} + + +void ModemDigitalOutputConsole::Hide() { + if (!dialog) { + return; + } + if (dialog->IsShown()) { + dialog->Hide(); + } +} + +void ModemDigitalOutputConsole::Close() { + if (!dialog) { + return; + } + dialog->Hide(); + dialog->Close(); + dialog = nullptr; +} + +void ModemDigitalOutputConsole::setTitle(std::string title) { + if (dialog) { + dialog->SetTitle(title); + } + dialogTitle = title; +} + +void ModemDigitalOutputConsole::write(std::string outp) { + if (!dialog) { + return; + } + dialog->write(outp); +} + +void ModemDigitalOutputConsole::write(char outc) { + if (!dialog) { + return; + } + dialog->write(outc); +} diff --git a/src/forms/DigitalConsole/DigitalConsole.fbp b/src/forms/DigitalConsole/DigitalConsole.fbp new file mode 100644 index 0000000..90aed1d --- /dev/null +++ b/src/forms/DigitalConsole/DigitalConsole.fbp @@ -0,0 +1,485 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + DigitalConsoleFrame + 1000 + none + 0 + DigitalConsole + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DigitalConsoleFrame + + 441,394 + wxCAPTION|wxFRAME_FLOAT_ON_PARENT|wxMAXIMIZE|wxMAXIMIZE_BOX|wxMINIMIZE|wxMINIMIZE_BOX|wxRESIZE_BORDER + ; + Digital Output + + wxWS_EX_PROCESS_UI_UPDATES + + wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL + 1 + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + mainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + dataViewSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,90,-1,76,0 + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_dataView + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_CHARWRAP|wxTE_MULTILINE|wxTE_NOHIDESEL|wxTE_READONLY|wxTE_WORDWRAP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + wxWS_EX_PROCESS_UI_UPDATES + + wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE|wxNO_BORDER|wxSIMPLE_BORDER|wxVSCROLL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + + buttonSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Clear + + 0 + + + 0 + + 1 + m_clearButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnClear + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Copy + + 0 + + + 0 + + 1 + m_copyButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCopy + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Stop + + 0 + + + 0 + + 1 + m_pauseButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnPause + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + wxID_ANY + m_refreshTimer + 0 + 250 + protected + DoRefresh + + + + diff --git a/src/forms/DigitalConsole/DigitalConsole.h b/src/forms/DigitalConsole/DigitalConsole.h new file mode 100644 index 0000000..5d5321d --- /dev/null +++ b/src/forms/DigitalConsole/DigitalConsole.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "DigitalConsoleFrame.h" +#include "ModemDigital.h" + +class ModemDigitalOutputConsole; +class DigitalConsole: public DigitalConsoleFrame { +public: + DigitalConsole( wxWindow* parent, ModemDigitalOutputConsole *doParent ); + ~DigitalConsole(); + + + void write(std::string outp); + void write(char outc); + +private: + void DoRefresh( wxTimerEvent& event ); + void OnClose( wxCloseEvent& event ); + void OnClear( wxCommandEvent& event ); + + void OnCopy( wxCommandEvent& event ); + void OnPause( wxCommandEvent& event ); + + std::stringstream streamBuf; + std::mutex stream_busy; + std::atomic streamWritten; + std::atomic streamPaused; + ModemDigitalOutputConsole *doParent; +}; + +class ModemDigitalOutputConsole: public ModemDigitalOutput { +public: + ModemDigitalOutputConsole(); + ~ModemDigitalOutputConsole(); + + void setDialog(DigitalConsole *dialog_in); + DigitalConsole *getDialog(); + + void setTitle(std::string title); + + void write(std::string outp); + void write(char outc); + + void Show(); + void Hide(); + void Close(); + +private: + DigitalConsole *dialog; + std::stringstream streamBuf; + std::mutex stream_busy; + std::atomic streamWritten; + std::string dialogTitle; +}; + diff --git a/src/forms/DigitalConsole/DigitalConsoleFrame.cpp b/src/forms/DigitalConsole/DigitalConsoleFrame.cpp new file mode 100644 index 0000000..b1e4885 --- /dev/null +++ b/src/forms/DigitalConsole/DigitalConsoleFrame.cpp @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Aug 23 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "DigitalConsoleFrame.h" + +/////////////////////////////////////////////////////////////////////////// + +DigitalConsoleFrame::DigitalConsoleFrame( 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 ); + this->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES ); + + wxBoxSizer* mainSizer; + mainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* dataViewSizer; + dataViewSizer = new wxBoxSizer( wxVERTICAL ); + + m_dataView = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CHARWRAP|wxTE_MULTILINE|wxTE_NOHIDESEL|wxTE_READONLY|wxTE_WORDWRAP|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE|wxNO_BORDER|wxSIMPLE_BORDER|wxVSCROLL ); + m_dataView->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES ); + m_dataView->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 76, 90, 90, false, wxEmptyString ) ); + + dataViewSizer->Add( m_dataView, 1, wxEXPAND, 5 ); + + + mainSizer->Add( dataViewSizer, 1, wxEXPAND, 5 ); + + wxBoxSizer* buttonSizer; + buttonSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_clearButton = new wxButton( this, wxID_ANY, wxT("Clear"), wxDefaultPosition, wxDefaultSize, 0 ); + buttonSizer->Add( m_clearButton, 1, wxEXPAND, 5 ); + + m_copyButton = new wxButton( this, wxID_ANY, wxT("Copy"), wxDefaultPosition, wxDefaultSize, 0 ); + buttonSizer->Add( m_copyButton, 1, wxEXPAND, 5 ); + + m_pauseButton = new wxButton( this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0 ); + buttonSizer->Add( m_pauseButton, 1, wxEXPAND, 5 ); + + + mainSizer->Add( buttonSizer, 0, wxALL|wxEXPAND, 5 ); + + + this->SetSizer( mainSizer ); + this->Layout(); + m_refreshTimer.SetOwner( this, wxID_ANY ); + m_refreshTimer.Start( 250 ); + + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DigitalConsoleFrame::OnClose ) ); + m_clearButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnClear ), NULL, this ); + m_copyButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnCopy ), NULL, this ); + m_pauseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnPause ), NULL, this ); + this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( DigitalConsoleFrame::DoRefresh ) ); +} + +DigitalConsoleFrame::~DigitalConsoleFrame() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DigitalConsoleFrame::OnClose ) ); + m_clearButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnClear ), NULL, this ); + m_copyButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnCopy ), NULL, this ); + m_pauseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnPause ), NULL, this ); + this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( DigitalConsoleFrame::DoRefresh ) ); + +} diff --git a/src/forms/DigitalConsole/DigitalConsoleFrame.h b/src/forms/DigitalConsole/DigitalConsoleFrame.h new file mode 100644 index 0000000..6665b66 --- /dev/null +++ b/src/forms/DigitalConsole/DigitalConsoleFrame.h @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Aug 23 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIGITALCONSOLEFRAME_H__ +#define __DIGITALCONSOLEFRAME_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DigitalConsoleFrame +/////////////////////////////////////////////////////////////////////////////// +class DigitalConsoleFrame : public wxFrame +{ + private: + + protected: + wxTextCtrl* m_dataView; + wxButton* m_clearButton; + wxButton* m_copyButton; + wxButton* m_pauseButton; + wxTimer m_refreshTimer; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnClear( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCopy( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPause( wxCommandEvent& event ) { event.Skip(); } + virtual void DoRefresh( wxTimerEvent& event ) { event.Skip(); } + + + public: + + DigitalConsoleFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Digital Output"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 441,394 ), long style = wxCAPTION|wxFRAME_FLOAT_ON_PARENT|wxMAXIMIZE|wxMAXIMIZE_BOX|wxMINIMIZE|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL ); + + ~DigitalConsoleFrame(); + +}; + +#endif //__DIGITALCONSOLEFRAME_H__ diff --git a/src/forms/SDRDevices/SDRDevices.h b/src/forms/SDRDevices/SDRDevices.h index 74441ae..c6052a1 100644 --- a/src/forms/SDRDevices/SDRDevices.h +++ b/src/forms/SDRDevices/SDRDevices.h @@ -3,7 +3,6 @@ #include #include -#include "SDRDevices.h" #include "SDRDevicesForm.h" #include "SoapySDRThread.h" #include "SDREnumerator.h" diff --git a/src/modules/modem/Modem.cpp b/src/modules/modem/Modem.cpp index 8a1ff0e..c98e2be 100644 --- a/src/modules/modem/Modem.cpp +++ b/src/modules/modem/Modem.cpp @@ -1,21 +1,33 @@ #include "Modem.h" +#include "CubicSDR.h" + ModemFactoryList Modem::modemFactories; -void Modem::addModemFactory(Modem *factorySingle) { - modemFactories[factorySingle->getName()] = factorySingle; +//! Create an empty range (0.0, 0.0) +ModemRange::ModemRange(void) { + _min = 0; + _max = 0; } -ModemFactoryList Modem::getFactories() { - return modemFactories; +//! Create a min/max range +ModemRange::ModemRange(const double minimum, const double maximum) { + _min = minimum; + _max = maximum; } -Modem *Modem::makeModem(std::string modemType) { - if (modemFactories.find(modemType) != modemFactories.end()) { - return modemFactories[modemType]->factory(); - } +//! Get the range minimum +double ModemRange::minimum(void) const { + return _min; +} + +//! Get the range maximum +double ModemRange::maximum(void) const { + return _max; +} + +ModemArgInfo::ModemArgInfo(void) { - return nullptr; } Modem::Modem() { @@ -25,3 +37,72 @@ Modem::Modem() { Modem::~Modem() { } + +void Modem::addModemFactory(Modem *factorySingle) { + modemFactories[factorySingle->getName()] = factorySingle; +} + +ModemFactoryList Modem::getFactories() { + return modemFactories; +} + +Modem *Modem::makeModem(std::string modemName) { + if (modemFactories.find(modemName) != modemFactories.end()) { + return modemFactories[modemName]->factory(); + } + + return nullptr; +} + +int Modem::getModemDefaultSampleRate(std::string modemName) { + if (modemFactories.find(modemName) != modemFactories.end()) { + return modemFactories[modemName]->getDefaultSampleRate(); + } + + return 0; +} + +ModemArgInfoList Modem::getSettings() { + ModemArgInfoList args; + + return args; +} + +int Modem::getDefaultSampleRate() { + return 200000; +} + +void Modem::writeSetting(std::string setting, std::string value) { + // ... +} + +std::string Modem::readSetting(std::string setting) { + return ""; +} + +void Modem::writeSettings(ModemSettings settings) { + for (ModemSettings::const_iterator i = settings.begin(); i != settings.end(); i++) { + writeSetting(i->first, i->second); + } +} + +ModemSettings Modem::readSettings() { + ModemArgInfoList args = getSettings(); + ModemSettings rs; + for (ModemArgInfoList::const_iterator i = args.begin(); i != args.end(); i++) { + rs[i->key] = readSetting(i->key); + } + return rs; +} + +bool Modem::shouldRebuildKit() { + return refreshKit.load(); +} + +void Modem::rebuildKit() { + refreshKit.store(true); +} + +void Modem::clearRebuildKit() { + refreshKit.store(false); +} diff --git a/src/modules/modem/Modem.h b/src/modules/modem/Modem.h index 035bbe4..0ce8d46 100644 --- a/src/modules/modem/Modem.h +++ b/src/modules/modem/Modem.h @@ -4,6 +4,9 @@ #include "IOThread.h" #include "AudioThread.h" #include +#include + +#define MIN_BANDWIDTH 500 class ModemKit { public: @@ -29,24 +32,118 @@ public: } }; +// Copy of SoapySDR::Range, original comments +class ModemRange +{ +public: + + //! Create an empty range (0.0, 0.0) + ModemRange(void); + + //! Create a min/max range + ModemRange(const double minimum, const double maximum); + + //! Get the range minimum + double minimum(void) const; + + //! Get the range maximum + double maximum(void) const; + +private: + double _min, _max; +}; + +// Modified version of SoapySDR::ArgInfo, original comments +class ModemArgInfo +{ +public: + //! Default constructor + ModemArgInfo(void); + + //! The key used to identify the argument (required) + std::string key; + + /*! + * The default value of the argument when not specified (required) + * Numbers should use standard floating point and integer formats. + * Boolean values should be represented as "true" and "false". + */ + std::string value; + + //! The displayable name of the argument (optional, use key if empty) + std::string name; + + //! A brief description about the argument (optional) + std::string description; + + //! The units of the argument: dB, Hz, etc (optional) + std::string units; + + //! The data type of the argument (required) + enum Type { BOOL, INT, FLOAT, STRING, PATH_DIR, PATH_FILE, COLOR } type; + + /*! + * The range of possible numeric values (optional) + * When specified, the argument should be restricted to this range. + * The range is only applicable to numeric argument types. + */ + ModemRange range; + + /*! + * A discrete list of possible values (optional) + * When specified, the argument should be restricted to this options set. + */ + std::vector options; + + /*! + * A discrete list of displayable names for the enumerated options (optional) + * When not specified, the option value itself can be used as a display name. + */ + std::vector optionNames; +}; + +typedef std::vector ModemArgInfoList; + class Modem; typedef std::map ModemFactoryList; +typedef std::map ModemSettings; + class Modem { public: static void addModemFactory(Modem *factorySingle); static ModemFactoryList getFactories(); - static Modem *makeModem(std::string modemType); + + static Modem *makeModem(std::string modemName); + static int getModemDefaultSampleRate(std::string modemName); + virtual std::string getType() = 0; virtual std::string getName() = 0; + virtual Modem *factory() = 0; Modem(); virtual ~Modem(); + virtual ModemArgInfoList getSettings(); + virtual int getDefaultSampleRate(); + virtual void writeSetting(std::string setting, std::string value); + virtual void writeSettings(ModemSettings settings); + virtual std::string readSetting(std::string setting); + virtual ModemSettings readSettings(); + + virtual int checkSampleRate(long long sampleRate, int audioSampleRate) = 0; + virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate) = 0; virtual void disposeKit(ModemKit *kit) = 0; + virtual void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) = 0; + + bool shouldRebuildKit(); + void rebuildKit(); + void clearRebuildKit(); + private: static ModemFactoryList modemFactories; + std::atomic_bool refreshKit; }; diff --git a/src/modules/modem/ModemAnalog.cpp b/src/modules/modem/ModemAnalog.cpp index eed8d5c..fc98ad8 100644 --- a/src/modules/modem/ModemAnalog.cpp +++ b/src/modules/modem/ModemAnalog.cpp @@ -8,6 +8,13 @@ std::string ModemAnalog::getType() { return "analog"; } +int ModemAnalog::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < MIN_BANDWIDTH) { + return MIN_BANDWIDTH; + } + return sampleRate; +} + ModemKit *ModemAnalog::buildKit(long long sampleRate, int audioSampleRate) { ModemKitAnalog *akit = new ModemKitAnalog; diff --git a/src/modules/modem/ModemAnalog.h b/src/modules/modem/ModemAnalog.h index f73a933..dbf07b9 100644 --- a/src/modules/modem/ModemAnalog.h +++ b/src/modules/modem/ModemAnalog.h @@ -16,12 +16,13 @@ class ModemAnalog : public Modem { public: ModemAnalog(); std::string getType(); - ModemKit *buildKit(long long sampleRate, int audioSampleRate); - void disposeKit(ModemKit *kit); - void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input); - void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain); - std::vector *getDemodOutputData(); - std::vector *getResampledOutputData(); + virtual int checkSampleRate(long long sampleRate, int audioSampleRate); + virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate); + virtual void disposeKit(ModemKit *kit); + virtual void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input); + virtual void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain); + virtual std::vector *getDemodOutputData(); + virtual std::vector *getResampledOutputData(); protected: int bufSize; std::vector demodOutputData; diff --git a/src/modules/modem/ModemDigital.cpp b/src/modules/modem/ModemDigital.cpp index 6c2224d..a5ec509 100644 --- a/src/modules/modem/ModemDigital.cpp +++ b/src/modules/modem/ModemDigital.cpp @@ -1,13 +1,31 @@ #include "ModemDigital.h" -ModemDigital::ModemDigital() { +ModemDigitalOutput::ModemDigitalOutput() { + +} + +ModemDigital::ModemDigital() { +#if ENABLE_DIGITAL_LAB + digitalOut = nullptr; +#endif +} + +ModemDigitalOutput::~ModemDigitalOutput() { + } std::string ModemDigital::getType() { return "digital"; } +int ModemDigital::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < MIN_BANDWIDTH) { + return MIN_BANDWIDTH; + } + return sampleRate; +} + ModemKit *ModemDigital::buildKit(long long sampleRate, int audioSampleRate) { ModemKitDigital *dkit = new ModemKitDigital; @@ -31,24 +49,10 @@ int ModemDigital::getDemodulatorLock() { return currentDemodLock.load(); } -void ModemDigital::setDemodulatorCons(int demod_cons_in) { - demodulatorCons.store(demod_cons_in); -} - -int ModemDigital::getDemodulatorCons() { - return currentDemodCons.load(); -} - void ModemDigital::updateDemodulatorLock(modem mod, float sensitivity) { setDemodulatorLock(modem_get_demodulator_evm(mod) <= sensitivity); } -void ModemDigital::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - } -} - void ModemDigital::digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input) { int bufSize = input->data.size(); @@ -58,14 +62,21 @@ void ModemDigital::digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *in } demodOutputDataDigital.resize(bufSize); } - - if (demodulatorCons.load() != currentDemodCons.load()) { - updateDemodulatorCons(demodulatorCons.load()); - currentDemodLock.store(false); - } } void ModemDigital::digitalFinish(ModemKitDigital *kit, modem mod) { - demodOutputDataDigital.empty(); +#if ENABLE_DIGITAL_LAB + if (digitalOut && outStream.str().length()) { + digitalOut->write(outStream.str()); + outStream.str(""); + } else { + outStream.str(""); + } +#endif } - + +#if ENABLE_DIGITAL_LAB +void ModemDigital::setOutput(ModemDigitalOutput *modemDigitalOutput) { + digitalOut = modemDigitalOutput; +} +#endif \ No newline at end of file diff --git a/src/modules/modem/ModemDigital.h b/src/modules/modem/ModemDigital.h index 34a119b..e1991c1 100644 --- a/src/modules/modem/ModemDigital.h +++ b/src/modules/modem/ModemDigital.h @@ -1,5 +1,10 @@ #pragma once #include "Modem.h" +#include +#include +#include +#include +#include class ModemKitDigital : public ModemKit { public: @@ -8,32 +13,49 @@ public: }; }; +class ModemDigitalOutput { +public: + ModemDigitalOutput(); + virtual ~ModemDigitalOutput(); + + virtual void write(std::string outp) = 0; + virtual void write(char outc) = 0; + + virtual void Show() = 0; + virtual void Hide() = 0; + virtual void Close() = 0; + +private: +}; class ModemDigital : public Modem { public: ModemDigital(); + std::string getType(); - ModemKit *buildKit(long long sampleRate, int audioSampleRate); - void disposeKit(ModemKit *kit); - void digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input); - void digitalFinish(ModemKitDigital *kit, modem mod); + + virtual int checkSampleRate(long long sampleRate, int audioSampleRate); + + virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate); + virtual void disposeKit(ModemKit *kit); + + virtual void digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input); + virtual void digitalFinish(ModemKitDigital *kit, modem mod); virtual void setDemodulatorLock(bool demod_lock_in); virtual int getDemodulatorLock(); - virtual void setDemodulatorCons(int demod_cons_in); - virtual int getDemodulatorCons(); - - virtual void updateDemodulatorCons(int cons); virtual void updateDemodulatorLock(modem mod, float sensitivity); +#if ENABLE_DIGITAL_LAB + void setOutput(ModemDigitalOutput *digitalOutput); +#endif + protected: std::vector demodOutputDataDigital; - std::atomic_int demodulatorCons; std::atomic_bool currentDemodLock; - std::atomic_int currentDemodCons; - -// std::vector demodOutputDataDigitalTest; -// std::vector demodOutputSoftbits; -// std::vector demodOutputSoftbitsTest; +#if ENABLE_DIGITAL_LAB + ModemDigitalOutput *digitalOut; + std::stringstream outStream; +#endif }; \ No newline at end of file diff --git a/src/modules/modem/analog/ModemAM.cpp b/src/modules/modem/analog/ModemAM.cpp index 678832e..a4baa57 100644 --- a/src/modules/modem/analog/ModemAM.cpp +++ b/src/modules/modem/analog/ModemAM.cpp @@ -1,9 +1,13 @@ #include "ModemAM.h" -ModemAM::ModemAM() { +ModemAM::ModemAM() : ModemAnalog() { demodAM = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0); } +ModemAM::~ModemAM() { + ampmodem_destroy(demodAM); +} + Modem *ModemAM::factory() { return new ModemAM; } @@ -12,6 +16,10 @@ std::string ModemAM::getName() { return "AM"; } +int ModemAM::getDefaultSampleRate() { + return 6000; +} + void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitAnalog *amkit = (ModemKitAnalog *)kit; diff --git a/src/modules/modem/analog/ModemAM.h b/src/modules/modem/analog/ModemAM.h index 8a1d017..5adf75f 100644 --- a/src/modules/modem/analog/ModemAM.h +++ b/src/modules/modem/analog/ModemAM.h @@ -5,8 +5,14 @@ class ModemAM : public ModemAnalog { public: ModemAM(); + ~ModemAM(); + std::string getName(); + Modem *factory(); + + int getDefaultSampleRate(); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/analog/ModemDSB.cpp b/src/modules/modem/analog/ModemDSB.cpp index c343425..b0de272 100644 --- a/src/modules/modem/analog/ModemDSB.cpp +++ b/src/modules/modem/analog/ModemDSB.cpp @@ -1,9 +1,13 @@ #include "ModemDSB.h" -ModemDSB::ModemDSB() { +ModemDSB::ModemDSB() : ModemAnalog() { demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1); } +ModemDSB::~ModemDSB() { + ampmodem_destroy(demodAM_DSB); +} + Modem *ModemDSB::factory() { return new ModemDSB; } @@ -12,6 +16,10 @@ std::string ModemDSB::getName() { return "DSB"; } +int ModemDSB::getDefaultSampleRate() { + return 5400; +} + void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitAnalog *amkit = (ModemKitAnalog *)kit; diff --git a/src/modules/modem/analog/ModemDSB.h b/src/modules/modem/analog/ModemDSB.h index fc0e550..8c99332 100644 --- a/src/modules/modem/analog/ModemDSB.h +++ b/src/modules/modem/analog/ModemDSB.h @@ -5,8 +5,14 @@ class ModemDSB : public ModemAnalog { public: ModemDSB(); + ~ModemDSB(); + std::string getName(); + Modem *factory(); + + int getDefaultSampleRate(); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/analog/ModemFM.cpp b/src/modules/modem/analog/ModemFM.cpp index 259fcfd..931eef6 100644 --- a/src/modules/modem/analog/ModemFM.cpp +++ b/src/modules/modem/analog/ModemFM.cpp @@ -1,9 +1,13 @@ #include "ModemFM.h" -ModemFM::ModemFM() { +ModemFM::ModemFM() : ModemAnalog() { demodFM = freqdem_create(0.5); } +ModemFM::~ModemFM() { + freqdem_destroy(demodFM); +} + Modem *ModemFM::factory() { return new ModemFM; } @@ -12,6 +16,10 @@ std::string ModemFM::getName() { return "FM"; } +int ModemFM::getDefaultSampleRate() { + return 200000; +} + void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitAnalog *fmkit = (ModemKitAnalog *)kit; diff --git a/src/modules/modem/analog/ModemFM.h b/src/modules/modem/analog/ModemFM.h index a763bc2..267114d 100644 --- a/src/modules/modem/analog/ModemFM.h +++ b/src/modules/modem/analog/ModemFM.h @@ -5,11 +5,16 @@ class ModemFM : public ModemAnalog { public: ModemFM(); + ~ModemFM(); + std::string getName(); + Modem *factory(); + + int getDefaultSampleRate(); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: - freqdem demodFM; }; \ No newline at end of file diff --git a/src/modules/modem/analog/ModemFMStereo.cpp b/src/modules/modem/analog/ModemFMStereo.cpp index 04ec5d7..935fb4b 100644 --- a/src/modules/modem/analog/ModemFMStereo.cpp +++ b/src/modules/modem/analog/ModemFMStereo.cpp @@ -30,11 +30,27 @@ Modem *ModemFMStereo::factory() { return new ModemFMStereo; } +int ModemFMStereo::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < 100000) { + return 100000; + } else if (sampleRate < 1500) { + return 1500; + } else { + return sampleRate; + } +} + +int ModemFMStereo::getDefaultSampleRate() { + return 200000; +} + ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) { ModemKitFMStereo *kit = new ModemKitFMStereo; kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate); - + kit->sampleRate = sampleRate; + kit->audioSampleRate = audioSampleRate; + float As = 60.0f; // stop-band attenuation [dB] kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As); diff --git a/src/modules/modem/analog/ModemFMStereo.h b/src/modules/modem/analog/ModemFMStereo.h index cbc5aec..21e41c1 100644 --- a/src/modules/modem/analog/ModemFMStereo.h +++ b/src/modules/modem/analog/ModemFMStereo.h @@ -20,11 +20,18 @@ class ModemFMStereo : public Modem { public: ModemFMStereo(); ~ModemFMStereo(); + std::string getType(); std::string getName(); + Modem *factory(); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + int getDefaultSampleRate(); + ModemKit *buildKit(long long sampleRate, int audioSampleRate); void disposeKit(ModemKit *kit); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/analog/ModemIQ.cpp b/src/modules/modem/analog/ModemIQ.cpp index 6c984f6..7eda625 100644 --- a/src/modules/modem/analog/ModemIQ.cpp +++ b/src/modules/modem/analog/ModemIQ.cpp @@ -4,15 +4,6 @@ ModemIQ::ModemIQ() { } -Modem *ModemIQ::factory() { - return new ModemIQ; -} - -ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) { - ModemKit *kit = new ModemKit; - return kit; -} - std::string ModemIQ::getType() { return "analog"; } @@ -21,10 +12,29 @@ std::string ModemIQ::getName() { return "I/Q"; } +Modem *ModemIQ::factory() { + return new ModemIQ; +} + +ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) { + ModemKit *kit = new ModemKit; + kit->sampleRate = sampleRate; + kit->audioSampleRate = audioSampleRate; + return kit; +} + void ModemIQ::disposeKit(ModemKit *kit) { delete kit; } +int ModemIQ::checkSampleRate(long long sampleRate, int audioSampleRate) { + return audioSampleRate; +} + +int ModemIQ::getDefaultSampleRate() { + return 48000; +} + void ModemIQ::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { int bufSize = input->data.size(); diff --git a/src/modules/modem/analog/ModemIQ.h b/src/modules/modem/analog/ModemIQ.h index abd9d94..ca9e5fa 100644 --- a/src/modules/modem/analog/ModemIQ.h +++ b/src/modules/modem/analog/ModemIQ.h @@ -4,11 +4,19 @@ class ModemIQ : public Modem { public: ModemIQ(); + std::string getType(); std::string getName(); + Modem *factory(); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + int getDefaultSampleRate(); + ModemKit *buildKit(long long sampleRate, int audioSampleRate); + void disposeKit(ModemKit *kit); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/analog/ModemLSB.cpp b/src/modules/modem/analog/ModemLSB.cpp index 44fb116..31d86a3 100644 --- a/src/modules/modem/analog/ModemLSB.cpp +++ b/src/modules/modem/analog/ModemLSB.cpp @@ -1,6 +1,6 @@ #include "ModemLSB.h" -ModemLSB::ModemLSB() { +ModemLSB::ModemLSB() : ModemAnalog() { // half band filter used for side-band elimination ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f); demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1); @@ -19,6 +19,20 @@ ModemLSB::~ModemLSB() { ampmodem_destroy(demodAM_LSB); } +int ModemLSB::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < MIN_BANDWIDTH) { + return MIN_BANDWIDTH; + } + if (sampleRate % 2 == 0) { + return sampleRate; + } + return sampleRate+1; +} + +int ModemLSB::getDefaultSampleRate() { + return 5400; +} + void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitAnalog *akit = (ModemKitAnalog *)kit; diff --git a/src/modules/modem/analog/ModemLSB.h b/src/modules/modem/analog/ModemLSB.h index cbdc176..04a462c 100644 --- a/src/modules/modem/analog/ModemLSB.h +++ b/src/modules/modem/analog/ModemLSB.h @@ -1,13 +1,18 @@ #pragma once -#include "Modem.h" #include "ModemAnalog.h" class ModemLSB : public ModemAnalog { public: ModemLSB(); ~ModemLSB(); + std::string getName(); + Modem *factory(); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + int getDefaultSampleRate(); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/analog/ModemUSB.cpp b/src/modules/modem/analog/ModemUSB.cpp index 0482d4f..8f3202b 100644 --- a/src/modules/modem/analog/ModemUSB.cpp +++ b/src/modules/modem/analog/ModemUSB.cpp @@ -1,6 +1,6 @@ #include "ModemUSB.h" -ModemUSB::ModemUSB() { +ModemUSB::ModemUSB() : ModemAnalog() { // half band filter used for side-band elimination ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f); demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1); @@ -19,6 +19,20 @@ ModemUSB::~ModemUSB() { ampmodem_destroy(demodAM_USB); } +int ModemUSB::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < MIN_BANDWIDTH) { + return MIN_BANDWIDTH; + } + if (sampleRate % 2 == 0) { + return sampleRate; + } + return sampleRate+1; +} + +int ModemUSB::getDefaultSampleRate() { + return 5400; +} + void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitAnalog *akit = (ModemKitAnalog *)kit; diff --git a/src/modules/modem/analog/ModemUSB.h b/src/modules/modem/analog/ModemUSB.h index d6d3a4d..44dd0f3 100644 --- a/src/modules/modem/analog/ModemUSB.h +++ b/src/modules/modem/analog/ModemUSB.h @@ -5,8 +5,14 @@ class ModemUSB : public ModemAnalog { public: ModemUSB(); ~ModemUSB(); + std::string getName(); + Modem *factory(); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + int getDefaultSampleRate(); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/digital/ModemAPSK.cpp b/src/modules/modem/digital/ModemAPSK.cpp index ed04c10..8d4ffc6 100644 --- a/src/modules/modem/digital/ModemAPSK.cpp +++ b/src/modules/modem/digital/ModemAPSK.cpp @@ -1,6 +1,6 @@ #include "ModemAPSK.h" -ModemAPSK::ModemAPSK() { +ModemAPSK::ModemAPSK() : ModemDigital() { demodAPSK4 = modem_create(LIQUID_MODEM_APSK4); demodAPSK8 = modem_create(LIQUID_MODEM_APSK8); demodAPSK16 = modem_create(LIQUID_MODEM_APSK16); @@ -8,9 +8,8 @@ ModemAPSK::ModemAPSK() { demodAPSK64 = modem_create(LIQUID_MODEM_APSK64); demodAPSK128 = modem_create(LIQUID_MODEM_APSK128); demodAPSK256 = modem_create(LIQUID_MODEM_APSK256); - demodulatorCons.store(4); - currentDemodCons.store(0); - updateDemodulatorCons(4); + demodAPSK = demodAPSK4; + cons = 4; } Modem *ModemAPSK::factory() { @@ -31,46 +30,67 @@ std::string ModemAPSK::getName() { return "APSK"; } +ModemArgInfoList ModemAPSK::getSettings() { + ModemArgInfoList args; + + ModemArgInfo consArg; + consArg.key = "cons"; + consArg.name = "Constellation"; + consArg.description = "Modem Constellation Pattern"; + consArg.value = std::to_string(cons); + consArg.type = ModemArgInfo::STRING; + std::vector consOpts; + consOpts.push_back("4"); + consOpts.push_back("8"); + consOpts.push_back("16"); + consOpts.push_back("32"); + consOpts.push_back("64"); + consOpts.push_back("128"); + consOpts.push_back("256"); + consArg.options = consOpts; + args.push_back(consArg); + + return args; +} + +void ModemAPSK::writeSetting(std::string setting, std::string value) { + if (setting == "cons") { + int newCons = std::stoi(value); + updateDemodulatorCons(newCons); + } +} + +std::string ModemAPSK::readSetting(std::string setting) { + if (setting == "cons") { + return std::to_string(cons); + } + return ""; +} + void ModemAPSK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - switch (demodulatorCons.load()) { - case 2: - demodAPSK = demodAPSK4; - updateDemodulatorCons(4); - break; - case 4: - demodAPSK = demodAPSK4; - updateDemodulatorCons(4); - break; - case 8: - demodAPSK = demodAPSK8; - updateDemodulatorCons(8); - break; - case 16: - demodAPSK = demodAPSK16; - updateDemodulatorCons(16); - break; - case 32: - demodAPSK = demodAPSK32; - updateDemodulatorCons(32); - break; - case 64: - demodAPSK = demodAPSK64; - updateDemodulatorCons(64); - break; - case 128: - demodAPSK = demodAPSK128; - updateDemodulatorCons(128); - break; - case 256: - demodAPSK = demodAPSK256; - updateDemodulatorCons(256); - break; - default: - demodAPSK = demodAPSK4; - break; - } + this->cons = cons; + switch (cons) { + case 4: + demodAPSK = demodAPSK4; + break; + case 8: + demodAPSK = demodAPSK8; + break; + case 16: + demodAPSK = demodAPSK16; + break; + case 32: + demodAPSK = demodAPSK32; + break; + case 64: + demodAPSK = demodAPSK64; + break; + case 128: + demodAPSK = demodAPSK128; + break; + case 256: + demodAPSK = demodAPSK256; + break; } } diff --git a/src/modules/modem/digital/ModemAPSK.h b/src/modules/modem/digital/ModemAPSK.h index f5497df..dc9a4c6 100644 --- a/src/modules/modem/digital/ModemAPSK.h +++ b/src/modules/modem/digital/ModemAPSK.h @@ -5,12 +5,20 @@ class ModemAPSK : public ModemDigital { public: ModemAPSK(); ~ModemAPSK(); + std::string getName(); + Modem *factory(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + void updateDemodulatorCons(int cons); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: + int cons; modem demodAPSK; modem demodAPSK4; modem demodAPSK8; diff --git a/src/modules/modem/digital/ModemASK.cpp b/src/modules/modem/digital/ModemASK.cpp index af09b76..f952a55 100644 --- a/src/modules/modem/digital/ModemASK.cpp +++ b/src/modules/modem/digital/ModemASK.cpp @@ -1,6 +1,6 @@ #include "ModemASK.h" -ModemASK::ModemASK() { +ModemASK::ModemASK() : ModemDigital() { demodASK2 = modem_create(LIQUID_MODEM_ASK2); demodASK4 = modem_create(LIQUID_MODEM_ASK4); demodASK8 = modem_create(LIQUID_MODEM_ASK8); @@ -10,9 +10,7 @@ ModemASK::ModemASK() { demodASK128 = modem_create(LIQUID_MODEM_ASK128); demodASK256 = modem_create(LIQUID_MODEM_ASK256); demodASK = demodASK2; - demodulatorCons.store(2); - currentDemodCons.store(0); - updateDemodulatorCons(2); + cons = 2; } Modem *ModemASK::factory() { @@ -33,47 +31,71 @@ std::string ModemASK::getName() { return "ASK"; } +ModemArgInfoList ModemASK::getSettings() { + ModemArgInfoList args; + + ModemArgInfo consArg; + consArg.key = "cons"; + consArg.name = "Constellation"; + consArg.description = "Modem Constellation Pattern"; + consArg.value = std::to_string(cons); + consArg.type = ModemArgInfo::STRING; + std::vector consOpts; + consOpts.push_back("2"); + consOpts.push_back("4"); + consOpts.push_back("8"); + consOpts.push_back("16"); + consOpts.push_back("32"); + consOpts.push_back("64"); + consOpts.push_back("128"); + consOpts.push_back("256"); + consArg.options = consOpts; + args.push_back(consArg); + + return args; +} + +void ModemASK::writeSetting(std::string setting, std::string value) { + if (setting == "cons") { + int newCons = std::stoi(value); + updateDemodulatorCons(newCons); + } +} + +std::string ModemASK::readSetting(std::string setting) { + if (setting == "cons") { + return std::to_string(cons); + } + return ""; +} + void ModemASK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - - switch (demodulatorCons.load()) { - case 2: - demodASK = demodASK2; - updateDemodulatorCons(2); - break; - case 4: - demodASK = demodASK4; - updateDemodulatorCons(4); - break; - case 8: - demodASK = demodASK8; - updateDemodulatorCons(8); - break; - case 16: - demodASK = demodASK16; - updateDemodulatorCons(16); - break; - case 32: - demodASK = demodASK32; - updateDemodulatorCons(32); - break; - case 64: - demodASK = demodASK64; - updateDemodulatorCons(64); - break; - case 128: - demodASK = demodASK128; - updateDemodulatorCons(128); - break; - case 256: - demodASK = demodASK256; - updateDemodulatorCons(256); - break; - default: - demodASK = demodASK2; - break; - } + this->cons = cons; + switch (cons) { + case 2: + demodASK = demodASK2; + break; + case 4: + demodASK = demodASK4; + break; + case 8: + demodASK = demodASK8; + break; + case 16: + demodASK = demodASK16; + break; + case 32: + demodASK = demodASK32; + break; + case 64: + demodASK = demodASK64; + break; + case 128: + demodASK = demodASK128; + break; + case 256: + demodASK = demodASK256; + break; } } diff --git a/src/modules/modem/digital/ModemASK.h b/src/modules/modem/digital/ModemASK.h index 5dfffc1..e102b96 100644 --- a/src/modules/modem/digital/ModemASK.h +++ b/src/modules/modem/digital/ModemASK.h @@ -5,12 +5,20 @@ class ModemASK : public ModemDigital { public: ModemASK(); ~ModemASK(); + std::string getName(); + Modem *factory(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + void updateDemodulatorCons(int cons); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: + int cons; modem demodASK; modem demodASK2; modem demodASK4; diff --git a/src/modules/modem/digital/ModemBPSK.cpp b/src/modules/modem/digital/ModemBPSK.cpp index 535cdae..bd82d88 100644 --- a/src/modules/modem/digital/ModemBPSK.cpp +++ b/src/modules/modem/digital/ModemBPSK.cpp @@ -1,6 +1,6 @@ #include "ModemBPSK.h" -ModemBPSK::ModemBPSK() { +ModemBPSK::ModemBPSK() : ModemDigital() { demodBPSK = modem_create(LIQUID_MODEM_BPSK); } @@ -16,12 +16,6 @@ std::string ModemBPSK::getName() { return "BPSK"; } -void ModemBPSK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - } -} - void ModemBPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitDigital *dkit = (ModemKitDigital *)kit; digitalStart(dkit, demodBPSK, input); diff --git a/src/modules/modem/digital/ModemBPSK.h b/src/modules/modem/digital/ModemBPSK.h index ef26c5c..e571478 100644 --- a/src/modules/modem/digital/ModemBPSK.h +++ b/src/modules/modem/digital/ModemBPSK.h @@ -5,12 +5,13 @@ class ModemBPSK : public ModemDigital { public: ModemBPSK(); ~ModemBPSK(); + std::string getName(); + Modem *factory(); - void updateDemodulatorCons(int cons); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: modem demodBPSK; - }; diff --git a/src/modules/modem/digital/ModemDPSK.cpp b/src/modules/modem/digital/ModemDPSK.cpp index b44ebb7..13f5083 100644 --- a/src/modules/modem/digital/ModemDPSK.cpp +++ b/src/modules/modem/digital/ModemDPSK.cpp @@ -1,6 +1,6 @@ #include "ModemDPSK.h" -ModemDPSK::ModemDPSK() { +ModemDPSK::ModemDPSK() : ModemDigital() { demodDPSK2 = modem_create(LIQUID_MODEM_DPSK2); demodDPSK4 = modem_create(LIQUID_MODEM_DPSK4); demodDPSK8 = modem_create(LIQUID_MODEM_DPSK8); @@ -9,9 +9,8 @@ ModemDPSK::ModemDPSK() { demodDPSK64 = modem_create(LIQUID_MODEM_DPSK64); demodDPSK128 = modem_create(LIQUID_MODEM_DPSK128); demodDPSK256 = modem_create(LIQUID_MODEM_DPSK256); - demodulatorCons.store(2); - currentDemodCons.store(0); - updateDemodulatorCons(2); + demodDPSK = demodDPSK2; + cons = 2; } Modem *ModemDPSK::factory() { @@ -33,47 +32,71 @@ ModemDPSK::~ModemDPSK() { modem_destroy(demodDPSK256); } +ModemArgInfoList ModemDPSK::getSettings() { + ModemArgInfoList args; + + ModemArgInfo consArg; + consArg.key = "cons"; + consArg.name = "Constellation"; + consArg.description = "Modem Constellation Pattern"; + consArg.value = std::to_string(cons); + consArg.type = ModemArgInfo::STRING; + std::vector consOpts; + consOpts.push_back("2"); + consOpts.push_back("4"); + consOpts.push_back("8"); + consOpts.push_back("16"); + consOpts.push_back("32"); + consOpts.push_back("64"); + consOpts.push_back("128"); + consOpts.push_back("256"); + consArg.options = consOpts; + args.push_back(consArg); + + return args; +} + +void ModemDPSK::writeSetting(std::string setting, std::string value) { + if (setting == "cons") { + int newCons = std::stoi(value); + updateDemodulatorCons(newCons); + } +} + +std::string ModemDPSK::readSetting(std::string setting) { + if (setting == "cons") { + return std::to_string(cons); + } + return ""; +} + void ModemDPSK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - - switch (demodulatorCons.load()) { - case 2: - demodDPSK = demodDPSK2; - updateDemodulatorCons(2); - break; - case 4: - demodDPSK = demodDPSK4; - updateDemodulatorCons(4); - break; - case 8: - demodDPSK = demodDPSK8; - updateDemodulatorCons(8); - break; - case 16: - demodDPSK = demodDPSK16; - updateDemodulatorCons(16); - break; - case 32: - demodDPSK = demodDPSK32; - updateDemodulatorCons(32); - break; - case 64: - demodDPSK = demodDPSK64; - updateDemodulatorCons(64); - break; - case 128: - demodDPSK = demodDPSK128; - updateDemodulatorCons(128); - break; - case 256: - demodDPSK = demodDPSK256; - updateDemodulatorCons(256); - break; - default: - demodDPSK = demodDPSK2; - break; - } + this->cons = cons; + switch (cons) { + case 2: + demodDPSK = demodDPSK2; + break; + case 4: + demodDPSK = demodDPSK4; + break; + case 8: + demodDPSK = demodDPSK8; + break; + case 16: + demodDPSK = demodDPSK16; + break; + case 32: + demodDPSK = demodDPSK32; + break; + case 64: + demodDPSK = demodDPSK64; + break; + case 128: + demodDPSK = demodDPSK128; + break; + case 256: + demodDPSK = demodDPSK256; + break; } } diff --git a/src/modules/modem/digital/ModemDPSK.h b/src/modules/modem/digital/ModemDPSK.h index b431ffd..3b76e00 100644 --- a/src/modules/modem/digital/ModemDPSK.h +++ b/src/modules/modem/digital/ModemDPSK.h @@ -5,12 +5,20 @@ class ModemDPSK : public ModemDigital { public: ModemDPSK(); ~ModemDPSK(); + std::string getName(); + Modem *factory(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + void updateDemodulatorCons(int cons); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: + int cons; modem demodDPSK; modem demodDPSK2; modem demodDPSK4; diff --git a/src/modules/modem/digital/ModemFSK.cpp b/src/modules/modem/digital/ModemFSK.cpp new file mode 100644 index 0000000..9aef453 --- /dev/null +++ b/src/modules/modem/digital/ModemFSK.cpp @@ -0,0 +1,143 @@ +#include "ModemFSK.h" +#include + +ModemFSK::ModemFSK() : ModemDigital() { + // DMR defaults? + bps = 1; + sps = 9600; + bw = 0.45; + outStream << std::hex; +} + +Modem *ModemFSK::factory() { + return new ModemFSK; +} + +int ModemFSK::checkSampleRate(long long sampleRate, int audioSampleRate) { + float minSps = pow(2.0,bps); + float nextSps = (float(sampleRate) / float(sps)); + if (nextSps < minSps) { + return 2 * bps * sps; + } else { + return sampleRate; + } +} + +int ModemFSK::getDefaultSampleRate() { + return 19200; +} + +ModemArgInfoList ModemFSK::getSettings() { + ModemArgInfoList args; + + ModemArgInfo bpsArg; + bpsArg.key = "bps"; + bpsArg.name = "Bits/symbol"; + bpsArg.value = std::to_string(bps); + bpsArg.description = "Modem bits-per-symbol"; + bpsArg.type = ModemArgInfo::STRING; + bpsArg.units = "bits"; + + std::vector bpsOpts; + bpsOpts.push_back("1"); + bpsOpts.push_back("2"); + bpsOpts.push_back("4"); + bpsOpts.push_back("8"); + bpsOpts.push_back("16"); + bpsArg.options = bpsOpts; + + args.push_back(bpsArg); + + ModemArgInfo spsArg; + spsArg.key = "sps"; + spsArg.name = "Symbols/second"; + spsArg.value = std::to_string(sps); + spsArg.description = "Modem symbols-per-second"; + spsArg.type = ModemArgInfo::INT; + spsArg.range = ModemRange(10,115200); + std::vector spsOpts; + + args.push_back(spsArg); + + ModemArgInfo bwArg; + bwArg.key = "bw"; + bwArg.name = "Signal bandwidth"; + bwArg.value = std::to_string(bw); + bwArg.description = "Total signal bandwidth"; + bwArg.type = ModemArgInfo::FLOAT; + bwArg.range = ModemRange(0.1,0.49); + args.push_back(bwArg); + + return args; +} + +void ModemFSK::writeSetting(std::string setting, std::string value) { + if (setting == "bps") { + bps = std::stoi(value); + rebuildKit(); + } else if (setting == "sps") { + sps = std::stoi(value); + rebuildKit(); + } else if (setting == "bw") { + bw = std::stof(value); + rebuildKit(); + } +} + +std::string ModemFSK::readSetting(std::string setting) { + if (setting == "bps") { + return std::to_string(bps); + } else if (setting == "sps") { + return std::to_string(sps); + } else if (setting == "bw") { + return std::to_string(bw); + } + return ""; +} + +ModemKit *ModemFSK::buildKit(long long sampleRate, int audioSampleRate) { + ModemKitFSK *dkit = new ModemKitFSK; + dkit->m = bps; + dkit->k = sampleRate / sps; + dkit->bw = bw; + + dkit->demodFSK = fskdem_create(dkit->m, dkit->k, dkit->bw); + + dkit->sampleRate = sampleRate; + dkit->audioSampleRate = audioSampleRate; + + return dkit; +} + +void ModemFSK::disposeKit(ModemKit *kit) { + ModemKitFSK *dkit = (ModemKitFSK *)kit; + + fskdem_destroy(dkit->demodFSK); + + delete dkit; +} + +std::string ModemFSK::getName() { + return "FSK"; +} + +ModemFSK::~ModemFSK() { + +} + +void ModemFSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { + ModemKitFSK *dkit = (ModemKitFSK *)kit; + + digitalStart(dkit, nullptr, input); + + dkit->inputBuffer.insert(dkit->inputBuffer.end(),input->data.begin(),input->data.end()); + + while (dkit->inputBuffer.size() >= dkit->k) { + outStream << fskdem_demodulate(dkit->demodFSK, &dkit->inputBuffer[0]); + +// float err = fskdem_get_frequency_error(dkit->demodFSK); + dkit->inputBuffer.erase(dkit->inputBuffer.begin(),dkit->inputBuffer.begin()+dkit->k); + } + + digitalFinish(dkit, nullptr); +} \ No newline at end of file diff --git a/src/modules/modem/digital/ModemFSK.h b/src/modules/modem/digital/ModemFSK.h new file mode 100644 index 0000000..332681f --- /dev/null +++ b/src/modules/modem/digital/ModemFSK.h @@ -0,0 +1,40 @@ +#pragma once +#include "ModemDigital.h" +#include + +class ModemKitFSK : public ModemKitDigital { +public: + unsigned int m, k; + float bw; + + fskdem demodFSK; + std::vector inputBuffer; +}; + + +class ModemFSK : public ModemDigital { +public: + ModemFSK(); + ~ModemFSK(); + + std::string getName(); + + Modem *factory(); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + int getDefaultSampleRate(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + + ModemKit *buildKit(long long sampleRate, int audioSampleRate); + void disposeKit(ModemKit *kit); + + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); + +private: + int sps, bps; + float bw; +}; + diff --git a/src/modules/modem/digital/ModemGMSK.cpp b/src/modules/modem/digital/ModemGMSK.cpp new file mode 100644 index 0000000..9786103 --- /dev/null +++ b/src/modules/modem/digital/ModemGMSK.cpp @@ -0,0 +1,133 @@ +#include "ModemGMSK.h" +#include + +ModemGMSK::ModemGMSK() : ModemDigital() { + _sps = 4; + _fdelay = 3; + _ebf = 0.3; + outStream << std::hex; +} + +ModemGMSK::~ModemGMSK() { + +} + +std::string ModemGMSK::getName() { + return "GMSK"; +} + +Modem *ModemGMSK::factory() { + return new ModemGMSK; +} + +int ModemGMSK::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < MIN_BANDWIDTH) { + return MIN_BANDWIDTH; + } + return sampleRate; +} + +int ModemGMSK::getDefaultSampleRate() { + return 19200; +} + +ModemArgInfoList ModemGMSK::getSettings() { + ModemArgInfoList args; + + ModemArgInfo fdelayArg; + fdelayArg.key = "fdelay"; + fdelayArg.name = "Filter delay"; + fdelayArg.value = std::to_string(_fdelay); + fdelayArg.description = "Filter delay in samples"; + fdelayArg.type = ModemArgInfo::INT; + fdelayArg.units = "samples"; + fdelayArg.range = ModemRange(1,128); + args.push_back(fdelayArg); + + ModemArgInfo spsArg; + spsArg.key = "sps"; + spsArg.name = "Samples / symbol"; + spsArg.value = std::to_string(_sps); + spsArg.description = "Modem samples-per-symbol"; + spsArg.type = ModemArgInfo::INT; + spsArg.units = "samples/symbol"; + spsArg.range = ModemRange(2,512); + args.push_back(spsArg); + + ModemArgInfo ebfArg; + ebfArg.key = "ebf"; + ebfArg.name = "Excess bandwidth"; + ebfArg.value = std::to_string(_ebf); + ebfArg.description = "Modem excess bandwidth factor"; + ebfArg.type = ModemArgInfo::FLOAT; + ebfArg.range = ModemRange(0.1,0.49); + args.push_back(ebfArg); + + return args; +} + +void ModemGMSK::writeSetting(std::string setting, std::string value) { + if (setting == "fdelay") { + _fdelay = std::stoi(value); + rebuildKit(); + } else if (setting == "sps") { + _sps = std::stoi(value); + rebuildKit(); + } else if (setting == "ebf") { + _ebf = std::stof(value); + rebuildKit(); + } +} + +std::string ModemGMSK::readSetting(std::string setting) { + if (setting == "fdelay") { + return std::to_string(_fdelay); + } else if (setting == "sps") { + return std::to_string(_sps); + } else if (setting == "ebf") { + return std::to_string(_ebf); + } + return ""; +} + +ModemKit *ModemGMSK::buildKit(long long sampleRate, int audioSampleRate) { + ModemKitGMSK *dkit = new ModemKitGMSK; + dkit->sps = _sps; + dkit->fdelay = _fdelay; + dkit->ebf = _ebf; + + dkit->demodGMSK = gmskdem_create(dkit->sps, dkit->fdelay, dkit->ebf); + + dkit->sampleRate = sampleRate; + dkit->audioSampleRate = audioSampleRate; + + return dkit; +} + +void ModemGMSK::disposeKit(ModemKit *kit) { + ModemKitGMSK *dkit = (ModemKitGMSK *)kit; + + gmskdem_destroy(dkit->demodGMSK); + + delete dkit; +} + +void ModemGMSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { + ModemKitGMSK *dkit = (ModemKitGMSK *)kit; + unsigned int sym_out; + + digitalStart(dkit, nullptr, input); + + dkit->inputBuffer.insert(dkit->inputBuffer.end(),input->data.begin(),input->data.end()); + + int numProcessed = 0; + for (int i = 0, iMax = dkit->inputBuffer.size()/dkit->sps; i < iMax; i+= dkit->sps) { + gmskdem_demodulate(dkit->demodGMSK, &input->data[i],&sym_out); + outStream << sym_out; + numProcessed += dkit->sps; + } + + dkit->inputBuffer.erase(dkit->inputBuffer.begin(),dkit->inputBuffer.begin()+numProcessed); + + digitalFinish(dkit, nullptr); +} \ No newline at end of file diff --git a/src/modules/modem/digital/ModemGMSK.h b/src/modules/modem/digital/ModemGMSK.h new file mode 100644 index 0000000..e2e0635 --- /dev/null +++ b/src/modules/modem/digital/ModemGMSK.h @@ -0,0 +1,41 @@ +#pragma once +#include "ModemDigital.h" +#include + +class ModemKitGMSK : public ModemKitDigital { +public: + unsigned int fdelay, sps; + float ebf; + + gmskdem demodGMSK; + std::vector inputBuffer; +}; + + +class ModemGMSK : public ModemDigital { +public: + ModemGMSK(); + ~ModemGMSK(); + + std::string getName(); + + Modem *factory(); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + int getDefaultSampleRate(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + + ModemKit *buildKit(long long sampleRate, int audioSampleRate); + void disposeKit(ModemKit *kit); + + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); + +private: + int _sps; // samples per symbol + int _fdelay; // filter delay + float _ebf; +}; + diff --git a/src/modules/modem/digital/ModemOOK.cpp b/src/modules/modem/digital/ModemOOK.cpp index 7be56d7..faef9d2 100644 --- a/src/modules/modem/digital/ModemOOK.cpp +++ b/src/modules/modem/digital/ModemOOK.cpp @@ -1,13 +1,9 @@ #include "ModemOOK.h" -ModemOOK::ModemOOK() { +ModemOOK::ModemOOK() : ModemDigital() { demodOOK = modem_create(LIQUID_MODEM_OOK); } -Modem *ModemOOK::factory() { - return new ModemOOK; -} - ModemOOK::~ModemOOK() { modem_destroy(demodOOK); } @@ -16,10 +12,15 @@ std::string ModemOOK::getName() { return "OOK"; } -void ModemOOK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; +Modem *ModemOOK::factory() { + return new ModemOOK; +} + +int ModemOOK::checkSampleRate(long long sampleRate, int audioSampleRate) { + if (sampleRate < 100) { + return 100; } + return sampleRate; } void ModemOOK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { diff --git a/src/modules/modem/digital/ModemOOK.h b/src/modules/modem/digital/ModemOOK.h index 6f15c8b..0c25001 100644 --- a/src/modules/modem/digital/ModemOOK.h +++ b/src/modules/modem/digital/ModemOOK.h @@ -5,12 +5,15 @@ class ModemOOK : public ModemDigital { public: ModemOOK(); ~ModemOOK(); + std::string getName(); + Modem *factory(); - void updateDemodulatorCons(int cons); + + int checkSampleRate(long long sampleRate, int audioSampleRate); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: modem demodOOK; - }; diff --git a/src/modules/modem/digital/ModemPSK.cpp b/src/modules/modem/digital/ModemPSK.cpp index cf05a9e..8789435 100644 --- a/src/modules/modem/digital/ModemPSK.cpp +++ b/src/modules/modem/digital/ModemPSK.cpp @@ -1,6 +1,6 @@ #include "ModemPSK.h" -ModemPSK::ModemPSK() { +ModemPSK::ModemPSK() : ModemDigital() { demodPSK2 = modem_create(LIQUID_MODEM_PSK2); demodPSK4 = modem_create(LIQUID_MODEM_PSK4); demodPSK8 = modem_create(LIQUID_MODEM_PSK8); @@ -9,9 +9,8 @@ ModemPSK::ModemPSK() { demodPSK64 = modem_create(LIQUID_MODEM_PSK64); demodPSK128 = modem_create(LIQUID_MODEM_PSK128); demodPSK256 = modem_create(LIQUID_MODEM_PSK256); - demodulatorCons.store(2); - currentDemodCons.store(0); - updateDemodulatorCons(2); + demodPSK = demodPSK2; + cons = 2; } Modem *ModemPSK::factory() { @@ -33,47 +32,72 @@ ModemPSK::~ModemPSK() { modem_destroy(demodPSK256); } + +ModemArgInfoList ModemPSK::getSettings() { + ModemArgInfoList args; + + ModemArgInfo consArg; + consArg.key = "cons"; + consArg.name = "Constellation"; + consArg.description = "Modem Constellation Pattern"; + consArg.value = std::to_string(cons); + consArg.type = ModemArgInfo::STRING; + std::vector consOpts; + consOpts.push_back("2"); + consOpts.push_back("4"); + consOpts.push_back("8"); + consOpts.push_back("16"); + consOpts.push_back("32"); + consOpts.push_back("64"); + consOpts.push_back("128"); + consOpts.push_back("256"); + consArg.options = consOpts; + args.push_back(consArg); + + return args; +} + +void ModemPSK::writeSetting(std::string setting, std::string value) { + if (setting == "cons") { + int newCons = std::stoi(value); + updateDemodulatorCons(newCons); + } +} + +std::string ModemPSK::readSetting(std::string setting) { + if (setting == "cons") { + return std::to_string(cons); + } + return ""; +} + void ModemPSK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - - switch (demodulatorCons.load()) { - case 2: - demodPSK = demodPSK2; - updateDemodulatorCons(2); - break; - case 4: - demodPSK = demodPSK4; - updateDemodulatorCons(4); - break; - case 8: - demodPSK = demodPSK8; - updateDemodulatorCons(8); - break; - case 16: - demodPSK = demodPSK16; - updateDemodulatorCons(16); - break; - case 32: - demodPSK = demodPSK32; - updateDemodulatorCons(32); - break; - case 64: - demodPSK = demodPSK64; - updateDemodulatorCons(64); - break; - case 128: - demodPSK = demodPSK128; - updateDemodulatorCons(128); - break; - case 256: - demodPSK = demodPSK256; - updateDemodulatorCons(256); - break; - default: - demodPSK = demodPSK2; - break; - } + this->cons = cons; + switch (cons) { + case 2: + demodPSK = demodPSK2; + break; + case 4: + demodPSK = demodPSK4; + break; + case 8: + demodPSK = demodPSK8; + break; + case 16: + demodPSK = demodPSK16; + break; + case 32: + demodPSK = demodPSK32; + break; + case 64: + demodPSK = demodPSK64; + break; + case 128: + demodPSK = demodPSK128; + break; + case 256: + demodPSK = demodPSK256; + break; } } diff --git a/src/modules/modem/digital/ModemPSK.h b/src/modules/modem/digital/ModemPSK.h index 913f8f8..6f51a58 100644 --- a/src/modules/modem/digital/ModemPSK.h +++ b/src/modules/modem/digital/ModemPSK.h @@ -5,12 +5,20 @@ class ModemPSK : public ModemDigital { public: ModemPSK(); ~ModemPSK(); + std::string getName(); + Modem *factory(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + void updateDemodulatorCons(int cons); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: + int cons; modem demodPSK; modem demodPSK2; modem demodPSK4; diff --git a/src/modules/modem/digital/ModemQAM.cpp b/src/modules/modem/digital/ModemQAM.cpp index f14b5b5..c593357 100644 --- a/src/modules/modem/digital/ModemQAM.cpp +++ b/src/modules/modem/digital/ModemQAM.cpp @@ -1,6 +1,6 @@ #include "ModemQAM.h" -ModemQAM::ModemQAM() { +ModemQAM::ModemQAM() : ModemDigital() { demodQAM4 = modem_create(LIQUID_MODEM_QAM4); demodQAM8 = modem_create(LIQUID_MODEM_QAM8); demodQAM16 = modem_create(LIQUID_MODEM_QAM16); @@ -8,9 +8,8 @@ ModemQAM::ModemQAM() { demodQAM64 = modem_create(LIQUID_MODEM_QAM64); demodQAM128 = modem_create(LIQUID_MODEM_QAM128); demodQAM256 = modem_create(LIQUID_MODEM_QAM256); - demodulatorCons.store(4); - currentDemodCons.store(0); - updateDemodulatorCons(4); + demodQAM = demodQAM4; + cons = 4; } Modem *ModemQAM::factory() { @@ -31,47 +30,67 @@ ModemQAM::~ModemQAM() { modem_destroy(demodQAM256); } +ModemArgInfoList ModemQAM::getSettings() { + ModemArgInfoList args; + + ModemArgInfo consArg; + consArg.key = "cons"; + consArg.name = "Constellation"; + consArg.description = "Modem Constellation Pattern"; + consArg.value = std::to_string(cons); + consArg.type = ModemArgInfo::STRING; + std::vector consOpts; + consOpts.push_back("4"); + consOpts.push_back("8"); + consOpts.push_back("16"); + consOpts.push_back("32"); + consOpts.push_back("64"); + consOpts.push_back("128"); + consOpts.push_back("256"); + consArg.options = consOpts; + args.push_back(consArg); + + return args; +} + +void ModemQAM::writeSetting(std::string setting, std::string value) { + if (setting == "cons") { + int newCons = std::stoi(value); + updateDemodulatorCons(newCons); + } +} + +std::string ModemQAM::readSetting(std::string setting) { + if (setting == "cons") { + return std::to_string(cons); + } + return ""; +} + void ModemQAM::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - - switch (demodulatorCons.load()) { - case 2: - demodQAM = demodQAM4; - updateDemodulatorCons(4); - break; - case 4: - demodQAM = demodQAM4; - updateDemodulatorCons(4); - break; - case 8: - demodQAM = demodQAM8; - updateDemodulatorCons(8); - break; - case 16: - demodQAM = demodQAM16; - updateDemodulatorCons(16); - break; - case 32: - demodQAM = demodQAM32; - updateDemodulatorCons(32); - break; - case 64: - demodQAM = demodQAM64; - updateDemodulatorCons(64); - break; - case 128: - demodQAM = demodQAM128; - updateDemodulatorCons(128); - break; - case 256: - demodQAM = demodQAM256; - updateDemodulatorCons(256); - break; - default: - demodQAM = demodQAM4; - break; - } + this->cons = cons; + switch (cons) { + case 4: + demodQAM = demodQAM4; + break; + case 8: + demodQAM = demodQAM8; + break; + case 16: + demodQAM = demodQAM16; + break; + case 32: + demodQAM = demodQAM32; + break; + case 64: + demodQAM = demodQAM64; + break; + case 128: + demodQAM = demodQAM128; + break; + case 256: + demodQAM = demodQAM256; + break; } } diff --git a/src/modules/modem/digital/ModemQAM.h b/src/modules/modem/digital/ModemQAM.h index 973f9ff..3be6936 100644 --- a/src/modules/modem/digital/ModemQAM.h +++ b/src/modules/modem/digital/ModemQAM.h @@ -5,12 +5,20 @@ class ModemQAM : public ModemDigital { public: ModemQAM(); ~ModemQAM(); + std::string getName(); + Modem *factory(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + void updateDemodulatorCons(int cons); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: + int cons; modem demodQAM; modem demodQAM4; modem demodQAM8; diff --git a/src/modules/modem/digital/ModemQPSK.cpp b/src/modules/modem/digital/ModemQPSK.cpp index 309cadb..4754e78 100644 --- a/src/modules/modem/digital/ModemQPSK.cpp +++ b/src/modules/modem/digital/ModemQPSK.cpp @@ -1,6 +1,6 @@ #include "ModemQPSK.h" -ModemQPSK::ModemQPSK() { +ModemQPSK::ModemQPSK() : ModemDigital() { demodQPSK = modem_create(LIQUID_MODEM_QPSK); } @@ -16,12 +16,6 @@ std::string ModemQPSK::getName() { return "QPSK"; } -void ModemQPSK::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - } -} - void ModemQPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitDigital *dkit = (ModemKitDigital *)kit; digitalStart(dkit, demodQPSK, input); diff --git a/src/modules/modem/digital/ModemQPSK.h b/src/modules/modem/digital/ModemQPSK.h index 4d26e49..9de5d4e 100644 --- a/src/modules/modem/digital/ModemQPSK.h +++ b/src/modules/modem/digital/ModemQPSK.h @@ -5,9 +5,11 @@ class ModemQPSK : public ModemDigital { public: ModemQPSK(); ~ModemQPSK(); + std::string getName(); + Modem *factory(); - void updateDemodulatorCons(int cons); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/modules/modem/digital/ModemSQAM.cpp b/src/modules/modem/digital/ModemSQAM.cpp index a4abd39..f2ef57f 100644 --- a/src/modules/modem/digital/ModemSQAM.cpp +++ b/src/modules/modem/digital/ModemSQAM.cpp @@ -1,11 +1,10 @@ #include "ModemSQAM.h" -ModemSQAM::ModemSQAM() { +ModemSQAM::ModemSQAM() : ModemDigital() { demodSQAM32 = modem_create(LIQUID_MODEM_SQAM32); demodSQAM128 = modem_create(LIQUID_MODEM_SQAM128); - demodulatorCons.store(32); - currentDemodCons.store(0); - updateDemodulatorCons(32); + demodSQAM = demodSQAM32; + cons = 32; } Modem *ModemSQAM::factory() { @@ -21,47 +20,47 @@ std::string ModemSQAM::getName() { return "SQAM"; } +ModemArgInfoList ModemSQAM::getSettings() { + ModemArgInfoList args; + + ModemArgInfo consArg; + consArg.key = "cons"; + consArg.name = "Constellation"; + consArg.description = "Modem Constellation Pattern"; + consArg.value = std::to_string(cons); + consArg.type = ModemArgInfo::STRING; + std::vector consOpts; + consOpts.push_back("32"); + consOpts.push_back("128"); + consArg.options = consOpts; + args.push_back(consArg); + + return args; +} + +void ModemSQAM::writeSetting(std::string setting, std::string value) { + if (setting == "cons") { + int newCons = std::stoi(value); + updateDemodulatorCons(newCons); + } +} + +std::string ModemSQAM::readSetting(std::string setting) { + if (setting == "cons") { + return std::to_string(cons); + } + return ""; +} + void ModemSQAM::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - - switch (demodulatorCons.load()) { - case 2: - demodSQAM = demodSQAM32; - updateDemodulatorCons(32); - break; - case 4: - demodSQAM = demodSQAM32; - updateDemodulatorCons(32); - break; - case 8: - demodSQAM = demodSQAM32; - updateDemodulatorCons(32); - break; - case 16: - demodSQAM = demodSQAM32; - updateDemodulatorCons(32); - break; - case 32: - demodSQAM = demodSQAM32; - updateDemodulatorCons(32); - break; - case 64: - demodSQAM = demodSQAM32; - updateDemodulatorCons(32); - break; - case 128: - demodSQAM = demodSQAM128; - updateDemodulatorCons(128); - break; - case 256: - demodSQAM = demodSQAM128; - updateDemodulatorCons(128); - break; - default: - demodSQAM = demodSQAM32; - break; - } + this->cons = cons; + switch (cons) { + case 32: + demodSQAM = demodSQAM32; + break; + case 128: + demodSQAM = demodSQAM128; + break; } } diff --git a/src/modules/modem/digital/ModemSQAM.h b/src/modules/modem/digital/ModemSQAM.h index e26b497..cb5b3af 100644 --- a/src/modules/modem/digital/ModemSQAM.h +++ b/src/modules/modem/digital/ModemSQAM.h @@ -5,12 +5,20 @@ class ModemSQAM : public ModemDigital { public: ModemSQAM(); ~ModemSQAM(); + std::string getName(); + Modem *factory(); + + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + void updateDemodulatorCons(int cons); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: + int cons; modem demodSQAM; modem demodSQAM32; modem demodSQAM128; diff --git a/src/modules/modem/digital/ModemST.cpp b/src/modules/modem/digital/ModemST.cpp index b5d8e3f..b827fc2 100644 --- a/src/modules/modem/digital/ModemST.cpp +++ b/src/modules/modem/digital/ModemST.cpp @@ -1,6 +1,6 @@ #include "ModemST.h" -ModemST::ModemST() { +ModemST::ModemST() : ModemDigital() { demodST = modem_create(LIQUID_MODEM_V29); } @@ -16,12 +16,6 @@ ModemST::~ModemST() { modem_destroy(demodST); } -void ModemST::updateDemodulatorCons(int cons) { - if (currentDemodCons.load() != cons) { - currentDemodCons = cons; - } -} - void ModemST::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitDigital *dkit = (ModemKitDigital *)kit; digitalStart(dkit, demodST, input); diff --git a/src/modules/modem/digital/ModemST.h b/src/modules/modem/digital/ModemST.h index ac9ee10..2e92ae2 100644 --- a/src/modules/modem/digital/ModemST.h +++ b/src/modules/modem/digital/ModemST.h @@ -5,9 +5,11 @@ class ModemST : public ModemDigital { public: ModemST(); ~ModemST(); + std::string getName(); + Modem *factory(); - void updateDemodulatorCons(int cons); + void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); private: diff --git a/src/panel/ScopePanel.cpp b/src/panel/ScopePanel.cpp index f72a14c..1bc15db 100644 --- a/src/panel/ScopePanel.cpp +++ b/src/panel/ScopePanel.cpp @@ -16,6 +16,9 @@ void ScopePanel::setMode(ScopeMode scopeMode) { this->scopeMode = scopeMode; } +ScopePanel::ScopeMode ScopePanel::getMode() { + return this->scopeMode; +} void ScopePanel::setPoints(std::vector &points) { this->points.assign(points.begin(),points.end()); @@ -61,14 +64,29 @@ void ScopePanel::drawPanelContents() { glEnd(); } else if (scopeMode == SCOPE_MODE_XY) { - // ... + RGBA4f bg1(ThemeMgr::mgr.currentTheme->scopeBackground), bg2(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0); + bg1.a = 0.05; + bg2.a = 0.05; + bgPanel.setFillColor(bg1, bg2); + bgPanel.calcTransform(transform); + bgPanel.draw(); + glLineWidth(1.0); + glEnable(GL_POINT_SMOOTH); + glPointSize(1.0); + glLoadMatrixf(transform); + glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.15, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.15, + ThemeMgr::mgr.currentTheme->scopeLine.b * 0.15); } if (points.size()) { glEnable (GL_BLEND); glEnable (GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (scopeMode == SCOPE_MODE_XY) { + glBlendFunc(GL_ONE, GL_ONE); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } glColor4f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b, 1.0); glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, &points[0]); @@ -83,7 +101,8 @@ void ScopePanel::drawPanelContents() { glLoadMatrixf(bgPanelStereo[1].transform); glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4); } else if (scopeMode == SCOPE_MODE_XY) { - // ... + glLoadMatrixf(bgPanel.transform); + glDrawArrays(GL_POINTS, 0, points.size() / 2); } glLineWidth(1.0); glDisableClientState(GL_VERTEX_ARRAY); diff --git a/src/panel/ScopePanel.h b/src/panel/ScopePanel.h index 7d72756..2ce9224 100644 --- a/src/panel/ScopePanel.h +++ b/src/panel/ScopePanel.h @@ -10,6 +10,7 @@ public: ScopePanel(); void setMode(ScopeMode scopeMode); + ScopeMode getMode(); void setPoints(std::vector &points); protected: diff --git a/src/process/ScopeVisualProcessor.cpp b/src/process/ScopeVisualProcessor.cpp index dad6a03..19eb794 100644 --- a/src/process/ScopeVisualProcessor.cpp +++ b/src/process/ScopeVisualProcessor.cpp @@ -95,7 +95,7 @@ void ScopeVisualProcessor::process() { } } - if (audioInputData->channels == 2) { + if (audioInputData->type == 1) { iMax = audioInputData->data.size(); if (renderData->waveform_points.size() != iMax * 2) { renderData->waveform_points.resize(iMax * 2); @@ -104,11 +104,23 @@ void ScopeVisualProcessor::process() { renderData->waveform_points[i * 2] = (((double) (i % (iMax/2)) / (double) iMax) * 2.0 - 0.5) * 2.0; renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak; } + renderData->mode = ScopePanel::SCOPE_MODE_2Y; + } else if (audioInputData->type == 2) { + iMax = audioInputData->data.size(); + if (renderData->waveform_points.size() != iMax) { + renderData->waveform_points.resize(iMax); + } + for (i = 0; i < iMax/2; i++) { + renderData->waveform_points[i * 2] = audioInputData->data[i * 2] / peak; + renderData->waveform_points[i * 2 + 1] = audioInputData->data[i * 2 + 1] / peak; + } + renderData->mode = ScopePanel::SCOPE_MODE_XY; } else { for (i = 0; i < iMax; i++) { renderData->waveform_points[i * 2] = (((double) i / (double) iMax) - 0.5) * 2.0; renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak; } + renderData->mode = ScopePanel::SCOPE_MODE_Y; } renderData->spectrum = false; diff --git a/src/process/ScopeVisualProcessor.h b/src/process/ScopeVisualProcessor.h index 98a2398..daa131f 100644 --- a/src/process/ScopeVisualProcessor.h +++ b/src/process/ScopeVisualProcessor.h @@ -3,10 +3,12 @@ #include "VisualProcessor.h" #include "AudioThread.h" #include "fftw3.h" +#include "ScopePanel.h" class ScopeRenderData: public ReferenceCounter { public: std::vector waveform_points; + ScopePanel::ScopeMode mode; int inputRate; int sampleRate; int channels; diff --git a/src/visual/ModeSelectorCanvas.cpp b/src/visual/ModeSelectorCanvas.cpp index d89be48..4d00f0a 100644 --- a/src/visual/ModeSelectorCanvas.cpp +++ b/src/visual/ModeSelectorCanvas.cpp @@ -155,10 +155,16 @@ void ModeSelectorCanvas::addChoice(int value, std::string label) { numChoices = selections.size(); } +void ModeSelectorCanvas::addChoice(std::string label) { + selections.push_back(ModeSelectorMode(selections.size()+1, label)); + numChoices = selections.size(); +} + void ModeSelectorCanvas::setSelection(std::string label) { for (int i = 0; i < numChoices; i++) { if (selections[i].label == label) { currentSelection = i; + Refresh(); return; } } diff --git a/src/visual/ModeSelectorCanvas.h b/src/visual/ModeSelectorCanvas.h index ca2a524..bdbcc41 100644 --- a/src/visual/ModeSelectorCanvas.h +++ b/src/visual/ModeSelectorCanvas.h @@ -32,6 +32,7 @@ public: void setHelpTip(std::string tip); void addChoice(int value, std::string label); + void addChoice(std::string label); void setSelection(std::string label); std::string getSelectionLabel(); void setSelection(int value); diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index 7aea40a..612e6bf 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -230,9 +230,9 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long } // advanced demodulators start here - if (demod->getDemodulatorCons() > 0) { - demodStr = demodStr + std::to_string(demod->getDemodulatorCons()); - } +// if (demod->getDemodulatorCons() > 0) { +// demodStr = demodStr + std::to_string(demod->getDemodulatorCons()); +// } // add lock to string if we have an lock if(demod->getDemodulatorLock()) { diff --git a/src/visual/PrimaryGLContext.h b/src/visual/PrimaryGLContext.h index 254d2e7..9bab239 100644 --- a/src/visual/PrimaryGLContext.h +++ b/src/visual/PrimaryGLContext.h @@ -29,6 +29,5 @@ public: void setHoverAlpha(float hoverAlpha); private: - DemodulatorThreadParameters defaultDemodParams; float hoverAlpha; }; diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp index 9dfaced..b98ae83 100644 --- a/src/visual/ScopeCanvas.cpp +++ b/src/visual/ScopeCanvas.cpp @@ -28,7 +28,7 @@ EVT_LEAVE_WINDOW(ScopeCanvas::OnMouseLeftWindow) EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow) wxEND_EVENT_TABLE() -ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), stereo(false), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") { +ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") { glContext = new ScopeContext(this, &wxGetApp().GetContext(this)); inputData.set_max_num_items(2); @@ -65,7 +65,7 @@ bool ScopeCanvas::spectrumVisible() { float panelInterval = (2.0 + panelSpacing); ctrTarget = abs(round(ctr / panelInterval)); - + if (ctrTarget == 1 || dragAccel || (ctr != ctrTarget)) { return true; } @@ -73,10 +73,6 @@ bool ScopeCanvas::spectrumVisible() { return false; } -void ScopeCanvas::setStereo(bool state) { - stereo = state; -} - void ScopeCanvas::setDeviceName(std::string device_name) { deviceName = device_name; deviceName.append(" "); @@ -106,12 +102,12 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { ScopeRenderData *avData; inputData.pop(avData); + if (!avData->spectrum) { + scopePanel.setMode(avData->mode); if (avData->waveform_points.size()) { scopePanel.setPoints(avData->waveform_points); - setStereo(avData->channels == 2); } - avData->decRefCount(); } else { if (avData->waveform_points.size()) { @@ -133,14 +129,18 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glViewport(0, 0, ClientSize.x, ClientSize.y); - glContext->DrawBegin(); + if (scopePanel.getMode() == ScopePanel::SCOPE_MODE_XY && !spectrumVisible()) { + glDrawBuffer(GL_FRONT); + glContext->DrawBegin(false); + } else { + glDrawBuffer(GL_BACK); + glContext->DrawBegin(); + + bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,1)); + bgPanel.calcTransform(CubicVR::mat4::identity()); + bgPanel.draw(); + } - bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,0)); - bgPanel.calcTransform(CubicVR::mat4::identity()); - bgPanel.draw(); - - scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0)); @@ -190,7 +190,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { spectrumPanel.setPosition(panelInterval+ctr, 0); if (spectrumVisible()) { - spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,0)); + spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,1)); spectrumPanel.contentsVisible = true; roty = atan2(spectrumPanel.pos[0],1.2); spectrumPanel.rot[1] = -(roty * (180.0 / M_PI)); @@ -217,7 +217,9 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->DrawTunerTitles(ppmMode); glContext->DrawEnd(); - SwapBuffers(); + if (scopePanel.getMode() != ScopePanel::SCOPE_MODE_XY || spectrumVisible()) { + SwapBuffers(); + } } diff --git a/src/visual/ScopeCanvas.h b/src/visual/ScopeCanvas.h index d868b2e..3a04f9a 100644 --- a/src/visual/ScopeCanvas.h +++ b/src/visual/ScopeCanvas.h @@ -18,7 +18,6 @@ public: ScopeCanvas(wxWindow *parent, int *attribList = NULL); ~ScopeCanvas(); - void setStereo(bool state); void setDeviceName(std::string device_name); void setPPMMode(bool ppmMode); bool getPPMMode(); @@ -50,7 +49,6 @@ private: GLPanel bgPanel; ScopeContext *glContext; std::string deviceName; - bool stereo; bool ppmMode; bool showDb; float panelSpacing; diff --git a/src/visual/ScopeContext.cpp b/src/visual/ScopeContext.cpp index 8c4a889..a24e4b8 100644 --- a/src/visual/ScopeContext.cpp +++ b/src/visual/ScopeContext.cpp @@ -12,10 +12,12 @@ ScopeContext::ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext) : glLoadIdentity(); } -void ScopeContext::DrawBegin() { - glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, - ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +void ScopeContext::DrawBegin(bool clear) { + if (clear) { + glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, + ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } glMatrixMode (GL_MODELVIEW); glLoadIdentity(); diff --git a/src/visual/ScopeContext.h b/src/visual/ScopeContext.h index c962429..873bde0 100644 --- a/src/visual/ScopeContext.h +++ b/src/visual/ScopeContext.h @@ -11,7 +11,7 @@ class ScopeContext: public PrimaryGLContext { public: ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext); - void DrawBegin(); + void DrawBegin(bool clear=true); void DrawTunerTitles(bool ppmMode=false); void DrawDeviceName(std::string deviceName); void DrawDivider(); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index ce4630e..6f4ed05 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -17,8 +17,6 @@ #include -#define MIN_BANDWIDTH 1500 - wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint) EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown) @@ -44,6 +42,7 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : preBuf = false; SetCursor(wxCURSOR_CROSS); scaleMove = 0; + minBandwidth = 30000; } WaterfallCanvas::~WaterfallCanvas() { @@ -179,8 +178,8 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { if (currentZoom < 1) { bw = (long long) ceil((long double) bw * currentZoom); - if (bw < 30000) { - bw = 30000; + if (bw < minBandwidth) { + bw = minBandwidth; } if (mouseInView) { long long mfreqA = getFrequencyAt(mpos); @@ -461,7 +460,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { bwDiff = -bwDiff; } - int currentBW = demod->getBandwidth(); + int currentBW = dragBW; currentBW = currentBW + bwDiff; if (currentBW > CHANNELIZER_RATE_MAX) { @@ -472,6 +471,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { } demod->setBandwidth(currentBW); + dragBW = currentBW; } if (dragState == WF_DRAG_FREQUENCY) { @@ -596,11 +596,13 @@ void WaterfallCanvas::OnMouseDown(wxMouseEvent& event) { InteractiveCanvas::OnMouseDown(event); dragState = nextDragState; + wxGetApp().getDemodMgr().updateLastState(); if (dragState && dragState != WF_DRAG_RANGE) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator(); if (demod) { dragOfs = (long long) (mouseTracker.getMouseX() * (float) getBandwidth()) + getCenterFrequency() - (getBandwidth() / 2) - demod->getFrequency(); + dragBW = demod->getBandwidth(); } wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false); } @@ -615,6 +617,7 @@ void WaterfallCanvas::OnMouseWheelMoved(wxMouseEvent& event) { void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { InteractiveCanvas::OnMouseReleased(event); + wxGetApp().getDemodMgr().updateLastState(); bool isNew = shiftDown || (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) || (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive()); @@ -651,6 +654,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { if (dragState == WF_DRAG_NONE) { if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) { + mgr->updateLastState(); demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); } else { isNew = true; @@ -663,7 +667,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { demod->setSquelchEnabled(mgr->isLastSquelchEnabled()); demod->setGain(mgr->getLastGain()); demod->setMuted(mgr->isLastMuted()); - + demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType())); demod->run(); wxGetApp().bindDemodulator(demod); @@ -676,7 +680,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { demod->updateLabel(freq); demod->setFrequency(freq); - + if (isNew) { setStatusText("New demodulator at frequency: %s", freq); } else { @@ -684,13 +688,14 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { } wxGetApp().getDemodMgr().setActiveDemodulator(demod, false); - SetCursor(wxCURSOR_SIZING); + SetCursor(wxCURSOR_SIZING); nextDragState = WF_DRAG_FREQUENCY; mouseTracker.setVertDragLock(true); mouseTracker.setHorizDragLock(false); } else { if (activeDemod) { wxGetApp().getDemodMgr().setActiveDemodulator(activeDemod, false); + mgr->updateLastState(); activeDemod->setTracking(true); nextDragState = WF_DRAG_FREQUENCY; } else { @@ -740,6 +745,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) { + mgr->updateLastState(); demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); } else { demod = wxGetApp().getDemodMgr().newThread(); @@ -749,6 +755,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { demod->setSquelchLevel(mgr->getLastSquelchLevel()); demod->setSquelchEnabled(mgr->isLastSquelchEnabled()); demod->setGain(mgr->getLastGain()); + demod->setMuted(mgr->isLastMuted()); + demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType())); demod->run(); @@ -765,7 +773,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { demod->updateLabel(freq); demod->setFrequency(freq); demod->setBandwidth(bw); - wxGetApp().getDemodMgr().setActiveDemodulator(demod, false); + mgr->setActiveDemodulator(demod, false); + mgr->updateLastState(); } dragState = WF_DRAG_NONE; @@ -842,4 +851,6 @@ void WaterfallCanvas::setLinesPerSecond(int lps) { tex_update.unlock(); } - +void WaterfallCanvas::setMinBandwidth(int min) { + minBandwidth = min; +} diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 9efa8c4..89333f0 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -30,6 +30,7 @@ public: SpectrumVisualDataQueue *getVisualDataQueue(); void setLinesPerSecond(int lps); + void setMinBandwidth(int min); private: void OnPaint(wxPaintEvent& event); @@ -68,12 +69,14 @@ private: float hoverAlpha; int linesPerSecond; float scaleMove; + int dragBW; SpectrumVisualDataQueue visualDataQueue; Timer gTimer; double lpsIndex; bool preBuf; std::mutex tex_update; + int minBandwidth; // event table wxDECLARE_EVENT_TABLE(); };