diff --git a/core/src/core.cpp b/core/src/core.cpp index 775128d0..d3997fa8 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -70,10 +70,50 @@ int sdrpp_main() { spdlog::info("SDR++ v" VERSION_STR); + // ======== DEFAULT CONFIG ======== + json defConfig; + defConfig["bandColors"]["amateur"] = "#FF0000FF"; + defConfig["bandColors"]["aviation"] = "#00FF00FF"; + defConfig["bandColors"]["broadcast"] = "#0000FFFF"; + defConfig["bandColors"]["marine"] = "#00FFFFFF"; + defConfig["bandColors"]["military"] = "#FFFF00FF"; + defConfig["bandPlan"] = "General"; + defConfig["bandPlanEnabled"] = true; + defConfig["centerTuning"] = true; + defConfig["fftHeight"] = 300; + defConfig["frequency"] = 100000000.0; + defConfig["max"] = 0.0; + defConfig["maximized"] = false; + defConfig["menuOrder"] = { + "Source", + "Radio", + "Recorder", + "Sinks", + "Audio", + "Scripting", + "Band Plan", + "Display" + }; + defConfig["menuWidth"] = 300; + defConfig["min"] = -70.0; + defConfig["moduleInstances"]["Audio Sink"] = "audio_sink"; + defConfig["moduleInstances"]["PlutoSDR Source"] = "plutosdr_source"; + defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source"; + defConfig["moduleInstances"]["Radio"] = "radio"; + defConfig["moduleInstances"]["Recorder"] = "recorder"; + defConfig["moduleInstances"]["SoapySDR Source"] = "soapy_source"; + defConfig["modules"] = json::array(); + defConfig["offset"] = 0.0; + defConfig["showWaterfall"] = true; + defConfig["source"] = ""; + defConfig["streams"] = json::object(); + defConfig["windowSize"]["h"] = 720; + defConfig["windowSize"]["w"] = 1280; + // Load config spdlog::info("Loading config"); core::configManager.setPath(ROOT_DIR "/config.json"); - core::configManager.load(json()); + core::configManager.load(defConfig); core::configManager.enableAutoSave(); // Setup window diff --git a/core/src/dsp/processing.h b/core/src/dsp/processing.h index 11ec6582..1ffcc05e 100644 --- a/core/src/dsp/processing.h +++ b/core/src/dsp/processing.h @@ -219,4 +219,73 @@ namespace dsp { stream* _in; }; + + class Squelch : public generic_block { + public: + Squelch() {} + + Squelch(stream* in, float level) { init(in, level); } + + ~Squelch() { + generic_block::stop(); + delete[] normBuffer; + } + + void init(stream* in, float level) { + _in = in; + _level = level; + normBuffer = new float[STREAM_BUFFER_SIZE]; + generic_block::registerInput(_in); + generic_block::registerOutput(&out); + } + + void setInput(stream* in) { + std::lock_guard lck(generic_block::ctrlMtx); + generic_block::tempStop(); + generic_block::unregisterInput(_in); + _in = in; + generic_block::registerInput(_in); + generic_block::tempStart(); + } + + void setLevel(float level) { + _level = level; + } + + float getLevel() { + return _level; + } + + int run() { + count = _in->read(); + if (count < 0) { return -1; } + + if (out.aquire() < 0) { return -1; } + float sum = 0.0f; + volk_32fc_magnitude_32f(normBuffer, (lv_32fc_t*)_in->data, count); + volk_32f_accumulator_s32f(&sum, normBuffer, count); + sum /= (float)count; + + if (10.0f * log10f(sum) >= _level) { + memcpy(out.data, _in->data, count * sizeof(complex_t)); + } + else { + memset(out.data, 0, count * sizeof(complex_t)); + } + + _in->flush(); + out.write(count); + return count; + } + + stream out; + + + private: + int count; + float* normBuffer; + float _level = -50.0f; + stream* _in; + + }; } \ No newline at end of file diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index 81aecb43..ad3db15d 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -35,7 +35,6 @@ std::thread worker; std::mutex fft_mtx; fftwf_complex *fft_in, *fft_out; fftwf_plan p; -float* tempData; char buf[1024]; int fftSize = 8192 * 8; @@ -83,6 +82,7 @@ int fftHeight = 300; bool showMenu = true; bool centerTuning = false; dsp::stream dummyStream; +bool demoWindow = false; void windowInit() { LoadingScreen::show("Initializing UI"); @@ -234,7 +234,7 @@ void setVFO(double freq) { gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); gui::waterfall.setCenterFrequency(freq); gui::waterfall.setViewOffset(0); - sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, 0); + sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, 0); sigpath::sourceManager.tune(freq); return; } @@ -500,6 +500,7 @@ void drawWindow() { if (ImGui::Checkbox("Test technique", &dcbias.val)) { //sigpath::signalPath.setDCBiasCorrection(dcbias.val); } + ImGui::Checkbox("Show demo window", &demoWindow); ImGui::Spacing(); } @@ -575,6 +576,10 @@ void drawWindow() { if (showCredits) { credits::show(); } + + if (demoWindow) { + ImGui::ShowDemoWindow(); + } } void setViewBandwidthSlider(float bandwidth) { diff --git a/radio/src/am_demod.h b/radio/src/am_demod.h index d5de43d2..debae935 100644 --- a/radio/src/am_demod.h +++ b/radio/src/am_demod.h @@ -25,8 +25,8 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("AM")) { - _config->conf[prefix]["AM"]["bandwidth"] = bw; - _config->conf[prefix]["AM"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["AM"].contains("bandwidth")) { _config->conf[prefix]["AM"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["AM"].contains("snapInterval")) { _config->conf[prefix]["AM"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["AM"]; bw = conf["bandwidth"]; @@ -37,8 +37,10 @@ public: _config->conf[prefix]["AM"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); - demod.init(_vfo->output); + demod.init(&squelch.out); agc.init(&demod.out, 1.0f / 125.0f); @@ -52,6 +54,7 @@ public: } void start() { + squelch.start(); demod.start(); agc.start(); resamp.start(); @@ -60,6 +63,7 @@ public: } void stop() { + squelch.stop(); demod.stop(); agc.stop(); resamp.stop(); @@ -79,7 +83,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - demod.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -131,6 +135,16 @@ public: _config->conf[uiPrefix]["AM"]["snapInterval"] = snapInterval; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_am_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["AM"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -153,8 +167,10 @@ private: float audioSampRate = 48000; float bw = 12500; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::AMDemod demod; dsp::AGC agc; dsp::filter_window::BlackmanWindow win; diff --git a/radio/src/cw_demod.h b/radio/src/cw_demod.h index ae528813..27d5da28 100644 --- a/radio/src/cw_demod.h +++ b/radio/src/cw_demod.h @@ -28,8 +28,8 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("CW")) { - _config->conf[prefix]["CW"]["bandwidth"] = bw; - _config->conf[prefix]["CW"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["CW"].contains("bandwidth")) { _config->conf[prefix]["CW"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["CW"].contains("snapInterval")) { _config->conf[prefix]["CW"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["CW"]; bw = conf["bandwidth"]; @@ -40,10 +40,12 @@ public: _config->conf[prefix]["CW"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); win.init(audioBW, audioBW, bbSampRate); - resamp.init(vfo->output, &win, bbSampRate, audioSampRate); + resamp.init(&squelch.out, &win, bbSampRate, audioSampRate); win.setSampleRate(bbSampRate * resamp.getInterpolation()); resamp.updateWindow(&win); @@ -57,6 +59,7 @@ public: } void start() { + squelch.start(); resamp.start(); xlator.start(); c2r.start(); @@ -66,6 +69,7 @@ public: } void stop() { + squelch.stop(); resamp.stop(); xlator.stop(); c2r.stop(); @@ -86,7 +90,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - resamp.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -141,6 +145,16 @@ public: _config->conf[uiPrefix]["CW"]["snapInterval"] = snapInterval; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_cw_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["CW"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -163,8 +177,10 @@ private: float audioSampRate = 48000; float bw = 200; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::filter_window::BlackmanWindow win; dsp::PolyphaseResampler resamp; dsp::FrequencyXlator xlator; diff --git a/radio/src/dsb_demod.h b/radio/src/dsb_demod.h index 5963d761..a0a4080d 100644 --- a/radio/src/dsb_demod.h +++ b/radio/src/dsb_demod.h @@ -25,8 +25,8 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("DSB")) { - _config->conf[prefix]["DSB"]["bandwidth"] = bw; - _config->conf[prefix]["DSB"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["DSB"].contains("bandwidth")) { _config->conf[prefix]["DSB"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["DSB"].contains("snapInterval")) { _config->conf[prefix]["DSB"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["DSB"]; bw = conf["bandwidth"]; @@ -37,8 +37,10 @@ public: _config->conf[prefix]["DSB"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); - demod.init(_vfo->output, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB); + demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB); agc.init(&demod.out, 1.0f / 125.0f); @@ -52,6 +54,7 @@ public: } void start() { + squelch.start(); demod.start(); agc.start(); resamp.start(); @@ -60,6 +63,7 @@ public: } void stop() { + squelch.stop(); demod.stop(); agc.stop(); resamp.stop(); @@ -79,7 +83,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - demod.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -131,6 +135,16 @@ public: _config->conf[uiPrefix]["DSB"]["snapInterval"] = snapInterval; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_dsb_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["DSB"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -153,8 +167,10 @@ private: float audioSampRate = 48000; float bw = 6000; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::SSBDemod demod; dsp::AGC agc; dsp::filter_window::BlackmanWindow win; diff --git a/radio/src/fm_demod.h b/radio/src/fm_demod.h index 1b0b6b65..68e23c25 100644 --- a/radio/src/fm_demod.h +++ b/radio/src/fm_demod.h @@ -25,8 +25,8 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("FM")) { - _config->conf[prefix]["FM"]["bandwidth"] = bw; - _config->conf[prefix]["FM"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["FM"].contains("bandwidth")) { _config->conf[prefix]["FM"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["FM"].contains("snapInterval")) { _config->conf[prefix]["FM"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["FM"]; bw = conf["bandwidth"]; @@ -37,8 +37,10 @@ public: _config->conf[prefix]["FM"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); - demod.init(_vfo->output, bbSampRate, bandWidth / 2.0f); + demod.init(&squelch.out, bbSampRate, bandWidth / 2.0f); float audioBW = std::min(audioSampleRate / 2.0f, bw / 2.0f); win.init(audioBW, audioBW, bbSampRate); @@ -50,6 +52,7 @@ public: } void start() { + squelch.start(); demod.start(); resamp.start(); m2s.start(); @@ -57,6 +60,7 @@ public: } void stop() { + squelch.stop(); demod.stop(); resamp.stop(); m2s.stop(); @@ -75,7 +79,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - demod.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -127,6 +131,16 @@ public: _config->conf[uiPrefix]["FM"]["snapInterval"] = snapInterval; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_fm_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["FM"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -150,8 +164,10 @@ private: float audioSampRate = 48000; float bw = 12500; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::FMDemod demod; dsp::filter_window::BlackmanWindow win; dsp::PolyphaseResampler resamp; diff --git a/radio/src/lsb_demod.h b/radio/src/lsb_demod.h index bb3e008a..4bf23398 100644 --- a/radio/src/lsb_demod.h +++ b/radio/src/lsb_demod.h @@ -25,8 +25,8 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("LSB")) { - _config->conf[prefix]["LSB"]["bandwidth"] = bw; - _config->conf[prefix]["LSB"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["LSB"].contains("bandwidth")) { _config->conf[prefix]["LSB"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["LSB"].contains("snapInterval")) { _config->conf[prefix]["LSB"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["LSB"]; bw = conf["bandwidth"]; @@ -37,8 +37,10 @@ public: _config->conf[prefix]["LSB"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); - demod.init(_vfo->output, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB); + demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB); agc.init(&demod.out, 1.0f / 125.0f); @@ -52,6 +54,7 @@ public: } void start() { + squelch.start(); demod.start(); agc.start(); resamp.start(); @@ -60,6 +63,7 @@ public: } void stop() { + squelch.stop(); demod.stop(); agc.stop(); resamp.stop(); @@ -79,7 +83,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - demod.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -131,6 +135,16 @@ public: _config->conf[uiPrefix]["LSB"]["snapInterval"] = snapInterval; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_lsb_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["LSB"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -153,8 +167,10 @@ private: float audioSampRate = 48000; float bw = 3000; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::SSBDemod demod; dsp::AGC agc; dsp::filter_window::BlackmanWindow win; diff --git a/radio/src/raw_demod.h b/radio/src/raw_demod.h index 4c6002aa..87fe5e47 100644 --- a/radio/src/raw_demod.h +++ b/radio/src/raw_demod.h @@ -25,7 +25,7 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("RAW")) { - _config->conf[prefix]["RAW"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["RAW"].contains("snapInterval")) { _config->conf[prefix]["RAW"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["RAW"]; snapInterval = conf["snapInterval"]; @@ -34,16 +34,20 @@ public: _config->conf[prefix]["RAW"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); - c2s.init(_vfo->output); + c2s.init(&squelch.out); } void start() { + squelch.start(); c2s.start(); running = true; } void stop() { + squelch.stop(); c2s.stop(); running = false; } @@ -60,7 +64,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - c2s.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -95,6 +99,16 @@ public: _config->release(true); } + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_raw_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["RAW"]["squelchLevel"] = squelchLevel; + _config->release(true); + } + // TODO: Allow selection of the bandwidth } @@ -109,8 +123,10 @@ private: float audioSampRate = 48000; float bw = 12500; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::ComplexToStereo c2s; ConfigManager* _config; diff --git a/radio/src/usb_demod.h b/radio/src/usb_demod.h index c80c0603..f59663dc 100644 --- a/radio/src/usb_demod.h +++ b/radio/src/usb_demod.h @@ -25,8 +25,8 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("USB")) { - _config->conf[prefix]["USB"]["bandwidth"] = bw; - _config->conf[prefix]["USB"]["snapInterval"] = snapInterval; + if (!_config->conf[prefix]["USB"].contains("bandwidth")) { _config->conf[prefix]["USB"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["USB"].contains("snapInterval")) { _config->conf[prefix]["USB"]["snapInterval"] = snapInterval; } } json conf = _config->conf[prefix]["USB"]; bw = conf["bandwidth"]; @@ -37,8 +37,10 @@ public: _config->conf[prefix]["USB"]["snapInterval"] = snapInterval; } _config->release(true); + + squelch.init(_vfo->output, squelchLevel); - demod.init(_vfo->output, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB); + demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB); agc.init(&demod.out, 1.0f / 125.0f); @@ -52,6 +54,7 @@ public: } void start() { + squelch.start(); demod.start(); agc.start(); resamp.start(); @@ -60,6 +63,7 @@ public: } void stop() { + squelch.stop(); demod.stop(); agc.stop(); resamp.stop(); @@ -79,7 +83,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - demod.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -131,6 +135,16 @@ public: _config->conf[uiPrefix]["USB"]["snapInterval"] = snapInterval; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_usb_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["USB"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -153,8 +167,10 @@ private: float audioSampRate = 48000; float bw = 3000; bool running = false; + float squelchLevel = -100.0f; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::SSBDemod demod; dsp::AGC agc; dsp::filter_window::BlackmanWindow win; diff --git a/radio/src/wfm_demod.h b/radio/src/wfm_demod.h index c4b4659d..ffd7aea9 100644 --- a/radio/src/wfm_demod.h +++ b/radio/src/wfm_demod.h @@ -25,24 +25,28 @@ public: _config->aquire(); if(_config->conf.contains(prefix)) { if(!_config->conf[prefix].contains("WFM")) { - _config->conf[prefix]["WFM"]["bandwidth"] = bw; - _config->conf[prefix]["WFM"]["snapInterval"] = snapInterval; - _config->conf[prefix]["WFM"]["deempMode"] = deempId; + if (!_config->conf[prefix]["WFM"].contains("bandwidth")) { _config->conf[prefix]["WFM"]["bandwidth"] = bw; } + if (!_config->conf[prefix]["WFM"].contains("snapInterval")) { _config->conf[prefix]["WFM"]["snapInterval"] = snapInterval; } + if (!_config->conf[prefix]["WFM"].contains("deempMode")) { _config->conf[prefix]["WFM"]["deempMode"] = deempId; } + if (!_config->conf[prefix]["WFM"].contains("squelchLevel")) { _config->conf[prefix]["WFM"]["squelchLevel"] = squelchLevel; } } json conf = _config->conf[prefix]["WFM"]; bw = conf["bandwidth"]; snapInterval = conf["snapInterval"]; deempId = conf["deempMode"]; + squelchLevel = conf["squelchLevel"]; } else { _config->conf[prefix]["WFM"]["bandwidth"] = bw; _config->conf[prefix]["WFM"]["snapInterval"] = snapInterval; _config->conf[prefix]["WFM"]["deempMode"] = deempId; + _config->conf[prefix]["WFM"]["squelchLevel"] = squelchLevel; } _config->release(true); + squelch.init(_vfo->output, squelchLevel); - demod.init(_vfo->output, bbSampRate, bandWidth / 2.0f); + demod.init(&squelch.out, bbSampRate, bandWidth / 2.0f); float audioBW = std::min(audioSampleRate / 2.0f, 16000.0f); win.init(audioBW, audioBW, bbSampRate); @@ -56,6 +60,7 @@ public: } void start() { + squelch.start(); demod.start(); resamp.start(); deemp.start(); @@ -64,6 +69,7 @@ public: } void stop() { + squelch.stop(); demod.stop(); resamp.stop(); deemp.stop(); @@ -83,7 +89,7 @@ public: void setVFO(VFOManager::VFO* vfo) { _vfo = vfo; - demod.setInput(_vfo->output); + squelch.setInput(_vfo->output); } VFOManager::VFO* getVFO() { @@ -149,6 +155,16 @@ public: _config->conf[uiPrefix]["WFM"]["deempMode"] = deempId; _config->release(true); } + + ImGui::Text("Squelch"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::SliderFloat(("##_radio_wfm_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) { + squelch.setLevel(squelchLevel); + _config->aquire(); + _config->conf[uiPrefix]["WFM"]["squelchLevel"] = squelchLevel; + _config->release(true); + } } private: @@ -181,12 +197,14 @@ private: std::string uiPrefix; float snapInterval = 100000; float audioSampRate = 48000; + float squelchLevel = -100.0f; float bw = 200000; int deempId = 0; float tau = 50e-6; bool running = false; VFOManager::VFO* _vfo; + dsp::Squelch squelch; dsp::FMDemod demod; dsp::filter_window::BlackmanWindow win; dsp::PolyphaseResampler resamp; diff --git a/root_dev/config.json b/root_dev/config.json index 92c23a3c..0a166c44 100644 --- a/root_dev/config.json +++ b/root_dev/config.json @@ -3,7 +3,7 @@ "bandPlanEnabled": true, "centerTuning": false, "fftHeight": 300, - "frequency": 99716000, + "frequency": 103600000, "max": 0.0, "maximized": false, "menuOrder": [ @@ -17,7 +17,7 @@ "Display" ], "menuWidth": 300, - "min": -65.44117736816406, + "min": -66.17647552490234, "moduleInstances": { "Audio Sink": "audio_sink", "PlutoSDR Source": "plutosdr_source", @@ -27,12 +27,12 @@ "SoapySDR Source": "soapy_source" }, "modules": [ - "./radio/Release/radio.dll", - "./recorder/Release/recorder.dll", - "./soapy_source/Release/soapy_source.dll", - "./rtl_tcp_source/Release/rtl_tcp_source.dll", - "./audio_sink/Release/audio_sink.dll", - "./plutosdr_source/Release/plutosdr_source.dll" + "./radio/RelWithDebInfo/radio.dll", + "./recorder/RelWithDebInfo/recorder.dll", + "./soapy_source/RelWithDebInfo/soapy_source.dll", + "./rtl_tcp_source/RelWithDebInfo/rtl_tcp_source.dll", + "./audio_sink/RelWithDebInfo/audio_sink.dll", + "./plutosdr_source/RelWithDebInfo/plutosdr_source.dll" ], "offset": 0.0, "showWaterfall": true, @@ -41,7 +41,7 @@ "Radio": { "muted": false, "sink": "Audio", - "volume": 0.4285714328289032 + "volume": 0.6785714030265808 }, "Radio 1": { "muted": false, diff --git a/root_dev/radio_config.json b/root_dev/radio_config.json index 940ffef3..d065ee78 100644 --- a/root_dev/radio_config.json +++ b/root_dev/radio_config.json @@ -2,11 +2,13 @@ "Radio": { "AM": { "bandwidth": 12500.0, - "snapInterval": 1000.0 + "snapInterval": 1000.0, + "squelchLevel": -100.0 }, "CW": { "bandwidth": 200.0, - "snapInterval": 10.0 + "snapInterval": 10.0, + "squelchLevel": -100.0 }, "DSB": { "bandwidth": 6000.0, @@ -30,7 +32,8 @@ "WFM": { "bandwidth": 200000.0, "deempMode": 0, - "snapInterval": 100000.0 + "snapInterval": 100000.0, + "squelchLevel": -100.0 }, "selectedDemodId": 1 } diff --git a/root_dev/soapy_source_config.json b/root_dev/soapy_source_config.json index 9e18a599..9bef9c32 100644 --- a/root_dev/soapy_source_config.json +++ b/root_dev/soapy_source_config.json @@ -1,17 +1,18 @@ { - "device": "HackRF One #0 901868dc282c8f8b", + "device": "AirSpy HF+ [c852435de0224af7]", "devices": { "": { + "agc": false, "gains": { "PGA": 0.0 }, - "sampleRate": 8000000.0 + "sampleRate": 4000000.0 }, "AirSpy HF+ [c852435de0224af7]": { "agc": false, "gains": { "LNA": 6.0, - "RF": 0.0 + "RF": -48.0 }, "sampleRate": 768000.0 }, diff --git a/soapy_source/src/main.cpp b/soapy_source/src/main.cpp index 4ab5d84a..171a0bdc 100644 --- a/soapy_source/src/main.cpp +++ b/soapy_source/src/main.cpp @@ -143,6 +143,8 @@ private: hasAgc = dev->hasGainMode(SOAPY_SDR_RX, channelId); + hasIQBalance = dev->hasIQBalanceMode(SOAPY_SDR_RX, channelId); + SoapySDR::Device::unmake(dev); config.aquire(); @@ -163,6 +165,12 @@ private: else { agc = false; } + if (hasIQBalance && config.conf["devices"][name].contains("iqBalance")) { + iqBalance = config.conf["devices"][name]["iqBalance"]; + } + else { + iqBalance = false; + } if (config.conf["devices"][name].contains("sampleRate")) { selectSampleRate(config.conf["devices"][name]["sampleRate"]); } @@ -196,6 +204,9 @@ private: if (hasAgc) { conf["agc"] = agc; } + if (hasIQBalance) { + conf["iqBalance"] = iqBalance; + } config.aquire(); config.conf["devices"][devArgs["label"]] = conf; config.release(true); @@ -231,6 +242,10 @@ private: _this->dev->setGainMode(SOAPY_SDR_RX, _this->channelId, _this->agc); } + if (_this->hasIQBalance) { + _this->dev->setIQBalanceMode(SOAPY_SDR_RX, _this->channelId, _this->iqBalance); + } + _this->dev->setFrequency(SOAPY_SDR_RX, _this->channelId, _this->freq); _this->devStream = _this->dev->setupStream(SOAPY_SDR_RX, "CF32"); @@ -322,6 +337,13 @@ private: } } + if (_this->hasIQBalance) { + if (ImGui::Checkbox((std::string("AGC##_iq_bal_sel_") + _this->name).c_str(), &_this->iqBalance)) { + if (_this->running) { _this->dev->setIQBalanceMode(SOAPY_SDR_RX, _this->channelId, _this->iqBalance); } + _this->saveCurrent(); + } + } + int i = 0; for (auto gain : _this->gainList) { ImGui::Text("%s gain", gain.c_str()); @@ -371,6 +393,8 @@ private: bool running = false; bool hasAgc = false; bool agc = false; + bool hasIQBalance = false; + bool iqBalance = false; std::vector sampleRates; int srId = -1; float* uiGains;