diff --git a/openrtx/include/rtx/OpMode_FM.h b/openrtx/include/rtx/OpMode_FM.h index b91ec5da..e3774d3f 100644 --- a/openrtx/include/rtx/OpMode_FM.h +++ b/openrtx/include/rtx/OpMode_FM.h @@ -83,7 +83,8 @@ public: private: - bool sqlOpen; ///< Flag for current squelch status. + bool rfSqlOpen; ///< Flag for RF squelch status (analog squelch). + bool sqlOpen; ///< Flag for squelch status. bool enterRx; ///< Flag for RX management. }; diff --git a/openrtx/src/rtx/OpMode_FM.cpp b/openrtx/src/rtx/OpMode_FM.cpp index 3f2ebdc1..541c3dc3 100644 --- a/openrtx/src/rtx/OpMode_FM.cpp +++ b/openrtx/src/rtx/OpMode_FM.cpp @@ -66,7 +66,7 @@ void _setVolume() } #endif -OpMode_FM::OpMode_FM() : sqlOpen(false), enterRx(true) +OpMode_FM::OpMode_FM() : rfSqlOpen(false), sqlOpen(false), enterRx(true) { } @@ -77,8 +77,9 @@ OpMode_FM::~OpMode_FM() void OpMode_FM::enable() { // When starting, close squelch and prepare for entering in RX mode. - sqlOpen = false; - enterRx = true; + rfSqlOpen = false; + sqlOpen = false; + enterRx = true; } void OpMode_FM::disable() @@ -87,8 +88,9 @@ void OpMode_FM::disable() audio_disableAmp(); audio_disableMic(); radio_disableRtx(); - sqlOpen = false; - enterRx = false; + rfSqlOpen = false; + sqlOpen = false; + enterRx = false; } void OpMode_FM::update(rtxStatus_t *const status, const bool newCfg) @@ -98,28 +100,34 @@ void OpMode_FM::update(rtxStatus_t *const status, const bool newCfg) // RX logic if(status->opStatus == RX) { + // RF squelch mechanism float squelch = -127.0f + status->sqlLevel * 66.0f / 15.0f; float rssi = rtx_getRssi(); + if((rfSqlOpen == false) && (rssi > (squelch + 0.1f))) rfSqlOpen = true; + if((rfSqlOpen == true) && (rssi < (squelch - 0.1f))) rfSqlOpen = false; - if((sqlOpen == false) && (rssi > (squelch + 0.1f))) + // Local flags for current RF and tone squelch status + bool rfSql = ((status->rxToneEn == 0) && (rfSqlOpen == true)); + bool toneSql = ((status->rxToneEn == 1) && radio_checkRxDigitalSquelch()); + + // Audio control + if((sqlOpen == false) && (rfSql || toneSql)) { audio_enableAmp(); sqlOpen = true; } - if((sqlOpen == true) && (rssi < (squelch - 0.1f))) + if((sqlOpen == true) && (rfSql == false) && (toneSql == false)) { audio_disableAmp(); sqlOpen = false; } #ifdef PLATFORM_MDUV3x0 - if(sqlOpen == true) - { - // Set output volume by changing the HR_C6000 DAC gain - _setVolume(); - } + // Set output volume by changing the HR_C6000 DAC gain + if(sqlOpen == true) _setVolume(); #endif + } else if((status->opStatus == OFF) && enterRx) { @@ -130,7 +138,7 @@ void OpMode_FM::update(rtxStatus_t *const status, const bool newCfg) enterRx = false; } - /* TX logic */ + // TX logic if(platform_getPttStatus() && (status->opStatus != TX) && (status->txDisable == 0)) { @@ -156,13 +164,20 @@ void OpMode_FM::update(rtxStatus_t *const status, const bool newCfg) switch(status->opStatus) { case RX: - if(sqlOpen) + if(radio_checkRxDigitalSquelch()) { - platform_ledOn(GREEN); + platform_ledOn(GREEN); // Red + green LEDs ("orange"): tone squelch open + platform_ledOn(RED); + } + else if(rfSqlOpen) + { + platform_ledOn(GREEN); // Green LED only: RF squelch open + platform_ledOff(RED); } else { platform_ledOff(GREEN); + platform_ledOff(RED); } break; diff --git a/platform/drivers/baseband/AT1846S.h b/platform/drivers/baseband/AT1846S.h index ae374b70..90356a6b 100644 --- a/platform/drivers/baseband/AT1846S.h +++ b/platform/drivers/baseband/AT1846S.h @@ -96,6 +96,7 @@ public: /** * Set the VCO frequency, either for transmission or reception. + * * @param freq: VCO frequency. */ void setFrequency(const freq_t freq) @@ -113,18 +114,21 @@ public: /** * Set the transmission and reception bandwidth. + * * @param band: bandwidth. */ void setBandwidth(const AT1846S_BW band); /** * Set the operating mode. + * * @param mode: operating mode. */ void setOpMode(const AT1846S_OpMode mode); /** * Set the functional mode. + * * @param mode: functional mode. */ void setFuncMode(const AT1846S_FuncMode mode) @@ -140,14 +144,42 @@ public: /** * Enable the CTCSS tone for transmission. + * * @param freq: CTCSS tone frequency. */ void enableTxCtcss(const tone_t freq) { - i2c_writeReg16(0x4A, freq*10); - i2c_writeReg16(0x4B, 0x0000); + i2c_writeReg16(0x4A, freq*10); // Set CTCSS1 frequency reg. + i2c_writeReg16(0x4B, 0x0000); // Clear CDCSS bits i2c_writeReg16(0x4C, 0x0000); - maskSetRegister(0x4E, 0x0600, 0x0600); + maskSetRegister(0x4E, 0x0600, 0x0600); // Enable CTCSS TX + } + + /** + * Enable the CTCSS tone detection during reception. + * + * @param freq: CTCSS tone frequency. + */ + void enableRxCtcss(const tone_t freq) + { + i2c_writeReg16(0x4D, freq*10); // Set CTCSS2 frequency reg. + i2c_writeReg16(0x5B, getCtcssThreshFromTone(freq)); + maskSetRegister(0x3A, 0x001F, 0x0008); // Enable CTCSS2 freq. detection + } + + /** + * Check if CTCSS tone is detected when in RX mode. + * + * @return true if the RX CTCSS tone is being detected. + */ + inline bool rxCtcssDetected() + { + // Check if CTCSS detection is enabled: if not, return false. + if((i2c_readReg16(0x3A) & 0x0008) == 0) return false; + + // Check CTCSS2 compare flag + uint16_t reg = i2c_readReg16(0x1C); + return ((reg & 0x100) != 0); } /** @@ -155,12 +187,15 @@ public: */ inline void disableCtcss() { - i2c_writeReg16(0x4A, 0x0000); - maskSetRegister(0x4E, 0x0600, 0x0000); // Disable TX CTCSS + maskSetRegister(0x4E, 0x0600, 0x0000); // Disable TX CTCSS + maskSetRegister(0x3A, 0x001F, 0x0000); // Disable CTCSS freq. detection + i2c_writeReg16(0x4A, 0x0000); // Clear CTCSS1 frequency reg. + i2c_writeReg16(0x4D, 0x0000); // Clear CTCSS2 frequency reg. } /** * Get current RSSI value. + * * @return current RSSI in dBm. */ inline int16_t readRSSI() @@ -171,6 +206,7 @@ public: /** * Set the gain of internal programmable gain amplifier. + * * @param gain: PGA gain. */ inline void setPgaGain(const uint8_t gain) @@ -181,6 +217,7 @@ public: /** * Set microphone gain for transmission. + * * @param gain: microphone gain. */ inline void setMicGain(const uint8_t gain) @@ -190,6 +227,7 @@ public: /** * Set maximum FM transmission deviation. + * * @param dev: maximum allowed deviation. */ inline void setTxDeviation(const uint16_t dev) @@ -200,6 +238,7 @@ public: /** * Set the gain for internal automatic gain control system. + * * @param gain: AGC gain. */ inline void setAgcGain(const uint8_t gain) @@ -210,6 +249,7 @@ public: /** * Set audio gain for recepion. + * * @param analogDacGain: "analog DAC gain" in AT1846S manual. * @param digitalGain: "digital voice gain" in AT1846S manual. */ @@ -223,6 +263,7 @@ public: /** * Set noise1 thresholds for squelch opening and closing. + * * @param highTsh: upper threshold. * @param lowTsh: lower threshold. */ @@ -234,6 +275,7 @@ public: /** * Set noise2 thresholds for squelch opening and closing. + * * @param highTsh: upper threshold. * @param lowTsh: lower threshold. */ @@ -245,6 +287,7 @@ public: /** * Set RSSI thresholds for squelch opening and closing. + * * @param highTsh: upper threshold. * @param lowTsh: lower threshold. */ @@ -256,6 +299,7 @@ public: /** * Set PA drive control bits. + * * @param value: PA drive value. */ inline void setPaDrive(const uint8_t value) @@ -266,6 +310,7 @@ public: /** * Set threshold for analog FM squelch opening. + * * @param thresh: squelch threshold. */ inline void setAnalogSqlThresh(const uint8_t thresh) @@ -332,6 +377,67 @@ private: * @param reg: address of the register to be read. */ uint16_t i2c_readReg16(const uint8_t reg); + + /** + * This function returns the value to be written into the AT1846S CTCSS + * threshold register when enabling the detection in RX mode. + * Values were obtained from the function contained in TYT firmware for + * MD-UV380 version S18.16 at address 0x0806ba2c. + * + * @param tone: tone_t variable specifying the CTCSS tone. + * @return an uint16_t value to be written directly into AT1846S + * CTCSS threshold register. + */ + uint16_t getCtcssThreshFromTone(const tone_t tone) + { + switch(tone) + { + case 670: return 0x0C0D; break; // 67.0 Hz + case 693: return 0x0C0C; break; // 69.3 Hz + case 719: return 0x0B0B; break; // 71.9 Hz + case 744: // 74.4 Hz + case 770: return 0x0A0A; break; // 77.0 Hz + case 797: // 79.7 Hz + case 825: return 0x0909; break; // 82.5 Hz + case 854: // 85.4 Hz + case 885: return 0x0808; break; // 88.5 Hz + case 915: // 91.5 Hz + case 948: return 0x0707; break; // 94.8 Hz + case 974: return 0x0706; break; // 97.4 Hz + case 1000: // 100.0Hz + case 1034: return 0x0606; break; // 103.4Hz + case 1072: // 107.2Hz + case 1109: return 0x0605; break; // 110.9Hz + case 1148: return 0x0505; break; // 114.8Hz + case 1188: // 118.8Hz + case 1230: return 0x0504; break; // 123.0Hz + case 1273: // 127.3Hz + case 1318: return 0x0404; break; // 131.8Hz + case 1365: // 136.5Hz + case 1413: // 141.3Hz + case 1462: return 0x0403; break; // 146.2Hz + case 1514: return 0x0504; break; // 151.4Hz + case 1567: // 156.7Hz + case 1622: // 162.2Hz + case 1679: // 167.9Hz + case 1713: // 171.3Hz + case 1799: return 0x0403; break; // 179.9Hz + case 1862: return 0x0400; break; // 186.2Hz + case 1928: return 0x0302; break; // 192.8Hz + case 2035: // 203.5Hz + case 2107: // 210.7Hz + case 2181: // 218.1Hz + case 2257: return 0x0302; break; // 225.7Hz + case 2336: // 233.6Hz + case 2418: // 241.8Hz + case 2503: return 0x0300; break; // 250.3Hz + + // 159.8Hz, 165.5Hz, 173.8Hz, + // 177.3Hz, 183.5Hz, 189.9Hz, + // 196.6Hz, 199.5Hz, 206.5Hz, + default: return 0x0505; break; // 229.1Hz, 254.1Hz + } + } }; #endif /* AT1846S_H */ diff --git a/platform/drivers/baseband/radio_GDx.cpp b/platform/drivers/baseband/radio_GDx.cpp index eed9b7d3..9f1e3d94 100644 --- a/platform/drivers/baseband/radio_GDx.cpp +++ b/platform/drivers/baseband/radio_GDx.cpp @@ -119,7 +119,7 @@ void radio_setOpmode(const enum opmode mode) bool radio_checkRxDigitalSquelch() { - return true; + return at1846s.rxCtcssDetected(); } void radio_enableRx() @@ -152,6 +152,11 @@ void radio_enableRx() } radioStatus = RX; + + if(config->rxToneEn) + { + at1846s.enableRxCtcss(config->rxTone); + } } void radio_enableTx() @@ -204,11 +209,12 @@ void radio_disableRtx() if(radioStatus == TX) { - at1846s.disableCtcss(); + // Set PA drive voltage to 0V DAC0->DAT[0].DATH = 0; DAC0->DAT[0].DATL = 0; } + at1846s.disableCtcss(); at1846s.setFuncMode(AT1846S_FuncMode::OFF); radioStatus = OFF; } diff --git a/platform/drivers/baseband/radio_MD3x0.cpp b/platform/drivers/baseband/radio_MD3x0.cpp index bc1933cc..f95b3d77 100644 --- a/platform/drivers/baseband/radio_MD3x0.cpp +++ b/platform/drivers/baseband/radio_MD3x0.cpp @@ -191,7 +191,7 @@ void radio_setOpmode(const enum opmode mode) bool radio_checkRxDigitalSquelch() { - return true; + return false; } void radio_enableRx() diff --git a/platform/drivers/baseband/radio_UV3x0.cpp b/platform/drivers/baseband/radio_UV3x0.cpp index 9531e9fe..ca4da1f9 100644 --- a/platform/drivers/baseband/radio_UV3x0.cpp +++ b/platform/drivers/baseband/radio_UV3x0.cpp @@ -125,7 +125,7 @@ void radio_setOpmode(const enum opmode mode) bool radio_checkRxDigitalSquelch() { - return true; + return at1846s.rxCtcssDetected(); } void radio_enableRx() @@ -151,6 +151,11 @@ void radio_enableRx() gpio_setPin(UHF_LNA_EN); } + if(config->rxToneEn) + { + at1846s.enableRxCtcss(config->rxTone); + } + radioStatus = RX; } @@ -225,10 +230,10 @@ void radio_disableRtx() // If we are currently transmitting, stop tone and C6000 TX if(radioStatus == TX) { - at1846s.disableCtcss(); C6000.stopAnalogTx(); } + at1846s.disableCtcss(); at1846s.setFuncMode(AT1846S_FuncMode::OFF); radioStatus = OFF; }