/*************************************************************************** * 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 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 OpMode_M17 m17Mode; // M17 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(&rtxStatus); radio_updateConfiguration(); /* * Initial value for RSSI filter */ rssi = radio_getRssi(); 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) { // Force TX and RX tone squelch to off for OpModes different from FM. if(rtxStatus.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 NONE: currMode = &noMode; break; case FM: currMode = &fmMode; break; case M17: currMode = &m17Mode; break; 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; }