1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-25 01:05:27 +03:00

Added RSNR to the OSD (#11062)

* Added RNSR to the OSD

* filtering with pt1

* update pgconfig ver

* rssi_smoothness and proper define wrapping

* missing define wrap

* smoothing moved to updateRSSI

* minor comment update

* fixed rx tests

Co-authored-by: Tony Cabello <>
Co-authored-by: J Blackman <blckmn@users.noreply.github.com>
This commit is contained in:
TonyBlit 2022-11-10 04:53:15 +01:00 committed by GitHub
parent b197d1d6bd
commit 22c5bf4eb3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 215 additions and 64 deletions

View file

@ -745,6 +745,7 @@ const clivalue_t valueTable[] = {
{ "rssi_offset", VAR_INT8 | MASTER_VALUE, .config.minmax = { -100, 100 }, PG_RX_CONFIG, offsetof(rxConfig_t, rssi_offset) },
{ "rssi_invert", VAR_INT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_RX_CONFIG, offsetof(rxConfig_t, rssi_invert) },
{ "rssi_src_frame_lpf_period", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { 0, UINT8_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rssi_src_frame_lpf_period) },
{ "rssi_smoothing", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { 0, UINT8_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rssi_smoothing) },
#ifdef USE_RC_SMOOTHING_FILTER
{ PARAM_NAME_RC_SMOOTHING, VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_RX_CONFIG, offsetof(rxConfig_t, rc_smoothing_mode) },
@ -773,11 +774,8 @@ const clivalue_t valueTable[] = {
#if defined(USE_SERIALRX_SBUS)
{ "sbus_baud_fast", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_RX_CONFIG, offsetof(rxConfig_t, sbus_baud_fast) },
#endif
#if defined(USE_SERIALRX_CRSF)
{ "crsf_use_rx_snr", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_RX_CONFIG, offsetof(rxConfig_t, crsf_use_rx_snr) },
#if defined(USE_CRSF_V3)
{ "crsf_use_negotiated_baud", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_RX_CONFIG, offsetof(rxConfig_t, crsf_use_negotiated_baud) },
#endif
#endif
{ "airmode_start_throttle_percent", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_RX_CONFIG, offsetof(rxConfig_t, airModeActivateThreshold) },
{ "rx_min_usec", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { PWM_PULSE_MIN, PWM_PULSE_MAX }, PG_RX_CONFIG, offsetof(rxConfig_t, rx_min_usec) },
@ -1315,7 +1313,10 @@ const clivalue_t valueTable[] = {
{ "osd_link_quality_alarm", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_OSD_CONFIG, offsetof(osdConfig_t, link_quality_alarm) },
#endif
#ifdef USE_RX_RSSI_DBM
{ "osd_rssi_dbm_alarm", VAR_INT16 | MASTER_VALUE, .config.minmax = { CRSF_RSSI_MIN, CRSF_SNR_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, rssi_dbm_alarm) },
{ "osd_rssi_dbm_alarm", VAR_INT16 | MASTER_VALUE, .config.minmax = { CRSF_RSSI_MIN, CRSF_RSSI_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, rssi_dbm_alarm) },
#endif
#ifdef USE_RX_RSNR
{ "osd_rsnr_alarm", VAR_INT16 | MASTER_VALUE, .config.minmax = { CRSF_SNR_MIN, CRSF_SNR_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, rsnr_alarm) },
#endif
{ "osd_cap_alarm", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 20000 }, PG_OSD_CONFIG, offsetof(osdConfig_t, cap_alarm) },
{ "osd_alt_alarm", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 10000 }, PG_OSD_CONFIG, offsetof(osdConfig_t, alt_alarm) },
@ -1346,6 +1347,9 @@ const clivalue_t valueTable[] = {
#endif
#ifdef USE_RX_RSSI_DBM
{ "osd_rssi_dbm_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_RSSI_DBM_VALUE]) },
#endif
#ifdef USE_RX_RSNR
{ "osd_rsnr_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_RSNR_VALUE]) },
#endif
{ "osd_tim_1_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_ITEM_TIMER_1]) },
{ "osd_tim_2_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_ITEM_TIMER_2]) },

View file

@ -80,6 +80,9 @@ const OSD_Entry menuOsdActiveElemsEntries[] =
{"RSSI", OME_VISIBLE | DYNAMIC, NULL, &osdConfig_item_pos[OSD_RSSI_VALUE]},
#ifdef USE_RX_RSSI_DBM
{"RSSI DBM", OME_VISIBLE | DYNAMIC, NULL, &osdConfig_item_pos[OSD_RSSI_DBM_VALUE]},
#endif
#ifdef USE_RX_RSNR
{"RSNR", OME_VISIBLE | DYNAMIC, NULL, &osdConfig_item_pos[OSD_RSNR_VALUE]},
#endif
{"BATTERY VOLTAGE", OME_VISIBLE | DYNAMIC, NULL, &osdConfig_item_pos[OSD_MAIN_BATT_VOLTAGE]},
{"BATTERY USAGE", OME_VISIBLE | DYNAMIC, NULL, &osdConfig_item_pos[OSD_MAIN_BATT_USAGE]},
@ -184,6 +187,7 @@ static CMS_Menu menuOsdActiveElems = {
static uint8_t osdConfig_rssi_alarm;
static uint16_t osdConfig_link_quality_alarm;
static int16_t osdConfig_rssi_dbm_alarm;
static int16_t osdConfig_rsnr_alarm;
static uint16_t osdConfig_cap_alarm;
static uint16_t osdConfig_alt_alarm;
static uint16_t osdConfig_distance_alarm;
@ -197,6 +201,7 @@ static const void *menuAlarmsOnEnter(displayPort_t *pDisp)
osdConfig_rssi_alarm = osdConfig()->rssi_alarm;
osdConfig_link_quality_alarm = osdConfig()->link_quality_alarm;
osdConfig_rssi_dbm_alarm = osdConfig()->rssi_dbm_alarm;
osdConfig_rsnr_alarm = osdConfig()->rsnr_alarm;
osdConfig_cap_alarm = osdConfig()->cap_alarm;
osdConfig_alt_alarm = osdConfig()->alt_alarm;
osdConfig_distance_alarm = osdConfig()->distance_alarm;
@ -214,6 +219,7 @@ static const void *menuAlarmsOnExit(displayPort_t *pDisp, const OSD_Entry *self)
osdConfigMutable()->rssi_alarm = osdConfig_rssi_alarm;
osdConfigMutable()->link_quality_alarm = osdConfig_link_quality_alarm;
osdConfigMutable()->rssi_dbm_alarm = osdConfig_rssi_dbm_alarm;
osdConfigMutable()->rsnr_alarm = osdConfig_rsnr_alarm;
osdConfigMutable()->cap_alarm = osdConfig_cap_alarm;
osdConfigMutable()->alt_alarm = osdConfig_alt_alarm;
osdConfigMutable()->distance_alarm = osdConfig_distance_alarm;
@ -229,6 +235,7 @@ const OSD_Entry menuAlarmsEntries[] =
{"RSSI", OME_UINT8, NULL, &(OSD_UINT8_t){&osdConfig_rssi_alarm, 5, 90, 5}},
{"LINK QUALITY", OME_UINT16, NULL, &(OSD_UINT16_t){&osdConfig_link_quality_alarm, 5, 300, 5}},
{"RSSI DBM", OME_INT16, NULL, &(OSD_INT16_t){&osdConfig_rssi_dbm_alarm, CRSF_RSSI_MIN, CRSF_SNR_MAX, 5}},
{"RSNR", OME_INT16, NULL, &(OSD_INT16_t){&osdConfig_rsnr_alarm, CRSF_SNR_MIN, CRSF_SNR_MAX, 5}},
{"MAIN BAT", OME_UINT16, NULL, &(OSD_UINT16_t){&osdConfig_cap_alarm, 50, 30000, 50}},
{"MAX ALT", OME_UINT16, NULL, &(OSD_UINT16_t){&osdConfig_alt_alarm, 1, 200, 1}},
{"MAX DISTANCE", OME_UINT16, NULL, &(OSD_UINT16_t){&osdConfig_distance_alarm, 0, UINT16_MAX, 10}},

View file

@ -149,7 +149,7 @@ escSensorData_t *osdEscDataCombined;
STATIC_ASSERT(OSD_POS_MAX == OSD_POS(31,31), OSD_POS_MAX_incorrect);
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 10);
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 11);
PG_REGISTER_WITH_RESET_FN(osdElementConfig_t, osdElementConfig, PG_OSD_ELEMENT_CONFIG, 1);
@ -185,6 +185,7 @@ const osd_stats_e osdStatsDisplayOrder[OSD_STAT_COUNT] = {
OSD_STAT_MIN_LINK_QUALITY,
OSD_STAT_MAX_FFT,
OSD_STAT_MIN_RSSI_DBM,
OSD_STAT_MIN_RSNR,
OSD_STAT_TOTAL_FLIGHTS,
OSD_STAT_TOTAL_TIME,
OSD_STAT_TOTAL_DIST,
@ -344,6 +345,7 @@ void pgResetFn_osdConfig(osdConfig_t *osdConfig)
osdWarnSetState(OSD_WARNING_RSSI, false);
osdWarnSetState(OSD_WARNING_LINK_QUALITY, false);
osdWarnSetState(OSD_WARNING_RSSI_DBM, false);
osdWarnSetState(OSD_WARNING_RSNR, false);
// turn off the over mah capacity warning
osdWarnSetState(OSD_WARNING_OVER_CAP, false);
@ -370,6 +372,7 @@ void pgResetFn_osdConfig(osdConfig_t *osdConfig)
osdConfig->profile[i][0] = '\0';
}
osdConfig->rssi_dbm_alarm = -60;
osdConfig->rsnr_alarm = 4;
osdConfig->gps_sats_show_hdop = false;
for (int i = 0; i < OSD_RCCHANNELS_COUNT; i++) {
@ -501,7 +504,8 @@ static void osdResetStats(void)
stats.max_esc_temp = 0;
stats.max_esc_rpm = 0;
stats.min_link_quality = (linkQualitySource == LQ_SOURCE_NONE) ? 99 : 100; // percent
stats.min_rssi_dbm = CRSF_SNR_MAX;
stats.min_rssi_dbm = CRSF_RSSI_MAX;
stats.min_rsnr = CRSF_SNR_MAX;
}
#if defined(USE_ESC_SENSOR) || defined(USE_DSHOT_TELEMETRY)
@ -581,6 +585,13 @@ static void osdUpdateStats(void)
}
#endif
#ifdef USE_RX_RSNR
value = getRsnr();
if (stats.min_rsnr > value) {
stats.min_rsnr = value;
}
#endif
#ifdef USE_GPS
if (STATE(GPS_FIX) && STATE(GPS_FIX_HOME)) {
if (stats.max_distance < GPS_distanceToHome) {
@ -876,6 +887,13 @@ static bool osdDisplayStat(int statistic, uint8_t displayRow)
return true;
#endif
#ifdef USE_RX_RSNR
case OSD_STAT_MIN_RSNR:
tfp_sprintf(buff, "%3d", stats.min_rsnr);
osdDisplayStatisticLabel(displayRow, "MIN RSNR", buff);
return true;
#endif
#ifdef USE_PERSISTENT_STATS
case OSD_STAT_TOTAL_FLIGHTS:
itoa(statsConfig()->stats_total_flights, buff, 10);

View file

@ -164,6 +164,7 @@ typedef enum {
OSD_WATT_HOURS_DRAWN,
OSD_AUX_VALUE,
OSD_READY_MODE,
OSD_RSNR_VALUE,
OSD_ITEM_COUNT // MUST BE LAST
} osd_items_e;
@ -204,6 +205,7 @@ typedef enum {
OSD_STAT_TOTAL_DIST,
OSD_STAT_MIN_RSSI_DBM,
OSD_STAT_WATT_HOURS_DRAWN,
OSD_STAT_MIN_RSNR,
OSD_STAT_COUNT // MUST BE LAST
} osd_stats_e;
@ -249,6 +251,7 @@ typedef enum {
OSD_WARNING_LINK_QUALITY,
OSD_WARNING_RSSI_DBM,
OSD_WARNING_OVER_CAP,
OSD_WARNING_RSNR,
OSD_WARNING_COUNT // MUST BE LAST
} osdWarningsFlags_e;
@ -296,6 +299,7 @@ typedef struct osdConfig_s {
char profile[OSD_PROFILE_COUNT][OSD_PROFILE_NAME_LENGTH + 1];
uint16_t link_quality_alarm;
int16_t rssi_dbm_alarm;
int16_t rsnr_alarm;
uint8_t gps_sats_show_hdop;
int8_t rcChannels[OSD_RCCHANNELS_COUNT]; // RC channel values to display, -1 if none
uint8_t displayPortDevice; // osdDisplayPortDevice_e
@ -338,6 +342,7 @@ typedef struct statistic_s {
int32_t max_esc_rpm;
uint16_t min_link_quality;
int16_t min_rssi_dbm;
int16_t min_rsnr;
} statistic_t;
extern timeUs_t resumeRefreshAt;

View file

@ -1384,6 +1384,13 @@ static void osdElementRssiDbm(osdElementParms_t *element)
}
#endif // USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
static void osdElementRsnr(osdElementParms_t *element)
{
tfp_sprintf(element->buff, "%c%3d", SYM_RSSI, getRsnr());
}
#endif // USE_RX_RSNR
#ifdef USE_OSD_STICK_OVERLAY
static void osdBackgroundStickOverlay(osdElementParms_t *element)
{
@ -1598,6 +1605,9 @@ static const uint8_t osdElementDisplayOrder[] = {
#ifdef USE_RX_RSSI_DBM
OSD_RSSI_DBM_VALUE,
#endif
#ifdef USE_RX_RSNR
OSD_RSNR_VALUE,
#endif
#ifdef USE_OSD_STICK_OVERLAY
OSD_STICK_OVERLAY_LEFT,
OSD_STICK_OVERLAY_RIGHT,
@ -1724,6 +1734,9 @@ const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
#endif
#ifdef USE_RX_RSSI_DBM
[OSD_RSSI_DBM_VALUE] = osdElementRssiDbm,
#endif
#ifdef USE_RX_RSNR
[OSD_RSNR_VALUE] = osdElementRsnr,
#endif
[OSD_RC_CHANNELS] = osdElementRcChannels,
#ifdef USE_GPS

View file

@ -186,6 +186,15 @@ void renderOsdWarning(char *warningText, bool *blinking, uint8_t *displayAttr)
return;
}
#endif // USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
// rsnr
if (osdWarnGetState(OSD_WARNING_RSNR) && (getRsnr() < osdConfig()->rsnr_alarm)) {
tfp_sprintf(warningText, "RSNR LOW");
*displayAttr = DISPLAYPORT_ATTR_WARNING;
*blinking = true;
return;
}
#endif // USE_RX_RSNR
#ifdef USE_RX_LINK_QUALITY_INFO
// Link Quality

View file

@ -34,7 +34,7 @@
#include "rx/rx.h"
#include "rx/rx_spi.h"
PG_REGISTER_WITH_RESET_FN(rxConfig_t, rxConfig, PG_RX_CONFIG, 3);
PG_REGISTER_WITH_RESET_FN(rxConfig_t, rxConfig, PG_RX_CONFIG, 4);
void pgResetFn_rxConfig(rxConfig_t *rxConfig)
{
RESET_CONFIG_2(rxConfig_t, rxConfig,
@ -56,6 +56,7 @@ void pgResetFn_rxConfig(rxConfig_t *rxConfig)
.rssi_offset = 0,
.rssi_invert = 0,
.rssi_src_frame_lpf_period = 30,
.rssi_smoothing = 125,
.fpvCamAngleDegrees = 0,
.airModeActivateThreshold = 25,
.max_aux_channel = DEFAULT_AUX_CHANNEL_COUNT,
@ -69,7 +70,6 @@ void pgResetFn_rxConfig(rxConfig_t *rxConfig)
.srxl2_unit_id = 1,
.srxl2_baud_fast = true,
.sbus_baud_fast = false,
.crsf_use_rx_snr = false,
.msp_override_channels_mask = 0,
.crsf_use_negotiated_baud = false,
);

View file

@ -57,10 +57,10 @@ typedef struct rxConfig_s {
uint8_t rc_smoothing_auto_factor_rpy; // Used to adjust the "smoothness" determined by the auto cutoff calculations
uint8_t rc_smoothing_auto_factor_throttle; // Used to adjust the "smoothness" determined by the auto cutoff calculations
uint8_t rssi_src_frame_lpf_period; // Period of the cutoff frequency for the source frame RSSI filter (in 0.1 s)
uint8_t rssi_smoothing; // Smoothing factor to reduce jumpiness of rssi, rssiDbm and rsnr
uint8_t srxl2_unit_id; // Spektrum SRXL2 RX unit id
uint8_t srxl2_baud_fast; // Select Spektrum SRXL2 fast baud rate
uint8_t sbus_baud_fast; // Select SBus fast baud rate
uint8_t crsf_use_rx_snr; // Use RX SNR (in dB) instead of RSSI dBm for CRSF
uint32_t msp_override_channels_mask; // Channels to override when the MSP override mode is enabled
uint8_t crsf_use_negotiated_baud; // Use negotiated baud rate for CRSF V3
} rxConfig_t;

View file

@ -229,24 +229,17 @@ static void handleCrsfLinkStatisticsFrame(const crsfLinkStatistics_t* statsPtr,
lastLinkStatisticsFrameUs = currentTimeUs;
int16_t rssiDbm = -1 * (stats.active_antenna ? stats.uplink_RSSI_2 : stats.uplink_RSSI_1);
if (rssiSource == RSSI_SOURCE_RX_PROTOCOL_CRSF) {
if (rxConfig()->crsf_use_rx_snr) {
// -10dB of SNR mapped to 0 RSSI (fail safe is likely to happen at this measure)
// 0dB of SNR mapped to 20 RSSI (default alarm)
// 41dB of SNR mapped to 99 RSSI (SNR can climb to around 60, but showing that is not very meaningful)
const uint16_t rsnrPercentScaled = constrain((stats.uplink_SNR + 10) * 20, 0, RSSI_MAX_VALUE);
setRssi(rsnrPercentScaled, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#ifdef USE_RX_RSSI_DBM
rssiDbm = stats.uplink_SNR;
#endif
} else {
const uint16_t rssiPercentScaled = scaleRange(rssiDbm, CRSF_RSSI_MIN, 0, 0, RSSI_MAX_VALUE);
setRssi(rssiPercentScaled, RSSI_SOURCE_RX_PROTOCOL_CRSF);
}
const uint16_t rssiPercentScaled = scaleRange(rssiDbm, CRSF_RSSI_MIN, CRSF_RSSI_MAX, 0, RSSI_MAX_VALUE);
setRssi(rssiPercentScaled, RSSI_SOURCE_RX_PROTOCOL_CRSF);
}
#ifdef USE_RX_RSSI_DBM
setRssiDbm(rssiDbm, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#endif
#ifdef USE_RX_RSNR
setRsnr(stats.uplink_SNR);
#endif
#ifdef USE_RX_LINK_QUALITY_INFO
if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) {
setLinkQualityDirect(stats.uplink_Link_quality);
@ -284,12 +277,13 @@ static void handleCrsfLinkStatisticsTxFrame(const crsfLinkStatisticsTx_t* statsP
}
#ifdef USE_RX_RSSI_DBM
int16_t rssiDbm = -1 * stats.uplink_RSSI;
if (rxConfig()->crsf_use_rx_snr) {
rssiDbm = stats.uplink_SNR;
}
setRssiDbm(rssiDbm, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#endif
#ifdef USE_RX_RSNR
setRsnr(stats.uplink_SNR);
#endif
#ifdef USE_RX_LINK_QUALITY_INFO
if (linkQualitySource == LQ_SOURCE_RX_PROTOCOL_CRSF) {
setLinkQualityDirect(stats.uplink_Link_quality);
@ -312,11 +306,10 @@ static void crsfCheckRssi(uint32_t currentTimeUs)
if (rssiSource == RSSI_SOURCE_RX_PROTOCOL_CRSF) {
setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#ifdef USE_RX_RSSI_DBM
if (rxConfig()->crsf_use_rx_snr) {
setRssiDbmDirect(CRSF_SNR_MIN, RSSI_SOURCE_RX_PROTOCOL_CRSF);
} else {
setRssiDbmDirect(CRSF_RSSI_MIN, RSSI_SOURCE_RX_PROTOCOL_CRSF);
}
setRssiDbmDirect(CRSF_RSSI_MIN, RSSI_SOURCE_RX_PROTOCOL_CRSF);
#endif
#ifdef USE_RX_RSNR
setRsnrDirect(CRSF_SNR_MIN);
#endif
}
#ifdef USE_RX_LINK_QUALITY_INFO

View file

@ -79,7 +79,10 @@ static uint8_t txPower = 0;
static uint8_t wideSwitchIndex = 0;
static uint8_t currTlmDenom = 1;
static simpleLowpassFilter_t rssiFilter;
static meanAccumulator_t snrFilter;
#ifdef USE_RX_RSNR
static simpleLowpassFilter_t rsnrFilter;
#endif //USE_RX_RSNR
static meanAccumulator_t snrFilter; //for dyn power purposes
static volatile DMA_DATA uint8_t dmaBuffer[ELRS_RX_TX_BUFF_SIZE];
static volatile DMA_DATA uint8_t telemetryPacket[ELRS_RX_TX_BUFF_SIZE];
@ -89,6 +92,9 @@ static volatile uint8_t *payload;
static void rssiFilterReset(void)
{
simpleLPFilterInit(&rssiFilter, 2, 5);
#ifdef USE_RX_RSNR
simpleLPFilterInit(&rsnrFilter, 2, 5);
#endif //USE_RX_RSNR
}
#define PACKET_HANDLING_TO_TOCK_ISR_DELAY_US 250
@ -568,6 +574,9 @@ static void initializeReceiver(void)
receiver.configChanged = false;
receiver.rssi = 0;
receiver.rssiFiltered = 0;
#ifdef USE_RX_RSNR
receiver.rsnrFiltered = 0;
#endif //USE_RX_RSNR
receiver.snr = 0;
receiver.uplinkLQ = 0;
receiver.rateIndex = receiver.inBindingMode ? bindingRateIndex : rxExpressLrsSpiConfig()->rateIndex;
@ -948,6 +957,9 @@ static void handleConnectionStateUpdate(const uint32_t timeStampMs)
#ifdef USE_RX_RSSI_DBM
setRssiDbmDirect(-130, RSSI_SOURCE_RX_PROTOCOL);
#endif
#ifdef USE_RX_RSNR
setRsnrDirect(-30);
#endif
#ifdef USE_RX_LINK_QUALITY_INFO
setLinkQualityDirect(0);
#endif
@ -1015,6 +1027,10 @@ static void handleLinkStatsUpdate(const uint32_t timeStampMs)
#ifdef USE_RX_RSSI_DBM
setRssiDbm(receiver.rssiFiltered, RSSI_SOURCE_RX_PROTOCOL);
#endif
#ifdef USE_RX_RSNR
receiver.rsnrFiltered = simpleLPFilterUpdate(&rsnrFilter, receiver.snr/4);
setRsnr(receiver.rsnrFiltered);
#endif
#ifdef USE_RX_LINK_QUALITY_INFO
setLinkQualityDirect(receiver.uplinkLQ);
#endif
@ -1026,6 +1042,9 @@ static void handleLinkStatsUpdate(const uint32_t timeStampMs)
#ifdef USE_RX_RSSI_DBM
setRssiDbmDirect(-130, RSSI_SOURCE_RX_PROTOCOL);
#endif
#ifdef USE_RX_RSNR
setRsnrDirect(-30);
#endif
#ifdef USE_RX_LINK_QUALITY_INFO
setLinkQualityDirect(0);
#endif

View file

@ -68,6 +68,9 @@ typedef struct elrsReceiver_s {
int8_t rssi;
int8_t snr;
int8_t rssiFiltered;
#ifdef USE_RX_RSNR
int8_t rsnrFiltered;
#endif //USE_RX_RSNR
uint8_t uplinkLQ;

View file

@ -76,10 +76,26 @@
const char rcChannelLetters[] = "AERT12345678abcdefgh";
static uint16_t rssi = 0; // range: [0;1023]
static int16_t rssiDbm = CRSF_RSSI_MIN; // range: [-130,20]
static uint16_t rssiRaw = 0; // range: [0;1023]
static timeUs_t lastRssiSmoothingUs = 0;
#ifdef USE_RX_RSSI_DBM
static int16_t rssiDbm = CRSF_RSSI_MIN; // range: [-130,0]
static int16_t rssiDbmRaw = CRSF_RSSI_MIN; // range: [-130,0]
#endif //USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
static int16_t rsnr = CRSF_SNR_MIN; // range: [-30,20]
static int16_t rsnrRaw = CRSF_SNR_MIN; // range: [-30,20]
#endif //USE_RX_RSNR
static timeUs_t lastMspRssiUpdateUs = 0;
static pt1Filter_t frameErrFilter;
static pt1Filter_t rssiFilter;
#ifdef USE_RX_RSSI_DBM
static pt1Filter_t rssiDbmFilter;
#endif //USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
static pt1Filter_t rsnrFilter;
#endif //USE_RX_RSNR
#ifdef USE_RX_LINK_QUALITY_INFO
static uint16_t linkQuality = 0;
@ -362,6 +378,19 @@ void rxInit(void)
// Setup source frame RSSI filtering to take averaged values every FRAME_ERR_RESAMPLE_US
pt1FilterInit(&frameErrFilter, pt1FilterGain(GET_FRAME_ERR_LPF_FREQUENCY(rxConfig()->rssi_src_frame_lpf_period), FRAME_ERR_RESAMPLE_US/1000000.0));
// Configurable amount of filtering to remove excessive jumpiness of the values on the osd
float k = (256.0f - rxConfig()->rssi_smoothing) / 256.0f;
pt1FilterInit(&rssiFilter, k);
#ifdef USE_RX_RSSI_DBM
pt1FilterInit(&rssiDbmFilter, k);
#endif //USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
pt1FilterInit(&rsnrFilter, k);
#endif //USE_RX_RSNR
rxChannelCount = MIN(rxConfig()->max_aux_channel + NON_AUX_CHANNEL_COUNT, rxRuntimeState.channelCount);
}
@ -764,20 +793,7 @@ void setRssiDirect(uint16_t newRssi, rssiSource_e source)
}
rssi = newRssi;
}
#define RSSI_SAMPLE_COUNT 16
static uint16_t updateRssiSamples(uint16_t value)
{
static uint16_t samples[RSSI_SAMPLE_COUNT];
static uint8_t sampleIndex = 0;
static unsigned sum = 0;
sum += value - samples[sampleIndex];
samples[sampleIndex] = value;
sampleIndex = (sampleIndex + 1) % RSSI_SAMPLE_COUNT;
return sum / RSSI_SAMPLE_COUNT;
rssiRaw = newRssi;
}
void setRssi(uint16_t rssiValue, rssiSource_e source)
@ -788,10 +804,9 @@ void setRssi(uint16_t rssiValue, rssiSource_e source)
// Filter RSSI value
if (source == RSSI_SOURCE_FRAME_ERRORS) {
rssi = pt1FilterApply(&frameErrFilter, rssiValue);
rssiRaw = pt1FilterApply(&frameErrFilter, rssiValue);
} else {
// calculate new sample mean
rssi = updateRssiSamples(rssiValue);
rssiRaw = rssiValue;
}
}
@ -852,6 +867,37 @@ void updateRSSI(timeUs_t currentTimeUs)
default:
break;
}
if (cmpTimeUs(currentTimeUs, lastRssiSmoothingUs) > 250000) { // 0.25s
lastRssiSmoothingUs = currentTimeUs;
} else {
if (lastRssiSmoothingUs != currentTimeUs) { // avoid div by 0
float k = (256.0f - rxConfig()->rssi_smoothing) / 256.0f;
float factor = ((currentTimeUs - lastRssiSmoothingUs) / 1000000.0f) / (1.0f / 4.0f);
float k2 = (k * factor) / ((k * factor) - k + 1);
if (rssi != rssiRaw) {
pt1FilterUpdateCutoff(&rssiFilter, k2);
rssi = pt1FilterApply(&rssiFilter, rssiRaw);
}
#ifdef USE_RX_RSSI_DBM
if (rssiDbm != rssiDbmRaw) {
pt1FilterUpdateCutoff(&rssiDbmFilter, k2);
rssiDbm = pt1FilterApply(&rssiDbmFilter, rssiDbmRaw);
}
#endif //USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
if (rsnr != rsnrRaw) {
pt1FilterUpdateCutoff(&rsnrFilter, k2);
rsnr = pt1FilterApply(&rsnrFilter, rsnrRaw);
}
#endif //USE_RX_RSNR
lastRssiSmoothingUs = currentTimeUs;
}
}
}
uint16_t getRssi(void)
@ -871,32 +917,19 @@ uint8_t getRssiPercent(void)
return scaleRange(getRssi(), 0, RSSI_MAX_VALUE, 0, 100);
}
#ifdef USE_RX_RSSI_DBM
int16_t getRssiDbm(void)
{
return rssiDbm;
}
#define RSSI_SAMPLE_COUNT_DBM 16
static int16_t updateRssiDbmSamples(int16_t value)
{
static int16_t samplesdbm[RSSI_SAMPLE_COUNT_DBM];
static uint8_t sampledbmIndex = 0;
static int sumdbm = 0;
sumdbm += value - samplesdbm[sampledbmIndex];
samplesdbm[sampledbmIndex] = value;
sampledbmIndex = (sampledbmIndex + 1) % RSSI_SAMPLE_COUNT_DBM;
return sumdbm / RSSI_SAMPLE_COUNT_DBM;
}
void setRssiDbm(int16_t rssiDbmValue, rssiSource_e source)
{
if (source != rssiSource) {
return;
}
rssiDbm = updateRssiDbmSamples(rssiDbmValue);
rssiDbmRaw = rssiDbmValue;
}
void setRssiDbmDirect(int16_t newRssiDbm, rssiSource_e source)
@ -906,7 +939,27 @@ void setRssiDbmDirect(int16_t newRssiDbm, rssiSource_e source)
}
rssiDbm = newRssiDbm;
rssiDbmRaw = newRssiDbm;
}
#endif //USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
int16_t getRsnr(void)
{
return rsnr;
}
void setRsnr(int16_t rsnrValue)
{
rsnrRaw = rsnrValue;
}
void setRsnrDirect(int16_t newRsnr)
{
rsnr = newRsnr;
rsnrRaw = newRsnr;
}
#endif //USE_RX_RSNR
#ifdef USE_RX_LINK_QUALITY_INFO
uint16_t rxGetLinkQuality(void)

View file

@ -201,9 +201,17 @@ uint16_t rxGetLinkQuality(void);
void setLinkQualityDirect(uint16_t linkqualityValue);
uint16_t rxGetLinkQualityPercent(void);
#ifdef USE_RX_RSSI_DBM
int16_t getRssiDbm(void);
void setRssiDbm(int16_t newRssiDbm, rssiSource_e source);
void setRssiDbmDirect(int16_t newRssiDbm, rssiSource_e source);
#endif //USE_RX_RSSI_DBM
#ifdef USE_RX_RSNR
int16_t getRsnr(void);
void setRsnr(int16_t newRsnr);
void setRsnrDirect(int16_t newRsnr);
#endif //USE_RX_RSNR
void rxSetRfMode(uint8_t rfModeValue);
uint8_t rxGetRfMode(void);

View file

@ -362,6 +362,7 @@ extern uint8_t _dmaram_end__;
#define USE_RX_MSP
#define USE_ESC_SENSOR_INFO
#define USE_RX_RSSI_DBM
#define USE_RX_RSNR
#if !defined(CLOUD_BUILD)
#define USE_CRSF_CMS_TELEMETRY

View file

@ -606,6 +606,12 @@ extern "C" {
UNUSED(k);
}
void pt1FilterUpdateCutoff(pt1Filter_t *filter, float k)
{
UNUSED(filter);
UNUSED(k);
}
float pt1FilterApply(pt1Filter_t *filter, float input)
{
UNUSED(filter);

View file

@ -253,6 +253,12 @@ void pt1FilterInit(pt1Filter_t *filter, float k)
UNUSED(k);
}
void pt1FilterUpdateCutoff(pt1Filter_t *filter, float k)
{
UNUSED(filter);
UNUSED(k);
}
float pt1FilterApply(pt1Filter_t *filter, float input)
{
UNUSED(filter);

View file

@ -259,6 +259,12 @@ extern "C" {
UNUSED(k);
}
void pt1FilterUpdateCutoff(pt1Filter_t *filter, float k)
{
UNUSED(filter);
UNUSED(k);
}
float pt1FilterApply(pt1Filter_t *filter, float input)
{
UNUSED(filter);