Improve fast scan detection and display metadata

This commit is contained in:
Armel FAUVEAU committed 2026-05-03 22:12:54 +02:00
1 parent ec4ea28325
commit 3e6b169b7b
6 files changed
+264 -21

No files matched your search

+133 -16
View File
@@ -1,4 +1,6 @@
#include <stddef.h>
#include "app/app.h"
#include "app/chFrScanner.h"
#include "audio.h"
@@ -61,6 +63,8 @@ static void CHFRSCANNER_AbortActiveReception(void)
#define SCAN_FAST_PRECHECK_STEPS 6
#define SCAN_FAST_RSSI_MARGIN 16
#define SCAN_FAST_SQUELCH_MARGIN 8
#define SCAN_FAST_WEAK_MARGIN 8
#define SCAN_FAST_RECHECK_DELAY_US 350
#define SCAN_FAST_FINE_STEP_LIMIT 250
#define SCAN_FAST_FINE_REFINE_SPAN 1000
#define SCAN_FAST_FINE_REFINE_MAX 80
@@ -86,6 +90,8 @@ static uint16_t scanFastReg30;
static uint16_t scanFastNoiseFloor = SCAN_FAST_RSSI_MAX;
static uint32_t scanFastPrevFrequency;
static bool scanFastLastFullTuneCandidate;
static VFO_Info_t scanFastDisplayVfo;
static bool scanFastDisplayVfoValid;
static void ScanFastResetState(void)
{
@@ -96,6 +102,7 @@ static void ScanFastResetState(void)
scanFastNoiseFloor = SCAN_FAST_RSSI_MAX;
scanFastPrevFrequency = 0;
scanFastLastFullTuneCandidate = false;
scanFastDisplayVfoValid = false;
}
static void ScanFastResetNoiseFloor(void)
@@ -131,25 +138,133 @@ static void ScanFastTune(uint32_t frequency)
BK4819_WriteRegister(BK4819_REG_30, scanFastReg30);
}
static bool ScanFastIsCandidate(uint16_t rssi)
const VFO_Info_t *CHFRSCANNER_GetScanDisplayVfo(void)
{
if (scanFastNoiseFloor == SCAN_FAST_RSSI_MAX)
if (!scanFastDisplayVfoValid || gScanStateDir == SCAN_OFF || FUNCTION_IsRx())
return NULL;
return &scanFastDisplayVfo;
}
static bool ScanFastUpdateDisplayVfo(uint16_t channel, uint32_t *frequency, ModulationMode_t *modulation)
{
ChannelScanDisplayInfo_t info;
if (!SETTINGS_FetchChannelScanDisplayInfo(channel, &info))
{
scanFastNoiseFloor = rssi;
scanFastDisplayVfoValid = false;
return false;
}
const uint16_t noiseTrigger =
(scanFastNoiseFloor > SCAN_FAST_RSSI_MAX - SCAN_FAST_RSSI_MARGIN)
? SCAN_FAST_RSSI_MAX
: (uint16_t)(scanFastNoiseFloor + SCAN_FAST_RSSI_MARGIN);
const uint16_t squelchTrigger =
(gRxVfo->SquelchOpenRSSIThresh > SCAN_FAST_SQUELCH_MARGIN)
? (uint16_t)(gRxVfo->SquelchOpenRSSIThresh - SCAN_FAST_SQUELCH_MARGIN)
: 0;
scanFastDisplayVfo = gEeprom.VfoInfo[gEeprom.RX_VFO];
scanFastDisplayVfo.CHANNEL_SAVE = channel;
scanFastDisplayVfo.freq_config_RX = info.rx;
scanFastDisplayVfo.freq_config_TX = info.tx;
scanFastDisplayVfo.TX_OFFSET_FREQUENCY = info.offset;
scanFastDisplayVfo.StepFrequency = info.stepFrequency;
scanFastDisplayVfo.STEP_SETTING = info.stepSetting;
scanFastDisplayVfo.Modulation = info.modulation;
scanFastDisplayVfo.TX_OFFSET_FREQUENCY_DIRECTION = info.txOffsetFrequencyDirection;
scanFastDisplayVfo.OUTPUT_POWER = info.outputPower;
scanFastDisplayVfo.FrequencyReverse = info.frequencyReverse;
scanFastDisplayVfo.CHANNEL_BANDWIDTH = info.channelBandwidth;
scanFastDisplayVfo.BUSY_CHANNEL_LOCK = info.busyChannelLock;
scanFastDisplayVfo.TX_LOCK = info.txLock;
#ifdef ENABLE_DTMF_CALLING
scanFastDisplayVfo.DTMF_DECODING_ENABLE = info.dtmfDecodingEnable;
#endif
scanFastDisplayVfo.DTMF_PTT_ID_TX_MODE = info.dtmfPttIdTxMode;
if (!scanFastDisplayVfo.FrequencyReverse)
{
scanFastDisplayVfo.pRX = &scanFastDisplayVfo.freq_config_RX;
scanFastDisplayVfo.pTX = &scanFastDisplayVfo.freq_config_TX;
}
else
{
scanFastDisplayVfo.pRX = &scanFastDisplayVfo.freq_config_TX;
scanFastDisplayVfo.pTX = &scanFastDisplayVfo.freq_config_RX;
}
scanFastDisplayVfoValid = true;
if (frequency)
*frequency = info.rx.Frequency;
if (modulation)
*modulation = info.modulation;
if (rssi >= noiseTrigger && rssi >= squelchTrigger)
return true;
}
static uint16_t ScanFastSaturatingAdd(uint16_t value, uint16_t add)
{
return (value > SCAN_FAST_RSSI_MAX - add) ? SCAN_FAST_RSSI_MAX : (uint16_t)(value + add);
}
static uint16_t ScanFastSaturatingSub(uint16_t value, uint16_t sub)
{
return (value > sub) ? (uint16_t)(value - sub) : 0;
}
static uint16_t ScanFastGetNoiseTrigger(void)
{
return ScanFastSaturatingAdd(scanFastNoiseFloor, SCAN_FAST_RSSI_MARGIN);
}
static uint16_t ScanFastGetSquelchTrigger(void)
{
return ScanFastSaturatingSub(gRxVfo->SquelchOpenRSSIThresh, SCAN_FAST_SQUELCH_MARGIN);
}
static bool ScanFastIsNearCandidate(uint16_t rssi)
{
const uint16_t rssiWithMargin = ScanFastSaturatingAdd(rssi, SCAN_FAST_WEAK_MARGIN);
const uint16_t squelchTrigger = ScanFastGetSquelchTrigger();
if (scanFastNoiseFloor == SCAN_FAST_RSSI_MAX)
return gRxVfo->SquelchOpenRSSIThresh > 0 &&
rssiWithMargin >= gRxVfo->SquelchOpenRSSIThresh;
return rssiWithMargin >= ScanFastGetNoiseTrigger() &&
rssiWithMargin >= squelchTrigger;
}
static uint16_t ScanFastReadCandidateRssi(void)
{
uint16_t rssi = ScanFastReadRssi();
if (ScanFastIsNearCandidate(rssi))
{
SYSTICK_DelayUs(SCAN_FAST_RECHECK_DELAY_US);
const uint16_t retryRssi = ScanFastReadRssi();
if (retryRssi > rssi)
rssi = retryRssi;
}
return rssi;
}
static bool ScanFastIsCandidate(uint16_t rssi)
{
const uint16_t squelchTrigger = ScanFastGetSquelchTrigger();
if (scanFastNoiseFloor == SCAN_FAST_RSSI_MAX)
{
scanFastNoiseFloor = rssi;
return gRxVfo->SquelchOpenRSSIThresh > 0 &&
rssi >= gRxVfo->SquelchOpenRSSIThresh;
}
const uint16_t noiseTrigger = ScanFastGetNoiseTrigger();
const uint16_t rssiWithMargin = ScanFastSaturatingAdd(rssi, SCAN_FAST_WEAK_MARGIN);
if ((rssi >= noiseTrigger && rssi >= squelchTrigger) ||
(rssiWithMargin >= noiseTrigger && rssiWithMargin >= squelchTrigger))
{
return true;
}
if (rssi < scanFastNoiseFloor)
scanFastNoiseFloor = rssi;
@@ -284,7 +399,7 @@ static scan_fast_result_t ScanRangeFastPrecheck(void)
ScanFastTune(freq);
const uint16_t rssi = ScanFastReadRssi();
const uint16_t rssi = ScanFastReadCandidateRssi();
if (ScanFastIsCandidate(rssi))
{
ScanRangeFastRefineCandidate(rssi);
@@ -308,7 +423,7 @@ static bool MemChannelFastPrecheck(uint16_t channel)
return true;
}
if (!SETTINGS_FetchChannelScanInfo(channel, &frequency, &modulation))
if (!ScanFastUpdateDisplayVfo(channel, &frequency, &modulation))
{
scanFastLastFullTuneCandidate = false;
return true;
@@ -320,7 +435,7 @@ static bool MemChannelFastPrecheck(uint16_t channel)
scanFastReg30 = BK4819_ReadRegister(BK4819_REG_30) & ~BK4819_REG_30_MASK_ENABLE_AF_DAC;
ScanFastTune(frequency);
if (ScanFastIsCandidate(ScanFastReadRssi()))
if (ScanFastIsCandidate(ScanFastReadCandidateRssi()))
{
scanFastLastFullTuneCandidate = true;
return true; // signal detected: let the full tune path follow
@@ -419,7 +534,9 @@ void CHFRSCANNER_ManualResume(const int8_t scan_direction)
{
CHFRSCANNER_Start(false, scan_direction);
gScanPauseDelayIn_10ms = 1;
gScanPauseDelayIn_10ms = (gRxVfo->SquelchOpenRSSIThresh == 0)
? scan_pause_delay_in_3_10ms
: 1;
gScheduleScanListen = false;
}
+5
View File
@@ -4,6 +4,8 @@
#include <stdbool.h>
#include <stdint.h>
#include "radio.h"
// scan direction, if not equal SCAN_OFF indicates
// that we are in a process of scanning channels/frequencies
extern int8_t gScanStateDir;
@@ -20,6 +22,9 @@ void CHFRSCANNER_Stop(void);
void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_direction);
void CHFRSCANNER_ManualResume(const int8_t scan_direction);
void CHFRSCANNER_ContinueScanning(void);
#ifdef ENABLE_FEAT_F4HWN_SCAN_FASTER
const VFO_Info_t *CHFRSCANNER_GetScanDisplayVfo(void);
#endif
#if defined(ENABLE_FEAT_F4HWN_RESUME_STATE) || defined(ENABLE_SCAN_RANGES)
void CHFRSCANNER_ScanRange(void);
+1
View File
@@ -156,6 +156,7 @@ uint16_t RADIO_FindNextChannel(uint16_t ChNum, int8_t Direction, bool bCheckScan
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint16_t ChannelSave, const uint32_t Frequency);
void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure);
void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo);
void RADIO_ValidateAndSetCode(FREQ_Config_t *pFreq_Config, uint8_t tmp);
void RADIO_ApplyOffset(VFO_Info_t *pInfo);
void RADIO_SelectVfos(void);
void RADIO_SetupRegisters(bool switchToForeground);
+93
View File
@@ -604,6 +604,99 @@ bool SETTINGS_FetchChannelScanInfo(const uint16_t channel, uint32_t *frequency,
return info.frequency != 0 && info.frequency != 0xFFFFFFFF;
}
bool SETTINGS_FetchChannelScanDisplayInfo(const uint16_t channel, ChannelScanDisplayInfo_t *info)
{
if (info == NULL)
return false;
struct
{
uint32_t frequency;
uint32_t offset;
uint8_t data[8];
} __attribute__((packed)) raw;
PY25Q16_ReadBuffer(channel * 16, &raw, sizeof(raw));
if (raw.frequency == 0 || raw.frequency == 0xFFFFFFFF)
return false;
memset(info, 0, sizeof(*info));
info->rx.Frequency = raw.frequency;
info->tx.Frequency = raw.frequency;
info->offset = (raw.offset >= _1GHz_in_KHz) ? (_1GHz_in_KHz / 100) : raw.offset;
info->rx.CodeType = (raw.data[2] >> 0) & 0x0F;
info->tx.CodeType = (raw.data[2] >> 4) & 0x0F;
RADIO_ValidateAndSetCode(&info->rx, raw.data[0]);
RADIO_ValidateAndSetCode(&info->tx, raw.data[1]);
uint8_t tmp = raw.data[3] & 0x0F;
if (tmp > TX_OFFSET_FREQUENCY_DIRECTION_SUB)
tmp = TX_OFFSET_FREQUENCY_DIRECTION_OFF;
info->txOffsetFrequencyDirection = tmp;
tmp = raw.data[3] >> 4;
if (tmp >= MODULATION_UKNOWN)
tmp = MODULATION_FM;
info->modulation = (ModulationMode_t)tmp;
tmp = raw.data[6];
if (tmp >= STEP_N_ELEM)
tmp = STEP_12_5kHz;
info->stepSetting = (STEP_Setting_t)tmp;
info->stepFrequency = gStepFrequencyTable[tmp];
if (raw.data[4] == 0xFF)
{
info->frequencyReverse = false;
info->channelBandwidth = BANDWIDTH_WIDE;
info->outputPower = OUTPUT_POWER_LOW1;
info->busyChannelLock = false;
info->txLock = true;
}
else
{
const uint8_t d4 = raw.data[4];
info->frequencyReverse = !!((d4 >> 0) & 1u);
info->channelBandwidth = !!((d4 >> 1) & 1u);
info->outputPower = ((d4 >> 2) & 7u);
info->busyChannelLock = !!((d4 >> 5) & 1u);
info->txLock = !!((d4 >> 6) & 1u);
}
switch (info->txOffsetFrequencyDirection)
{
case TX_OFFSET_FREQUENCY_DIRECTION_ADD:
info->tx.Frequency = raw.frequency + info->offset;
break;
case TX_OFFSET_FREQUENCY_DIRECTION_SUB:
info->tx.Frequency = raw.frequency - info->offset;
break;
default:
break;
}
if (raw.data[5] == 0xFF)
{
#ifdef ENABLE_DTMF_CALLING
info->dtmfDecodingEnable = false;
#endif
info->dtmfPttIdTxMode = PTT_ID_OFF;
}
else
{
#ifdef ENABLE_DTMF_CALLING
info->dtmfDecodingEnable = (raw.data[5] >> 0) & 1u;
#endif
const uint8_t pttId = (raw.data[5] >> 1) & 7u;
info->dtmfPttIdTxMode = pttId < ARRAY_SIZE(gSubMenu_PTT_ID) ? pttId : PTT_ID_OFF;
}
return true;
}
void SETTINGS_FetchChannelName(char *s, const uint16_t channel)
{
if (s == NULL)
+20
View File
@@ -307,10 +307,30 @@ typedef struct {
extern EEPROM_Config_t gEeprom;
typedef struct {
FREQ_Config_t rx;
FREQ_Config_t tx;
uint32_t offset;
uint16_t stepFrequency;
STEP_Setting_t stepSetting;
ModulationMode_t modulation;
uint8_t txOffsetFrequencyDirection;
uint8_t outputPower;
bool frequencyReverse;
uint8_t channelBandwidth;
uint8_t busyChannelLock;
uint8_t txLock;
#ifdef ENABLE_DTMF_CALLING
uint8_t dtmfDecodingEnable;
#endif
PTT_ID_t dtmfPttIdTxMode;
} ChannelScanDisplayInfo_t;
void SETTINGS_InitEEPROM(void);
void SETTINGS_LoadCalibration(void);
uint32_t SETTINGS_FetchChannelFrequency(const uint16_t channel);
bool SETTINGS_FetchChannelScanInfo(const uint16_t channel, uint32_t *frequency, ModulationMode_t *modulation);
bool SETTINGS_FetchChannelScanDisplayInfo(const uint16_t channel, ChannelScanDisplayInfo_t *info);
void SETTINGS_FetchChannelName(char *s, const uint16_t channel);
void SETTINGS_FactoryReset(bool bIsAll);
#ifdef ENABLE_FMRADIO
+12 -5
View File
@@ -1748,6 +1748,11 @@ void UI_DisplayMain(void)
String[0] = '\0';
const VFO_Info_t *vfoInfo = &gEeprom.VfoInfo[vfo_num];
#ifdef ENABLE_FEAT_F4HWN_SCAN_FASTER
const VFO_Info_t *scanDisplayVfo = CHFRSCANNER_GetScanDisplayVfo();
if (vfo_num == gEeprom.RX_VFO && scanDisplayVfo != NULL)
vfoInfo = scanDisplayVfo;
#endif
// show the modulation symbol
const char * s = "";
@@ -1937,10 +1942,12 @@ void UI_DisplayMain(void)
#endif
#if ENABLE_FEAT_F4HWN
const uint8_t displayBandwidth = vfoInfo->CHANNEL_BANDWIDTH;
#ifdef ENABLE_FEAT_F4HWN_NARROWER
bool narrower = 0;
if(vfoInfo->CHANNEL_BANDWIDTH == BANDWIDTH_NARROW && gSetting_set_nfm == 1)
if(displayBandwidth == BANDWIDTH_NARROW && gSetting_set_nfm == 1)
{
narrower = 1;
}
@@ -1948,23 +1955,23 @@ void UI_DisplayMain(void)
if (gSetting_set_gui)
{
const char *bandWidthNames[] = {"W", "N", "N+"};
UI_PrintStringSmallNormal(bandWidthNames[vfoInfo->CHANNEL_BANDWIDTH + narrower], LCD_WIDTH + 80, 0, line + 1);
UI_PrintStringSmallNormal(bandWidthNames[displayBandwidth + narrower], LCD_WIDTH + 80, 0, line + 1);
}
else
{
const char *bandWidthNames[] = {"WIDE", "NAR", "NAR+"};
GUI_DisplaySmallest(bandWidthNames[vfoInfo->CHANNEL_BANDWIDTH + narrower], 91, line == 0 ? 17 : 49, false, true);
GUI_DisplaySmallest(bandWidthNames[displayBandwidth + narrower], 91, line == 0 ? 17 : 49, false, true);
}
#else
if (gSetting_set_gui)
{
const char *bandWidthNames[] = {"W", "N"};
UI_PrintStringSmallNormal(bandWidthNames[vfoInfo->CHANNEL_BANDWIDTH], LCD_WIDTH + 80, 0, line + 1);
UI_PrintStringSmallNormal(bandWidthNames[displayBandwidth], LCD_WIDTH + 80, 0, line + 1);
}
else
{
const char *bandWidthNames[] = {"WIDE", "NAR"};
GUI_DisplaySmallest(bandWidthNames[vfoInfo->CHANNEL_BANDWIDTH], 91, line == 0 ? 17 : 49, false, true);
GUI_DisplaySmallest(bandWidthNames[displayBandwidth], 91, line == 0 ? 17 : 49, false, true);
}
#endif
#else