Merge pull request #199 from cjcliffe/digital_experiments

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

View File

@ -14,7 +14,7 @@ SET(CPACK_PACKAGE_VERSION_PATCH ${CUBICSDR_VERSION_PATCH})
SET (VERSION_SUFFIX "" CACHE STRING "Add custom version suffix to CubicSDR application title.")
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

View File

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

View File

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

View File

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

View File

@ -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
View File

@ -0,0 +1,179 @@
#include "ModemProperties.h"
#include "CubicSDR.h"
ModemProperties::ModemProperties(wxWindow *parent, wxWindowID winid,
const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxPanel(parent, winid, pos, size, style, name) {
m_propertyGrid = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE);
bSizer = new wxBoxSizer( wxVERTICAL );
bSizer->Add(m_propertyGrid, 1, wxEXPAND, 5);
this->SetSizer(bSizer);
m_propertyGrid->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( ModemProperties::OnChange ), NULL, this );
this->Connect( wxEVT_SHOW, wxShowEventHandler( ModemProperties::OnShow ), NULL, this );
this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseEnter ), NULL, this);
this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseLeave ), NULL, this);
mouseInView = false;
}
void ModemProperties::OnShow(wxShowEvent &event) {
}
ModemProperties::~ModemProperties() {
}
void ModemProperties::initProperties(ModemArgInfoList newArgs) {
args = newArgs;
bSizer->Layout();
m_propertyGrid->Clear();
if (newArgs.size() == 0) {
Hide();
return;
} else {
Show();
}
m_propertyGrid->Append(new wxPropertyCategory("Modem Settings"));
ModemArgInfoList::const_iterator args_i;
for (args_i = args.begin(); args_i != args.end(); args_i++) {
ModemArgInfo arg = (*args_i);
props[arg.key] = addArgInfoProperty(m_propertyGrid, arg);
}
m_propertyGrid->FitColumns();
}
wxPGProperty *ModemProperties::addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg) {
wxPGProperty *prop = nullptr;
int intVal;
double floatVal;
std::vector<std::string>::iterator stringIter;
switch (arg.type) {
case ModemArgInfo::INT:
try {
intVal = std::stoi(arg.value);
} catch (std::invalid_argument e) {
intVal = 0;
}
prop = pg->Append( new wxIntProperty(arg.name, wxPG_LABEL, intVal) );
if (arg.range.minimum() != arg.range.maximum()) {
pg->SetPropertyAttribute( prop, wxPG_ATTR_MIN, arg.range.minimum());
pg->SetPropertyAttribute( prop, wxPG_ATTR_MAX, arg.range.maximum());
}
break;
case ModemArgInfo::FLOAT:
try {
floatVal = std::stod(arg.value);
} catch (std::invalid_argument e) {
floatVal = 0;
}
prop = pg->Append( new wxFloatProperty(arg.name, wxPG_LABEL, floatVal) );
if (arg.range.minimum() != arg.range.maximum()) {
pg->SetPropertyAttribute( prop, wxPG_ATTR_MIN, arg.range.minimum());
pg->SetPropertyAttribute( prop, wxPG_ATTR_MAX, arg.range.maximum());
}
break;
case ModemArgInfo::BOOL:
prop = pg->Append( new wxBoolProperty(arg.name, wxPG_LABEL, (arg.value=="true")) );
break;
case ModemArgInfo::STRING:
if (arg.options.size()) {
intVal = 0;
prop = pg->Append( new wxEnumProperty(arg.name, wxPG_LABEL) );
for (stringIter = arg.options.begin(); stringIter != arg.options.end(); stringIter++) {
std::string optName = (*stringIter);
std::string displayName = optName;
if (arg.optionNames.size()) {
displayName = arg.optionNames[intVal];
}
prop->AddChoice(displayName);
if ((*stringIter)==arg.value) {
prop->SetChoiceSelection(intVal);
}
intVal++;
}
} else {
prop = pg->Append( new wxStringProperty(arg.name, wxPG_LABEL, arg.value) );
}
break;
case ModemArgInfo::PATH_DIR:
break;
case ModemArgInfo::PATH_FILE:
break;
case ModemArgInfo::COLOR:
break;
}
if (prop != NULL) {
prop->SetHelpString(arg.key + ": " + arg.description);
}
return prop;
}
std::string ModemProperties::readProperty(std::string key) {
int i = 0;
ModemArgInfoList::const_iterator args_i;
for (args_i = args.begin(); args_i != args.end(); args_i++) {
ModemArgInfo arg = (*args_i);
if (arg.key == key) {
wxPGProperty *prop = props[key];
std::string result = "";
if (arg.type == ModemArgInfo::STRING && arg.options.size()) {
return arg.options[prop->GetChoiceSelection()];
} else if (arg.type == ModemArgInfo::BOOL) {
return (prop->GetValueAsString()=="True")?"true":"false";
} else {
return prop->GetValueAsString().ToStdString();
}
}
i++;
}
return "";
}
void ModemProperties::OnChange(wxPropertyGridEvent &event) {
DemodulatorInstance *inst = wxGetApp().getDemodMgr().getLastActiveDemodulator();
if (!inst) {
return;
}
std::map<std::string, wxPGProperty *>::const_iterator prop_i;
for (prop_i = props.begin(); prop_i != props.end(); prop_i++) {
if (prop_i->second == event.m_property) {
std::string key = prop_i->first;
std::string value = readProperty(prop_i->first);
inst->writeModemSetting(key, value);
return;
}
}
}
void ModemProperties::OnMouseEnter(wxMouseEvent &event) {
mouseInView = true;
}
void ModemProperties::OnMouseLeave(wxMouseEvent &event) {
mouseInView = false;
}
bool ModemProperties::isMouseInView() {
return mouseInView;
}

39
src/ModemProperties.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/advprops.h>
#include "Modem.h"
class ModemProperties : public wxPanel {
public:
ModemProperties(
wxWindow *parent,
wxWindowID winid = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxNO_BORDER,
const wxString& name = wxPanelNameStr
);
~ModemProperties();
void initProperties(ModemArgInfoList newArgs);
bool isMouseInView();
private:
wxPGProperty *addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg);
std::string readProperty(std::string);
void OnChange(wxPropertyGridEvent &event);
void OnShow(wxShowEvent &event);
void OnMouseEnter(wxMouseEvent &event);
void OnMouseLeave(wxMouseEvent &event);
wxBoxSizer* bSizer;
wxPropertyGrid* m_propertyGrid;
ModemArgInfoList args;
std::map<std::string, wxPGProperty *> props;
bool mouseInView;
};

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &params_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;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,138 @@
#include "DigitalConsole.h"
#include "CubicSDR.h"
#include <iomanip>
DigitalConsole::DigitalConsole( wxWindow* parent, ModemDigitalOutputConsole *doParent ): DigitalConsoleFrame( parent ), doParent(doParent) {
streamWritten.store(false);
streamPaused.store(false);
}
DigitalConsole::~DigitalConsole() {
doParent->setDialog(nullptr);
}
void DigitalConsole::OnClose( wxCloseEvent& event ) {
doParent->setDialog(nullptr);
}
void DigitalConsole::OnCopy( wxCommandEvent& event ) {
m_dataView->SelectAll();
m_dataView->Copy();
}
void DigitalConsole::OnPause( wxCommandEvent& event ) {
if (streamPaused.load()) {
m_pauseButton->SetLabel("Stop");
streamPaused.store(false);
} else {
m_pauseButton->SetLabel("Run");
streamPaused.store(true);
}
}
void DoRefresh( wxTimerEvent& event ) {
event.Skip();
}
void DigitalConsole::DoRefresh( wxTimerEvent& event ) {
if (streamWritten.load()) {
stream_busy.lock();
m_dataView->AppendText(streamBuf.str());
streamBuf.str("");
streamWritten.store(false);
stream_busy.unlock();
}
}
void DigitalConsole::OnClear( wxCommandEvent& event ) {
m_dataView->Clear();
}
void DigitalConsole::write(std::string outp) {
if (streamPaused.load()) {
return;
}
stream_busy.lock();
streamBuf << outp;
streamWritten.store(true);
stream_busy.unlock();
}
void DigitalConsole::write(char outc) {
if (streamPaused.load()) {
return;
}
stream_busy.lock();
streamBuf << outc;
streamWritten.store(true);
stream_busy.unlock();
}
ModemDigitalOutputConsole::ModemDigitalOutputConsole(): ModemDigitalOutput(), dialog(nullptr) {
streamWritten.store(false);
}
ModemDigitalOutputConsole::~ModemDigitalOutputConsole() {
}
void ModemDigitalOutputConsole::setDialog(DigitalConsole *dialog_in) {
dialog = dialog_in;
if (dialog && dialogTitle != "") {
dialog->SetTitle(dialogTitle);
}
}
DigitalConsole *ModemDigitalOutputConsole::getDialog() {
return dialog;
}
void ModemDigitalOutputConsole::Show() {
if (!dialog) {
return;
}
if (!dialog->IsShown()) {
dialog->Show();
}
}
void ModemDigitalOutputConsole::Hide() {
if (!dialog) {
return;
}
if (dialog->IsShown()) {
dialog->Hide();
}
}
void ModemDigitalOutputConsole::Close() {
if (!dialog) {
return;
}
dialog->Hide();
dialog->Close();
dialog = nullptr;
}
void ModemDigitalOutputConsole::setTitle(std::string title) {
if (dialog) {
dialog->SetTitle(title);
}
dialogTitle = title;
}
void ModemDigitalOutputConsole::write(std::string outp) {
if (!dialog) {
return;
}
dialog->write(outp);
}
void ModemDigitalOutputConsole::write(char outc) {
if (!dialog) {
return;
}
dialog->write(outc);
}

View File

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

View File

@ -0,0 +1,61 @@
#pragma once
#include <map>
#include <vector>
#include <sstream>
#include <ostream>
#include <mutex>
#include "DigitalConsoleFrame.h"
#include "ModemDigital.h"
class ModemDigitalOutputConsole;
class DigitalConsole: public DigitalConsoleFrame {
public:
DigitalConsole( wxWindow* parent, ModemDigitalOutputConsole *doParent );
~DigitalConsole();
void write(std::string outp);
void write(char outc);
private:
void DoRefresh( wxTimerEvent& event );
void OnClose( wxCloseEvent& event );
void OnClear( wxCommandEvent& event );
void OnCopy( wxCommandEvent& event );
void OnPause( wxCommandEvent& event );
std::stringstream streamBuf;
std::mutex stream_busy;
std::atomic<bool> streamWritten;
std::atomic<bool> streamPaused;
ModemDigitalOutputConsole *doParent;
};
class ModemDigitalOutputConsole: public ModemDigitalOutput {
public:
ModemDigitalOutputConsole();
~ModemDigitalOutputConsole();
void setDialog(DigitalConsole *dialog_in);
DigitalConsole *getDialog();
void setTitle(std::string title);
void write(std::string outp);
void write(char outc);
void Show();
void Hide();
void Close();
private:
DigitalConsole *dialog;
std::stringstream streamBuf;
std::mutex stream_busy;
std::atomic<bool> streamWritten;
std::string dialogTitle;
};

View File

@ -0,0 +1,73 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Aug 23 2015)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "DigitalConsoleFrame.h"
///////////////////////////////////////////////////////////////////////////
DigitalConsoleFrame::DigitalConsoleFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
this->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES );
wxBoxSizer* mainSizer;
mainSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* dataViewSizer;
dataViewSizer = new wxBoxSizer( wxVERTICAL );
m_dataView = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CHARWRAP|wxTE_MULTILINE|wxTE_NOHIDESEL|wxTE_READONLY|wxTE_WORDWRAP|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE|wxNO_BORDER|wxSIMPLE_BORDER|wxVSCROLL );
m_dataView->SetExtraStyle( wxWS_EX_PROCESS_UI_UPDATES );
m_dataView->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 76, 90, 90, false, wxEmptyString ) );
dataViewSizer->Add( m_dataView, 1, wxEXPAND, 5 );
mainSizer->Add( dataViewSizer, 1, wxEXPAND, 5 );
wxBoxSizer* buttonSizer;
buttonSizer = new wxBoxSizer( wxHORIZONTAL );
m_clearButton = new wxButton( this, wxID_ANY, wxT("Clear"), wxDefaultPosition, wxDefaultSize, 0 );
buttonSizer->Add( m_clearButton, 1, wxEXPAND, 5 );
m_copyButton = new wxButton( this, wxID_ANY, wxT("Copy"), wxDefaultPosition, wxDefaultSize, 0 );
buttonSizer->Add( m_copyButton, 1, wxEXPAND, 5 );
m_pauseButton = new wxButton( this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0 );
buttonSizer->Add( m_pauseButton, 1, wxEXPAND, 5 );
mainSizer->Add( buttonSizer, 0, wxALL|wxEXPAND, 5 );
this->SetSizer( mainSizer );
this->Layout();
m_refreshTimer.SetOwner( this, wxID_ANY );
m_refreshTimer.Start( 250 );
this->Centre( wxBOTH );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DigitalConsoleFrame::OnClose ) );
m_clearButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnClear ), NULL, this );
m_copyButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnCopy ), NULL, this );
m_pauseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnPause ), NULL, this );
this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( DigitalConsoleFrame::DoRefresh ) );
}
DigitalConsoleFrame::~DigitalConsoleFrame()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DigitalConsoleFrame::OnClose ) );
m_clearButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnClear ), NULL, this );
m_copyButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnCopy ), NULL, this );
m_pauseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DigitalConsoleFrame::OnPause ), NULL, this );
this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( DigitalConsoleFrame::DoRefresh ) );
}

View File

@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Aug 23 2015)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIGITALCONSOLEFRAME_H__
#define __DIGITALCONSOLEFRAME_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/timer.h>
#include <wx/frame.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DigitalConsoleFrame
///////////////////////////////////////////////////////////////////////////////
class DigitalConsoleFrame : public wxFrame
{
private:
protected:
wxTextCtrl* m_dataView;
wxButton* m_clearButton;
wxButton* m_copyButton;
wxButton* m_pauseButton;
wxTimer m_refreshTimer;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
virtual void OnClear( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCopy( wxCommandEvent& event ) { event.Skip(); }
virtual void OnPause( wxCommandEvent& event ) { event.Skip(); }
virtual void DoRefresh( wxTimerEvent& event ) { event.Skip(); }
public:
DigitalConsoleFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Digital Output"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 441,394 ), long style = wxCAPTION|wxFRAME_FLOAT_ON_PARENT|wxMAXIMIZE|wxMAXIMIZE_BOX|wxMINIMIZE|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL );
~DigitalConsoleFrame();
};
#endif //__DIGITALCONSOLEFRAME_H__

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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:

View File

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

View File

@ -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:

View File

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

View File

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

View File

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

View File

@ -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:

View File

@ -4,15 +4,6 @@ ModemIQ::ModemIQ() {
}
Modem *ModemIQ::factory() {
return new ModemIQ;
}
ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) {
ModemKit *kit = new ModemKit;
return kit;
}
std::string ModemIQ::getType() {
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();

View File

@ -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:

View File

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

View File

@ -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:

View File

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

View File

@ -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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,143 @@
#include "ModemFSK.h"
#include <iomanip>
ModemFSK::ModemFSK() : ModemDigital() {
// DMR defaults?
bps = 1;
sps = 9600;
bw = 0.45;
outStream << std::hex;
}
Modem *ModemFSK::factory() {
return new ModemFSK;
}
int ModemFSK::checkSampleRate(long long sampleRate, int audioSampleRate) {
float minSps = pow(2.0,bps);
float nextSps = (float(sampleRate) / float(sps));
if (nextSps < minSps) {
return 2 * bps * sps;
} else {
return sampleRate;
}
}
int ModemFSK::getDefaultSampleRate() {
return 19200;
}
ModemArgInfoList ModemFSK::getSettings() {
ModemArgInfoList args;
ModemArgInfo bpsArg;
bpsArg.key = "bps";
bpsArg.name = "Bits/symbol";
bpsArg.value = std::to_string(bps);
bpsArg.description = "Modem bits-per-symbol";
bpsArg.type = ModemArgInfo::STRING;
bpsArg.units = "bits";
std::vector<std::string> bpsOpts;
bpsOpts.push_back("1");
bpsOpts.push_back("2");
bpsOpts.push_back("4");
bpsOpts.push_back("8");
bpsOpts.push_back("16");
bpsArg.options = bpsOpts;
args.push_back(bpsArg);
ModemArgInfo spsArg;
spsArg.key = "sps";
spsArg.name = "Symbols/second";
spsArg.value = std::to_string(sps);
spsArg.description = "Modem symbols-per-second";
spsArg.type = ModemArgInfo::INT;
spsArg.range = ModemRange(10,115200);
std::vector<std::string> spsOpts;
args.push_back(spsArg);
ModemArgInfo bwArg;
bwArg.key = "bw";
bwArg.name = "Signal bandwidth";
bwArg.value = std::to_string(bw);
bwArg.description = "Total signal bandwidth";
bwArg.type = ModemArgInfo::FLOAT;
bwArg.range = ModemRange(0.1,0.49);
args.push_back(bwArg);
return args;
}
void ModemFSK::writeSetting(std::string setting, std::string value) {
if (setting == "bps") {
bps = std::stoi(value);
rebuildKit();
} else if (setting == "sps") {
sps = std::stoi(value);
rebuildKit();
} else if (setting == "bw") {
bw = std::stof(value);
rebuildKit();
}
}
std::string ModemFSK::readSetting(std::string setting) {
if (setting == "bps") {
return std::to_string(bps);
} else if (setting == "sps") {
return std::to_string(sps);
} else if (setting == "bw") {
return std::to_string(bw);
}
return "";
}
ModemKit *ModemFSK::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitFSK *dkit = new ModemKitFSK;
dkit->m = bps;
dkit->k = sampleRate / sps;
dkit->bw = bw;
dkit->demodFSK = fskdem_create(dkit->m, dkit->k, dkit->bw);
dkit->sampleRate = sampleRate;
dkit->audioSampleRate = audioSampleRate;
return dkit;
}
void ModemFSK::disposeKit(ModemKit *kit) {
ModemKitFSK *dkit = (ModemKitFSK *)kit;
fskdem_destroy(dkit->demodFSK);
delete dkit;
}
std::string ModemFSK::getName() {
return "FSK";
}
ModemFSK::~ModemFSK() {
}
void ModemFSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitFSK *dkit = (ModemKitFSK *)kit;
digitalStart(dkit, nullptr, input);
dkit->inputBuffer.insert(dkit->inputBuffer.end(),input->data.begin(),input->data.end());
while (dkit->inputBuffer.size() >= dkit->k) {
outStream << fskdem_demodulate(dkit->demodFSK, &dkit->inputBuffer[0]);
// float err = fskdem_get_frequency_error(dkit->demodFSK);
dkit->inputBuffer.erase(dkit->inputBuffer.begin(),dkit->inputBuffer.begin()+dkit->k);
}
digitalFinish(dkit, nullptr);
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "ModemDigital.h"
#include <sstream>
class ModemKitFSK : public ModemKitDigital {
public:
unsigned int m, k;
float bw;
fskdem demodFSK;
std::vector<liquid_float_complex> inputBuffer;
};
class ModemFSK : public ModemDigital {
public:
ModemFSK();
~ModemFSK();
std::string getName();
Modem *factory();
int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
int sps, bps;
float bw;
};

View File

@ -0,0 +1,133 @@
#include "ModemGMSK.h"
#include <iomanip>
ModemGMSK::ModemGMSK() : ModemDigital() {
_sps = 4;
_fdelay = 3;
_ebf = 0.3;
outStream << std::hex;
}
ModemGMSK::~ModemGMSK() {
}
std::string ModemGMSK::getName() {
return "GMSK";
}
Modem *ModemGMSK::factory() {
return new ModemGMSK;
}
int ModemGMSK::checkSampleRate(long long sampleRate, int audioSampleRate) {
if (sampleRate < MIN_BANDWIDTH) {
return MIN_BANDWIDTH;
}
return sampleRate;
}
int ModemGMSK::getDefaultSampleRate() {
return 19200;
}
ModemArgInfoList ModemGMSK::getSettings() {
ModemArgInfoList args;
ModemArgInfo fdelayArg;
fdelayArg.key = "fdelay";
fdelayArg.name = "Filter delay";
fdelayArg.value = std::to_string(_fdelay);
fdelayArg.description = "Filter delay in samples";
fdelayArg.type = ModemArgInfo::INT;
fdelayArg.units = "samples";
fdelayArg.range = ModemRange(1,128);
args.push_back(fdelayArg);
ModemArgInfo spsArg;
spsArg.key = "sps";
spsArg.name = "Samples / symbol";
spsArg.value = std::to_string(_sps);
spsArg.description = "Modem samples-per-symbol";
spsArg.type = ModemArgInfo::INT;
spsArg.units = "samples/symbol";
spsArg.range = ModemRange(2,512);
args.push_back(spsArg);
ModemArgInfo ebfArg;
ebfArg.key = "ebf";
ebfArg.name = "Excess bandwidth";
ebfArg.value = std::to_string(_ebf);
ebfArg.description = "Modem excess bandwidth factor";
ebfArg.type = ModemArgInfo::FLOAT;
ebfArg.range = ModemRange(0.1,0.49);
args.push_back(ebfArg);
return args;
}
void ModemGMSK::writeSetting(std::string setting, std::string value) {
if (setting == "fdelay") {
_fdelay = std::stoi(value);
rebuildKit();
} else if (setting == "sps") {
_sps = std::stoi(value);
rebuildKit();
} else if (setting == "ebf") {
_ebf = std::stof(value);
rebuildKit();
}
}
std::string ModemGMSK::readSetting(std::string setting) {
if (setting == "fdelay") {
return std::to_string(_fdelay);
} else if (setting == "sps") {
return std::to_string(_sps);
} else if (setting == "ebf") {
return std::to_string(_ebf);
}
return "";
}
ModemKit *ModemGMSK::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitGMSK *dkit = new ModemKitGMSK;
dkit->sps = _sps;
dkit->fdelay = _fdelay;
dkit->ebf = _ebf;
dkit->demodGMSK = gmskdem_create(dkit->sps, dkit->fdelay, dkit->ebf);
dkit->sampleRate = sampleRate;
dkit->audioSampleRate = audioSampleRate;
return dkit;
}
void ModemGMSK::disposeKit(ModemKit *kit) {
ModemKitGMSK *dkit = (ModemKitGMSK *)kit;
gmskdem_destroy(dkit->demodGMSK);
delete dkit;
}
void ModemGMSK::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitGMSK *dkit = (ModemKitGMSK *)kit;
unsigned int sym_out;
digitalStart(dkit, nullptr, input);
dkit->inputBuffer.insert(dkit->inputBuffer.end(),input->data.begin(),input->data.end());
int numProcessed = 0;
for (int i = 0, iMax = dkit->inputBuffer.size()/dkit->sps; i < iMax; i+= dkit->sps) {
gmskdem_demodulate(dkit->demodGMSK, &input->data[i],&sym_out);
outStream << sym_out;
numProcessed += dkit->sps;
}
dkit->inputBuffer.erase(dkit->inputBuffer.begin(),dkit->inputBuffer.begin()+numProcessed);
digitalFinish(dkit, nullptr);
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "ModemDigital.h"
#include <sstream>
class ModemKitGMSK : public ModemKitDigital {
public:
unsigned int fdelay, sps;
float ebf;
gmskdem demodGMSK;
std::vector<liquid_float_complex> inputBuffer;
};
class ModemGMSK : public ModemDigital {
public:
ModemGMSK();
~ModemGMSK();
std::string getName();
Modem *factory();
int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate();
ModemArgInfoList getSettings();
void writeSetting(std::string setting, std::string value);
std::string readSetting(std::string setting);
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
int _sps; // samples per symbol
int _fdelay; // filter delay
float _ebf;
};

View File

@ -1,13 +1,9 @@
#include "ModemOOK.h"
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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:

View File

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

View File

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

View File

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

View File

@ -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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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