Merge pull request #199 from cjcliffe/digital_experiments

Digital experiments and cleanup
This commit is contained in:
Charles J. Cliffe 2015-12-01 22:17:36 -05:00
commit 777e4a3488
83 changed files with 3076 additions and 844 deletions

View File

@ -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.") SET (VERSION_SUFFIX "" CACHE STRING "Add custom version suffix to CubicSDR application title.")
ADD_DEFINITIONS( 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.") SET (ENABLE_DIGITAL_LAB OFF CACHE BOOL "Enable 'Digital Lab' testing features.")
@ -22,6 +22,16 @@ IF(ENABLE_DIGITAL_LAB)
ADD_DEFINITIONS( ADD_DEFINITIONS(
-DENABLE_DIGITAL_LAB=1 -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() ENDIF()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
@ -225,6 +235,7 @@ SET (cubicsdr_sources
src/AppConfig.cpp src/AppConfig.cpp
src/FrequencyDialog.cpp src/FrequencyDialog.cpp
src/IOThread.cpp src/IOThread.cpp
src/ModemProperties.cpp
src/sdr/SDRDeviceInfo.cpp src/sdr/SDRDeviceInfo.cpp
src/sdr/SDRPostThread.cpp src/sdr/SDRPostThread.cpp
src/sdr/SDREnumerator.cpp src/sdr/SDREnumerator.cpp
@ -237,16 +248,6 @@ SET (cubicsdr_sources
src/modules/modem/Modem.cpp src/modules/modem/Modem.cpp
src/modules/modem/ModemAnalog.cpp src/modules/modem/ModemAnalog.cpp
src/modules/modem/ModemDigital.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/ModemAM.cpp
src/modules/modem/analog/ModemDSB.cpp src/modules/modem/analog/ModemDSB.cpp
src/modules/modem/analog/ModemFM.cpp src/modules/modem/analog/ModemFM.cpp
@ -296,6 +297,31 @@ SET (cubicsdr_sources
external/cubicvr2/math/cubic_math.cpp 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 SET (cubicsdr_headers
src/CubicSDRDefs.h src/CubicSDRDefs.h
src/CubicSDR.h src/CubicSDR.h
@ -303,6 +329,7 @@ SET (cubicsdr_headers
src/AppConfig.h src/AppConfig.h
src/FrequencyDialog.h src/FrequencyDialog.h
src/IOThread.h src/IOThread.h
src/ModemProperties.h
src/sdr/SDRDeviceInfo.h src/sdr/SDRDeviceInfo.h
src/sdr/SDRPostThread.h src/sdr/SDRPostThread.h
src/sdr/SDREnumerator.h src/sdr/SDREnumerator.h
@ -316,16 +343,6 @@ SET (cubicsdr_headers
src/modules/modem/Modem.h src/modules/modem/Modem.h
src/modules/modem/ModemAnalog.h src/modules/modem/ModemAnalog.h
src/modules/modem/ModemDigital.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/ModemAM.h
src/modules/modem/analog/ModemDSB.h src/modules/modem/analog/ModemDSB.h
src/modules/modem/analog/ModemFM.h src/modules/modem/analog/ModemFM.h
@ -391,6 +408,31 @@ SET (cubicsdr_headers
external/cubicvr2/math/vec4.h 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 SET (CUBICSDR_RESOURCES
${PROJECT_SOURCE_DIR}/font/vera_sans_mono12.fnt ${PROJECT_SOURCE_DIR}/font/vera_sans_mono12.fnt
${PROJECT_SOURCE_DIR}/font/vera_sans_mono16.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("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}")
SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}") SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}")
SOURCE_GROUP("Modem" REGULAR_EXPRESSION "src/modules/modem/${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\\Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}")
SOURCE_GROUP("Modem-Digital" REGULAR_EXPRESSION "src/modules/modem/digital/${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("Audio" REGULAR_EXPRESSION "src/audio/${REG_EXT}")
SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}") SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}")
SOURCE_GROUP("Visual" REGULAR_EXPRESSION "src/visual/${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 ( include_directories (
${PROJECT_SOURCE_DIR}/src/forms/SDRDevices ${PROJECT_SOURCE_DIR}/src/forms/SDRDevices
${PROJECT_SOURCE_DIR}/src/forms/DigitalConsole
${PROJECT_SOURCE_DIR}/src/sdr ${PROJECT_SOURCE_DIR}/src/sdr
${PROJECT_SOURCE_DIR}/src/demod ${PROJECT_SOURCE_DIR}/src/demod
${PROJECT_SOURCE_DIR}/src/modules ${PROJECT_SOURCE_DIR}/src/modules

View File

@ -67,46 +67,47 @@ AppFrame::AppFrame() :
gainSpacerItem->Show(false); gainSpacerItem->Show(false);
demodModeSelector = new ModeSelectorCanvas(demodPanel, attribList); demodModeSelector = new ModeSelectorCanvas(demodPanel, attribList);
demodModeSelector->addChoice(0, "FM"); demodModeSelector->addChoice("FM");
demodModeSelector->addChoice(1, "FMS"); demodModeSelector->addChoice("FMS");
demodModeSelector->addChoice(2, "AM"); demodModeSelector->addChoice("AM");
demodModeSelector->addChoice(3, "LSB"); demodModeSelector->addChoice("LSB");
demodModeSelector->addChoice(4, "USB"); demodModeSelector->addChoice("USB");
demodModeSelector->addChoice(5, "DSB"); demodModeSelector->addChoice("DSB");
demodModeSelector->addChoice(6, "I/Q"); demodModeSelector->addChoice("I/Q");
demodModeSelector->setSelection("FM"); demodModeSelector->setSelection("FM");
demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band."); 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); demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0);
#ifdef ENABLE_DIGITAL_LAB #ifdef ENABLE_DIGITAL_LAB
demodModeSelectorAdv = new ModeSelectorCanvas(this, attribList); demodModeSelectorAdv = new ModeSelectorCanvas(demodPanel, attribList);
demodModeSelectorAdv->addChoice(0, "ASK"); demodModeSelectorAdv->addChoice("ASK");
demodModeSelectorAdv->addChoice(1, "APSK"); demodModeSelectorAdv->addChoice("APSK");
demodModeSelectorAdv->addChoice(2, "BPSK"); demodModeSelectorAdv->addChoice("BPSK");
demodModeSelectorAdv->addChoice(3, "DPSK"); demodModeSelectorAdv->addChoice("DPSK");
demodModeSelectorAdv->addChoice(4, "PSK"); demodModeSelectorAdv->addChoice("PSK");
demodModeSelectorAdv->addChoice(5, "OOK"); demodModeSelectorAdv->addChoice("FSK");
demodModeSelectorAdv->addChoice(6, "ST"); demodModeSelectorAdv->addChoice("GMSK");
demodModeSelectorAdv->addChoice(7, "SQAM"); demodModeSelectorAdv->addChoice("OOK");
demodModeSelectorAdv->addChoice(8, "QAM"); demodModeSelectorAdv->addChoice("ST");
demodModeSelectorAdv->addChoice(9, "QPSK"); demodModeSelectorAdv->addChoice("SQAM");
demodModeSelectorAdv->addChoice("QAM");
demodModeSelectorAdv->addChoice("QPSK");
demodModeSelectorAdv->setHelpTip("Choose advanced modulation types."); demodModeSelectorAdv->setHelpTip("Choose advanced modulation types.");
demodModeSelectorAdv->SetMinSize(wxSize(40,-1));
demodModeSelectorAdv->SetMaxSize(wxSize(40,-1));
demodTray->Add(demodModeSelectorAdv, 3, wxEXPAND | wxALL, 0); 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 #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); wxGetApp().getDemodSpectrumProcessor()->setup(1024);
demodSpectrumCanvas = new SpectrumCanvas(demodPanel, attribList); demodSpectrumCanvas = new SpectrumCanvas(demodPanel, attribList);
demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
@ -119,11 +120,14 @@ AppFrame::AppFrame() :
demodWaterfallCanvas->setup(1024, 128); demodWaterfallCanvas->setup(1024, 128);
demodWaterfallCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); demodWaterfallCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas); demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
demodWaterfallCanvas->setMinBandwidth(8000);
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0); demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0);
wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue()); wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue());
demodWaterfallCanvas->getVisualDataQueue()->set_max_num_items(3); demodWaterfallCanvas->getVisualDataQueue()->set_max_num_items(3);
demodVisuals->SetMinSize(wxSize(128,-1));
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
demodTray->AddSpacer(1); demodTray->AddSpacer(1);
@ -142,6 +146,7 @@ AppFrame::AppFrame() :
scopeCanvas = new ScopeCanvas(demodPanel, attribList); scopeCanvas = new ScopeCanvas(demodPanel, attribList);
scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum."); scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum.");
scopeCanvas->SetMinSize(wxSize(128,-1));
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0); demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
wxGetApp().getScopeProcessor()->setup(2048); wxGetApp().getScopeProcessor()->setup(2048);
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue()); wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
@ -833,7 +838,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
if (demod) { if (demod && demod->isModemInitialized()) {
if (demod->isTracking()) { if (demod->isTracking()) {
if (spectrumCanvas->getViewState()) { if (spectrumCanvas->getViewState()) {
long long diff = abs(demod->getFrequency() - spectrumCanvas->getCenterFrequency()) + (demod->getBandwidth()/2) + (demod->getBandwidth()/4); 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); demod->setTracking(false);
} }
} }
if (demod->getBandwidth() != wxGetApp().getDemodMgr().getLastBandwidth()) {
wxGetApp().getDemodMgr().setLastBandwidth(demod->getBandwidth());
}
if (demod != activeDemodulator) { if (demod != activeDemodulator) {
demodSignalMeter->setInputValue(demod->getSquelchLevel()); demodSignalMeter->setInputValue(demod->getSquelchLevel());
@ -861,11 +870,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
std::string dType = demod->getDemodulatorType(); std::string dType = demod->getDemodulatorType();
demodModeSelector->setSelection(dType); demodModeSelector->setSelection(dType);
#ifdef ENABLE_DIGITAL_LAB #ifdef ENABLE_DIGITAL_LAB
int dCons = demod->getDemodulatorCons();
demodModeSelectorAdv->setSelection(dType); demodModeSelectorAdv->setSelection(dType);
demodModeSelectorCons->setSelection(dCons);
#endif #endif
demodMuteButton->setSelection(demod->isMuted()?1:-1); demodMuteButton->setSelection(demod->isMuted()?1:-1);
modemPropertiesUpdated.store(true);
} }
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
long long centerFreq = demod->getFrequency(); long long centerFreq = demod->getFrequency();
@ -895,7 +903,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
std::string dSelection = demodModeSelector->getSelectionLabel(); std::string dSelection = demodModeSelector->getSelectionLabel();
#ifdef ENABLE_DIGITAL_LAB #ifdef ENABLE_DIGITAL_LAB
std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel(); std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel();
int dSelectionCons = demodModeSelectorCons->getSelection();
// basic demodulators // basic demodulators
if (dSelection != "" && dSelection != demod->getDemodulatorType()) { if (dSelection != "" && dSelection != demod->getDemodulatorType()) {
@ -907,11 +914,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
demod->setDemodulatorType(dSelectionadv); demod->setDemodulatorType(dSelectionadv);
demodModeSelector->setSelection(-1); demodModeSelector->setSelection(-1);
} }
// set constellations
if (dSelectionCons != demod->getDemodulatorCons()) {
demod->setDemodulatorCons(dSelectionCons);
}
#else #else
// basic demodulators // basic demodulators
if (dSelection != "" && dSelection != demod->getDemodulatorType()) { if (dSelection != "" && dSelection != demod->getDemodulatorType()) {
@ -951,13 +953,14 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
demodGainMeter->setLevel(demodGainMeter->getInputValue()); demodGainMeter->setLevel(demodGainMeter->getInputValue());
} }
activeDemodulator = demod; activeDemodulator = demod;
} else if (demod) {
// Wait state for current demodulator modem to activate..
} else { } else {
DemodulatorMgr *mgr = &wxGetApp().getDemodMgr(); DemodulatorMgr *mgr = &wxGetApp().getDemodMgr();
std::string dSelection = demodModeSelector->getSelectionLabel(); std::string dSelection = demodModeSelector->getSelectionLabel();
#ifdef ENABLE_DIGITAL_LAB #ifdef ENABLE_DIGITAL_LAB
std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel(); std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel();
int dSelectionCons = demodModeSelectorCons->getSelection();
// basic demodulators // basic demodulators
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) { if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
@ -969,11 +972,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
mgr->setLastDemodulatorType(dSelectionadv); mgr->setLastDemodulatorType(dSelectionadv);
demodModeSelector->setSelection(-1); demodModeSelector->setSelection(-1);
} }
// set constellations
if (dSelectionCons != mgr->getLastDemodulatorCons()) {
mgr->setLastDemodulatorCons(dSelectionCons);
}
#else #else
// basic demodulators // basic demodulators
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) { if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
@ -1012,7 +1010,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
if (!demodTuner->HasFocus()) { if (!demodTuner->HasFocus()) {
demodTuner->SetFocus(); demodTuner->SetFocus();
} }
} else if (!wxGetApp().isDeviceSelectorOpen()) { } else if (!wxGetApp().isDeviceSelectorOpen() && (!modemProps || !modemProps->isMouseInView())) {
if (!waterfallCanvas->HasFocus()) { if (!waterfallCanvas->HasFocus()) {
waterfallCanvas->SetFocus(); 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().getAudioVisualQueue()->set_max_num_items((scopeCanvas->scopeVisible()?1:0) + (scopeCanvas->spectrumVisible()?1:0));
wxGetApp().getScopeProcessor()->run(); wxGetApp().getScopeProcessor()->run();
// wxGetApp().getSpectrumDistributor()->run();
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor(); SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor();
@ -1069,11 +1066,24 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
wxGetApp().getSDRPostThread()->setIQVisualRange(waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth()); wxGetApp().getSDRPostThread()->setIQVisualRange(waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth());
// waterfallCanvas->processInputQueue(); demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
// waterfallCanvas->Refresh();
// demodWaterfallCanvas->processInputQueue(); if (modemPropertiesUpdated.load() && demod && demod->isModemInitialized()) {
// demodWaterfallCanvas->Refresh(); 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()) { if (!this->IsActive()) {
std::this_thread::sleep_for(std::chrono::milliseconds(25)); 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("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name;
*demod->newChild("gain") = (*instance_i)->getGain(); *demod->newChild("gain") = (*instance_i)->getGain();
*demod->newChild("muted") = (*instance_i)->isMuted() ? 1 : 0; *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); s.SaveToFileXML(fileName);
@ -1177,35 +1195,79 @@ bool AppFrame::loadSession(std::string fileName) {
long bandwidth = *demod->getNext("bandwidth"); long bandwidth = *demod->getNext("bandwidth");
long long freq = *demod->getNext("frequency"); 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; 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 squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0;
int muted = demod->hasAnother("muted") ? (int) *demod->getNext("muted") : 0; int muted = demod->hasAnother("muted") ? (int) *demod->getNext("muted") : 0;
std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : ""; std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : "";
float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0; float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0;
// TODO: Check if "type" is numeric and perform update to new values std::string type = "FM";
//#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
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(); DemodulatorInstance *newDemod = wxGetApp().getDemodMgr().newThread();
loadedDemod = newDemod; loadedDemod = newDemod;
numDemodulators++; numDemodulators++;
newDemod->writeModemSettings(mSettings);
newDemod->setDemodulatorType(type); newDemod->setDemodulatorType(type);
newDemod->setBandwidth(bandwidth); newDemod->setBandwidth(bandwidth);
newDemod->setFrequency(freq); newDemod->setFrequency(freq);
@ -1269,3 +1331,8 @@ FFTVisualDataThread *AppFrame::getWaterfallDataThread() {
return waterfallDataThread; return waterfallDataThread;
} }
void AppFrame::updateModemProperties(ModemArgInfoList args) {
newModemArgs = args;
modemPropertiesUpdated.store(true);
}

View File

@ -16,6 +16,7 @@
#include "GainCanvas.h" #include "GainCanvas.h"
#include "FFTVisualDataThread.h" #include "FFTVisualDataThread.h"
#include "SDRDeviceInfo.h" #include "SDRDeviceInfo.h"
#include "ModemProperties.h"
//#include "UITestCanvas.h" //#include "UITestCanvas.h"
#include <map> #include <map>
@ -67,6 +68,8 @@ public:
FFTVisualDataThread *getWaterfallDataThread(); FFTVisualDataThread *getWaterfallDataThread();
void updateModemProperties(ModemArgInfoList args);
private: private:
void OnMenu(wxCommandEvent& event); void OnMenu(wxCommandEvent& event);
void OnClose(wxCloseEvent& event); void OnClose(wxCloseEvent& event);
@ -81,7 +84,6 @@ private:
ModeSelectorCanvas *demodModeSelector; ModeSelectorCanvas *demodModeSelector;
#ifdef ENABLE_DIGITAL_LAB #ifdef ENABLE_DIGITAL_LAB
ModeSelectorCanvas *demodModeSelectorAdv; ModeSelectorCanvas *demodModeSelectorAdv;
ModeSelectorCanvas *demodModeSelectorCons;
#endif #endif
SpectrumCanvas *demodSpectrumCanvas; SpectrumCanvas *demodSpectrumCanvas;
WaterfallCanvas *demodWaterfallCanvas; WaterfallCanvas *demodWaterfallCanvas;
@ -121,6 +123,10 @@ private:
std::thread *t_FFTData; std::thread *t_FFTData;
SDRDeviceInfo *devInfo; SDRDeviceInfo *devInfo;
std::atomic_bool deviceChanged; std::atomic_bool deviceChanged;
ModemProperties *modemProps;
std::atomic_bool modemPropertiesUpdated;
ModemArgInfoList newModemArgs;
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };

View File

@ -20,20 +20,20 @@
IMPLEMENT_APP(CubicSDR) IMPLEMENT_APP(CubicSDR)
#ifdef ENABLE_DIGITAL_LAB //#ifdef ENABLE_DIGITAL_LAB
// console output buffer for windows //// console output buffer for windows
#ifdef _WINDOWS //#ifdef _WINDOWS
class outbuf : public std::streambuf { //class outbuf : public std::streambuf {
public: // public:
outbuf() { // outbuf() {
setp(0, 0); // setp(0, 0);
} // }
virtual int_type overflow(int_type c = traits_type::eof()) { // virtual int_type overflow(int_type c = traits_type::eof()) {
return fputc(c, stdout) == EOF ? traits_type::eof() : c; // return fputc(c, stdout) == EOF ? traits_type::eof() : c;
} // }
}; //};
#endif //#endif
#endif //#endif
#ifdef MINGW_PATCH #ifdef MINGW_PATCH
FILE _iob[] = { *stdin, *stdout, *stderr }; FILE _iob[] = { *stdin, *stdout, *stderr };
@ -149,18 +149,18 @@ bool CubicSDR::OnInit() {
return false; return false;
} }
#ifdef ENABLE_DIGITAL_LAB //#ifdef ENABLE_DIGITAL_LAB
// console output for windows // // console output for windows
#ifdef _WINDOWS // #ifdef _WINDOWS
if (AllocConsole()) { // if (AllocConsole()) {
freopen("CONOUT$", "w", stdout); // freopen("CONOUT$", "w", stdout);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); // SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
} // }
outbuf ob; // outbuf ob;
std::streambuf *sb = std::cout.rdbuf(&ob); // std::streambuf *sb = std::cout.rdbuf(&ob);
std::cout.rdbuf(sb); // std::cout.rdbuf(sb);
#endif // #endif
#endif //#endif
wxApp::SetAppName("CubicSDR"); wxApp::SetAppName("CubicSDR");
@ -172,17 +172,23 @@ bool CubicSDR::OnInit() {
Modem::addModemFactory(new ModemDSB); Modem::addModemFactory(new ModemDSB);
Modem::addModemFactory(new ModemIQ); Modem::addModemFactory(new ModemIQ);
#ifdef ENABLE_DIGITAL_LAB
Modem::addModemFactory(new ModemAPSK); Modem::addModemFactory(new ModemAPSK);
Modem::addModemFactory(new ModemASK); Modem::addModemFactory(new ModemASK);
Modem::addModemFactory(new ModemBPSK); Modem::addModemFactory(new ModemBPSK);
Modem::addModemFactory(new ModemDPSK); Modem::addModemFactory(new ModemDPSK);
#if ENABLE_LIQUID_EXPERIMENTAL
Modem::addModemFactory(new ModemFSK);
#endif
Modem::addModemFactory(new ModemGMSK);
Modem::addModemFactory(new ModemOOK); Modem::addModemFactory(new ModemOOK);
Modem::addModemFactory(new ModemPSK); Modem::addModemFactory(new ModemPSK);
Modem::addModemFactory(new ModemQAM); Modem::addModemFactory(new ModemQAM);
Modem::addModemFactory(new ModemQPSK); Modem::addModemFactory(new ModemQPSK);
Modem::addModemFactory(new ModemSQAM); Modem::addModemFactory(new ModemSQAM);
Modem::addModemFactory(new ModemST); Modem::addModemFactory(new ModemST);
#endif
frequency = wxGetApp().getConfig()->getCenterFreq(); frequency = wxGetApp().getConfig()->getCenterFreq();
offset = 0; offset = 0;
ppm = 0; ppm = 0;

View File

@ -37,16 +37,22 @@
#include "ModemDSB.h" #include "ModemDSB.h"
#include "ModemIQ.h" #include "ModemIQ.h"
#ifdef ENABLE_DIGITAL_LAB
#include "ModemAPSK.h" #include "ModemAPSK.h"
#include "ModemASK.h" #include "ModemASK.h"
#include "ModemBPSK.h" #include "ModemBPSK.h"
#include "ModemDPSK.h" #include "ModemDPSK.h"
#if ENABLE_LIQUID_EXPERIMENTAL
#include "ModemFSK.h"
#endif
#include "ModemGMSK.h"
#include "ModemOOK.h" #include "ModemOOK.h"
#include "ModemPSK.h" #include "ModemPSK.h"
#include "ModemQAM.h" #include "ModemQAM.h"
#include "ModemQPSK.h" #include "ModemQPSK.h"
#include "ModemSQAM.h" #include "ModemSQAM.h"
#include "ModemST.h" #include "ModemST.h"
#endif
#include <wx/cmdline.h> #include <wx/cmdline.h>
@ -123,7 +129,6 @@ public:
void setDeviceSelectorClosed(); void setDeviceSelectorClosed();
bool isDeviceSelectorOpen(); bool isDeviceSelectorOpen();
void closeDeviceSelector(); void closeDeviceSelector();
void setAGCMode(bool mode); void setAGCMode(bool mode);
bool getAGCMode(); bool getAGCMode();

179
src/ModemProperties.cpp Normal file
View File

@ -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<std::string>::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<std::string, wxPGProperty *>::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;
}

39
src/ModemProperties.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/advprops.h>
#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<std::string, wxPGProperty *> props;
bool mouseInView;
};

View File

@ -18,6 +18,7 @@ public:
int sampleRate; int sampleRate;
int channels; int channels;
float peak; float peak;
int type;
std::vector<float> data; std::vector<float> data;
std::mutex busy_update; std::mutex busy_update;

View File

@ -14,9 +14,6 @@ class DemodulatorThreadCommand {
public: public:
enum DemodulatorThreadCommandEnum { enum DemodulatorThreadCommandEnum {
DEMOD_THREAD_CMD_NULL, 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_PREPROCESS_TERMINATED,
DEMOD_THREAD_CMD_DEMOD_TERMINATED, DEMOD_THREAD_CMD_DEMOD_TERMINATED,
DEMOD_THREAD_CMD_AUDIO_TERMINATED DEMOD_THREAD_CMD_AUDIO_TERMINATED
@ -82,6 +79,7 @@ class DemodulatorThreadPostIQData: public ReferenceCounter {
public: public:
std::vector<liquid_float_complex> data; std::vector<liquid_float_complex> data;
long long sampleRate; long long sampleRate;
std::string modemName;
std::string modemType; std::string modemType;
Modem *modem; Modem *modem;
ModemKit *modemKit; ModemKit *modemKit;
@ -124,23 +122,3 @@ typedef ThreadQueue<DemodulatorThreadIQData *> DemodulatorThreadInputQueue;
typedef ThreadQueue<DemodulatorThreadPostIQData *> DemodulatorThreadPostInputQueue; typedef ThreadQueue<DemodulatorThreadPostIQData *> DemodulatorThreadPostInputQueue;
typedef ThreadQueue<DemodulatorThreadCommand> DemodulatorThreadCommandQueue; typedef ThreadQueue<DemodulatorThreadCommand> DemodulatorThreadCommandQueue;
typedef ThreadQueue<DemodulatorThreadControlCommand> DemodulatorThreadControlCommandQueue; typedef ThreadQueue<DemodulatorThreadControlCommand> 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() {
}
};

View File

@ -1,8 +1,12 @@
#include "DemodulatorInstance.h" #include "DemodulatorInstance.h"
#include "CubicSDR.h"
DemodulatorInstance::DemodulatorInstance() : 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); terminated.store(true);
audioTerminated.store(true); audioTerminated.store(true);
demodTerminated.store(true); demodTerminated.store(true);
@ -12,23 +16,20 @@ DemodulatorInstance::DemodulatorInstance() :
muted.store(false); muted.store(false);
tracking.store(false); tracking.store(false);
follow.store(false); follow.store(false);
currentAudioSampleRate.store(0);
currentFrequency.store(0);
currentBandwidth.store(0);
currentOutputDevice.store(-1); currentOutputDevice.store(-1);
currentAudioGain.store(1.0); currentAudioGain.store(1.0);
label = new std::string("Unnamed"); label = new std::string("Unnamed");
pipeIQInputData = new DemodulatorThreadInputQueue; pipeIQInputData = new DemodulatorThreadInputQueue;
pipeIQDemodData = new DemodulatorThreadPostInputQueue; pipeIQDemodData = new DemodulatorThreadPostInputQueue;
pipeDemodCommand = new DemodulatorThreadCommandQueue;
pipeDemodNotify = new DemodulatorThreadCommandQueue; pipeDemodNotify = new DemodulatorThreadCommandQueue;
demodulatorPreThread = new DemodulatorPreThread(); audioThread = new AudioThread();
demodulatorPreThread = new DemodulatorPreThread(this);
demodulatorPreThread->setInputQueue("IQDataInput",pipeIQInputData); demodulatorPreThread->setInputQueue("IQDataInput",pipeIQInputData);
demodulatorPreThread->setOutputQueue("IQDataOutput",pipeIQDemodData); demodulatorPreThread->setOutputQueue("IQDataOutput",pipeIQDemodData);
demodulatorPreThread->setOutputQueue("NotifyQueue",pipeDemodNotify); demodulatorPreThread->setOutputQueue("NotifyQueue",pipeDemodNotify);
demodulatorPreThread->setInputQueue("CommandQueue",pipeDemodCommand);
pipeAudioData = new AudioThreadInputQueue; pipeAudioData = new AudioThreadInputQueue;
threadQueueControl = new DemodulatorThreadControlCommandQueue; threadQueueControl = new DemodulatorThreadControlCommandQueue;
@ -39,20 +40,19 @@ DemodulatorInstance::DemodulatorInstance() :
demodulatorThread->setOutputQueue("NotifyQueue",pipeDemodNotify); demodulatorThread->setOutputQueue("NotifyQueue",pipeDemodNotify);
demodulatorThread->setOutputQueue("AudioDataOutput", pipeAudioData); demodulatorThread->setOutputQueue("AudioDataOutput", pipeAudioData);
audioThread = new AudioThread();
audioThread->setInputQueue("AudioDataInput", pipeAudioData); audioThread->setInputQueue("AudioDataInput", pipeAudioData);
audioThread->setOutputQueue("NotifyQueue", pipeDemodNotify); audioThread->setOutputQueue("NotifyQueue", pipeDemodNotify);
currentDemodType = demodulatorPreThread->getParams().demodType;
} }
DemodulatorInstance::~DemodulatorInstance() { DemodulatorInstance::~DemodulatorInstance() {
#if ENABLE_DIGITAL_LAB
delete activeOutput;
#endif
delete audioThread; delete audioThread;
delete demodulatorThread; delete demodulatorThread;
delete demodulatorPreThread; delete demodulatorPreThread;
delete pipeIQInputData; delete pipeIQInputData;
delete pipeIQDemodData; delete pipeIQDemodData;
delete pipeDemodCommand;
delete pipeDemodNotify; delete pipeDemodNotify;
delete threadQueueControl; delete threadQueueControl;
delete pipeAudioData; delete pipeAudioData;
@ -67,17 +67,8 @@ void DemodulatorInstance::run() {
return; 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); t_Audio = new std::thread(&AudioThread::threadMain, audioThread);
#ifdef __APPLE__ // Already using pthreads, might as well do some custom init.. #ifdef __APPLE__ // Already using pthreads, might as well do some custom init..
pthread_attr_t attr; pthread_attr_t attr;
size_t size; size_t size;
@ -113,10 +104,6 @@ void DemodulatorInstance::updateLabel(long long freq) {
setLabel(newLabel.str()); setLabel(newLabel.str());
} }
DemodulatorThreadCommandQueue *DemodulatorInstance::getCommandQueue() {
return pipeDemodCommand;
}
void DemodulatorInstance::terminate() { void DemodulatorInstance::terminate() {
std::cout << "Terminating demodulator audio thread.." << std::endl; std::cout << "Terminating demodulator audio thread.." << std::endl;
audioThread->terminate(); audioThread->terminate();
@ -156,6 +143,11 @@ bool DemodulatorInstance::isTerminated() {
#else #else
t_Demod->join(); t_Demod->join();
delete t_Demod; delete t_Demod;
#endif
#if ENABLE_DIGITAL_LAB
if (activeOutput) {
closeOutput();
}
#endif #endif
demodTerminated = true; demodTerminated = true;
break; break;
@ -184,8 +176,18 @@ bool DemodulatorInstance::isActive() {
void DemodulatorInstance::setActive(bool state) { void DemodulatorInstance::setActive(bool state) {
if (active && !state) { if (active && !state) {
#if ENABLE_DIGITAL_LAB
if (activeOutput && !isTerminated()) {
activeOutput->Hide();
}
#endif
audioThread->setActive(state); audioThread->setActive(state);
} else if (!active && state) { } else if (!active && state) {
#if ENABLE_DIGITAL_LAB
if (activeOutput && getModemType() == "digital") {
activeOutput->Show();
}
#endif
audioThread->setActive(state); audioThread->setActive(state);
} }
if (!state) { if (!state) {
@ -225,6 +227,8 @@ float DemodulatorInstance::getSignalLevel() {
void DemodulatorInstance::setSquelchLevel(float signal_level_in) { void DemodulatorInstance::setSquelchLevel(float signal_level_in) {
demodulatorThread->setSquelchLevel(signal_level_in); demodulatorThread->setSquelchLevel(signal_level_in);
wxGetApp().getDemodMgr().setLastSquelchLevel(signal_level_in);
wxGetApp().getDemodMgr().setLastSquelchEnabled(true);
} }
float DemodulatorInstance::getSquelchLevel() { float DemodulatorInstance::getSquelchLevel() {
@ -254,35 +258,36 @@ int DemodulatorInstance::getOutputDevice() {
return currentOutputDevice; 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) { 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()); 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; demodulatorPreThread->setDemodType(demod_type_in);
if (!active) { int lastbw = 0;
checkBandwidth(); if (currentDemodType != "" && lastModemBandwidth.find(demod_type_in) != lastModemBandwidth.end()) {
demodulatorPreThread->setDemodType(currentDemodType); lastbw = lastModemBandwidth[demod_type_in];
} else if (demodulatorThread && threadQueueControl) { }
demodulatorPreThread->setDemodType(currentDemodType); if (!lastbw) {
lastbw = Modem::getModemDefaultSampleRate(demod_type_in);
}
if (lastbw) {
setBandwidth(lastbw);
}
} }
} }
std::string DemodulatorInstance::getDemodulatorType() { std::string DemodulatorInstance::getDemodulatorType() {
return currentDemodType; return demodulatorPreThread->getDemodType();
} }
void DemodulatorInstance::setDemodulatorLock(bool demod_lock_in) { void DemodulatorInstance::setDemodulatorLock(bool demod_lock_in) {
@ -302,101 +307,50 @@ int DemodulatorInstance::getDemodulatorLock() {
return 0; 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) { void DemodulatorInstance::setBandwidth(int bw) {
if (currentDemodType == "I/Q") { demodulatorPreThread->setBandwidth(bw);
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);
}
} }
int DemodulatorInstance::getBandwidth() { int DemodulatorInstance::getBandwidth() {
if (!currentBandwidth) { return demodulatorPreThread->getBandwidth();
currentBandwidth = demodulatorPreThread->getParams().bandwidth;
}
return currentBandwidth;
} }
void DemodulatorInstance::setFrequency(long long freq) { void DemodulatorInstance::setFrequency(long long freq) {
if ((freq - getBandwidth() / 2) <= 0) { if ((freq - getBandwidth() / 2) <= 0) {
freq = getBandwidth() / 2; freq = getBandwidth() / 2;
} }
if (!active) {
currentFrequency = freq; demodulatorPreThread->setFrequency(freq);
demodulatorPreThread->getParams().frequency = currentFrequency; #if ENABLE_DIGITAL_LAB
} else if (demodulatorPreThread && pipeDemodCommand) { if (activeOutput) {
DemodulatorThreadCommand command; if (isModemInitialized() && getModemType() == "digital") {
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY; ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)getOutput();
currentFrequency = freq; outp->setTitle(getDemodulatorType() + ": " + frequencyToStr(getFrequency()));
command.llong_value = freq; }
pipeDemodCommand->push(command);
} }
#endif
} }
long long DemodulatorInstance::getFrequency() { long long DemodulatorInstance::getFrequency() {
if (!currentFrequency) { return demodulatorPreThread->getFrequency();
currentFrequency = demodulatorPreThread->getParams().frequency;
}
return currentFrequency;
} }
void DemodulatorInstance::setAudioSampleRate(int sampleRate) { void DemodulatorInstance::setAudioSampleRate(int sampleRate) {
if (terminated) { demodulatorPreThread->setSampleRate(sampleRate);
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);
}
} }
int DemodulatorInstance::getAudioSampleRate() { int DemodulatorInstance::getAudioSampleRate() {
if (!currentAudioSampleRate) { if (!audioThread) {
currentAudioSampleRate = audioThread->getSampleRate(); return 0;
} }
return currentAudioSampleRate; return audioThread->getSampleRate();
} }
void DemodulatorInstance::setGain(float gain_in) { void DemodulatorInstance::setGain(float gain_in) {
currentAudioGain = gain_in; currentAudioGain = gain_in;
audioThread->setGain(gain_in); audioThread->setGain(gain_in);
wxGetApp().getDemodMgr().setLastGain(gain_in);
} }
float DemodulatorInstance::getGain() { float DemodulatorInstance::getGain() {
@ -426,8 +380,91 @@ bool DemodulatorInstance::isMuted() {
void DemodulatorInstance::setMuted(bool muted) { void DemodulatorInstance::setMuted(bool muted) {
this->muted = muted; this->muted = muted;
demodulatorThread->setMuted(muted); demodulatorThread->setMuted(muted);
wxGetApp().getDemodMgr().setLastMuted(muted);
} }
DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() { DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() {
return pipeIQInputData; 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

View File

@ -10,6 +10,10 @@
#include "ModemDigital.h" #include "ModemDigital.h"
#include "ModemAnalog.h" #include "ModemAnalog.h"
#if ENABLE_DIGITAL_LAB
#include "DigitalConsole.h"
#endif
class DemodulatorInstance { class DemodulatorInstance {
public: public:
@ -58,9 +62,6 @@ public:
void setDemodulatorLock(bool demod_lock_in); void setDemodulatorLock(bool demod_lock_in);
int getDemodulatorLock(); int getDemodulatorLock();
void setDemodulatorCons(int demod_cons_in);
int getDemodulatorCons();
void setBandwidth(int bw); void setBandwidth(int bw);
int getBandwidth(); int getBandwidth();
@ -73,7 +74,7 @@ public:
void setAudioSampleRate(int sampleRate); void setAudioSampleRate(int sampleRate);
int getAudioSampleRate(); int getAudioSampleRate();
bool isFollow(); bool isFollow();
void setFollow(bool follow); void setFollow(bool follow);
@ -85,11 +86,27 @@ public:
DemodulatorThreadInputQueue *getIQInputDataPipe(); 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: protected:
DemodulatorThreadInputQueue* pipeIQInputData; DemodulatorThreadInputQueue* pipeIQInputData;
DemodulatorThreadPostInputQueue* pipeIQDemodData; DemodulatorThreadPostInputQueue* pipeIQDemodData;
AudioThreadInputQueue *pipeAudioData; AudioThreadInputQueue *pipeAudioData;
DemodulatorThreadCommandQueue* pipeDemodCommand;
DemodulatorThreadCommandQueue* pipeDemodNotify; DemodulatorThreadCommandQueue* pipeDemodNotify;
DemodulatorPreThread *demodulatorPreThread; DemodulatorPreThread *demodulatorPreThread;
DemodulatorThread *demodulatorThread; DemodulatorThread *demodulatorThread;
@ -97,8 +114,6 @@ protected:
private: private:
void checkBandwidth();
std::atomic<std::string *> label; // std::atomic<std::string *> label; //
std::atomic_bool terminated; // std::atomic_bool terminated; //
std::atomic_bool demodTerminated; // std::atomic_bool demodTerminated; //
@ -108,11 +123,12 @@ private:
std::atomic_bool squelch; std::atomic_bool squelch;
std::atomic_bool muted; std::atomic_bool muted;
std::atomic_llong currentFrequency;
std::atomic_int currentBandwidth;
std::string currentDemodType;
std::atomic_int currentOutputDevice; std::atomic_int currentOutputDevice;
std::atomic_int currentAudioSampleRate;
std::atomic<float> currentAudioGain; std::atomic<float> currentAudioGain;
std::atomic_bool follow, tracking; std::atomic_bool follow, tracking;
}; std::map<std::string, ModemSettings> lastModemSettings;
std::map<std::string, int> lastModemBandwidth;
#if ENABLE_DIGITAL_LAB
ModemDigitalOutput *activeOutput;
#endif
};

View File

@ -8,7 +8,6 @@
DemodulatorMgr::DemodulatorMgr() : DemodulatorMgr::DemodulatorMgr() :
activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType( activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType(
DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(-100), lastGain(1.0), lastMuted(false) { DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(-100), lastGain(1.0), lastMuted(false) {
} }
DemodulatorMgr::~DemodulatorMgr() { DemodulatorMgr::~DemodulatorMgr() {
@ -88,6 +87,7 @@ void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool tempo
if (!temporary) { if (!temporary) {
if (activeDemodulator != NULL) { if (activeDemodulator != NULL) {
lastActiveDemodulator = activeDemodulator; lastActiveDemodulator = activeDemodulator;
updateLastState();
} else { } else {
lastActiveDemodulator = demod; lastActiveDemodulator = demod;
} }
@ -121,8 +121,6 @@ DemodulatorInstance *DemodulatorMgr::getActiveDemodulator() {
} }
DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() { DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() {
updateLastState();
return lastActiveDemodulator; return lastActiveDemodulator;
} }
@ -162,10 +160,10 @@ void DemodulatorMgr::updateLastState() {
lastBandwidth = lastActiveDemodulator->getBandwidth(); lastBandwidth = lastActiveDemodulator->getBandwidth();
lastDemodType = lastActiveDemodulator->getDemodulatorType(); lastDemodType = lastActiveDemodulator->getDemodulatorType();
lastDemodLock = lastActiveDemodulator->getDemodulatorLock(); lastDemodLock = lastActiveDemodulator->getDemodulatorLock();
lastDemodCons = lastActiveDemodulator->getDemodulatorCons();
lastSquelchEnabled = lastActiveDemodulator->isSquelchEnabled(); lastSquelchEnabled = lastActiveDemodulator->isSquelchEnabled();
lastSquelch = lastActiveDemodulator->getSquelchLevel(); lastSquelch = lastActiveDemodulator->getSquelchLevel();
lastGain = lastActiveDemodulator->getGain(); lastGain = lastActiveDemodulator->getGain();
lastModemSettings[lastDemodType] = lastActiveDemodulator->readModemSettings();
} }
} }
@ -175,8 +173,8 @@ int DemodulatorMgr::getLastBandwidth() const {
} }
void DemodulatorMgr::setLastBandwidth(int lastBandwidth) { void DemodulatorMgr::setLastBandwidth(int lastBandwidth) {
if (lastBandwidth < 1500) { if (lastBandwidth < MIN_BANDWIDTH) {
lastBandwidth = 1500; lastBandwidth = MIN_BANDWIDTH;
} else if (lastBandwidth > wxGetApp().getSampleRate()) { } else if (lastBandwidth > wxGetApp().getSampleRate()) {
lastBandwidth = wxGetApp().getSampleRate(); lastBandwidth = wxGetApp().getSampleRate();
} }
@ -191,14 +189,6 @@ void DemodulatorMgr::setLastDemodulatorType(std::string lastDemodType) {
this->lastDemodType = lastDemodType; this->lastDemodType = lastDemodType;
} }
int DemodulatorMgr::getLastDemodulatorCons() const {
return lastDemodCons;
}
void DemodulatorMgr::setLastDemodulatorCons(int lastDemodCons) {
this->lastDemodCons = lastDemodCons;
}
float DemodulatorMgr::getLastGain() const { float DemodulatorMgr::getLastGain() const {
return lastGain; return lastGain;
} }
@ -231,3 +221,10 @@ void DemodulatorMgr::setLastMuted(bool lastMuted) {
this->lastMuted = lastMuted; this->lastMuted = lastMuted;
} }
ModemSettings DemodulatorMgr::getLastModemSettings(std::string modemType) {
return lastModemSettings[modemType];
}
void DemodulatorMgr::setLastModemSettings(std::string modemType, ModemSettings settings) {
lastModemSettings[modemType] = settings;
}

View File

@ -27,9 +27,6 @@ public:
std::string getLastDemodulatorType() const; std::string getLastDemodulatorType() const;
void setLastDemodulatorType(std::string lastDemodType); void setLastDemodulatorType(std::string lastDemodType);
int getLastDemodulatorCons() const;
void setLastDemodulatorCons(int lastDemodCons);
float getLastGain() const; float getLastGain() const;
void setLastGain(float lastGain); void setLastGain(float lastGain);
@ -43,9 +40,13 @@ public:
bool isLastMuted() const; bool isLastMuted() const;
void setLastMuted(bool lastMuted); void setLastMuted(bool lastMuted);
ModemSettings getLastModemSettings(std::string);
void setLastModemSettings(std::string, ModemSettings);
void updateLastState();
private: private:
void garbageCollect(); void garbageCollect();
void updateLastState();
std::vector<DemodulatorInstance *> demods; std::vector<DemodulatorInstance *> demods;
std::vector<DemodulatorInstance *> demods_deleted; std::vector<DemodulatorInstance *> demods_deleted;
@ -56,9 +57,10 @@ private:
int lastBandwidth; int lastBandwidth;
std::string lastDemodType; std::string lastDemodType;
bool lastDemodLock; bool lastDemodLock;
int lastDemodCons;
bool lastSquelchEnabled; bool lastSquelchEnabled;
float lastSquelch; float lastSquelch;
float lastGain; float lastGain;
bool lastMuted; bool lastMuted;
std::map<std::string, ModemSettings> lastModemSettings;
}; };

View File

@ -7,10 +7,12 @@
#include "DemodulatorPreThread.h" #include "DemodulatorPreThread.h"
#include "CubicSDR.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); initialized.store(false);
this->parent = parent;
freqShifter = nco_crcf_create(LIQUID_VCO); freqShifter = nco_crcf_create(LIQUID_VCO);
shiftFrequency = 0; shiftFrequency = 0;
@ -21,18 +23,21 @@ DemodulatorPreThread::DemodulatorPreThread() : IOThread(), iqResampler(NULL), iq
workerThread = new DemodulatorWorkerThread(); workerThread = new DemodulatorWorkerThread();
workerThread->setInputQueue("WorkerCommandQueue",workerQueue); workerThread->setInputQueue("WorkerCommandQueue",workerQueue);
workerThread->setOutputQueue("WorkerResultQueue",workerResults); 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() { bool DemodulatorPreThread::isInitialized() {
iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate; return initialized.load();
float As = 60.0f; // stop-band attenuation [dB]
iqResampler = msresamp_crcf_create(iqResampleRatio, As);
initialized.store(true);
lastParams = params;
} }
DemodulatorPreThread::~DemodulatorPreThread() { DemodulatorPreThread::~DemodulatorPreThread() {
@ -46,10 +51,6 @@ void DemodulatorPreThread::run() {
pthread_setschedparam(tID, SCHED_FIFO, &prio); pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif #endif
if (!initialized) {
initialize();
}
std::cout << "Demodulator preprocessor thread started.." << std::endl; std::cout << "Demodulator preprocessor thread started.." << std::endl;
ReBuffer<DemodulatorThreadPostIQData> buffers; ReBuffer<DemodulatorThreadPostIQData> buffers;
@ -57,87 +58,103 @@ void DemodulatorPreThread::run() {
iqInputQueue = (DemodulatorThreadInputQueue*)getInputQueue("IQDataInput"); iqInputQueue = (DemodulatorThreadInputQueue*)getInputQueue("IQDataInput");
iqOutputQueue = (DemodulatorThreadPostInputQueue*)getOutputQueue("IQDataOutput"); iqOutputQueue = (DemodulatorThreadPostInputQueue*)getOutputQueue("IQDataOutput");
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue"); threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
commandQueue = ( DemodulatorThreadCommandQueue*)getInputQueue("CommandQueue");
std::vector<liquid_float_complex> in_buf_data; std::vector<liquid_float_complex> in_buf_data;
std::vector<liquid_float_complex> out_buf_data; std::vector<liquid_float_complex> out_buf_data;
setDemodType(params.demodType);
t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread); t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread);
while (!terminated) { while (!terminated) {
DemodulatorThreadIQData *inp; DemodulatorThreadIQData *inp;
iqInputQueue->pop(inp); iqInputQueue->pop(inp);
bool bandwidthChanged = false; if (frequencyChanged.load()) {
bool rateChanged = false; currentFrequency = newFrequency;
DemodulatorThreadParameters tempParams = params; frequencyChanged.store(false);
}
if (!commandQueue->empty()) {
while (!commandQueue->empty()) { if (inp->sampleRate != currentSampleRate) {
DemodulatorThreadCommand command; newSampleRate = inp->sampleRate;
commandQueue->pop(command); if (newSampleRate) {
switch (command.cmd) { sampleRateChanged.store(true);
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 (inp->sampleRate != tempParams.sampleRate && inp->sampleRate) { if (!newAudioSampleRate) {
tempParams.sampleRate = inp->sampleRate; newAudioSampleRate = parent->getAudioSampleRate();
rateChanged = true; 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); DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS);
command.sampleRate = tempParams.sampleRate; command.frequency = newFrequency;
command.audioSampleRate = tempParams.audioSampleRate; command.sampleRate = newSampleRate;
command.bandwidth = tempParams.bandwidth; command.bandwidth = newBandwidth;
command.frequency = tempParams.frequency; command.audioSampleRate = newAudioSampleRate;
bandwidthChanged.store(false);
sampleRateChanged.store(false);
audioSampleRateChanged.store(false);
modemSettingsBuffered.clear();
workerQueue->push(command); workerQueue->push(command);
} }
if (!initialized) {
inp->decRefCount();
continue;
}
// Requested frequency is not center, shift it into the center! // Requested frequency is not center, shift it into the center!
if ((params.frequency - inp->frequency) != shiftFrequency || rateChanged) { if ((currentFrequency - inp->frequency) != shiftFrequency) {
shiftFrequency = params.frequency - inp->frequency; shiftFrequency = currentFrequency - inp->frequency;
if (abs(shiftFrequency) <= (int) ((double) (inp->sampleRate / 2) * 1.5)) { 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))); 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(); inp->decRefCount();
continue; continue;
} }
// std::lock_guard < std::mutex > lock(inp->m_mutex); // std::lock_guard < std::mutex > lock(inp->m_mutex);
std::vector<liquid_float_complex> *data = &inp->data; std::vector<liquid_float_complex> *data = &inp->data;
if (data->size() && (inp->sampleRate == params.sampleRate)) { if (data->size() && (inp->sampleRate == currentSampleRate) && cModem && cModemKit) {
int bufSize = data->size(); int bufSize = data->size();
if (in_buf_data.size() != bufSize) { if (in_buf_data.size() != bufSize) {
@ -183,10 +200,11 @@ void DemodulatorPreThread::run() {
resamp->setRefCount(1); resamp->setRefCount(1);
resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten); resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);
resamp->modemType = demodType; resamp->modemType = cModem->getType();
resamp->modemName = cModem->getName();
resamp->modem = cModem; resamp->modem = cModem;
resamp->modemKit = cModemKit; resamp->modemKit = cModemKit;
resamp->sampleRate = params.bandwidth; resamp->sampleRate = currentBandwidth;
iqOutputQueue->push(resamp); iqOutputQueue->push(resamp);
} }
@ -200,7 +218,6 @@ void DemodulatorPreThread::run() {
switch (result.cmd) { switch (result.cmd) {
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS: case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
if (result.iqResampler) { if (result.iqResampler) {
if (iqResampler) { if (iqResampler) {
msresamp_crcf_destroy(iqResampler); msresamp_crcf_destroy(iqResampler);
@ -211,31 +228,46 @@ void DemodulatorPreThread::run() {
if (result.modem != nullptr) { if (result.modem != nullptr) {
cModem = result.modem; cModem = result.modem;
#if ENABLE_DIGITAL_LAB
if (cModem->getType() == "digital") {
ModemDigital *mDigi = (ModemDigital *)cModem;
mDigi->setOutput(parent->getOutput());
}
#endif
} }
if (result.modemKit != nullptr) { if (result.modemKit != nullptr) {
cModemKit = result.modemKit; cModemKit = result.modemKit;
currentAudioSampleRate = cModemKit->audioSampleRate;
} }
if (result.bandwidth) { if (result.bandwidth) {
params.bandwidth = result.bandwidth; currentBandwidth = result.bandwidth;
} }
if (result.sampleRate) { if (result.sampleRate) {
params.sampleRate = result.sampleRate; currentSampleRate = result.sampleRate;
} }
if (result.modemType != "") { if (result.modemName != "") {
demodType = result.modemType; demodType = result.modemName;
params.demodType = result.modemType;
demodTypeChanged.store(false); demodTypeChanged.store(false);
} }
shiftFrequency = inp->frequency-1;
initialized.store(cModem != nullptr);
break; break;
default: default:
break; break;
} }
} }
} }
if ((cModem != nullptr) && modemSettingsChanged.load()) {
cModem->writeSettings(modemSettingsBuffered);
modemSettingsBuffered.clear();
modemSettingsChanged.store(false);
}
} }
buffers.purge(); buffers.purge();
@ -246,21 +278,8 @@ void DemodulatorPreThread::run() {
std::cout << "Demodulator preprocessor thread done." << std::endl; std::cout << "Demodulator preprocessor thread done." << std::endl;
} }
DemodulatorThreadParameters &DemodulatorPreThread::getParams() {
return params;
}
void DemodulatorPreThread::setParams(DemodulatorThreadParameters &params_in) {
params = params_in;
}
void DemodulatorPreThread::setDemodType(std::string demodType) { void DemodulatorPreThread::setDemodType(std::string demodType) {
this->newDemodType = demodType; 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);
demodTypeChanged.store(true); demodTypeChanged.store(true);
} }
@ -271,6 +290,51 @@ std::string DemodulatorPreThread::getDemodType() {
return demodType; 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() { void DemodulatorPreThread::terminate() {
terminated = true; terminated = true;
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
@ -285,7 +349,6 @@ void DemodulatorPreThread::terminate() {
delete workerQueue; delete workerQueue;
} }
Modem *DemodulatorPreThread::getModem() { Modem *DemodulatorPreThread::getModem() {
return cModem; return cModem;
} }
@ -293,3 +356,31 @@ Modem *DemodulatorPreThread::getModem() {
ModemKit *DemodulatorPreThread::getModemKit() { ModemKit *DemodulatorPreThread::getModemKit() {
return cModemKit; 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);
}

View File

@ -7,37 +7,62 @@
#include "DemodDefs.h" #include "DemodDefs.h"
#include "DemodulatorWorkerThread.h" #include "DemodulatorWorkerThread.h"
class DemodulatorInstance;
class DemodulatorPreThread : public IOThread { class DemodulatorPreThread : public IOThread {
public: public:
DemodulatorPreThread(); DemodulatorPreThread(DemodulatorInstance *parent);
~DemodulatorPreThread(); ~DemodulatorPreThread();
void run(); void run();
DemodulatorThreadParameters &getParams();
void setParams(DemodulatorThreadParameters &params_in);
void setDemodType(std::string demodType); void setDemodType(std::string demodType);
std::string getDemodType(); 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(); void terminate();
Modem *getModem(); Modem *getModem();
ModemKit *getModemKit(); ModemKit *getModemKit();
std::string readModemSetting(std::string setting);
void writeModemSetting(std::string setting, std::string value);
ModemSettings readModemSettings();
void writeModemSettings(ModemSettings settings);
protected: protected:
DemodulatorInstance *parent;
msresamp_crcf iqResampler; msresamp_crcf iqResampler;
double iqResampleRatio; double iqResampleRatio;
std::vector<liquid_float_complex> resampledData; std::vector<liquid_float_complex> resampledData;
Modem *cModem; Modem *cModem;
ModemKit *cModemKit; ModemKit *cModemKit;
long long currentSampleRate, newSampleRate;
long long currentFrequency, newFrequency;
int currentBandwidth, newBandwidth;
int currentAudioSampleRate, newAudioSampleRate;
DemodulatorThreadParameters params; std::atomic_bool sampleRateChanged, frequencyChanged, bandwidthChanged, audioSampleRateChanged;
DemodulatorThreadParameters lastParams;
ModemSettings modemSettingsBuffered;
std::atomic_bool modemSettingsChanged;
nco_crcf freqShifter; nco_crcf freqShifter;
int shiftFrequency; int shiftFrequency;
@ -55,5 +80,4 @@ protected:
DemodulatorThreadInputQueue* iqInputQueue; DemodulatorThreadInputQueue* iqInputQueue;
DemodulatorThreadPostInputQueue* iqOutputQueue; DemodulatorThreadPostInputQueue* iqOutputQueue;
DemodulatorThreadCommandQueue* threadQueueNotify; DemodulatorThreadCommandQueue* threadQueueNotify;
DemodulatorThreadCommandQueue* commandQueue;
}; };

View File

@ -12,7 +12,7 @@
#include <pthread.h> #include <pthread.h>
#endif #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; demodInstance = parent;
muted.store(false); muted.store(false);
@ -73,8 +73,6 @@ void DemodulatorThread::run() {
iqInputQueue->pop(inp); iqInputQueue->pop(inp);
// std::lock_guard < std::mutex > lock(inp->m_mutex); // std::lock_guard < std::mutex > lock(inp->m_mutex);
audioSampleRate = demodInstance->getAudioSampleRate();
int bufSize = inp->data.size(); int bufSize = inp->data.size();
if (!bufSize) { if (!bufSize) {
@ -122,15 +120,22 @@ void DemodulatorThread::run() {
AudioThreadInput *ati = NULL; AudioThreadInput *ati = NULL;
ModemAnalog *modemAnalog = (cModem->getType() == "analog")?((ModemAnalog *)cModem):nullptr; 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) { if (modemAnalog != nullptr) {
ati = outputBuffers.getBuffer(); 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->inputRate = inp->sampleRate;
ati->setRefCount(1); ati->setRefCount(1);
} }
cModem->demodulate(cModemKit, &modemData, ati); cModem->demodulate(cModemKit, &modemData, ati);
if (currentSignalLevel > signalLevel) { if (currentSignalLevel > signalLevel) {
@ -162,7 +167,15 @@ void DemodulatorThread::run() {
ati_vis->inputRate = inp->sampleRate; ati_vis->inputRate = inp->sampleRate;
int num_vis = DEMOD_VIS_SIZE; 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; ati_vis->channels = 2;
int stereoSize = ati->data.size(); int stereoSize = ati->data.size();
if (stereoSize > DEMOD_VIS_SIZE * 2) { if (stereoSize > DEMOD_VIS_SIZE * 2) {
@ -171,25 +184,26 @@ void DemodulatorThread::run() {
ati_vis->data.resize(stereoSize); ati_vis->data.resize(stereoSize);
if (inp->modemType == "I/Q") { if (inp->modemName == "I/Q") {
for (int i = 0; i < stereoSize / 2; i++) { for (int i = 0; i < stereoSize / 2; i++) {
ati_vis->data[i] = (*inputData)[i].real * 0.75; ati_vis->data[i] = (*inputData)[i].real * 0.75;
ati_vis->data[i + stereoSize / 2] = (*inputData)[i].imag * 0.75; ati_vis->data[i + stereoSize / 2] = (*inputData)[i].imag * 0.75;
} }
} else { } else {
for (int i = 0; i < stereoSize / 2; i++) { for (int i = 0; i < stereoSize / 2; i++) {
ati_vis->inputRate = audioSampleRate; ati_vis->inputRate = cModemKit->audioSampleRate;
ati_vis->sampleRate = 36000; ati_vis->sampleRate = 36000;
ati_vis->data[i] = ati->data[i * 2]; ati_vis->data[i] = ati->data[i * 2];
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1]; ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
} }
} }
ati_vis->type = 1;
} else { } else {
int numAudioWritten = ati->data.size(); int numAudioWritten = ati->data.size();
ati_vis->channels = 1; ati_vis->channels = 1;
std::vector<float> *demodOutData = (modemAnalog != nullptr)?modemAnalog->getDemodOutputData():nullptr; std::vector<float> *demodOutData = (modemAnalog != nullptr)?modemAnalog->getDemodOutputData():nullptr;
if ((numAudioWritten > bufSize) || (demodOutData == nullptr)) { if ((numAudioWritten > bufSize) || (demodOutData == nullptr)) {
ati_vis->inputRate = audioSampleRate; ati_vis->inputRate = cModemKit->audioSampleRate;
if (num_vis > numAudioWritten) { if (num_vis > numAudioWritten) {
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->data.assign(demodOutData->begin(), demodOutData->begin() + num_vis);
} }
ati_vis->type = 0;
} }
audioVisOutputQueue->push(ati_vis); audioVisOutputQueue->push(ati_vis);

View File

@ -43,7 +43,6 @@ protected:
ReBuffer<AudioThreadInput> outputBuffers; ReBuffer<AudioThreadInput> outputBuffers;
std::atomic_bool muted; std::atomic_bool muted;
int audioSampleRate;
std::atomic<float> squelchLevel; std::atomic<float> squelchLevel;
std::atomic<float> signalLevel; std::atomic<float> signalLevel;

View File

@ -1,5 +1,6 @@
#include "DemodulatorWorkerThread.h" #include "DemodulatorWorkerThread.h"
#include "CubicSDRDefs.h" #include "CubicSDRDefs.h"
#include "CubicSDR.h"
#include <vector> #include <vector>
DemodulatorWorkerThread::DemodulatorWorkerThread() : IOThread(), DemodulatorWorkerThread::DemodulatorWorkerThread() : IOThread(),
@ -26,63 +27,72 @@ void DemodulatorWorkerThread::run() {
while (!done) { while (!done) {
commandQueue->pop(command); commandQueue->pop(command);
switch (command.cmd) { switch (command.cmd) {
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS: case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS:
filterChanged = true; filterChanged = true;
filterCommand = command; filterCommand = command;
break; break;
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD: case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD:
makeDemod = true; makeDemod = true;
demodCommand = command; demodCommand = command;
break; break;
default: default:
break; break;
} }
done = commandQueue->empty(); done = commandQueue->empty();
} }
if ((makeDemod || filterChanged) && !terminated) { if ((makeDemod || filterChanged) && !terminated) {
DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS); DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS);
float As = 60.0f; // stop-band attenuation [dB]
if (filterCommand.sampleRate) {
if (filterCommand.sampleRate && filterCommand.bandwidth) { result.sampleRate = filterCommand.sampleRate;
result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate;
result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As);
} }
if (makeDemod) { if (makeDemod) {
cModem = Modem::makeModem(demodCommand.demodType); 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; result.modem = cModem;
if (makeDemod && demodCommand.bandwidth && demodCommand.audioSampleRate) { if (makeDemod && demodCommand.bandwidth && demodCommand.audioSampleRate) {
if (cModem != nullptr) { 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 { } else {
cModemKit = nullptr; cModemKit = nullptr;
} }
} else if (filterChanged && filterCommand.bandwidth && filterCommand.audioSampleRate) { } else if (filterChanged && filterCommand.bandwidth && filterCommand.audioSampleRate) {
if (cModem != nullptr) { 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 { } else {
cModemKit = nullptr; cModemKit = nullptr;
} }
} else if (makeDemod) { } else if (makeDemod) {
cModemKit = nullptr; 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; result.modemKit = cModemKit;
if (filterCommand.bandwidth) {
result.bandwidth = filterCommand.bandwidth;
}
if (filterCommand.sampleRate) {
result.sampleRate = filterCommand.sampleRate;
}
result.modemType = cModemType; result.modemType = cModemType;
result.modemName = cModemName;
resultQueue->push(result); resultQueue->push(result);
} }

View File

@ -37,6 +37,7 @@ public:
Modem *modem; Modem *modem;
ModemKit *modemKit; ModemKit *modemKit;
std::string modemType; std::string modemType;
std::string modemName;
}; };
class DemodulatorWorkerThreadCommand { class DemodulatorWorkerThreadCommand {
@ -62,6 +63,7 @@ public:
unsigned int bandwidth; unsigned int bandwidth;
unsigned int audioSampleRate; unsigned int audioSampleRate;
std::string demodType; std::string demodType;
ModemSettings settings;
}; };
typedef ThreadQueue<DemodulatorWorkerThreadCommand> DemodulatorThreadWorkerCommandQueue; typedef ThreadQueue<DemodulatorWorkerThreadCommand> DemodulatorThreadWorkerCommandQueue;
@ -92,4 +94,5 @@ protected:
Modem *cModem; Modem *cModem;
ModemKit *cModemKit; ModemKit *cModemKit;
std::string cModemType; std::string cModemType;
std::string cModemName;
}; };

View File

@ -0,0 +1,138 @@
#include "DigitalConsole.h"
#include "CubicSDR.h"
#include <iomanip>
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);
}

View File

@ -0,0 +1,485 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="13" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">DigitalConsoleFrame</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="internationalize">0</property>
<property name="name">DigitalConsole</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Frame" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">DigitalConsoleFrame</property>
<property name="pos"></property>
<property name="size">441,394</property>
<property name="style">wxCAPTION|wxFRAME_FLOAT_ON_PARENT|wxMAXIMIZE|wxMAXIMIZE_BOX|wxMINIMIZE|wxMINIMIZE_BOX|wxRESIZE_BORDER</property>
<property name="subclass">; </property>
<property name="title">Digital Output</property>
<property name="tooltip"></property>
<property name="window_extra_style">wxWS_EX_PROCESS_UI_UPDATES</property>
<property name="window_name"></property>
<property name="window_style">wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL</property>
<property name="xrc_skip_sizer">1</property>
<event name="OnActivate"></event>
<event name="OnActivateApp"></event>
<event name="OnAuiFindManager"></event>
<event name="OnAuiPaneButton"></event>
<event name="OnAuiPaneClose"></event>
<event name="OnAuiPaneMaximize"></event>
<event name="OnAuiPaneRestore"></event>
<event name="OnAuiRender"></event>
<event name="OnChar"></event>
<event name="OnClose">OnClose</event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnHibernate"></event>
<event name="OnIconize"></event>
<event name="OnIdle"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">mainSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">dataViewSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font">,90,90,-1,76,0</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_dataView</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxTE_CHARWRAP|wxTE_MULTILINE|wxTE_NOHIDESEL|wxTE_READONLY|wxTE_WORDWRAP</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style">wxWS_EX_PROCESS_UI_UPDATES</property>
<property name="window_name"></property>
<property name="window_style">wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE|wxNO_BORDER|wxSIMPLE_BORDER|wxVSCROLL</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnText"></event>
<event name="OnTextEnter"></event>
<event name="OnTextMaxLen"></event>
<event name="OnTextURL"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">buttonSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Clear</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_clearButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnClear</event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Copy</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_copyButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnCopy</event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Stop</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_pauseButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnPause</event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
</object>
<object class="wxTimer" expanded="1">
<property name="enabled">1</property>
<property name="id">wxID_ANY</property>
<property name="name">m_refreshTimer</property>
<property name="oneshot">0</property>
<property name="period">250</property>
<property name="permission">protected</property>
<event name="OnTimer">DoRefresh</event>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,61 @@
#pragma once
#include <map>
#include <vector>
#include <sstream>
#include <ostream>
#include <mutex>
#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<bool> streamWritten;
std::atomic<bool> 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<bool> streamWritten;
std::string dialogTitle;
};

View File

@ -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 ) );
}

View File

@ -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 <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/timer.h>
#include <wx/frame.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// 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__

View File

@ -3,7 +3,6 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "SDRDevices.h"
#include "SDRDevicesForm.h" #include "SDRDevicesForm.h"
#include "SoapySDRThread.h" #include "SoapySDRThread.h"
#include "SDREnumerator.h" #include "SDREnumerator.h"

View File

@ -1,21 +1,33 @@
#include "Modem.h" #include "Modem.h"
#include "CubicSDR.h"
ModemFactoryList Modem::modemFactories; ModemFactoryList Modem::modemFactories;
void Modem::addModemFactory(Modem *factorySingle) { //! Create an empty range (0.0, 0.0)
modemFactories[factorySingle->getName()] = factorySingle; ModemRange::ModemRange(void) {
_min = 0;
_max = 0;
} }
ModemFactoryList Modem::getFactories() { //! Create a min/max range
return modemFactories; ModemRange::ModemRange(const double minimum, const double maximum) {
_min = minimum;
_max = maximum;
} }
Modem *Modem::makeModem(std::string modemType) { //! Get the range minimum
if (modemFactories.find(modemType) != modemFactories.end()) { double ModemRange::minimum(void) const {
return modemFactories[modemType]->factory(); return _min;
} }
//! Get the range maximum
double ModemRange::maximum(void) const {
return _max;
}
ModemArgInfo::ModemArgInfo(void) {
return nullptr;
} }
Modem::Modem() { Modem::Modem() {
@ -25,3 +37,72 @@ Modem::Modem() {
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);
}

View File

@ -4,6 +4,9 @@
#include "IOThread.h" #include "IOThread.h"
#include "AudioThread.h" #include "AudioThread.h"
#include <cmath> #include <cmath>
#include <atomic>
#define MIN_BANDWIDTH 500
class ModemKit { class ModemKit {
public: 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<std::string> 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<std::string> optionNames;
};
typedef std::vector<ModemArgInfo> ModemArgInfoList;
class Modem; class Modem;
typedef std::map<std::string,Modem *> ModemFactoryList; typedef std::map<std::string,Modem *> ModemFactoryList;
typedef std::map<std::string, std::string> ModemSettings;
class Modem { class Modem {
public: public:
static void addModemFactory(Modem *factorySingle); static void addModemFactory(Modem *factorySingle);
static ModemFactoryList getFactories(); 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 getType() = 0;
virtual std::string getName() = 0; virtual std::string getName() = 0;
virtual Modem *factory() = 0; virtual Modem *factory() = 0;
Modem(); Modem();
virtual ~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 ModemKit *buildKit(long long sampleRate, int audioSampleRate) = 0;
virtual void disposeKit(ModemKit *kit) = 0; virtual void disposeKit(ModemKit *kit) = 0;
virtual void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) = 0; virtual void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) = 0;
bool shouldRebuildKit();
void rebuildKit();
void clearRebuildKit();
private: private:
static ModemFactoryList modemFactories; static ModemFactoryList modemFactories;
std::atomic_bool refreshKit;
}; };

View File

@ -8,6 +8,13 @@ std::string ModemAnalog::getType() {
return "analog"; 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) { ModemKit *ModemAnalog::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitAnalog *akit = new ModemKitAnalog; ModemKitAnalog *akit = new ModemKitAnalog;

View File

@ -16,12 +16,13 @@ class ModemAnalog : public Modem {
public: public:
ModemAnalog(); ModemAnalog();
std::string getType(); std::string getType();
ModemKit *buildKit(long long sampleRate, int audioSampleRate); virtual int checkSampleRate(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit); virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input); virtual void disposeKit(ModemKit *kit);
void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain); virtual void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input);
std::vector<float> *getDemodOutputData(); virtual void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain);
std::vector<float> *getResampledOutputData(); virtual std::vector<float> *getDemodOutputData();
virtual std::vector<float> *getResampledOutputData();
protected: protected:
int bufSize; int bufSize;
std::vector<float> demodOutputData; std::vector<float> demodOutputData;

View File

@ -1,13 +1,31 @@
#include "ModemDigital.h" #include "ModemDigital.h"
ModemDigital::ModemDigital() {
ModemDigitalOutput::ModemDigitalOutput() {
}
ModemDigital::ModemDigital() {
#if ENABLE_DIGITAL_LAB
digitalOut = nullptr;
#endif
}
ModemDigitalOutput::~ModemDigitalOutput() {
} }
std::string ModemDigital::getType() { std::string ModemDigital::getType() {
return "digital"; 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) { ModemKit *ModemDigital::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitDigital *dkit = new ModemKitDigital; ModemKitDigital *dkit = new ModemKitDigital;
@ -31,24 +49,10 @@ int ModemDigital::getDemodulatorLock() {
return currentDemodLock.load(); 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) { void ModemDigital::updateDemodulatorLock(modem mod, float sensitivity) {
setDemodulatorLock(modem_get_demodulator_evm(mod) <= 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) { void ModemDigital::digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input) {
int bufSize = input->data.size(); int bufSize = input->data.size();
@ -58,14 +62,21 @@ void ModemDigital::digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *in
} }
demodOutputDataDigital.resize(bufSize); demodOutputDataDigital.resize(bufSize);
} }
if (demodulatorCons.load() != currentDemodCons.load()) {
updateDemodulatorCons(demodulatorCons.load());
currentDemodLock.store(false);
}
} }
void ModemDigital::digitalFinish(ModemKitDigital *kit, modem mod) { 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

View File

@ -1,5 +1,10 @@
#pragma once #pragma once
#include "Modem.h" #include "Modem.h"
#include <map>
#include <vector>
#include <sstream>
#include <ostream>
#include <mutex>
class ModemKitDigital : public ModemKit { class ModemKitDigital : public ModemKit {
public: 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 { class ModemDigital : public Modem {
public: public:
ModemDigital(); ModemDigital();
std::string getType(); std::string getType();
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit); virtual int checkSampleRate(long long sampleRate, int audioSampleRate);
void digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input);
void digitalFinish(ModemKitDigital *kit, modem mod); 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 void setDemodulatorLock(bool demod_lock_in);
virtual int getDemodulatorLock(); 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); virtual void updateDemodulatorLock(modem mod, float sensitivity);
#if ENABLE_DIGITAL_LAB
void setOutput(ModemDigitalOutput *digitalOutput);
#endif
protected: protected:
std::vector<unsigned int> demodOutputDataDigital; std::vector<unsigned int> demodOutputDataDigital;
std::atomic_int demodulatorCons;
std::atomic_bool currentDemodLock; std::atomic_bool currentDemodLock;
std::atomic_int currentDemodCons; #if ENABLE_DIGITAL_LAB
ModemDigitalOutput *digitalOut;
// std::vector<unsigned int> demodOutputDataDigitalTest; std::stringstream outStream;
// std::vector<unsigned char> demodOutputSoftbits; #endif
// std::vector<unsigned char> demodOutputSoftbitsTest;
}; };

View File

@ -1,9 +1,13 @@
#include "ModemAM.h" #include "ModemAM.h"
ModemAM::ModemAM() { ModemAM::ModemAM() : ModemAnalog() {
demodAM = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0); demodAM = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
} }
ModemAM::~ModemAM() {
ampmodem_destroy(demodAM);
}
Modem *ModemAM::factory() { Modem *ModemAM::factory() {
return new ModemAM; return new ModemAM;
} }
@ -12,6 +16,10 @@ std::string ModemAM::getName() {
return "AM"; return "AM";
} }
int ModemAM::getDefaultSampleRate() {
return 6000;
}
void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *amkit = (ModemKitAnalog *)kit; ModemKitAnalog *amkit = (ModemKitAnalog *)kit;

View File

@ -5,8 +5,14 @@
class ModemAM : public ModemAnalog { class ModemAM : public ModemAnalog {
public: public:
ModemAM(); ModemAM();
~ModemAM();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int getDefaultSampleRate();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -1,9 +1,13 @@
#include "ModemDSB.h" #include "ModemDSB.h"
ModemDSB::ModemDSB() { ModemDSB::ModemDSB() : ModemAnalog() {
demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1); demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
} }
ModemDSB::~ModemDSB() {
ampmodem_destroy(demodAM_DSB);
}
Modem *ModemDSB::factory() { Modem *ModemDSB::factory() {
return new ModemDSB; return new ModemDSB;
} }
@ -12,6 +16,10 @@ std::string ModemDSB::getName() {
return "DSB"; return "DSB";
} }
int ModemDSB::getDefaultSampleRate() {
return 5400;
}
void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *amkit = (ModemKitAnalog *)kit; ModemKitAnalog *amkit = (ModemKitAnalog *)kit;

View File

@ -5,8 +5,14 @@
class ModemDSB : public ModemAnalog { class ModemDSB : public ModemAnalog {
public: public:
ModemDSB(); ModemDSB();
~ModemDSB();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int getDefaultSampleRate();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -1,9 +1,13 @@
#include "ModemFM.h" #include "ModemFM.h"
ModemFM::ModemFM() { ModemFM::ModemFM() : ModemAnalog() {
demodFM = freqdem_create(0.5); demodFM = freqdem_create(0.5);
} }
ModemFM::~ModemFM() {
freqdem_destroy(demodFM);
}
Modem *ModemFM::factory() { Modem *ModemFM::factory() {
return new ModemFM; return new ModemFM;
} }
@ -12,6 +16,10 @@ std::string ModemFM::getName() {
return "FM"; return "FM";
} }
int ModemFM::getDefaultSampleRate() {
return 200000;
}
void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *fmkit = (ModemKitAnalog *)kit; ModemKitAnalog *fmkit = (ModemKitAnalog *)kit;

View File

@ -5,11 +5,16 @@
class ModemFM : public ModemAnalog { class ModemFM : public ModemAnalog {
public: public:
ModemFM(); ModemFM();
~ModemFM();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int getDefaultSampleRate();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
freqdem demodFM; freqdem demodFM;
}; };

View File

@ -30,11 +30,27 @@ Modem *ModemFMStereo::factory() {
return new ModemFMStereo; 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) { ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitFMStereo *kit = new ModemKitFMStereo; ModemKitFMStereo *kit = new ModemKitFMStereo;
kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate); kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
kit->sampleRate = sampleRate;
kit->audioSampleRate = audioSampleRate;
float As = 60.0f; // stop-band attenuation [dB] float As = 60.0f; // stop-band attenuation [dB]
kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As); kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);

View File

@ -20,11 +20,18 @@ class ModemFMStereo : public Modem {
public: public:
ModemFMStereo(); ModemFMStereo();
~ModemFMStereo(); ~ModemFMStereo();
std::string getType(); std::string getType();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate();
ModemKit *buildKit(long long sampleRate, int audioSampleRate); ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit); void disposeKit(ModemKit *kit);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -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() { std::string ModemIQ::getType() {
return "analog"; return "analog";
} }
@ -21,10 +12,29 @@ std::string ModemIQ::getName() {
return "I/Q"; 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) { void ModemIQ::disposeKit(ModemKit *kit) {
delete 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) { void ModemIQ::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
int bufSize = input->data.size(); int bufSize = input->data.size();

View File

@ -4,11 +4,19 @@
class ModemIQ : public Modem { class ModemIQ : public Modem {
public: public:
ModemIQ(); ModemIQ();
std::string getType(); std::string getType();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate();
ModemKit *buildKit(long long sampleRate, int audioSampleRate); ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit); void disposeKit(ModemKit *kit);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -1,6 +1,6 @@
#include "ModemLSB.h" #include "ModemLSB.h"
ModemLSB::ModemLSB() { ModemLSB::ModemLSB() : ModemAnalog() {
// half band filter used for side-band elimination // half band filter used for side-band elimination
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f); ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1); demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
@ -19,6 +19,20 @@ ModemLSB::~ModemLSB() {
ampmodem_destroy(demodAM_LSB); 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) { void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *akit = (ModemKitAnalog *)kit; ModemKitAnalog *akit = (ModemKitAnalog *)kit;

View File

@ -1,13 +1,18 @@
#pragma once #pragma once
#include "Modem.h"
#include "ModemAnalog.h" #include "ModemAnalog.h"
class ModemLSB : public ModemAnalog { class ModemLSB : public ModemAnalog {
public: public:
ModemLSB(); ModemLSB();
~ModemLSB(); ~ModemLSB();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -1,6 +1,6 @@
#include "ModemUSB.h" #include "ModemUSB.h"
ModemUSB::ModemUSB() { ModemUSB::ModemUSB() : ModemAnalog() {
// half band filter used for side-band elimination // half band filter used for side-band elimination
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f); ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1); demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
@ -19,6 +19,20 @@ ModemUSB::~ModemUSB() {
ampmodem_destroy(demodAM_USB); 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) { void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *akit = (ModemKitAnalog *)kit; ModemKitAnalog *akit = (ModemKitAnalog *)kit;

View File

@ -5,8 +5,14 @@ class ModemUSB : public ModemAnalog {
public: public:
ModemUSB(); ModemUSB();
~ModemUSB(); ~ModemUSB();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -1,6 +1,6 @@
#include "ModemAPSK.h" #include "ModemAPSK.h"
ModemAPSK::ModemAPSK() { ModemAPSK::ModemAPSK() : ModemDigital() {
demodAPSK4 = modem_create(LIQUID_MODEM_APSK4); demodAPSK4 = modem_create(LIQUID_MODEM_APSK4);
demodAPSK8 = modem_create(LIQUID_MODEM_APSK8); demodAPSK8 = modem_create(LIQUID_MODEM_APSK8);
demodAPSK16 = modem_create(LIQUID_MODEM_APSK16); demodAPSK16 = modem_create(LIQUID_MODEM_APSK16);
@ -8,9 +8,8 @@ ModemAPSK::ModemAPSK() {
demodAPSK64 = modem_create(LIQUID_MODEM_APSK64); demodAPSK64 = modem_create(LIQUID_MODEM_APSK64);
demodAPSK128 = modem_create(LIQUID_MODEM_APSK128); demodAPSK128 = modem_create(LIQUID_MODEM_APSK128);
demodAPSK256 = modem_create(LIQUID_MODEM_APSK256); demodAPSK256 = modem_create(LIQUID_MODEM_APSK256);
demodulatorCons.store(4); demodAPSK = demodAPSK4;
currentDemodCons.store(0); cons = 4;
updateDemodulatorCons(4);
} }
Modem *ModemAPSK::factory() { Modem *ModemAPSK::factory() {
@ -31,46 +30,67 @@ std::string ModemAPSK::getName() {
return "APSK"; 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<std::string> 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) { void ModemAPSK::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) { this->cons = cons;
currentDemodCons = cons; switch (cons) {
switch (demodulatorCons.load()) { case 4:
case 2: demodAPSK = demodAPSK4;
demodAPSK = demodAPSK4; break;
updateDemodulatorCons(4); case 8:
break; demodAPSK = demodAPSK8;
case 4: break;
demodAPSK = demodAPSK4; case 16:
updateDemodulatorCons(4); demodAPSK = demodAPSK16;
break; break;
case 8: case 32:
demodAPSK = demodAPSK8; demodAPSK = demodAPSK32;
updateDemodulatorCons(8); break;
break; case 64:
case 16: demodAPSK = demodAPSK64;
demodAPSK = demodAPSK16; break;
updateDemodulatorCons(16); case 128:
break; demodAPSK = demodAPSK128;
case 32: break;
demodAPSK = demodAPSK32; case 256:
updateDemodulatorCons(32); demodAPSK = demodAPSK256;
break; 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;
}
} }
} }

View File

@ -5,12 +5,20 @@ class ModemAPSK : public ModemDigital {
public: public:
ModemAPSK(); ModemAPSK();
~ModemAPSK(); ~ModemAPSK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
void updateDemodulatorCons(int cons); void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
int cons;
modem demodAPSK; modem demodAPSK;
modem demodAPSK4; modem demodAPSK4;
modem demodAPSK8; modem demodAPSK8;

View File

@ -1,6 +1,6 @@
#include "ModemASK.h" #include "ModemASK.h"
ModemASK::ModemASK() { ModemASK::ModemASK() : ModemDigital() {
demodASK2 = modem_create(LIQUID_MODEM_ASK2); demodASK2 = modem_create(LIQUID_MODEM_ASK2);
demodASK4 = modem_create(LIQUID_MODEM_ASK4); demodASK4 = modem_create(LIQUID_MODEM_ASK4);
demodASK8 = modem_create(LIQUID_MODEM_ASK8); demodASK8 = modem_create(LIQUID_MODEM_ASK8);
@ -10,9 +10,7 @@ ModemASK::ModemASK() {
demodASK128 = modem_create(LIQUID_MODEM_ASK128); demodASK128 = modem_create(LIQUID_MODEM_ASK128);
demodASK256 = modem_create(LIQUID_MODEM_ASK256); demodASK256 = modem_create(LIQUID_MODEM_ASK256);
demodASK = demodASK2; demodASK = demodASK2;
demodulatorCons.store(2); cons = 2;
currentDemodCons.store(0);
updateDemodulatorCons(2);
} }
Modem *ModemASK::factory() { Modem *ModemASK::factory() {
@ -33,47 +31,71 @@ std::string ModemASK::getName() {
return "ASK"; 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<std::string> 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) { void ModemASK::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) { this->cons = cons;
currentDemodCons = cons; switch (cons) {
case 2:
switch (demodulatorCons.load()) { demodASK = demodASK2;
case 2: break;
demodASK = demodASK2; case 4:
updateDemodulatorCons(2); demodASK = demodASK4;
break; break;
case 4: case 8:
demodASK = demodASK4; demodASK = demodASK8;
updateDemodulatorCons(4); break;
break; case 16:
case 8: demodASK = demodASK16;
demodASK = demodASK8; break;
updateDemodulatorCons(8); case 32:
break; demodASK = demodASK32;
case 16: break;
demodASK = demodASK16; case 64:
updateDemodulatorCons(16); demodASK = demodASK64;
break; break;
case 32: case 128:
demodASK = demodASK32; demodASK = demodASK128;
updateDemodulatorCons(32); break;
break; case 256:
case 64: demodASK = demodASK256;
demodASK = demodASK64; break;
updateDemodulatorCons(64);
break;
case 128:
demodASK = demodASK128;
updateDemodulatorCons(128);
break;
case 256:
demodASK = demodASK256;
updateDemodulatorCons(256);
break;
default:
demodASK = demodASK2;
break;
}
} }
} }

View File

@ -5,12 +5,20 @@ class ModemASK : public ModemDigital {
public: public:
ModemASK(); ModemASK();
~ModemASK(); ~ModemASK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
void updateDemodulatorCons(int cons); void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
int cons;
modem demodASK; modem demodASK;
modem demodASK2; modem demodASK2;
modem demodASK4; modem demodASK4;

View File

@ -1,6 +1,6 @@
#include "ModemBPSK.h" #include "ModemBPSK.h"
ModemBPSK::ModemBPSK() { ModemBPSK::ModemBPSK() : ModemDigital() {
demodBPSK = modem_create(LIQUID_MODEM_BPSK); demodBPSK = modem_create(LIQUID_MODEM_BPSK);
} }
@ -16,12 +16,6 @@ std::string ModemBPSK::getName() {
return "BPSK"; return "BPSK";
} }
void ModemBPSK::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) {
currentDemodCons = cons;
}
}
void ModemBPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemBPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitDigital *dkit = (ModemKitDigital *)kit; ModemKitDigital *dkit = (ModemKitDigital *)kit;
digitalStart(dkit, demodBPSK, input); digitalStart(dkit, demodBPSK, input);

View File

@ -5,12 +5,13 @@ class ModemBPSK : public ModemDigital {
public: public:
ModemBPSK(); ModemBPSK();
~ModemBPSK(); ~ModemBPSK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
modem demodBPSK; modem demodBPSK;
}; };

View File

@ -1,6 +1,6 @@
#include "ModemDPSK.h" #include "ModemDPSK.h"
ModemDPSK::ModemDPSK() { ModemDPSK::ModemDPSK() : ModemDigital() {
demodDPSK2 = modem_create(LIQUID_MODEM_DPSK2); demodDPSK2 = modem_create(LIQUID_MODEM_DPSK2);
demodDPSK4 = modem_create(LIQUID_MODEM_DPSK4); demodDPSK4 = modem_create(LIQUID_MODEM_DPSK4);
demodDPSK8 = modem_create(LIQUID_MODEM_DPSK8); demodDPSK8 = modem_create(LIQUID_MODEM_DPSK8);
@ -9,9 +9,8 @@ ModemDPSK::ModemDPSK() {
demodDPSK64 = modem_create(LIQUID_MODEM_DPSK64); demodDPSK64 = modem_create(LIQUID_MODEM_DPSK64);
demodDPSK128 = modem_create(LIQUID_MODEM_DPSK128); demodDPSK128 = modem_create(LIQUID_MODEM_DPSK128);
demodDPSK256 = modem_create(LIQUID_MODEM_DPSK256); demodDPSK256 = modem_create(LIQUID_MODEM_DPSK256);
demodulatorCons.store(2); demodDPSK = demodDPSK2;
currentDemodCons.store(0); cons = 2;
updateDemodulatorCons(2);
} }
Modem *ModemDPSK::factory() { Modem *ModemDPSK::factory() {
@ -33,47 +32,71 @@ ModemDPSK::~ModemDPSK() {
modem_destroy(demodDPSK256); 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<std::string> 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) { void ModemDPSK::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) { this->cons = cons;
currentDemodCons = cons; switch (cons) {
case 2:
switch (demodulatorCons.load()) { demodDPSK = demodDPSK2;
case 2: break;
demodDPSK = demodDPSK2; case 4:
updateDemodulatorCons(2); demodDPSK = demodDPSK4;
break; break;
case 4: case 8:
demodDPSK = demodDPSK4; demodDPSK = demodDPSK8;
updateDemodulatorCons(4); break;
break; case 16:
case 8: demodDPSK = demodDPSK16;
demodDPSK = demodDPSK8; break;
updateDemodulatorCons(8); case 32:
break; demodDPSK = demodDPSK32;
case 16: break;
demodDPSK = demodDPSK16; case 64:
updateDemodulatorCons(16); demodDPSK = demodDPSK64;
break; break;
case 32: case 128:
demodDPSK = demodDPSK32; demodDPSK = demodDPSK128;
updateDemodulatorCons(32); break;
break; case 256:
case 64: demodDPSK = demodDPSK256;
demodDPSK = demodDPSK64; break;
updateDemodulatorCons(64);
break;
case 128:
demodDPSK = demodDPSK128;
updateDemodulatorCons(128);
break;
case 256:
demodDPSK = demodDPSK256;
updateDemodulatorCons(256);
break;
default:
demodDPSK = demodDPSK2;
break;
}
} }
} }

View File

@ -5,12 +5,20 @@ class ModemDPSK : public ModemDigital {
public: public:
ModemDPSK(); ModemDPSK();
~ModemDPSK(); ~ModemDPSK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
void updateDemodulatorCons(int cons); void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
int cons;
modem demodDPSK; modem demodDPSK;
modem demodDPSK2; modem demodDPSK2;
modem demodDPSK4; modem demodDPSK4;

View File

@ -0,0 +1,143 @@
#include "ModemFSK.h"
#include <iomanip>
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<std::string> 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<std::string> 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);
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "ModemDigital.h"
#include <sstream>
class ModemKitFSK : public ModemKitDigital {
public:
unsigned int m, k;
float bw;
fskdem demodFSK;
std::vector<liquid_float_complex> 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;
};

View File

@ -0,0 +1,133 @@
#include "ModemGMSK.h"
#include <iomanip>
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);
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "ModemDigital.h"
#include <sstream>
class ModemKitGMSK : public ModemKitDigital {
public:
unsigned int fdelay, sps;
float ebf;
gmskdem demodGMSK;
std::vector<liquid_float_complex> 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;
};

View File

@ -1,13 +1,9 @@
#include "ModemOOK.h" #include "ModemOOK.h"
ModemOOK::ModemOOK() { ModemOOK::ModemOOK() : ModemDigital() {
demodOOK = modem_create(LIQUID_MODEM_OOK); demodOOK = modem_create(LIQUID_MODEM_OOK);
} }
Modem *ModemOOK::factory() {
return new ModemOOK;
}
ModemOOK::~ModemOOK() { ModemOOK::~ModemOOK() {
modem_destroy(demodOOK); modem_destroy(demodOOK);
} }
@ -16,10 +12,15 @@ std::string ModemOOK::getName() {
return "OOK"; return "OOK";
} }
void ModemOOK::updateDemodulatorCons(int cons) { Modem *ModemOOK::factory() {
if (currentDemodCons.load() != cons) { return new ModemOOK;
currentDemodCons = cons; }
int ModemOOK::checkSampleRate(long long sampleRate, int audioSampleRate) {
if (sampleRate < 100) {
return 100;
} }
return sampleRate;
} }
void ModemOOK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemOOK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {

View File

@ -5,12 +5,15 @@ class ModemOOK : public ModemDigital {
public: public:
ModemOOK(); ModemOOK();
~ModemOOK(); ~ModemOOK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
void updateDemodulatorCons(int cons);
int checkSampleRate(long long sampleRate, int audioSampleRate);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
modem demodOOK; modem demodOOK;
}; };

View File

@ -1,6 +1,6 @@
#include "ModemPSK.h" #include "ModemPSK.h"
ModemPSK::ModemPSK() { ModemPSK::ModemPSK() : ModemDigital() {
demodPSK2 = modem_create(LIQUID_MODEM_PSK2); demodPSK2 = modem_create(LIQUID_MODEM_PSK2);
demodPSK4 = modem_create(LIQUID_MODEM_PSK4); demodPSK4 = modem_create(LIQUID_MODEM_PSK4);
demodPSK8 = modem_create(LIQUID_MODEM_PSK8); demodPSK8 = modem_create(LIQUID_MODEM_PSK8);
@ -9,9 +9,8 @@ ModemPSK::ModemPSK() {
demodPSK64 = modem_create(LIQUID_MODEM_PSK64); demodPSK64 = modem_create(LIQUID_MODEM_PSK64);
demodPSK128 = modem_create(LIQUID_MODEM_PSK128); demodPSK128 = modem_create(LIQUID_MODEM_PSK128);
demodPSK256 = modem_create(LIQUID_MODEM_PSK256); demodPSK256 = modem_create(LIQUID_MODEM_PSK256);
demodulatorCons.store(2); demodPSK = demodPSK2;
currentDemodCons.store(0); cons = 2;
updateDemodulatorCons(2);
} }
Modem *ModemPSK::factory() { Modem *ModemPSK::factory() {
@ -33,47 +32,72 @@ ModemPSK::~ModemPSK() {
modem_destroy(demodPSK256); 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<std::string> 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) { void ModemPSK::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) { this->cons = cons;
currentDemodCons = cons; switch (cons) {
case 2:
switch (demodulatorCons.load()) { demodPSK = demodPSK2;
case 2: break;
demodPSK = demodPSK2; case 4:
updateDemodulatorCons(2); demodPSK = demodPSK4;
break; break;
case 4: case 8:
demodPSK = demodPSK4; demodPSK = demodPSK8;
updateDemodulatorCons(4); break;
break; case 16:
case 8: demodPSK = demodPSK16;
demodPSK = demodPSK8; break;
updateDemodulatorCons(8); case 32:
break; demodPSK = demodPSK32;
case 16: break;
demodPSK = demodPSK16; case 64:
updateDemodulatorCons(16); demodPSK = demodPSK64;
break; break;
case 32: case 128:
demodPSK = demodPSK32; demodPSK = demodPSK128;
updateDemodulatorCons(32); break;
break; case 256:
case 64: demodPSK = demodPSK256;
demodPSK = demodPSK64; break;
updateDemodulatorCons(64);
break;
case 128:
demodPSK = demodPSK128;
updateDemodulatorCons(128);
break;
case 256:
demodPSK = demodPSK256;
updateDemodulatorCons(256);
break;
default:
demodPSK = demodPSK2;
break;
}
} }
} }

View File

@ -5,12 +5,20 @@ class ModemPSK : public ModemDigital {
public: public:
ModemPSK(); ModemPSK();
~ModemPSK(); ~ModemPSK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
void updateDemodulatorCons(int cons); void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
int cons;
modem demodPSK; modem demodPSK;
modem demodPSK2; modem demodPSK2;
modem demodPSK4; modem demodPSK4;

View File

@ -1,6 +1,6 @@
#include "ModemQAM.h" #include "ModemQAM.h"
ModemQAM::ModemQAM() { ModemQAM::ModemQAM() : ModemDigital() {
demodQAM4 = modem_create(LIQUID_MODEM_QAM4); demodQAM4 = modem_create(LIQUID_MODEM_QAM4);
demodQAM8 = modem_create(LIQUID_MODEM_QAM8); demodQAM8 = modem_create(LIQUID_MODEM_QAM8);
demodQAM16 = modem_create(LIQUID_MODEM_QAM16); demodQAM16 = modem_create(LIQUID_MODEM_QAM16);
@ -8,9 +8,8 @@ ModemQAM::ModemQAM() {
demodQAM64 = modem_create(LIQUID_MODEM_QAM64); demodQAM64 = modem_create(LIQUID_MODEM_QAM64);
demodQAM128 = modem_create(LIQUID_MODEM_QAM128); demodQAM128 = modem_create(LIQUID_MODEM_QAM128);
demodQAM256 = modem_create(LIQUID_MODEM_QAM256); demodQAM256 = modem_create(LIQUID_MODEM_QAM256);
demodulatorCons.store(4); demodQAM = demodQAM4;
currentDemodCons.store(0); cons = 4;
updateDemodulatorCons(4);
} }
Modem *ModemQAM::factory() { Modem *ModemQAM::factory() {
@ -31,47 +30,67 @@ ModemQAM::~ModemQAM() {
modem_destroy(demodQAM256); 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<std::string> 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) { void ModemQAM::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) { this->cons = cons;
currentDemodCons = cons; switch (cons) {
case 4:
switch (demodulatorCons.load()) { demodQAM = demodQAM4;
case 2: break;
demodQAM = demodQAM4; case 8:
updateDemodulatorCons(4); demodQAM = demodQAM8;
break; break;
case 4: case 16:
demodQAM = demodQAM4; demodQAM = demodQAM16;
updateDemodulatorCons(4); break;
break; case 32:
case 8: demodQAM = demodQAM32;
demodQAM = demodQAM8; break;
updateDemodulatorCons(8); case 64:
break; demodQAM = demodQAM64;
case 16: break;
demodQAM = demodQAM16; case 128:
updateDemodulatorCons(16); demodQAM = demodQAM128;
break; break;
case 32: case 256:
demodQAM = demodQAM32; demodQAM = demodQAM256;
updateDemodulatorCons(32); break;
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;
}
} }
} }

View File

@ -5,12 +5,20 @@ class ModemQAM : public ModemDigital {
public: public:
ModemQAM(); ModemQAM();
~ModemQAM(); ~ModemQAM();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
void updateDemodulatorCons(int cons); void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
int cons;
modem demodQAM; modem demodQAM;
modem demodQAM4; modem demodQAM4;
modem demodQAM8; modem demodQAM8;

View File

@ -1,6 +1,6 @@
#include "ModemQPSK.h" #include "ModemQPSK.h"
ModemQPSK::ModemQPSK() { ModemQPSK::ModemQPSK() : ModemDigital() {
demodQPSK = modem_create(LIQUID_MODEM_QPSK); demodQPSK = modem_create(LIQUID_MODEM_QPSK);
} }
@ -16,12 +16,6 @@ std::string ModemQPSK::getName() {
return "QPSK"; return "QPSK";
} }
void ModemQPSK::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) {
currentDemodCons = cons;
}
}
void ModemQPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemQPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitDigital *dkit = (ModemKitDigital *)kit; ModemKitDigital *dkit = (ModemKitDigital *)kit;
digitalStart(dkit, demodQPSK, input); digitalStart(dkit, demodQPSK, input);

View File

@ -5,9 +5,11 @@ class ModemQPSK : public ModemDigital {
public: public:
ModemQPSK(); ModemQPSK();
~ModemQPSK(); ~ModemQPSK();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -1,11 +1,10 @@
#include "ModemSQAM.h" #include "ModemSQAM.h"
ModemSQAM::ModemSQAM() { ModemSQAM::ModemSQAM() : ModemDigital() {
demodSQAM32 = modem_create(LIQUID_MODEM_SQAM32); demodSQAM32 = modem_create(LIQUID_MODEM_SQAM32);
demodSQAM128 = modem_create(LIQUID_MODEM_SQAM128); demodSQAM128 = modem_create(LIQUID_MODEM_SQAM128);
demodulatorCons.store(32); demodSQAM = demodSQAM32;
currentDemodCons.store(0); cons = 32;
updateDemodulatorCons(32);
} }
Modem *ModemSQAM::factory() { Modem *ModemSQAM::factory() {
@ -21,47 +20,47 @@ std::string ModemSQAM::getName() {
return "SQAM"; 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<std::string> 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) { void ModemSQAM::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) { this->cons = cons;
currentDemodCons = cons; switch (cons) {
case 32:
switch (demodulatorCons.load()) { demodSQAM = demodSQAM32;
case 2: break;
demodSQAM = demodSQAM32; case 128:
updateDemodulatorCons(32); demodSQAM = demodSQAM128;
break; 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;
}
} }
} }

View File

@ -5,12 +5,20 @@ class ModemSQAM : public ModemDigital {
public: public:
ModemSQAM(); ModemSQAM();
~ModemSQAM(); ~ModemSQAM();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
void updateDemodulatorCons(int cons); void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:
int cons;
modem demodSQAM; modem demodSQAM;
modem demodSQAM32; modem demodSQAM32;
modem demodSQAM128; modem demodSQAM128;

View File

@ -1,6 +1,6 @@
#include "ModemST.h" #include "ModemST.h"
ModemST::ModemST() { ModemST::ModemST() : ModemDigital() {
demodST = modem_create(LIQUID_MODEM_V29); demodST = modem_create(LIQUID_MODEM_V29);
} }
@ -16,12 +16,6 @@ ModemST::~ModemST() {
modem_destroy(demodST); modem_destroy(demodST);
} }
void ModemST::updateDemodulatorCons(int cons) {
if (currentDemodCons.load() != cons) {
currentDemodCons = cons;
}
}
void ModemST::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { void ModemST::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitDigital *dkit = (ModemKitDigital *)kit; ModemKitDigital *dkit = (ModemKitDigital *)kit;
digitalStart(dkit, demodST, input); digitalStart(dkit, demodST, input);

View File

@ -5,9 +5,11 @@ class ModemST : public ModemDigital {
public: public:
ModemST(); ModemST();
~ModemST(); ~ModemST();
std::string getName(); std::string getName();
Modem *factory(); Modem *factory();
void updateDemodulatorCons(int cons);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut); void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private: private:

View File

@ -16,6 +16,9 @@ void ScopePanel::setMode(ScopeMode scopeMode) {
this->scopeMode = scopeMode; this->scopeMode = scopeMode;
} }
ScopePanel::ScopeMode ScopePanel::getMode() {
return this->scopeMode;
}
void ScopePanel::setPoints(std::vector<float> &points) { void ScopePanel::setPoints(std::vector<float> &points) {
this->points.assign(points.begin(),points.end()); this->points.assign(points.begin(),points.end());
@ -61,14 +64,29 @@ void ScopePanel::drawPanelContents() {
glEnd(); glEnd();
} else if (scopeMode == SCOPE_MODE_XY) { } 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()) { if (points.size()) {
glEnable (GL_BLEND); glEnable (GL_BLEND);
glEnable (GL_LINE_SMOOTH); glEnable (GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 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); glColor4f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b, 1.0);
glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &points[0]); glVertexPointer(2, GL_FLOAT, 0, &points[0]);
@ -83,7 +101,8 @@ void ScopePanel::drawPanelContents() {
glLoadMatrixf(bgPanelStereo[1].transform); glLoadMatrixf(bgPanelStereo[1].transform);
glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4); glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
} else if (scopeMode == SCOPE_MODE_XY) { } else if (scopeMode == SCOPE_MODE_XY) {
// ... glLoadMatrixf(bgPanel.transform);
glDrawArrays(GL_POINTS, 0, points.size() / 2);
} }
glLineWidth(1.0); glLineWidth(1.0);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);

View File

@ -10,6 +10,7 @@ public:
ScopePanel(); ScopePanel();
void setMode(ScopeMode scopeMode); void setMode(ScopeMode scopeMode);
ScopeMode getMode();
void setPoints(std::vector<float> &points); void setPoints(std::vector<float> &points);
protected: protected:

View File

@ -95,7 +95,7 @@ void ScopeVisualProcessor::process() {
} }
} }
if (audioInputData->channels == 2) { if (audioInputData->type == 1) {
iMax = audioInputData->data.size(); iMax = audioInputData->data.size();
if (renderData->waveform_points.size() != iMax * 2) { if (renderData->waveform_points.size() != iMax * 2) {
renderData->waveform_points.resize(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] = (((double) (i % (iMax/2)) / (double) iMax) * 2.0 - 0.5) * 2.0;
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak; 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 { } else {
for (i = 0; i < iMax; i++) { for (i = 0; i < iMax; i++) {
renderData->waveform_points[i * 2] = (((double) i / (double) iMax) - 0.5) * 2.0; renderData->waveform_points[i * 2] = (((double) i / (double) iMax) - 0.5) * 2.0;
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak; renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak;
} }
renderData->mode = ScopePanel::SCOPE_MODE_Y;
} }
renderData->spectrum = false; renderData->spectrum = false;

View File

@ -3,10 +3,12 @@
#include "VisualProcessor.h" #include "VisualProcessor.h"
#include "AudioThread.h" #include "AudioThread.h"
#include "fftw3.h" #include "fftw3.h"
#include "ScopePanel.h"
class ScopeRenderData: public ReferenceCounter { class ScopeRenderData: public ReferenceCounter {
public: public:
std::vector<float> waveform_points; std::vector<float> waveform_points;
ScopePanel::ScopeMode mode;
int inputRate; int inputRate;
int sampleRate; int sampleRate;
int channels; int channels;

View File

@ -155,10 +155,16 @@ void ModeSelectorCanvas::addChoice(int value, std::string label) {
numChoices = selections.size(); 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) { void ModeSelectorCanvas::setSelection(std::string label) {
for (int i = 0; i < numChoices; i++) { for (int i = 0; i < numChoices; i++) {
if (selections[i].label == label) { if (selections[i].label == label) {
currentSelection = i; currentSelection = i;
Refresh();
return; return;
} }
} }

View File

@ -32,6 +32,7 @@ public:
void setHelpTip(std::string tip); void setHelpTip(std::string tip);
void addChoice(int value, std::string label); void addChoice(int value, std::string label);
void addChoice(std::string label);
void setSelection(std::string label); void setSelection(std::string label);
std::string getSelectionLabel(); std::string getSelectionLabel();
void setSelection(int value); void setSelection(int value);

View File

@ -230,9 +230,9 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long
} }
// advanced demodulators start here // advanced demodulators start here
if (demod->getDemodulatorCons() > 0) { // if (demod->getDemodulatorCons() > 0) {
demodStr = demodStr + std::to_string(demod->getDemodulatorCons()); // demodStr = demodStr + std::to_string(demod->getDemodulatorCons());
} // }
// add lock to string if we have an lock // add lock to string if we have an lock
if(demod->getDemodulatorLock()) { if(demod->getDemodulatorLock()) {

View File

@ -29,6 +29,5 @@ public:
void setHoverAlpha(float hoverAlpha); void setHoverAlpha(float hoverAlpha);
private: private:
DemodulatorThreadParameters defaultDemodParams;
float hoverAlpha; float hoverAlpha;
}; };

View File

@ -28,7 +28,7 @@ EVT_LEAVE_WINDOW(ScopeCanvas::OnMouseLeftWindow)
EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow) EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow)
wxEND_EVENT_TABLE() 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)); glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
inputData.set_max_num_items(2); inputData.set_max_num_items(2);
@ -65,7 +65,7 @@ bool ScopeCanvas::spectrumVisible() {
float panelInterval = (2.0 + panelSpacing); float panelInterval = (2.0 + panelSpacing);
ctrTarget = abs(round(ctr / panelInterval)); ctrTarget = abs(round(ctr / panelInterval));
if (ctrTarget == 1 || dragAccel || (ctr != ctrTarget)) { if (ctrTarget == 1 || dragAccel || (ctr != ctrTarget)) {
return true; return true;
} }
@ -73,10 +73,6 @@ bool ScopeCanvas::spectrumVisible() {
return false; return false;
} }
void ScopeCanvas::setStereo(bool state) {
stereo = state;
}
void ScopeCanvas::setDeviceName(std::string device_name) { void ScopeCanvas::setDeviceName(std::string device_name) {
deviceName = device_name; deviceName = device_name;
deviceName.append(" "); deviceName.append(" ");
@ -106,12 +102,12 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
ScopeRenderData *avData; ScopeRenderData *avData;
inputData.pop(avData); inputData.pop(avData);
if (!avData->spectrum) { if (!avData->spectrum) {
scopePanel.setMode(avData->mode);
if (avData->waveform_points.size()) { if (avData->waveform_points.size()) {
scopePanel.setPoints(avData->waveform_points); scopePanel.setPoints(avData->waveform_points);
setStereo(avData->channels == 2);
} }
avData->decRefCount(); avData->decRefCount();
} else { } else {
if (avData->waveform_points.size()) { if (avData->waveform_points.size()) {
@ -133,14 +129,18 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glViewport(0, 0, ClientSize.x, ClientSize.y); 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); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0)); 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); spectrumPanel.setPosition(panelInterval+ctr, 0);
if (spectrumVisible()) { 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; spectrumPanel.contentsVisible = true;
roty = atan2(spectrumPanel.pos[0],1.2); roty = atan2(spectrumPanel.pos[0],1.2);
spectrumPanel.rot[1] = -(roty * (180.0 / M_PI)); spectrumPanel.rot[1] = -(roty * (180.0 / M_PI));
@ -217,7 +217,9 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glContext->DrawTunerTitles(ppmMode); glContext->DrawTunerTitles(ppmMode);
glContext->DrawEnd(); glContext->DrawEnd();
SwapBuffers(); if (scopePanel.getMode() != ScopePanel::SCOPE_MODE_XY || spectrumVisible()) {
SwapBuffers();
}
} }

View File

@ -18,7 +18,6 @@ public:
ScopeCanvas(wxWindow *parent, int *attribList = NULL); ScopeCanvas(wxWindow *parent, int *attribList = NULL);
~ScopeCanvas(); ~ScopeCanvas();
void setStereo(bool state);
void setDeviceName(std::string device_name); void setDeviceName(std::string device_name);
void setPPMMode(bool ppmMode); void setPPMMode(bool ppmMode);
bool getPPMMode(); bool getPPMMode();
@ -50,7 +49,6 @@ private:
GLPanel bgPanel; GLPanel bgPanel;
ScopeContext *glContext; ScopeContext *glContext;
std::string deviceName; std::string deviceName;
bool stereo;
bool ppmMode; bool ppmMode;
bool showDb; bool showDb;
float panelSpacing; float panelSpacing;

View File

@ -12,10 +12,12 @@ ScopeContext::ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext) :
glLoadIdentity(); glLoadIdentity();
} }
void ScopeContext::DrawBegin() { void ScopeContext::DrawBegin(bool clear) {
glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, if (clear) {
ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0); glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g,
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
glMatrixMode (GL_MODELVIEW); glMatrixMode (GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();

View File

@ -11,7 +11,7 @@ class ScopeContext: public PrimaryGLContext {
public: public:
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext); ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
void DrawBegin(); void DrawBegin(bool clear=true);
void DrawTunerTitles(bool ppmMode=false); void DrawTunerTitles(bool ppmMode=false);
void DrawDeviceName(std::string deviceName); void DrawDeviceName(std::string deviceName);
void DrawDivider(); void DrawDivider();

View File

@ -17,8 +17,6 @@
#include <wx/numformatter.h> #include <wx/numformatter.h>
#define MIN_BANDWIDTH 1500
wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas)
EVT_PAINT(WaterfallCanvas::OnPaint) EVT_PAINT(WaterfallCanvas::OnPaint)
EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown) EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)
@ -44,6 +42,7 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
preBuf = false; preBuf = false;
SetCursor(wxCURSOR_CROSS); SetCursor(wxCURSOR_CROSS);
scaleMove = 0; scaleMove = 0;
minBandwidth = 30000;
} }
WaterfallCanvas::~WaterfallCanvas() { WaterfallCanvas::~WaterfallCanvas() {
@ -179,8 +178,8 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
if (currentZoom < 1) { if (currentZoom < 1) {
bw = (long long) ceil((long double) bw * currentZoom); bw = (long long) ceil((long double) bw * currentZoom);
if (bw < 30000) { if (bw < minBandwidth) {
bw = 30000; bw = minBandwidth;
} }
if (mouseInView) { if (mouseInView) {
long long mfreqA = getFrequencyAt(mpos); long long mfreqA = getFrequencyAt(mpos);
@ -461,7 +460,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
bwDiff = -bwDiff; bwDiff = -bwDiff;
} }
int currentBW = demod->getBandwidth(); int currentBW = dragBW;
currentBW = currentBW + bwDiff; currentBW = currentBW + bwDiff;
if (currentBW > CHANNELIZER_RATE_MAX) { if (currentBW > CHANNELIZER_RATE_MAX) {
@ -472,6 +471,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
} }
demod->setBandwidth(currentBW); demod->setBandwidth(currentBW);
dragBW = currentBW;
} }
if (dragState == WF_DRAG_FREQUENCY) { if (dragState == WF_DRAG_FREQUENCY) {
@ -596,11 +596,13 @@ void WaterfallCanvas::OnMouseDown(wxMouseEvent& event) {
InteractiveCanvas::OnMouseDown(event); InteractiveCanvas::OnMouseDown(event);
dragState = nextDragState; dragState = nextDragState;
wxGetApp().getDemodMgr().updateLastState();
if (dragState && dragState != WF_DRAG_RANGE) { if (dragState && dragState != WF_DRAG_RANGE) {
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator(); DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator();
if (demod) { if (demod) {
dragOfs = (long long) (mouseTracker.getMouseX() * (float) getBandwidth()) + getCenterFrequency() - (getBandwidth() / 2) - demod->getFrequency(); dragOfs = (long long) (mouseTracker.getMouseX() * (float) getBandwidth()) + getCenterFrequency() - (getBandwidth() / 2) - demod->getFrequency();
dragBW = demod->getBandwidth();
} }
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false); wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false);
} }
@ -615,6 +617,7 @@ void WaterfallCanvas::OnMouseWheelMoved(wxMouseEvent& event) {
void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
InteractiveCanvas::OnMouseReleased(event); InteractiveCanvas::OnMouseReleased(event);
wxGetApp().getDemodMgr().updateLastState();
bool isNew = shiftDown || (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) bool isNew = shiftDown || (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL)
|| (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive()); || (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive());
@ -651,6 +654,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
if (dragState == WF_DRAG_NONE) { if (dragState == WF_DRAG_NONE) {
if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) { if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) {
mgr->updateLastState();
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
} else { } else {
isNew = true; isNew = true;
@ -663,7 +667,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
demod->setSquelchEnabled(mgr->isLastSquelchEnabled()); demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
demod->setGain(mgr->getLastGain()); demod->setGain(mgr->getLastGain());
demod->setMuted(mgr->isLastMuted()); demod->setMuted(mgr->isLastMuted());
demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType()));
demod->run(); demod->run();
wxGetApp().bindDemodulator(demod); wxGetApp().bindDemodulator(demod);
@ -676,7 +680,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
demod->updateLabel(freq); demod->updateLabel(freq);
demod->setFrequency(freq); demod->setFrequency(freq);
if (isNew) { if (isNew) {
setStatusText("New demodulator at frequency: %s", freq); setStatusText("New demodulator at frequency: %s", freq);
} else { } else {
@ -684,13 +688,14 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
} }
wxGetApp().getDemodMgr().setActiveDemodulator(demod, false); wxGetApp().getDemodMgr().setActiveDemodulator(demod, false);
SetCursor(wxCURSOR_SIZING); SetCursor(wxCURSOR_SIZING);
nextDragState = WF_DRAG_FREQUENCY; nextDragState = WF_DRAG_FREQUENCY;
mouseTracker.setVertDragLock(true); mouseTracker.setVertDragLock(true);
mouseTracker.setHorizDragLock(false); mouseTracker.setHorizDragLock(false);
} else { } else {
if (activeDemod) { if (activeDemod) {
wxGetApp().getDemodMgr().setActiveDemodulator(activeDemod, false); wxGetApp().getDemodMgr().setActiveDemodulator(activeDemod, false);
mgr->updateLastState();
activeDemod->setTracking(true); activeDemod->setTracking(true);
nextDragState = WF_DRAG_FREQUENCY; nextDragState = WF_DRAG_FREQUENCY;
} else { } else {
@ -740,6 +745,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) { if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) {
mgr->updateLastState();
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
} else { } else {
demod = wxGetApp().getDemodMgr().newThread(); demod = wxGetApp().getDemodMgr().newThread();
@ -749,6 +755,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
demod->setSquelchLevel(mgr->getLastSquelchLevel()); demod->setSquelchLevel(mgr->getLastSquelchLevel());
demod->setSquelchEnabled(mgr->isLastSquelchEnabled()); demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
demod->setGain(mgr->getLastGain()); demod->setGain(mgr->getLastGain());
demod->setMuted(mgr->isLastMuted());
demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType()));
demod->run(); demod->run();
@ -765,7 +773,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
demod->updateLabel(freq); demod->updateLabel(freq);
demod->setFrequency(freq); demod->setFrequency(freq);
demod->setBandwidth(bw); demod->setBandwidth(bw);
wxGetApp().getDemodMgr().setActiveDemodulator(demod, false); mgr->setActiveDemodulator(demod, false);
mgr->updateLastState();
} }
dragState = WF_DRAG_NONE; dragState = WF_DRAG_NONE;
@ -842,4 +851,6 @@ void WaterfallCanvas::setLinesPerSecond(int lps) {
tex_update.unlock(); tex_update.unlock();
} }
void WaterfallCanvas::setMinBandwidth(int min) {
minBandwidth = min;
}

View File

@ -30,6 +30,7 @@ public:
SpectrumVisualDataQueue *getVisualDataQueue(); SpectrumVisualDataQueue *getVisualDataQueue();
void setLinesPerSecond(int lps); void setLinesPerSecond(int lps);
void setMinBandwidth(int min);
private: private:
void OnPaint(wxPaintEvent& event); void OnPaint(wxPaintEvent& event);
@ -68,12 +69,14 @@ private:
float hoverAlpha; float hoverAlpha;
int linesPerSecond; int linesPerSecond;
float scaleMove; float scaleMove;
int dragBW;
SpectrumVisualDataQueue visualDataQueue; SpectrumVisualDataQueue visualDataQueue;
Timer gTimer; Timer gTimer;
double lpsIndex; double lpsIndex;
bool preBuf; bool preBuf;
std::mutex tex_update; std::mutex tex_update;
int minBandwidth;
// event table // event table
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };