mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-04 08:21:16 -05:00
Merge pull request #199 from cjcliffe/digital_experiments
Digital experiments and cleanup
This commit is contained in:
commit
777e4a3488
@ -14,7 +14,7 @@ SET(CPACK_PACKAGE_VERSION_PATCH ${CUBICSDR_VERSION_PATCH})
|
||||
SET (VERSION_SUFFIX "" CACHE STRING "Add custom version suffix to CubicSDR application title.")
|
||||
|
||||
ADD_DEFINITIONS(
|
||||
-DCUBICSDR_VERSION="${CUBICSDR_VERSION}-${VERSION_SUFFIX}"
|
||||
-DCUBICSDR_VERSION="${CUBICSDR_VERSION}${VERSION_SUFFIX}"
|
||||
)
|
||||
|
||||
SET (ENABLE_DIGITAL_LAB OFF CACHE BOOL "Enable 'Digital Lab' testing features.")
|
||||
@ -22,6 +22,16 @@ IF(ENABLE_DIGITAL_LAB)
|
||||
ADD_DEFINITIONS(
|
||||
-DENABLE_DIGITAL_LAB=1
|
||||
)
|
||||
IF(MSVC)
|
||||
SET (ENABLE_LIQUID_EXPERIMENTAL OFF CACHE BOOL "Enable experimental liquid-dsp features (requires latest liquid-dsp installed)")
|
||||
ELSE()
|
||||
SET (ENABLE_LIQUID_EXPERIMENTAL ON CACHE BOOL "Enable experimental liquid-dsp features (requires latest liquid-dsp installed)")
|
||||
ENDIF()
|
||||
IF(ENABLE_LIQUID_EXPERIMENTAL)
|
||||
ADD_DEFINITIONS(
|
||||
-DENABLE_LIQUID_EXPERIMENTAL=1
|
||||
)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
@ -225,6 +235,7 @@ SET (cubicsdr_sources
|
||||
src/AppConfig.cpp
|
||||
src/FrequencyDialog.cpp
|
||||
src/IOThread.cpp
|
||||
src/ModemProperties.cpp
|
||||
src/sdr/SDRDeviceInfo.cpp
|
||||
src/sdr/SDRPostThread.cpp
|
||||
src/sdr/SDREnumerator.cpp
|
||||
@ -237,16 +248,6 @@ SET (cubicsdr_sources
|
||||
src/modules/modem/Modem.cpp
|
||||
src/modules/modem/ModemAnalog.cpp
|
||||
src/modules/modem/ModemDigital.cpp
|
||||
src/modules/modem/digital/ModemASK.cpp
|
||||
src/modules/modem/digital/ModemAPSK.cpp
|
||||
src/modules/modem/digital/ModemBPSK.cpp
|
||||
src/modules/modem/digital/ModemDPSK.cpp
|
||||
src/modules/modem/digital/ModemPSK.cpp
|
||||
src/modules/modem/digital/ModemOOK.cpp
|
||||
src/modules/modem/digital/ModemST.cpp
|
||||
src/modules/modem/digital/ModemSQAM.cpp
|
||||
src/modules/modem/digital/ModemQAM.cpp
|
||||
src/modules/modem/digital/ModemQPSK.cpp
|
||||
src/modules/modem/analog/ModemAM.cpp
|
||||
src/modules/modem/analog/ModemDSB.cpp
|
||||
src/modules/modem/analog/ModemFM.cpp
|
||||
@ -296,6 +297,31 @@ SET (cubicsdr_sources
|
||||
external/cubicvr2/math/cubic_math.cpp
|
||||
)
|
||||
|
||||
IF(ENABLE_DIGITAL_LAB)
|
||||
SET (cubicsdr_sources
|
||||
${cubicsdr_sources}
|
||||
src/forms/DigitalConsole/DigitalConsole.cpp
|
||||
src/forms/DigitalConsole/DigitalConsoleFrame.cpp
|
||||
src/modules/modem/digital/ModemASK.cpp
|
||||
src/modules/modem/digital/ModemAPSK.cpp
|
||||
src/modules/modem/digital/ModemBPSK.cpp
|
||||
src/modules/modem/digital/ModemDPSK.cpp
|
||||
src/modules/modem/digital/ModemGMSK.cpp
|
||||
src/modules/modem/digital/ModemPSK.cpp
|
||||
src/modules/modem/digital/ModemOOK.cpp
|
||||
src/modules/modem/digital/ModemST.cpp
|
||||
src/modules/modem/digital/ModemSQAM.cpp
|
||||
src/modules/modem/digital/ModemQAM.cpp
|
||||
src/modules/modem/digital/ModemQPSK.cpp
|
||||
)
|
||||
IF(ENABLE_LIQUID_EXPERIMENTAL)
|
||||
SET (cubicsdr_sources
|
||||
${cubicsdr_sources}
|
||||
src/modules/modem/digital/ModemFSK.cpp
|
||||
)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET (cubicsdr_headers
|
||||
src/CubicSDRDefs.h
|
||||
src/CubicSDR.h
|
||||
@ -303,6 +329,7 @@ SET (cubicsdr_headers
|
||||
src/AppConfig.h
|
||||
src/FrequencyDialog.h
|
||||
src/IOThread.h
|
||||
src/ModemProperties.h
|
||||
src/sdr/SDRDeviceInfo.h
|
||||
src/sdr/SDRPostThread.h
|
||||
src/sdr/SDREnumerator.h
|
||||
@ -316,16 +343,6 @@ SET (cubicsdr_headers
|
||||
src/modules/modem/Modem.h
|
||||
src/modules/modem/ModemAnalog.h
|
||||
src/modules/modem/ModemDigital.h
|
||||
src/modules/modem/digital/ModemASK.h
|
||||
src/modules/modem/digital/ModemAPSK.h
|
||||
src/modules/modem/digital/ModemBPSK.h
|
||||
src/modules/modem/digital/ModemDPSK.h
|
||||
src/modules/modem/digital/ModemPSK.h
|
||||
src/modules/modem/digital/ModemOOK.h
|
||||
src/modules/modem/digital/ModemST.h
|
||||
src/modules/modem/digital/ModemSQAM.h
|
||||
src/modules/modem/digital/ModemQAM.h
|
||||
src/modules/modem/digital/ModemQPSK.h
|
||||
src/modules/modem/analog/ModemAM.h
|
||||
src/modules/modem/analog/ModemDSB.h
|
||||
src/modules/modem/analog/ModemFM.h
|
||||
@ -391,6 +408,31 @@ SET (cubicsdr_headers
|
||||
external/cubicvr2/math/vec4.h
|
||||
)
|
||||
|
||||
IF(ENABLE_DIGITAL_LAB)
|
||||
SET (cubicsdr_headers
|
||||
${cubicsdr_headers}
|
||||
src/forms/DigitalConsole/DigitalConsole.h
|
||||
src/forms/DigitalConsole/DigitalConsoleFrame.h
|
||||
src/modules/modem/digital/ModemASK.h
|
||||
src/modules/modem/digital/ModemAPSK.h
|
||||
src/modules/modem/digital/ModemBPSK.h
|
||||
src/modules/modem/digital/ModemDPSK.h
|
||||
src/modules/modem/digital/ModemGMSK.h
|
||||
src/modules/modem/digital/ModemPSK.h
|
||||
src/modules/modem/digital/ModemOOK.h
|
||||
src/modules/modem/digital/ModemST.h
|
||||
src/modules/modem/digital/ModemSQAM.h
|
||||
src/modules/modem/digital/ModemQAM.h
|
||||
src/modules/modem/digital/ModemQPSK.h
|
||||
)
|
||||
IF(ENABLE_LIQUID_EXPERIMENTAL)
|
||||
SET (cubicsdr_sources
|
||||
${cubicsdr_sources}
|
||||
src/modules/modem/digital/ModemFSK.h
|
||||
)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET (CUBICSDR_RESOURCES
|
||||
${PROJECT_SOURCE_DIR}/font/vera_sans_mono12.fnt
|
||||
${PROJECT_SOURCE_DIR}/font/vera_sans_mono16.fnt
|
||||
@ -413,8 +455,11 @@ SOURCE_GROUP("Forms\\SDRDevices" REGULAR_EXPRESSION "src/forms/SDRDevices/${REG_
|
||||
SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}")
|
||||
SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem" REGULAR_EXPRESSION "src/modules/modem/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem-Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem-Digital" REGULAR_EXPRESSION "src/modules/modem/digital/${REG_EXT}")
|
||||
SOURCE_GROUP("Modem\\Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}")
|
||||
IF(ENABLE_DIGITAL_LAB)
|
||||
SOURCE_GROUP("Modem\\Digital" REGULAR_EXPRESSION "src/modules/modem/digital/${REG_EXT}")
|
||||
SOURCE_GROUP("Forms\\DigitalConsole" REGULAR_EXPRESSION "src/forms/DigitalConsole/${REG_EXT}")
|
||||
ENDIF()
|
||||
SOURCE_GROUP("Audio" REGULAR_EXPRESSION "src/audio/${REG_EXT}")
|
||||
SOURCE_GROUP("Utility" REGULAR_EXPRESSION "src/util/${REG_EXT}")
|
||||
SOURCE_GROUP("Visual" REGULAR_EXPRESSION "src/visual/${REG_EXT}")
|
||||
@ -428,6 +473,7 @@ SOURCE_GROUP("_ext-CubicVR2" REGULAR_EXPRESSION "external/cubicvr2/.*${REG_EXT}"
|
||||
|
||||
include_directories (
|
||||
${PROJECT_SOURCE_DIR}/src/forms/SDRDevices
|
||||
${PROJECT_SOURCE_DIR}/src/forms/DigitalConsole
|
||||
${PROJECT_SOURCE_DIR}/src/sdr
|
||||
${PROJECT_SOURCE_DIR}/src/demod
|
||||
${PROJECT_SOURCE_DIR}/src/modules
|
||||
|
211
src/AppFrame.cpp
211
src/AppFrame.cpp
@ -67,46 +67,47 @@ AppFrame::AppFrame() :
|
||||
gainSpacerItem->Show(false);
|
||||
|
||||
demodModeSelector = new ModeSelectorCanvas(demodPanel, attribList);
|
||||
demodModeSelector->addChoice(0, "FM");
|
||||
demodModeSelector->addChoice(1, "FMS");
|
||||
demodModeSelector->addChoice(2, "AM");
|
||||
demodModeSelector->addChoice(3, "LSB");
|
||||
demodModeSelector->addChoice(4, "USB");
|
||||
demodModeSelector->addChoice(5, "DSB");
|
||||
demodModeSelector->addChoice(6, "I/Q");
|
||||
demodModeSelector->addChoice("FM");
|
||||
demodModeSelector->addChoice("FMS");
|
||||
demodModeSelector->addChoice("AM");
|
||||
demodModeSelector->addChoice("LSB");
|
||||
demodModeSelector->addChoice("USB");
|
||||
demodModeSelector->addChoice("DSB");
|
||||
demodModeSelector->addChoice("I/Q");
|
||||
demodModeSelector->setSelection("FM");
|
||||
demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band.");
|
||||
demodModeSelector->SetMinSize(wxSize(40,-1));
|
||||
demodModeSelector->SetMaxSize(wxSize(40,-1));
|
||||
demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0);
|
||||
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
demodModeSelectorAdv = new ModeSelectorCanvas(this, attribList);
|
||||
demodModeSelectorAdv->addChoice(0, "ASK");
|
||||
demodModeSelectorAdv->addChoice(1, "APSK");
|
||||
demodModeSelectorAdv->addChoice(2, "BPSK");
|
||||
demodModeSelectorAdv->addChoice(3, "DPSK");
|
||||
demodModeSelectorAdv->addChoice(4, "PSK");
|
||||
demodModeSelectorAdv->addChoice(5, "OOK");
|
||||
demodModeSelectorAdv->addChoice(6, "ST");
|
||||
demodModeSelectorAdv->addChoice(7, "SQAM");
|
||||
demodModeSelectorAdv->addChoice(8, "QAM");
|
||||
demodModeSelectorAdv->addChoice(9, "QPSK");
|
||||
demodModeSelectorAdv = new ModeSelectorCanvas(demodPanel, attribList);
|
||||
demodModeSelectorAdv->addChoice("ASK");
|
||||
demodModeSelectorAdv->addChoice("APSK");
|
||||
demodModeSelectorAdv->addChoice("BPSK");
|
||||
demodModeSelectorAdv->addChoice("DPSK");
|
||||
demodModeSelectorAdv->addChoice("PSK");
|
||||
demodModeSelectorAdv->addChoice("FSK");
|
||||
demodModeSelectorAdv->addChoice("GMSK");
|
||||
demodModeSelectorAdv->addChoice("OOK");
|
||||
demodModeSelectorAdv->addChoice("ST");
|
||||
demodModeSelectorAdv->addChoice("SQAM");
|
||||
demodModeSelectorAdv->addChoice("QAM");
|
||||
demodModeSelectorAdv->addChoice("QPSK");
|
||||
demodModeSelectorAdv->setHelpTip("Choose advanced modulation types.");
|
||||
demodModeSelectorAdv->SetMinSize(wxSize(40,-1));
|
||||
demodModeSelectorAdv->SetMaxSize(wxSize(40,-1));
|
||||
demodTray->Add(demodModeSelectorAdv, 3, wxEXPAND | wxALL, 0);
|
||||
|
||||
demodModeSelectorCons = new ModeSelectorCanvas(this, attribList);
|
||||
demodModeSelectorCons->addChoice(1, "auto");
|
||||
demodModeSelectorCons->addChoice(2, "2");
|
||||
demodModeSelectorCons->addChoice(4, "4");
|
||||
demodModeSelectorCons->addChoice(8, "8");
|
||||
demodModeSelectorCons->addChoice(16, "16");
|
||||
demodModeSelectorCons->addChoice(32, "32");
|
||||
demodModeSelectorCons->addChoice(64, "64");
|
||||
demodModeSelectorCons->addChoice(128, "128");
|
||||
demodModeSelectorCons->addChoice(256, "256");
|
||||
demodModeSelectorCons->setHelpTip("Choose number of constallations types.");
|
||||
demodTray->Add(demodModeSelectorCons, 2, wxEXPAND | wxALL, 0);
|
||||
#endif
|
||||
|
||||
modemPropertiesUpdated.store(false);
|
||||
modemProps = new ModemProperties(demodPanel, wxID_ANY);
|
||||
modemProps->SetMinSize(wxSize(200,-1));
|
||||
modemProps->SetMaxSize(wxSize(200,-1));
|
||||
|
||||
modemProps->Hide();
|
||||
demodTray->Add(modemProps, 15, wxEXPAND | wxALL, 0);
|
||||
|
||||
wxGetApp().getDemodSpectrumProcessor()->setup(1024);
|
||||
demodSpectrumCanvas = new SpectrumCanvas(demodPanel, attribList);
|
||||
demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
|
||||
@ -119,11 +120,14 @@ AppFrame::AppFrame() :
|
||||
demodWaterfallCanvas->setup(1024, 128);
|
||||
demodWaterfallCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000);
|
||||
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
|
||||
demodWaterfallCanvas->setMinBandwidth(8000);
|
||||
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
|
||||
demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0);
|
||||
wxGetApp().getDemodSpectrumProcessor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue());
|
||||
demodWaterfallCanvas->getVisualDataQueue()->set_max_num_items(3);
|
||||
|
||||
demodVisuals->SetMinSize(wxSize(128,-1));
|
||||
|
||||
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
|
||||
|
||||
demodTray->AddSpacer(1);
|
||||
@ -142,6 +146,7 @@ AppFrame::AppFrame() :
|
||||
|
||||
scopeCanvas = new ScopeCanvas(demodPanel, attribList);
|
||||
scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum.");
|
||||
scopeCanvas->SetMinSize(wxSize(128,-1));
|
||||
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
||||
wxGetApp().getScopeProcessor()->setup(2048);
|
||||
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
|
||||
@ -833,7 +838,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
|
||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
if (demod) {
|
||||
if (demod && demod->isModemInitialized()) {
|
||||
if (demod->isTracking()) {
|
||||
if (spectrumCanvas->getViewState()) {
|
||||
long long diff = abs(demod->getFrequency() - spectrumCanvas->getCenterFrequency()) + (demod->getBandwidth()/2) + (demod->getBandwidth()/4);
|
||||
@ -851,6 +856,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
demod->setTracking(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (demod->getBandwidth() != wxGetApp().getDemodMgr().getLastBandwidth()) {
|
||||
wxGetApp().getDemodMgr().setLastBandwidth(demod->getBandwidth());
|
||||
}
|
||||
|
||||
if (demod != activeDemodulator) {
|
||||
demodSignalMeter->setInputValue(demod->getSquelchLevel());
|
||||
@ -861,11 +870,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
std::string dType = demod->getDemodulatorType();
|
||||
demodModeSelector->setSelection(dType);
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
int dCons = demod->getDemodulatorCons();
|
||||
demodModeSelectorAdv->setSelection(dType);
|
||||
demodModeSelectorCons->setSelection(dCons);
|
||||
#endif
|
||||
demodMuteButton->setSelection(demod->isMuted()?1:-1);
|
||||
modemPropertiesUpdated.store(true);
|
||||
}
|
||||
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
|
||||
long long centerFreq = demod->getFrequency();
|
||||
@ -895,7 +903,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
std::string dSelection = demodModeSelector->getSelectionLabel();
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel();
|
||||
int dSelectionCons = demodModeSelectorCons->getSelection();
|
||||
|
||||
// basic demodulators
|
||||
if (dSelection != "" && dSelection != demod->getDemodulatorType()) {
|
||||
@ -907,11 +914,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
demod->setDemodulatorType(dSelectionadv);
|
||||
demodModeSelector->setSelection(-1);
|
||||
}
|
||||
|
||||
// set constellations
|
||||
if (dSelectionCons != demod->getDemodulatorCons()) {
|
||||
demod->setDemodulatorCons(dSelectionCons);
|
||||
}
|
||||
#else
|
||||
// basic demodulators
|
||||
if (dSelection != "" && dSelection != demod->getDemodulatorType()) {
|
||||
@ -951,13 +953,14 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
demodGainMeter->setLevel(demodGainMeter->getInputValue());
|
||||
}
|
||||
activeDemodulator = demod;
|
||||
} else if (demod) {
|
||||
// Wait state for current demodulator modem to activate..
|
||||
} else {
|
||||
DemodulatorMgr *mgr = &wxGetApp().getDemodMgr();
|
||||
|
||||
std::string dSelection = demodModeSelector->getSelectionLabel();
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
std::string dSelectionadv = demodModeSelectorAdv->getSelectionLabel();
|
||||
int dSelectionCons = demodModeSelectorCons->getSelection();
|
||||
|
||||
// basic demodulators
|
||||
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
|
||||
@ -969,11 +972,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
mgr->setLastDemodulatorType(dSelectionadv);
|
||||
demodModeSelector->setSelection(-1);
|
||||
}
|
||||
|
||||
// set constellations
|
||||
if (dSelectionCons != mgr->getLastDemodulatorCons()) {
|
||||
mgr->setLastDemodulatorCons(dSelectionCons);
|
||||
}
|
||||
#else
|
||||
// basic demodulators
|
||||
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
|
||||
@ -1012,7 +1010,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
if (!demodTuner->HasFocus()) {
|
||||
demodTuner->SetFocus();
|
||||
}
|
||||
} else if (!wxGetApp().isDeviceSelectorOpen()) {
|
||||
} else if (!wxGetApp().isDeviceSelectorOpen() && (!modemProps || !modemProps->isMouseInView())) {
|
||||
if (!waterfallCanvas->HasFocus()) {
|
||||
waterfallCanvas->SetFocus();
|
||||
}
|
||||
@ -1026,7 +1024,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
wxGetApp().getAudioVisualQueue()->set_max_num_items((scopeCanvas->scopeVisible()?1:0) + (scopeCanvas->spectrumVisible()?1:0));
|
||||
|
||||
wxGetApp().getScopeProcessor()->run();
|
||||
// wxGetApp().getSpectrumDistributor()->run();
|
||||
|
||||
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor();
|
||||
|
||||
@ -1069,11 +1066,24 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
|
||||
wxGetApp().getSDRPostThread()->setIQVisualRange(waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth());
|
||||
|
||||
// waterfallCanvas->processInputQueue();
|
||||
// waterfallCanvas->Refresh();
|
||||
// demodWaterfallCanvas->processInputQueue();
|
||||
// demodWaterfallCanvas->Refresh();
|
||||
|
||||
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
|
||||
if (modemPropertiesUpdated.load() && demod && demod->isModemInitialized()) {
|
||||
modemProps->initProperties(demod->getModemArgs());
|
||||
modemPropertiesUpdated.store(false);
|
||||
demodTray->Layout();
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (demod->getModemType() == "digital") {
|
||||
ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)demod->getOutput();
|
||||
if (!outp->getDialog()) {
|
||||
outp->setTitle(demod->getDemodulatorType() + ": " + frequencyToStr(demod->getFrequency()));
|
||||
outp->setDialog(new DigitalConsole(this, outp));
|
||||
}
|
||||
demod->showOutput();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!this->IsActive()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(25));
|
||||
}
|
||||
@ -1134,6 +1144,14 @@ void AppFrame::saveSession(std::string fileName) {
|
||||
*demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name;
|
||||
*demod->newChild("gain") = (*instance_i)->getGain();
|
||||
*demod->newChild("muted") = (*instance_i)->isMuted() ? 1 : 0;
|
||||
|
||||
ModemSettings saveSettings = (*instance_i)->readModemSettings();
|
||||
if (saveSettings.size()) {
|
||||
DataNode *settingsNode = demod->newChild("settings");
|
||||
for (ModemSettings::const_iterator msi = saveSettings.begin(); msi != saveSettings.end(); msi++) {
|
||||
*settingsNode->newChild(msi->first.c_str()) = msi->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.SaveToFileXML(fileName);
|
||||
@ -1177,35 +1195,79 @@ bool AppFrame::loadSession(std::string fileName) {
|
||||
|
||||
long bandwidth = *demod->getNext("bandwidth");
|
||||
long long freq = *demod->getNext("frequency");
|
||||
std::string type = demod->hasAnother("type") ? string(*demod->getNext("type")) : "FM";
|
||||
float squelch_level = demod->hasAnother("squelch_level") ? (float) *demod->getNext("squelch_level") : 0;
|
||||
int squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0;
|
||||
int muted = demod->hasAnother("muted") ? (int) *demod->getNext("muted") : 0;
|
||||
std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : "";
|
||||
float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0;
|
||||
|
||||
// TODO: Check if "type" is numeric and perform update to new values
|
||||
//#define DEMOD_TYPE_NULL 0
|
||||
//#define DEMOD_TYPE_FM 1
|
||||
//#define DEMOD_TYPE_AM 2
|
||||
//#define DEMOD_TYPE_LSB 3
|
||||
//#define DEMOD_TYPE_USB 4
|
||||
//#define DEMOD_TYPE_DSB 5
|
||||
//#define DEMOD_TYPE_ASK 6
|
||||
//#define DEMOD_TYPE_APSK 7
|
||||
//#define DEMOD_TYPE_BPSK 8
|
||||
//#define DEMOD_TYPE_DPSK 9
|
||||
//#define DEMOD_TYPE_PSK 10
|
||||
//#define DEMOD_TYPE_OOK 11
|
||||
//#define DEMOD_TYPE_ST 12
|
||||
//#define DEMOD_TYPE_SQAM 13
|
||||
//#define DEMOD_TYPE_QAM 14
|
||||
//#define DEMOD_TYPE_QPSK 15
|
||||
//#define DEMOD_TYPE_RAW 16
|
||||
std::string type = "FM";
|
||||
|
||||
DataNode *demodTypeNode = demod->hasAnother("type")?demod->getNext("type"):nullptr;
|
||||
|
||||
if (demodTypeNode->element()->getDataType() == DATA_INT) {
|
||||
int legacyType = *demodTypeNode;
|
||||
int legacyStereo = demod->hasAnother("stereo") ? (int) *demod->getNext("stereo") : 0;
|
||||
switch (legacyType) { // legacy demod ID
|
||||
case 1: type = legacyStereo?"FMS":"FM"; break;
|
||||
case 2: type = "AM"; break;
|
||||
case 3: type = "LSB"; break;
|
||||
case 4: type = "USB"; break;
|
||||
case 5: type = "DSB"; break;
|
||||
case 6: type = "ASK"; break;
|
||||
case 7: type = "APSK"; break;
|
||||
case 8: type = "BPSK"; break;
|
||||
case 9: type = "DPSK"; break;
|
||||
case 10: type = "PSK"; break;
|
||||
case 11: type = "OOK"; break;
|
||||
case 12: type = "ST"; break;
|
||||
case 13: type = "SQAM"; break;
|
||||
case 14: type = "QAM"; break;
|
||||
case 15: type = "QPSK"; break;
|
||||
case 16: type = "I/Q"; break;
|
||||
default: type = "FM"; break;
|
||||
}
|
||||
} else if (demodTypeNode->element()->getDataType() == DATA_STRING) {
|
||||
demodTypeNode->element()->get(type);
|
||||
}
|
||||
|
||||
ModemSettings mSettings;
|
||||
|
||||
if (demod->hasAnother("settings")) {
|
||||
DataNode *modemSettings = demod->getNext("settings");
|
||||
for (int msi = 0, numSettings = modemSettings->numChildren(); msi < numSettings; msi++) {
|
||||
DataNode *settingNode = modemSettings->child(msi);
|
||||
std::string keyName = settingNode->getName();
|
||||
std::string strSettingValue = "";
|
||||
|
||||
int dataType = settingNode->element()->getDataType();
|
||||
|
||||
try {
|
||||
if (dataType == DATA_STRING) {
|
||||
settingNode->element()->get(strSettingValue);
|
||||
} else if (dataType == DATA_INT || dataType == DATA_LONG || dataType == DATA_LONGLONG) {
|
||||
long long intSettingValue = *settingNode;
|
||||
strSettingValue = std::to_string(intSettingValue);
|
||||
} else if (dataType == DATA_FLOAT || dataType == DATA_DOUBLE) {
|
||||
double floatSettingValue = *settingNode;
|
||||
strSettingValue = std::to_string(floatSettingValue);
|
||||
} else {
|
||||
std::cout << "Unhandled setting data type: " << dataType << std::endl;
|
||||
}
|
||||
} catch (DataTypeMismatchException e) {
|
||||
std::cout << "Setting data type mismatch: " << dataType << std::endl;
|
||||
}
|
||||
|
||||
if (keyName != "" && strSettingValue != "") {
|
||||
mSettings[keyName] = strSettingValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DemodulatorInstance *newDemod = wxGetApp().getDemodMgr().newThread();
|
||||
loadedDemod = newDemod;
|
||||
numDemodulators++;
|
||||
newDemod->writeModemSettings(mSettings);
|
||||
newDemod->setDemodulatorType(type);
|
||||
newDemod->setBandwidth(bandwidth);
|
||||
newDemod->setFrequency(freq);
|
||||
@ -1269,3 +1331,8 @@ FFTVisualDataThread *AppFrame::getWaterfallDataThread() {
|
||||
return waterfallDataThread;
|
||||
}
|
||||
|
||||
void AppFrame::updateModemProperties(ModemArgInfoList args) {
|
||||
newModemArgs = args;
|
||||
modemPropertiesUpdated.store(true);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "GainCanvas.h"
|
||||
#include "FFTVisualDataThread.h"
|
||||
#include "SDRDeviceInfo.h"
|
||||
#include "ModemProperties.h"
|
||||
//#include "UITestCanvas.h"
|
||||
|
||||
#include <map>
|
||||
@ -67,6 +68,8 @@ public:
|
||||
|
||||
FFTVisualDataThread *getWaterfallDataThread();
|
||||
|
||||
void updateModemProperties(ModemArgInfoList args);
|
||||
|
||||
private:
|
||||
void OnMenu(wxCommandEvent& event);
|
||||
void OnClose(wxCloseEvent& event);
|
||||
@ -81,7 +84,6 @@ private:
|
||||
ModeSelectorCanvas *demodModeSelector;
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
ModeSelectorCanvas *demodModeSelectorAdv;
|
||||
ModeSelectorCanvas *demodModeSelectorCons;
|
||||
#endif
|
||||
SpectrumCanvas *demodSpectrumCanvas;
|
||||
WaterfallCanvas *demodWaterfallCanvas;
|
||||
@ -121,6 +123,10 @@ private:
|
||||
std::thread *t_FFTData;
|
||||
SDRDeviceInfo *devInfo;
|
||||
std::atomic_bool deviceChanged;
|
||||
|
||||
ModemProperties *modemProps;
|
||||
std::atomic_bool modemPropertiesUpdated;
|
||||
ModemArgInfoList newModemArgs;
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
@ -20,20 +20,20 @@
|
||||
|
||||
IMPLEMENT_APP(CubicSDR)
|
||||
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
// console output buffer for windows
|
||||
#ifdef _WINDOWS
|
||||
class outbuf : public std::streambuf {
|
||||
public:
|
||||
outbuf() {
|
||||
setp(0, 0);
|
||||
}
|
||||
virtual int_type overflow(int_type c = traits_type::eof()) {
|
||||
return fputc(c, stdout) == EOF ? traits_type::eof() : c;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
//#ifdef ENABLE_DIGITAL_LAB
|
||||
//// console output buffer for windows
|
||||
//#ifdef _WINDOWS
|
||||
//class outbuf : public std::streambuf {
|
||||
// public:
|
||||
// outbuf() {
|
||||
// setp(0, 0);
|
||||
// }
|
||||
// virtual int_type overflow(int_type c = traits_type::eof()) {
|
||||
// return fputc(c, stdout) == EOF ? traits_type::eof() : c;
|
||||
// }
|
||||
//};
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
#ifdef MINGW_PATCH
|
||||
FILE _iob[] = { *stdin, *stdout, *stderr };
|
||||
@ -149,18 +149,18 @@ bool CubicSDR::OnInit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
// console output for windows
|
||||
#ifdef _WINDOWS
|
||||
if (AllocConsole()) {
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
|
||||
}
|
||||
outbuf ob;
|
||||
std::streambuf *sb = std::cout.rdbuf(&ob);
|
||||
std::cout.rdbuf(sb);
|
||||
#endif
|
||||
#endif
|
||||
//#ifdef ENABLE_DIGITAL_LAB
|
||||
// // console output for windows
|
||||
// #ifdef _WINDOWS
|
||||
// if (AllocConsole()) {
|
||||
// freopen("CONOUT$", "w", stdout);
|
||||
// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
|
||||
// }
|
||||
// outbuf ob;
|
||||
// std::streambuf *sb = std::cout.rdbuf(&ob);
|
||||
// std::cout.rdbuf(sb);
|
||||
// #endif
|
||||
//#endif
|
||||
|
||||
wxApp::SetAppName("CubicSDR");
|
||||
|
||||
@ -172,17 +172,23 @@ bool CubicSDR::OnInit() {
|
||||
Modem::addModemFactory(new ModemDSB);
|
||||
Modem::addModemFactory(new ModemIQ);
|
||||
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
Modem::addModemFactory(new ModemAPSK);
|
||||
Modem::addModemFactory(new ModemASK);
|
||||
Modem::addModemFactory(new ModemBPSK);
|
||||
Modem::addModemFactory(new ModemDPSK);
|
||||
#if ENABLE_LIQUID_EXPERIMENTAL
|
||||
Modem::addModemFactory(new ModemFSK);
|
||||
#endif
|
||||
Modem::addModemFactory(new ModemGMSK);
|
||||
Modem::addModemFactory(new ModemOOK);
|
||||
Modem::addModemFactory(new ModemPSK);
|
||||
Modem::addModemFactory(new ModemQAM);
|
||||
Modem::addModemFactory(new ModemQPSK);
|
||||
Modem::addModemFactory(new ModemSQAM);
|
||||
Modem::addModemFactory(new ModemST);
|
||||
|
||||
#endif
|
||||
|
||||
frequency = wxGetApp().getConfig()->getCenterFreq();
|
||||
offset = 0;
|
||||
ppm = 0;
|
||||
|
@ -37,16 +37,22 @@
|
||||
#include "ModemDSB.h"
|
||||
#include "ModemIQ.h"
|
||||
|
||||
#ifdef ENABLE_DIGITAL_LAB
|
||||
#include "ModemAPSK.h"
|
||||
#include "ModemASK.h"
|
||||
#include "ModemBPSK.h"
|
||||
#include "ModemDPSK.h"
|
||||
#if ENABLE_LIQUID_EXPERIMENTAL
|
||||
#include "ModemFSK.h"
|
||||
#endif
|
||||
#include "ModemGMSK.h"
|
||||
#include "ModemOOK.h"
|
||||
#include "ModemPSK.h"
|
||||
#include "ModemQAM.h"
|
||||
#include "ModemQPSK.h"
|
||||
#include "ModemSQAM.h"
|
||||
#include "ModemST.h"
|
||||
#endif
|
||||
|
||||
#include <wx/cmdline.h>
|
||||
|
||||
@ -123,7 +129,6 @@ public:
|
||||
void setDeviceSelectorClosed();
|
||||
bool isDeviceSelectorOpen();
|
||||
void closeDeviceSelector();
|
||||
|
||||
|
||||
void setAGCMode(bool mode);
|
||||
bool getAGCMode();
|
||||
|
179
src/ModemProperties.cpp
Normal file
179
src/ModemProperties.cpp
Normal 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
39
src/ModemProperties.h
Normal 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;
|
||||
};
|
@ -18,6 +18,7 @@ public:
|
||||
int sampleRate;
|
||||
int channels;
|
||||
float peak;
|
||||
int type;
|
||||
std::vector<float> data;
|
||||
std::mutex busy_update;
|
||||
|
||||
|
@ -14,9 +14,6 @@ class DemodulatorThreadCommand {
|
||||
public:
|
||||
enum DemodulatorThreadCommandEnum {
|
||||
DEMOD_THREAD_CMD_NULL,
|
||||
DEMOD_THREAD_CMD_SET_BANDWIDTH,
|
||||
DEMOD_THREAD_CMD_SET_FREQUENCY,
|
||||
DEMOD_THREAD_CMD_SET_AUDIO_RATE,
|
||||
DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED,
|
||||
DEMOD_THREAD_CMD_DEMOD_TERMINATED,
|
||||
DEMOD_THREAD_CMD_AUDIO_TERMINATED
|
||||
@ -82,6 +79,7 @@ class DemodulatorThreadPostIQData: public ReferenceCounter {
|
||||
public:
|
||||
std::vector<liquid_float_complex> data;
|
||||
long long sampleRate;
|
||||
std::string modemName;
|
||||
std::string modemType;
|
||||
Modem *modem;
|
||||
ModemKit *modemKit;
|
||||
@ -124,23 +122,3 @@ typedef ThreadQueue<DemodulatorThreadIQData *> DemodulatorThreadInputQueue;
|
||||
typedef ThreadQueue<DemodulatorThreadPostIQData *> DemodulatorThreadPostInputQueue;
|
||||
typedef ThreadQueue<DemodulatorThreadCommand> DemodulatorThreadCommandQueue;
|
||||
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() {
|
||||
|
||||
}
|
||||
};
|
||||
|
@ -1,8 +1,12 @@
|
||||
#include "DemodulatorInstance.h"
|
||||
#include "CubicSDR.h"
|
||||
|
||||
DemodulatorInstance::DemodulatorInstance() :
|
||||
t_PreDemod(NULL), t_Demod(NULL), t_Audio(NULL) {
|
||||
t_PreDemod(nullptr), t_Demod(nullptr), t_Audio(nullptr) {
|
||||
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
activeOutput = nullptr;
|
||||
#endif
|
||||
terminated.store(true);
|
||||
audioTerminated.store(true);
|
||||
demodTerminated.store(true);
|
||||
@ -12,23 +16,20 @@ DemodulatorInstance::DemodulatorInstance() :
|
||||
muted.store(false);
|
||||
tracking.store(false);
|
||||
follow.store(false);
|
||||
currentAudioSampleRate.store(0);
|
||||
currentFrequency.store(0);
|
||||
currentBandwidth.store(0);
|
||||
currentOutputDevice.store(-1);
|
||||
currentAudioGain.store(1.0);
|
||||
|
||||
label = new std::string("Unnamed");
|
||||
pipeIQInputData = new DemodulatorThreadInputQueue;
|
||||
pipeIQDemodData = new DemodulatorThreadPostInputQueue;
|
||||
pipeDemodCommand = new DemodulatorThreadCommandQueue;
|
||||
pipeDemodNotify = new DemodulatorThreadCommandQueue;
|
||||
|
||||
demodulatorPreThread = new DemodulatorPreThread();
|
||||
audioThread = new AudioThread();
|
||||
|
||||
demodulatorPreThread = new DemodulatorPreThread(this);
|
||||
demodulatorPreThread->setInputQueue("IQDataInput",pipeIQInputData);
|
||||
demodulatorPreThread->setOutputQueue("IQDataOutput",pipeIQDemodData);
|
||||
demodulatorPreThread->setOutputQueue("NotifyQueue",pipeDemodNotify);
|
||||
demodulatorPreThread->setInputQueue("CommandQueue",pipeDemodCommand);
|
||||
|
||||
pipeAudioData = new AudioThreadInputQueue;
|
||||
threadQueueControl = new DemodulatorThreadControlCommandQueue;
|
||||
@ -39,20 +40,19 @@ DemodulatorInstance::DemodulatorInstance() :
|
||||
demodulatorThread->setOutputQueue("NotifyQueue",pipeDemodNotify);
|
||||
demodulatorThread->setOutputQueue("AudioDataOutput", pipeAudioData);
|
||||
|
||||
audioThread = new AudioThread();
|
||||
audioThread->setInputQueue("AudioDataInput", pipeAudioData);
|
||||
audioThread->setOutputQueue("NotifyQueue", pipeDemodNotify);
|
||||
|
||||
currentDemodType = demodulatorPreThread->getParams().demodType;
|
||||
}
|
||||
|
||||
DemodulatorInstance::~DemodulatorInstance() {
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
delete activeOutput;
|
||||
#endif
|
||||
delete audioThread;
|
||||
delete demodulatorThread;
|
||||
delete demodulatorPreThread;
|
||||
delete pipeIQInputData;
|
||||
delete pipeIQDemodData;
|
||||
delete pipeDemodCommand;
|
||||
delete pipeDemodNotify;
|
||||
delete threadQueueControl;
|
||||
delete pipeAudioData;
|
||||
@ -67,17 +67,8 @@ void DemodulatorInstance::run() {
|
||||
return;
|
||||
}
|
||||
|
||||
// while (!isTerminated()) {
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
// }
|
||||
|
||||
currentFrequency = demodulatorPreThread->getParams().frequency;
|
||||
currentAudioSampleRate = AudioThread::deviceSampleRate[getOutputDevice()];
|
||||
demodulatorPreThread->getParams().audioSampleRate = currentAudioSampleRate;
|
||||
setDemodulatorType(demodulatorPreThread->getParams().demodType);
|
||||
|
||||
t_Audio = new std::thread(&AudioThread::threadMain, audioThread);
|
||||
|
||||
|
||||
#ifdef __APPLE__ // Already using pthreads, might as well do some custom init..
|
||||
pthread_attr_t attr;
|
||||
size_t size;
|
||||
@ -113,10 +104,6 @@ void DemodulatorInstance::updateLabel(long long freq) {
|
||||
setLabel(newLabel.str());
|
||||
}
|
||||
|
||||
DemodulatorThreadCommandQueue *DemodulatorInstance::getCommandQueue() {
|
||||
return pipeDemodCommand;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::terminate() {
|
||||
std::cout << "Terminating demodulator audio thread.." << std::endl;
|
||||
audioThread->terminate();
|
||||
@ -156,6 +143,11 @@ bool DemodulatorInstance::isTerminated() {
|
||||
#else
|
||||
t_Demod->join();
|
||||
delete t_Demod;
|
||||
#endif
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (activeOutput) {
|
||||
closeOutput();
|
||||
}
|
||||
#endif
|
||||
demodTerminated = true;
|
||||
break;
|
||||
@ -184,8 +176,18 @@ bool DemodulatorInstance::isActive() {
|
||||
|
||||
void DemodulatorInstance::setActive(bool state) {
|
||||
if (active && !state) {
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (activeOutput && !isTerminated()) {
|
||||
activeOutput->Hide();
|
||||
}
|
||||
#endif
|
||||
audioThread->setActive(state);
|
||||
} else if (!active && state) {
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (activeOutput && getModemType() == "digital") {
|
||||
activeOutput->Show();
|
||||
}
|
||||
#endif
|
||||
audioThread->setActive(state);
|
||||
}
|
||||
if (!state) {
|
||||
@ -225,6 +227,8 @@ float DemodulatorInstance::getSignalLevel() {
|
||||
|
||||
void DemodulatorInstance::setSquelchLevel(float signal_level_in) {
|
||||
demodulatorThread->setSquelchLevel(signal_level_in);
|
||||
wxGetApp().getDemodMgr().setLastSquelchLevel(signal_level_in);
|
||||
wxGetApp().getDemodMgr().setLastSquelchEnabled(true);
|
||||
}
|
||||
|
||||
float DemodulatorInstance::getSquelchLevel() {
|
||||
@ -254,35 +258,36 @@ int DemodulatorInstance::getOutputDevice() {
|
||||
return currentOutputDevice;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::checkBandwidth() {
|
||||
// if ((currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB) && (getBandwidth() % 2)) {
|
||||
// setBandwidth(getBandwidth()+1);
|
||||
// }
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setDemodulatorType(std::string demod_type_in) {
|
||||
currentDemodType = demod_type_in;
|
||||
|
||||
if (currentDemodType == "I/Q") {
|
||||
if (currentAudioSampleRate) {
|
||||
setBandwidth(currentAudioSampleRate);
|
||||
} else {
|
||||
setBandwidth(AudioThread::deviceSampleRate[getOutputDevice()]);
|
||||
}
|
||||
}
|
||||
setGain(getGain());
|
||||
if (demodulatorPreThread) {
|
||||
std::string currentDemodType = demodulatorPreThread->getDemodType();
|
||||
if ((currentDemodType != "") && (currentDemodType != demod_type_in)) {
|
||||
lastModemSettings[currentDemodType] = demodulatorPreThread->readModemSettings();
|
||||
lastModemBandwidth[currentDemodType] = demodulatorPreThread->getBandwidth();
|
||||
}
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (activeOutput) {
|
||||
activeOutput->Hide();
|
||||
}
|
||||
#endif
|
||||
|
||||
demodulatorPreThread->getParams().demodType = currentDemodType;
|
||||
if (!active) {
|
||||
checkBandwidth();
|
||||
demodulatorPreThread->setDemodType(currentDemodType);
|
||||
} else if (demodulatorThread && threadQueueControl) {
|
||||
demodulatorPreThread->setDemodType(currentDemodType);
|
||||
demodulatorPreThread->setDemodType(demod_type_in);
|
||||
int lastbw = 0;
|
||||
if (currentDemodType != "" && lastModemBandwidth.find(demod_type_in) != lastModemBandwidth.end()) {
|
||||
lastbw = lastModemBandwidth[demod_type_in];
|
||||
}
|
||||
if (!lastbw) {
|
||||
lastbw = Modem::getModemDefaultSampleRate(demod_type_in);
|
||||
}
|
||||
if (lastbw) {
|
||||
setBandwidth(lastbw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string DemodulatorInstance::getDemodulatorType() {
|
||||
return currentDemodType;
|
||||
return demodulatorPreThread->getDemodType();
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setDemodulatorLock(bool demod_lock_in) {
|
||||
@ -302,101 +307,50 @@ int DemodulatorInstance::getDemodulatorLock() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setDemodulatorCons(int demod_cons_in) {
|
||||
Modem *cModem = demodulatorPreThread->getModem();
|
||||
if (cModem && cModem->getType() == "digital") {
|
||||
((ModemDigital *)cModem)->setDemodulatorCons(demod_cons_in);
|
||||
}
|
||||
}
|
||||
|
||||
int DemodulatorInstance::getDemodulatorCons() {
|
||||
Modem *cModem = demodulatorPreThread->getModem();
|
||||
if (cModem && cModem->getType() == "digital") {
|
||||
return ((ModemDigital *)cModem)->getDemodulatorCons();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setBandwidth(int bw) {
|
||||
if (currentDemodType == "I/Q") {
|
||||
if (currentAudioSampleRate) {
|
||||
bw = currentAudioSampleRate;
|
||||
} else {
|
||||
bw = AudioThread::deviceSampleRate[getOutputDevice()];
|
||||
}
|
||||
}
|
||||
if (!active && demodulatorPreThread != NULL) {
|
||||
currentBandwidth = bw;
|
||||
checkBandwidth();
|
||||
demodulatorPreThread->getParams().bandwidth = currentBandwidth;
|
||||
} else if (demodulatorPreThread && pipeDemodCommand) {
|
||||
DemodulatorThreadCommand command;
|
||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH;
|
||||
currentBandwidth = bw;
|
||||
checkBandwidth();
|
||||
command.llong_value = currentBandwidth;
|
||||
pipeDemodCommand->push(command);
|
||||
}
|
||||
demodulatorPreThread->setBandwidth(bw);
|
||||
}
|
||||
|
||||
int DemodulatorInstance::getBandwidth() {
|
||||
if (!currentBandwidth) {
|
||||
currentBandwidth = demodulatorPreThread->getParams().bandwidth;
|
||||
}
|
||||
return currentBandwidth;
|
||||
return demodulatorPreThread->getBandwidth();
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setFrequency(long long freq) {
|
||||
if ((freq - getBandwidth() / 2) <= 0) {
|
||||
freq = getBandwidth() / 2;
|
||||
}
|
||||
if (!active) {
|
||||
currentFrequency = freq;
|
||||
demodulatorPreThread->getParams().frequency = currentFrequency;
|
||||
} else if (demodulatorPreThread && pipeDemodCommand) {
|
||||
DemodulatorThreadCommand command;
|
||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY;
|
||||
currentFrequency = freq;
|
||||
command.llong_value = freq;
|
||||
pipeDemodCommand->push(command);
|
||||
|
||||
demodulatorPreThread->setFrequency(freq);
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (activeOutput) {
|
||||
if (isModemInitialized() && getModemType() == "digital") {
|
||||
ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)getOutput();
|
||||
outp->setTitle(getDemodulatorType() + ": " + frequencyToStr(getFrequency()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
long long DemodulatorInstance::getFrequency() {
|
||||
if (!currentFrequency) {
|
||||
currentFrequency = demodulatorPreThread->getParams().frequency;
|
||||
}
|
||||
return currentFrequency;
|
||||
return demodulatorPreThread->getFrequency();
|
||||
}
|
||||
|
||||
|
||||
void DemodulatorInstance::setAudioSampleRate(int sampleRate) {
|
||||
if (terminated) {
|
||||
currentAudioSampleRate = sampleRate;
|
||||
demodulatorPreThread->getParams().audioSampleRate = sampleRate;
|
||||
} else if (demodulatorPreThread && pipeDemodCommand) {
|
||||
DemodulatorThreadCommand command;
|
||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE;
|
||||
currentAudioSampleRate = sampleRate;
|
||||
command.llong_value = sampleRate;
|
||||
pipeDemodCommand->push(command);
|
||||
}
|
||||
if (currentDemodType == "I/Q") {
|
||||
setBandwidth(currentAudioSampleRate);
|
||||
}
|
||||
demodulatorPreThread->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
int DemodulatorInstance::getAudioSampleRate() {
|
||||
if (!currentAudioSampleRate) {
|
||||
currentAudioSampleRate = audioThread->getSampleRate();
|
||||
if (!audioThread) {
|
||||
return 0;
|
||||
}
|
||||
return currentAudioSampleRate;
|
||||
return audioThread->getSampleRate();
|
||||
}
|
||||
|
||||
|
||||
void DemodulatorInstance::setGain(float gain_in) {
|
||||
currentAudioGain = gain_in;
|
||||
audioThread->setGain(gain_in);
|
||||
wxGetApp().getDemodMgr().setLastGain(gain_in);
|
||||
}
|
||||
|
||||
float DemodulatorInstance::getGain() {
|
||||
@ -426,8 +380,91 @@ bool DemodulatorInstance::isMuted() {
|
||||
void DemodulatorInstance::setMuted(bool muted) {
|
||||
this->muted = muted;
|
||||
demodulatorThread->setMuted(muted);
|
||||
wxGetApp().getDemodMgr().setLastMuted(muted);
|
||||
}
|
||||
|
||||
DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() {
|
||||
return pipeIQInputData;
|
||||
}
|
||||
|
||||
ModemArgInfoList DemodulatorInstance::getModemArgs() {
|
||||
Modem *m = demodulatorPreThread->getModem();
|
||||
|
||||
ModemArgInfoList args;
|
||||
if (m != nullptr) {
|
||||
args = m->getSettings();
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
std::string DemodulatorInstance::readModemSetting(std::string setting) {
|
||||
return demodulatorPreThread->readModemSetting(setting);
|
||||
}
|
||||
|
||||
void DemodulatorInstance::writeModemSetting(std::string setting, std::string value) {
|
||||
demodulatorPreThread->writeModemSetting(setting, value);
|
||||
}
|
||||
|
||||
ModemSettings DemodulatorInstance::readModemSettings() {
|
||||
return demodulatorPreThread->readModemSettings();
|
||||
}
|
||||
|
||||
void DemodulatorInstance::writeModemSettings(ModemSettings settings) {
|
||||
demodulatorPreThread->writeModemSettings(settings);
|
||||
}
|
||||
|
||||
bool DemodulatorInstance::isModemInitialized() {
|
||||
if (!demodulatorPreThread || isTerminated()) {
|
||||
return false;
|
||||
}
|
||||
return demodulatorPreThread->isInitialized();
|
||||
}
|
||||
|
||||
std::string DemodulatorInstance::getModemType() {
|
||||
if (isModemInitialized()) {
|
||||
return demodulatorPreThread->getModem()->getType();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
ModemSettings DemodulatorInstance::getLastModemSettings(std::string demodType) {
|
||||
if (lastModemSettings.find(demodType) != lastModemSettings.end()) {
|
||||
return lastModemSettings[demodType];
|
||||
} else {
|
||||
ModemSettings mods;
|
||||
return mods;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
ModemDigitalOutput *DemodulatorInstance::getOutput() {
|
||||
if (activeOutput == nullptr) {
|
||||
activeOutput = new ModemDigitalOutputConsole();
|
||||
}
|
||||
return activeOutput;
|
||||
}
|
||||
|
||||
void DemodulatorInstance::showOutput() {
|
||||
if (activeOutput != nullptr) {
|
||||
activeOutput->Show();
|
||||
}
|
||||
}
|
||||
|
||||
void DemodulatorInstance::hideOutput() {
|
||||
if (activeOutput != nullptr) {
|
||||
activeOutput->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void DemodulatorInstance::closeOutput() {
|
||||
if (isModemInitialized()) {
|
||||
if (getModemType() == "digital") {
|
||||
ModemDigital *dModem = (ModemDigital *)demodulatorPreThread->getModem();
|
||||
dModem->setOutput(nullptr);
|
||||
}
|
||||
}
|
||||
if (activeOutput) {
|
||||
activeOutput->Close();
|
||||
}
|
||||
}
|
||||
#endif
|
@ -10,6 +10,10 @@
|
||||
#include "ModemDigital.h"
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
#include "DigitalConsole.h"
|
||||
#endif
|
||||
|
||||
class DemodulatorInstance {
|
||||
public:
|
||||
|
||||
@ -58,9 +62,6 @@ public:
|
||||
|
||||
void setDemodulatorLock(bool demod_lock_in);
|
||||
int getDemodulatorLock();
|
||||
|
||||
void setDemodulatorCons(int demod_cons_in);
|
||||
int getDemodulatorCons();
|
||||
|
||||
void setBandwidth(int bw);
|
||||
int getBandwidth();
|
||||
@ -73,7 +74,7 @@ public:
|
||||
|
||||
void setAudioSampleRate(int sampleRate);
|
||||
int getAudioSampleRate();
|
||||
|
||||
|
||||
bool isFollow();
|
||||
void setFollow(bool follow);
|
||||
|
||||
@ -85,11 +86,27 @@ public:
|
||||
|
||||
DemodulatorThreadInputQueue *getIQInputDataPipe();
|
||||
|
||||
ModemArgInfoList getModemArgs();
|
||||
std::string readModemSetting(std::string setting);
|
||||
ModemSettings readModemSettings();
|
||||
void writeModemSetting(std::string setting, std::string value);
|
||||
void writeModemSettings(ModemSettings settings);
|
||||
|
||||
bool isModemInitialized();
|
||||
std::string getModemType();
|
||||
ModemSettings getLastModemSettings(std::string demodType);
|
||||
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
ModemDigitalOutput *getOutput();
|
||||
void showOutput();
|
||||
void hideOutput();
|
||||
void closeOutput();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
DemodulatorThreadInputQueue* pipeIQInputData;
|
||||
DemodulatorThreadPostInputQueue* pipeIQDemodData;
|
||||
AudioThreadInputQueue *pipeAudioData;
|
||||
DemodulatorThreadCommandQueue* pipeDemodCommand;
|
||||
DemodulatorThreadCommandQueue* pipeDemodNotify;
|
||||
DemodulatorPreThread *demodulatorPreThread;
|
||||
DemodulatorThread *demodulatorThread;
|
||||
@ -97,8 +114,6 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
void checkBandwidth();
|
||||
|
||||
std::atomic<std::string *> label; //
|
||||
std::atomic_bool terminated; //
|
||||
std::atomic_bool demodTerminated; //
|
||||
@ -108,11 +123,12 @@ private:
|
||||
std::atomic_bool squelch;
|
||||
std::atomic_bool muted;
|
||||
|
||||
std::atomic_llong currentFrequency;
|
||||
std::atomic_int currentBandwidth;
|
||||
std::string currentDemodType;
|
||||
std::atomic_int currentOutputDevice;
|
||||
std::atomic_int currentAudioSampleRate;
|
||||
std::atomic<float> currentAudioGain;
|
||||
std::atomic_bool follow, tracking;
|
||||
};
|
||||
std::map<std::string, ModemSettings> lastModemSettings;
|
||||
std::map<std::string, int> lastModemBandwidth;
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
ModemDigitalOutput *activeOutput;
|
||||
#endif
|
||||
};
|
||||
|
@ -8,7 +8,6 @@
|
||||
DemodulatorMgr::DemodulatorMgr() :
|
||||
activeDemodulator(NULL), lastActiveDemodulator(NULL), activeVisualDemodulator(NULL), lastBandwidth(DEFAULT_DEMOD_BW), lastDemodType(
|
||||
DEFAULT_DEMOD_TYPE), lastSquelchEnabled(false), lastSquelch(-100), lastGain(1.0), lastMuted(false) {
|
||||
|
||||
}
|
||||
|
||||
DemodulatorMgr::~DemodulatorMgr() {
|
||||
@ -88,6 +87,7 @@ void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool tempo
|
||||
if (!temporary) {
|
||||
if (activeDemodulator != NULL) {
|
||||
lastActiveDemodulator = activeDemodulator;
|
||||
updateLastState();
|
||||
} else {
|
||||
lastActiveDemodulator = demod;
|
||||
}
|
||||
@ -121,8 +121,6 @@ DemodulatorInstance *DemodulatorMgr::getActiveDemodulator() {
|
||||
}
|
||||
|
||||
DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() {
|
||||
updateLastState();
|
||||
|
||||
return lastActiveDemodulator;
|
||||
}
|
||||
|
||||
@ -162,10 +160,10 @@ void DemodulatorMgr::updateLastState() {
|
||||
lastBandwidth = lastActiveDemodulator->getBandwidth();
|
||||
lastDemodType = lastActiveDemodulator->getDemodulatorType();
|
||||
lastDemodLock = lastActiveDemodulator->getDemodulatorLock();
|
||||
lastDemodCons = lastActiveDemodulator->getDemodulatorCons();
|
||||
lastSquelchEnabled = lastActiveDemodulator->isSquelchEnabled();
|
||||
lastSquelch = lastActiveDemodulator->getSquelchLevel();
|
||||
lastGain = lastActiveDemodulator->getGain();
|
||||
lastModemSettings[lastDemodType] = lastActiveDemodulator->readModemSettings();
|
||||
}
|
||||
|
||||
}
|
||||
@ -175,8 +173,8 @@ int DemodulatorMgr::getLastBandwidth() const {
|
||||
}
|
||||
|
||||
void DemodulatorMgr::setLastBandwidth(int lastBandwidth) {
|
||||
if (lastBandwidth < 1500) {
|
||||
lastBandwidth = 1500;
|
||||
if (lastBandwidth < MIN_BANDWIDTH) {
|
||||
lastBandwidth = MIN_BANDWIDTH;
|
||||
} else if (lastBandwidth > wxGetApp().getSampleRate()) {
|
||||
lastBandwidth = wxGetApp().getSampleRate();
|
||||
}
|
||||
@ -191,14 +189,6 @@ void DemodulatorMgr::setLastDemodulatorType(std::string lastDemodType) {
|
||||
this->lastDemodType = lastDemodType;
|
||||
}
|
||||
|
||||
int DemodulatorMgr::getLastDemodulatorCons() const {
|
||||
return lastDemodCons;
|
||||
}
|
||||
|
||||
void DemodulatorMgr::setLastDemodulatorCons(int lastDemodCons) {
|
||||
this->lastDemodCons = lastDemodCons;
|
||||
}
|
||||
|
||||
float DemodulatorMgr::getLastGain() const {
|
||||
return lastGain;
|
||||
}
|
||||
@ -231,3 +221,10 @@ void DemodulatorMgr::setLastMuted(bool lastMuted) {
|
||||
this->lastMuted = lastMuted;
|
||||
}
|
||||
|
||||
ModemSettings DemodulatorMgr::getLastModemSettings(std::string modemType) {
|
||||
return lastModemSettings[modemType];
|
||||
}
|
||||
|
||||
void DemodulatorMgr::setLastModemSettings(std::string modemType, ModemSettings settings) {
|
||||
lastModemSettings[modemType] = settings;
|
||||
}
|
||||
|
@ -27,9 +27,6 @@ public:
|
||||
|
||||
std::string getLastDemodulatorType() const;
|
||||
void setLastDemodulatorType(std::string lastDemodType);
|
||||
|
||||
int getLastDemodulatorCons() const;
|
||||
void setLastDemodulatorCons(int lastDemodCons);
|
||||
|
||||
float getLastGain() const;
|
||||
void setLastGain(float lastGain);
|
||||
@ -43,9 +40,13 @@ public:
|
||||
bool isLastMuted() const;
|
||||
void setLastMuted(bool lastMuted);
|
||||
|
||||
ModemSettings getLastModemSettings(std::string);
|
||||
void setLastModemSettings(std::string, ModemSettings);
|
||||
|
||||
void updateLastState();
|
||||
|
||||
private:
|
||||
void garbageCollect();
|
||||
void updateLastState();
|
||||
|
||||
std::vector<DemodulatorInstance *> demods;
|
||||
std::vector<DemodulatorInstance *> demods_deleted;
|
||||
@ -56,9 +57,10 @@ private:
|
||||
int lastBandwidth;
|
||||
std::string lastDemodType;
|
||||
bool lastDemodLock;
|
||||
int lastDemodCons;
|
||||
bool lastSquelchEnabled;
|
||||
float lastSquelch;
|
||||
float lastGain;
|
||||
bool lastMuted;
|
||||
|
||||
std::map<std::string, ModemSettings> lastModemSettings;
|
||||
};
|
||||
|
@ -7,10 +7,12 @@
|
||||
|
||||
#include "DemodulatorPreThread.h"
|
||||
#include "CubicSDR.h"
|
||||
#include "DemodulatorInstance.h"
|
||||
|
||||
DemodulatorPreThread::DemodulatorPreThread() : IOThread(), iqResampler(NULL), iqResampleRatio(1), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), iqOutputQueue(NULL), threadQueueNotify(NULL), commandQueue(NULL)
|
||||
DemodulatorPreThread::DemodulatorPreThread(DemodulatorInstance *parent) : IOThread(), iqResampler(NULL), iqResampleRatio(1), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), iqOutputQueue(NULL), threadQueueNotify(NULL)
|
||||
{
|
||||
initialized.store(false);
|
||||
this->parent = parent;
|
||||
|
||||
freqShifter = nco_crcf_create(LIQUID_VCO);
|
||||
shiftFrequency = 0;
|
||||
@ -21,18 +23,21 @@ DemodulatorPreThread::DemodulatorPreThread() : IOThread(), iqResampler(NULL), iq
|
||||
workerThread = new DemodulatorWorkerThread();
|
||||
workerThread->setInputQueue("WorkerCommandQueue",workerQueue);
|
||||
workerThread->setOutputQueue("WorkerResultQueue",workerResults);
|
||||
|
||||
newSampleRate = currentSampleRate = 0;
|
||||
newBandwidth = currentBandwidth = 0;
|
||||
newAudioSampleRate = currentAudioSampleRate = 0;
|
||||
newFrequency = currentFrequency = 0;
|
||||
|
||||
sampleRateChanged.store(false);
|
||||
frequencyChanged.store(false);
|
||||
bandwidthChanged.store(false);
|
||||
audioSampleRateChanged.store(false);
|
||||
modemSettingsChanged.store(false);
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::initialize() {
|
||||
iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate;
|
||||
|
||||
float As = 60.0f; // stop-band attenuation [dB]
|
||||
|
||||
iqResampler = msresamp_crcf_create(iqResampleRatio, As);
|
||||
|
||||
initialized.store(true);
|
||||
|
||||
lastParams = params;
|
||||
bool DemodulatorPreThread::isInitialized() {
|
||||
return initialized.load();
|
||||
}
|
||||
|
||||
DemodulatorPreThread::~DemodulatorPreThread() {
|
||||
@ -46,10 +51,6 @@ void DemodulatorPreThread::run() {
|
||||
pthread_setschedparam(tID, SCHED_FIFO, &prio);
|
||||
#endif
|
||||
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
std::cout << "Demodulator preprocessor thread started.." << std::endl;
|
||||
|
||||
ReBuffer<DemodulatorThreadPostIQData> buffers;
|
||||
@ -57,87 +58,103 @@ void DemodulatorPreThread::run() {
|
||||
iqInputQueue = (DemodulatorThreadInputQueue*)getInputQueue("IQDataInput");
|
||||
iqOutputQueue = (DemodulatorThreadPostInputQueue*)getOutputQueue("IQDataOutput");
|
||||
threadQueueNotify = (DemodulatorThreadCommandQueue*)getOutputQueue("NotifyQueue");
|
||||
commandQueue = ( DemodulatorThreadCommandQueue*)getInputQueue("CommandQueue");
|
||||
|
||||
std::vector<liquid_float_complex> in_buf_data;
|
||||
std::vector<liquid_float_complex> out_buf_data;
|
||||
|
||||
setDemodType(params.demodType);
|
||||
t_Worker = new std::thread(&DemodulatorWorkerThread::threadMain, workerThread);
|
||||
|
||||
while (!terminated) {
|
||||
DemodulatorThreadIQData *inp;
|
||||
iqInputQueue->pop(inp);
|
||||
|
||||
bool bandwidthChanged = false;
|
||||
bool rateChanged = false;
|
||||
DemodulatorThreadParameters tempParams = params;
|
||||
|
||||
if (!commandQueue->empty()) {
|
||||
while (!commandQueue->empty()) {
|
||||
DemodulatorThreadCommand command;
|
||||
commandQueue->pop(command);
|
||||
switch (command.cmd) {
|
||||
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH:
|
||||
if (command.llong_value < 1500) {
|
||||
command.llong_value = 1500;
|
||||
}
|
||||
if (command.llong_value > params.sampleRate) {
|
||||
tempParams.bandwidth = params.sampleRate;
|
||||
} else {
|
||||
tempParams.bandwidth = command.llong_value;
|
||||
}
|
||||
bandwidthChanged = true;
|
||||
break;
|
||||
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY:
|
||||
params.frequency = tempParams.frequency = command.llong_value;
|
||||
break;
|
||||
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE:
|
||||
tempParams.audioSampleRate = (int)command.llong_value;
|
||||
rateChanged = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (frequencyChanged.load()) {
|
||||
currentFrequency = newFrequency;
|
||||
frequencyChanged.store(false);
|
||||
}
|
||||
|
||||
if (inp->sampleRate != currentSampleRate) {
|
||||
newSampleRate = inp->sampleRate;
|
||||
if (newSampleRate) {
|
||||
sampleRateChanged.store(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (inp->sampleRate != tempParams.sampleRate && inp->sampleRate) {
|
||||
tempParams.sampleRate = inp->sampleRate;
|
||||
rateChanged = true;
|
||||
|
||||
if (!newAudioSampleRate) {
|
||||
newAudioSampleRate = parent->getAudioSampleRate();
|
||||
if (newAudioSampleRate) {
|
||||
audioSampleRateChanged.store(true);
|
||||
}
|
||||
} else if (parent->getAudioSampleRate() != newAudioSampleRate) {
|
||||
int newRate;
|
||||
if ((newRate = parent->getAudioSampleRate())) {
|
||||
newAudioSampleRate = parent->getAudioSampleRate();
|
||||
audioSampleRateChanged.store(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (bandwidthChanged || rateChanged) {
|
||||
|
||||
if (demodTypeChanged.load() && (newSampleRate && newAudioSampleRate && newBandwidth)) {
|
||||
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD);
|
||||
command.frequency = newFrequency;
|
||||
command.sampleRate = newSampleRate;
|
||||
command.demodType = newDemodType;
|
||||
command.bandwidth = newBandwidth;
|
||||
command.audioSampleRate = newAudioSampleRate;
|
||||
demodType = newDemodType;
|
||||
sampleRateChanged.store(false);
|
||||
audioSampleRateChanged.store(false);
|
||||
ModemSettings lastSettings = parent->getLastModemSettings(newDemodType);
|
||||
if (lastSettings.size() != 0) {
|
||||
command.settings = lastSettings;
|
||||
if (modemSettingsBuffered.size()) {
|
||||
for (ModemSettings::const_iterator msi = modemSettingsBuffered.begin(); msi != modemSettingsBuffered.end(); msi++) {
|
||||
command.settings[msi->first] = msi->second;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
command.settings = modemSettingsBuffered;
|
||||
}
|
||||
modemSettingsBuffered.clear();
|
||||
modemSettingsChanged.store(false);
|
||||
workerQueue->push(command);
|
||||
cModem = nullptr;
|
||||
cModemKit = nullptr;
|
||||
demodTypeChanged.store(false);
|
||||
initialized.store(false);
|
||||
}
|
||||
else if (
|
||||
cModemKit && cModem &&
|
||||
(bandwidthChanged.load() || sampleRateChanged.load() || audioSampleRateChanged.load() || cModem->shouldRebuildKit()) &&
|
||||
(newSampleRate && newAudioSampleRate && newBandwidth)
|
||||
) {
|
||||
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS);
|
||||
command.sampleRate = tempParams.sampleRate;
|
||||
command.audioSampleRate = tempParams.audioSampleRate;
|
||||
command.bandwidth = tempParams.bandwidth;
|
||||
command.frequency = tempParams.frequency;
|
||||
|
||||
command.frequency = newFrequency;
|
||||
command.sampleRate = newSampleRate;
|
||||
command.bandwidth = newBandwidth;
|
||||
command.audioSampleRate = newAudioSampleRate;
|
||||
bandwidthChanged.store(false);
|
||||
sampleRateChanged.store(false);
|
||||
audioSampleRateChanged.store(false);
|
||||
modemSettingsBuffered.clear();
|
||||
workerQueue->push(command);
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
inp->decRefCount();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Requested frequency is not center, shift it into the center!
|
||||
if ((params.frequency - inp->frequency) != shiftFrequency || rateChanged) {
|
||||
shiftFrequency = params.frequency - inp->frequency;
|
||||
if ((currentFrequency - inp->frequency) != shiftFrequency) {
|
||||
shiftFrequency = currentFrequency - inp->frequency;
|
||||
if (abs(shiftFrequency) <= (int) ((double) (inp->sampleRate / 2) * 1.5)) {
|
||||
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) inp->sampleRate)));
|
||||
}
|
||||
}
|
||||
|
||||
if (abs(shiftFrequency) > (int) ((double) (inp->sampleRate / 2) * 1.5)) {
|
||||
if (cModem && cModemKit && abs(shiftFrequency) > (int) ((double) (inp->sampleRate / 2) * 1.5)) {
|
||||
inp->decRefCount();
|
||||
continue;
|
||||
}
|
||||
|
||||
// std::lock_guard < std::mutex > lock(inp->m_mutex);
|
||||
std::vector<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();
|
||||
|
||||
if (in_buf_data.size() != bufSize) {
|
||||
@ -183,10 +200,11 @@ void DemodulatorPreThread::run() {
|
||||
resamp->setRefCount(1);
|
||||
resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten);
|
||||
|
||||
resamp->modemType = demodType;
|
||||
resamp->modemType = cModem->getType();
|
||||
resamp->modemName = cModem->getName();
|
||||
resamp->modem = cModem;
|
||||
resamp->modemKit = cModemKit;
|
||||
resamp->sampleRate = params.bandwidth;
|
||||
resamp->sampleRate = currentBandwidth;
|
||||
|
||||
iqOutputQueue->push(resamp);
|
||||
}
|
||||
@ -200,7 +218,6 @@ void DemodulatorPreThread::run() {
|
||||
|
||||
switch (result.cmd) {
|
||||
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
|
||||
|
||||
if (result.iqResampler) {
|
||||
if (iqResampler) {
|
||||
msresamp_crcf_destroy(iqResampler);
|
||||
@ -211,31 +228,46 @@ void DemodulatorPreThread::run() {
|
||||
|
||||
if (result.modem != nullptr) {
|
||||
cModem = result.modem;
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (cModem->getType() == "digital") {
|
||||
ModemDigital *mDigi = (ModemDigital *)cModem;
|
||||
mDigi->setOutput(parent->getOutput());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (result.modemKit != nullptr) {
|
||||
cModemKit = result.modemKit;
|
||||
currentAudioSampleRate = cModemKit->audioSampleRate;
|
||||
}
|
||||
|
||||
if (result.bandwidth) {
|
||||
params.bandwidth = result.bandwidth;
|
||||
currentBandwidth = result.bandwidth;
|
||||
}
|
||||
|
||||
if (result.sampleRate) {
|
||||
params.sampleRate = result.sampleRate;
|
||||
currentSampleRate = result.sampleRate;
|
||||
}
|
||||
|
||||
if (result.modemType != "") {
|
||||
demodType = result.modemType;
|
||||
params.demodType = result.modemType;
|
||||
if (result.modemName != "") {
|
||||
demodType = result.modemName;
|
||||
demodTypeChanged.store(false);
|
||||
}
|
||||
|
||||
shiftFrequency = inp->frequency-1;
|
||||
initialized.store(cModem != nullptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((cModem != nullptr) && modemSettingsChanged.load()) {
|
||||
cModem->writeSettings(modemSettingsBuffered);
|
||||
modemSettingsBuffered.clear();
|
||||
modemSettingsChanged.store(false);
|
||||
}
|
||||
}
|
||||
|
||||
buffers.purge();
|
||||
@ -246,21 +278,8 @@ void DemodulatorPreThread::run() {
|
||||
std::cout << "Demodulator preprocessor thread done." << std::endl;
|
||||
}
|
||||
|
||||
DemodulatorThreadParameters &DemodulatorPreThread::getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::setParams(DemodulatorThreadParameters ¶ms_in) {
|
||||
params = params_in;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::setDemodType(std::string demodType) {
|
||||
this->newDemodType = demodType;
|
||||
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD);
|
||||
command.demodType = demodType;
|
||||
command.bandwidth = params.bandwidth;
|
||||
command.audioSampleRate = params.audioSampleRate;
|
||||
workerQueue->push(command);
|
||||
newDemodType = demodType;
|
||||
demodTypeChanged.store(true);
|
||||
}
|
||||
|
||||
@ -271,6 +290,51 @@ std::string DemodulatorPreThread::getDemodType() {
|
||||
return demodType;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::setFrequency(long long freq) {
|
||||
frequencyChanged.store(true);
|
||||
newFrequency = freq;
|
||||
}
|
||||
|
||||
long long DemodulatorPreThread::getFrequency() {
|
||||
if (frequencyChanged.load()) {
|
||||
return newFrequency;
|
||||
}
|
||||
return currentFrequency;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::setSampleRate(long long sampleRate) {
|
||||
sampleRateChanged.store(true);
|
||||
newSampleRate = sampleRate;
|
||||
}
|
||||
|
||||
long long DemodulatorPreThread::getSampleRate() {
|
||||
if (sampleRateChanged.load()) {
|
||||
return newSampleRate;
|
||||
}
|
||||
return currentSampleRate;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::setBandwidth(int bandwidth) {
|
||||
bandwidthChanged.store(true);
|
||||
newBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
int DemodulatorPreThread::getBandwidth() {
|
||||
return currentBandwidth;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::setAudioSampleRate(int rate) {
|
||||
audioSampleRateChanged.store(true);
|
||||
newAudioSampleRate = rate;
|
||||
}
|
||||
|
||||
int DemodulatorPreThread::getAudioSampleRate() {
|
||||
if (audioSampleRateChanged.load()) {
|
||||
return newAudioSampleRate;
|
||||
}
|
||||
return currentAudioSampleRate;
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::terminate() {
|
||||
terminated = true;
|
||||
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
|
||||
@ -285,7 +349,6 @@ void DemodulatorPreThread::terminate() {
|
||||
delete workerQueue;
|
||||
}
|
||||
|
||||
|
||||
Modem *DemodulatorPreThread::getModem() {
|
||||
return cModem;
|
||||
}
|
||||
@ -293,3 +356,31 @@ Modem *DemodulatorPreThread::getModem() {
|
||||
ModemKit *DemodulatorPreThread::getModemKit() {
|
||||
return cModemKit;
|
||||
}
|
||||
|
||||
|
||||
std::string DemodulatorPreThread::readModemSetting(std::string setting) {
|
||||
if (cModem) {
|
||||
return cModem->readSetting(setting);
|
||||
} else if (modemSettingsBuffered.find(setting) != modemSettingsBuffered.end()) {
|
||||
return modemSettingsBuffered[setting];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::writeModemSetting(std::string setting, std::string value) {
|
||||
modemSettingsBuffered[setting] = value;
|
||||
modemSettingsChanged.store(true);
|
||||
}
|
||||
|
||||
ModemSettings DemodulatorPreThread::readModemSettings() {
|
||||
if (cModem) {
|
||||
return cModem->readSettings();
|
||||
} else {
|
||||
return modemSettingsBuffered;
|
||||
}
|
||||
}
|
||||
|
||||
void DemodulatorPreThread::writeModemSettings(ModemSettings settings) {
|
||||
modemSettingsBuffered = settings;
|
||||
modemSettingsChanged.store(true);
|
||||
}
|
||||
|
@ -7,37 +7,62 @@
|
||||
#include "DemodDefs.h"
|
||||
#include "DemodulatorWorkerThread.h"
|
||||
|
||||
class DemodulatorInstance;
|
||||
|
||||
class DemodulatorPreThread : public IOThread {
|
||||
public:
|
||||
|
||||
DemodulatorPreThread();
|
||||
DemodulatorPreThread(DemodulatorInstance *parent);
|
||||
~DemodulatorPreThread();
|
||||
|
||||
void run();
|
||||
|
||||
DemodulatorThreadParameters &getParams();
|
||||
void setParams(DemodulatorThreadParameters ¶ms_in);
|
||||
|
||||
void setDemodType(std::string demodType);
|
||||
std::string getDemodType();
|
||||
|
||||
void initialize();
|
||||
void setFrequency(long long sampleRate);
|
||||
long long getFrequency();
|
||||
|
||||
void setSampleRate(long long sampleRate);
|
||||
long long getSampleRate();
|
||||
|
||||
void setBandwidth(int bandwidth);
|
||||
int getBandwidth();
|
||||
|
||||
void setAudioSampleRate(int rate);
|
||||
int getAudioSampleRate();
|
||||
|
||||
bool isInitialized();
|
||||
|
||||
void terminate();
|
||||
|
||||
Modem *getModem();
|
||||
ModemKit *getModemKit();
|
||||
|
||||
std::string readModemSetting(std::string setting);
|
||||
void writeModemSetting(std::string setting, std::string value);
|
||||
ModemSettings readModemSettings();
|
||||
void writeModemSettings(ModemSettings settings);
|
||||
|
||||
protected:
|
||||
DemodulatorInstance *parent;
|
||||
msresamp_crcf iqResampler;
|
||||
double iqResampleRatio;
|
||||
std::vector<liquid_float_complex> resampledData;
|
||||
|
||||
Modem *cModem;
|
||||
ModemKit *cModemKit;
|
||||
|
||||
long long currentSampleRate, newSampleRate;
|
||||
long long currentFrequency, newFrequency;
|
||||
int currentBandwidth, newBandwidth;
|
||||
int currentAudioSampleRate, newAudioSampleRate;
|
||||
|
||||
DemodulatorThreadParameters params;
|
||||
DemodulatorThreadParameters lastParams;
|
||||
std::atomic_bool sampleRateChanged, frequencyChanged, bandwidthChanged, audioSampleRateChanged;
|
||||
|
||||
ModemSettings modemSettingsBuffered;
|
||||
std::atomic_bool modemSettingsChanged;
|
||||
|
||||
nco_crcf freqShifter;
|
||||
int shiftFrequency;
|
||||
|
||||
@ -55,5 +80,4 @@ protected:
|
||||
DemodulatorThreadInputQueue* iqInputQueue;
|
||||
DemodulatorThreadPostInputQueue* iqOutputQueue;
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||
DemodulatorThreadCommandQueue* commandQueue;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
DemodulatorThread::DemodulatorThread(DemodulatorInstance *parent) : IOThread(), audioSampleRate(0), squelchLevel(-100), signalLevel(-100), squelchEnabled(false), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) {
|
||||
DemodulatorThread::DemodulatorThread(DemodulatorInstance *parent) : IOThread(), squelchLevel(-100), signalLevel(-100), squelchEnabled(false), cModem(nullptr), cModemKit(nullptr), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) {
|
||||
|
||||
demodInstance = parent;
|
||||
muted.store(false);
|
||||
@ -73,8 +73,6 @@ void DemodulatorThread::run() {
|
||||
iqInputQueue->pop(inp);
|
||||
// std::lock_guard < std::mutex > lock(inp->m_mutex);
|
||||
|
||||
audioSampleRate = demodInstance->getAudioSampleRate();
|
||||
|
||||
int bufSize = inp->data.size();
|
||||
|
||||
if (!bufSize) {
|
||||
@ -122,15 +120,22 @@ void DemodulatorThread::run() {
|
||||
AudioThreadInput *ati = NULL;
|
||||
|
||||
ModemAnalog *modemAnalog = (cModem->getType() == "analog")?((ModemAnalog *)cModem):nullptr;
|
||||
// ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr;
|
||||
ModemDigital *modemDigital = (cModem->getType() == "digital")?((ModemDigital *)cModem):nullptr;
|
||||
|
||||
if (modemAnalog != nullptr) {
|
||||
ati = outputBuffers.getBuffer();
|
||||
|
||||
ati->sampleRate = audioSampleRate;
|
||||
ati->sampleRate = cModemKit->audioSampleRate;
|
||||
ati->inputRate = inp->sampleRate;
|
||||
ati->setRefCount(1);
|
||||
} else if (modemDigital != nullptr) {
|
||||
ati = outputBuffers.getBuffer();
|
||||
|
||||
ati->sampleRate = cModemKit->sampleRate;
|
||||
ati->inputRate = inp->sampleRate;
|
||||
ati->setRefCount(1);
|
||||
}
|
||||
|
||||
cModem->demodulate(cModemKit, &modemData, ati);
|
||||
|
||||
if (currentSignalLevel > signalLevel) {
|
||||
@ -162,7 +167,15 @@ void DemodulatorThread::run() {
|
||||
ati_vis->inputRate = inp->sampleRate;
|
||||
|
||||
int num_vis = DEMOD_VIS_SIZE;
|
||||
if (ati->channels==2) {
|
||||
if (modemDigital) {
|
||||
ati_vis->data.resize(inputData->size());
|
||||
ati_vis->channels = 2;
|
||||
for (int i = 0, iMax = inputData->size() / 2; i < iMax; i++) {
|
||||
ati_vis->data[i * 2] = (*inputData)[i].real;
|
||||
ati_vis->data[i * 2 + 1] = (*inputData)[i].imag;
|
||||
}
|
||||
ati_vis->type = 2;
|
||||
} else if (ati->channels==2) {
|
||||
ati_vis->channels = 2;
|
||||
int stereoSize = ati->data.size();
|
||||
if (stereoSize > DEMOD_VIS_SIZE * 2) {
|
||||
@ -171,25 +184,26 @@ void DemodulatorThread::run() {
|
||||
|
||||
ati_vis->data.resize(stereoSize);
|
||||
|
||||
if (inp->modemType == "I/Q") {
|
||||
if (inp->modemName == "I/Q") {
|
||||
for (int i = 0; i < stereoSize / 2; i++) {
|
||||
ati_vis->data[i] = (*inputData)[i].real * 0.75;
|
||||
ati_vis->data[i + stereoSize / 2] = (*inputData)[i].imag * 0.75;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < stereoSize / 2; i++) {
|
||||
ati_vis->inputRate = audioSampleRate;
|
||||
ati_vis->inputRate = cModemKit->audioSampleRate;
|
||||
ati_vis->sampleRate = 36000;
|
||||
ati_vis->data[i] = ati->data[i * 2];
|
||||
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
ati_vis->type = 1;
|
||||
} else {
|
||||
int numAudioWritten = ati->data.size();
|
||||
ati_vis->channels = 1;
|
||||
std::vector<float> *demodOutData = (modemAnalog != nullptr)?modemAnalog->getDemodOutputData():nullptr;
|
||||
if ((numAudioWritten > bufSize) || (demodOutData == nullptr)) {
|
||||
ati_vis->inputRate = audioSampleRate;
|
||||
ati_vis->inputRate = cModemKit->audioSampleRate;
|
||||
if (num_vis > numAudioWritten) {
|
||||
num_vis = numAudioWritten;
|
||||
}
|
||||
@ -200,7 +214,7 @@ void DemodulatorThread::run() {
|
||||
}
|
||||
ati_vis->data.assign(demodOutData->begin(), demodOutData->begin() + num_vis);
|
||||
}
|
||||
|
||||
ati_vis->type = 0;
|
||||
}
|
||||
|
||||
audioVisOutputQueue->push(ati_vis);
|
||||
|
@ -43,7 +43,6 @@ protected:
|
||||
ReBuffer<AudioThreadInput> outputBuffers;
|
||||
|
||||
std::atomic_bool muted;
|
||||
int audioSampleRate;
|
||||
|
||||
std::atomic<float> squelchLevel;
|
||||
std::atomic<float> signalLevel;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "DemodulatorWorkerThread.h"
|
||||
#include "CubicSDRDefs.h"
|
||||
#include "CubicSDR.h"
|
||||
#include <vector>
|
||||
|
||||
DemodulatorWorkerThread::DemodulatorWorkerThread() : IOThread(),
|
||||
@ -26,63 +27,72 @@ void DemodulatorWorkerThread::run() {
|
||||
while (!done) {
|
||||
commandQueue->pop(command);
|
||||
switch (command.cmd) {
|
||||
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS:
|
||||
filterChanged = true;
|
||||
filterCommand = command;
|
||||
break;
|
||||
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD:
|
||||
makeDemod = true;
|
||||
demodCommand = command;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS:
|
||||
filterChanged = true;
|
||||
filterCommand = command;
|
||||
break;
|
||||
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_MAKE_DEMOD:
|
||||
makeDemod = true;
|
||||
demodCommand = command;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
done = commandQueue->empty();
|
||||
}
|
||||
|
||||
|
||||
if ((makeDemod || filterChanged) && !terminated) {
|
||||
DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS);
|
||||
|
||||
float As = 60.0f; // stop-band attenuation [dB]
|
||||
|
||||
if (filterCommand.sampleRate && filterCommand.bandwidth) {
|
||||
result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate;
|
||||
result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As);
|
||||
|
||||
|
||||
if (filterCommand.sampleRate) {
|
||||
result.sampleRate = filterCommand.sampleRate;
|
||||
}
|
||||
|
||||
|
||||
if (makeDemod) {
|
||||
cModem = Modem::makeModem(demodCommand.demodType);
|
||||
cModemType = demodCommand.demodType;
|
||||
cModemName = cModem->getName();
|
||||
cModemType = cModem->getType();
|
||||
if (demodCommand.settings.size()) {
|
||||
cModem->writeSettings(demodCommand.settings);
|
||||
}
|
||||
result.sampleRate = demodCommand.sampleRate;
|
||||
wxGetApp().getAppFrame()->updateModemProperties(cModem->getSettings());
|
||||
}
|
||||
result.modem = cModem;
|
||||
|
||||
if (makeDemod && demodCommand.bandwidth && demodCommand.audioSampleRate) {
|
||||
if (cModem != nullptr) {
|
||||
cModemKit = cModem->buildKit(demodCommand.bandwidth, demodCommand.audioSampleRate);
|
||||
result.bandwidth = cModem->checkSampleRate(demodCommand.bandwidth, demodCommand.audioSampleRate);
|
||||
cModemKit = cModem->buildKit(result.bandwidth, demodCommand.audioSampleRate);
|
||||
} else {
|
||||
cModemKit = nullptr;
|
||||
}
|
||||
} else if (filterChanged && filterCommand.bandwidth && filterCommand.audioSampleRate) {
|
||||
if (cModem != nullptr) {
|
||||
cModemKit = cModem->buildKit(filterCommand.bandwidth, filterCommand.audioSampleRate);
|
||||
result.bandwidth = cModem->checkSampleRate(filterCommand.bandwidth, filterCommand.audioSampleRate);
|
||||
cModemKit = cModem->buildKit(result.bandwidth, filterCommand.audioSampleRate);
|
||||
} else {
|
||||
cModemKit = nullptr;
|
||||
}
|
||||
} else if (makeDemod) {
|
||||
cModemKit = nullptr;
|
||||
}
|
||||
if (cModem != nullptr) {
|
||||
cModem->clearRebuildKit();
|
||||
}
|
||||
|
||||
float As = 60.0f; // stop-band attenuation [dB]
|
||||
|
||||
if (result.sampleRate && result.bandwidth) {
|
||||
result.bandwidth = cModem->checkSampleRate(result.bandwidth, makeDemod?demodCommand.audioSampleRate:filterCommand.audioSampleRate);
|
||||
result.iqResampleRatio = (double) (result.bandwidth) / (double) result.sampleRate;
|
||||
result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As);
|
||||
}
|
||||
|
||||
result.modemKit = cModemKit;
|
||||
|
||||
if (filterCommand.bandwidth) {
|
||||
result.bandwidth = filterCommand.bandwidth;
|
||||
}
|
||||
|
||||
if (filterCommand.sampleRate) {
|
||||
result.sampleRate = filterCommand.sampleRate;
|
||||
}
|
||||
|
||||
result.modemType = cModemType;
|
||||
result.modemName = cModemName;
|
||||
|
||||
resultQueue->push(result);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
Modem *modem;
|
||||
ModemKit *modemKit;
|
||||
std::string modemType;
|
||||
std::string modemName;
|
||||
};
|
||||
|
||||
class DemodulatorWorkerThreadCommand {
|
||||
@ -62,6 +63,7 @@ public:
|
||||
unsigned int bandwidth;
|
||||
unsigned int audioSampleRate;
|
||||
std::string demodType;
|
||||
ModemSettings settings;
|
||||
};
|
||||
|
||||
typedef ThreadQueue<DemodulatorWorkerThreadCommand> DemodulatorThreadWorkerCommandQueue;
|
||||
@ -92,4 +94,5 @@ protected:
|
||||
Modem *cModem;
|
||||
ModemKit *cModemKit;
|
||||
std::string cModemType;
|
||||
std::string cModemName;
|
||||
};
|
||||
|
138
src/forms/DigitalConsole/DigitalConsole.cpp
Normal file
138
src/forms/DigitalConsole/DigitalConsole.cpp
Normal 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);
|
||||
}
|
485
src/forms/DigitalConsole/DigitalConsole.fbp
Normal file
485
src/forms/DigitalConsole/DigitalConsole.fbp
Normal 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>
|
61
src/forms/DigitalConsole/DigitalConsole.h
Normal file
61
src/forms/DigitalConsole/DigitalConsole.h
Normal 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;
|
||||
};
|
||||
|
73
src/forms/DigitalConsole/DigitalConsoleFrame.cpp
Normal file
73
src/forms/DigitalConsole/DigitalConsoleFrame.cpp
Normal 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 ) );
|
||||
|
||||
}
|
57
src/forms/DigitalConsole/DigitalConsoleFrame.h
Normal file
57
src/forms/DigitalConsole/DigitalConsoleFrame.h
Normal 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__
|
@ -3,7 +3,6 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "SDRDevices.h"
|
||||
#include "SDRDevicesForm.h"
|
||||
#include "SoapySDRThread.h"
|
||||
#include "SDREnumerator.h"
|
||||
|
@ -1,21 +1,33 @@
|
||||
#include "Modem.h"
|
||||
#include "CubicSDR.h"
|
||||
|
||||
|
||||
ModemFactoryList Modem::modemFactories;
|
||||
|
||||
void Modem::addModemFactory(Modem *factorySingle) {
|
||||
modemFactories[factorySingle->getName()] = factorySingle;
|
||||
//! Create an empty range (0.0, 0.0)
|
||||
ModemRange::ModemRange(void) {
|
||||
_min = 0;
|
||||
_max = 0;
|
||||
}
|
||||
|
||||
ModemFactoryList Modem::getFactories() {
|
||||
return modemFactories;
|
||||
//! Create a min/max range
|
||||
ModemRange::ModemRange(const double minimum, const double maximum) {
|
||||
_min = minimum;
|
||||
_max = maximum;
|
||||
}
|
||||
|
||||
Modem *Modem::makeModem(std::string modemType) {
|
||||
if (modemFactories.find(modemType) != modemFactories.end()) {
|
||||
return modemFactories[modemType]->factory();
|
||||
}
|
||||
//! Get the range minimum
|
||||
double ModemRange::minimum(void) const {
|
||||
return _min;
|
||||
}
|
||||
|
||||
//! Get the range maximum
|
||||
double ModemRange::maximum(void) const {
|
||||
return _max;
|
||||
}
|
||||
|
||||
ModemArgInfo::ModemArgInfo(void) {
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Modem::Modem() {
|
||||
@ -25,3 +37,72 @@ Modem::Modem() {
|
||||
Modem::~Modem() {
|
||||
|
||||
}
|
||||
|
||||
void Modem::addModemFactory(Modem *factorySingle) {
|
||||
modemFactories[factorySingle->getName()] = factorySingle;
|
||||
}
|
||||
|
||||
ModemFactoryList Modem::getFactories() {
|
||||
return modemFactories;
|
||||
}
|
||||
|
||||
Modem *Modem::makeModem(std::string modemName) {
|
||||
if (modemFactories.find(modemName) != modemFactories.end()) {
|
||||
return modemFactories[modemName]->factory();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Modem::getModemDefaultSampleRate(std::string modemName) {
|
||||
if (modemFactories.find(modemName) != modemFactories.end()) {
|
||||
return modemFactories[modemName]->getDefaultSampleRate();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ModemArgInfoList Modem::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
int Modem::getDefaultSampleRate() {
|
||||
return 200000;
|
||||
}
|
||||
|
||||
void Modem::writeSetting(std::string setting, std::string value) {
|
||||
// ...
|
||||
}
|
||||
|
||||
std::string Modem::readSetting(std::string setting) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void Modem::writeSettings(ModemSettings settings) {
|
||||
for (ModemSettings::const_iterator i = settings.begin(); i != settings.end(); i++) {
|
||||
writeSetting(i->first, i->second);
|
||||
}
|
||||
}
|
||||
|
||||
ModemSettings Modem::readSettings() {
|
||||
ModemArgInfoList args = getSettings();
|
||||
ModemSettings rs;
|
||||
for (ModemArgInfoList::const_iterator i = args.begin(); i != args.end(); i++) {
|
||||
rs[i->key] = readSetting(i->key);
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
bool Modem::shouldRebuildKit() {
|
||||
return refreshKit.load();
|
||||
}
|
||||
|
||||
void Modem::rebuildKit() {
|
||||
refreshKit.store(true);
|
||||
}
|
||||
|
||||
void Modem::clearRebuildKit() {
|
||||
refreshKit.store(false);
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include "IOThread.h"
|
||||
#include "AudioThread.h"
|
||||
#include <cmath>
|
||||
#include <atomic>
|
||||
|
||||
#define MIN_BANDWIDTH 500
|
||||
|
||||
class ModemKit {
|
||||
public:
|
||||
@ -29,24 +32,118 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Copy of SoapySDR::Range, original comments
|
||||
class ModemRange
|
||||
{
|
||||
public:
|
||||
|
||||
//! Create an empty range (0.0, 0.0)
|
||||
ModemRange(void);
|
||||
|
||||
//! Create a min/max range
|
||||
ModemRange(const double minimum, const double maximum);
|
||||
|
||||
//! Get the range minimum
|
||||
double minimum(void) const;
|
||||
|
||||
//! Get the range maximum
|
||||
double maximum(void) const;
|
||||
|
||||
private:
|
||||
double _min, _max;
|
||||
};
|
||||
|
||||
// Modified version of SoapySDR::ArgInfo, original comments
|
||||
class ModemArgInfo
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
ModemArgInfo(void);
|
||||
|
||||
//! The key used to identify the argument (required)
|
||||
std::string key;
|
||||
|
||||
/*!
|
||||
* The default value of the argument when not specified (required)
|
||||
* Numbers should use standard floating point and integer formats.
|
||||
* Boolean values should be represented as "true" and "false".
|
||||
*/
|
||||
std::string value;
|
||||
|
||||
//! The displayable name of the argument (optional, use key if empty)
|
||||
std::string name;
|
||||
|
||||
//! A brief description about the argument (optional)
|
||||
std::string description;
|
||||
|
||||
//! The units of the argument: dB, Hz, etc (optional)
|
||||
std::string units;
|
||||
|
||||
//! The data type of the argument (required)
|
||||
enum Type { BOOL, INT, FLOAT, STRING, PATH_DIR, PATH_FILE, COLOR } type;
|
||||
|
||||
/*!
|
||||
* The range of possible numeric values (optional)
|
||||
* When specified, the argument should be restricted to this range.
|
||||
* The range is only applicable to numeric argument types.
|
||||
*/
|
||||
ModemRange range;
|
||||
|
||||
/*!
|
||||
* A discrete list of possible values (optional)
|
||||
* When specified, the argument should be restricted to this options set.
|
||||
*/
|
||||
std::vector<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;
|
||||
typedef std::map<std::string,Modem *> ModemFactoryList;
|
||||
|
||||
typedef std::map<std::string, std::string> ModemSettings;
|
||||
|
||||
class Modem {
|
||||
public:
|
||||
static void addModemFactory(Modem *factorySingle);
|
||||
static ModemFactoryList getFactories();
|
||||
static Modem *makeModem(std::string modemType);
|
||||
|
||||
static Modem *makeModem(std::string modemName);
|
||||
static int getModemDefaultSampleRate(std::string modemName);
|
||||
|
||||
virtual std::string getType() = 0;
|
||||
virtual std::string getName() = 0;
|
||||
|
||||
virtual Modem *factory() = 0;
|
||||
|
||||
Modem();
|
||||
virtual ~Modem();
|
||||
|
||||
virtual ModemArgInfoList getSettings();
|
||||
virtual int getDefaultSampleRate();
|
||||
virtual void writeSetting(std::string setting, std::string value);
|
||||
virtual void writeSettings(ModemSettings settings);
|
||||
virtual std::string readSetting(std::string setting);
|
||||
virtual ModemSettings readSettings();
|
||||
|
||||
virtual int checkSampleRate(long long sampleRate, int audioSampleRate) = 0;
|
||||
|
||||
virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate) = 0;
|
||||
virtual void disposeKit(ModemKit *kit) = 0;
|
||||
|
||||
virtual void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) = 0;
|
||||
|
||||
bool shouldRebuildKit();
|
||||
void rebuildKit();
|
||||
void clearRebuildKit();
|
||||
|
||||
private:
|
||||
static ModemFactoryList modemFactories;
|
||||
std::atomic_bool refreshKit;
|
||||
};
|
||||
|
@ -8,6 +8,13 @@ std::string ModemAnalog::getType() {
|
||||
return "analog";
|
||||
}
|
||||
|
||||
int ModemAnalog::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
if (sampleRate < MIN_BANDWIDTH) {
|
||||
return MIN_BANDWIDTH;
|
||||
}
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
ModemKit *ModemAnalog::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKitAnalog *akit = new ModemKitAnalog;
|
||||
|
||||
|
@ -16,12 +16,13 @@ class ModemAnalog : public Modem {
|
||||
public:
|
||||
ModemAnalog();
|
||||
std::string getType();
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
void disposeKit(ModemKit *kit);
|
||||
void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input);
|
||||
void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain);
|
||||
std::vector<float> *getDemodOutputData();
|
||||
std::vector<float> *getResampledOutputData();
|
||||
virtual int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
virtual void disposeKit(ModemKit *kit);
|
||||
virtual void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input);
|
||||
virtual void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain);
|
||||
virtual std::vector<float> *getDemodOutputData();
|
||||
virtual std::vector<float> *getResampledOutputData();
|
||||
protected:
|
||||
int bufSize;
|
||||
std::vector<float> demodOutputData;
|
||||
|
@ -1,13 +1,31 @@
|
||||
#include "ModemDigital.h"
|
||||
|
||||
ModemDigital::ModemDigital() {
|
||||
|
||||
ModemDigitalOutput::ModemDigitalOutput() {
|
||||
|
||||
}
|
||||
|
||||
ModemDigital::ModemDigital() {
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
digitalOut = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ModemDigitalOutput::~ModemDigitalOutput() {
|
||||
|
||||
}
|
||||
|
||||
std::string ModemDigital::getType() {
|
||||
return "digital";
|
||||
}
|
||||
|
||||
int ModemDigital::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
if (sampleRate < MIN_BANDWIDTH) {
|
||||
return MIN_BANDWIDTH;
|
||||
}
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
ModemKit *ModemDigital::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKitDigital *dkit = new ModemKitDigital;
|
||||
|
||||
@ -31,24 +49,10 @@ int ModemDigital::getDemodulatorLock() {
|
||||
return currentDemodLock.load();
|
||||
}
|
||||
|
||||
void ModemDigital::setDemodulatorCons(int demod_cons_in) {
|
||||
demodulatorCons.store(demod_cons_in);
|
||||
}
|
||||
|
||||
int ModemDigital::getDemodulatorCons() {
|
||||
return currentDemodCons.load();
|
||||
}
|
||||
|
||||
void ModemDigital::updateDemodulatorLock(modem mod, float sensitivity) {
|
||||
setDemodulatorLock(modem_get_demodulator_evm(mod) <= sensitivity);
|
||||
}
|
||||
|
||||
void ModemDigital::updateDemodulatorCons(int cons) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
}
|
||||
}
|
||||
|
||||
void ModemDigital::digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input) {
|
||||
int bufSize = input->data.size();
|
||||
|
||||
@ -58,14 +62,21 @@ void ModemDigital::digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *in
|
||||
}
|
||||
demodOutputDataDigital.resize(bufSize);
|
||||
}
|
||||
|
||||
if (demodulatorCons.load() != currentDemodCons.load()) {
|
||||
updateDemodulatorCons(demodulatorCons.load());
|
||||
currentDemodLock.store(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ModemDigital::digitalFinish(ModemKitDigital *kit, modem mod) {
|
||||
demodOutputDataDigital.empty();
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
if (digitalOut && outStream.str().length()) {
|
||||
digitalOut->write(outStream.str());
|
||||
outStream.str("");
|
||||
} else {
|
||||
outStream.str("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
void ModemDigital::setOutput(ModemDigitalOutput *modemDigitalOutput) {
|
||||
digitalOut = modemDigitalOutput;
|
||||
}
|
||||
#endif
|
@ -1,5 +1,10 @@
|
||||
#pragma once
|
||||
#include "Modem.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <ostream>
|
||||
#include <mutex>
|
||||
|
||||
class ModemKitDigital : public ModemKit {
|
||||
public:
|
||||
@ -8,32 +13,49 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
class ModemDigitalOutput {
|
||||
public:
|
||||
ModemDigitalOutput();
|
||||
virtual ~ModemDigitalOutput();
|
||||
|
||||
virtual void write(std::string outp) = 0;
|
||||
virtual void write(char outc) = 0;
|
||||
|
||||
virtual void Show() = 0;
|
||||
virtual void Hide() = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class ModemDigital : public Modem {
|
||||
public:
|
||||
ModemDigital();
|
||||
|
||||
std::string getType();
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
void disposeKit(ModemKit *kit);
|
||||
void digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input);
|
||||
void digitalFinish(ModemKitDigital *kit, modem mod);
|
||||
|
||||
virtual int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
|
||||
virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
virtual void disposeKit(ModemKit *kit);
|
||||
|
||||
virtual void digitalStart(ModemKitDigital *kit, modem mod, ModemIQData *input);
|
||||
virtual void digitalFinish(ModemKitDigital *kit, modem mod);
|
||||
|
||||
virtual void setDemodulatorLock(bool demod_lock_in);
|
||||
virtual int getDemodulatorLock();
|
||||
|
||||
virtual void setDemodulatorCons(int demod_cons_in);
|
||||
virtual int getDemodulatorCons();
|
||||
|
||||
virtual void updateDemodulatorCons(int cons);
|
||||
virtual void updateDemodulatorLock(modem mod, float sensitivity);
|
||||
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
void setOutput(ModemDigitalOutput *digitalOutput);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::vector<unsigned int> demodOutputDataDigital;
|
||||
std::atomic_int demodulatorCons;
|
||||
std::atomic_bool currentDemodLock;
|
||||
std::atomic_int currentDemodCons;
|
||||
|
||||
// std::vector<unsigned int> demodOutputDataDigitalTest;
|
||||
// std::vector<unsigned char> demodOutputSoftbits;
|
||||
// std::vector<unsigned char> demodOutputSoftbitsTest;
|
||||
#if ENABLE_DIGITAL_LAB
|
||||
ModemDigitalOutput *digitalOut;
|
||||
std::stringstream outStream;
|
||||
#endif
|
||||
};
|
@ -1,9 +1,13 @@
|
||||
#include "ModemAM.h"
|
||||
|
||||
ModemAM::ModemAM() {
|
||||
ModemAM::ModemAM() : ModemAnalog() {
|
||||
demodAM = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
|
||||
}
|
||||
|
||||
ModemAM::~ModemAM() {
|
||||
ampmodem_destroy(demodAM);
|
||||
}
|
||||
|
||||
Modem *ModemAM::factory() {
|
||||
return new ModemAM;
|
||||
}
|
||||
@ -12,6 +16,10 @@ std::string ModemAM::getName() {
|
||||
return "AM";
|
||||
}
|
||||
|
||||
int ModemAM::getDefaultSampleRate() {
|
||||
return 6000;
|
||||
}
|
||||
|
||||
void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
|
||||
|
||||
|
@ -5,8 +5,14 @@
|
||||
class ModemAM : public ModemAnalog {
|
||||
public:
|
||||
ModemAM();
|
||||
~ModemAM();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int getDefaultSampleRate();
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -1,9 +1,13 @@
|
||||
#include "ModemDSB.h"
|
||||
|
||||
ModemDSB::ModemDSB() {
|
||||
ModemDSB::ModemDSB() : ModemAnalog() {
|
||||
demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
|
||||
}
|
||||
|
||||
ModemDSB::~ModemDSB() {
|
||||
ampmodem_destroy(demodAM_DSB);
|
||||
}
|
||||
|
||||
Modem *ModemDSB::factory() {
|
||||
return new ModemDSB;
|
||||
}
|
||||
@ -12,6 +16,10 @@ std::string ModemDSB::getName() {
|
||||
return "DSB";
|
||||
}
|
||||
|
||||
int ModemDSB::getDefaultSampleRate() {
|
||||
return 5400;
|
||||
}
|
||||
|
||||
void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
|
||||
|
||||
|
@ -5,8 +5,14 @@
|
||||
class ModemDSB : public ModemAnalog {
|
||||
public:
|
||||
ModemDSB();
|
||||
~ModemDSB();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int getDefaultSampleRate();
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -1,9 +1,13 @@
|
||||
#include "ModemFM.h"
|
||||
|
||||
ModemFM::ModemFM() {
|
||||
ModemFM::ModemFM() : ModemAnalog() {
|
||||
demodFM = freqdem_create(0.5);
|
||||
}
|
||||
|
||||
ModemFM::~ModemFM() {
|
||||
freqdem_destroy(demodFM);
|
||||
}
|
||||
|
||||
Modem *ModemFM::factory() {
|
||||
return new ModemFM;
|
||||
}
|
||||
@ -12,6 +16,10 @@ std::string ModemFM::getName() {
|
||||
return "FM";
|
||||
}
|
||||
|
||||
int ModemFM::getDefaultSampleRate() {
|
||||
return 200000;
|
||||
}
|
||||
|
||||
void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *fmkit = (ModemKitAnalog *)kit;
|
||||
|
||||
|
@ -5,11 +5,16 @@
|
||||
class ModemFM : public ModemAnalog {
|
||||
public:
|
||||
ModemFM();
|
||||
~ModemFM();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int getDefaultSampleRate();
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
||||
freqdem demodFM;
|
||||
};
|
@ -30,11 +30,27 @@ Modem *ModemFMStereo::factory() {
|
||||
return new ModemFMStereo;
|
||||
}
|
||||
|
||||
int ModemFMStereo::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
if (sampleRate < 100000) {
|
||||
return 100000;
|
||||
} else if (sampleRate < 1500) {
|
||||
return 1500;
|
||||
} else {
|
||||
return sampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
int ModemFMStereo::getDefaultSampleRate() {
|
||||
return 200000;
|
||||
}
|
||||
|
||||
ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKitFMStereo *kit = new ModemKitFMStereo;
|
||||
|
||||
kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
|
||||
|
||||
kit->sampleRate = sampleRate;
|
||||
kit->audioSampleRate = audioSampleRate;
|
||||
|
||||
float As = 60.0f; // stop-band attenuation [dB]
|
||||
|
||||
kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
|
||||
|
@ -20,11 +20,18 @@ class ModemFMStereo : public Modem {
|
||||
public:
|
||||
ModemFMStereo();
|
||||
~ModemFMStereo();
|
||||
|
||||
std::string getType();
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
int getDefaultSampleRate();
|
||||
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
void disposeKit(ModemKit *kit);
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -4,15 +4,6 @@ ModemIQ::ModemIQ() {
|
||||
|
||||
}
|
||||
|
||||
Modem *ModemIQ::factory() {
|
||||
return new ModemIQ;
|
||||
}
|
||||
|
||||
ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKit *kit = new ModemKit;
|
||||
return kit;
|
||||
}
|
||||
|
||||
std::string ModemIQ::getType() {
|
||||
return "analog";
|
||||
}
|
||||
@ -21,10 +12,29 @@ std::string ModemIQ::getName() {
|
||||
return "I/Q";
|
||||
}
|
||||
|
||||
Modem *ModemIQ::factory() {
|
||||
return new ModemIQ;
|
||||
}
|
||||
|
||||
ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) {
|
||||
ModemKit *kit = new ModemKit;
|
||||
kit->sampleRate = sampleRate;
|
||||
kit->audioSampleRate = audioSampleRate;
|
||||
return kit;
|
||||
}
|
||||
|
||||
void ModemIQ::disposeKit(ModemKit *kit) {
|
||||
delete kit;
|
||||
}
|
||||
|
||||
int ModemIQ::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
return audioSampleRate;
|
||||
}
|
||||
|
||||
int ModemIQ::getDefaultSampleRate() {
|
||||
return 48000;
|
||||
}
|
||||
|
||||
void ModemIQ::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
int bufSize = input->data.size();
|
||||
|
||||
|
@ -4,11 +4,19 @@
|
||||
class ModemIQ : public Modem {
|
||||
public:
|
||||
ModemIQ();
|
||||
|
||||
std::string getType();
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
int getDefaultSampleRate();
|
||||
|
||||
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
|
||||
|
||||
void disposeKit(ModemKit *kit);
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemLSB.h"
|
||||
|
||||
ModemLSB::ModemLSB() {
|
||||
ModemLSB::ModemLSB() : ModemAnalog() {
|
||||
// half band filter used for side-band elimination
|
||||
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
|
||||
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
|
||||
@ -19,6 +19,20 @@ ModemLSB::~ModemLSB() {
|
||||
ampmodem_destroy(demodAM_LSB);
|
||||
}
|
||||
|
||||
int ModemLSB::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
if (sampleRate < MIN_BANDWIDTH) {
|
||||
return MIN_BANDWIDTH;
|
||||
}
|
||||
if (sampleRate % 2 == 0) {
|
||||
return sampleRate;
|
||||
}
|
||||
return sampleRate+1;
|
||||
}
|
||||
|
||||
int ModemLSB::getDefaultSampleRate() {
|
||||
return 5400;
|
||||
}
|
||||
|
||||
void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
|
||||
|
||||
|
@ -1,13 +1,18 @@
|
||||
#pragma once
|
||||
#include "Modem.h"
|
||||
#include "ModemAnalog.h"
|
||||
|
||||
class ModemLSB : public ModemAnalog {
|
||||
public:
|
||||
ModemLSB();
|
||||
~ModemLSB();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
int getDefaultSampleRate();
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemUSB.h"
|
||||
|
||||
ModemUSB::ModemUSB() {
|
||||
ModemUSB::ModemUSB() : ModemAnalog() {
|
||||
// half band filter used for side-band elimination
|
||||
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
|
||||
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
||||
@ -19,6 +19,20 @@ ModemUSB::~ModemUSB() {
|
||||
ampmodem_destroy(demodAM_USB);
|
||||
}
|
||||
|
||||
int ModemUSB::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
if (sampleRate < MIN_BANDWIDTH) {
|
||||
return MIN_BANDWIDTH;
|
||||
}
|
||||
if (sampleRate % 2 == 0) {
|
||||
return sampleRate;
|
||||
}
|
||||
return sampleRate+1;
|
||||
}
|
||||
|
||||
int ModemUSB::getDefaultSampleRate() {
|
||||
return 5400;
|
||||
}
|
||||
|
||||
void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
|
||||
|
||||
|
@ -5,8 +5,14 @@ class ModemUSB : public ModemAnalog {
|
||||
public:
|
||||
ModemUSB();
|
||||
~ModemUSB();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
int getDefaultSampleRate();
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemAPSK.h"
|
||||
|
||||
ModemAPSK::ModemAPSK() {
|
||||
ModemAPSK::ModemAPSK() : ModemDigital() {
|
||||
demodAPSK4 = modem_create(LIQUID_MODEM_APSK4);
|
||||
demodAPSK8 = modem_create(LIQUID_MODEM_APSK8);
|
||||
demodAPSK16 = modem_create(LIQUID_MODEM_APSK16);
|
||||
@ -8,9 +8,8 @@ ModemAPSK::ModemAPSK() {
|
||||
demodAPSK64 = modem_create(LIQUID_MODEM_APSK64);
|
||||
demodAPSK128 = modem_create(LIQUID_MODEM_APSK128);
|
||||
demodAPSK256 = modem_create(LIQUID_MODEM_APSK256);
|
||||
demodulatorCons.store(4);
|
||||
currentDemodCons.store(0);
|
||||
updateDemodulatorCons(4);
|
||||
demodAPSK = demodAPSK4;
|
||||
cons = 4;
|
||||
}
|
||||
|
||||
Modem *ModemAPSK::factory() {
|
||||
@ -31,46 +30,67 @@ std::string ModemAPSK::getName() {
|
||||
return "APSK";
|
||||
}
|
||||
|
||||
ModemArgInfoList ModemAPSK::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
ModemArgInfo consArg;
|
||||
consArg.key = "cons";
|
||||
consArg.name = "Constellation";
|
||||
consArg.description = "Modem Constellation Pattern";
|
||||
consArg.value = std::to_string(cons);
|
||||
consArg.type = ModemArgInfo::STRING;
|
||||
std::vector<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) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
switch (demodulatorCons.load()) {
|
||||
case 2:
|
||||
demodAPSK = demodAPSK4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 4:
|
||||
demodAPSK = demodAPSK4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 8:
|
||||
demodAPSK = demodAPSK8;
|
||||
updateDemodulatorCons(8);
|
||||
break;
|
||||
case 16:
|
||||
demodAPSK = demodAPSK16;
|
||||
updateDemodulatorCons(16);
|
||||
break;
|
||||
case 32:
|
||||
demodAPSK = demodAPSK32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 64:
|
||||
demodAPSK = demodAPSK64;
|
||||
updateDemodulatorCons(64);
|
||||
break;
|
||||
case 128:
|
||||
demodAPSK = demodAPSK128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
case 256:
|
||||
demodAPSK = demodAPSK256;
|
||||
updateDemodulatorCons(256);
|
||||
break;
|
||||
default:
|
||||
demodAPSK = demodAPSK4;
|
||||
break;
|
||||
}
|
||||
this->cons = cons;
|
||||
switch (cons) {
|
||||
case 4:
|
||||
demodAPSK = demodAPSK4;
|
||||
break;
|
||||
case 8:
|
||||
demodAPSK = demodAPSK8;
|
||||
break;
|
||||
case 16:
|
||||
demodAPSK = demodAPSK16;
|
||||
break;
|
||||
case 32:
|
||||
demodAPSK = demodAPSK32;
|
||||
break;
|
||||
case 64:
|
||||
demodAPSK = demodAPSK64;
|
||||
break;
|
||||
case 128:
|
||||
demodAPSK = demodAPSK128;
|
||||
break;
|
||||
case 256:
|
||||
demodAPSK = demodAPSK256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,20 @@ class ModemAPSK : public ModemDigital {
|
||||
public:
|
||||
ModemAPSK();
|
||||
~ModemAPSK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
ModemArgInfoList getSettings();
|
||||
void writeSetting(std::string setting, std::string value);
|
||||
std::string readSetting(std::string setting);
|
||||
|
||||
void updateDemodulatorCons(int cons);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
int cons;
|
||||
modem demodAPSK;
|
||||
modem demodAPSK4;
|
||||
modem demodAPSK8;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemASK.h"
|
||||
|
||||
ModemASK::ModemASK() {
|
||||
ModemASK::ModemASK() : ModemDigital() {
|
||||
demodASK2 = modem_create(LIQUID_MODEM_ASK2);
|
||||
demodASK4 = modem_create(LIQUID_MODEM_ASK4);
|
||||
demodASK8 = modem_create(LIQUID_MODEM_ASK8);
|
||||
@ -10,9 +10,7 @@ ModemASK::ModemASK() {
|
||||
demodASK128 = modem_create(LIQUID_MODEM_ASK128);
|
||||
demodASK256 = modem_create(LIQUID_MODEM_ASK256);
|
||||
demodASK = demodASK2;
|
||||
demodulatorCons.store(2);
|
||||
currentDemodCons.store(0);
|
||||
updateDemodulatorCons(2);
|
||||
cons = 2;
|
||||
}
|
||||
|
||||
Modem *ModemASK::factory() {
|
||||
@ -33,47 +31,71 @@ std::string ModemASK::getName() {
|
||||
return "ASK";
|
||||
}
|
||||
|
||||
ModemArgInfoList ModemASK::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
ModemArgInfo consArg;
|
||||
consArg.key = "cons";
|
||||
consArg.name = "Constellation";
|
||||
consArg.description = "Modem Constellation Pattern";
|
||||
consArg.value = std::to_string(cons);
|
||||
consArg.type = ModemArgInfo::STRING;
|
||||
std::vector<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) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
|
||||
switch (demodulatorCons.load()) {
|
||||
case 2:
|
||||
demodASK = demodASK2;
|
||||
updateDemodulatorCons(2);
|
||||
break;
|
||||
case 4:
|
||||
demodASK = demodASK4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 8:
|
||||
demodASK = demodASK8;
|
||||
updateDemodulatorCons(8);
|
||||
break;
|
||||
case 16:
|
||||
demodASK = demodASK16;
|
||||
updateDemodulatorCons(16);
|
||||
break;
|
||||
case 32:
|
||||
demodASK = demodASK32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 64:
|
||||
demodASK = demodASK64;
|
||||
updateDemodulatorCons(64);
|
||||
break;
|
||||
case 128:
|
||||
demodASK = demodASK128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
case 256:
|
||||
demodASK = demodASK256;
|
||||
updateDemodulatorCons(256);
|
||||
break;
|
||||
default:
|
||||
demodASK = demodASK2;
|
||||
break;
|
||||
}
|
||||
this->cons = cons;
|
||||
switch (cons) {
|
||||
case 2:
|
||||
demodASK = demodASK2;
|
||||
break;
|
||||
case 4:
|
||||
demodASK = demodASK4;
|
||||
break;
|
||||
case 8:
|
||||
demodASK = demodASK8;
|
||||
break;
|
||||
case 16:
|
||||
demodASK = demodASK16;
|
||||
break;
|
||||
case 32:
|
||||
demodASK = demodASK32;
|
||||
break;
|
||||
case 64:
|
||||
demodASK = demodASK64;
|
||||
break;
|
||||
case 128:
|
||||
demodASK = demodASK128;
|
||||
break;
|
||||
case 256:
|
||||
demodASK = demodASK256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,20 @@ class ModemASK : public ModemDigital {
|
||||
public:
|
||||
ModemASK();
|
||||
~ModemASK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
ModemArgInfoList getSettings();
|
||||
void writeSetting(std::string setting, std::string value);
|
||||
std::string readSetting(std::string setting);
|
||||
|
||||
void updateDemodulatorCons(int cons);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
int cons;
|
||||
modem demodASK;
|
||||
modem demodASK2;
|
||||
modem demodASK4;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemBPSK.h"
|
||||
|
||||
ModemBPSK::ModemBPSK() {
|
||||
ModemBPSK::ModemBPSK() : ModemDigital() {
|
||||
demodBPSK = modem_create(LIQUID_MODEM_BPSK);
|
||||
}
|
||||
|
||||
@ -16,12 +16,6 @@ std::string ModemBPSK::getName() {
|
||||
return "BPSK";
|
||||
}
|
||||
|
||||
void ModemBPSK::updateDemodulatorCons(int cons) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
}
|
||||
}
|
||||
|
||||
void ModemBPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitDigital *dkit = (ModemKitDigital *)kit;
|
||||
digitalStart(dkit, demodBPSK, input);
|
||||
|
@ -5,12 +5,13 @@ class ModemBPSK : public ModemDigital {
|
||||
public:
|
||||
ModemBPSK();
|
||||
~ModemBPSK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
void updateDemodulatorCons(int cons);
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
modem demodBPSK;
|
||||
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemDPSK.h"
|
||||
|
||||
ModemDPSK::ModemDPSK() {
|
||||
ModemDPSK::ModemDPSK() : ModemDigital() {
|
||||
demodDPSK2 = modem_create(LIQUID_MODEM_DPSK2);
|
||||
demodDPSK4 = modem_create(LIQUID_MODEM_DPSK4);
|
||||
demodDPSK8 = modem_create(LIQUID_MODEM_DPSK8);
|
||||
@ -9,9 +9,8 @@ ModemDPSK::ModemDPSK() {
|
||||
demodDPSK64 = modem_create(LIQUID_MODEM_DPSK64);
|
||||
demodDPSK128 = modem_create(LIQUID_MODEM_DPSK128);
|
||||
demodDPSK256 = modem_create(LIQUID_MODEM_DPSK256);
|
||||
demodulatorCons.store(2);
|
||||
currentDemodCons.store(0);
|
||||
updateDemodulatorCons(2);
|
||||
demodDPSK = demodDPSK2;
|
||||
cons = 2;
|
||||
}
|
||||
|
||||
Modem *ModemDPSK::factory() {
|
||||
@ -33,47 +32,71 @@ ModemDPSK::~ModemDPSK() {
|
||||
modem_destroy(demodDPSK256);
|
||||
}
|
||||
|
||||
ModemArgInfoList ModemDPSK::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
ModemArgInfo consArg;
|
||||
consArg.key = "cons";
|
||||
consArg.name = "Constellation";
|
||||
consArg.description = "Modem Constellation Pattern";
|
||||
consArg.value = std::to_string(cons);
|
||||
consArg.type = ModemArgInfo::STRING;
|
||||
std::vector<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) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
|
||||
switch (demodulatorCons.load()) {
|
||||
case 2:
|
||||
demodDPSK = demodDPSK2;
|
||||
updateDemodulatorCons(2);
|
||||
break;
|
||||
case 4:
|
||||
demodDPSK = demodDPSK4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 8:
|
||||
demodDPSK = demodDPSK8;
|
||||
updateDemodulatorCons(8);
|
||||
break;
|
||||
case 16:
|
||||
demodDPSK = demodDPSK16;
|
||||
updateDemodulatorCons(16);
|
||||
break;
|
||||
case 32:
|
||||
demodDPSK = demodDPSK32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 64:
|
||||
demodDPSK = demodDPSK64;
|
||||
updateDemodulatorCons(64);
|
||||
break;
|
||||
case 128:
|
||||
demodDPSK = demodDPSK128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
case 256:
|
||||
demodDPSK = demodDPSK256;
|
||||
updateDemodulatorCons(256);
|
||||
break;
|
||||
default:
|
||||
demodDPSK = demodDPSK2;
|
||||
break;
|
||||
}
|
||||
this->cons = cons;
|
||||
switch (cons) {
|
||||
case 2:
|
||||
demodDPSK = demodDPSK2;
|
||||
break;
|
||||
case 4:
|
||||
demodDPSK = demodDPSK4;
|
||||
break;
|
||||
case 8:
|
||||
demodDPSK = demodDPSK8;
|
||||
break;
|
||||
case 16:
|
||||
demodDPSK = demodDPSK16;
|
||||
break;
|
||||
case 32:
|
||||
demodDPSK = demodDPSK32;
|
||||
break;
|
||||
case 64:
|
||||
demodDPSK = demodDPSK64;
|
||||
break;
|
||||
case 128:
|
||||
demodDPSK = demodDPSK128;
|
||||
break;
|
||||
case 256:
|
||||
demodDPSK = demodDPSK256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,20 @@ class ModemDPSK : public ModemDigital {
|
||||
public:
|
||||
ModemDPSK();
|
||||
~ModemDPSK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
ModemArgInfoList getSettings();
|
||||
void writeSetting(std::string setting, std::string value);
|
||||
std::string readSetting(std::string setting);
|
||||
|
||||
void updateDemodulatorCons(int cons);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
int cons;
|
||||
modem demodDPSK;
|
||||
modem demodDPSK2;
|
||||
modem demodDPSK4;
|
||||
|
143
src/modules/modem/digital/ModemFSK.cpp
Normal file
143
src/modules/modem/digital/ModemFSK.cpp
Normal 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);
|
||||
}
|
40
src/modules/modem/digital/ModemFSK.h
Normal file
40
src/modules/modem/digital/ModemFSK.h
Normal 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;
|
||||
};
|
||||
|
133
src/modules/modem/digital/ModemGMSK.cpp
Normal file
133
src/modules/modem/digital/ModemGMSK.cpp
Normal 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);
|
||||
}
|
41
src/modules/modem/digital/ModemGMSK.h
Normal file
41
src/modules/modem/digital/ModemGMSK.h
Normal 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;
|
||||
};
|
||||
|
@ -1,13 +1,9 @@
|
||||
#include "ModemOOK.h"
|
||||
|
||||
ModemOOK::ModemOOK() {
|
||||
ModemOOK::ModemOOK() : ModemDigital() {
|
||||
demodOOK = modem_create(LIQUID_MODEM_OOK);
|
||||
}
|
||||
|
||||
Modem *ModemOOK::factory() {
|
||||
return new ModemOOK;
|
||||
}
|
||||
|
||||
ModemOOK::~ModemOOK() {
|
||||
modem_destroy(demodOOK);
|
||||
}
|
||||
@ -16,10 +12,15 @@ std::string ModemOOK::getName() {
|
||||
return "OOK";
|
||||
}
|
||||
|
||||
void ModemOOK::updateDemodulatorCons(int cons) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
Modem *ModemOOK::factory() {
|
||||
return new ModemOOK;
|
||||
}
|
||||
|
||||
int ModemOOK::checkSampleRate(long long sampleRate, int audioSampleRate) {
|
||||
if (sampleRate < 100) {
|
||||
return 100;
|
||||
}
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
void ModemOOK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
|
@ -5,12 +5,15 @@ class ModemOOK : public ModemDigital {
|
||||
public:
|
||||
ModemOOK();
|
||||
~ModemOOK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
void updateDemodulatorCons(int cons);
|
||||
|
||||
int checkSampleRate(long long sampleRate, int audioSampleRate);
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
modem demodOOK;
|
||||
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemPSK.h"
|
||||
|
||||
ModemPSK::ModemPSK() {
|
||||
ModemPSK::ModemPSK() : ModemDigital() {
|
||||
demodPSK2 = modem_create(LIQUID_MODEM_PSK2);
|
||||
demodPSK4 = modem_create(LIQUID_MODEM_PSK4);
|
||||
demodPSK8 = modem_create(LIQUID_MODEM_PSK8);
|
||||
@ -9,9 +9,8 @@ ModemPSK::ModemPSK() {
|
||||
demodPSK64 = modem_create(LIQUID_MODEM_PSK64);
|
||||
demodPSK128 = modem_create(LIQUID_MODEM_PSK128);
|
||||
demodPSK256 = modem_create(LIQUID_MODEM_PSK256);
|
||||
demodulatorCons.store(2);
|
||||
currentDemodCons.store(0);
|
||||
updateDemodulatorCons(2);
|
||||
demodPSK = demodPSK2;
|
||||
cons = 2;
|
||||
}
|
||||
|
||||
Modem *ModemPSK::factory() {
|
||||
@ -33,47 +32,72 @@ ModemPSK::~ModemPSK() {
|
||||
modem_destroy(demodPSK256);
|
||||
}
|
||||
|
||||
|
||||
ModemArgInfoList ModemPSK::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
ModemArgInfo consArg;
|
||||
consArg.key = "cons";
|
||||
consArg.name = "Constellation";
|
||||
consArg.description = "Modem Constellation Pattern";
|
||||
consArg.value = std::to_string(cons);
|
||||
consArg.type = ModemArgInfo::STRING;
|
||||
std::vector<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) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
|
||||
switch (demodulatorCons.load()) {
|
||||
case 2:
|
||||
demodPSK = demodPSK2;
|
||||
updateDemodulatorCons(2);
|
||||
break;
|
||||
case 4:
|
||||
demodPSK = demodPSK4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 8:
|
||||
demodPSK = demodPSK8;
|
||||
updateDemodulatorCons(8);
|
||||
break;
|
||||
case 16:
|
||||
demodPSK = demodPSK16;
|
||||
updateDemodulatorCons(16);
|
||||
break;
|
||||
case 32:
|
||||
demodPSK = demodPSK32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 64:
|
||||
demodPSK = demodPSK64;
|
||||
updateDemodulatorCons(64);
|
||||
break;
|
||||
case 128:
|
||||
demodPSK = demodPSK128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
case 256:
|
||||
demodPSK = demodPSK256;
|
||||
updateDemodulatorCons(256);
|
||||
break;
|
||||
default:
|
||||
demodPSK = demodPSK2;
|
||||
break;
|
||||
}
|
||||
this->cons = cons;
|
||||
switch (cons) {
|
||||
case 2:
|
||||
demodPSK = demodPSK2;
|
||||
break;
|
||||
case 4:
|
||||
demodPSK = demodPSK4;
|
||||
break;
|
||||
case 8:
|
||||
demodPSK = demodPSK8;
|
||||
break;
|
||||
case 16:
|
||||
demodPSK = demodPSK16;
|
||||
break;
|
||||
case 32:
|
||||
demodPSK = demodPSK32;
|
||||
break;
|
||||
case 64:
|
||||
demodPSK = demodPSK64;
|
||||
break;
|
||||
case 128:
|
||||
demodPSK = demodPSK128;
|
||||
break;
|
||||
case 256:
|
||||
demodPSK = demodPSK256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,20 @@ class ModemPSK : public ModemDigital {
|
||||
public:
|
||||
ModemPSK();
|
||||
~ModemPSK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
ModemArgInfoList getSettings();
|
||||
void writeSetting(std::string setting, std::string value);
|
||||
std::string readSetting(std::string setting);
|
||||
|
||||
void updateDemodulatorCons(int cons);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
int cons;
|
||||
modem demodPSK;
|
||||
modem demodPSK2;
|
||||
modem demodPSK4;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemQAM.h"
|
||||
|
||||
ModemQAM::ModemQAM() {
|
||||
ModemQAM::ModemQAM() : ModemDigital() {
|
||||
demodQAM4 = modem_create(LIQUID_MODEM_QAM4);
|
||||
demodQAM8 = modem_create(LIQUID_MODEM_QAM8);
|
||||
demodQAM16 = modem_create(LIQUID_MODEM_QAM16);
|
||||
@ -8,9 +8,8 @@ ModemQAM::ModemQAM() {
|
||||
demodQAM64 = modem_create(LIQUID_MODEM_QAM64);
|
||||
demodQAM128 = modem_create(LIQUID_MODEM_QAM128);
|
||||
demodQAM256 = modem_create(LIQUID_MODEM_QAM256);
|
||||
demodulatorCons.store(4);
|
||||
currentDemodCons.store(0);
|
||||
updateDemodulatorCons(4);
|
||||
demodQAM = demodQAM4;
|
||||
cons = 4;
|
||||
}
|
||||
|
||||
Modem *ModemQAM::factory() {
|
||||
@ -31,47 +30,67 @@ ModemQAM::~ModemQAM() {
|
||||
modem_destroy(demodQAM256);
|
||||
}
|
||||
|
||||
ModemArgInfoList ModemQAM::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
ModemArgInfo consArg;
|
||||
consArg.key = "cons";
|
||||
consArg.name = "Constellation";
|
||||
consArg.description = "Modem Constellation Pattern";
|
||||
consArg.value = std::to_string(cons);
|
||||
consArg.type = ModemArgInfo::STRING;
|
||||
std::vector<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) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
|
||||
switch (demodulatorCons.load()) {
|
||||
case 2:
|
||||
demodQAM = demodQAM4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 4:
|
||||
demodQAM = demodQAM4;
|
||||
updateDemodulatorCons(4);
|
||||
break;
|
||||
case 8:
|
||||
demodQAM = demodQAM8;
|
||||
updateDemodulatorCons(8);
|
||||
break;
|
||||
case 16:
|
||||
demodQAM = demodQAM16;
|
||||
updateDemodulatorCons(16);
|
||||
break;
|
||||
case 32:
|
||||
demodQAM = demodQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 64:
|
||||
demodQAM = demodQAM64;
|
||||
updateDemodulatorCons(64);
|
||||
break;
|
||||
case 128:
|
||||
demodQAM = demodQAM128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
case 256:
|
||||
demodQAM = demodQAM256;
|
||||
updateDemodulatorCons(256);
|
||||
break;
|
||||
default:
|
||||
demodQAM = demodQAM4;
|
||||
break;
|
||||
}
|
||||
this->cons = cons;
|
||||
switch (cons) {
|
||||
case 4:
|
||||
demodQAM = demodQAM4;
|
||||
break;
|
||||
case 8:
|
||||
demodQAM = demodQAM8;
|
||||
break;
|
||||
case 16:
|
||||
demodQAM = demodQAM16;
|
||||
break;
|
||||
case 32:
|
||||
demodQAM = demodQAM32;
|
||||
break;
|
||||
case 64:
|
||||
demodQAM = demodQAM64;
|
||||
break;
|
||||
case 128:
|
||||
demodQAM = demodQAM128;
|
||||
break;
|
||||
case 256:
|
||||
demodQAM = demodQAM256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,20 @@ class ModemQAM : public ModemDigital {
|
||||
public:
|
||||
ModemQAM();
|
||||
~ModemQAM();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
ModemArgInfoList getSettings();
|
||||
void writeSetting(std::string setting, std::string value);
|
||||
std::string readSetting(std::string setting);
|
||||
|
||||
void updateDemodulatorCons(int cons);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
int cons;
|
||||
modem demodQAM;
|
||||
modem demodQAM4;
|
||||
modem demodQAM8;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemQPSK.h"
|
||||
|
||||
ModemQPSK::ModemQPSK() {
|
||||
ModemQPSK::ModemQPSK() : ModemDigital() {
|
||||
demodQPSK = modem_create(LIQUID_MODEM_QPSK);
|
||||
}
|
||||
|
||||
@ -16,12 +16,6 @@ std::string ModemQPSK::getName() {
|
||||
return "QPSK";
|
||||
}
|
||||
|
||||
void ModemQPSK::updateDemodulatorCons(int cons) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
}
|
||||
}
|
||||
|
||||
void ModemQPSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitDigital *dkit = (ModemKitDigital *)kit;
|
||||
digitalStart(dkit, demodQPSK, input);
|
||||
|
@ -5,9 +5,11 @@ class ModemQPSK : public ModemDigital {
|
||||
public:
|
||||
ModemQPSK();
|
||||
~ModemQPSK();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
void updateDemodulatorCons(int cons);
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -1,11 +1,10 @@
|
||||
#include "ModemSQAM.h"
|
||||
|
||||
ModemSQAM::ModemSQAM() {
|
||||
ModemSQAM::ModemSQAM() : ModemDigital() {
|
||||
demodSQAM32 = modem_create(LIQUID_MODEM_SQAM32);
|
||||
demodSQAM128 = modem_create(LIQUID_MODEM_SQAM128);
|
||||
demodulatorCons.store(32);
|
||||
currentDemodCons.store(0);
|
||||
updateDemodulatorCons(32);
|
||||
demodSQAM = demodSQAM32;
|
||||
cons = 32;
|
||||
}
|
||||
|
||||
Modem *ModemSQAM::factory() {
|
||||
@ -21,47 +20,47 @@ std::string ModemSQAM::getName() {
|
||||
return "SQAM";
|
||||
}
|
||||
|
||||
ModemArgInfoList ModemSQAM::getSettings() {
|
||||
ModemArgInfoList args;
|
||||
|
||||
ModemArgInfo consArg;
|
||||
consArg.key = "cons";
|
||||
consArg.name = "Constellation";
|
||||
consArg.description = "Modem Constellation Pattern";
|
||||
consArg.value = std::to_string(cons);
|
||||
consArg.type = ModemArgInfo::STRING;
|
||||
std::vector<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) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
|
||||
switch (demodulatorCons.load()) {
|
||||
case 2:
|
||||
demodSQAM = demodSQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 4:
|
||||
demodSQAM = demodSQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 8:
|
||||
demodSQAM = demodSQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 16:
|
||||
demodSQAM = demodSQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 32:
|
||||
demodSQAM = demodSQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 64:
|
||||
demodSQAM = demodSQAM32;
|
||||
updateDemodulatorCons(32);
|
||||
break;
|
||||
case 128:
|
||||
demodSQAM = demodSQAM128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
case 256:
|
||||
demodSQAM = demodSQAM128;
|
||||
updateDemodulatorCons(128);
|
||||
break;
|
||||
default:
|
||||
demodSQAM = demodSQAM32;
|
||||
break;
|
||||
}
|
||||
this->cons = cons;
|
||||
switch (cons) {
|
||||
case 32:
|
||||
demodSQAM = demodSQAM32;
|
||||
break;
|
||||
case 128:
|
||||
demodSQAM = demodSQAM128;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,20 @@ class ModemSQAM : public ModemDigital {
|
||||
public:
|
||||
ModemSQAM();
|
||||
~ModemSQAM();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
|
||||
ModemArgInfoList getSettings();
|
||||
void writeSetting(std::string setting, std::string value);
|
||||
std::string readSetting(std::string setting);
|
||||
|
||||
void updateDemodulatorCons(int cons);
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
int cons;
|
||||
modem demodSQAM;
|
||||
modem demodSQAM32;
|
||||
modem demodSQAM128;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ModemST.h"
|
||||
|
||||
ModemST::ModemST() {
|
||||
ModemST::ModemST() : ModemDigital() {
|
||||
demodST = modem_create(LIQUID_MODEM_V29);
|
||||
}
|
||||
|
||||
@ -16,12 +16,6 @@ ModemST::~ModemST() {
|
||||
modem_destroy(demodST);
|
||||
}
|
||||
|
||||
void ModemST::updateDemodulatorCons(int cons) {
|
||||
if (currentDemodCons.load() != cons) {
|
||||
currentDemodCons = cons;
|
||||
}
|
||||
}
|
||||
|
||||
void ModemST::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
|
||||
ModemKitDigital *dkit = (ModemKitDigital *)kit;
|
||||
digitalStart(dkit, demodST, input);
|
||||
|
@ -5,9 +5,11 @@ class ModemST : public ModemDigital {
|
||||
public:
|
||||
ModemST();
|
||||
~ModemST();
|
||||
|
||||
std::string getName();
|
||||
|
||||
Modem *factory();
|
||||
void updateDemodulatorCons(int cons);
|
||||
|
||||
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
|
||||
|
||||
private:
|
||||
|
@ -16,6 +16,9 @@ void ScopePanel::setMode(ScopeMode scopeMode) {
|
||||
this->scopeMode = scopeMode;
|
||||
}
|
||||
|
||||
ScopePanel::ScopeMode ScopePanel::getMode() {
|
||||
return this->scopeMode;
|
||||
}
|
||||
|
||||
void ScopePanel::setPoints(std::vector<float> &points) {
|
||||
this->points.assign(points.begin(),points.end());
|
||||
@ -61,14 +64,29 @@ void ScopePanel::drawPanelContents() {
|
||||
glEnd();
|
||||
|
||||
} else if (scopeMode == SCOPE_MODE_XY) {
|
||||
// ...
|
||||
RGBA4f bg1(ThemeMgr::mgr.currentTheme->scopeBackground), bg2(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0);
|
||||
bg1.a = 0.05;
|
||||
bg2.a = 0.05;
|
||||
bgPanel.setFillColor(bg1, bg2);
|
||||
bgPanel.calcTransform(transform);
|
||||
bgPanel.draw();
|
||||
glLineWidth(1.0);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glPointSize(1.0);
|
||||
glLoadMatrixf(transform);
|
||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.15, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.15,
|
||||
ThemeMgr::mgr.currentTheme->scopeLine.b * 0.15);
|
||||
}
|
||||
|
||||
if (points.size()) {
|
||||
glEnable (GL_BLEND);
|
||||
glEnable (GL_LINE_SMOOTH);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (scopeMode == SCOPE_MODE_XY) {
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
} else {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
glColor4f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b, 1.0);
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||
@ -83,7 +101,8 @@ void ScopePanel::drawPanelContents() {
|
||||
glLoadMatrixf(bgPanelStereo[1].transform);
|
||||
glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
|
||||
} else if (scopeMode == SCOPE_MODE_XY) {
|
||||
// ...
|
||||
glLoadMatrixf(bgPanel.transform);
|
||||
glDrawArrays(GL_POINTS, 0, points.size() / 2);
|
||||
}
|
||||
glLineWidth(1.0);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
@ -10,6 +10,7 @@ public:
|
||||
ScopePanel();
|
||||
|
||||
void setMode(ScopeMode scopeMode);
|
||||
ScopeMode getMode();
|
||||
void setPoints(std::vector<float> &points);
|
||||
|
||||
protected:
|
||||
|
@ -95,7 +95,7 @@ void ScopeVisualProcessor::process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (audioInputData->channels == 2) {
|
||||
if (audioInputData->type == 1) {
|
||||
iMax = audioInputData->data.size();
|
||||
if (renderData->waveform_points.size() != iMax * 2) {
|
||||
renderData->waveform_points.resize(iMax * 2);
|
||||
@ -104,11 +104,23 @@ void ScopeVisualProcessor::process() {
|
||||
renderData->waveform_points[i * 2] = (((double) (i % (iMax/2)) / (double) iMax) * 2.0 - 0.5) * 2.0;
|
||||
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak;
|
||||
}
|
||||
renderData->mode = ScopePanel::SCOPE_MODE_2Y;
|
||||
} else if (audioInputData->type == 2) {
|
||||
iMax = audioInputData->data.size();
|
||||
if (renderData->waveform_points.size() != iMax) {
|
||||
renderData->waveform_points.resize(iMax);
|
||||
}
|
||||
for (i = 0; i < iMax/2; i++) {
|
||||
renderData->waveform_points[i * 2] = audioInputData->data[i * 2] / peak;
|
||||
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i * 2 + 1] / peak;
|
||||
}
|
||||
renderData->mode = ScopePanel::SCOPE_MODE_XY;
|
||||
} else {
|
||||
for (i = 0; i < iMax; i++) {
|
||||
renderData->waveform_points[i * 2] = (((double) i / (double) iMax) - 0.5) * 2.0;
|
||||
renderData->waveform_points[i * 2 + 1] = audioInputData->data[i] / peak;
|
||||
}
|
||||
renderData->mode = ScopePanel::SCOPE_MODE_Y;
|
||||
}
|
||||
|
||||
renderData->spectrum = false;
|
||||
|
@ -3,10 +3,12 @@
|
||||
#include "VisualProcessor.h"
|
||||
#include "AudioThread.h"
|
||||
#include "fftw3.h"
|
||||
#include "ScopePanel.h"
|
||||
|
||||
class ScopeRenderData: public ReferenceCounter {
|
||||
public:
|
||||
std::vector<float> waveform_points;
|
||||
ScopePanel::ScopeMode mode;
|
||||
int inputRate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
|
@ -155,10 +155,16 @@ void ModeSelectorCanvas::addChoice(int value, std::string label) {
|
||||
numChoices = selections.size();
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::addChoice(std::string label) {
|
||||
selections.push_back(ModeSelectorMode(selections.size()+1, label));
|
||||
numChoices = selections.size();
|
||||
}
|
||||
|
||||
void ModeSelectorCanvas::setSelection(std::string label) {
|
||||
for (int i = 0; i < numChoices; i++) {
|
||||
if (selections[i].label == label) {
|
||||
currentSelection = i;
|
||||
Refresh();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
void setHelpTip(std::string tip);
|
||||
|
||||
void addChoice(int value, std::string label);
|
||||
void addChoice(std::string label);
|
||||
void setSelection(std::string label);
|
||||
std::string getSelectionLabel();
|
||||
void setSelection(int value);
|
||||
|
@ -230,9 +230,9 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long
|
||||
}
|
||||
// advanced demodulators start here
|
||||
|
||||
if (demod->getDemodulatorCons() > 0) {
|
||||
demodStr = demodStr + std::to_string(demod->getDemodulatorCons());
|
||||
}
|
||||
// if (demod->getDemodulatorCons() > 0) {
|
||||
// demodStr = demodStr + std::to_string(demod->getDemodulatorCons());
|
||||
// }
|
||||
|
||||
// add lock to string if we have an lock
|
||||
if(demod->getDemodulatorLock()) {
|
||||
|
@ -29,6 +29,5 @@ public:
|
||||
void setHoverAlpha(float hoverAlpha);
|
||||
|
||||
private:
|
||||
DemodulatorThreadParameters defaultDemodParams;
|
||||
float hoverAlpha;
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ EVT_LEAVE_WINDOW(ScopeCanvas::OnMouseLeftWindow)
|
||||
EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), stereo(false), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
|
||||
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0), helpTip("") {
|
||||
|
||||
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
|
||||
inputData.set_max_num_items(2);
|
||||
@ -65,7 +65,7 @@ bool ScopeCanvas::spectrumVisible() {
|
||||
float panelInterval = (2.0 + panelSpacing);
|
||||
|
||||
ctrTarget = abs(round(ctr / panelInterval));
|
||||
|
||||
|
||||
if (ctrTarget == 1 || dragAccel || (ctr != ctrTarget)) {
|
||||
return true;
|
||||
}
|
||||
@ -73,10 +73,6 @@ bool ScopeCanvas::spectrumVisible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScopeCanvas::setStereo(bool state) {
|
||||
stereo = state;
|
||||
}
|
||||
|
||||
void ScopeCanvas::setDeviceName(std::string device_name) {
|
||||
deviceName = device_name;
|
||||
deviceName.append(" ");
|
||||
@ -106,12 +102,12 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
ScopeRenderData *avData;
|
||||
inputData.pop(avData);
|
||||
|
||||
|
||||
if (!avData->spectrum) {
|
||||
scopePanel.setMode(avData->mode);
|
||||
if (avData->waveform_points.size()) {
|
||||
scopePanel.setPoints(avData->waveform_points);
|
||||
setStereo(avData->channels == 2);
|
||||
}
|
||||
|
||||
avData->decRefCount();
|
||||
} else {
|
||||
if (avData->waveform_points.size()) {
|
||||
@ -133,14 +129,18 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
|
||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||
|
||||
glContext->DrawBegin();
|
||||
if (scopePanel.getMode() == ScopePanel::SCOPE_MODE_XY && !spectrumVisible()) {
|
||||
glDrawBuffer(GL_FRONT);
|
||||
glContext->DrawBegin(false);
|
||||
} else {
|
||||
glDrawBuffer(GL_BACK);
|
||||
glContext->DrawBegin();
|
||||
|
||||
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,1));
|
||||
bgPanel.calcTransform(CubicVR::mat4::identity());
|
||||
bgPanel.draw();
|
||||
}
|
||||
|
||||
bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,0));
|
||||
bgPanel.calcTransform(CubicVR::mat4::identity());
|
||||
bgPanel.draw();
|
||||
|
||||
scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0));
|
||||
@ -190,7 +190,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
|
||||
spectrumPanel.setPosition(panelInterval+ctr, 0);
|
||||
if (spectrumVisible()) {
|
||||
spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,0));
|
||||
spectrumPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 2.0, RGBA4f(0,0,0,1));
|
||||
spectrumPanel.contentsVisible = true;
|
||||
roty = atan2(spectrumPanel.pos[0],1.2);
|
||||
spectrumPanel.rot[1] = -(roty * (180.0 / M_PI));
|
||||
@ -217,7 +217,9 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
glContext->DrawTunerTitles(ppmMode);
|
||||
glContext->DrawEnd();
|
||||
|
||||
SwapBuffers();
|
||||
if (scopePanel.getMode() != ScopePanel::SCOPE_MODE_XY || spectrumVisible()) {
|
||||
SwapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,6 @@ public:
|
||||
ScopeCanvas(wxWindow *parent, int *attribList = NULL);
|
||||
~ScopeCanvas();
|
||||
|
||||
void setStereo(bool state);
|
||||
void setDeviceName(std::string device_name);
|
||||
void setPPMMode(bool ppmMode);
|
||||
bool getPPMMode();
|
||||
@ -50,7 +49,6 @@ private:
|
||||
GLPanel bgPanel;
|
||||
ScopeContext *glContext;
|
||||
std::string deviceName;
|
||||
bool stereo;
|
||||
bool ppmMode;
|
||||
bool showDb;
|
||||
float panelSpacing;
|
||||
|
@ -12,10 +12,12 @@ ScopeContext::ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext) :
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void ScopeContext::DrawBegin() {
|
||||
glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g,
|
||||
ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
void ScopeContext::DrawBegin(bool clear) {
|
||||
if (clear) {
|
||||
glClearColor(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g,
|
||||
ThemeMgr::mgr.currentTheme->scopeBackground.b, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
@ -11,7 +11,7 @@ class ScopeContext: public PrimaryGLContext {
|
||||
public:
|
||||
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
|
||||
|
||||
void DrawBegin();
|
||||
void DrawBegin(bool clear=true);
|
||||
void DrawTunerTitles(bool ppmMode=false);
|
||||
void DrawDeviceName(std::string deviceName);
|
||||
void DrawDivider();
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
#include <wx/numformatter.h>
|
||||
|
||||
#define MIN_BANDWIDTH 1500
|
||||
|
||||
wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas)
|
||||
EVT_PAINT(WaterfallCanvas::OnPaint)
|
||||
EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)
|
||||
@ -44,6 +42,7 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
||||
preBuf = false;
|
||||
SetCursor(wxCURSOR_CROSS);
|
||||
scaleMove = 0;
|
||||
minBandwidth = 30000;
|
||||
}
|
||||
|
||||
WaterfallCanvas::~WaterfallCanvas() {
|
||||
@ -179,8 +178,8 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||
|
||||
if (currentZoom < 1) {
|
||||
bw = (long long) ceil((long double) bw * currentZoom);
|
||||
if (bw < 30000) {
|
||||
bw = 30000;
|
||||
if (bw < minBandwidth) {
|
||||
bw = minBandwidth;
|
||||
}
|
||||
if (mouseInView) {
|
||||
long long mfreqA = getFrequencyAt(mpos);
|
||||
@ -461,7 +460,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
bwDiff = -bwDiff;
|
||||
}
|
||||
|
||||
int currentBW = demod->getBandwidth();
|
||||
int currentBW = dragBW;
|
||||
|
||||
currentBW = currentBW + bwDiff;
|
||||
if (currentBW > CHANNELIZER_RATE_MAX) {
|
||||
@ -472,6 +471,7 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||
}
|
||||
|
||||
demod->setBandwidth(currentBW);
|
||||
dragBW = currentBW;
|
||||
}
|
||||
|
||||
if (dragState == WF_DRAG_FREQUENCY) {
|
||||
@ -596,11 +596,13 @@ void WaterfallCanvas::OnMouseDown(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseDown(event);
|
||||
|
||||
dragState = nextDragState;
|
||||
wxGetApp().getDemodMgr().updateLastState();
|
||||
|
||||
if (dragState && dragState != WF_DRAG_RANGE) {
|
||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator();
|
||||
if (demod) {
|
||||
dragOfs = (long long) (mouseTracker.getMouseX() * (float) getBandwidth()) + getCenterFrequency() - (getBandwidth() / 2) - demod->getFrequency();
|
||||
dragBW = demod->getBandwidth();
|
||||
}
|
||||
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false);
|
||||
}
|
||||
@ -615,6 +617,7 @@ void WaterfallCanvas::OnMouseWheelMoved(wxMouseEvent& event) {
|
||||
|
||||
void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
InteractiveCanvas::OnMouseReleased(event);
|
||||
wxGetApp().getDemodMgr().updateLastState();
|
||||
|
||||
bool isNew = shiftDown || (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL)
|
||||
|| (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive());
|
||||
@ -651,6 +654,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
|
||||
if (dragState == WF_DRAG_NONE) {
|
||||
if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) {
|
||||
mgr->updateLastState();
|
||||
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
} else {
|
||||
isNew = true;
|
||||
@ -663,7 +667,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
|
||||
demod->setGain(mgr->getLastGain());
|
||||
demod->setMuted(mgr->isLastMuted());
|
||||
|
||||
demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType()));
|
||||
demod->run();
|
||||
|
||||
wxGetApp().bindDemodulator(demod);
|
||||
@ -676,7 +680,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
|
||||
demod->updateLabel(freq);
|
||||
demod->setFrequency(freq);
|
||||
|
||||
|
||||
if (isNew) {
|
||||
setStatusText("New demodulator at frequency: %s", freq);
|
||||
} else {
|
||||
@ -684,13 +688,14 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
}
|
||||
|
||||
wxGetApp().getDemodMgr().setActiveDemodulator(demod, false);
|
||||
SetCursor(wxCURSOR_SIZING);
|
||||
SetCursor(wxCURSOR_SIZING);
|
||||
nextDragState = WF_DRAG_FREQUENCY;
|
||||
mouseTracker.setVertDragLock(true);
|
||||
mouseTracker.setHorizDragLock(false);
|
||||
} else {
|
||||
if (activeDemod) {
|
||||
wxGetApp().getDemodMgr().setActiveDemodulator(activeDemod, false);
|
||||
mgr->updateLastState();
|
||||
activeDemod->setTracking(true);
|
||||
nextDragState = WF_DRAG_FREQUENCY;
|
||||
} else {
|
||||
@ -740,6 +745,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
|
||||
|
||||
if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) {
|
||||
mgr->updateLastState();
|
||||
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||
} else {
|
||||
demod = wxGetApp().getDemodMgr().newThread();
|
||||
@ -749,6 +755,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
demod->setSquelchLevel(mgr->getLastSquelchLevel());
|
||||
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
|
||||
demod->setGain(mgr->getLastGain());
|
||||
demod->setMuted(mgr->isLastMuted());
|
||||
demod->writeModemSettings(mgr->getLastModemSettings(mgr->getLastDemodulatorType()));
|
||||
|
||||
demod->run();
|
||||
|
||||
@ -765,7 +773,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
||||
demod->updateLabel(freq);
|
||||
demod->setFrequency(freq);
|
||||
demod->setBandwidth(bw);
|
||||
wxGetApp().getDemodMgr().setActiveDemodulator(demod, false);
|
||||
mgr->setActiveDemodulator(demod, false);
|
||||
mgr->updateLastState();
|
||||
}
|
||||
|
||||
dragState = WF_DRAG_NONE;
|
||||
@ -842,4 +851,6 @@ void WaterfallCanvas::setLinesPerSecond(int lps) {
|
||||
tex_update.unlock();
|
||||
}
|
||||
|
||||
|
||||
void WaterfallCanvas::setMinBandwidth(int min) {
|
||||
minBandwidth = min;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ public:
|
||||
SpectrumVisualDataQueue *getVisualDataQueue();
|
||||
|
||||
void setLinesPerSecond(int lps);
|
||||
void setMinBandwidth(int min);
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
@ -68,12 +69,14 @@ private:
|
||||
float hoverAlpha;
|
||||
int linesPerSecond;
|
||||
float scaleMove;
|
||||
int dragBW;
|
||||
|
||||
SpectrumVisualDataQueue visualDataQueue;
|
||||
Timer gTimer;
|
||||
double lpsIndex;
|
||||
bool preBuf;
|
||||
std::mutex tex_update;
|
||||
int minBandwidth;
|
||||
// event table
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user