diff --git a/openrtx/include/rtx/OpMode.h b/openrtx/include/rtx/OpMode.h
new file mode 100644
index 00000000..75bb58df
--- /dev/null
+++ b/openrtx/include/rtx/OpMode.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef OPMODE_H
+#define OPMODE_H
+
+#include "rtx.h"
+
+/**
+ * This class provides a standard interface for all the operating modes.
+ * The class is then specialised for each operating mode and its implementation
+ * groups all the common code required to manage the given mode, like data
+ * encoding and decoding, squelch management, ...
+ */
+
+class OpMode
+{
+public:
+
+ /**
+ * Constructor.
+ */
+ OpMode() { }
+
+ /**
+ * Destructor.
+ */
+ virtual ~OpMode() { }
+
+ /**
+ * Enable the operating mode.
+ *
+ * Application must ensure this function is being called when entering the
+ * new operating mode and always before the first call of "update".
+ */
+ virtual void enable() { }
+
+ /**
+ * Disable the operating mode. This function ensures that, after being
+ * called, the radio, the audio amplifier and the microphone are in OFF state.
+ *
+ * Application must ensure this function is being called when exiting the
+ * current operating mode.
+ */
+ virtual void disable() { }
+
+ /**
+ * Update the internal FSM.
+ * Application code has to call this function periodically, to ensure proper
+ * functionality.
+ *
+ * @param status: pointer to the rtxStatus_t structure containing the current
+ * RTX status. Internal FSM may change the current value of the opStatus flag.
+ * @param newCfg: flag used inform the internal FSM that a new RTX configuration
+ * has been applied.
+ */
+ virtual void update(rtxStatus_t *const status, const bool newCfg)
+ {
+ (void) status;
+ (void) newCfg;
+ }
+
+ /**
+ * Get the mode identifier corresponding to the OpMode class.
+ *
+ * @return the corresponding flag from the opmode enum.
+ */
+ virtual opmode getID()
+ {
+ return NONE;
+ }
+};
+
+#endif /* OPMODE_H */
diff --git a/openrtx/include/rtx/OpMode_FM.h b/openrtx/include/rtx/OpMode_FM.h
new file mode 100644
index 00000000..b91ec5da
--- /dev/null
+++ b/openrtx/include/rtx/OpMode_FM.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef OPMODE_FM_H
+#define OPMODE_FM_H
+
+#include "OpMode.h"
+
+/**
+ * Specialisation of the OpMode class for the management of analog FM operating
+ * mode.
+ */
+
+class OpMode_FM : public OpMode
+{
+public:
+
+ /**
+ * Constructor.
+ */
+ OpMode_FM();
+
+ /**
+ * Destructor.
+ */
+ ~OpMode_FM();
+
+ /**
+ * Enable the operating mode.
+ *
+ * Application must ensure this function is being called when entering the
+ * new operating mode and always before the first call of "update".
+ */
+ virtual void enable() override;
+
+ /**
+ * Disable the operating mode. This function ensures that, after being
+ * called, the radio, the audio amplifier and the microphone are in OFF state.
+ *
+ * Application must ensure this function is being called when exiting the
+ * current operating mode.
+ */
+ virtual void disable() override;
+
+ /**
+ * Update the internal FSM.
+ * Application code has to call this function periodically, to ensure proper
+ * functionality.
+ *
+ * @param status: pointer to the rtxStatus_t structure containing the current
+ * RTX status. Internal FSM may change the current value of the opStatus flag.
+ * @param newCfg: flag used inform the internal FSM that a new RTX configuration
+ * has been applied.
+ */
+ virtual void update(rtxStatus_t *const status, const bool newCfg) override;
+
+ /**
+ * Get the mode identifier corresponding to the OpMode class.
+ *
+ * @return the corresponding flag from the opmode enum.
+ */
+ virtual opmode getID() override
+ {
+ return FM;
+ }
+
+private:
+
+ bool sqlOpen; ///< Flag for current squelch status.
+ bool enterRx; ///< Flag for RX management.
+};
+
+#endif /* OPMODE_FM_H */
diff --git a/openrtx/include/rtx.h b/openrtx/include/rtx/rtx.h
similarity index 95%
rename from openrtx/include/rtx.h
rename to openrtx/include/rtx/rtx.h
index 88675c10..395feba1 100644
--- a/openrtx/include/rtx.h
+++ b/openrtx/include/rtx/rtx.h
@@ -63,8 +63,10 @@ enum bandwidth
*/
enum opmode
{
- FM = 0, /**< Analog FM */
- DMR = 1 /**< DMR */
+ NONE = 0, /**< No opMode selected */
+ FM = 1, /**< Analog FM */
+ DMR = 2, /**< DMR */
+ M17 = 3 /**< M17 */
};
/**
diff --git a/openrtx/src/rtx.c b/openrtx/src/rtx.c
deleted file mode 100644
index c36329ca..00000000
--- a/openrtx/src/rtx.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
- * Niccolò Izzo IU2KIN *
- * Frederik Saraci IU2NRO *
- * Silvano Seva IU2KWO *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 3 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, see *
- ***************************************************************************/
-
-#include
-#include
-#include
-#include
-#include
-#include
-#ifdef PLATFORM_MDUV3x0
-#include "../../platform/drivers/baseband/HR_C6000.h"
-#endif
-
-pthread_mutex_t *cfgMutex; /* Mutex for incoming config messages */
-
-const rtxStatus_t *newCnf; /* Pointer for incoming config messages */
-rtxStatus_t rtxStatus; /* RTX driver status */
-
-bool sqlOpen; /* Flag for squelch open/close */
-bool enterRx; /* Flag for RX mode activation */
-
-float rssi; /* Current RSSI in dBm */
-
-/*
- * Unfortunately on MD-UV3x0 radios the volume knob does not regulate
- * the amplitude of the analog signal towards the audio amplifier but it
- * rather serves to provide a digital value to be fed into the HR_C6000
- * lineout DAC gain. We thus have to place the #ifdef'd piece of code
- * below to keep the real volume level consistent with the knob position.
- * Knob position is given by an analog signal in the range 0 - 1500mV,
- * which has to be mapped in a range between 1 and 31.
- */
-#ifdef PLATFORM_MDUV3x0
-void _setVolume()
-{
- float level = (platform_getVolumeLevel() / 1560.0f) * 30.0f;
- uint8_t volume = ((uint8_t) (level + 0.5f));
-
- // Mute volume when knob is set below 10%
- if(volume < 1)
- audio_disableAmp();
- else
- {
- audio_enableAmp();
- /* Update HR_C6000 gain only if volume changed */
- static uint8_t old_volume = 0;
- if(volume != old_volume)
- {
- // Setting HR_C6000 volume to 0 = max volume
- C6000_setDacGain(volume);
- old_volume = volume;
- }
- }
-}
-#endif
-
-void rtx_init(pthread_mutex_t *m)
-{
- /* Initialise mutex for configuration access */
- cfgMutex = m;
- newCnf = NULL;
-
- /*
- * Default initialisation for rtx status
- */
- rtxStatus.opMode = FM;
- rtxStatus.bandwidth = BW_25;
- rtxStatus.txDisable = 0;
- rtxStatus.opStatus = OFF;
- rtxStatus.rxFrequency = 430000000;
- rtxStatus.txFrequency = 430000000;
- rtxStatus.txPower = 0.0f;
- rtxStatus.sqlLevel = 1;
- rtxStatus.rxToneEn = 0;
- rtxStatus.rxTone = 0;
- rtxStatus.txToneEn = 0;
- rtxStatus.txTone = 0;
-
- sqlOpen = false;
- enterRx = false;
-
- /*
- * Initialise low-level platform-specific driver
- */
- radio_init();
-
- /*
- * Initial value for RSSI filter
- */
- rssi = radio_getRssi(rtxStatus.rxFrequency);
-}
-
-void rtx_terminate()
-{
- radio_terminate();
-}
-
-void rtx_configure(const rtxStatus_t *cfg)
-{
- /*
- * NOTE: an incoming configuration may overwrite a preceding one not yet
- * read by the radio task. This mechanism ensures that the radio driver
- * always gets the most recent configuration.
- */
-
- pthread_mutex_lock(cfgMutex);
- newCnf = cfg;
- pthread_mutex_unlock(cfgMutex);
-}
-
-rtxStatus_t rtx_getCurrentStatus()
-{
- return rtxStatus;
-}
-
-void rtx_taskFunc()
-{
- /* Check if there is a pending new configuration and, in case, read it. */
- bool reconfigure = false;
- if(pthread_mutex_trylock(cfgMutex) == 0)
- {
- if(newCnf != NULL)
- {
- /* Copy new configuration and override opStatus flags */
- uint8_t tmp = rtxStatus.opStatus;
- memcpy(&rtxStatus, newCnf, sizeof(rtxStatus_t));
- rtxStatus.opStatus = tmp;
-
- reconfigure = true;
- newCnf = NULL;
- }
-
- pthread_mutex_unlock(cfgMutex);
- }
-
- if(reconfigure)
- {
- /* Update HW configuration */
- radio_setOpmode(rtxStatus.opMode);
- radio_setBandwidth(rtxStatus.bandwidth);
- radio_setCSS(rtxStatus.rxTone, rtxStatus.txTone);
- radio_updateCalibrationParams(&rtxStatus);
-
- /*
- * If currently transmitting or receiving, update VCO frequency and
- * call again enableRx/enableTx.
- * This is done because the new configuration may have changed the
- * RX and TX frequencies, requiring an update of both the VCO
- * settings and of some tuning parameters, like APC voltage, which
- * are managed by enableRx/enableTx.
- */
- if(rtxStatus.opStatus == TX)
- {
- radio_setVcoFrequency(rtxStatus.txFrequency, true);
- radio_enableTx(rtxStatus.txPower, rtxStatus.txToneEn);
- }
-
- if(rtxStatus.opStatus == RX)
- {
- radio_setVcoFrequency(rtxStatus.rxFrequency, false);
- radio_enableRx();
- }
-
- /* TODO: temporarily force to RX mode if rtx is off. */
- if(rtxStatus.opStatus == OFF) enterRx = true;
- }
-
- /* RX logic */
- if(rtxStatus.opStatus == RX)
- {
- /*
- * RSSI-based squelch mechanism, with 15 levels from -140dBm to -70dBm.
- *
- * RSSI value is passed through a filter with a time constant of 60ms
- * (cut-off frequency of 15Hz) at an update rate of 33.3Hz.
- *
- * The low pass filter skips an update step if a new configuration has
- * just been applied. This is a workaround for the AT1846S returning a
- * full-scale RSSI value immediately after one of its parameters changed,
- * thus causing the squelch to open briefly.
- */
- if(!reconfigure)
- {
- rssi = 0.74*radio_getRssi(rtxStatus.rxFrequency) + 0.26*rssi;
- }
-
- float squelch = -127.0f + rtxStatus.sqlLevel * 66.0f / 15.0f;
-
- if((sqlOpen == false) && (rssi > (squelch + 0.1f)))
- {
- audio_enableAmp();
- sqlOpen = true;
- }
-
- if((sqlOpen == true) && (rssi < (squelch - 0.1f)))
- {
- audio_disableAmp();
- sqlOpen = false;
- }
-
- #ifdef PLATFORM_MDUV3x0
- if(sqlOpen == true)
- {
- // Set output volume by changing the HR_C6000 DAC gain
- _setVolume();
- }
- #endif
- }
- else if((rtxStatus.opMode == OFF) && enterRx)
- {
- radio_disableRtx();
-
- radio_setVcoFrequency(rtxStatus.rxFrequency, false);
- radio_enableRx();
- rtxStatus.opStatus = RX;
- enterRx = false;
-
- /* Reinitialise RSSI filter state */
- rssi = radio_getRssi(rtxStatus.rxFrequency);
- }
-
- /* TX logic */
- if(platform_getPttStatus() && (rtxStatus.opStatus != TX))
- {
- audio_disableAmp();
- radio_disableRtx();
-
- audio_enableMic();
- radio_setVcoFrequency(rtxStatus.txFrequency, true);
- radio_enableTx(rtxStatus.txPower, rtxStatus.txToneEn);
-
- rtxStatus.opStatus = TX;
- }
-
- if(!platform_getPttStatus() && (rtxStatus.opStatus == TX))
- {
- audio_disableMic();
- radio_disableRtx();
-
- rtxStatus.opStatus = OFF;
- enterRx = true;
- }
-
- /* Led control logic */
- switch(rtxStatus.opStatus)
- {
- case RX:
- if(sqlOpen)
- platform_ledOn(GREEN);
- else
- platform_ledOff(GREEN);
-
- break;
-
- case TX:
- platform_ledOff(GREEN);
- platform_ledOn(RED);
- break;
-
- default:
- platform_ledOff(GREEN);
- platform_ledOff(RED);
- break;
- }
-}
-
-float rtx_getRssi()
-{
- return rssi;
-}
diff --git a/openrtx/src/rtx/OpMode_FM.cpp b/openrtx/src/rtx/OpMode_FM.cpp
new file mode 100644
index 00000000..22c0b1a8
--- /dev/null
+++ b/openrtx/src/rtx/OpMode_FM.cpp
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * \internal
+ * On MD-UV3x0 radios the volume knob does not regulate the amplitude of the
+ * analog signal towards the audio amplifier but it rather serves to provide a
+ * digital value to be fed into the HR_C6000 lineout DAC gain. We thus have to
+ * provide the helper function below to keep the real volume level consistent
+ * with the knob position.
+ * Current knob position corresponds to an analog signal in the range 0 - 1500mV,
+ * which has to be mapped in a range between 1 and 31.
+ */
+#ifdef PLATFORM_MDUV3x0
+void _setVolume()
+{
+ float level = (platform_getVolumeLevel() / 1560.0f) * 30.0f;
+ uint8_t volume = ((uint8_t) (level + 0.5f));
+
+ // Mute volume when knob is set below 10%
+ if(volume < 1)
+ {
+ audio_disableAmp();
+ }
+ else
+ {
+ audio_enableAmp();
+
+ // Update HR_C6000 gain only if volume changed
+ static uint8_t old_volume = 0;
+ if(volume != old_volume)
+ {
+ // Setting HR_C6000 volume to 0 = max volume
+ C6000_setDacGain(volume);
+ old_volume = volume;
+ }
+ }
+}
+#endif
+
+OpMode_FM::OpMode_FM() : sqlOpen(false), enterRx(true)
+{
+}
+
+OpMode_FM::~OpMode_FM()
+{
+}
+
+void OpMode_FM::enable()
+{
+ // When starting, close squelch and prepare for entering in RX mode.
+ sqlOpen = false;
+ enterRx = true;
+}
+
+void OpMode_FM::disable()
+{
+ // Clean shutdown.
+ audio_disableAmp();
+ audio_disableMic();
+ radio_disableRtx();
+ sqlOpen = false;
+ enterRx = false;
+}
+
+void OpMode_FM::update(rtxStatus_t *const status, const bool newCfg)
+{
+ // RX logic
+ if(status->opStatus == RX)
+ {
+ float squelch = -127.0f + status->sqlLevel * 66.0f / 15.0f;
+ float rssi = rtx_getRssi();
+
+ if((sqlOpen == false) && (rssi > (squelch + 0.1f)))
+ {
+ audio_enableAmp();
+ sqlOpen = true;
+ }
+
+ if((sqlOpen == true) && (rssi < (squelch - 0.1f)))
+ {
+ audio_disableAmp();
+ sqlOpen = false;
+ }
+
+ #ifdef PLATFORM_MDUV3x0
+ if(sqlOpen == true)
+ {
+ // Set output volume by changing the HR_C6000 DAC gain
+ _setVolume();
+ }
+ #endif
+ }
+ else if((status->opMode == OFF) && enterRx)
+ {
+ radio_disableRtx();
+
+ radio_setVcoFrequency(status->rxFrequency, false);
+ radio_enableRx();
+ status->opStatus = RX;
+ enterRx = false;
+ }
+
+ /* TX logic */
+ if(platform_getPttStatus() && (status->opStatus != TX) &&
+ (status->txDisable == 0))
+ {
+ audio_disableAmp();
+ radio_disableRtx();
+
+ audio_enableMic();
+ radio_setVcoFrequency(status->txFrequency, true);
+ radio_enableTx(status->txPower, status->txToneEn);
+
+ status->opStatus = TX;
+ }
+
+ if(!platform_getPttStatus() && (status->opStatus == TX))
+ {
+ audio_disableMic();
+ radio_disableRtx();
+
+ status->opStatus = OFF;
+ enterRx = true;
+ }
+
+ /* Led control logic */
+ switch(status->opStatus)
+ {
+ case RX:
+ if(sqlOpen)
+ {
+ platform_ledOn(GREEN);
+ }
+ else
+ {
+ platform_ledOff(GREEN);
+ }
+
+ break;
+
+ case TX:
+ platform_ledOff(GREEN);
+ platform_ledOn(RED);
+ break;
+
+ default:
+ platform_ledOff(GREEN);
+ platform_ledOff(RED);
+ break;
+ }
+}
diff --git a/openrtx/src/rtx/rtx.cpp b/openrtx/src/rtx/rtx.cpp
new file mode 100644
index 00000000..baca4fb7
--- /dev/null
+++ b/openrtx/src/rtx/rtx.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+
+pthread_mutex_t *cfgMutex; // Mutex for incoming config messages
+
+const rtxStatus_t *newCnf; // Pointer for incoming config messages
+rtxStatus_t rtxStatus; // RTX driver status
+
+float rssi; // Current RSSI in dBm
+bool reinitFilter; // Flag for RSSI filter re-initialisation
+
+OpMode *currMode; // Pointer to currently active opMode handler
+OpMode noMode; // Empty opMode handler for opmode::NONE
+OpMode_FM fmMode; // FM mode handler
+
+void rtx_init(pthread_mutex_t *m)
+{
+ // Initialise mutex for configuration access
+ cfgMutex = m;
+ newCnf = NULL;
+
+ /*
+ * Default initialisation for rtx status
+ */
+ rtxStatus.opMode = NONE;
+ rtxStatus.bandwidth = BW_25;
+ rtxStatus.txDisable = 0;
+ rtxStatus.opStatus = OFF;
+ rtxStatus.rxFrequency = 430000000;
+ rtxStatus.txFrequency = 430000000;
+ rtxStatus.txPower = 0.0f;
+ rtxStatus.sqlLevel = 1;
+ rtxStatus.rxToneEn = 0;
+ rtxStatus.rxTone = 0;
+ rtxStatus.txToneEn = 0;
+ rtxStatus.txTone = 0;
+ currMode = &noMode;
+
+ /*
+ * Initialise low-level platform-specific driver
+ */
+ radio_init();
+
+ /*
+ * Initial value for RSSI filter
+ */
+ rssi = radio_getRssi(rtxStatus.rxFrequency);
+ reinitFilter = false;
+}
+
+void rtx_terminate()
+{
+ rtxStatus.opStatus = OFF;
+ rtxStatus.opMode = NONE;
+ currMode->disable();
+ radio_terminate();
+}
+
+void rtx_configure(const rtxStatus_t *cfg)
+{
+ /*
+ * NOTE: an incoming configuration may overwrite a preceding one not yet
+ * read by the radio task. This mechanism ensures that the radio driver
+ * always gets the most recent configuration.
+ */
+
+ pthread_mutex_lock(cfgMutex);
+ newCnf = cfg;
+ pthread_mutex_unlock(cfgMutex);
+}
+
+rtxStatus_t rtx_getCurrentStatus()
+{
+ return rtxStatus;
+}
+
+void rtx_taskFunc()
+{
+ // Check if there is a pending new configuration and, in case, read it.
+ bool reconfigure = false;
+ if(pthread_mutex_trylock(cfgMutex) == 0)
+ {
+ if(newCnf != NULL)
+ {
+ // Copy new configuration and override opStatus flags
+ uint8_t tmp = rtxStatus.opStatus;
+ memcpy(&rtxStatus, newCnf, sizeof(rtxStatus_t));
+ rtxStatus.opStatus = tmp;
+
+ reconfigure = true;
+ newCnf = NULL;
+ }
+
+ pthread_mutex_unlock(cfgMutex);
+ }
+
+ if(reconfigure)
+ {
+ /*
+ * Handle change of opMode:
+ * - deactivate current opMode and switch operating status to "OFF";
+ * - update pointer to current mode handler to the OpMode object for the
+ * selected mode;
+ * - enable the new mode handler
+ */
+ if(currMode->getID() != rtxStatus.opMode)
+ {
+ currMode->disable();
+ rtxStatus.opStatus = OFF;
+
+ switch(rtxStatus.opMode)
+ {
+ case NONE: currMode = &noMode; break;
+ case FM: currMode = &fmMode; break;
+ default: currMode = &noMode;
+ }
+
+ currMode->enable();
+ }
+ }
+
+ /*
+ * RSSI update block, run only when radio is in RX mode.
+ *
+ * RSSI value is passed through a filter with a time constant of 60ms
+ * (cut-off frequency of 15Hz) at an update rate of 33.3Hz.
+ *
+ * The low pass filter skips an update step if a new configuration has
+ * just been applied. This is a workaround for the AT1846S returning a
+ * full-scale RSSI value immediately after one of its parameters changed,
+ * thus causing the squelch to open briefly.
+ *
+ * Also, the RSSI filter is re-initialised every time radio stage is
+ * switched back from TX/OFF to RX. This provides a workaround for some
+ * radios reporting a full-scale RSSI value when transmitting.
+ */
+ if(rtxStatus.opStatus == RX)
+ {
+
+ if(!reconfigure)
+ {
+ if(!reinitFilter)
+ {
+ rssi = 0.74*radio_getRssi(rtxStatus.rxFrequency) + 0.26*rssi;
+ }
+ else
+ {
+ rssi = radio_getRssi(rtxStatus.rxFrequency);
+ reinitFilter = false;
+ }
+ }
+ }
+ else
+ {
+ // Reinit required if current operating status is TX or OFF
+ reinitFilter = true;
+ }
+
+ /*
+ * Forward the periodic update step to the currently active opMode handler.
+ * Call is placed after RSSI update to allow handler's code have a fresh
+ * version of the RSSI level.
+ */
+ currMode->update(&rtxStatus, reconfigure);
+}
+
+float rtx_getRssi()
+{
+ return rssi;
+}