OpenRTX/openrtx/src/rtx/rtx.cpp

225 wiersze
7.2 KiB
C++

/***************************************************************************
* Copyright (C) 2020 - 2023 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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#include <interfaces/radio.h>
#include <hwconfig.h>
#include <string.h>
#include <rtx.h>
#include <OpMode_FM.hpp>
#include <OpMode_M17.hpp>
static pthread_mutex_t *cfgMutex; // Mutex for incoming config messages
static const rtxStatus_t *newCnf; // Pointer for incoming config messages
static rtxStatus_t rtxStatus; // RTX driver status
static float rssi; // Current RSSI in dBm
static bool reinitFilter; // Flag for RSSI filter re-initialisation
static OpMode *currMode; // Pointer to currently active opMode handler
static OpMode noMode; // Empty opMode handler for opmode::NONE
static OpMode_FM fmMode; // FM mode handler
#ifdef CONFIG_M17
static OpMode_M17 m17Mode; // M17 mode handler
#endif
void rtx_init(pthread_mutex_t *m)
{
// Initialise mutex for configuration access
cfgMutex = m;
newCnf = NULL;
/*
* Default initialisation for rtx status
*/
rtxStatus.opMode = 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;
rtxStatus.invertRxPhase = false;
rtxStatus.lsfOk = false;
rtxStatus.M17_src[0] = '\0';
rtxStatus.M17_dst[0] = '\0';
rtxStatus.M17_link[0] = '\0';
rtxStatus.M17_refl[0] = '\0';
currMode = &noMode;
/*
* Initialise low-level platform-specific driver
*/
radio_init(&rtxStatus);
radio_updateConfiguration();
/*
* Initial value for RSSI filter
*/
rssi = radio_getRssi();
reinitFilter = false;
}
void rtx_terminate()
{
rtxStatus.opStatus = OFF;
rtxStatus.opMode = 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_task()
{
// 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)
{
// Force TX and RX tone squelch to off for OpModes different from FM.
if(rtxStatus.opMode != OPMODE_FM)
{
rtxStatus.txToneEn = 0;
rtxStatus.rxToneEn = 0;
}
/*
* 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)
{
// Forward opMode change also to radio driver
radio_setOpmode(static_cast< enum opmode >(rtxStatus.opMode));
currMode->disable();
rtxStatus.opStatus = OFF;
switch(rtxStatus.opMode)
{
case OPMODE_NONE: currMode = &noMode; break;
case OPMODE_FM: currMode = &fmMode; break;
#ifdef CONFIG_M17
case OPMODE_M17: currMode = &m17Mode; break;
#endif
default: currMode = &noMode;
}
currMode->enable();
}
// Tell radio driver that there was a change in its configuration.
radio_updateConfiguration();
}
/*
* 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() + 0.26*rssi;
}
else
{
rssi = radio_getRssi();
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;
}
bool rtx_rxSquelchOpen()
{
return currMode->rxSquelchOpen();
}