mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2026-04-18 22:32:44 +00:00
bugfix, new squelch system, dragon labs source
This commit is contained in:
@@ -20,6 +20,16 @@ enum IFNRPreset {
|
||||
IFNR_PRESET_BROADCAST
|
||||
};
|
||||
|
||||
enum SquelchMode {
|
||||
SQUELCH_MODE_OFF,
|
||||
SQUELCH_MODE_POWER,
|
||||
SQUELCH_MODE_SNR,
|
||||
SQUELCH_MODE_CTCSS_MUTE,
|
||||
SQUELCH_MODE_CTCSS_DECODE,
|
||||
SQUELCH_MODE_DCS_MUTE,
|
||||
SQUELCH_MODE_DCS_DECODE,
|
||||
};
|
||||
|
||||
namespace demod {
|
||||
class Demodulator {
|
||||
public:
|
||||
@@ -45,6 +55,8 @@ namespace demod {
|
||||
virtual int getDefaultDeemphasisMode() = 0;
|
||||
virtual bool getFMIFNRAllowed() = 0;
|
||||
virtual bool getNBAllowed() = 0;
|
||||
virtual bool getHighPassAllowed() = 0;
|
||||
virtual bool getSquelchAllowed() = 0;
|
||||
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@ namespace demod {
|
||||
|
||||
void showMenu() {
|
||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||
if (ImGui::Checkbox(("Carrier AGC##_radio_am_carrier_agc_" + name).c_str(), &carrierAgc)) {
|
||||
demod.setAGCMode(carrierAgc ? dsp::demod::AM<dsp::stereo_t>::AGCMode::CARRIER : dsp::demod::AM<dsp::stereo_t>::AGCMode::AUDIO);
|
||||
_config->acquire();
|
||||
_config->conf[name][getName()]["carrierAgc"] = carrierAgc;
|
||||
_config->release(true);
|
||||
}
|
||||
ImGui::LeftLabel("AGC Attack");
|
||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::SliderFloat(("##_radio_am_agc_attack_" + name).c_str(), &agcAttack, 1.0f, 200.0f)) {
|
||||
@@ -56,12 +62,6 @@ namespace demod {
|
||||
_config->conf[name][getName()]["agcDecay"] = agcDecay;
|
||||
_config->release(true);
|
||||
}
|
||||
if (ImGui::Checkbox(("Carrier AGC##_radio_am_carrier_agc_" + name).c_str(), &carrierAgc)) {
|
||||
demod.setAGCMode(carrierAgc ? dsp::demod::AM<dsp::stereo_t>::AGCMode::CARRIER : dsp::demod::AM<dsp::stereo_t>::AGCMode::AUDIO);
|
||||
_config->acquire();
|
||||
_config->conf[name][getName()]["carrierAgc"] = carrierAgc;
|
||||
_config->release(true);
|
||||
}
|
||||
}
|
||||
|
||||
void setBandwidth(double bandwidth) { demod.setBandwidth(bandwidth); }
|
||||
@@ -86,6 +86,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return false; }
|
||||
bool getNBAllowed() { return false; }
|
||||
bool getHighPassAllowed() { return true; }
|
||||
bool getSquelchAllowed() { return true; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -92,6 +92,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return false; }
|
||||
bool getNBAllowed() { return false; }
|
||||
bool getHighPassAllowed() { return false; }
|
||||
bool getSquelchAllowed() { return false; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return false; }
|
||||
bool getNBAllowed() { return true; }
|
||||
bool getHighPassAllowed() { return true; }
|
||||
bool getSquelchAllowed() { return true; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return false; }
|
||||
bool getNBAllowed() { return true; }
|
||||
bool getHighPassAllowed() { return true; }
|
||||
bool getSquelchAllowed() { return true; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,14 +22,11 @@ namespace demod {
|
||||
if (config->conf[name][getName()].contains("lowPass")) {
|
||||
_lowPass = config->conf[name][getName()]["lowPass"];
|
||||
}
|
||||
if (config->conf[name][getName()].contains("highPass")) {
|
||||
_highPass = config->conf[name][getName()]["highPass"];
|
||||
}
|
||||
_config->release();
|
||||
|
||||
|
||||
// Define structure
|
||||
demod.init(input, getIFSampleRate(), bandwidth, _lowPass, _highPass);
|
||||
demod.init(input, getIFSampleRate(), bandwidth, _lowPass);
|
||||
}
|
||||
|
||||
void start() { demod.start(); }
|
||||
@@ -43,12 +40,6 @@ namespace demod {
|
||||
_config->conf[name][getName()]["lowPass"] = _lowPass;
|
||||
_config->release(true);
|
||||
}
|
||||
if (ImGui::Checkbox(("High Pass##_radio_wfm_highpass_" + name).c_str(), &_highPass)) {
|
||||
demod.setHighPass(_highPass);
|
||||
_config->acquire();
|
||||
_config->conf[name][getName()]["highPass"] = _highPass;
|
||||
_config->release(true);
|
||||
}
|
||||
}
|
||||
|
||||
void setBandwidth(double bandwidth) {
|
||||
@@ -75,6 +66,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return true; }
|
||||
bool getNBAllowed() { return false; }
|
||||
bool getHighPassAllowed() { return true; }
|
||||
bool getSquelchAllowed() { return true; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
private:
|
||||
@@ -83,7 +76,6 @@ namespace demod {
|
||||
ConfigManager* _config = NULL;
|
||||
|
||||
bool _lowPass = true;
|
||||
bool _highPass = false;
|
||||
|
||||
std::string name;
|
||||
};
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return false; }
|
||||
bool getNBAllowed() { return true; }
|
||||
bool getHighPassAllowed() { return false; }
|
||||
bool getSquelchAllowed() { return false; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -80,6 +80,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_NONE; }
|
||||
bool getFMIFNRAllowed() { return false; }
|
||||
bool getNBAllowed() { return true; }
|
||||
bool getHighPassAllowed() { return true; }
|
||||
bool getSquelchAllowed() { return true; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -100,18 +100,18 @@ namespace demod {
|
||||
}
|
||||
|
||||
void showMenu() {
|
||||
if (ImGui::Checkbox(("Stereo##_radio_wfm_stereo_" + name).c_str(), &_stereo)) {
|
||||
setStereo(_stereo);
|
||||
_config->acquire();
|
||||
_config->conf[name][getName()]["stereo"] = _stereo;
|
||||
_config->release(true);
|
||||
}
|
||||
if (ImGui::Checkbox(("Low Pass##_radio_wfm_lowpass_" + name).c_str(), &_lowPass)) {
|
||||
demod.setLowPass(_lowPass);
|
||||
_config->acquire();
|
||||
_config->conf[name][getName()]["lowPass"] = _lowPass;
|
||||
_config->release(true);
|
||||
}
|
||||
if (ImGui::Checkbox(("Stereo##_radio_wfm_stereo_" + name).c_str(), &_stereo)) {
|
||||
setStereo(_stereo);
|
||||
_config->acquire();
|
||||
_config->conf[name][getName()]["stereo"] = _stereo;
|
||||
_config->release(true);
|
||||
}
|
||||
if (ImGui::Checkbox(("Decode RDS##_radio_wfm_rds_" + name).c_str(), &_rds)) {
|
||||
demod.setRDSOut(_rds);
|
||||
_config->acquire();
|
||||
@@ -270,6 +270,8 @@ namespace demod {
|
||||
int getDefaultDeemphasisMode() { return DEEMP_MODE_50US; }
|
||||
bool getFMIFNRAllowed() { return true; }
|
||||
bool getNBAllowed() { return false; }
|
||||
bool getHighPassAllowed() { return true; }
|
||||
bool getSquelchAllowed() { return true; }
|
||||
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
|
||||
|
||||
// ============= DEDICATED FUNCTIONS =============
|
||||
|
||||
@@ -5,10 +5,14 @@ enum {
|
||||
RADIO_IFACE_CMD_SET_MODE,
|
||||
RADIO_IFACE_CMD_GET_BANDWIDTH,
|
||||
RADIO_IFACE_CMD_SET_BANDWIDTH,
|
||||
RADIO_IFACE_CMD_GET_SQUELCH_ENABLED,
|
||||
RADIO_IFACE_CMD_SET_SQUELCH_ENABLED,
|
||||
RADIO_IFACE_CMD_GET_SQUELCH_MODE,
|
||||
RADIO_IFACE_CMD_SET_SQUELCH_MODE,
|
||||
RADIO_IFACE_CMD_GET_SQUELCH_LEVEL,
|
||||
RADIO_IFACE_CMD_SET_SQUELCH_LEVEL,
|
||||
RADIO_IFACE_CMD_GET_CTCSS_TONE,
|
||||
RADIO_IFACE_CMD_SET_CTCSS_TONE,
|
||||
RADIO_IFACE_CMD_GET_HIGHPASS,
|
||||
RADIO_IFACE_CMD_SET_HIGHPASS
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#include <dsp/chain.h>
|
||||
#include <dsp/noise_reduction/noise_blanker.h>
|
||||
#include <dsp/noise_reduction/fm_if.h>
|
||||
#include <dsp/noise_reduction/squelch.h>
|
||||
#include <dsp/noise_reduction/power_squelch.h>
|
||||
#include <dsp/noise_reduction/ctcss_squelch.h>
|
||||
#include <dsp/multirate/rational_resampler.h>
|
||||
#include <dsp/filter/deephasis.h>
|
||||
#include <core.h>
|
||||
@@ -49,6 +50,22 @@ public:
|
||||
ifnrPresets.define("Voice", IFNR_PRESET_VOICE);
|
||||
ifnrPresets.define("Narrow Band", IFNR_PRESET_NARROW_BAND);
|
||||
|
||||
squelchModes.define("off", "Off", SQUELCH_MODE_OFF);
|
||||
squelchModes.define("power", "Power", SQUELCH_MODE_POWER);
|
||||
//squelchModes.define("snr", "SNR", SQUELCH_MODE_SNR);
|
||||
squelchModes.define("ctcss_mute", "CTCSS (Mute)", SQUELCH_MODE_CTCSS_MUTE);
|
||||
squelchModes.define("ctcss_decode", "CTCSS (Decode Only)", SQUELCH_MODE_CTCSS_DECODE);
|
||||
//squelchModes.define("dcs_mute", "DCS (Mute)", SQUELCH_MODE_DCS_MUTE);
|
||||
//squelchModes.define("dcs_decode", "DCS (Decode Only)", SQUELCH_MODE_DCS_DECODE);
|
||||
|
||||
for (int i = 0; i < dsp::noise_reduction::_CTCSS_TONE_COUNT; i++) {
|
||||
float tone = dsp::noise_reduction::CTCSS_TONES[i];
|
||||
char buf[64];
|
||||
sprintf(buf, "%.1fHz", tone);
|
||||
ctcssTones.define((int)round(tone) * 10, buf, (dsp::noise_reduction::CTCSSTone)i);
|
||||
}
|
||||
ctcssTones.define(-1, "Any", dsp::noise_reduction::CTCSS_TONE_ANY);
|
||||
|
||||
// Initialize the config if it doesn't exist
|
||||
bool created = false;
|
||||
config.acquire();
|
||||
@@ -72,19 +89,24 @@ public:
|
||||
|
||||
nb.init(NULL, 500.0 / 24000.0, 10.0);
|
||||
fmnr.init(NULL, 32);
|
||||
squelch.init(NULL, MIN_SQUELCH);
|
||||
powerSquelch.init(NULL, MIN_SQUELCH);
|
||||
|
||||
ifChain.addBlock(&nb, false);
|
||||
ifChain.addBlock(&squelch, false);
|
||||
ifChain.addBlock(&powerSquelch, false);
|
||||
ifChain.addBlock(&fmnr, false);
|
||||
|
||||
// Initialize audio DSP chain
|
||||
afChain.init(&dummyAudioStream);
|
||||
|
||||
ctcss.init(NULL, 50000.0);
|
||||
resamp.init(NULL, 250000.0, 48000.0);
|
||||
hpTaps = dsp::taps::highPass(300.0, 100.0, 48000.0);
|
||||
hpf.init(NULL, hpTaps);
|
||||
deemp.init(NULL, 50e-6, 48000.0);
|
||||
|
||||
afChain.addBlock(&ctcss, false);
|
||||
afChain.addBlock(&resamp, true);
|
||||
afChain.addBlock(&hpf, false);
|
||||
afChain.addBlock(&deemp, false);
|
||||
|
||||
// Initialize the sink
|
||||
@@ -233,6 +255,33 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Squelch
|
||||
if (_this->squelchAllowed) {
|
||||
ImGui::LeftLabel("Squelch Mode");
|
||||
ImGui::FillWidth();
|
||||
if (ImGui::Combo(("##_radio_sqelch_mode_" + _this->name).c_str(), &_this->squelchModeId, _this->squelchModes.txt)) {
|
||||
_this->setSquelchMode(_this->squelchModes[_this->squelchModeId]);
|
||||
}
|
||||
switch (_this->squelchModes[_this->squelchModeId]) {
|
||||
case SQUELCH_MODE_POWER:
|
||||
ImGui::LeftLabel("Squelch Level");
|
||||
ImGui::FillWidth();
|
||||
if (ImGui::SliderFloat(("##_radio_sqelch_lvl_" + _this->name).c_str(), &_this->squelchLevel, _this->MIN_SQUELCH, _this->MAX_SQUELCH, "%.3fdB")) {
|
||||
_this->setSquelchLevel(_this->squelchLevel);
|
||||
}
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_CTCSS_MUTE:
|
||||
if (_this->squelchModes[_this->squelchModeId] == SQUELCH_MODE_CTCSS_MUTE) {
|
||||
ImGui::LeftLabel("CTCSS Tone");
|
||||
ImGui::FillWidth();
|
||||
if (ImGui::Combo(("##_radio_ctcss_tone_" + _this->name).c_str(), &_this->ctcssToneId, _this->ctcssTones.txt)) {
|
||||
_this->setCTCSSTone(_this->ctcssTones[_this->ctcssToneId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Noise blanker
|
||||
if (_this->nbAllowed) {
|
||||
if (ImGui::Checkbox(("Noise blanker (W.I.P.)##_radio_nb_ena_" + _this->name).c_str(), &_this->nbEnabled)) {
|
||||
@@ -246,19 +295,6 @@ private:
|
||||
}
|
||||
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
|
||||
}
|
||||
|
||||
|
||||
// Squelch
|
||||
if (ImGui::Checkbox(("Squelch##_radio_sqelch_ena_" + _this->name).c_str(), &_this->squelchEnabled)) {
|
||||
_this->setSquelchEnabled(_this->squelchEnabled);
|
||||
}
|
||||
if (!_this->squelchEnabled && _this->enabled) { style::beginDisabled(); }
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::SliderFloat(("##_radio_sqelch_lvl_" + _this->name).c_str(), &_this->squelchLevel, _this->MIN_SQUELCH, _this->MAX_SQUELCH, "%.3fdB")) {
|
||||
_this->setSquelchLevel(_this->squelchLevel);
|
||||
}
|
||||
if (!_this->squelchEnabled && _this->enabled) { style::endDisabled(); }
|
||||
|
||||
// FM IF Noise Reduction
|
||||
if (_this->FMIFNRAllowed) {
|
||||
@@ -276,9 +312,53 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// High pass
|
||||
if (_this->highPassAllowed) {
|
||||
if (ImGui::Checkbox(("High Pass##_radio_hpf_" + _this->name).c_str(), &_this->highPass)) {
|
||||
_this->setHighPass(_this->highPass);
|
||||
}
|
||||
}
|
||||
|
||||
// Demodulator specific menu
|
||||
_this->selectedDemod->showMenu();
|
||||
|
||||
// Display the squelch diagnostics
|
||||
switch (_this->squelchModes[_this->squelchModeId]) {
|
||||
case SQUELCH_MODE_CTCSS_MUTE:
|
||||
ImGui::TextUnformatted("Received Tone:");
|
||||
ImGui::SameLine();
|
||||
{
|
||||
auto ctone = _this->ctcss.getCurrentTone();
|
||||
auto dtone = _this->ctcssTones[_this->ctcssToneId];
|
||||
if (ctone != dsp::noise_reduction::CTCSS_TONE_NONE) {
|
||||
if (dtone == dsp::noise_reduction::CTCSS_TONE_ANY || ctone == dtone) {
|
||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "%.1fHz", dsp::noise_reduction::CTCSS_TONES[_this->ctcss.getCurrentTone()]);
|
||||
}
|
||||
else {
|
||||
ImGui::TextColored(ImVec4(1, 0, 0, 1), "%.1fHz", dsp::noise_reduction::CTCSS_TONES[_this->ctcss.getCurrentTone()]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ImGui::TextUnformatted("None");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_CTCSS_DECODE:
|
||||
ImGui::TextUnformatted("Received Tone:");
|
||||
ImGui::SameLine();
|
||||
{
|
||||
auto ctone = _this->ctcss.getCurrentTone();
|
||||
if (ctone != dsp::noise_reduction::CTCSS_TONE_NONE) {
|
||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), "%.1fHz", dsp::noise_reduction::CTCSS_TONES[_this->ctcss.getCurrentTone()]);
|
||||
}
|
||||
else {
|
||||
ImGui::TextUnformatted("None");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_this->enabled) { style::endDisabled(); }
|
||||
}
|
||||
|
||||
@@ -287,13 +367,13 @@ private:
|
||||
switch (id) {
|
||||
case DemodID::RADIO_DEMOD_NFM: demod = new demod::NFM(); break;
|
||||
case DemodID::RADIO_DEMOD_WFM: demod = new demod::WFM(); break;
|
||||
case DemodID::RADIO_DEMOD_AM: demod = new demod::AM(); break;
|
||||
case DemodID::RADIO_DEMOD_AM: demod = new demod::AM(); break;
|
||||
case DemodID::RADIO_DEMOD_DSB: demod = new demod::DSB(); break;
|
||||
case DemodID::RADIO_DEMOD_USB: demod = new demod::USB(); break;
|
||||
case DemodID::RADIO_DEMOD_CW: demod = new demod::CW(); break;
|
||||
case DemodID::RADIO_DEMOD_CW: demod = new demod::CW(); break;
|
||||
case DemodID::RADIO_DEMOD_LSB: demod = new demod::LSB(); break;
|
||||
case DemodID::RADIO_DEMOD_RAW: demod = new demod::RAW(); break;
|
||||
default: demod = NULL; break;
|
||||
default: demod = NULL; break;
|
||||
}
|
||||
if (!demod) { return NULL; }
|
||||
|
||||
@@ -360,15 +440,20 @@ private:
|
||||
maxBandwidth = selectedDemod->getMaxBandwidth();
|
||||
bandwidthLocked = selectedDemod->getBandwidthLocked();
|
||||
snapInterval = selectedDemod->getDefaultSnapInterval();
|
||||
squelchLevel = MIN_SQUELCH;
|
||||
deempAllowed = selectedDemod->getDeempAllowed();
|
||||
deempId = deempModes.valueId((DeemphasisMode)selectedDemod->getDefaultDeemphasisMode());
|
||||
squelchEnabled = false;
|
||||
squelchModeId = squelchModes.valueId(SQUELCH_MODE_OFF);
|
||||
squelchLevel = MIN_SQUELCH;
|
||||
ctcssToneId = ctcssTones.valueId(dsp::noise_reduction::CTCSS_TONE_67Hz);
|
||||
highPass = false;
|
||||
|
||||
postProcEnabled = selectedDemod->getPostProcEnabled();
|
||||
FMIFNRAllowed = selectedDemod->getFMIFNRAllowed();
|
||||
FMIFNREnabled = false;
|
||||
fmIFPresetId = ifnrPresets.valueId(IFNR_PRESET_VOICE);
|
||||
nbAllowed = selectedDemod->getNBAllowed();
|
||||
squelchAllowed = selectedDemod->getSquelchAllowed();
|
||||
highPassAllowed = selectedDemod->getHighPassAllowed();
|
||||
nbEnabled = false;
|
||||
nbLevel = 0.0f;
|
||||
double ifSamplerate = selectedDemod->getIFSampleRate();
|
||||
@@ -380,11 +465,24 @@ private:
|
||||
if (config.conf[name][selectedDemod->getName()].contains("snapInterval")) {
|
||||
snapInterval = config.conf[name][selectedDemod->getName()]["snapInterval"];
|
||||
}
|
||||
|
||||
if (config.conf[name][selectedDemod->getName()].contains("squelchMode")) {
|
||||
std::string squelchModeStr = config.conf[name][selectedDemod->getName()]["squelchMode"];
|
||||
if (squelchModes.keyExists(squelchModeStr)) {
|
||||
squelchModeId = squelchModes.keyId(squelchModeStr);
|
||||
}
|
||||
}
|
||||
if (config.conf[name][selectedDemod->getName()].contains("squelchLevel")) {
|
||||
squelchLevel = config.conf[name][selectedDemod->getName()]["squelchLevel"];
|
||||
}
|
||||
if (config.conf[name][selectedDemod->getName()].contains("squelchEnabled")) {
|
||||
squelchEnabled = config.conf[name][selectedDemod->getName()]["squelchEnabled"];
|
||||
if (config.conf[name][selectedDemod->getName()].contains("ctcssTone")) {
|
||||
int ctcssToneX10 = config.conf[name][selectedDemod->getName()]["ctcssTone"];
|
||||
if (ctcssTones.keyExists(ctcssToneX10)) {
|
||||
ctcssToneId = ctcssTones.keyId(ctcssToneX10);
|
||||
}
|
||||
}
|
||||
if (config.conf[name][selectedDemod->getName()].contains("highPass")) {
|
||||
highPass = config.conf[name][selectedDemod->getName()]["highPass"];
|
||||
}
|
||||
if (config.conf[name][selectedDemod->getName()].contains("deempMode")) {
|
||||
if (!config.conf[name][selectedDemod->getName()]["deempMode"].is_string()) {
|
||||
@@ -434,16 +532,22 @@ private:
|
||||
setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false);
|
||||
|
||||
// Configure squelch
|
||||
setSquelchMode(squelchAllowed ? squelchModes[squelchModeId] : SQUELCH_MODE_OFF);
|
||||
setSquelchLevel(squelchLevel);
|
||||
setSquelchEnabled(squelchEnabled);
|
||||
setCTCSSTone(ctcssTones[ctcssToneId]);
|
||||
|
||||
// Configure AF chain
|
||||
if (postProcEnabled) {
|
||||
// Configure resampler
|
||||
afChain.stop();
|
||||
resamp.setInSamplerate(selectedDemod->getAFSampleRate());
|
||||
setAudioSampleRate(audioSampleRate);
|
||||
double afsr = selectedDemod->getAFSampleRate();
|
||||
ctcss.setSamplerate(afsr);
|
||||
resamp.setInSamplerate(afsr);
|
||||
afChain.enableBlock(&resamp, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||
setAudioSampleRate(audioSampleRate);
|
||||
|
||||
// Configure the HPF
|
||||
setHighPass(highPass && highPassAllowed);
|
||||
|
||||
// Configure deemphasis
|
||||
setDeemphasisMode(deempModes[deempId]);
|
||||
@@ -489,12 +593,32 @@ private:
|
||||
// Configure resampler
|
||||
resamp.setOutSamplerate(audioSampleRate);
|
||||
|
||||
// Configure the HPF sample rate
|
||||
hpTaps = dsp::taps::highPass(300.0, 100.0, audioSampleRate);
|
||||
hpf.setTaps(hpTaps);
|
||||
|
||||
// Configure deemphasis sample rate
|
||||
deemp.setSamplerate(audioSampleRate);
|
||||
|
||||
afChain.start();
|
||||
}
|
||||
|
||||
void setHighPass(bool enabled) {
|
||||
// Update the state
|
||||
highPass = enabled;
|
||||
|
||||
// Check if post-processing is enabled and that a demodulator is selected
|
||||
if (!postProcEnabled || !selectedDemod) { return; }
|
||||
|
||||
// Set the state of the HPF in the AF chain
|
||||
afChain.setBlockEnabled(&hpf, enabled, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||
|
||||
// Save config
|
||||
config.acquire();
|
||||
config.conf[name][selectedDemod->getName()]["highPass"] = enabled;
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
void setDeemphasisMode(DeemphasisMode mode) {
|
||||
deempId = deempModes.valueId(mode);
|
||||
if (!postProcEnabled || !selectedDemod) { return; }
|
||||
@@ -522,6 +646,7 @@ private:
|
||||
void setNBLevel(float level) {
|
||||
nbLevel = std::clamp<float>(level, MIN_NB, MAX_NB);
|
||||
nb.setLevel(nbLevel);
|
||||
if (!selectedDemod) { return; }
|
||||
|
||||
// Save config
|
||||
config.acquire();
|
||||
@@ -529,20 +654,59 @@ private:
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
void setSquelchEnabled(bool enable) {
|
||||
squelchEnabled = enable;
|
||||
void setSquelchMode(SquelchMode mode) {
|
||||
squelchModeId = squelchModes.valueId(mode);
|
||||
if (!selectedDemod) { return; }
|
||||
ifChain.setBlockEnabled(&squelch, squelchEnabled, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
||||
|
||||
// Disable all squelch blocks
|
||||
ifChain.disableBlock(&powerSquelch, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
||||
afChain.disableBlock(&ctcss, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||
|
||||
// Enable the block depending on the mode
|
||||
switch (mode) {
|
||||
case SQUELCH_MODE_OFF:
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_POWER:
|
||||
// Enable the power squelch block
|
||||
ifChain.enableBlock(&powerSquelch, [=](dsp::stream<dsp::complex_t>* out){ selectedDemod->setInput(out); });
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_SNR:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_CTCSS_MUTE:
|
||||
// Set the required tone and enable the CTCSS squelch block
|
||||
ctcss.setRequiredTone(ctcssTones[ctcssToneId]);
|
||||
afChain.enableBlock(&ctcss, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_CTCSS_DECODE:
|
||||
// Set the required tone to none and enable the CTCSS squelch block
|
||||
ctcss.setRequiredTone(dsp::noise_reduction::CTCSS_TONE_NONE);
|
||||
afChain.enableBlock(&ctcss, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_DCS_MUTE:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case SQUELCH_MODE_DCS_DECODE:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
// Save config
|
||||
config.acquire();
|
||||
config.conf[name][selectedDemod->getName()]["squelchEnabled"] = squelchEnabled;
|
||||
config.conf[name][selectedDemod->getName()]["squelchMode"] = squelchModes.key(squelchModeId);
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
void setSquelchLevel(float level) {
|
||||
squelchLevel = std::clamp<float>(level, MIN_SQUELCH, MAX_SQUELCH);
|
||||
squelch.setLevel(squelchLevel);
|
||||
powerSquelch.setLevel(squelchLevel);
|
||||
if (!selectedDemod) { return; }
|
||||
|
||||
// Save config
|
||||
config.acquire();
|
||||
@@ -550,6 +714,24 @@ private:
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
void setCTCSSTone(dsp::noise_reduction::CTCSSTone tone) {
|
||||
// Check for an invalid value
|
||||
if (tone == dsp::noise_reduction::CTCSS_TONE_NONE) { return; }
|
||||
|
||||
// If not in CTCSS mute mode, do nothing
|
||||
if (squelchModes[squelchModeId] != SQUELCH_MODE_CTCSS_MUTE) { return; }
|
||||
|
||||
// Set the tone
|
||||
ctcssToneId = ctcssTones.valueId(tone);
|
||||
ctcss.setRequiredTone(tone);
|
||||
if (!selectedDemod) { return; }
|
||||
|
||||
// Save config
|
||||
config.acquire();
|
||||
config.conf[name][selectedDemod->getName()]["ctcssTone"] = ctcssTones.key(ctcssToneId);
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
void setFMIFNREnabled(bool enabled) {
|
||||
FMIFNREnabled = enabled;
|
||||
if (!selectedDemod) { return; }
|
||||
@@ -619,13 +801,13 @@ private:
|
||||
if (_this->bandwidthLocked) { return; }
|
||||
_this->setBandwidth(*_in);
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_ENABLED && out) {
|
||||
bool* _out = (bool*)out;
|
||||
*_out = _this->squelchEnabled;
|
||||
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_MODE && out) {
|
||||
SquelchMode* _out = (SquelchMode*)out;
|
||||
*_out = _this->squelchModes[_this->squelchModeId];
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_ENABLED && in && _this->enabled) {
|
||||
bool* _in = (bool*)in;
|
||||
_this->setSquelchEnabled(*_in);
|
||||
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_MODE && in && _this->enabled) {
|
||||
SquelchMode* _in = (SquelchMode*)in;
|
||||
_this->setSquelchMode(*_in);
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_GET_SQUELCH_LEVEL && out) {
|
||||
float* _out = (float*)out;
|
||||
@@ -635,6 +817,22 @@ private:
|
||||
float* _in = (float*)in;
|
||||
_this->setSquelchLevel(*_in);
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_GET_CTCSS_TONE && out) {
|
||||
dsp::noise_reduction::CTCSSTone* _out = (dsp::noise_reduction::CTCSSTone*)out;
|
||||
*_out = _this->ctcssTones[_this->ctcssToneId];
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_SET_CTCSS_TONE && in && _this->enabled) {
|
||||
dsp::noise_reduction::CTCSSTone* _in = (dsp::noise_reduction::CTCSSTone*)in;
|
||||
_this->setCTCSSTone(*_in);
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_GET_HIGHPASS && out) {
|
||||
bool* _out = (bool*)out;
|
||||
*_out = _this->highPass;
|
||||
}
|
||||
else if (code == RADIO_IFACE_CMD_SET_HIGHPASS && in && _this->enabled) {
|
||||
bool* _in = (bool*)in;
|
||||
_this->setHighPass(*_in);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
@@ -655,12 +853,15 @@ private:
|
||||
dsp::chain<dsp::complex_t> ifChain;
|
||||
dsp::noise_reduction::NoiseBlanker nb;
|
||||
dsp::noise_reduction::FMIF fmnr;
|
||||
dsp::noise_reduction::Squelch squelch;
|
||||
dsp::noise_reduction::PowerSquelch powerSquelch;
|
||||
|
||||
// Audio chain
|
||||
dsp::stream<dsp::stereo_t> dummyAudioStream;
|
||||
dsp::chain<dsp::stereo_t> afChain;
|
||||
dsp::noise_reduction::CTCSSSquelch ctcss;
|
||||
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
||||
dsp::tap<float> hpTaps;
|
||||
dsp::filter::FIR<dsp::stereo_t, float> hpf;
|
||||
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
||||
|
||||
SinkManager::Stream stream;
|
||||
@@ -669,6 +870,8 @@ private:
|
||||
|
||||
OptionList<std::string, DeemphasisMode> deempModes;
|
||||
OptionList<std::string, IFNRPreset> ifnrPresets;
|
||||
OptionList<std::string, SquelchMode> squelchModes;
|
||||
OptionList<int, dsp::noise_reduction::CTCSSTone> ctcssTones;
|
||||
|
||||
double audioSampleRate = 48000.0;
|
||||
float minBandwidth;
|
||||
@@ -679,8 +882,13 @@ private:
|
||||
int selectedDemodID = 1;
|
||||
bool postProcEnabled;
|
||||
|
||||
bool squelchEnabled = false;
|
||||
int squelchModeId = 0;
|
||||
float squelchLevel;
|
||||
int ctcssToneId = 0;
|
||||
bool squelchAllowed = false;
|
||||
|
||||
bool highPass = false;
|
||||
bool highPassAllowed = false;
|
||||
|
||||
int deempId = 0;
|
||||
bool deempAllowed;
|
||||
|
||||
Reference in New Issue
Block a user