From 10868858c51683cc9b927733967a2e3f069c4633 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 19 Jul 2026 15:50:34 +0200 Subject: [PATCH 01/42] Update README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5617c0ab..0d74699d 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Anyway, have fun. # Donations -Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ and Carlos EA1IJ for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 +Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ, Carlos EA1IJ and Brian M7YLF for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 ## Table of Contents @@ -140,7 +140,7 @@ Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Ol * named scan lists are shown in the UI and status bar when available, * if the selected scan list is empty or invalid, the firmware automatically jumps to the next valid one, * very fast scan mode (around 150 freq/s), - * frequencies exclusions, + * 64 frequencies exclusions, * add resume mode on startup (scan, spectrum analyzer and FM radio), * improve VFO persistence and restore behavior: * save the Squelch level adjusted with F + UP or F + DOWN, @@ -155,6 +155,7 @@ Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Ol * POWER HIGH, * REMOVE OFFSET, * BEAM, + * RF LOG, * new key combinations: * add the F + UP or F + DOWN key combination to dynamically change the Squelch level, * add the F + F1 or F + F2 key combination to dynamically change the Step, From dd3fc786b54210fbe3153de21766065435ef9da4 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Mon, 20 Jul 2026 22:29:15 +0200 Subject: [PATCH 02/42] Gate RF logging on key assignment --- App/app/rxtx_log.c | 48 +++++++++++++++++++++++++++++++--------------- App/app/rxtx_log.h | 13 ++++++++----- App/k5viewer.c | 11 +++++++++-- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/App/app/rxtx_log.c b/App/app/rxtx_log.c index 3b3e9e87..fd952035 100644 --- a/App/app/rxtx_log.c +++ b/App/app/rxtx_log.c @@ -136,6 +136,22 @@ static uint16_t gLogCursor; static uint8_t gLogFilter; static uint8_t gLogDetailMode; +bool RXTX_LOG_IsEnabled(void) +{ + return gEeprom.KEY_1_SHORT_PRESS_ACTION == ACTION_OPT_RXTX_LOG || + gEeprom.KEY_1_LONG_PRESS_ACTION == ACTION_OPT_RXTX_LOG || + gEeprom.KEY_2_SHORT_PRESS_ACTION == ACTION_OPT_RXTX_LOG || + gEeprom.KEY_2_LONG_PRESS_ACTION == ACTION_OPT_RXTX_LOG || + gEeprom.KEY_M_LONG_PRESS_ACTION == ACTION_OPT_RXTX_LOG; +} + +static void RXTX_LOG_ResetActiveSession(void) +{ + gSessionActive = false; + gSessionSMeter = RXTX_LOG_SMETER_UNKNOWN; + gSessionBattVolt = RXTX_LOG_BATT_UNKNOWN; +} + static uint8_t RXTX_LOG_Crc8(const void *data, uint16_t size) { const uint8_t *p = (const uint8_t *)data; @@ -755,6 +771,7 @@ uint32_t RXTX_LOG_K5ViewerSignature(void) { uint32_t hash = 2166136261u; + hash = RXTX_LOG_K5ViewerMix(hash, RXTX_LOG_IsEnabled()); hash = RXTX_LOG_K5ViewerMix(hash, gSessionActive); hash = RXTX_LOG_K5ViewerMix(hash, gClearActive); hash = RXTX_LOG_K5ViewerMix(hash, gLogHasTraffic); @@ -863,6 +880,13 @@ void RXTX_LOG_SendK5ViewerPacket(void (*send)(const uint8_t *data, uint16_t size RXTX_LogK5ViewerRow_t row; uint8_t header[4] = {RXTX_LOG_K5VIEWER_VERSION, 0, RXTX_LOG_K5VIEWER_ROW_COUNT, 0}; + if (!RXTX_LOG_IsEnabled()) { + header[1] = RXTX_LOG_K5VIEWER_STATUS_DISABLED; + header[2] = 0; + send(header, sizeof(header)); + return; + } + if (gSessionActive) header[1] |= RXTX_LOG_K5VIEWER_STATUS_ACTIVE; if (gLogHasTraffic) @@ -898,7 +922,7 @@ uint32_t RXTX_LOG_SendK5ViewerHistoryPage(uint32_t beforeSeq, void (*send)(const static void RXTX_LOG_CaptureSession(uint8_t flags, const VFO_Info_t *vfo) { - if (gClearActive) + if (!RXTX_LOG_IsEnabled() || vfo == NULL || gClearActive) return; const uint32_t frequency = (flags & RXTX_LOG_FLAG_TX) ? vfo->pTX->Frequency : vfo->pRX->Frequency; @@ -984,15 +1008,13 @@ void RXTX_LOG_Init(void) // Skip the marker if the log already ends with one (e.g. repeated // reboots with no RX/TX in between) to avoid stacking empty separators. - if (!found || (lastEntryFlags & RXTX_LOG_FLAG_SESSION) == 0) + if (RXTX_LOG_IsEnabled() && + (!found || (lastEntryFlags & RXTX_LOG_FLAG_SESSION) == 0)) RXTX_LOG_WriteSessionMarker(); } void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function) { - if (vfo == NULL) - return; - uint8_t flags = 0; if (function == FUNCTION_MONITOR) flags |= RXTX_LOG_FLAG_MONITOR; @@ -1002,9 +1024,6 @@ void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function) void RXTX_LOG_BeginTx(const VFO_Info_t *vfo) { - if (vfo == NULL) - return; - RXTX_LOG_CaptureSession(RXTX_LOG_FLAG_TX, vfo); } @@ -1013,10 +1032,8 @@ void RXTX_LOG_EndActive(void) if (!gSessionActive) return; - if (gClearActive) { - gSessionActive = false; - gSessionSMeter = RXTX_LOG_SMETER_UNKNOWN; - gSessionBattVolt = RXTX_LOG_BATT_UNKNOWN; + if (!RXTX_LOG_IsEnabled() || gClearActive) { + RXTX_LOG_ResetActiveSession(); return; } @@ -1040,9 +1057,7 @@ void RXTX_LOG_EndActive(void) gLogHasTraffic = true; RXTX_LOG_InvalidateViewCache(); - gSessionActive = false; - gSessionSMeter = RXTX_LOG_SMETER_UNKNOWN; - gSessionBattVolt = RXTX_LOG_BATT_UNKNOWN; + RXTX_LOG_ResetActiveSession(); } void RXTX_LOG_Tick500ms(void) @@ -1056,6 +1071,9 @@ void RXTX_LOG_Tick500ms(void) void RXTX_LOG_Task10ms(void) { + if (gSessionActive && !RXTX_LOG_IsEnabled()) + RXTX_LOG_ResetActiveSession(); + if (gClearActive) { RXTX_LOG_StepClear(); } else if (gViewScanActive) { diff --git a/App/app/rxtx_log.h b/App/app/rxtx_log.h index 0c849bb3..5fcc2a69 100644 --- a/App/app/rxtx_log.h +++ b/App/app/rxtx_log.h @@ -42,6 +42,8 @@ typedef struct { #define RXTX_LOG_K5VIEWER_STATUS_ACTIVE (1u << 0) #define RXTX_LOG_K5VIEWER_STATUS_HAS_TRAFFIC (1u << 1) #define RXTX_LOG_K5VIEWER_STATUS_CLEARING (1u << 2) +#define RXTX_LOG_K5VIEWER_STATUS_DISABLED (1u << 3) +#define RXTX_LOG_K5VIEWER_STATUS_PACKET_SIZE 4u typedef struct __attribute__((packed)) { uint32_t frequency; @@ -54,11 +56,11 @@ typedef struct __attribute__((packed)) { char channelName[RXTX_LOG_K5VIEWER_NAME_LENGTH]; } RXTX_LogK5ViewerRow_t; -// On-wire packet layout: 4-byte header (version, status, rowCount, -// reserved), one live row, then RXTX_LOG_K5VIEWER_ROW_COUNT row slots, -// zero-padded past the last valid row. The packet is streamed row by row -// and never built whole in RAM, so only its size is defined here. -#define RXTX_LOG_K5VIEWER_PACKET_SIZE (4u + ((RXTX_LOG_K5VIEWER_ROW_COUNT + 1u) * sizeof(RXTX_LogK5ViewerRow_t))) +// On-wire packet layout: a disabled log sends only the 4-byte status header. +// An enabled log continues with one live row and +// RXTX_LOG_K5VIEWER_ROW_COUNT row slots, zero-padded past the last valid row. +// The packet is streamed row by row and never built whole in RAM. +#define RXTX_LOG_K5VIEWER_PACKET_SIZE (RXTX_LOG_K5VIEWER_STATUS_PACKET_SIZE + ((RXTX_LOG_K5VIEWER_ROW_COUNT + 1u) * sizeof(RXTX_LogK5ViewerRow_t))) #define RXTX_LOG_K5VIEWER_HISTORY_PACKET_SIZE (RXTX_LOG_K5VIEWER_HISTORY_ROW_COUNT * sizeof(RXTX_LogK5ViewerRow_t)) uint32_t RXTX_LOG_K5ViewerSignature(void); @@ -70,6 +72,7 @@ uint32_t RXTX_LOG_SendK5ViewerHistoryPage(uint32_t beforeSeq, void (*send)(const #endif void RXTX_LOG_Init(void); +bool RXTX_LOG_IsEnabled(void); void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function); void RXTX_LOG_BeginTx(const VFO_Info_t *vfo); void RXTX_LOG_EndActive(void); diff --git a/App/k5viewer.c b/App/k5viewer.c index 683b8859..5752ad34 100644 --- a/App/k5viewer.c +++ b/App/k5viewer.c @@ -123,6 +123,9 @@ static uint8_t K5VIEWER_StateFlags(void) #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER static bool K5VIEWER_HasPendingRfLogUpdate(void) { + if (!RXTX_LOG_IsEnabled()) + rfLogHistoryBefore = RXTX_LOG_K5VIEWER_HISTORY_START; + if ((gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_RESTART) != 0) { gSerialViewerFeatures &= ~SERIAL_VIEWER_FEATURE_RF_LOG_RESTART; rfLogSent = false; @@ -157,14 +160,18 @@ static void K5VIEWER_SendRfLog(void) previousRfLogSignature = RXTX_LOG_K5ViewerSignature(); rfLogSent = true; - K5VIEWER_SendRfLogFrameHeader(K5VIEWER_TYPE_RXTX_LOG, RXTX_LOG_K5VIEWER_PACKET_SIZE); + const uint16_t size = RXTX_LOG_IsEnabled() + ? RXTX_LOG_K5VIEWER_PACKET_SIZE + : RXTX_LOG_K5VIEWER_STATUS_PACKET_SIZE; + K5VIEWER_SendRfLogFrameHeader(K5VIEWER_TYPE_RXTX_LOG, size); RXTX_LOG_SendK5ViewerPacket(K5VIEWER_Send); K5VIEWER_SendRfLogFrameEnd(); } static bool K5VIEWER_HasPendingRfLogHistory(void) { - return (gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_HISTORY) != 0 && + return RXTX_LOG_IsEnabled() && + (gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_HISTORY) != 0 && rfLogHistoryBefore != 0; } From 65ec12bb0d8afa7f9e14a675a90d43f82a754145 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Wed, 22 Jul 2026 04:05:07 +0200 Subject: [PATCH 03/42] Show active scan list name when it changes during scan (discussion #462) --- App/app/action.c | 2 +- App/app/chFrScanner.c | 8 +++-- App/app/main.c | 6 ++-- App/ui/main.c | 69 ++++++++++++++++++++++++++++++++++++++----- App/ui/main.h | 2 ++ 5 files changed, 74 insertions(+), 13 deletions(-) diff --git a/App/app/action.c b/App/app/action.c index 97da7c59..d4468e32 100644 --- a/App/app/action.c +++ b/App/app/action.c @@ -243,7 +243,7 @@ void ACTION_Scan(bool bRestart) // channel mode. Keep scanning but toggle between scan lists RADIO_NextValidList(1); - UI_MAIN_NotifyScanProgressDataChanged(); + UI_MAIN_NotifyScanListChanged(); #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE SETTINGS_WriteCurrentState(); diff --git a/App/app/chFrScanner.c b/App/app/chFrScanner.c index 0d6a2758..862370b6 100644 --- a/App/app/chFrScanner.c +++ b/App/app/chFrScanner.c @@ -771,13 +771,17 @@ void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_directi #endif if (IS_MR_CHANNEL(gNextMrChannel)) - { + { + bool scanListChanged = false; if(!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) { RADIO_NextValidList(1); - UI_MAIN_NotifyScanProgressDataChanged(); + scanListChanged = true; } + if (storeBackupSettings || scanListChanged) + UI_MAIN_NotifyScanListChanged(); + // channel mode if (storeBackupSettings) { initialFrqOrChan = gRxVfo->CHANNEL_SAVE; diff --git a/App/app/main.c b/App/app/main.c index 4d8938db..a3a45362 100644 --- a/App/app/main.c +++ b/App/app/main.c @@ -317,7 +317,7 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep) if (gScanStateDir != SCAN_OFF) { RADIO_NextValidList(isKeyUp ? 1 : -1); - UI_MAIN_NotifyScanProgressDataChanged(); + UI_MAIN_NotifyScanListChanged(); } else { // Adjust squelch: UP increments, DOWN decrements if (gSquelchLevelOriginal == 10) @@ -500,7 +500,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) if (value == 0) { gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1; - UI_MAIN_NotifyScanProgressDataChanged(); + UI_MAIN_NotifyScanListChanged(); #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE SETTINGS_WriteCurrentState(); #endif @@ -519,7 +519,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; RADIO_NextValidList(1); } - UI_MAIN_NotifyScanProgressDataChanged(); + UI_MAIN_NotifyScanListChanged(); #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE SETTINGS_WriteCurrentState(); diff --git a/App/ui/main.c b/App/ui/main.c index b5c860ac..3946966d 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -68,6 +68,7 @@ center_line_t center_line = CENTER_LINE_NONE; #ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS #define SCAN_PROGRESS_MR_CHANNEL_BYTES ((MR_CHANNELS_MAX + 7u) / 8u) +#define SCAN_LIST_NAME_HOLD_500MS (2000u / 500u) static bool gScanProgressSessionActive; static bool gScanProgressSessionIsMemory; @@ -82,6 +83,7 @@ static bool gScanProgressPrevResetVfosFlag; static bool gScanProgressForceRebuild; static uint16_t gScanProgressLastMemoryIndex; static uint8_t gScanProgressPriorityState; +static uint8_t gScanListNameCountdown_500ms; #define SCAN_PROGRESS_PRIORITY_LABEL_MASK 0x03u #define SCAN_PROGRESS_PRIORITY_SEEN_SHIFT 2 #define SCAN_PROGRESS_PRIORITY_SEEN_MASK 0x1cu @@ -90,15 +92,24 @@ static uint8_t gScanProgressPriorityState; #define SCAN_PROGRESS_PRIORITY_HOLD_FRAMES 6 #endif +#if defined(ENABLE_FEAT_F4HWN_BEAM) || defined(ENABLE_FEAT_F4HWN_SCAN_PROGRESS) +// Shared center-line renderer: clear the line and print bold text on it. +static void UI_MAIN_DrawCenterBoldLine(const char *text, uint8_t start) +{ +#ifdef ENABLE_FEAT_F4HWN + const uint8_t line = isMainOnly() ? 5 : 3; +#else + const uint8_t line = 3; +#endif + memset(gFrameBuffer[line], 0, LCD_WIDTH); + UI_PrintStringSmallBold(text, start, LCD_WIDTH - 1, line); +} +#endif + #ifdef ENABLE_FEAT_F4HWN_BEAM static void UI_MAIN_DrawBeamLine(void) { const char *text; -#ifdef ENABLE_FEAT_F4HWN - const unsigned int line = isMainOnly() ? 5 : 3; -#else - const unsigned int line = 3; -#endif switch (gBeamStatus) { case BEAM_STATUS_TX_WAIT: @@ -125,8 +136,7 @@ static void UI_MAIN_DrawBeamLine(void) break; } - memset(gFrameBuffer[line], 0, LCD_WIDTH); - UI_PrintStringSmallBold(text, 2, 127, line); + UI_MAIN_DrawCenterBoldLine(text, 2); } #endif @@ -214,6 +224,7 @@ static void ScanProgress_ResetSession(void) gScanProgressForceRebuild = false; gScanProgressLastMemoryIndex = 0; gScanProgressPriorityState = 0; + gScanListNameCountdown_500ms = 0; } void UI_MAIN_NotifyScanProgressDataChanged(void) @@ -222,6 +233,13 @@ void UI_MAIN_NotifyScanProgressDataChanged(void) gUpdateStatus = true; } +void UI_MAIN_NotifyScanListChanged(void) +{ + UI_MAIN_NotifyScanProgressDataChanged(); + gScanListNameCountdown_500ms = SCAN_LIST_NAME_HOLD_500MS; + gUpdateDisplay = true; +} + static inline void ScanProgress_SetBit(uint8_t *map, uint16_t ch) { map[ch >> 3] |= (uint8_t)(1u << (ch & 7)); @@ -243,6 +261,33 @@ static uint8_t ScanProgress_GetActiveScanList(void) return scan_list; } +static void UI_MAIN_DrawScanListName(void) +{ + const uint8_t scan_list = ScanProgress_GetActiveScanList(); + char text[16]; + + // Manual formatting instead of snprintf: much smaller on a divide-less M0 core + strcpy(text, "SCAN LIST "); + char *p = text + 10; // sizeof("SCAN LIST ") - 1 + + if (scan_list > MR_CHANNELS_LIST) { + *p++ = 'A'; *p++ = 'L'; *p++ = 'L'; + } else { + const char *name = gListName[scan_list - 1]; + + if (IsEmptyName(name, sizeof(gListName[0]))) { + *p++ = (char)('0' + scan_list / 10); + *p++ = (char)('0' + scan_list % 10); + } else { + for (uint8_t i = 0; i < 3 && name[i]; i++) + *p++ = name[i]; + } + } + *p = '\0'; + + UI_MAIN_DrawCenterBoldLine(text, 0); +} + static bool ScanProgress_ChannelBelongsToList(uint16_t channel, const ChannelAttributes_t *att, uint8_t scan_list) { if (!IS_MR_CHANNEL(channel)) @@ -490,6 +535,12 @@ static bool UI_DrawScanProgress(void) return false; } + // Right after a scan-list change, briefly show its name instead of the progress bar + if (show_memory && gScanListNameCountdown_500ms > 0) { + UI_MAIN_DrawScanListName(); + return true; + } + if (show_memory) { const uint8_t scan_list = ScanProgress_GetActiveScanList(); const bool reset_vfos_edge = gFlagResetVfos && !gScanProgressPrevResetVfosFlag; @@ -1167,6 +1218,10 @@ void UI_MAIN_PrintAGC(bool now) void UI_MAIN_TimeSlice500ms(void) { if(gScreenToDisplay==DISPLAY_MAIN) { +#ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS + if (gScanListNameCountdown_500ms > 0 && --gScanListNameCountdown_500ms == 0) + gUpdateDisplay = true; +#endif #ifdef ENABLE_AGC_SHOW_DATA UI_MAIN_PrintAGC(true); return; diff --git a/App/ui/main.h b/App/ui/main.h index 43abb3aa..777b26f1 100644 --- a/App/ui/main.h +++ b/App/ui/main.h @@ -55,8 +55,10 @@ void UI_DisplayMain(void); #ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS void UI_MAIN_NotifyScanProgressDataChanged(void); +void UI_MAIN_NotifyScanListChanged(void); #else static inline void UI_MAIN_NotifyScanProgressDataChanged(void) {} +static inline void UI_MAIN_NotifyScanListChanged(void) {} #endif #ifdef ENABLE_AGC_SHOW_DATA From 2ee1d96e5cba5a310f81f416a18e94bd2668fc80 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 26 Jul 2026 16:53:15 +0200 Subject: [PATCH 04/42] Smooth power-on backlight fade with smoothstep easing (~470 ms) --- App/driver/backlight.c | 45 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/App/driver/backlight.c b/App/driver/backlight.c index 7c59ad84..bbf9bab2 100644 --- a/App/driver/backlight.c +++ b/App/driver/backlight.c @@ -54,6 +54,17 @@ static int16_t currentBrightness = 0; static int16_t targetBrightness = 0; static int16_t fadeStep = 0; +static void BACKLIGHT_SetHardwareBrightness(uint8_t brightness); + +#ifdef ENABLE_FEAT_F4HWN + // Power-on fade-in tuning. + // STEPS = number of intermediate brightness stops (smoothness). + // STEP_MS = pacing between stops. + // STEPS * STEP_MS ~= total fade duration in ms. + #define BL_STARTUP_FADE_STEPS 40 + #define BL_STARTUP_FADE_STEP_MS 12 +#endif + #ifdef ENABLE_FEAT_F4HWN const uint8_t value[] = { 0, // 0 off @@ -130,6 +141,37 @@ void BACKLIGHT_UpdateTickless(void) { } } +#ifdef ENABLE_FEAT_F4HWN +// Soft, progressive power-on fade-in. +// Ramps from the current brightness (0 at power-on) to targetBrightness using +// a smoothstep (3x^2 - 2x^3) easing curve. Easing gently at both ends reads as +// a smooth, progressive fade instead of the abrupt linear ramp, and stepping +// through many fine stops keeps it fluid even with the 32-level PWM. +static void BACKLIGHT_FadeInStartup(void) +{ + const int16_t from = currentBrightness; // 0 at power-on + const int16_t span = targetBrightness - from; // ramp amplitude + + if (span <= 0) { + gUpdateBacklight = false; + return; + } + + for (uint16_t s = 1; s < BL_STARTUP_FADE_STEPS; s++) { + // x in Q8 (0..256), e = smoothstep(x) in Q16 (0..65536) + uint32_t x = (uint32_t)s * 256 / BL_STARTUP_FADE_STEPS; + uint32_t e = (x * x * (768 - 2 * x)) >> 8; + currentBrightness = from + (int16_t)(((uint32_t)span * e) >> 16); + BACKLIGHT_SetHardwareBrightness((uint8_t)currentBrightness); + SYSTEM_DelayMs(BL_STARTUP_FADE_STEP_MS); + } + + currentBrightness = targetBrightness; + BACKLIGHT_SetHardwareBrightness((uint8_t)currentBrightness); + gUpdateBacklight = false; +} +#endif + void BACKLIGHT_TurnOn(void) { #ifdef ENABLE_FEAT_F4HWN_SLEEP @@ -163,10 +205,11 @@ void BACKLIGHT_TurnOn(void) if(startup) #endif { - BACKLIGHT_UpdateTickless(); #ifdef ENABLE_FEAT_F4HWN + BACKLIGHT_FadeInStartup(); BACKLIGHT_Sound(); #else + BACKLIGHT_UpdateTickless(); startup = false; #endif } From bf7eda8a48393d93c7c414623de16562d880f284 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Mon, 27 Jul 2026 17:09:39 +0200 Subject: [PATCH 05/42] Fix false Remove Offset indicator after disabling reverse (issue #469) --- App/ui/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/App/ui/main.c b/App/ui/main.c index 3946966d..484111ce 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -2110,7 +2110,11 @@ void UI_DisplayMain(void) #ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS const char dir_list[][2] = {"", "+", "-", "D"}; - if(gTxVfo->TX_OFFSET_FREQUENCY_DIRECTION != 0 && gTxVfo->pTX == &gTxVfo->freq_config_RX && !vfoInfo->FrequencyReverse) + if(gRemoveOffset && + vfoInfo == gTxVfo && + gTxVfo->TX_OFFSET_FREQUENCY_DIRECTION != 0 && + gTxVfo->pTX == &gTxVfo->freq_config_RX && + !vfoInfo->FrequencyReverse) { i = 3; } From 7f906300e3678a981d444d96b8e836a45a7e1763 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 28 Jul 2026 18:33:19 +0200 Subject: [PATCH 06/42] Add opt-in Fusion development firmware build --- App/CMakeLists.txt | 1 + App/ui/menu.c | 2 +- App/ui/welcome.c | 29 +++++++++++++++++++++------ App/version.c | 11 +++++----- App/version.h | 1 + CMakeLists.txt | 23 +++++++++++++++++++++ CMakePresets.json | 3 ++- README.md | 11 ++++++++++ archive/f4hwn.fusion.development.bin | Bin 0 -> 104208 bytes compile-with-docker.sh | 1 + 10 files changed, 69 insertions(+), 13 deletions(-) create mode 100755 archive/f4hwn.fusion.development.bin diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index 0fdd20ce..09d33e28 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -70,6 +70,7 @@ if(ENABLE_FEAT_F4HWN) "AUTHOR_STRING_2=\"${AUTHOR_STRING_2}\"" "VERSION_STRING_1=\"${VERSION_STRING_1}\"" "VERSION_STRING_2=\"${VERSION_STRING_2}\"" + "DISPLAY_VERSION_STRING_2=\"${DISPLAY_VERSION_STRING_2}\"" "EDITION_STRING=\"${EDITION_STRING}\"" ALERT_TOT=10 ) diff --git a/App/ui/menu.c b/App/ui/menu.c index 65975b1a..febae9a6 100644 --- a/App/ui/menu.c +++ b/App/ui/menu.c @@ -1187,7 +1187,7 @@ void UI_DisplayMenu(void) if (page == p++) { // Page 0: firmware identity. #ifdef ENABLE_FEAT_F4HWN - sprintf(String, "%s\n%s", AUTHOR_STRING_2, VERSION_STRING_2); + sprintf(String, "%s\n%s", AUTHOR_STRING_2, DISPLAY_VERSION_STRING_2); UI_PrintStringSmallNormal(Edition, menu_item_x1 - 1, menu_item_x2, 6); #else sprintf(String, "%u.%02uV\n%u%%", diff --git a/App/ui/welcome.c b/App/ui/welcome.c index 798526c5..0547f468 100644 --- a/App/ui/welcome.c +++ b/App/ui/welcome.c @@ -20,6 +20,7 @@ #include "driver/py25q16.h" #include "driver/st7565.h" #include "external/printf/printf.h" +#include "font.h" #include "helper/battery.h" #include "settings.h" #include "misc.h" @@ -312,17 +313,33 @@ void UI_DisplayWelcome(void) UI_PrintString(WelcomeString1, 0, 127, 2, 10); #ifdef ENABLE_FEAT_F4HWN - UI_PrintStringSmallNormal(Version, 0, 128, 4); + const size_t version_width = strlen(DisplayVersion) * (ARRAY_SIZE(gFontSmall[0]) + 1u); + const uint8_t version_x = version_width < LCD_WIDTH + ? (uint8_t)((LCD_WIDTH - version_width + 1u) / 2u) + : 0u; + const uint8_t capsule_left = version_x > 2u ? (uint8_t)(version_x - 3u) : 0u; + const size_t capsule_right_candidate = version_x + version_width + 2u; + const uint8_t capsule_right = capsule_right_candidate < LCD_WIDTH + ? (uint8_t)capsule_right_candidate + : (LCD_WIDTH - 1u); - UI_DrawLineBuffer(gFrameBuffer, 0, 35, 18, 35, 1); - gFrameBuffer[4][19] ^= 0x7F; - for (uint8_t x = 20; x < 108; x++) + UI_PrintStringSmallNormal(DisplayVersion, version_x, 0, 4); + + if (capsule_left > 0u) + { + UI_DrawLineBuffer(gFrameBuffer, 0, 35, capsule_left - 1u, 35, 1); + } + gFrameBuffer[4][capsule_left] ^= 0x7F; + for (uint8_t x = capsule_left + 1u; x < capsule_right; x++) { gFrameBuffer[4][x] ^= 0xFF; gFrameBuffer[3][x] ^= 0x80; } - gFrameBuffer[4][108] ^= 0x7F; - UI_DrawLineBuffer(gFrameBuffer, 109, 35, 127, 35, 1); + gFrameBuffer[4][capsule_right] ^= 0x7F; + if (capsule_right < LCD_WIDTH - 1u) + { + UI_DrawLineBuffer(gFrameBuffer, capsule_right + 1u, 35, LCD_WIDTH - 1u, 35, 1); + } /* #ifdef ENABLE_FEAT_F4HWN_MEM diff --git a/App/version.c b/App/version.c index 5b854a05..31ef85af 100644 --- a/App/version.c +++ b/App/version.c @@ -6,11 +6,12 @@ #endif #ifdef ENABLE_FEAT_F4HWN - const char Version[] = AUTHOR_STRING_2 " " VERSION_STRING_2; - const char Edition[] = EDITION_STRING; - const char BuildDate[] = __DATE__; - const char BuildTime[] = __TIME__; - const char BuildCommit[] = BUILD_COMMIT; + const char Version[] = AUTHOR_STRING_2 " " VERSION_STRING_2; + const char DisplayVersion[] = AUTHOR_STRING_2 " " DISPLAY_VERSION_STRING_2; + const char Edition[] = EDITION_STRING; + const char BuildDate[] = __DATE__; + const char BuildTime[] = __TIME__; + const char BuildCommit[] = BUILD_COMMIT; #else const char Version[] = AUTHOR_STRING VER; #endif diff --git a/App/version.h b/App/version.h index 80467895..7b2a55c1 100644 --- a/App/version.h +++ b/App/version.h @@ -23,6 +23,7 @@ extern const char UART_Version[]; #endif #ifdef ENABLE_FEAT_F4HWN +extern const char DisplayVersion[]; extern const char Edition[]; extern const char BuildDate[]; extern const char BuildTime[]; diff --git a/CMakeLists.txt b/CMakeLists.txt index eb6ad2ed..0c13acd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ message("Build type: " ${CMAKE_BUILD_TYPE}) enable_language(C ASM) +option(DEV "Prepare the rolling Fusion development firmware" OFF) + find_package(Git QUIET) set(BUILD_COMMIT "unknown") if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") @@ -71,7 +73,17 @@ else() set(EXE_NAME "firmware") endif() +if(DEV) + if(NOT "${TARGET}" STREQUAL "f4hwn.fusion") + message(FATAL_ERROR "DEV is only supported for the Fusion target") + endif() + set(DISPLAY_VERSION_STRING_2 "${VERSION_STRING_2} Dev") +else() + set(DISPLAY_VERSION_STRING_2 "${VERSION_STRING_2}") +endif() + message("EXE_NAME = " ${EXE_NAME}) +message("Development build = " ${DEV}) add_executable(${EXE_NAME}) @@ -110,6 +122,17 @@ add_custom_command( COMMENT "Generating .bin file" ) +if(DEV) + add_custom_command( + TARGET ${EXE_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.bin" + "${CMAKE_SOURCE_DIR}/archive/f4hwn.fusion.development.bin" + COMMENT "Preparing archive/f4hwn.fusion.development.bin" + ) +endif() + # Generate .hex file add_custom_command( TARGET ${EXE_NAME} diff --git a/CMakePresets.json b/CMakePresets.json index 960fed01..fe155522 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -9,6 +9,7 @@ "toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", + "DEV": false, "ENABLE_LTO": false, "ENABLE_FMRADIO": false, "ENABLE_UART": true, @@ -81,7 +82,7 @@ "ENABLE_UART_RW_BK_REGS": false, "ENABLE_SWD": false, "VERSION_STRING_1": "v0.22", - "VERSION_STRING_2": "v5.7.0" + "VERSION_STRING_2": "v5.7.1" } }, { diff --git a/README.md b/README.md index 0d74699d..27a419a9 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,17 @@ Examples: ./compile-with-docker.sh Fusion -DSQL_TONE=600 ``` +To prepare the rolling development firmware: + +```bash +./compile-with-docker.sh Fusion -DDEV=ON +``` + +This keeps the regular build output in `build/Fusion` and also updates +`archive/f4hwn.fusion.development.bin`. The development build is identified as +`DEV` in the firmware information screen. Publishing the updated archive file +remains an explicit Git operation. + ### Notes - The first run may take a few minutes while Docker builds the base image. diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin new file mode 100755 index 0000000000000000000000000000000000000000..4c61f8956f46838a854aa7e83bddc6b82f8b32c9 GIT binary patch literal 104208 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

sqW6I@x99rek$*P=+4yGL>W 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 Q@k}4L8Ay_$<|`;~Hv{dM9@?kasIsNjE6z z*D(dw%j_6uJkC$jWv&tuS}iAlZX6TRW71t8*;m>wCX{Fj*v~@BAeZ|h_+m*#0ej#6 zGxqZTr@c3ikFvV=$3M^PnGD$jlZE7&nFO-1Ocp{27-mUAlF3FE44Y02!C+Vh!ZJu; z202gw`sApm6ld-uUqX5)?OC92Jy=%f{j+3Y$U(;=b40Sy}#e<_t)>g z-;;dioadbLob_||&+;&KX$n)aJ%fIY_t7DK*W+D&=$Du+4(pE?StdcEI}UuN$*xDs z0Yj~zy-e((p61oS6J3ySkn5H7hUre^ExX>6ksWh3GED^?Jla=`G#3-iNHBFM4ZBxR zxu31QDCB+IlQE6X)?eINzH50#_JscxS|f!%hSi$mqEO(SamMdk?pzb626m zK7$^He2S~VcLwJ|cG61ei~quSs>Vr4DEyUS`QcDqPP}-#V?%oSQjJs5%zLUUKoN5X;1>C;cgqW%E42JIdM-F zW+Wa1Yx*mtwF!@?f z#5ihF9Nb3_G(K1PKx6miSohz0wrdXX$+s!W)!KC8vU7Pvh6;O)RGj<#;__*|v+1eJ zGK_thI2Fqy(1Bhykbu)QA-^Abx*-YtvS7?k0I#jz0PN}q4}ky~-%tI>^_1lLG)hgw zkSYsP93BbIL#s2DT8@NK{g5rXTf$nSZ&&3C17oe!{|8z6B)9nP0oF{qy+TOmR(}NJ zQI64U04_e(AAA}+r+ma20}RbEE;rC)=P%0-uQ0G|v8$kkVA*0E#~qT)yEPRbLpu%A zo-s8=M|pp+60<|%C}uVEBh65I)mDi%Lf)5;dk?emvqoj!cF2w{lV~|;>t_( zVRLVf0;4WLqr}{b#6|q|=L31}3<`ypAEf=6&?v#}{q11NY{j&Ki01A}81JLNrc1UIE+c)|$q*{^x+~+1o8rBq}hR~`)b{6f0 zQORrk;PVLVf=57)J`#)`IbAj%xc@uADDZ#$4v6vmMF8)&d9CuNxX>EsukXMAejXmp z8<6P)_ty~S4Z!&PcM9Q{MuPVre2<-szTw3h=}m;;br8>&3Wu^hvAxc&sPyXfP77Id zpbbFSH8p>+&M^}y`Ci+ra42v`kF`7Ot_2(6zZozkgYS8cqoike+VnBccuGb z4wHiW+gO@?Qd6bvN$<8KY4nS2i02XNA<$0UJ#=iVbNy1=vGtsH4&M)+jHxt*BCA!P z)Vzvw3CIP?l=&ku-hAE@XWC|05|$%Hyw5vCVhVROI2nTSvz%>KS7d;MsSa#jqu ztNTy=5pe}i7CDNlh5a+P(oE1MA6CwK($?<}o?7kBc7Lwc6kx1hlw4jg&(%Xcbm?Zg>*n~XGo8T@s zxgaIQzc;{b&SmB{;d>ewg-#LH<*J@bbW~+#B4`01ld_OL}2%5?nJSEO>Z;ZG=)7*QI`RV|CK6LcQ|_QfC{^*tu< zQ5R09J{}Dgji?P@1;OoTlFw;be{4PPevaZ^UzV-^`0YtydaI>n{md*#fDuzG7biz8 z+G)FX;SscqR=?l&#m90Z&YVWxHnI-tL~n0kTlN>9ygkX9cqx#Rb?%dRaLfvGP2T?C zF`O#RLbyoW%j3k}ca$KFefo>5vYCCRpQo5iw@Wz=>|7eB{&BY7YPOtby0k?E`lfT6t4z%3@>-w z1|H&=?xgnR6%FJL^UuYbgTbUpIrKn_YlHQ5S12lA;4 zYw}!tI!wT7>Z={7!3lbY>uc!Rt*Xkv4UWdAIIGC8`Et)vMuV>dcR4w@tD)>9e<^5d z_*A*1T!vm=WRYP6p9@+W*7rLayaOp6LP}FcZ>i1zMaWXDyB^|u7Vp==_Q9`%&4V0^ z+@CM)1x}$YsBgu<>kzINjaUYud!jk13JiL6NL zGPw@pycj*!Vsbs_dcgJ%pTab;oLgzq=tDT~GP-hI`)zxC?*^igLt$=QHhmIj$`DT{ zejWUL@CmdZ>kY*Q6@;9SLx{F>!Q?i46>ZA>h1-?;61TAd?aF;A2uT_Wb-V*>*hrZr zGDC5W!eSgk;c4Mby^ubGp0QBcJ|VIe`jbQ%B`k{oA5av#sY@E0?7YX2=+;`8e>(yvSK*byoM>mFTQEhD z-jWDiN}5VNF{P#ocWK{@sE|v2BJ0_WLb{ws&g*p4r5O-)@_H~5ns3AXL%}?pwP<{i z=wpd4ts?@nsum}WQKyE3e;J^RLHLBIO4tXpt?L`))rG{1)nyio_D7uwx&E`Wl9m|(;kl(+e>jL(qQ>Y z^1auCuMbkjB>#O9eOjz^3Kr|yRka&hw<7$o;S75en060LhS1q}qLZcV;Esjw2%%>O z_i>PfPkRN}9HWZ8%ri-8%Dqv*ULADvD2F!Hq|l!JH|Z?Va{FzsDduyd3wiOlL{c!~EcdhlXL+h{>9-mH0jCTZDRy&3+1c zZGZ`qKO_sha3DDf63~{~V(o%K?gG8yNVP+KLhhBBcDb^(%JoXan{fRbw0=OJ##G(& zmoy(PGg6i%);iag;2SSjawp4|3p0eBz&#Yk);6Pt zgC)-^<+{K-?W|w*!r5f4DU|M0IL)PO6Y%WR4IzEHL;a%OnTFd>@U!1w4rHYv)4{l( z>G*}~v_8!tt~Yt*+Dk63Q}0MxIdJ@j*2EmXCggX^2$wnDm+DYGuikGlDGjk3)W}=M zNK{oqh1gDg^G38L)$^hgr{wF|=e7~>L>yweM8?PPF??ivVZ33y9LIIW`$D|`$CJrB z_X{Kxz#c)MJ#7O01nkcajE*i>5n0y>n&+ETDiR@~2mMp;Qlt0jK?$1ZRXJq2k_}Yy zryv1z7c$N|jqgF+J7IbO!IP6x%%HuW0owanK4HqP>KV|^qdcq4m~z(ali^l8t9L@i zp#N%cWCU6e!G{q64QYwpUD#EJ`MMm<+l0v#^lrTsATwMK-ZFGO7=A+#ucNF49-^JN z)8)adkybt$akc-t+vd_yM>(tE2>sFZmn2RY4SR@9ra=b zy1p!TiTwdR%XK8k4iR_i=^ogeFb|kz-Ing7J9}Zj*G%r0jp9ZBe~ag&~oz;wbq0rLpVU%~8!`5gOi*3(NcW86;IUf>WgdpHElXJI=T{i3fR|Mc zIcA5e!G~|eV$4+<7r>3c*IFj+(!L7*apc>;9eYfBVicLwUY2OT4ql#1dyekmRPHKM z?KgE9s9}9;mocZI^H^8x`b%B0ogHO&YzKwQ7UT8_FMuj#yB5EBrq8x_lz?N$WZc2# zbkiM@d29#I$l1obN+5O9^qJ(=>XAMF;g+eDkgBufuCo2Rj(Wlo!(C;UJhAt+CZG4r zFmVjWV4Ee`3h)~Rs!v(pqW)4-ds#;b_nx~3+RLs37bZIHD$Ah7+vKM2gWuoaunE{k ze;-_ZLvD<6O!kJO#NiGZYT>J3`N&p`N!&i%wm;f2N`j@bDOi?AjSnAOXMWx z$#7b$@C)VxHk?mDs}>|yK-Ztv0oe$kMg+CKD-3gg$Yi?&&QXbyjcGnd5HAQ)#38^S zU;xk$coFa%fWY?+3SpNTUjm#AeHiiT<%!Pmz2Y+n_cY)L;0eG1Kv;#gG7NnYTS)N{ za7C$c_k+8mvnuebLf1HMB@SDgZLS5J?!AEVd_;jqdo;~tv0K#TTCLq~v@EgM?BP0- zrNLsihea&5l!JQobQzD$>XS_G96AXCqfs7m_%9;C_r z&@i?Z%lAEQNQJ(i#BP>(r#v?q`p8FcE#aCS#(FCWWBIc; zCW5Lmrk%MG^!i;r)FY$ixsex^=OyDTGXvjeq=jML2h}{ISY!(uI z(vo4BhSfoGRkN^^l9qaJ>eYPO>g|b1G+FlbOsq0_Ct@ZfW4uET`X;`)4R@Uft-~j0 zVjZ#2QjwIf6jA}M1YSftar-l_G0u(S!H@BgaqCsU_keE!eSq%(jB7-YW^z)7lpyB` zyR`e@7R9u~mC4=sbtkzG+4PWb8C7XYeusXF8o{cQc_zVUqVtDz+J^gem}MaW&(CX) zBUn+(B-@8$@%<1_InUfjxUUGH-jtIjeTkTpmXed`uCruOS&s!WSfHKaywf5S;XE0u zBbH3{PjFmDo&2+h(vD}P_-$Q6SBy++-`N$Wh_?T^D@LWY?C-7UGhL+&cy zZV%)!jAHd`TW0+nC+AV8`oN?4*sICl`2u|)D6%?wDWly-QwkjUG`YRNaZT?vtqHq8 zSWE7w>2;9&^HNVAAJ&DC1W@H?+bdXgPeq?9+Lj1OZBrZ* z4kooj2U;S_F?_&QbS4T~!*#D5w8fv(9aQa)IIMhG`N-Bixt;3$+qRjhv-9`cg#2G& zy;zIe`~-viFyyg61&ITYB*`)$AP2x_nf6o)@NEO zH#x<2(WrgyYVd;*Emn=SsFftYsXb8{2Ab-m@OmK$R}|kF>*f1xQ_uWQ=-)`83lUo3 z$LbS`lhD(#2NaFSB<@qPN8yT@K8I3q+nF}{ozc`@FBkJz&Tc5(m{(n=*!K4T<2jdc z0?y=O+!Gx7tXQyz+j3*v`m6}p?2;`Ewi3yv@Qvo_J^DgkMe}%`nH-|^kX6bhiU{T$ z=KiI}84}Z0e+ZiFiRIYO+?a^7Y0yI4h?h+JjX24ie!+Q^={%u#AEUQke7`I>|I(t;_3X9-E-tMVb@1op@~83-~GEegKb8JZ8C0 zW;(iGg|IB_uYLl&)A;Wy)0pFX$4;+C0s zCD7nX`hlBb%#CIGomdd>m{y)n0(g4&4aJGk;77o`1RwN@ypXgl7I&S3AqR6lxc?xjSvYt<&iNI%s{?z~ z44F@J=x5*z()=7JhmWb~JCitTsr*UXKhV=@h8cRjQ=PKI#!4~o1>2M}v7mZ>5prOK zCxuz54o?5q7#He#>YPFR6{?8RM>;(6S*KGv|aA33YHY3Tl)51>A0;xy_v zLle-q8NWXYq&WW`;PIJplIwK5-nd?QZsxVbalmfCcz@@*V?63RnTj(|J~NB(K_k)# z_^+yP^5IJcB{j{&DF)V$qc~xP{4Jyh{2cBmn^^g2XQKCy}xs*2D)SO?ka09iv_)-|At`XRoZB9(U1>#@Z=VK;L^RWH?@a;DRLgH?anE!^j~x zK=-lE`B?W0Hno2e=HcJteh!*tyMG0qv(aD|PFDp`#gI{Ucry6wQk{{YA;yZqD?c;} z9WjD0GvDN94Hu(Eos|3ILtG!GRsV@Ha6R)nhRgE*)GuXoenpC%Wo^SNT*h451$drYilT z#(NziWRdJf?sivAMcXC#c2#G%FPcZqJa&dbmIG64WV_U$8VXTs{C<%2gDY{~AsFw* zci||}R#3dN)X*^8Lr&}6Qf}#$p*PeFQ%1T^W01YjS(&sg#vKlB8OlobuSX4@S4Dz{ zk@W7C6p6 zOjQLbjVOJguLShQ*jV`12F4`M_*cP})UCn}Z$7BNuoCq<1F_!Q0~C$609H<4tIEJhZ0g827*_H8E-i}k2^dL@fd_j z7IV}D$dHX;Y z#=LXC@4XTX4BVcQ^U{-Yn*OQJSxwWp@4PZ_73V{JK|k&TvRxm7I`A3TmW)x#e&=hh zTr5e)WIFAG1C3+z+*Qa!LVX198+;E`-g;o(e@d8l9ii?U;5%iU?)$C=_ug=ne+9R@ z2P-8E`SqA~(4YH5n)>9v1yb0b`7D)X=)qx_8!h0n^Y&oRa4y#S1T?5|TnBtn-v0y* zcaqIUXWcU{o^gnf$%)CFXmfl&ze9sPo&c|ILjN~T9xQj~v1z#yH) zlJE9_AV#^eE8{=|80m|3Wr2%7)|CoQI;?N|aXW|B(E}y|Dgsfi>r6lHFOlR;Sy7(2 z0fc3_Bxjk{CeBqpCJ#b}8dVLL5kfwI-3rd*=1Jd7gLPWH$3-YeBxj86j{ z#U7)9?kT6oz7O_GS|knRmEOKV+wZ@@5|lwDIKX2Y-^qmNH_!V*TsU*Ug+pnRyLrrb z(sudGr5;FX#ad}$KV^LC>vU+q{r^?shUz3?$>M8z*}mtub+jw@VI8nPd(Wyp^8MM{ z)@{RFgIPl`eMWNJ2MhZZhC6X*b9dhNpu15`d&B2+2>G1C(>-koFZEoYchNe`chGD( z5D=!MSQIZLZeHd%XuI9NtU`9+N^t6c?7#$Qytx8BS*+*nR!|l~2j0LUoc|@ZD-L6H zOxy{f6RwsZQn&~t?>rtQhK6nkf>S>0>r-eMCXv6o=!C6^;spk{IoHpxP z5ADw)GTjdM!-G7&3E9Qq*)aR;mFk($`8@Uabg)@-g8CjG^&sXQb3g0p0F~mra>5zQ z=|RnjE5UybD3MlJVg+^NWU*eF{TigYaj-j}J#jr4H;gqBWPCmA{~6wMiF2@bV0!tf zK-f&xxgwfY5mux@&TRu91d1rLq92r?asJ0mhY1`cPpvSlEHTrS;PHO5L|t_S^o?`L z06HfACS%~&fq4cw>gch4`GJR^C+!L}r{@uCivBtynBf=B?#k z2d#Lk_}(Z76U2c9Y3<(yx{!wYq>T2vg%fgD!`A4nNwRSJQsvSKcJGI7xiQva$Emz* zi1!nxdm>IbO?@YiSN-JGba%Ez#Auy$(SqOBi)wWAMdrfH@rwbP1<&-PH?`=E`{^(JUR(UKYN|2jL~zgIeAnB+@rKk7`{ zYHGobr#CWF?SDXW4~P3w_u=8KHl@9Y-OPC_`euZ20Z1**NFLcWM9`Xrsr-D)Sgq!+QL*E9N>wDR# z3Npv(z>!AGBjRU`(4;v!82sh%1A*I2qj{H>QTFpbu8pZ%!!wSfK0Y2%J3?X|g;htLEx0v327R9Q1TOT9PQfnQgmOPFL;j&BB3tR#h_ZvwaycSDTqTuQff7&f zap|rFzH+~eb?|SHR_NB~Uw+wR-voYxvx?ArsLVed3`k}E3>xD?r8|NZ0Qu(xR=UAC zG9$_-p8-x`=;Jg86fb-_c@7qSe;z#6UIdxZ$J%dmrME-{TJZ(iuJ55iE%e%&T9N{7 z-86jwF1HVU9gv$Cm(u+a4oGr9DN*B)1*z>_-cHl?zQxJ!cpd@&7IcVKYAQ}FIBh>2 zIed9H&OqJ3XBXh24EL%qABEdb0ZHwUstC@IFD_>}a5mi@13|qX`JO~<^0C;?`jXHe zLg!r3z83eAt&i9y`;T@ja389K{J!@tC!%f--`{ij5U}v@o|i8tjNxUA`w+sa5mt?G zzq!o#d${|l%aM-Bh<`liU!fF&e|r0MaAfEzbrlB|PzGw*B$)M4J)kAz{BwCW{-7MV-!-T(uf$>x$##~tI|26DCox_?&*;lWO4EQ|;)#0UB{g_Z z(fWNRtWzLspf7d6Ag$T2-&lCLZ2w7Pl>i--I5g`U8upq#>t2errRto??ExRY z7jYgK=syKIq?*s1&p3@O;--6SDqqMq2j6TNJrnhFafeyGlS zM7gC5X}zak;&d(GRNv88ItRwmL;Lq7^n-gkOAE;bUT9A_jgxe6i{!{%58y0w!0%ch zE+dN|Ny~OE@FITP2oRt9K!%Q}#=ZQ3PQ5E}gR1DzhUN{t<|Tv&U4tK|r#K_myQDAR zc0|fs@TA9>OmUFV8soPZtdIg91rfBd6n*czdC`!%E12FlXXQ-Gl|zOk)_;%_=QhUL z?(#3~d7`YaGS2kawpRO>J;Ec8b}n$2b-PonwsLD**-Xd?dQVT&GcP35+xb(x&$@)P z_w!CeYFE_eh8-qbtZ%QWVY6mN^f?*sI0W;@^lMuLBHUDk^iL_~?-BFYQq13CWn{5Eh_>LmX=h<0Tz9Bp5AJhh zmV?_YpqD??Nf}WWAVtxyX4xt(r%~S}vnOtp_lm~m9Wwip&Cm(fiB`$_+81SP-VT>d z*AXYjwG;7ruvYzHT+xV2;a7->U67@`QQhklm+ZI)u`JmkntvGEHJ@2rvK>B~EMu{L z6W};KCP*-4~HIIGUCZKJRHOeY2{LZv#)jV@Epg+%BXSV_7%T2F@u_ zIDD+rVw>6<-P+Llcq?Vt{nM&vx(9oNnI@kccPf-M5%J3XN^+9;m@DBJ~iKel|9C@tDZtmx%G>G)ypjNpp|fVRw>gm-9_0B-%he+pNb0 z&A?;Wr!4S-F1_BSbt!TyU59e-cTFsM&vpNL$NKQ~tm&}xq}{EfiKN_W$Ts+lxHl5B zGyQ+wx@&8UEUcX=0;unB|0>+Dv+R4&%bt46y~~{@OSTJB4A|}DSO$XWqb(Y?v83{A zfl%1Da2KOaTUBO6@7UI#@4P7WvQGnMoXrb!jwCnpnA-RXdNLf$mSJa9FW;gA%A`BW$dzT1Khl&T5UE0Ug$dd3#!2WfR* zcE7etJLaOq{_a=w6?7g81z!ioZQlmcaM#0-F=j%>8rBG`Rh7WSfVl^A0&om@36%rm zBG!ec%le@!?5Q%>f*;ynk{2ppm%XldUB>2rC}r~36*9QVK@$|bNNRpnFFEUG3dC#tHw70$J{!lU+9c-7tt z&)QqzT~UGn6${EK1#x_geewjDqu5X5#6qJ1u&xsl2(&;j!)_spxf_gl-;w3Mg#s0T z!;am?0h#;ZgU?6?!0{1*9OwV_`EhuVlaU&L^(=+4nQSg;UhO4KlwLHKw?F>&=(>(O z@2Fc)G|f6YebVReo%}harB5*!rxwkff19&w+xFW*qe(NSP0z@*%v_dzOO|O~@zUix za;W8w)?8ZAwla_IY+sd6cXh0uMQhfsD&y*rRQy$k#3%a4;t+a4OC(Wq?_~BrMJRs1*MDm zE5!6pYDix}*@$=rm8EaW<{zppE2Gk8vXxq^#l|tSzM1NBs7`8U(PnLIEUjNm4XtbI z*WO9Rh^DE*M#aUHJ|n*qKUtkK(r4tsW**N(Ix@3~(pMl$xtkoYIHA`iO$qzoT2WF;HP(8DY^upd6_Bl|VKE`&BG8i>o5hlf2CJ>Alo~6lOKY1N z$y#Ntuck${RgI#AwpOgY(3+G}#QENom18!q=|s$q3No9`GtFjdXsR!rFXhRAT<1!; z&X&r#!Zu#gj`F)vHKp~G-lowl zsuC1RYK%o<`lj@BuF6_8X<3!Ep&Tw~EjTvR0|jor)t6dJwAI#{CTrErkF`>(woAEL zLltW~SFLE%mWfsCT069Lt6SDmS@l?xGVV%^JAFFU)Yg=SlG0XTjA*2~+FMacj1i4! z$3?Zx_)e_1mQ>VI&g@xc)C}Xf7I)lH41RPVNi64FX7T#phjD%Aqp8%lv6z;>!f&TAJClDWOQw5Cb2G}TE) zNiC|6J*3XXmWIXzk?d8a)*5LrwAI!&G$MD+D13c2 zYOu_TccAlP1hO_XRM_4dpaX z%r&pUcrj}Y<<5d_7SNTdO3NCx^<2T)rbW{oIn-3A<#I@GvoZ=ZDW?G8tnH#>7UkyN zwC3^GA=jMzF>4OT8*5Ro}M#1UyE<2 z=g&4%ncXgyTdTD>`T5gx@(Z>3xp1Fl2A2Q3bKaP9=?|O>wE66uZ>9ydA2=hDG3S3v zEYD2;{$5CR)%9Y2egQ40u5Zwm0jitoF%*Wnzt(zl5S6UJCaSMpz_?gq2hJ_1m433( zaEM9#uRg2YPAcSDr!oAB=&M^O-*T)wx+4t zhNx?-)jT{^muj<-q0)sC&T1u`EkT=#_08J)(uTTPw6eXvwxL05v%)GNc4M=4EC|)i zv?6b}LdpmKh6ZM71{S3$Se!)-Et}isV~}oHE0(paTHS^renZ>(qUqD8&j6qsHm+OS z#;+ku4c?@0ibCO}@nL-az$l0z0sRp3NRc#;V5Dkm+0fc9a-`#Sjxm&?ecc+@>b8w- z(g?-F1COH8fP>*1y`rHMLvEGGI8V2hR@rM&C$@^xnnmb$r5LBg(iN*Vu3ER28mx;j z%$Af^&8O<=JW*hDOYfYXzM`6{>oe@-9CaoS12^qfDOg52oTY&llU-<-&FLg-MLpW9 zZgEC^$>PkLZ#OL&_UbwwNXJHHX@cQNOq?#VfnsjlxN7a4om6jMBo#_3QF^*qTEx>> zP00@(kvfLr{LT)l#uPRalbN*$1>*^LlRH!!vo?vIv1;j{h9XfKO~na3WR5QoUa9S>6VlC5D5F9lFcm$ZNKVG59!N1o6uKBgOG}F(MhDB9t!rTEDl6rutZNFwR^)nUGoBrxXpH2s z;2BRaEG$fgr1+Nu=PJWu6O3t@+0)Fq1%>k#lvh+b>KkGy9y_=Mkg2AS2{cccI3}1z zv!Iux2$B=#Q5BZ$HIS0gM2oQ>SVpbXMt9K~T1y*f6QnkE(Yu z!g=9i;gWDw5E7G9L}S{NshQJro|2uE{Z00TOeUW!pCex+-vq_Kzm|U>|3V(FFe{oA zU5cj_A1DSCQe_-%)5+;=;#Pi%9M%-MU;jV3RdW> zSIASMBW0A+l$fBa61Q{hxOipDCi_yiT>Jld^Qk1%^lvG(VO{OSu za;h#SIyEXKA|*wZtc%eVbI9UknJg|vD@%=ufR8>RB{>Bjt1?m&Qzj~sqA7`@lduC7 zVkX59-F6!hcyRC^SByWJ(c$SRqSidUZe^?4QQc&$!_JDgR>{S!Rxs_f7AIrpot&IS zdi{HF7MnHsV;!sQ=o#orCO^q;b>)7Tg z-r-3~^6cASTGf$m zcci+tbKAN*TZxmy7F?l;auTBSkS;?s3*A^n^tl2qD4FAc|5CEcNG?Ptwyo= z*W;PDW6`49bX+<}=eaEuMyKm?6WxtXwb|+1ehZ@4&)cz*=6fteU0r&87ak4+$CW$g z?buOJfN`<7V8;$8yX&b6@oX07BP}P*>vB4~=IQ3ST=?lSo4e+ftS&5EU7}js-oB%F z<>no0SCXc93u>Oo!#~z7#TwG7bb1|LfHFWD{EgwvlnPHpF15yL6nC`zJI-+1q1Avg zA)L`@iZN1;;fw|kJQ!yzVw6T9d5aX=5va)_2?ZB8Dwu1-riUKJ`BM<)8V#&qI zBXXEf%;^?+IEV1WKSY6A=L>>IgQ4CcjpG)NOrel@@T-aPgmNx@t17lGY(Z>cJiCOZ z0emM2G@nQR`RYQ8rBFTJVm4dmV_Lx^rPjDKYHC?nQEJDWgrvrChLAETFc2t+KgHA$ z!kNa#MmKp%N=gc;5WgAHuZIfZUQS&Yn`G1s`#kbsTm#Br9ss6UEI584PgDlZagZ0_ z3`STtemM-sQ%GH?FrFLZ;<_yC4m;uzX+C@{G!HqLM>?~`tb^SQdr1bzrmL%~gMCFK zwxF5<31vb!L)HQet*9Rb4Uded@QjQM&mZq_^D$^7kBp2UH;e=5d_aWcloSNJZ)Bv) z>2i0iy|cB&>C{C;+=mBlW|s@|Z40`n_jIqTFgXIBM@B~K@ZfX2{6%{1LpbhY9?$&# z;W0Pw|D+oc5rHHwkL&=>pcc@b@jEgymIlIw(wP50c@{9R;6aBc@7RMz8hbdB;bH!z z2@~)WnM#xzDZQiC`}_G{78%L^uKwF;)ts(|ON!eg4K- zi#k%H0Z`Pf?S6D_4azb@RY;r z=7VVf0YlGC$8n2}yEMGV^MaGiVKn}5Kj%dgsir8sR6f|@pifrpeygic7ZDx?UwtxA zWB9kK2q`2-fv{4=L`HUX!SAizC@sg**I$J$ORg(6M{dRvJ(hCm{7y3i#MRJ=(Mh=Ja!bL@{rJ6|AOF4^B4WnLA_3Ve7Ng)*qDWpbo z^9`{`HMo2C69>jhG(3!a4G)i{fc8T~2*mZtf%%nd5LG=q+>6;0aY`i`L#vx9=v}DY zoB2fPLT^H3^Xv`_jD+qXg`GMJuTH)r22F( z-kege(&!Y@+jxm0r8oXg8u3N3e>g1-u}ZZT^6ORCmY0`%=HHAH39`3%^(rSl-hR@% z*=4bCNXAKVto@{>y&1B%SHvH3M)-@wTPUAWoT2o_%Ag+e^YHvLR)*eQseB$!Z?6*{ zA_b0@r0+yg!$pWxi6Z9|&QjRkUf9OIhXkiH|0-kfKK(~Eof4F6^7p5!|0JI$ zUqLhEEz~bdfM7ipZRX2|vBv_x>GIp@bJ;w4Qx;Fp%ak|$OW{`pzprJv^aj3N4Zr5G zZ#mBCi1T~6|Kmq-E`VPyzWY)(oBjy@C-B|6vG3%3Ns(bLoR3n+q5NMUY#i#~J3$Nc zX<-E*o@BV&$e<`)AISf|6Wj==ps>A^8@BhkJeUP#_x2U7yq9hv`QC$Y%OT~MiTASZ z(}fAK6T(!AxJa!=rN9v`;c!$shS% z5HJybN1h1n+mFNKu)l=K#rX|Po_NmTeu#VMAMpTa$!PN-Ox~P*3R4U7 zE12OhzlX`w(Z66~K%gO*jOpi|#N8E4CCq4;(J*6SPK1dy9wowzhnWtO^Opy663jxF zyf2v#vm8(hXa=+Zw1B$+oq(+X4`4T758z?Ie!xM%lYplI&jDTrJdd)y2J=n8`+#E9 z$tN%`0kUwf#$m1iz6JCHZUAIY37V_$`xcx9`3;JBG) zmFZMnc;5_o81O9M4}gyVR{_HS9m2!`jDQ&c*15^~;W%!AX&V}MrxuLIrz{2jpGygqg($aTx_5qM8Wc^`!N1;Ts{ z_zo}#Ah>fqi-6pQjcqQplTf#AOWOu4X6oI1zeVzTH{W)VqA~QYYz)1t8r`)et2U4t z=E{|wq`7rw4L&EWZByq~dliNAY314#Bv!9m(FS*OV>91ikj~y-wW@O?CE45gFqJ0Q z+e_MTJr`kbuW4D+Mv)DzlE1N`wQj>IA`^b??KzYtnYonCH)ObcNhr%{Xy34r%F1%8 z*5Sr%L0PW!US5_fy;oF=l3D3!+ggQm6C2%)wVO6ln5|_a5~gUFjqZ&!vwBr4=Q{aid7_Fk7&sp9pt%y_@1}ZBo7I>(|}M z^)|f$*CKe5>+3|ePR#b)MHiXW{Prg!y%Tgr99Lt3QVP3zgu18K)4!&v)8wEB3T0crSyO_oK^z= zHUM@2Jl5sQmt(heSLDWsGp}y^@~qoxS0UFHO;Zz5J&~E_ZJ+ z-cW4ZxDhlc!IyV(fX0#8#_TK4Kl|YAIZeNu|G~Ryd7g%cj*TZrcm4LgBWu*}rJnh5 zMt*W^)tdoirKq?`G$s8mT$eW9~2)hVSEMN{3V38@)5Q{Pm6Qd$chBp;N zCn$HxHKYy0Y$@X@Os$m3ENtv#Lm>}SXytX%!K{^%Z`wq%6K;V>#4qkPsg@?nb5Y7% z{NYB9@+cq2yEy79R1_+9%ll;=fPR@*rXeq%2GVIus&)pA%A!GrpJFAV4**0_KLcuy z#?~L;7oK4+E_~xe>6FjuY;s*u?-itgZ$aMid&qnQ!~yz$2RaVGX~5HfZoq25Mt~f= zm#D*E2o%x1wj1@g_aA%lOM4~15@Zi80+o_d-TwsgY4GymxStum+%g!a=sx-h`@KEx zmw}uRh*!An?j>+%5Pd%GCt`uaE!&RY-E=Se5%MWVRS{&0;jLL}`(3n~{gTK1aB_>+ zI`|UZL%Z0oaNG|&X}p$8xU-Y)VZX+4zfeV4nCu1R*a@!gA7O}j_AT}WZ|}u(IRzZ)jy~#cB9w3SI}l6~^n}t(|M`Y+2e=TQNT;Gu?zk zHO!;DHsCdae;R3y1DNiHFPV@%AvQMl=;>cP^K{zI)R~r7u=~Z`&0iM?np2IWsa`~y zmzqfv-xRvP`3UcGZY9lsbd%;fpluInzCk$t=G0=+Tm#HnLYnOe{}JE@;1G)l1mJwOCx1M&cK026|wnXE$^30PCi7c^g%2%2;Efd&Z$-3iFd53ND}lowi) z!s+JYM;pWfleqo=!FHuuvY%%=D2Ldc>x@^v$O(B1Vd}iP$Kk#M?jLY{BG7jTe+}?0 ae-|4%1A<9P{%$M|IfwoKpZ`y5;Qs=RE*QT6 literal 0 HcmV?d00001 diff --git a/compile-with-docker.sh b/compile-with-docker.sh index 3dfd0b1f..aca105a6 100755 --- a/compile-with-docker.sh +++ b/compile-with-docker.sh @@ -8,6 +8,7 @@ set -euo pipefail # ./compile-with-docker.sh Custom # ./compile-with-docker.sh Bandscope -DENABLE_SPECTRUM=ON # ./compile-with-docker.sh Broadcast -DENABLE_FEAT_F4HWN_GAME=ON -DENABLE_NOAA=ON +# ./compile-with-docker.sh Fusion -DDEV=ON # ./compile-with-docker.sh All # Default preset: "Custom" # --------------------------------------------- From e1610bcc6fbb3809ff20bd3d6098c8a715928505 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Wed, 29 Jul 2026 23:23:30 +0200 Subject: [PATCH 07/42] Avoid fast scan RSSI and chevron overlap --- App/ui/main.c | 10 +++++----- archive/f4hwn.fusion.development.bin | Bin 104208 -> 104196 bytes 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/App/ui/main.c b/App/ui/main.c index 484111ce..293d8322 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -1593,11 +1593,6 @@ void UI_DisplayMain(void) #endif } -#if defined(ENABLE_FEAT_F4HWN_SCAN_FASTER) && defined(ENABLE_FEAT_F4HWN_SCAN_RSSI) - if (vfo_num == gEeprom.RX_VFO && gScanStateDir != SCAN_OFF && !FUNCTION_IsRx()) - UI_MAIN_DrawScanRssiSparkline(line); -#endif - if((gScanStateDir == SCAN_OFF || vfo_num != gEeprom.RX_VFO) && TX_freq_check(frequency) != 0 && gEeprom.VfoInfo[vfo_num].TX_LOCK == true) { if (!FUNCTION_IsRx() || RxOnVfofrequency != frequency) @@ -2257,6 +2252,11 @@ void UI_DisplayMain(void) #endif } +#if defined(ENABLE_FEAT_F4HWN_SCAN_FASTER) && defined(ENABLE_FEAT_F4HWN_SCAN_RSSI) + if (gScanStateDir != SCAN_OFF && !FUNCTION_IsRx()) + UI_MAIN_DrawScanRssiSparkline(isMainOnly() ? 0 : (uint8_t)(gEeprom.RX_VFO * 4u)); +#endif + #ifdef ENABLE_AGC_SHOW_DATA center_line = CENTER_LINE_IN_USE; UI_MAIN_PrintAGC(false); diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 4c61f8956f46838a854aa7e83bddc6b82f8b32c9..54cce14f90b10ddc2453d3e9bd50974db55f3a65 100755 GIT binary patch delta 14569 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�i1Vj@c^kkE;%*7CN^U;Qt!#d) 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 V()_KYi})Q6JAlr%&0DFC{vXT0z!m@i delta 14599 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 From 222448e1adc4fbc25e16f5a2c4b365eee218391e Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Thu, 30 Jul 2026 02:32:13 +0200 Subject: [PATCH 08/42] Avoid full-buffer channel attribute writes --- App/app/main.c | 2 +- App/app/menu.c | 6 ++--- App/settings.c | 68 ++++++++++++++++---------------------------------- App/settings.h | 2 +- 4 files changed, 26 insertions(+), 52 deletions(-) diff --git a/App/app/main.c b/App/app/main.c index a3a45362..84856c70 100644 --- a/App/app/main.c +++ b/App/app/main.c @@ -105,7 +105,7 @@ static void toggle_chan_scanlist(void) gTxVfo->SCANLIST_PARTICIPATION = scanlist; - SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, true, true); + SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true); } gVfoConfigureMode = VFO_CONFIGURE; diff --git a/App/app/menu.c b/App/app/menu.c index 1155455e..9bede201 100644 --- a/App/app/menu.c +++ b/App/app/menu.c @@ -725,7 +725,7 @@ void MENU_AcceptSetting(void) case MENU_LIST_CH: gTxVfo->SCANLIST_PARTICIPATION = gSubMenuSelection; - SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true); + SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true); gVfoConfigureMode = VFO_CONFIGURE; gFlagResetVfos = true; return; @@ -752,7 +752,7 @@ void MENU_AcceptSetting(void) case MENU_COMPAND: gTxVfo->Compander = gSubMenuSelection; - SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true); + SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true); gVfoConfigureMode = VFO_CONFIGURE; gFlagResetVfos = true; // gRequestSaveChannel = 1; @@ -864,7 +864,7 @@ void MENU_AcceptSetting(void) #endif case MENU_DEL_CH: - SETTINGS_UpdateChannel(gSubMenuSelection, NULL, false, false, true); + SETTINGS_UpdateChannel(gSubMenuSelection, NULL, false); gVfoConfigureMode = VFO_CONFIGURE_RELOAD; gFlagResetVfos = true; return; diff --git a/App/settings.c b/App/settings.c index 83fb8182..6cd43647 100644 --- a/App/settings.c +++ b/App/settings.c @@ -1210,7 +1210,7 @@ void SETTINGS_SaveChannel(uint16_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, PY25Q16_WriteBuffer(OffsetVFO, Buf, 0x10, false); - SETTINGS_UpdateChannel(Channel, pVFO, true, true, true); + SETTINGS_UpdateChannel(Channel, pVFO, true); if (IS_MR_CHANNEL(Channel)) { #ifndef ENABLE_KEEP_MEM_NAME @@ -1241,58 +1241,32 @@ void SETTINGS_SaveChannelName(uint16_t channel, const char * name) PY25Q16_WriteBuffer(0x004000 + offset, buf, 0x10, false); } -void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save) +void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep) { #ifdef ENABLE_NOAA - if (!IS_NOAA_CHANNEL(channel)) + if (IS_NOAA_CHANNEL(channel)) + return; #endif - { - ChannelAttributes_t state; - ChannelAttributes_t att = { - .band = 0x7, - .compander = 0, - .unused_1 = 0, - .unused_2 = 0, - .exclude = 0, - .scanlist = 0, - }; // default attributes - // 0x0D60 - PY25Q16_ReadBuffer(0x008000 + (channel * 2), &state, 2); + ChannelAttributes_t att = { + .band = 0x7, + .compander = 0, + .unused_1 = 0, + .unused_2 = 0, + .exclude = 0, + .scanlist = 0, + }; - if (keep) { - att.band = pVFO->Band; - att.compander = pVFO->Compander; - att.unused_1 = 0; - att.unused_2 = 0; - att.exclude = 0; - att.scanlist = pVFO->SCANLIST_PARTICIPATION; - if (check && state.__val == att.__val) - return; // no change in the attributes - } - - state.__val = att.__val; - -#ifndef ENABLE_FEAT_F4HWN - save = true; -#endif - if(save) - { - uint16_t buf[MR_CHANNELS_MAX + 24]; - PY25Q16_ReadBuffer(0x008000, buf, sizeof(buf)); - buf[channel] = state.__val; - PY25Q16_WriteBuffer(0x008000, buf, sizeof(buf), false); - } - - MR_SetChannelAttributes(channel, &att); - - if (IS_MR_CHANNEL(channel)) { // it's a memory channel - if (!keep) { - // clear/reset the channel name - SETTINGS_SaveChannelName(channel, ""); - } - } + if (keep) { + att.band = pVFO->Band; + att.compander = pVFO->Compander; + att.scanlist = pVFO->SCANLIST_PARTICIPATION; } + + MR_SetChannelAttributes(channel, &att); + + if (IS_MR_CHANNEL(channel) && !keep) + SETTINGS_SaveChannelName(channel, ""); } void SETTINGS_WriteBuildOptions(void) diff --git a/App/settings.h b/App/settings.h index 1f0153f9..f450a349 100644 --- a/App/settings.h +++ b/App/settings.h @@ -346,7 +346,7 @@ void SETTINGS_SaveSettings(void); void SETTINGS_SaveChannelName(uint16_t channel, const char * name); void SETTINGS_SaveChannel(uint16_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode); void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration); -void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save); +void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep); void SETTINGS_WriteBuildOptions(void); #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE void SETTINGS_WriteCurrentState(void); From c9da65117fbad677344de730b86e66ff12d1d6fa Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Thu, 30 Jul 2026 02:56:06 +0200 Subject: [PATCH 09/42] Avoid unnecessary flash sector erases --- App/driver/py25q16.c | 8 ++++++-- archive/f4hwn.fusion.development.bin | Bin 104196 -> 104068 bytes 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/App/driver/py25q16.c b/App/driver/py25q16.c index 11e5f737..3d9990a1 100644 --- a/App/driver/py25q16.c +++ b/App/driver/py25q16.c @@ -284,9 +284,13 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b if (0 != memcmp(pBuffer, (char *)SectorCache + SecOffset, SecSize)) { bool Erase = false; + const uint8_t *oldData = SectorCache + SecOffset; + const uint8_t *newData = (const uint8_t *)pBuffer; + for (uint32_t i = 0; i < SecSize; i++) { - if (0xff != SectorCache[SecOffset + i]) + // NOR flash programming can only change bits from 1 to 0. + if ((oldData[i] & newData[i]) != newData[i]) { Erase = true; break; @@ -491,4 +495,4 @@ void DMA1_Channel4_5_6_7_IRQHandler() TC_Flag = true; } -} \ No newline at end of file +} diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 54cce14f90b10ddc2453d3e9bd50974db55f3a65..242c0493eedbfd55735aae677b400ba713381791 100755 GIT binary patch delta 17062 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 delta 17190 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

UDcP)bz&e&OTEV9sjaRG=B_ObZlc8X0% zL%S;6r!Xy3^@|ysGpQbcYziDK6kNl+4e-uVN;r z%0Oivlt~`4OMHb>uNq~opBM?=KEkvWk239{$Cx&9!r$xt4B~kcnf8kfO#1+s{Q}e8 zK|ZBS%Os|~3FJ&>+UJq~4B!C<1BZ~-0$86R?UFU5-MO7 Date: Thu, 30 Jul 2026 19:05:16 +0200 Subject: [PATCH 10/42] Optimize RAM usage by making lookup tables const --- App/app/action.c | 2 +- App/app/app.c | 2 +- App/app/spectrum.c | 4 ++-- App/driver/st7565.c | 2 +- App/ui/main.c | 2 +- App/ui/ui.c | 2 +- archive/f4hwn.fusion.development.bin | Bin 104068 -> 104064 bytes 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/App/app/action.c b/App/app/action.c index d4468e32..1811260f 100644 --- a/App/app/action.c +++ b/App/app/action.c @@ -61,7 +61,7 @@ inline static void ACTION_1750() { ACTION_AlarmOr1750(true); }; inline static void ACTION_ScanRestart() { ACTION_Scan(true); }; -void (*action_opt_table[])(void) = { +void (*const action_opt_table[])(void) = { [ACTION_OPT_NONE] = &FUNCTION_NOP, [ACTION_OPT_POWER] = &ACTION_Power, [ACTION_OPT_MONITOR] = &ACTION_Monitor, diff --git a/App/app/app.c b/App/app/app.c index e81e09ba..175e52e3 100644 --- a/App/app/app.c +++ b/App/app/app.c @@ -107,7 +107,7 @@ static KEY_Code_t gScreenSaverWakeKey = KEY_INVALID; static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld); -void (*ProcessKeysFunctions[])(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) = { +void (*const ProcessKeysFunctions[])(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) = { [DISPLAY_MAIN] = &MAIN_ProcessKeys, [DISPLAY_MENU] = &MENU_ProcessKeys, [DISPLAY_SCANNER] = &SCANNER_ProcessKeys, diff --git a/App/app/spectrum.c b/App/app/spectrum.c index 29b51a52..d4830b07 100644 --- a/App/app/spectrum.c +++ b/App/app/spectrum.c @@ -73,7 +73,7 @@ static uint16_t blacklistFreqs[15]; static uint8_t blacklistFreqsIdx; #endif -const char *bwOptions[] = {"25", "12.5", "6.25"}; +const char *const bwOptions[] = {"25", "12.5", "6.25"}; const uint8_t modulationTypeTuneSteps[] = {100, 50, 10}; const uint8_t modTypeReg47Values[] = {1, 7, 5}; @@ -176,7 +176,7 @@ char freqInputString[11]; uint8_t menuState = 0; uint16_t listenT = 0; -RegisterSpec registerSpecs[] = { +const RegisterSpec registerSpecs[] = { {}, {"LNAs", BK4819_REG_13, 8, 0b11, 1}, {"LNA", BK4819_REG_13, 5, 0b111, 1}, diff --git a/App/driver/st7565.c b/App/driver/st7565.c index c488bb68..23d93e48 100644 --- a/App/driver/st7565.c +++ b/App/driver/st7565.c @@ -260,7 +260,7 @@ void ST7565_FillScreen(uint8_t value) // D=0, display OFF #define ST7565_CMD_DISPLAY_ON_OFF 0xAE -uint8_t cmds[] = { +const uint8_t cmds[] = { ST7565_CMD_BIAS_SELECT | 0, // Select bias setting: 1/9 ST7565_CMD_COM_DIRECTION | (0 << 3), // Set output direction of COM: normal ST7565_CMD_SEG_DIRECTION | 1, // Set scan direction of SEG: reverse diff --git a/App/ui/main.c b/App/ui/main.c index 293d8322..f36cf878 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -140,7 +140,7 @@ static void UI_MAIN_DrawBeamLine(void) } #endif -const char *VfoStateStr[] = { +const char *const VfoStateStr[] = { [VFO_STATE_NORMAL]="", [VFO_STATE_BUSY]="BUSY", [VFO_STATE_BAT_LOW]="BAT LOW", diff --git a/App/ui/ui.c b/App/ui/ui.c index 116fa962..489c7613 100644 --- a/App/ui/ui.c +++ b/App/ui/ui.c @@ -48,7 +48,7 @@ bool gAskToSave; bool gAskToDelete; -void (*UI_DisplayFunctions[])(void) = { +void (*const UI_DisplayFunctions[])(void) = { [DISPLAY_MAIN] = &UI_DisplayMain, [DISPLAY_MENU] = &UI_DisplayMenu, [DISPLAY_SCANNER] = &UI_DisplayScanner, diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 242c0493eedbfd55735aae677b400ba713381791..1a80d5cfc20541921c3d6b1a7b2e4bc74e347419 100755 GIT binary patch delta 13864 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 M1%T6Qg`6k<8|xa+y#N3J From bbee375623ff03e5379c63d2ad84581a696b5bc9 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Thu, 30 Jul 2026 19:13:04 +0200 Subject: [PATCH 11/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 104064 -> 104064 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 1a80d5cfc20541921c3d6b1a7b2e4bc74e347419..2956afdd1fc1b0ebad12e514ac1e9ead67132197 100755 GIT binary patch delta 34 ocmZoz%hmuyTNqDH5HK`KNlUayv|unaw=y)cGTMG~0^@R40M=v+q5uE@ delta 34 ocmZoz%hmuyTNqDH5J Date: Fri, 31 Jul 2026 02:36:23 +0200 Subject: [PATCH 12/42] Remove dead empty block --- App/ui/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/App/ui/main.c b/App/ui/main.c index f36cf878..a6fe990e 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -1776,8 +1776,6 @@ void UI_DisplayMain(void) #endif #ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS - { - } } #endif From c0e39098530c7736558b4aee4cf6f096942c9645 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Fri, 31 Jul 2026 02:37:14 +0200 Subject: [PATCH 13/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 104064 -> 104064 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 2956afdd1fc1b0ebad12e514ac1e9ead67132197..8fa3001934fd756c91ff1443f41cac8d141e6e2c 100755 GIT binary patch delta 42 wcmZoz%hmuyTNqDHkT5n(OEXR~NntQBurfBYGB#)MD$P+aHr)Pj0^@vE05M7pjQ{`u delta 42 wcmZoz%hmuyTNqDHkT5h#NlUayv|unaw=y)cGBRNBD$P+aHrW1f0^@vE05OUUhyVZp From 73f44911ed7e74e0c9c3a463aaaf95321d1c5b49 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 03:38:03 +0200 Subject: [PATCH 14/42] Add Fox Hunt mode --- App/CMakeLists.txt | 3 + App/app/action.c | 9 + App/app/foxhunt.c | 400 +++++++++++++++++++++++++++++++++++++++++++++ App/app/foxhunt.h | 56 +++++++ App/bitmaps.c | 75 +++++++++ App/bitmaps.h | 8 + App/settings.h | 3 + App/ui/menu.c | 3 + CMakePresets.json | 2 + 9 files changed, 559 insertions(+) create mode 100644 App/app/foxhunt.c create mode 100644 App/app/foxhunt.h diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index 09d33e28..9919cec1 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -211,6 +211,9 @@ enable_feature(ENABLE_FEAT_F4HWN_BEAM enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG app/rxtx_log.c ) +enable_feature(ENABLE_FEAT_F4HWN_FOXHUNT + app/foxhunt.c +) enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP) enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER) diff --git a/App/app/action.c b/App/app/action.c index 1811260f..22f64b76 100644 --- a/App/app/action.c +++ b/App/app/action.c @@ -48,6 +48,9 @@ #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG #include "app/rxtx_log.h" #endif +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT + #include "app/foxhunt.h" +#endif #if defined(ENABLE_FMRADIO) static void ACTION_Scan_FM(bool bRestart); @@ -137,6 +140,9 @@ void (*const action_opt_table[])(void) = { #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG [ACTION_OPT_RXTX_LOG] = &ACTION_RxTxLog, #endif +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT + [ACTION_OPT_FOXHUNT] = &ACTION_FoxHunt, +#endif }; static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN); @@ -382,6 +388,9 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) #endif #ifdef ENABLE_FEAT_F4HWN_BEAM case ACTION_OPT_BEAM: + #endif + #ifdef ENABLE_FEAT_F4HWN_FOXHUNT + case ACTION_OPT_FOXHUNT: #endif gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; return; diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c new file mode 100644 index 00000000..05e35a0d --- /dev/null +++ b/App/app/foxhunt.c @@ -0,0 +1,400 @@ +/* Copyright 2026 Armel F4HWN + * https://github.com/armel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app/foxhunt.h" + +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT + +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER +#include "k5viewer.h" +#endif + +// Signal window mapped onto the RSSI bar, in dBm. +// Roughly S0 (empty) to S9 + 40 dB (full), IARU VHF/UHF scale. +#define FOXHUNT_DBM_FLOOR (-141) +#define FOXHUNT_DBM_CEIL (-53) + +// Gauge geometry inside the main frame buffer (y in 0..55, status line excluded). +// 13 segments on the IARU S-meter scale: S1..S9 are 6 dB apart, the four marks +// past S9 (+10..+40) are 10 dB apart, so the axis compresses at the top. +#define FOXHUNT_BAR_X0 6 // leftmost segment x (centres the 13 segments) +#define FOXHUNT_SEG_COUNT 13 // S1..S9 + (+10..+40) +#define FOXHUNT_SEG_PITCH 9 // px between segment starts +#define FOXHUNT_SEG_W 8 // segment width +#define FOXHUNT_SEG_BOTTOM 37 // base the staircase grows up from + +// Refresh period and trend sampling window. +#define FOXHUNT_TICK_MS 50 +#define FOXHUNT_TREND_TICKS 20 // compare the level roughly once per second + +// Geiger audio: the blip RATE tracks the signal level (faster = closer), the +// pitch rises too as a secondary cue. Below the silence floor, no blips at all. +#define FOXHUNT_AUDIO_SETTLE_MS 60 // audio amplifier warm-up after enabling the speaker +#define FOXHUNT_BLIP_MS 50 // tone duration per blip +#define FOXHUNT_RATE_SLOW_TICKS 20 // ticks between blips at the floor (~1/s) +#define FOXHUNT_RATE_FAST_TICKS 2 // ticks between blips at the ceiling (fast) +#define FOXHUNT_SILENCE_DBM (-120) // stay silent below this level (noise floor) +#define FOXHUNT_TONE_MIN 400 // Hz at the floor of the window +#define FOXHUNT_TONE_MAX 2400 // Hz at the ceiling of the window + +// Audio mode cycled by the 1 key: silent -> Geiger beep -> received station. +#define FOXHUNT_AUDIO_OFF 0 +#define FOXHUNT_AUDIO_BEEP 1 +#define FOXHUNT_AUDIO_STATION 2 + +// Attenuator via the BK4829 PGA (REG_13 bits 0..2) — the last gain stage before +// the RSSI detector, so it scales the reading linearly. Reducing the early LNA +// alone barely moved the reading on strong signals (mixer + PGA re-amplify). +// pgaTab (bk4829.c) = {-33,-27,-21,-15,-9,-6,-3,0}; index 7 (= 0 dB) matches the +// RX default (0x03DF), so step 0 leaves the gain untouched. +static const uint8_t FOXHUNT_ATT_PGA[4] = {7, 5, 3, 1}; // 0, -6, -15, -27 dB +static const uint8_t FOXHUNT_ATT_DB[4] = {0, 6, 15, 27}; + +static KeyboardState kbd = {KEY_INVALID, KEY_INVALID, 0}; + +static bool foxRunning; +static uint8_t foxAudioMode; +static uint8_t attStep; +static int16_t curDbm; +static int16_t peakDbm; +static int16_t trendRef; +static int16_t trendDelta; +static uint8_t trendTick; +static uint8_t audioTick; + +static char str[16]; + +// Read the calibrated signal level of the current RX VFO, in dBm. +static int16_t FOXHUNT_ReadDbm(void) +{ + return BK4819_GetRSSI_dBm() + dBmCorrTable[gRxVfo->Band]; +} + +// Apply the selected attenuator step to the BK4829 PGA gain field. +static void FOXHUNT_ApplyAtt(void) +{ + uint16_t reg = BK4819_ReadRegister(BK4819_REG_13); + reg = (reg & ~0x7u) | (uint16_t)FOXHUNT_ATT_PGA[attStep]; // PGA = REG_13 bits 0..2 + BK4819_WriteRegister(BK4819_REG_13, reg); +} + +// Set the speaker/AF state for the current audio mode. +static void FOXHUNT_SetAudio(void) +{ + if (foxAudioMode == FOXHUNT_AUDIO_OFF) { + AUDIO_AudioPathOff(); + return; + } + // Speaker on, let the amplifier warm up, RX audio muted for now. BEEP keeps it + // muted (only the blips are heard); STATION un-mutes per level in the loop. + AUDIO_AudioPathOn(); + SYSTEM_DelayMs(FOXHUNT_AUDIO_SETTLE_MS); + BK4819_SetAF(BK4819_AF_MUTE); +} + +// Map a dBm value to a Geiger tone frequency (higher signal, higher pitch). +static uint16_t FOXHUNT_DbmToTone(int16_t dbm) +{ + if (dbm <= FOXHUNT_DBM_FLOOR) return FOXHUNT_TONE_MIN; + if (dbm >= FOXHUNT_DBM_CEIL) return FOXHUNT_TONE_MAX; + return FOXHUNT_TONE_MIN + + (uint16_t)(((int32_t)(dbm - FOXHUNT_DBM_FLOOR) * (FOXHUNT_TONE_MAX - FOXHUNT_TONE_MIN)) / + (FOXHUNT_DBM_CEIL - FOXHUNT_DBM_FLOOR)); +} + +// Ticks between two blips: fewer ticks = faster clicking as the signal rises. +static uint8_t FOXHUNT_BlipPeriod(int16_t dbm) +{ + if (dbm <= FOXHUNT_DBM_FLOOR) return FOXHUNT_RATE_SLOW_TICKS; + if (dbm >= FOXHUNT_DBM_CEIL) return FOXHUNT_RATE_FAST_TICKS; + return FOXHUNT_RATE_SLOW_TICKS - + (uint8_t)(((int32_t)(dbm - FOXHUNT_DBM_FLOOR) * (FOXHUNT_RATE_SLOW_TICKS - FOXHUNT_RATE_FAST_TICKS)) / + (FOXHUNT_DBM_CEIL - FOXHUNT_DBM_FLOOR)); +} + +// Emit one short blip at the given pitch, then hand the chip back to RX. +// The speaker path is already on and settled (see the key-1 handler); between +// blips TurnsOffTones_TurnsOnRX mutes the AF, so the RX stays silent. +static void FOXHUNT_Blip(uint16_t freq) +{ + BK4819_PrepareToPlayTone(true); + BK4819_PlayToneRaw(freq, FOXHUNT_BLIP_MS); + BK4819_TurnsOffTones_TurnsOnRX(); + + // TurnsOffTones_TurnsOnRX restores a normal RX front-end, so re-assert the + // fixed gain and attenuator the level reading relies on. + BK4819_SetAGC(false); + FOXHUNT_ApplyAtt(); +} + +// Number of lit segments for a level, on the IARU S-meter scale: +// S1..S9 are 6 dB apart, the four marks past S9 (+10..+40) are 10 dB apart. +static uint8_t FOXHUNT_FillCount(int16_t dbm) +{ + int16_t n; + if (dbm < -141) return 0; + if (dbm <= -93) + n = 1 + (dbm + 141) / 6; // S1 (-141) .. S9 (-93) -> 1..9 + else + n = 9 + (dbm + 93) / 10; // +10 (-83) .. +40 (-53) -> 10..13 + if (n > FOXHUNT_SEG_COUNT) + n = FOXHUNT_SEG_COUNT; + return (uint8_t)n; +} + +// Build the IARU S-meter reading string (e.g. "S7" or "S9+30"). +static void FOXHUNT_BuildS(char *out, int16_t dbm) +{ + if (dbm >= -93) { + int16_t over = dbm - (-93); + if (over > 40) over = 40; + sprintf(out, "S9+%02d", over); + } else if (dbm < -141) { + sprintf(out, "S0"); + } else { + sprintf(out, "S%d", (dbm + 147) / 6); + } +} + +// Fill a solid rectangle, column by column. +static void FOXHUNT_FillRect(int16_t x0, int16_t y0, int16_t x1, int16_t y1, bool black) +{ + for (int16_t x = x0; x <= x1; x++) + UI_DrawLineBuffer(gFrameBuffer, x, y0, x, y1, black); +} + +static void FOXHUNT_DrawBar(void) +{ + uint8_t nCur = FOXHUNT_FillCount(curDbm); + uint8_t i; + + // Continuous S-meter staircase (no frame): each segment is 1 px taller than + // the previous, from S1 (1 px) to S9+40 (13 px), growing up from the base. + for (i = 0; i < nCur; i++) { + int16_t sx = FOXHUNT_BAR_X0 + i * FOXHUNT_SEG_PITCH; + FOXHUNT_FillRect(sx, FOXHUNT_SEG_BOTTOM - i, sx + FOXHUNT_SEG_W - 1, FOXHUNT_SEG_BOTTOM, true); + } + + // Solid separator line between the staircase and the scale labels below, + // with a 1 px gap above (y38) and below (y40) it. + UI_DrawLineBuffer(gFrameBuffer, FOXHUNT_BAR_X0, FOXHUNT_SEG_BOTTOM + 2, + FOXHUNT_BAR_X0 + (FOXHUNT_SEG_COUNT - 1) * FOXHUNT_SEG_PITCH + FOXHUNT_SEG_W - 1, + FOXHUNT_SEG_BOTTOM + 2, true); +} + +static void FOXHUNT_Draw(void) +{ + const uint8_t *trendIcon; + char sMeter[8]; + char big[8]; + + UI_DisplayClear(); + UI_StatusClear(); + + // Title as an inverse label, in the scan-list tag style. + GUI_DisplaySmallestInverse("FOX HUNT", 2, 0, true, true, 34); + + // Battery (icon + optional percentage/voltage) top-right, as on the main screens. + unsigned int bx = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1); + UI_DrawBattery(gStatusLine + bx, gBatteryDisplayLevel, gLowBatteryBlink); + if (gSetting_battery_text != 0) { + if (gSetting_battery_text == 1) { // voltage + const uint16_t v = MIN(gBatteryVoltageAverage, 999); + sprintf(str, "%u.%02u", v / 100, v % 100); + } else { // percentage + sprintf(str, "%02u%%", BATTERY_VoltsToPercent(gBatteryVoltageAverage)); + } + bx -= 7 * strlen(str); + UI_PrintStringSmallBufferNormal(str, gStatusLine + bx); + } + + // Audio state icon between the label and the battery: speaker for beep, + // headphones for station audio, nothing when silent. + if (foxAudioMode == FOXHUNT_AUDIO_BEEP) + memcpy(gStatusLine + 55, BITMAP_FoxHuntSignal, sizeof(BITMAP_FoxHuntSignal)); + else if (foxAudioMode == FOXHUNT_AUDIO_STATION) + memcpy(gStatusLine + 55, BITMAP_FoxHuntSpeaker, sizeof(BITMAP_FoxHuntSpeaker)); + + // Hero level, floating: the big number renders naturally (left-anchored) and + // the "dBm" unit follows right after it, so the block flows with the width. + sprintf(big, "%d", curDbm); + UI_DisplayFrequency(big, 2, 0, false); + UI_PrintStringSmallNormal("dBm", (uint8_t)(strlen(big) * 13 + 4), 0, 1); + + // Trend as an arrow on line 0 (up = nearer, down = farther, = stable), + // right-anchored; the signed delta since ~1 s ago sits on line 1. + trendIcon = (trendDelta > 0) ? BITMAP_FoxHuntUp + : (trendDelta < 0) ? BITMAP_FoxHuntDown + : BITMAP_FoxHuntFlat; + memcpy(gFrameBuffer[0] + (126 - 11), trendIcon, 11); + // Signed delta on line 1 — only when it actually moved (no "00 dBm" when + // stable). "dBm" right-anchored to x126, the value 2 px to its left (a real + // space would be 7 px), so they are drawn as two separate strings. + if (trendDelta != 0) { + sprintf(str, "%+03d", trendDelta); // sign + 2 digits, e.g. "+05" / "-12" + UI_PrintStringSmallNormal("dBm", 127 - 3 * 7, 0, 1); + UI_PrintStringSmallNormal(str, 127 - 3 * 7 - 2 - strlen(str) * 7, 0, 1); + } + + // Context line: peak hold and S-meter as small inverse labels (scan-list tag + // style, 4 px/char), PK anchored left and S anchored right. + sprintf(str, "PK %d", peakDbm); + GUI_DisplaySmallestInverse(str, 4, 2, false, true, 4 + strlen(str) * 4); + FOXHUNT_BuildS(sMeter, curDbm); + GUI_DisplaySmallestInverse(sMeter, 126 - strlen(sMeter) * 4, 2, false, true, 125); + + // Segmented S-meter staircase. + FOXHUNT_DrawBar(); + + // Scale under the gauge, aligned with segments 1 / 5 / 9 / 13. + GUI_DisplaySmallest("S1", 6, 41, false, true); + GUI_DisplaySmallest("S5", 42, 41, false, true); + GUI_DisplaySmallest("S9", 78, 41, false, true); + GUI_DisplaySmallest("+40", 110, 41, false, true); + + // Attenuator as an inverse label (left), tuned frequency (right). + sprintf(str, "ATT %ddB", FOXHUNT_ATT_DB[attStep]); + GUI_DisplaySmallestInverse(str, 4, 6, false, true, 4 + strlen(str) * 4); + sprintf(str, "%u.%05u", gRxVfo->pRX->Frequency / 100000, gRxVfo->pRX->Frequency % 100000); + UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); +} + +static void FOXHUNT_HandleKeys(void) +{ + kbd.prev = kbd.current; + kbd.current = KEYBOARD_GetKey(); + + // Act only on the rising edge of a new key. + if (kbd.current == KEY_INVALID || kbd.current == kbd.prev) + return; + + switch (kbd.current) { + case KEY_EXIT: + foxRunning = false; + break; + case KEY_UP: + case KEY_4: + if (attStep < 3) { attStep++; FOXHUNT_ApplyAtt(); } + break; + case KEY_DOWN: + case KEY_0: + if (attStep > 0) { attStep--; FOXHUNT_ApplyAtt(); } + break; + case KEY_MENU: + // Reset the peak hold and the trend reference. + peakDbm = curDbm; + trendRef = curDbm; + break; + case KEY_1: + // Cycle the audio: silent -> Geiger beep -> station audio -> silent. + foxAudioMode = (uint8_t)((foxAudioMode + 1) % 3); + FOXHUNT_SetAudio(); + if (foxAudioMode == FOXHUNT_AUDIO_BEEP) + audioTick = FOXHUNT_RATE_SLOW_TICKS; // blip promptly + break; + default: + break; + } +} + +void APP_RunFoxHunt(void) +{ + // Finish any pending backlight fade before taking over the screen. + BACKLIGHT_UpdateTickless(); + + // Hunt on the user-selected VFO: dual-watch / cross-band may have left the + // radio listening on the other VFO, so force RX on the selected one and retune. + gEeprom.RX_VFO = gEeprom.TX_VFO; + gRxVfo = gTxVfo; + RADIO_SetupRegisters(true); + + // Start silent; the audio (beep / station) is opt-in from inside the mode. + AUDIO_AudioPathOff(); + foxAudioMode = FOXHUNT_AUDIO_OFF; + audioTick = 0; + + // Fixed front-end gain so the attenuator steps and the reading stay stable. + BK4819_SetAGC(false); + attStep = 0; + FOXHUNT_ApplyAtt(); + + curDbm = FOXHUNT_ReadDbm(); + peakDbm = curDbm; + trendRef = curDbm; + trendDelta = 0; + trendTick = 0; + + kbd.current = KEY_INVALID; + kbd.prev = KEY_INVALID; + + foxRunning = true; + while (foxRunning) { +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + // Keep the K5Viewer link alive and pick up any remote key. + K5VIEWER_ParseInput(); +#endif + FOXHUNT_HandleKeys(); + + curDbm = FOXHUNT_ReadDbm(); + if (curDbm > peakDbm) + peakDbm = curDbm; + + if (++trendTick >= FOXHUNT_TREND_TICKS) { + trendDelta = curDbm - trendRef; + trendRef = curDbm; + trendTick = 0; + } + + FOXHUNT_Draw(); + + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); + +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + // Mirror the screen to K5Viewer (sends only changed chunks). + K5VIEWER_Update(false); +#endif + + // Beep mode: Geiger blip whose rate/pitch track the level (silent below floor). + if (foxAudioMode == FOXHUNT_AUDIO_BEEP && curDbm >= FOXHUNT_SILENCE_DBM) { + if (++audioTick >= FOXHUNT_BlipPeriod(curDbm)) { + audioTick = 0; + FOXHUNT_Blip(FOXHUNT_DbmToTone(curDbm)); + } + } + // Station mode: route the received audio, gated by the silence floor. + else if (foxAudioMode == FOXHUNT_AUDIO_STATION) { + BK4819_SetAF(curDbm >= FOXHUNT_SILENCE_DBM + ? (gRxVfo->Modulation == MODULATION_AM ? BK4819_AF_AM : BK4819_AF_FM) + : BK4819_AF_MUTE); + } + + SYSTEM_DelayMs(FOXHUNT_TICK_MS); + } + + // Mute any pending tone and restore the normal VFO selection and RX config. + AUDIO_AudioPathOff(); + RADIO_SelectVfos(); + RADIO_SetupRegisters(true); +} + +void ACTION_FoxHunt(void) +{ + APP_RunFoxHunt(); + GUI_SelectNextDisplay(DISPLAY_MAIN); +} + +#endif // ENABLE_FEAT_F4HWN_FOXHUNT diff --git a/App/app/foxhunt.h b/App/app/foxhunt.h new file mode 100644 index 00000000..e69349f4 --- /dev/null +++ b/App/app/foxhunt.h @@ -0,0 +1,56 @@ +/* Copyright 2026 Armel F4HWN + * https://github.com/armel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APP_FOXHUNT_H +#define APP_FOXHUNT_H + +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT + +#include "keyboard_state.h" + +#include "../bitmaps.h" +#include "../board.h" +#include "py32f0xx.h" +#include "../driver/backlight.h" +#include "../driver/bk4819-regs.h" +#include "../driver/bk4819.h" +#include "../driver/gpio.h" +#include "../driver/keyboard.h" +#include "../driver/st7565.h" +#include "../driver/system.h" +#include "../driver/systick.h" +#include "../external/printf/printf.h" +#include "../font.h" +#include "../helper/battery.h" +#include "../misc.h" +#include "../radio.h" +#include "../settings.h" +#include "../ui/battery.h" +#include "../ui/helper.h" +#include "../ui/ui.h" +#include "../audio.h" +#include +#include +#include + +// Entry point wired as an assignable side-key action (see action.c). +void ACTION_FoxHunt(void); + +// Self-contained modal loop that owns the screen and keypad until EXIT. +void APP_RunFoxHunt(void); + +#endif // ENABLE_FEAT_F4HWN_FOXHUNT +#endif // APP_FOXHUNT_H diff --git a/App/bitmaps.c b/App/bitmaps.c index 4d25d970..56c8e929 100644 --- a/App/bitmaps.c +++ b/App/bitmaps.c @@ -301,6 +301,81 @@ const uint8_t BITMAP_NOAA[12] = }; #endif +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT +const uint8_t BITMAP_FoxHuntSignal[10] = +{ // point source + the speaker bitmap's two sound waves, oriented horizontally + 0b00001000, + 0b00011100, + 0b00011100, + 0b00001000, + 0b00000000, + 0b00100010, + 0b00011100, + 0b01000001, + 0b00100010, + 0b00011100 +}; + +const uint8_t BITMAP_FoxHuntSpeaker[10] = +{ // speaker cone + two sound waves (bit0 = top row) + 0b00011100, + 0b00011100, + 0b00111110, + 0b01111111, + 0b00000000, + 0b00100010, + 0b00011100, + 0b01000001, + 0b00100010, + 0b00011100 +}; + +const uint8_t BITMAP_FoxHuntUp[11] = +{ // filled up triangle (getting nearer) + 0b00100000, + 0b00110000, + 0b00111000, + 0b00111100, + 0b00111110, + 0b00111111, + 0b00111110, + 0b00111100, + 0b00111000, + 0b00110000, + 0b00100000 +}; + +const uint8_t BITMAP_FoxHuntDown[11] = +{ // filled down triangle (getting farther) + 0b00000001, + 0b00000011, + 0b00000111, + 0b00001111, + 0b00011111, + 0b00111111, + 0b00011111, + 0b00001111, + 0b00000111, + 0b00000011, + 0b00000001 +}; + +const uint8_t BITMAP_FoxHuntFlat[11] = +{ // equals sign (stable) + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010, + 0b00010010 +}; +#endif + #ifndef ENABLE_CUSTOM_MENU_LAYOUT const uint8_t BITMAP_CurrentIndicator[8] = { 0xFF, diff --git a/App/bitmaps.h b/App/bitmaps.h index 88d1a7bd..c72b41d5 100644 --- a/App/bitmaps.h +++ b/App/bitmaps.h @@ -45,6 +45,14 @@ extern const uint8_t BITMAP_compand[6]; extern const uint8_t BITMAP_NOAA[12]; +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT + extern const uint8_t BITMAP_FoxHuntSignal[10]; + extern const uint8_t BITMAP_FoxHuntSpeaker[10]; + extern const uint8_t BITMAP_FoxHuntUp[11]; + extern const uint8_t BITMAP_FoxHuntDown[11]; + extern const uint8_t BITMAP_FoxHuntFlat[11]; +#endif + #ifndef ENABLE_CUSTOM_MENU_LAYOUT extern const uint8_t BITMAP_CurrentIndicator[8]; #endif diff --git a/App/settings.h b/App/settings.h index f450a349..a4e4bcb2 100644 --- a/App/settings.h +++ b/App/settings.h @@ -132,6 +132,9 @@ enum ACTION_OPT_t { #endif #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG ACTION_OPT_RXTX_LOG, +#endif +#ifdef ENABLE_FEAT_F4HWN_FOXHUNT + ACTION_OPT_FOXHUNT, #endif ACTION_OPT_LEN }; diff --git a/App/ui/menu.c b/App/ui/menu.c index febae9a6..5fd33441 100644 --- a/App/ui/menu.c +++ b/App/ui/menu.c @@ -525,6 +525,9 @@ const t_sidefunction gSubMenu_SIDEFUNCTIONS[] = #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG {"RF LOG", ACTION_OPT_RXTX_LOG}, #endif + #ifdef ENABLE_FEAT_F4HWN_FOXHUNT + {"FOX HUNT", ACTION_OPT_FOXHUNT}, + #endif #endif }; diff --git a/CMakePresets.json b/CMakePresets.json index fe155522..1734f9f3 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -73,6 +73,7 @@ "ENABLE_FEAT_F4HWN_SCAN_RSSI": false, "ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": false, "ENABLE_FEAT_F4HWN_BEAM": false, + "ENABLE_FEAT_F4HWN_FOXHUNT": false, "ENABLE_FEAT_F4HWN_RXTX_LOG": false, "ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP": false, "ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER": false, @@ -207,6 +208,7 @@ "ENABLE_FEAT_F4HWN_SCAN_RSSI": true, "ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": true, "ENABLE_FEAT_F4HWN_BEAM": true, + "ENABLE_FEAT_F4HWN_FOXHUNT": true, "ENABLE_FEAT_F4HWN_RXTX_LOG": true, "ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP": false, "ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER": true, From 027240de543dd205e59f4b50a3a54ae2e986ece6 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 03:38:43 +0200 Subject: [PATCH 15/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 104064 -> 105780 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 8fa3001934fd756c91ff1443f41cac8d141e6e2c..1654b953a7cd79cf992c4d12bfc505b6c92a6b15 100755 GIT binary patch delta 8297 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 delta 6526 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 QEmb)FzZNU1Xtgx>Klz!SkN^Mx From a59f3edcff98cd9230409c71372a76f24e8f8b73 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 15:35:46 +0200 Subject: [PATCH 16/42] Add Beacon mode --- App/app/foxhunt.c | 447 ++++++++++++++++++++++++++++++++++++++++++---- App/app/foxhunt.h | 1 + App/ui/menu.c | 2 +- 3 files changed, 414 insertions(+), 36 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 05e35a0d..73468ef2 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -55,6 +55,19 @@ #define FOXHUNT_AUDIO_BEEP 1 #define FOXHUNT_AUDIO_STATION 2 +// --- Beacon (fox) sub-mode --------------------------------------------------- +// Turns the radio into the hidden transmitter: each cycle keys up on the TX VFO +// and sends the CW message (" BEACON") in Morse, then stays silent for the +// (adjustable) idle gap. The carrier stays up during the message; only the tone +// modulation is keyed on/off (EnterTxMute/ExitTxMute) = MCW on FM. +#define FOXHUNT_BEACON_TONE_HZ 1000 // CW tone pitch (Hz) +#define FOXHUNT_MORSE_UNIT_MS 80 // one Morse time unit (~15 WPM) +#define FOXHUNT_BEACON_IDLE_DEF 30 // default silence between IDs (s) +#define FOXHUNT_BEACON_IDLE_MIN 5 // shortest idle gap (s) +#define FOXHUNT_BEACON_IDLE_MAX 60 // longest idle gap (s) +#define FOXHUNT_BEACON_IDLE_STEP 5 // idle adjust step (s) +#define FOXHUNT_CALLSIGN_ADDR 0x00A0C8u // boot message line 1 in SPI flash + // Attenuator via the BK4829 PGA (REG_13 bits 0..2) — the last gain stage before // the RSSI detector, so it scales the reading linearly. Reducing the early LNA // alone barely moved the reading on strong signals (mixer + PGA re-amplify). @@ -77,6 +90,29 @@ static uint8_t audioTick; static char str[16]; +// Sentinel-prefixed Morse patterns: after the leading 1 sentinel bit, each lower +// bit is one element read MSB-first (0 = dit, 1 = dah). 0 = unsupported char. +static const uint8_t FOXHUNT_MORSE_LETTER[26] = { + 0x05, 0x18, 0x1A, 0x0C, 0x02, 0x12, 0x0E, 0x10, 0x04, 0x17, // A..J + 0x0D, 0x14, 0x07, 0x06, 0x0F, 0x16, 0x1D, 0x0A, 0x08, 0x03, // K..T + 0x09, 0x11, 0x0B, 0x19, 0x1B, 0x1C, // U..Z +}; +static const uint8_t FOXHUNT_MORSE_DIGIT[10] = { + 0x3F, 0x2F, 0x27, 0x23, 0x21, 0x20, 0x30, 0x38, 0x3C, 0x3E, // 0..9 +}; + +// Beacon sub-mode state. +static bool foxBeacon; // false = hunt (RX), true = beacon (TX) +static bool beaconPhaseTx; // true = transmit this tick, false = idle gap +static uint8_t beaconIdle; // configured silence between IDs (s) +static uint8_t beaconIdleLeft; // seconds left in the current silence +static uint8_t beaconIdleTick; // tick counter that clocks the idle countdown +static char beaconMsg[24]; // CW message, e.g. "F4HWN BEACON" + +static void FOXHUNT_EnterHunt(void); +static void FOXHUNT_EnterBeacon(void); +static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft); + // Read the calibrated signal level of the current RX VFO, in dBm. static int16_t FOXHUNT_ReadDbm(void) { @@ -195,6 +231,24 @@ static void FOXHUNT_DrawBar(void) FOXHUNT_SEG_BOTTOM + 2, true); } +// Battery icon plus the optional voltage/percentage text, top-right of the status +// line — shared by the hunt and beacon screens. +static void FOXHUNT_DrawStatusBattery(void) +{ + unsigned int bx = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1); + UI_DrawBattery(gStatusLine + bx, gBatteryDisplayLevel, gLowBatteryBlink); + if (gSetting_battery_text != 0) { + if (gSetting_battery_text == 1) { // voltage + const uint16_t v = MIN(gBatteryVoltageAverage, 999); + sprintf(str, "%u.%02u", v / 100, v % 100); + } else { // percentage + sprintf(str, "%02u%%", BATTERY_VoltsToPercent(gBatteryVoltageAverage)); + } + bx -= 7 * strlen(str); + UI_PrintStringSmallBufferNormal(str, gStatusLine + bx); + } +} + static void FOXHUNT_Draw(void) { const uint8_t *trendIcon; @@ -208,18 +262,7 @@ static void FOXHUNT_Draw(void) GUI_DisplaySmallestInverse("FOX HUNT", 2, 0, true, true, 34); // Battery (icon + optional percentage/voltage) top-right, as on the main screens. - unsigned int bx = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1); - UI_DrawBattery(gStatusLine + bx, gBatteryDisplayLevel, gLowBatteryBlink); - if (gSetting_battery_text != 0) { - if (gSetting_battery_text == 1) { // voltage - const uint16_t v = MIN(gBatteryVoltageAverage, 999); - sprintf(str, "%u.%02u", v / 100, v % 100); - } else { // percentage - sprintf(str, "%02u%%", BATTERY_VoltsToPercent(gBatteryVoltageAverage)); - } - bx -= 7 * strlen(str); - UI_PrintStringSmallBufferNormal(str, gStatusLine + bx); - } + FOXHUNT_DrawStatusBattery(); // Audio state icon between the label and the battery: speaker for beep, // headphones for station audio, nothing when silent. @@ -272,6 +315,74 @@ static void FOXHUNT_Draw(void) UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); } +// Map a navigation key to a logical step (+1 = up/increase, -1 = down/decrease), +// honouring the SET_NAV up/down orientation (UV-K1 vs UV-K5), like the rest of +// the firmware (see MAIN_Key_UP_DOWN / spectrum GetDirection). +static int8_t FOXHUNT_NavDir(KEY_Code_t key) +{ + int8_t dir = (key == KEY_UP) ? 1 : -1; + return gEeprom.SET_NAV ? dir : -dir; +} + +// Change the attenuator by one step in the given direction. +static void FOXHUNT_AttStep(int8_t dir) +{ + if (dir > 0) { + if (attStep < 3) { attStep++; FOXHUNT_ApplyAtt(); } + } else { + if (attStep > 0) { attStep--; FOXHUNT_ApplyAtt(); } + } +} + +// Change the beacon idle gap by one step in the given direction (shared by the +// idle-phase keys and the mid-transmission adjust). +static void FOXHUNT_IdleStep(int8_t dir) +{ + if (dir > 0) { + if (beaconIdle < FOXHUNT_BEACON_IDLE_MAX) beaconIdle += FOXHUNT_BEACON_IDLE_STEP; + } else { + if (beaconIdle > FOXHUNT_BEACON_IDLE_MIN) beaconIdle -= FOXHUNT_BEACON_IDLE_STEP; + } +} + +// Sleep one UI tick, but in 10 ms slices stepping the backlight fade each slice, +// so the fade rate matches the main screen (BACKLIGHT_Update runs every 10 ms in +// APP_TimeSlice10ms; delaying the whole 50 ms tick at once made it ~5x slower). +static void FOXHUNT_TickDelay(void) +{ + for (uint8_t i = 0; i < FOXHUNT_TICK_MS / 10; i++) { + SYSTEM_DelayMs(10); + BACKLIGHT_Update(); + } +} + +// Idle housekeeping the foreground scheduler normally does but this modal loop +// bypasses: backlight timeout (BLTime) and, while hunting, the sleep auto power +// off. Cadenced on the 500 ms system tick. +static void FOXHUNT_IdleHousekeeping(void) +{ + if (!gNextTimeslice_500ms) + return; + gNextTimeslice_500ms = false; + + // Backlight timeout: switch it off when the countdown expires (both modes). + if (gBacklightCountdown_500ms > 0 + && gEeprom.BACKLIGHT_TIME < 61 + && --gBacklightCountdown_500ms == 0) + BACKLIGHT_TurnOff(); + +#ifdef ENABLE_FEAT_F4HWN_SLEEP + // Auto power-off: only while hunting (a running beacon must stay alive). Hand + // back to the main loop just before expiry so it performs the actual sleep. + if (!foxBeacon && gSetting_set_off != 0 && gSleepModeCountdown_500ms > 0) { + if (gSleepModeCountdown_500ms > 1) + gSleepModeCountdown_500ms--; + else + foxRunning = false; + } +#endif +} + static void FOXHUNT_HandleKeys(void) { kbd.prev = kbd.current; @@ -281,17 +392,22 @@ static void FOXHUNT_HandleKeys(void) if (kbd.current == KEY_INVALID || kbd.current == kbd.prev) return; + BACKLIGHT_TurnOn(); // any keypress wakes the screen and re-arms the timers + switch (kbd.current) { case KEY_EXIT: foxRunning = false; break; case KEY_UP: - case KEY_4: - if (attStep < 3) { attStep++; FOXHUNT_ApplyAtt(); } - break; case KEY_DOWN: + // Arrows follow SET_NAV; the 4/0 alternates below stay fixed. + FOXHUNT_AttStep(FOXHUNT_NavDir(kbd.current)); + break; + case KEY_4: + FOXHUNT_AttStep(1); + break; case KEY_0: - if (attStep > 0) { attStep--; FOXHUNT_ApplyAtt(); } + FOXHUNT_AttStep(-1); break; case KEY_MENU: // Reset the peak hold and the trend reference. @@ -305,30 +421,25 @@ static void FOXHUNT_HandleKeys(void) if (foxAudioMode == FOXHUNT_AUDIO_BEEP) audioTick = FOXHUNT_RATE_SLOW_TICKS; // blip promptly break; + case KEY_SIDE1: + case KEY_SIDE2: + // Same shortcut that opened Fox Hunt now toggles to the beacon. + FOXHUNT_EnterBeacon(); + break; default: break; } } -void APP_RunFoxHunt(void) +// (Re)enter the hunt (RX) sub-mode: fixed front-end gain, attenuator re-applied, +// audio silenced, peak/trend reset. Called at start-up and when leaving beacon. +static void FOXHUNT_EnterHunt(void) { - // Finish any pending backlight fade before taking over the screen. - BACKLIGHT_UpdateTickless(); - - // Hunt on the user-selected VFO: dual-watch / cross-band may have left the - // radio listening on the other VFO, so force RX on the selected one and retune. - gEeprom.RX_VFO = gEeprom.TX_VFO; - gRxVfo = gTxVfo; - RADIO_SetupRegisters(true); - - // Start silent; the audio (beep / station) is opt-in from inside the mode. - AUDIO_AudioPathOff(); + foxBeacon = false; foxAudioMode = FOXHUNT_AUDIO_OFF; - audioTick = 0; + AUDIO_AudioPathOff(); - // Fixed front-end gain so the attenuator steps and the reading stay stable. BK4819_SetAGC(false); - attStep = 0; FOXHUNT_ApplyAtt(); curDbm = FOXHUNT_ReadDbm(); @@ -336,17 +447,280 @@ void APP_RunFoxHunt(void) trendRef = curDbm; trendDelta = 0; trendTick = 0; + audioTick = 0; +} - kbd.current = KEY_INVALID; - kbd.prev = KEY_INVALID; +// Enter the beacon (fox) sub-mode and transmit at once for instant feedback. +static void FOXHUNT_EnterBeacon(void) +{ + foxBeacon = true; + foxAudioMode = FOXHUNT_AUDIO_OFF; + AUDIO_AudioPathOff(); + gCurrentVfo = gTxVfo; // the VFO RADIO_SetTxParameters keys up + beaconPhaseTx = true; +} + +// Sleep in short slices while watching the keypad, so a burst stays interactive: +// EXIT cuts it mid-air (returns true), and UP/DOWN retune the idle gap live. +static bool FOXHUNT_TxDelay(uint16_t ms) +{ + while (ms) { + const uint16_t slice = (ms > 10) ? 10 : ms; // 10 ms: same fade rate as idle + SYSTEM_DelayMs(slice); + ms -= slice; + BACKLIGHT_Update(); // keep any brightness fade moving in TX + + kbd.prev = kbd.current; + kbd.current = KEYBOARD_GetKey(); + if (kbd.current == KEY_INVALID || kbd.current == kbd.prev) + continue; // rising edge only + + BACKLIGHT_TurnOn(); // keep the screen awake during TX + + if (kbd.current == KEY_EXIT) { + foxRunning = false; // abort the burst and leave Fox Hunt + return true; + } + if (kbd.current == KEY_SIDE1 || kbd.current == KEY_SIDE2) { + foxBeacon = false; // abort the burst and switch back to hunt + return true; + } + if (kbd.current == KEY_UP || kbd.current == KEY_DOWN) { + // The gap is only read once the burst ends, so it is safe to change + // now; refresh the "IDLE nn" label so the change is visible at once. + FOXHUNT_IdleStep(FOXHUNT_NavDir(kbd.current)); + FOXHUNT_BeaconDraw(true, 0); + ST7565_BlitFullScreen(); + } + } + return false; +} + +// Morse pattern of one character (letters, digits, '/'); 0 = space / unsupported. +static uint8_t FOXHUNT_MorseByte(char c) +{ + if (c >= 'a' && c <= 'z') c -= 32; + if (c >= 'A' && c <= 'Z') return FOXHUNT_MORSE_LETTER[c - 'A']; + if (c >= '0' && c <= '9') return FOXHUNT_MORSE_DIGIT[c - '0']; + if (c == '/') return 0x32; // -..-. + return 0; +} + +// Send one character as modulated CW: key the running TX tone on per element, +// muting the modulation (carrier stays up) between them. Returns true if aborted. +static bool FOXHUNT_MorseChar(char c) +{ + uint8_t code = FOXHUNT_MorseByte(c); + + if (code == 0) // space / unknown -> word gap + return FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 4); + + uint8_t bit = 0x80; + while (!(code & bit)) bit >>= 1; // skip to the sentinel bit + for (bit >>= 1; bit; bit >>= 1) { // then walk the elements, MSB first + const uint16_t on = (code & bit) ? (FOXHUNT_MORSE_UNIT_MS * 3) // dah + : FOXHUNT_MORSE_UNIT_MS; // dit + BK4819_ExitTxMute(); + if (FOXHUNT_TxDelay(on)) { BK4819_EnterTxMute(); return true; } + BK4819_EnterTxMute(); + if (FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS)) return true; // intra gap + } + // Inter-character gap is 3 units; one already elapsed after the last element. + return FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 2); +} + +// One beacon burst: transmit the CW identification message once, at the TX VFO's +// configured power. Carrier stays up; the tone is keyed per Morse element (MCW). +static void FOXHUNT_BeaconTransmit(void) +{ + RADIO_SetTxParameters(); // key up: carrier + PA + + // Prime the tone generator, then start silent before the first element. + BK4819_TransmitTone(false, FOXHUNT_BEACON_TONE_HZ); + BK4819_EnterTxMute(); + + bool stop = false; + for (uint8_t i = 0; !stop && beaconMsg[i]; i++) + stop = FOXHUNT_MorseChar(beaconMsg[i]); + + // Key down: mute, drop the PA and restore RX for the silent gap. If the burst + // was interrupted, FOXHUNT_TxDelay already set the target mode (quit or hunt). + BK4819_EnterTxMute(); + BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); + RADIO_SetupRegisters(true); +} + +static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft) +{ + UI_DisplayClear(); + UI_StatusClear(); + + // Status line: BEACON tag (left) + battery (right), same style as FOX HUNT. + GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 28); + FOXHUNT_DrawStatusBattery(); + + // Centre, on two lines: the state, and below it the idle countdown (idle only). + if (txNow) { + UI_PrintString("TX", 0, 127, 1, 10); + } else { + UI_PrintString("IDLE", 0, 127, 1, 10); + sprintf(str, "%02us", idleLeft); + UI_PrintString(str, 0, 127, 3, 10); + } + + // Bottom-left: the idle-duration setting as an inverse label (ATT style). + sprintf(str, "IDLE %02u", beaconIdle); + GUI_DisplaySmallestInverse(str, 4, 6, false, true, 4 + strlen(str) * 4); + + // Bottom-right: the working (TX) frequency. + sprintf(str, "%u.%05u", gTxVfo->pTX->Frequency / 100000, gTxVfo->pTX->Frequency % 100000); + UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); +} + +static void FOXHUNT_BeaconKeys(void) +{ + kbd.prev = kbd.current; + kbd.current = KEYBOARD_GetKey(); + + if (kbd.current == KEY_INVALID || kbd.current == kbd.prev) + return; + + BACKLIGHT_TurnOn(); // any keypress wakes the screen and re-arms the timers + + switch (kbd.current) { + case KEY_EXIT: + foxRunning = false; // leave Fox Hunt entirely + break; + case KEY_SIDE1: + case KEY_SIDE2: + foxBeacon = false; // toggle back to the hunt + break; + case KEY_UP: + case KEY_DOWN: + // Idle duration, arrows following the SET_NAV orientation. + FOXHUNT_IdleStep(FOXHUNT_NavDir(kbd.current)); + break; + default: + break; + } +} + +// One iteration of the beacon loop: either transmit a burst, or count down the +// editable silent gap. Kept off the hot RX path so hunt stays lightweight. +static void FOXHUNT_BeaconTick(void) +{ + if (beaconPhaseTx) { + FOXHUNT_BeaconDraw(true, 0); + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + K5VIEWER_Update(false); +#endif + FOXHUNT_BeaconTransmit(); // may clear foxBeacon (abort) + + beaconPhaseTx = false; + beaconIdleLeft = beaconIdle; + beaconIdleTick = 0; + + if (foxRunning && !foxBeacon) // side-key switched to hunt + FOXHUNT_EnterHunt(); + return; // EXIT (quit) falls through + } + + // Idle (silent) phase: responsive, editable countdown. +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + K5VIEWER_ParseInput(); +#endif + FOXHUNT_BeaconKeys(); + + if (!foxRunning) // EXIT: leave Fox Hunt + return; + if (!foxBeacon) { // side-key: back to the hunt + FOXHUNT_EnterHunt(); + return; + } + + FOXHUNT_BeaconDraw(false, beaconIdleLeft); + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + K5VIEWER_Update(false); +#endif + + if (++beaconIdleTick >= (1000 / FOXHUNT_TICK_MS)) { // one second elapsed + beaconIdleTick = 0; + if (beaconIdleLeft > 0) + beaconIdleLeft--; + if (beaconIdleLeft == 0) + beaconPhaseTx = true; // next tick transmits + } + + FOXHUNT_IdleHousekeeping(); // backlight timeout (no sleep while beaconing) + FOXHUNT_TickDelay(); // tick delay + smooth backlight fade +} + +void APP_RunFoxHunt(void) +{ + // Finish any pending backlight fade, then start with the screen on and a full + // BLTime window (BACKLIGHT_TurnOn also re-arms the sleep countdown). + BACKLIGHT_UpdateTickless(); + BACKLIGHT_TurnOn(); + + // Hunt on the user-selected VFO: dual-watch / cross-band may have left the + // radio listening on the other VFO, so force RX on the selected one and retune. + gEeprom.RX_VFO = gEeprom.TX_VFO; + gRxVfo = gTxVfo; + gCurrentVfo = gTxVfo; + RADIO_SetupRegisters(true); + + // Beacon defaults. + beaconIdle = FOXHUNT_BEACON_IDLE_DEF; + beaconPhaseTx = false; + + // Build the CW message " BEACON": the callsign is the boot message + // (line 1), sanitised to what Morse can send; empty/erased falls back to FOX. + { + char call[16]; + uint8_t n = 0; + PY25Q16_ReadBuffer(FOXHUNT_CALLSIGN_ADDR, call, sizeof(call) - 1); + call[sizeof(call) - 1] = '\0'; + for (uint8_t i = 0; i < sizeof(call) - 1; i++) { + char c = call[i]; + if (c == '\0' || (uint8_t)c == 0xFF) + break; + if (c >= 'a' && c <= 'z') + c -= 32; + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '/') + call[n++] = c; + } + call[n] = '\0'; + if (n == 0) + strcpy(call, "FOX"); + sprintf(beaconMsg, "%s BEACON", call); + } + + // Start in the hunt (RX) sub-mode. + attStep = 0; + FOXHUNT_EnterHunt(); + + // Prime the key state with whatever is held right now, so the side key that + // launched Fox Hunt (still down on a long-press assignment) is not taken for + // a fresh press and does not immediately toggle to the beacon. + kbd.prev = kbd.current = KEYBOARD_GetKey(); foxRunning = true; while (foxRunning) { + if (foxBeacon) { + FOXHUNT_BeaconTick(); + continue; + } #ifdef ENABLE_FEAT_F4HWN_K5VIEWER // Keep the K5Viewer link alive and pick up any remote key. K5VIEWER_ParseInput(); #endif FOXHUNT_HandleKeys(); + if (foxBeacon) // just switched to beacon: skip the RX work this tick + continue; curDbm = FOXHUNT_ReadDbm(); if (curDbm > peakDbm) @@ -382,11 +756,14 @@ void APP_RunFoxHunt(void) : BK4819_AF_MUTE); } - SYSTEM_DelayMs(FOXHUNT_TICK_MS); + FOXHUNT_IdleHousekeeping(); // backlight timeout / sleep + FOXHUNT_TickDelay(); // tick delay + smooth backlight fade } - // Mute any pending tone and restore the normal VFO selection and RX config. + // Mute any pending tone, drop the PA (safety), then restore the normal VFO + // selection and RX config. AUDIO_AudioPathOff(); + BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); RADIO_SelectVfos(); RADIO_SetupRegisters(true); } diff --git a/App/app/foxhunt.h b/App/app/foxhunt.h index e69349f4..3743e6b1 100644 --- a/App/app/foxhunt.h +++ b/App/app/foxhunt.h @@ -29,6 +29,7 @@ #include "../driver/bk4819.h" #include "../driver/gpio.h" #include "../driver/keyboard.h" +#include "../driver/py25q16.h" #include "../driver/st7565.h" #include "../driver/system.h" #include "../driver/systick.h" diff --git a/App/ui/menu.c b/App/ui/menu.c index 5fd33441..e171cce5 100644 --- a/App/ui/menu.c +++ b/App/ui/menu.c @@ -526,7 +526,7 @@ const t_sidefunction gSubMenu_SIDEFUNCTIONS[] = {"RF LOG", ACTION_OPT_RXTX_LOG}, #endif #ifdef ENABLE_FEAT_F4HWN_FOXHUNT - {"FOX HUNT", ACTION_OPT_FOXHUNT}, + {"FOX HUNT\nBEACON", ACTION_OPT_FOXHUNT}, #endif #endif }; From 2569e4649d41ec2977f9fed90c359e2ba4e28e49 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 15:36:21 +0200 Subject: [PATCH 17/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 105780 -> 107256 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 1654b953a7cd79cf992c4d12bfc505b6c92a6b15..1f691bb9b83cf43007be9fb06068f95b526b6971 100755 GIT binary patch delta 9257 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 Date: Sat, 1 Aug 2026 16:14:08 +0200 Subject: [PATCH 18/42] Fix RX mode restore after Close Call (Issue #478) --- App/app/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/App/app/main.c b/App/app/main.c index 84856c70..2ef9adc1 100644 --- a/App/app/main.c +++ b/App/app/main.c @@ -225,6 +225,12 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep) case KEY_4: HideFKeyIcon(); + if (gScanStateDir != SCAN_OFF) { + // Stop the channel/frequency scan before saving the RX mode for Close Call. + gScanKeepResult = false; + CHFRSCANNER_Stop(); + } + gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF; From 2a13c1819d796447853de313ebae9388e2970009 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 16:14:56 +0200 Subject: [PATCH 19/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 107256 -> 107280 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 1f691bb9b83cf43007be9fb06068f95b526b6971..3814cf82416da58a40a5a93a255705d08091fefc 100755 GIT binary patch delta 13146 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 delta 13159 zcmYLv30#y__y0Y!z_1C3D2u=hBLa>JhzN=%i-I`fz9TNF36VM0>npuxXzrO?H+xjl zw6fqeQyGm+NzHOeEwI^^_bTiD)06VFTG9Zs%VsTq2B>-I?Pi;>@?Zh ztzDps4qN-R-=U$K{LhGDx@hee8Kb6nUK~9|8}w8;q|;67#x7@6RLiGzGtwEp48PvIy4!pj%MIN#y;rr6 z-dp~IPw$=-_`Ng0+-68*IWuYM+sNnmj_#3^%-IMv*< zkaZ2ICw;gj$kIkO*{T*U@?I1eAb0m@Spo}?J9=Un84_3(|dH|^f?eg{O~$zOip&=+#$-gJ1GBUS>7g6fXu-HKrPi@>dLrmqKj@a)u5%CPQAy+PE#H>4GXW_(M! zJE+1u|JST5r(TuNf~~#!dB0#|aXxY+zt*doPVv?0nH?s3$jJ0YOE9?nKgh(dq|c^_ z+?-*K@95Dpt!(xfSVBo#xxY=-RaKt~sVCOQKwboCF}Vp-m-xQ^o!Ge=+?+V zJiVXErr4_?+U()$UN#Y@iTYx<3&1b(C6C>q3jzmP)z;AJnYp>%G4A(3La zvH!yq*)=@&MYC2PW0{7Xatnt`>1l5%Y!wgHt14qGRGF0;R?ZUq8nkjb&&|rFQobxJ zhMM@!to|77M%IMzHcrD3W9vG-b3G>o|3l$0yvmwq|VkWc^y=_FF^TnfGoh{VN5>2IvqDJ+uIRG&twahyV;!L zg6*hT&s02erD_YMR@Q_p@{>=xx96zp^~_J+#?uRy1^ng4$!b`4ZS^&^e3G9oD5l@7 z@q=TC%6Y!IkPh&T=0tFM#GKf{?yl&WW{$U{4N-ADo7S-+Hom;A{D6DRBWNHWF~k_$ z3CuhRWBU8gPeo6@Y{)R#cjik9CyU{E0pbe2vqUJv2!VpSB}l3 z2mH6Oh2CSJ%!2E!f`1S#4E-{(F(qG+(y5l9_ngrNGQ?Bb-dsB+vpiTVJ-#m z%@bncTrH-O$kMP9k9f^Ru|1$UrXhN?Y-&+{|9}c>hNt$iMPA zQ$ssQw&W7E{I+LLPGfzK5;7VV)UVdcx2%;@qljv)2dDKXV-18Bbf8@p?ayNV05SHLwuaYyk z_sn>D#FJ*Opx1cq%;^<-hIq3!Y~})%h{GNG1(^NoE#;0=C8_G2BE@d2t7;uh-LTWF zf;nq$Y@5U`Exne(>|&%VgtceyviH~~_9?r}{>yH%r|fMC#Q(RS|4*eenNsHXUtP*IIM9el0)t zQcC^{p0}~7YI%}N`OSAK(tO88#2EOn0gy)fmM#m;H;GTptzjJFyo_GQ#~#1ZFYq-V9Jo1Eht zonobp>9sv)nEzLCb$*0}!UfD|^}Rf{k&GwwP1}tI^IKfcyf7Z)@Hu+PbujWaw&+EHR}5| zu%wv77q#3}T06x_NAu0jjKvP>70i-XW~=3HEy{tvceBSzQ&bU~&Hgv?#Zk|UZWnXo z&FJTQ;R~DZm!yTEX>@qW`)u*%lE$nY(b$>qDoF{v>pWW1HYuf{eZn6X$(YRVmK26= zg7G_~pe@sfE63f)5~}%#((v#vE>f)GUsN@=h;1I$oi&u+q*#@CwslGAZ1N+g2Ml%p z%Oeta%gaV`@R+iEpU>Qi$Kw%Gt#iu!h_3PluN)8g#${k_8|T28c!cxtA~1lDn4RyV zTT6`q1x>&4sn)e&Pk^)`RjA$dxzPY!FC02n$sU1V~S;(Prbe04LvxE z=9QM&IDI~I$JtI2;TACw+)IH6R>m`*ehNdLmTWR;;1l`0*8~wALzCe6GUX z{?R)-lh)bnVvSAJX_mRCC2Y|wb96~Evx&7XbqTMUk*~P!mvYfxZIv(ys zGMbELWLy7fEjywfw^B?6_o?9{o0>-vpP+XtMm;sM@uyV+vDO*~KKACR(bu z3yEjGyBaqC1TlDId5t zE~yJ#E`O-4sM|hq!b+R)cTt)$>#y$nHQzNVj`CwDprVXlsF?mL-@G=SX7gifBijZz z7a3L6m+=VN9;f0$Xr27Q+V=VOmQPV!gyW|aK599JTqPPQxw|b&mrC**q~xx*Of~ur zQB^;yyV7#hsArW-Rjt(h%FXM3P~nucU7v+xF=~A}ea}~~PorvnZ2h``DNc{jdh8+) z@^9e98}g|K-??EHegob!!By@3UOK7x-1pK4cHB!kGKWpFx(t4SXQLe3&jaGQ5H#R2GU>^EGTEKs7 zHj!aBKq5j+3B(9Nbr{whVvDh4D>Fq-jqUn`Q=TAD1u9yr@?`;Z(bAdlE=?{xuUP> z+C?GW;e1QK$T!>?rYOoTTWYB(=ShQ2Slrsyl8^b_Eqk>4-9r4%KdSr)j$8i^`_mI% z@u7icS$BNcNOXa(+LlJ2T90g-KzQMXZ%>2G8n%5d{lbrJuk?8fM__5|F_^hy3bnQV zup^G>TYmTBCitRPJ{hG|OkrDV+NbG?glF%p3}5U~b%htmm_dxO$tT%T?Xk zCDu8ku$j#*GU<1RHw&9HNng6MSv+x$)>nhd&N2Gip!b|fxE#B+zKvMDT2F>%@v6r( zIMC?*W3$-m*%57y-khCaF31TF%j$;-|Kl{WiP1beZg6Fd_m9-KS*+%3J`Yd-)|sR4 z2nN1!-ZFI2pQdJUz{w0I^w@`~+oNW;Q`J@15Lz%AWuH6S6^sG>gkSkQJo5u*>B{?! zljbni^B;^Ig#cc{HY$SH1iGsWW1oUfEMsi_CdPc$Ggh6#*fG?P8&ui8}_5N$gJWsI~1LFGDe&#pLavAspywI+V?gUaWyJ;+d!*8+PfzRV7g z>=|bNs&Gd9saVDb?uqH3b?D$>YpVR^(XQ=!U96^>sf73^U$7@U?Y>>9^Fm!;mo7GD zkXN-3Q|zi;MGIB`{v>zQyof=}sEbufFWU97y;+ArLJZ@l_hg12u(!J!guWTfUsk)w zcpaKQbq8Ztc+}n~YR@zG#s#dfEAu5XWj+_5y>}UX!yoTmL$CA2`=(GXzqT(wFvg~p z$GDYN#TYw`r`IgTeSEOSKqvU+ntt>-54W0WF`sE&N4@z|>jZ?@hV37R3*qzqnStNA z^UO-$yg?l;&EgPm+JD6N`lmQ=;N;Gy{F?*s;r&$jRX3QH1z#EAqc|D3IbsH37Db3TxHjBgj;a9T|iyK#)-8&3gyON0I zKvS~-?*oiaz-;Gsy{a1GS2c?=zTr>|9HV`QmUItqc{xvOF3k&BgqRgJu35a_5`st7 zc!(nrC+_tF(S@aX2~4R`x9}Gack=rO9)iyndzWuG+?z)7GlvbKb&h8PMV9LspZjd6 zbWU}`?~r3S7Pbkj_u%SpS5FvXA80Ha5N0tlOKR9kU&9lTYtMUL^4jx~KKA_QCI5I{ zl45VWOX>5^=lMi?L2HZQvCLSSHwB{);Emt*qc|RSWR9PrrKNd&P&$KubYuyA#*Ih! zAq;TgsF5nZJ4Iuu?TjiG8I!7D3A0@2=#4W zPE60kPpA9Mb!M=&HNJ+&;wCRTT^O2(WhpnzKe5atqjup) zI#M}8PJ}?Mv|Mvyy`Xl`zzjAIm0*Ki^ zAv)Q@^r~1>xqd9qCDVfj%J53Kd-1VISC1p zcVv2H_fKJ{EhyUzYyy;f>F^QKDfiS$^gD&Lau>ae^g2M9)^qi#b~w^z;C){ApB?mv zb;^a`$nPz<^*$SV6g(1-dG>GXvbSP_+vq$MZ=D}MBi%cgYzg*dFVf1sY{mfNfx>^2 zZZxPeu%e>M?ruXqhX-G*2xxF7u+`XMEq^2i@~sz(gWEfIn3vUT%lX&E8HQx`NW9Pe zE`3f}+UZ9e{9MNQeDl3gAyE!r!=jod@sZuw$72kx6HioyE?K-rgRpijWJvYwxT{{Xjv>nM8( zR5?EpkjraWrwjQ$P`Vy~59BZebO6u>=@6hEeTD#E10MpBDC-P#1(JTi-hvu`prN`5 zWP*Wt5G2Fk8K`K)KpE(ihjbxO1Z>0Pb1>=qC_e{gf5GW0MR^JGZP0HX(#d@H1CyVG zB?d4>m|yU}9^}&RJpSQ9*x+jqkI%e??OBYLf2*25dOKlzl&v!qsj$ zXa8}C6?x^zyamc)WfAK(vA1h73p7fs)e^PO-@ISbWXBpZ2Z@!k{m-XZlv-4kkClko^I=2NTUi`3&R_ zLqHm|vmvcS=vJV9C2$e>pMmR0ZwC||>I8-rJyPtlV!Q94J|E-Mg02CU0K0%|z|!`N zA9)&{co1{R$R7tj!9|A;aCmEb@I6gExROoBR=SyyM>lu$_DAUU zvB>28n)?MbyROD+3$%mYgJG5Visq=8+xExel0B%-azG1nqQtWA8GOxtg9=pRb7eSM z$D0i*+sFK7^EZ*xzQtpe&EgX)k#^lrB5uMPkGupLBh)E+~ z^E5RE#ZDijseU9vTtTtA>S==>i8ijO=9raAsJzKD!{Eg-nCvg^z(G;Wu#5mksjUqD z#|4{bigKEkRFm#J80v*nrm(IYzw5~V4u}Jfh0$&oJ6k?5Gwv|5Eg=>rcX9C{dM1km z7u+9w?Pc;o7s=_ib%kwWyCG`ojgLQHyxt^oc&g)g@XIz2OD)aJ8PmYxe6gJOxpzwe z9t|T}Occr&wsh$6r_IEA;YCRqnuP3&viQW2-gns8vDgP+cSyp{21@(15f<6@XQM}S za5o9Hjh|@gL%5`z#y-bwPsBAxTx&GOUjIbA?l!ijAJ;z>Cv9@$V=>wugU?nT@w@YO zqe|ZCzS+16+I8o9KG_)?kcAWdzM^bEHeci9w90C5&C*a^E#jL~hz>}%RTK{rtR{q2 zrDJLuL0zN}4W$v63N$pG=1aRZ6xF7^J+(wrwJSGusw^~i>7s_Z(n(3HrIZkx{R3m9 zO2hpTNYhm7xGWY*1zP%uHcGd(^cx+nJ?2HVM2Dp}bhL!V)Vg$3M4`iBj$TE8uMx~W z#0d)3c4GO`Y+qVOMNTF z6`X}8ao^b_Ql0vhS>G(GX2Zp2xR=Dj9u2q063-kxxMXn{wp2Wnr#dzU@v%1DdR|Om55*7Cv_J}> zI%!@Y^$VV8{}US@>G`8k&oZ)_!~^MgAm!7?l3x%Fq;=AWAo?U~2!!+sgrwNzcOa+| zq<_Xy{|Oi>1qahGN|UAq(+{eDdbqx=!xVV zN@Hk%R2)hvkt02?+zi8$V!Nm0CUs>EGjFP}f(Q#_BvprEZL)MXlr~VQw6Hx*qfXMF z?J1JlOD*l`Prt4RN-G}D1F=K8(SZ!Jy4aOqgF~G6v@cMx;~j4|DmR3}wPK+IVCV>j zOX2(>PM*U3Q_wQ3#uw#ymFYu4C&54}UUMn(F9Qy=F`!(A!`c-zRhk_}Wl)bxVbIL~ zO8vs=bntmQGw2}QPOX8NhvHvShX@+seax=GDgHy66G2ApRF5o9Nm2xaaY4$Cq%!R; z_e0Sj?Te&b3YVTnQi{r}MM~&M9U-5A9cixLw~h>^+VE1r1Cc5n>xfw;saq7Kb$G?G zq$UjRgqlAPf7oXjmer^?JrKpx8&PzoUq3Ku21WzQLKIhDxytmg_R*b~UJrbZvR6?5 zBJd^<1UI=O%9lxtqbZ5D)b5KWBhi<&7h^3lkel1yzl;RhU zKMM(9+JgJyL+PQB!ZC(VCpt#IN@qGzc!1)}{Tu9APLb|Qsi_l9kJ*l-uQ}*IWQp=U z(PwbGlIsy3anGX|%KPH?+SlW#nCNY(p)(m`{5|pblZ}sayz3XmcC>6aj%1g$tZQ2R zmT3wPv!&p83XOC-^O2c?_APKL_BT;)D30Wr-ye?5+(qFHUh04LYK5BR5_>~!&H6J6}xs*YUoNv)q|6@ z&0VR4XofVUJC16!w5K~=h-`HE+#FxwXk^`3z3JN2=o2-;3G9;R#(l9@`Y4G?DMa!~ zhW#5L^-HD;9oE}U*A%d~%tJ<9dgp4*qC~GtSLvScNQo)5n?93%OM$w)Ew!ZJNSu(S z^ng7dDy`^2JJ3HdmC}PBoP>)4+p(fE(|3jV%A~oe6q1zcI&Ri*GKS@3)~oa>*ufKS zmHxhncV%gNTu=g*ofqAQ(mbn!(xlSN&}D9q$aicTywiOCU%C2`tYPAPu|Vq9ldNQv zuJxo*kpcDumNxZ)*lJU>?!I{FDl;eR!&lxHcWQ^FK|um0frsJnHxDTXKswlqPExV7 zI32dO&RJoMU=0zAbJ)cPqbYNq$%fsVC>>9SVeBUPW#D}LQ_9T1K0cI+GiXY1J}ksa ztZOvJQ~n0RDxJ%K03_*Y22DWQVZEuhVT_YHt;=DTR6P?|ZNWWJ=v~pDkx6O_KaN$^13kgjNl=9=g~PX`y1sPAZwy{1ZD2m`i6152k9zy1;&~I$ zT2NK{TR%ET-IU%x17;Y74D>t}0yh)sb7#+%{_eEzZKa1uChr$S#Lri+m&hbp&MLL&78|gb~dN$-aPFj{t zd-|2x17iCdrgl`z_gYHIkLn(XK<5YgMF>DWa0en7t4DC?&*wENXK$v(4v(<6H6*XR zE3Qd%b8xYrlFsG8nHVT7%!O8@Nht#;#rVCm*gSb~WJ%kVktM|iqjD#zeu)Un(oJOs zWrTsYdt!pLYyiBD2hyPdRHWVOcp$b*kppo?PfG&_;vVWM{WcJ0ufODzM>~A-@Yj1< z{XLOWYt5tGYIrcy2IJrikj@OI721pLd%|5i&Wy`8(&m0DzQV)uzNmyo>acb9@m+z? zH&JePlmq5ilC^b@S3X4g;Ctj8+N7FnyTN^xv zE)X59Z5&G%R5U`Wn?OI){n|AXF(17k6-|N^yGa`+Q3tKoEsJnz_arFyUFpgsSgVV* z>S7SZG)$%ibXnRtnXG=Z?W#=yY(l{u@jq$$6s#gmvQMGu*>~}dQ%=GiG1ZpI3rh++4eG|C>1058=P2*0paUWLJK~>iZ+sZtl-sskV_sZSIVnURo_kk# zX*$Gqyg~2a z-dQz``fHV$K9SBLU_-G|%!?Es-HdN70a(IqQRXor4jNvdN2gQ_bw@C}G~-3;Yc8t7 z8x3=OLF4s?}%Tem>IBv z4r$g5iqVd5xr5WOdIrwJ1*vWZ&87WP(oAULAJV9qWQuyzaZkMBP(A{s+nAO?%aTPt;3?UZU3{_uG^fIjt@FqeY%WU*0yM&&Au~hEy<%a<%gz zk_8ezlXuYWfSsz6cF%&hF-AH$i`J;T-O|_+8cKgkJ4;}=&q(J=XtiOSOZm=huqc08 zz!Irp%Zu@i%AXkA6O-+D-H6rF8>QI0A<~&r+>_Cgr<5w_kyP-rYk67 zx`4^g@|)jdI{J+18ulRH8;^xth;b?D9(si5jHkupQD^7m4(MX6z$4&oU?Z>v_z3tE zs0O|S_5%k2*81<3x-TR4g!)1Q)>Aa2+Q1dGBe3EJv>1diD4|sY(ywc%HGKC=uum^a8Sh0$>=>0b^Kk>nam|4XTX!J*W!wM^OCH2UFsxaKPDlxzexN=uHi*kGFVHriZ9oG-ouEOWVW7dFoj^lC6G8Ep zpsX8cC};*~d(b>kg;6tT80KdqkqAe@i=bt|Yrq0vDG&v$0X_ge1U?2n2fhGmfUkhV zz)|2Na299)&S908KyLyMfzgm4t0tWnphUftHUUV7R^TTR&;xNmAUcKu@jw^kGl3z% zIN(KKHc$>IVpd`~s{v(j#RMx?2SeSjXn`yqvunPH&zz$$dGt+JGgOY|})h{4= zIsnYp-mk=aCumw)@0U_%&X~?pQv0O#>XTgCdn-aPoxeW`YXiIsSb)($2G9{;!1WX0 z^@QZ!MiH=R;U7_CR3{Xx@vVj>Bf7?zg~4lN%h?J=y|bhdXhM^u*$OF_Rw*6c|GPsF z3qzaXY&?G7W=oU~d!=Ja%d^szk0>)Z;ncI!pa)fyKTJy8PVw0fVMRkQr_$kxlGb{+ zrfo`^Jxe>0#(PKS1%w6p&gg-|(iUkyAV}J Date: Sat, 1 Aug 2026 18:33:57 +0200 Subject: [PATCH 20/42] Update donors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27a419a9..b201db2e 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Anyway, have fun. # Donations -Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ, Carlos EA1IJ and Brian M7YLF for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 +Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ, Carlos EA1IJ, Brian M7YLF and Giuseppe IT9LLH for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 ## Table of Contents From b972e026ca7e33d98fbc6aa5987b38a5a6fd5730 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 23:40:20 +0200 Subject: [PATCH 21/42] Enforce TX gates in Beacon mode: F LOCK, TX LOCK, battery, AM (Issue #478) --- App/app/foxhunt.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++- App/radio.h | 3 ++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 73468ef2..12522aae 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -365,6 +365,17 @@ static void FOXHUNT_IdleHousekeeping(void) return; gNextTimeslice_500ms = false; + // This modal loop bypasses the foreground scheduler that normally samples the + // battery, which would otherwise freeze gBatteryDisplayLevel for the whole + // session. Refresh it here — every caller of this function has the PA off (the + // hunt loop, and the beacon idle gap, never a burst), so the reading is not + // pulled down by TX load — keeping the status icon live and letting the + // beacon's battery gate react to a pack draining under a long run. + BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent); + if (gBatteryVoltageIndex > 3) + gBatteryVoltageIndex = 0; + BATTERY_GetReadings(false); + // Backlight timeout: switch it off when the countdown expires (both modes). if (gBacklightCountdown_500ms > 0 && gEeprom.BACKLIGHT_TIME < 61 @@ -450,7 +461,57 @@ static void FOXHUNT_EnterHunt(void) audioTick = 0; } -// Enter the beacon (fox) sub-mode and transmit at once for instant feedback. +// Evaluate the TX gates for the beacon's TX VFO in the same precedence order as +// RADIO_PrepareTX (F LOCK / per-VFO TX LOCK, then battery, then modulation) and +// return the matching VfoState_t. VFO_STATE_NORMAL means the burst is clear to +// transmit. Reusing the radio's own states keeps the on-screen wording identical +// to the main display (VfoStateStr). +static VfoState_t FOXHUNT_TxState(void) +{ + if (TX_freq_check(gTxVfo->pTX->Frequency) != 0 && gTxVfo->TX_LOCK) + return VFO_STATE_TX_DISABLE; + if (gBatteryDisplayLevel == 0) + return VFO_STATE_BAT_LOW; + if (gBatteryDisplayLevel > 6) + return VFO_STATE_VOLTAGE_HIGH; +#ifndef ENABLE_TX_WHEN_AM + if (gTxVfo->Modulation != MODULATION_FM) + return VFO_STATE_TX_DISABLE; +#endif + return VFO_STATE_NORMAL; +} + +// Refuse feedback shown when a burst is barred: reuse the beacon screen layout and +// the radio's own state label (VfoStateStr, e.g. "TX DISABLE" / "BAT LOW" / "VOLT +// HIGH"), same font as the main screen, for a beat; the caller then falls back to +// the hunt. The RX front-end and audio path are left untouched so the hunt keeps +// reading cleanly. +static void FOXHUNT_TxDeniedNotice(VfoState_t state) +{ + UI_DisplayClear(); + UI_StatusClear(); + + GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 28); + FOXHUNT_DrawStatusBattery(); + + // Centred, gFontBig — same wording and font as the main screen's VFO state, + // on line 1 so it sits exactly where the beacon's "TX" / "IDLE" text appears. + UI_PrintString(VfoStateStr[state], 0, 127, 1, 8); + + // Bottom-right: the barred TX frequency, so it is clear what was refused. + sprintf(str, "%u.%05u", gTxVfo->pTX->Frequency / 100000, gTxVfo->pTX->Frequency % 100000); + UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); + + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); + + // Hold the notice ~1 s while keeping the backlight fade alive. + for (uint8_t i = 0; i < 20; i++) + FOXHUNT_TickDelay(); +} + +// Enter the beacon (fox) sub-mode. The TX gates are enforced per burst in +// FOXHUNT_BeaconTick (which runs immediately), so entry just arms the state. static void FOXHUNT_EnterBeacon(void) { foxBeacon = true; @@ -610,6 +671,20 @@ static void FOXHUNT_BeaconKeys(void) static void FOXHUNT_BeaconTick(void) { if (beaconPhaseTx) { + // Re-assert the TX gates before every burst (RADIO_PrepareTX parity). F + // LOCK / TX LOCK and modulation are fixed for the session, but the battery + // is re-sampled over the idle gaps (FOXHUNT_IdleHousekeeping), so a beacon + // left running stops keying up once the pack falls low or over-voltage + // instead of transmitting blind. Refuse, notify, and drop back to hunt. + VfoState_t state = FOXHUNT_TxState(); + if (state != VFO_STATE_NORMAL) { + FOXHUNT_TxDeniedNotice(state); + foxBeacon = false; + beaconPhaseTx = false; + FOXHUNT_EnterHunt(); + return; + } + FOXHUNT_BeaconDraw(true, 0); ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); diff --git a/App/radio.h b/App/radio.h index e6ae7f01..5d53b399 100644 --- a/App/radio.h +++ b/App/radio.h @@ -149,6 +149,9 @@ extern DCS_CodeType_t gCurrentCodeType; extern VfoState_t VfoState[2]; +// Human-readable label per VfoState_t (defined in ui/main.c), e.g. "TX DISABLE". +extern const char *const VfoStateStr[]; + bool RADIO_CheckValidList(uint8_t scanList); void RADIO_NextValidList(int8_t direction); bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList); From 5437bf2d8eecd512ac9124ba220cea1b4f07b1b2 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sat, 1 Aug 2026 23:41:34 +0200 Subject: [PATCH 22/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 107280 -> 107552 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 3814cf82416da58a40a5a93a255705d08091fefc..a2c253d894646188b3d51d2877675f90f4291913 100755 GIT binary patch delta 8620 zcmYkB3tUvy_Q&_yGYsQ^h=2qm>M(;m)p#fwJ|Z*)2Dxfx<^%DOqNYyTEh-Z-HM26~ zq(>pmeBdKQn~|n#Drlx+;J zeaR>NpDBgbOa3v_d10HaC?-tJJ=M15@!^~Y9k6Xoj8*eVwYFmeu5uoAz_vAIJMqc2 zwyd;$JiM@$w09zz0qZc_f^>ihwGvM+=POY)eIw@uwNm=y9{$2HTWW??#mCl4O~b}> zORX(q_$U>mwBpHB{^bGN7fUz&5;RGklsYHc0av7`=lEo!yJ=hjig`@WKagUoT3L3vyo=7_(>5lfg_Yg?W7z(2xqfV7H_vGb70#^4$jtgP;0B6ttGB$vwit| ztBQAb+pP2QINh=N7K{_c()fj=bT1quZ57yg%(i{uK~8nj)0P_1R`+5C=Ye&$QA;oR zX=Y>RgX?Uuug+2H{?bW{vW;(Ksd!wwbg8sAU)U~rN@MAU6#eE9%_11*+5u_in=Y!e zJ-uQY=khL_b!9qc3Ja&8FB4FTlqSjickJrs{C+{ z5J6>$Jl!f~l%?}TtF)vnebmU$NlWI4sg}`oql}on3g%SjcAvUAOXZ;ChwHPAEqtSn3nw#fTFnm~llE;o z!qeSS(dPBsxy$C+JXl4SY-w8()IBRP-Kx$hlh#rb&eW_c%f`lZbu~(_d^(0_9J8JJ zbUxPz<3dm0iG^dhMZ59|3$Y!m%%#M2XfHgW4)U`^#=e7`ynwOwn;7e|p0T|tj2%b$ zYqhr2JsqN*l)5jUzgTNqu}?#MX02`QXRoP}=63iUOg@@`(;(3GTt}hnX zF)*z$fyE~Wy6peelc9euz4%3su9e7%MtLxDw%MdF{D^1PO6B%!+AiI&{~v589saU_ z`@1FmznVyr=x`6ZDm`*|9)Gagw&L(6&NV(;)X^|bZMKwJ70+;cEl0Z>4NR94;L2&| z{gsP+Sl5B-{_JOUUzKUvi06A67&oeOR6_$?kGEH4DGg1|O$SN4_n@@s_#7TlDP1@| zKK6U>U8jEzrT&H$21YSMI51#crB$RAff^5eQni$SBAs?it4=HqT{FtB!AFrDa<Vnzj_CGwzAfr3APRNdG+f z7&m??Ri8Y^%dOJ#Z_0T8N?XXOM4}dH*y%^R4HI^)Dea8-0M`ZS_0!Sxjcv>6UhoFD zbmUAFf5RnzF+t_v`)8@b}Lr!EcD5UnJJahv3djT zwEa@wozwv?eXFhc?0Xcr*H>yxVX93!SH4er@4Jn3T{3XxQnjOTG~Y4ychWR(_Q`dY1Xjc%3FFK1+luEh{y&m3qftkf-z zu?x_PG5lPtvOgQic49hLz%R&e#IUu{w}Bg#HtXe7;){K@rYkEcu%JVDPEK|goD0&+ zSGQ)|LW8&Bnc-a_fiR)i*==AXbTMEG))upuv|TWfS7FlNp3HE+Qp*2j6nE{mZTuxf z72-nCMl_c|AxL#=n3h3({>)`vAyhE$0uGz(VyT9rXI7O zv>!v?0vs4-FXRs31Ow5nn4{=667p>+TPr)FN=2P?!Z59%bgDqGNL+6DkaH69^ zG+G4xpWrQU3WLj-#1Z6wkIDXko&6B`>yZvZyDiWs9ha)_zsE;*NJD=gpRDhgkb_g( z72e@fy0q~mO~be`L3{gU&3-{pw}bs zhdq++4+GC@m-_wToj4A=wF=zBvLr0$cgR^t-+~l@_b&7$;0DsKL%JaU0K%CzA$=3N zh_ovwVPB+$!&O#E%O4o|2(PsLK`dY8mCim`!p&Z3_@DXQBarNvxr!dFkh~6uZKViJ* zk^dgjM__?|sAm9Qg)qb0C|?5@(hACNLKnd)d?^p}75*d+9C0Xxpw4LY^9$hBK+QB{K0p7%KwlyU70*Q4(CEHuo&{C8->$+zM7PY18Q7qvA-vbyDIFuXDpr zsp;Wi%{$+~xxSGql`PF|bnr)&bYD5xrOX|;SBsUdlXkbdahH^~yHk4$|NCqoX+5Y{ z0KYtjMF@ut#9(~C^uRq>t#!T8Y8&7gzERJK7FN+1>F?_1;RC6{X}xK6MeN8LeX-Oy9`~E` zdVg1yI|EuW^LOo*FZ$CbqWNoDTF0lkWnCAVKsV*-UC13?jM!gfVg@HB@H=*(hhGd^ zd`e!VL)BY5uxa2i$0ofW?51+>M zewz+jFtjyoT4)uW|2MU1Tvcu2X7;0z8JbVY!viUc{w2Q|NGY^UwguA9y!^CW)|FQ9 z?Wg7NAQ~Q0ej4{!BR2K$i_j!9k4?4^ziU1Qeh5HYJ8zo?; zMD0f)MT=gL3(!LMW*)K1OAk5q?mqpMhe(SV+ zDS~ElO}%}1BxzK*`r1cDk(&5WpPbi=me3)&wim4${yZ8l18O{AQ!$-Z8j; zf!)aa2<2ge&Lzdb!C+<@`*&yuw7Q`T8nZ7eh<tC!Em(sjPGUj8DEh6a?oGx4O=Wc#@`$n9~I7XG@s z6uT6NjF&r$bkJUO+egLIGQ8io?I#l`P{o6)<@5buxA1!V!+wMpTG(lLGTjlcBywUJ zrH6!L^ds2Qw`1{Y3|*?XFG-^eRnST##^P+fA*@m_A5Nzx`r7{KW7LyE79$wfhz2MZ zH`mMi<#U56wzoKsi(t9=pcv)JeVL(intRl)0Jj|SI5pB%``yRsUp)CP`fUXRQSWz1 z(U0g;JWEx^(&+u!D%Ybvp;bXk^x1zLN~uKa?f%2*G3wgfKA81}1xk}uuKTk233_UP z=uH7;j6N7W9S_AF5c>DuefM1&{+h6&wa6#T(!W|h_5_6oi6uXa5e<-6tL5uY(4~-J zC@;p!vLR#Rm|=Xi{ahwlh`;2OGqWgy&-Kcav#^t{di%L7nn`?GwLNttT_8TU+O8W# zlR2N^w$I6iW75y|g=QK=w8_3BkG>_c%8T=99$rE0m+~o=_`+(Lk45w^YquwlrDEcZ z2jqR@$O>sM7*E+mb@J|~X$qCuRTHQy@#cDa$TKvR(-r&TXX#%W5qOCObcpDI{L6G? zyo71**e!1@q{IQ@((y6wW1qk*;!3*`y0{04*zAY0<*2(Fh-3VxD*0g{#fHY86>pqT z=BR9aag;f-xJ7A|N6(^lhclm&R6DLvrGoN2zL!XLpo^ZhzB=5nANb z>mMpvZp+a>mFL<5ayS!p%3JT@okyx`36tw)z~Evy@w9N&tUBn&R3B38L#4*^Q2D_V zWnxAi-9MWowlR%8RL;9~aX#e}Ut%8XKg^NFN)QF{*-U<@jA@NC$K~jY4d{OcW_Cw0 z%6(?iBP9pjz0G}cdKOKY*Sjd0-Bup@lJV}W&$+EE@Fg+MB5@1xC{J`YVVL&v=n*68 z^~|U-8Cbpbp|Y&i@1X0b7%G8v>l~_EYfz4=T(pX5RhdLSzQ)LhoNw(V?fXaw%dUmo z083s;`tJ!NOurTxAAsN*zZe>-Gu*V^Q}%oBDCA}R9ySCYmCwwisuD{L>#NV}X*Lx1 zvW$o_St8AutS%xl=Yevn!&IzFVi)^b@N%TQ>*2B|{T5jWndf8d}Pd zsNs%sr>&b=U(6B%8iMcyW=Z~zt~mjyjjt6++(APEN-alqX1%4&S&wjU0vzZfnf&c6 zN-??HX7{|KJ{C;|pR%#z zo^r{<`qecU*j48m#LGUI;5{G?e^<>12k$6@+wLf(ZS`g{On#lk=$D=`pUKroJ&V+3 zp@pY&b^AjLn-y%A@f&jj(_2oOyJeir_Lrh8cNH7HDcoC{H0`wfWKSYfxfqh7OK84G1H1KWYG9_%CX{EX8seEPhg`XB)|^CU z&2}r_bTH%RSiVm=fr)?YCgTBfgk_SY8hQKkQ;JzaP{TG;sqwPkcve1>40n{1zGfw` zl?=_wbayv+#IAn~fmusf!)yO3H}@)L{aM4!YaivA;Ajy=50p?Ji}!PwisCzOZOrlZ zwerq=80gR>l{A`)2BwKN%Ni1xuwHBXJtfz3Ps#Aavks-ZyIG-D55A_n!|p2AJ$Dto zdzE?0G?v5~-oK`2GcqC*XEYkH^wlM~6;oA`s)8lWZP;eWWIm<6g9iO(W${gp;%hwS zq4IVs^?j)9Z2c>gUKgRXA&IppJA6Ln#dfXfmF%7HZNnsdB9TOXpAJpM($0A4RTPhS z`MDh*b=YFW%lP(1V>mOhMF?xR(zipDmNa$zZ^$6ttu4yTjz;0MmJCO<6Kltm5~w7VtB7p;Dqe9BuLEI!I{7puLitZEf5c}MxJ zL+sYtR%Z0CNXgM#x)f)bBQ06j;k05Yi!}r~hY0D=I%}MFmHDk>u@TeJ4|5baXKPP6 z+Z7KE8dLEsc>nvY26%s3%tLN$5h-kslTHz4p)eP3`(4OF%9m(8m>1PI`{cK zM_e8=L>K#%KOO>$ z8XJdME;t8Sess!~xfE9NF5>9SHpV`|>9GS?kjA@`;eX?-1Me91cy5VfNPLqJ_Zo2= ziIc~H{C7lsAYz>i0ZH11kIfa!#c7e5m5DuC+P=}5nbquMrcjFsYf&|j@go?k(n%u9 zOcs{(X+sOFGS9cZ(<*lruTNN|N2gUnV3l=lLvcua*T&mQr1#qkfq}Jw;_uv{Lpq4& zX2wiu77;bfk==AxIqO!JFULFH^1P6B6%!*O-Y~yuWql`4XI4Y$iY#_1qVzQ!VU&8_ zTB5gvCi-7|WlVAIfHm=@@AT|m%8YtTixTE*QBr+I6G_oSm?WMRmh2WK1+SF8w#Be4 zVW?x*7G^KX(HY704>vPiFL)tGx5up<_c9ZY)-&Cn7G+kuZqIFHS$o&$Cr3P=uTCLT zy_Ff05e%)~Ddw3utf23->8wA$QkcUWg*gGn!fbLSxC`+Rdc={)rsE0XRyKPH53Bij z9cWR0_ToF8GNIkyRP^7c33WbAS`>$OquKj@$Bb# zXTxYGrG+BKX0>HGr)1rA`jqwFVNRo&87m5+b3;qveWin(F?p(JLop@aR=)L$V=mfq zxdbO2OQ44GnX%6D8AA>Cl=H0&QRHhkb(*oKGt3wRcX-6fqQlH&jI?YsQOadMUrL5$ z^UOXueau~oA`AV@zd11tN0u`%J1S==9`oY(7w#)uReZ&(guWAO1>3#1W!trPbA-iC zwP~@pZ+qXsgT0h>(UY_co}%4@-8YJ}Dh#hW!shRnq=jErv8iaf<(ek?eVFFCHcDnz zRa94OL06L|mc?DR`bmD}ZPxNEc5(eR>KkW#)uf4DlFiC!LyPh>x=Ju=q8Dc~r1rtV z5{!w_3p-OgI#c=4^E*=?ccvCa7j>pKc<1KM%?m9uhZGm(lus3o@j{z$p#E~neCpBv zh*w=P9Vc?nd3}loBb&DkW*u%_*(TRrEFb==iI%Yb z6Q1F?uwmmgkT*j)~?c1^R&UUCN4C;qL1j(IJw!TKEg2d%HAAEq9)(<|DSHDgf;Zu>06Yn07!$1}o zwcCE-bt>2KPdCU*R#QRjZu~^L4;%$2z-jOuXaE<$74V;3_J^zKaJQ1*kjQ4;7%|4& z(3h&IQx8VZJwPuI3myf7fSA=dFcB1hdEiCx3U~y4T*g}t1iJ<)`n(6pAs;~Ew=E{V zajGFbNc%BX!aAV%Bf}q$7tt~ZvJ0dhQU@6e8336A83;K5G6*sqvKwT~K5PMGCeqy@ z^B_YZ$3fz^N%jn656D8uaL7fFVxmhSBQQRD4N4?3)lX$2baJD&;^4Tz++%Ecos|t3&E?PM0^tY z`;-3~=<9&!unbZLTYxARv)>6R1{Gyu0-|0O^h4kn_!hK)OW-!R4?IAPiG_haK(rCx zu7&r)x=EcG;*+2Sh2k4}8sy{P3Gfs!17YeZd+if9)5~1}}!7MSqvYqZCP$GPa80SYT}B8F>-f^KED3wW6ORf7cCW z5hxzZCgJ}I_LivI_;;C>3CGPwDPwQ46{4*9jC}PI$_N=-|5un~LyD-#td|qFQEb*D zIEg|rLs2(M=zjj4xL_=VZH8V5Cx4FL3DSME)fR>MS(_DY8 zKLs^4G+&U;s8gDVsfez+U~b_fVIQ`6m7`vdon2WDou=@tV#ZowAU-G-$&n9Q+MfWV=wwZ`meDc zX(iv7$-J@6IxD8TnzvM1i{ryM_f%TfC&sFIPPMhV?+wlatE^l4Z6}^rZOuyE!^1{Z zleQ&-=`ar6uaNa%c(ugS%J{p;nzo+vf@&#kU>h$yW=+YksCZ_z)coRTKBd~4F(g|B zDJ>nE!gp0!4-YL+@lUHH&C7XVnW)x)D*uP-_Hm{=8^&})s;x6$9!)%>S~`+#;0WHx z4&(k~k##&6S8es=#F9GH(d@Ox=haZSkGG`%08^ZKKt7jrY-&`AA+9LY(dJo~KZ;MR zmPY3rLI)Kpm$$G$^ca#^>$9_-7rtEH+*X?%FKwRsXJo>gsanH;Q&IftSlhq@b> zp67IRtaOJQtH~aT4s`jmk*GG z=QPdgo%@PNmPWso?O%9|w41=^$E@4m+RrIndewYLl=Xi*gY))kYxcscKAJI@d3M|y z`{7Kr{~tPOk+%MCSt|ZTyL7cQn%`-c+Dc<-f}~$ENHYn>sjrfzEpbq~_0^>lIbTs> zwS1CBV$xccP2*##rGn+n5Z1I6=TJZLW0p0m*AaJCS$OF(a9O?H&?2Bv$OrZM{DU16_` zTarbM<1FS8G)TF`bZvID_h4NXhj&RS|GLGeRa?W>`*Y!Bh7HSk#W88mhVOWlQ<}AL zE&r*)+O{!WMWd~$n-kPM*Q2|eI=f6-^Pw=NWVJ7)jRVju^8orC+vsZo5`y+HfZZU_(a_GM?{+Ywf%Rj3aumho!b;Jrkv2wJ@b&XFSo-4YH)6XWht4pNX^~^M zt9w%j@}#3CRRMlV=j+dsj_za6_v2x9pT>Byli5d+$EOlwGB z@yUUX=l|4`p(jXhAMOzpjTk-BLl6^gl@9w5Pp+2AY&jGu{bKtsY$qN0W)d%PN|E0- zQ-DNAdeB(unIp6Lt)14TM>cR??6F22>&|JRwcl|S&v?7te5|WM$NX~x94Fd&ALR;v zF{r<~5Bpi&OJ$rm?9HA!#trIR)!+cff%bh_N<*`K<=3R$__Z|u#7wT;A^mt_bnMIR z_w2s8l=44}FffYg!a&FlOz&ROiiH{uJ*QGC_&$xEla_tIAkgmiMWc5k0vxy8>rQs( z4{TD{$2^Or<8VfIN#)y7N6}MHWZ~}50G{ZMlb?;9@dO$hg5x5M^V)J&l))7nWqqhnaqb4_0F@{T*9P!?R2$ zd^QHl?G(17@1ehnswaaf$lJD$w68-ySZTd+;VQNqI7CC@fI7G~YxjEpg``YWGY!lD zn-G>zrD!IgoR_W3m9nh$z6LG&@tPEI>1~RV{&C65kGQRwKZMiFzapRLMiI*8L5i+@ zj`HszUd&leC25<`RvF?pf(<})_wsSl)HQm9G8$3f<9Md~2y!71CKNNfRUEv~MT2^bt@|$0x{&^%SOPtn?#2$O;AS>&+G$;X zGgKAYgg!18Re|+i!91AcTUGqw4r$IWk^GGl((+%TA*?%pxyAF|I6>MkP@oP|@ilCj zj6r^da3Xfb{g6jN?;6skBVP@4VMAfpGW6pN!cQHz_X+7z^LGA)%lf{34Ig_ENxy(P zbiF&A?o;TiLA{uHND2G|Vo&qra4_OD3<5dmH2p=Jfclba)j%H&49-3r z8CKLrRQPlnW6(%%Kx7T!nDr-5G(o(t)Kdm76?T=!4hg&-L=pBC2Ee-j-fS0?aHNQvl)oy9e z@3VT0atFs6Swd>hB9`P+KOtAWOY2}#+~bji9sTk1)J59yxV$7Dbq>MRvvZ$99}i&l zUWYt`_TEJNVuZhg1)`8I1RM=zx)n%Y2^>hXgWJ%>;uO9#82uIgBsLteDRGn;fqMRf zd^KYv%?ZY@Ttk-l=eaF>*}yHcWs|CR5? zH6Hm2;Fr}HgmBn)gdgpd9=X!hzK&L}wQpNr&iQF+QoA8|9Ngh^3}hp~F0rOP#h1@J zEq||~3<|P!sAw*yKJsi0z0NNqT0_nKR=dQFg_So(_&Qd&cz-IlTW(t%;a_HrxKe5u zjr+}|NMA>cD+5|G^L0EYU-6|cMDayhTEqYAl>Pl^3>C_g{m2zI3u}MAk?HK{z;Bp= z9zHQ_@@aX#Ke9G{DSP~>mK7b-gE!zVqE}6Llax{+B z9*x7t?GJ4wH0IVq>(==@#I13}xW&!vvVrMtpO%LNQWo`-mjqHj3YV>c^fO;oE3XTp zrF>nj92QJNLRZz|9&6yHkjzXLKHfZHX{~K$Fx{Z=yY0+4JG<1N&UvVO?3!Zm>Q!jy zM!Q@XLK~uIU^w$I9I?b!VMw!}{|9USBA8ii3++mIYTV~-lX}n*K2|I+kyE&TFSt)eHY9>HDqMYS*-@k>e$XT5KTGdWZ~6GMv~0+0C_Ej^1EK+OR*UtUj*6pW z@MQ?TLfj`vUj#k}Avh7E5Wjh!yfm8na?3uOC7KMxYpdiRpQCg9XuG^!M|1e_IyqQR zG4zg{s)y0vkl)nPhZJSIsV7`HOY7uj1C{Y_>g1(HTFy)N%Kpg9FSN}+)ybD)=@$RIPCgt*g9AccnK)@RIX;dcxg(BJ!+v*` zVwM6C@xUpP{Gr`-+Op$mF`9PTP9;#FihK6SmwLl)nmXH)-h>ZY*l9>IwTMp=IWd*e zLN#dpJIv{dSR5G8Kd!UAlS&z?;CB%ig}wC$VU;@hNE$WMAltSVs3(O^#^PIv0%MRa zZm$2{Ctpmb*l4jI&w}OVfFh(P_hP!vZthY$K6c8X1F4b1Z1)Dzw>ire;N4}eo zq8?GFI7?NAQhjBP%JG#)X#1dT_t-8ErW7Kr&36dBKtc05(pfYtP@1fA%#=+p(aU{B zZFXQn>*=WJL^s?4p5#E;OqW$@yO>F4;`iNhW)_9>n{Ii07G|=k&UP`2rV$@mX-gSSKN5ev(&nE{ z<2k?Lw9U+cW72E3w@fsED8%+@H%~~5eqMI5*;L(Bj22i zh#Ba%v{T+Pg%bOUOUEYM$3DZ5#g+CG=;9tE)@Bsa<|FU>Ky2e@_R3GDP;658S+R}# z#L!@W-EGT#<-Lv;JZn*=x_phphG`LVHu8y*<}x4qT^Z>P$mLArStEZomGnuXb#Zt& z4lUd7!&LvI*eA;FwkOJ&wkRVraDAT~lGyrG_C%?buT7q$6|hDwDlQjI#(_ zN!pau&N?1DeT~KXVZ+WwGK0pbV`nW-6tmN3zvEacE5XNRmmDTPQB=<07jso*qFA_7 zWfTc$Og?B|xC^%?1caSeK`w(`#RWucH)0+ZAzT9Fx@olUweF^nLy<)+QCH6lk>=36 zZYx=me|^{7vn7KQG>tT<+|sR-B~e3*;&ca^M9zSQ0359>$+sS#p~#JAh$LQ5g91uJ zj`^A*&2D?M{BSy@8iU$r^lVY4xFbhaSdxn7n(r&=ZSm%A@$vO@i$2ckRo|kVlSj;; zK|y9O)057t9QNE-9>|}~pq?eG_qQnd?iS^9_ctcejsJ+nL@u80MA6*VCuVobe7)8x;FBIWUw&=mi~hgYb7m)=b!4Iz3=+@8_l-NtOl zQZ;PJ)$St4#kS44+C7_dTuOt788%_8UgaYCyvs#~GE=yDoOvVSHvDB^5laYe*lH{_ zT=N;t%BGR7MXC2b#ypYku`<^cgsEIRG6^w&|Jf@9dtUb>CAmUCgMG7MoOM<%KLMqdu~8Tp^9RLDwvc^R^VSzRxsl z)nziT(#5MPr_^f}mBiwk>w7gtc8>G@l}MJH;g?8_Z|B+V&nNxbkP=%Olgf;lGqfzJ zt)BI!hOH&KoAyygwG^90^;=Wb(mkb*OTEFXG<#Tlbp1WWlfO+O1j5vzo*=Ej>2r$psuQh8QNOA2kxDh zZ!DS)7g4!%aFLS0`swfyKlsSM+Kfd(NeT5v9GL+blo)$uP^aPY?U|i!c)5OPKE5@I zyvmx6`^sh4edUx(SgzbTIImlg7=O2<$i{A%s!<-V64Q}v?>dN*t~d5IU$qZ0H`+-T zkfd$UnaYcWn`dTaTD;10C7$#4%&fY zfA)KqQ}jElv)eDB+Zk=TqR{w^#=FXuc7<^o$Of`|;OS2rYr@Y9e};9WBXL&|>r`9~ z!Y<>NSiE&x8T$w1XIQXOrR@1Dg_V4ZGol9k9q}sxGY&F$I#d18=6gzR8!x+o511SI zp=-*=hKK)bT4G_n#!qGzUFp&+b~U{83YIaYT(U%(yCwQw`Dx@&d3{&Lm;SwH*HWT_C^{jlDu_KT*TB}J6P>W?*D$hnZ~Zy-lD9P-wre`AHX zluSIRaeXAy?rK$Tb!d0pRoopx`k}*47pVJ@@vMazl3AG1S)XU>6InGjM3)kdhd5@KgR5?SaXK22DTxY1D!<3huKh_jl zG&Z-aP)u5{&Pl_`F_(JGeXoO;kHl%&bM|wy(lM7u-RUft<>ItVcBkUB9MS0<>dqpk z+kIn;_2yxIks7#)I4xV1q3!pSliquZ)ys4p$|_GZc8a~&g1%`AGqISc$wpR`%C6qM zV`Opif_XT|m$|ze!y{`f%d!?<8esn6jz%xR9E;ouxFFnV_Sa8DXrbFLc`}|%#f#uh zEV~M@1#Aaf!DcMc-H`9$Q*|UhL&YUjyb`8EH-J8%AFhJpY~G2qeZT^+?qAm7{Xw@G zbiNc|?Ta-(3^oNJ_ zzvE}Z4g72?zdGA~F8C{kK z&8JrSS?;%hB6ya|mcM{P{ODWT#3K5gG_$wCDBI+*i)bc)#U)oSq9?&o7?(iTDdq1! zqS|0_NgM)7@NrhMM_#{}GQ#o^eg?)J1lb3qfV7>q=EYRz&;R+kymSRkik0zLUj{0H z1=zrM-~^}z=Rre-O|z1YbSe26fgIL_5o7Ew^o45b)ER2_0YM-PJO_FK(W{{#8x(*y zz*O*8@C@qsH*WI~tR7O-c^#5N-h#y6aF}?@Q$w~O?88_IdjQ235elRz>4Efv^v8Y9 zA2JLw08$Sb2pJ6-3>gdA1+x2Y+?OGf5$*~(7_uAWP)Pg@j=c=o19B8(7~~{K(b4IU z;b@=Dff9j;MUWqZRX_rpzyPoVRDpxw2sjQ-fpg#@xC|P>O>i6B1$S`ad0=xMDbQ^giHX>g8^U= z5T-Wmvdt``_qqQzL{x%r_u85_(W}(8{|f^LzB#Rb8td0T1OHP~ZFyU03&mbPgUtg} zfR$h#7zO%+aL`_hZk>^Xw^Ah6osknEGX^7Gg(rBH%+lc#W`-|Oww$dHt~~B(T0Bx2 zn}t-ymN9%^F!t^lxmeV*_KaL6>e=@+ZwL!V@+dYAzn8L)Mc%rnX<8;6HwUSVEn!PV z+U+y)gRPVinpyY9GD(LNt0K8h&e%q=S-#l(x}k?6Z=le9d^`0Jp|d~q?$9GZGzbsz gpOJ!PlnC7j;w$Ct+i0}Em{Q>{MLTSsZFr&hf28Y{nE(I) From e9181c22876d854bdaaaa97a83fc4dc86fe8c8ed Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 2 Aug 2026 05:01:20 +0200 Subject: [PATCH 23/42] Add Fox Hunt signal-history gauge and persistent settings --- App/app/aircopy.c | 5 +- App/app/foxhunt.c | 223 +++++++++++++++++++++++++++++++++---- App/bitmaps.c | 22 ++++ App/bitmaps.h | 2 + App/driver/eeprom_compat.c | 8 +- 5 files changed, 237 insertions(+), 23 deletions(-) diff --git a/App/app/aircopy.c b/App/app/aircopy.c index 8ff485e5..b9790346 100644 --- a/App/app/aircopy.c +++ b/App/app/aircopy.c @@ -90,10 +90,11 @@ DECLARE_AIRCOPY_BANK(1) static const AIRCOPY_Segment_t AIRCOPY_Segments_Settings[] = { { 0xA000, 0xA170, AIRCOPY_WRITE_BYTES }, { 0x880E, 0x886E, AIRCOPY_WRITE_BYTES }, - { 0x9000, 0x90D6, AIRCOPY_WRITE_BYTES }, // VFO area (so scan-range source frequencies are replicated) + { 0x9000, 0x90E5, AIRCOPY_WRITE_BYTES }, // VFO area (full 14 VFOs 0x9000..0x90E0) + + // Fox Hunt settings tail 0x90E0..0x90E5 }; -// total_blocks = ceil(0x170/64) + ceil(0x60/64) + ceil(0xD6/64) = 6 + 2 + 4 = 12 +// total_blocks = ceil(0x170/64) + ceil(0x60/64) + ceil(0xE5/64) = 6 + 2 + 4 = 12 static const AIRCOPY_TransferMap_t AIRCOPY_Map_Settings = { .segments = AIRCOPY_Segments_Settings, .num_segments = 3, diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 12522aae..37fc6e27 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -40,6 +40,23 @@ #define FOXHUNT_TICK_MS 50 #define FOXHUNT_TREND_TICKS 20 // compare the level roughly once per second +// Signal-history graph: a full-width scrolling trace of the level over the last +// seconds, on the same 13-level S scale as the staircase (FOXHUNT_FillCount). It is +// an alternate main gauge, toggled with the 2 key. The reading is EMA-smoothed each +// tick; one sample is stored every FOXHUNT_HIST_DECIM ticks, so the visible window +// spans LEN * DECIM * TICK_MS (120 * 3 * 50 ms = 18 s). +#define FOXHUNT_HIST_LEN 120 // samples kept (also the graph width in px) +#define FOXHUNT_HIST_DECIM 3 // ticks between stored samples (3 * 50 ms = 150 ms) +#define FOXHUNT_GRAPH_X0 4 // left column of the graph (frame-buffer x) +#define FOXHUNT_GRAPH_TOP 27 // top row (level 13, S9+40) +#define FOXHUNT_GRAPH_BOT 45 // baseline (axis) row +#define FOXHUNT_GRAPH_FLOOR 2 // gap between the level-0 line and the baseline, so + // the lowest reading never sits on the axis + +// Main-gauge mode cycled by the 2 key. +#define FOXHUNT_GRAPH_BAR 0 // S-meter staircase (default) +#define FOXHUNT_GRAPH_HIST 1 // full-width signal history + // Geiger audio: the blip RATE tracks the signal level (faster = closer), the // pitch rises too as a secondary cue. Below the silence floor, no blips at all. #define FOXHUNT_AUDIO_SETTLE_MS 60 // audio amplifier warm-up after enabling the speaker @@ -80,6 +97,7 @@ static KeyboardState kbd = {KEY_INVALID, KEY_INVALID, 0}; static bool foxRunning; static uint8_t foxAudioMode; +static uint8_t foxGraphMode; // FOXHUNT_GRAPH_BAR / _HIST, cycled by the 2 key static uint8_t attStep; static int16_t curDbm; static int16_t peakDbm; @@ -88,6 +106,12 @@ static int16_t trendDelta; static uint8_t trendTick; static uint8_t audioTick; +// Signal-history ring: FOXHUNT_FillCount levels (0..13), oldest at histHead. +static uint8_t histBuf[FOXHUNT_HIST_LEN]; +static uint8_t histHead; // index of the oldest sample (next write slot) +static uint8_t histTick; // decimation counter (0..FOXHUNT_HIST_DECIM-1) +static int16_t histEma; // EMA-smoothed level feed, dBm in 1/8 units (x8 fixed) + static char str[16]; // Sentinel-prefixed Morse patterns: after the leading 1 sentinel bit, each lower @@ -112,6 +136,7 @@ static char beaconMsg[24]; // CW message, e.g. "F4HWN BEACON" static void FOXHUNT_EnterHunt(void); static void FOXHUNT_EnterBeacon(void); static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft); +static void FOXHUNT_SaveConfig(void); // Read the calibrated signal level of the current RX VFO, in dBm. static int16_t FOXHUNT_ReadDbm(void) @@ -231,6 +256,63 @@ static void FOXHUNT_DrawBar(void) FOXHUNT_SEG_BOTTOM + 2, true); } +// Push one EMA-smoothed reading into the signal history, decimated so the visible +// window spans several seconds. Called once per hunt tick. +static void FOXHUNT_HistSample(void) +{ + // First-order IIR (EMA) on the raw dBm, in x8 fixed point so the /4 step does + // not stall a few dB short of the input. Tau ~4 ticks (~200 ms): kills the RSSI + // snow while staying responsive. + histEma += ((int16_t)curDbm * 8 - histEma) / 4; + + if (++histTick < FOXHUNT_HIST_DECIM) + return; + histTick = 0; + + histBuf[histHead] = FOXHUNT_FillCount((int16_t)(histEma / 8)); + histHead = (uint8_t)((histHead + 1) % FOXHUNT_HIST_LEN); +} + +// Draw the full-width signal-history graph, spectrum-style: a solid crest contour +// over a checkerboard-filled body, on the 13-level S scale. Oldest sample on the +// left, newest ("now") on the right. Replaces the staircase when the 2 key selects +// it. The level-0 line sits FOXHUNT_GRAPH_FLOOR px above the baseline so the lowest +// reading never touches the axis. +static void FOXHUNT_DrawHist(void) +{ + const uint8_t floorY = FOXHUNT_GRAPH_BOT - FOXHUNT_GRAPH_FLOOR; // level-0 line + const uint8_t span = floorY - FOXHUNT_GRAPH_TOP; // px for 13 levels + + // Baseline (axis) across the full width, below the level-0 line. + UI_DrawLineBuffer(gFrameBuffer, FOXHUNT_GRAPH_X0, FOXHUNT_GRAPH_BOT, + FOXHUNT_GRAPH_X0 + FOXHUNT_HIST_LEN - 1, FOXHUNT_GRAPH_BOT, true); + + uint8_t prevY = 0; + for (uint8_t c = 0; c < FOXHUNT_HIST_LEN; c++) { + uint8_t lvl = histBuf[(histHead + c) % FOXHUNT_HIST_LEN]; // oldest -> newest + if (lvl > FOXHUNT_SEG_COUNT) + lvl = FOXHUNT_SEG_COUNT; + uint8_t x = FOXHUNT_GRAPH_X0 + c; + uint8_t y = (uint8_t)(floorY - (lvl * span) / FOXHUNT_SEG_COUNT); // crest top + + // Checkerboard body from just under the crest down to the level-0 line + // (same pattern as the spectrum: ((x + y) & 1) == 0). + for (uint8_t yy = y + 1; yy <= floorY; yy++) + if (((x + yy) & 1) == 0) + UI_DrawLineBuffer(gFrameBuffer, x, yy, x, yy, true); + + // Solid crest, bridged to the previous sample so it reads as one contour. + if (c == 0) { + UI_DrawLineBuffer(gFrameBuffer, x, y, x, y, true); + } else { + uint8_t ylo = (y < prevY) ? y : prevY; + uint8_t yhi = (y < prevY) ? prevY : y; + UI_DrawLineBuffer(gFrameBuffer, x, ylo, x, yhi, true); + } + prevY = y; + } +} + // Battery icon plus the optional voltage/percentage text, top-right of the status // line — shared by the hunt and beacon screens. static void FOXHUNT_DrawStatusBattery(void) @@ -264,6 +346,14 @@ static void FOXHUNT_Draw(void) // Battery (icon + optional percentage/voltage) top-right, as on the main screens. FOXHUNT_DrawStatusBattery(); + // Gauge-mode icon (2 key), between the label and the audio icon: ascending + // bars for the S-meter staircase, a sine wave for the signal history. Each + // bitmap has its own width, so copy its own size. + if (foxGraphMode == FOXHUNT_GRAPH_HIST) + memcpy(gStatusLine + 38, BITMAP_FoxHuntGraph, sizeof(BITMAP_FoxHuntGraph)); + else + memcpy(gStatusLine + 38, BITMAP_FoxHuntBars, sizeof(BITMAP_FoxHuntBars)); + // Audio state icon between the label and the battery: speaker for beep, // headphones for station audio, nothing when silent. if (foxAudioMode == FOXHUNT_AUDIO_BEEP) @@ -292,21 +382,27 @@ static void FOXHUNT_Draw(void) UI_PrintStringSmallNormal(str, 127 - 3 * 7 - 2 - strlen(str) * 7, 0, 1); } - // Context line: peak hold and S-meter as small inverse labels (scan-list tag - // style, 4 px/char), PK anchored left and S anchored right. + // Context line: peak hold (left) and S-meter (right) as small inverse labels + // (scan-list tag style, 4 px/char). sprintf(str, "PK %d", peakDbm); GUI_DisplaySmallestInverse(str, 4, 2, false, true, 4 + strlen(str) * 4); FOXHUNT_BuildS(sMeter, curDbm); GUI_DisplaySmallestInverse(sMeter, 126 - strlen(sMeter) * 4, 2, false, true, 125); - // Segmented S-meter staircase. - FOXHUNT_DrawBar(); + // Main gauge, toggled by the 2 key: the S-meter staircase, or a full-width + // scrolling history of the level over the last seconds (same 13-level S scale). + if (foxGraphMode == FOXHUNT_GRAPH_HIST) { + FOXHUNT_DrawHist(); + } else { + // Segmented S-meter staircase. + FOXHUNT_DrawBar(); - // Scale under the gauge, aligned with segments 1 / 5 / 9 / 13. - GUI_DisplaySmallest("S1", 6, 41, false, true); - GUI_DisplaySmallest("S5", 42, 41, false, true); - GUI_DisplaySmallest("S9", 78, 41, false, true); - GUI_DisplaySmallest("+40", 110, 41, false, true); + // Scale under the gauge, aligned with segments 1 / 5 / 9 / 13. + GUI_DisplaySmallest("S1", 6, 41, false, true); + GUI_DisplaySmallest("S5", 42, 41, false, true); + GUI_DisplaySmallest("S9", 78, 41, false, true); + GUI_DisplaySmallest("+40", 110, 41, false, true); + } // Attenuator as an inverse label (left), tuned frequency (right). sprintf(str, "ATT %ddB", FOXHUNT_ATT_DB[attStep]); @@ -376,6 +472,10 @@ static void FOXHUNT_IdleHousekeeping(void) gBatteryVoltageIndex = 0; BATTERY_GetReadings(false); + // Persist any changed setting within ~0.5 s, so it survives a power-off (not + // just a clean EXIT). No-op when nothing changed. + FOXHUNT_SaveConfig(); + // Backlight timeout: switch it off when the countdown expires (both modes). if (gBacklightCountdown_500ms > 0 && gEeprom.BACKLIGHT_TIME < 61 @@ -432,6 +532,10 @@ static void FOXHUNT_HandleKeys(void) if (foxAudioMode == FOXHUNT_AUDIO_BEEP) audioTick = FOXHUNT_RATE_SLOW_TICKS; // blip promptly break; + case KEY_2: + // Toggle the main gauge: S-meter staircase <-> full-width history. + foxGraphMode ^= 1; + break; case KEY_SIDE1: case KEY_SIDE2: // Same shortcut that opened Fox Hunt now toggles to the beacon. @@ -442,23 +546,35 @@ static void FOXHUNT_HandleKeys(void) } } -// (Re)enter the hunt (RX) sub-mode: fixed front-end gain, attenuator re-applied, -// audio silenced, peak/trend reset. Called at start-up and when leaving beacon. +// (Re)enter the hunt (RX) sub-mode: fixed front-end gain, attenuator and audio mode +// re-applied, peak/trend reset. Called at start-up and when leaving the beacon. The +// audio mode is a hunt setting, so it is (re)applied here, not forced off — it must +// survive a trip through the beacon. static void FOXHUNT_EnterHunt(void) { - foxBeacon = false; - foxAudioMode = FOXHUNT_AUDIO_OFF; - AUDIO_AudioPathOff(); + foxBeacon = false; BK4819_SetAGC(false); FOXHUNT_ApplyAtt(); + FOXHUNT_SetAudio(); // (re)apply the current audio mode: off / beep / station curDbm = FOXHUNT_ReadDbm(); peakDbm = curDbm; trendRef = curDbm; trendDelta = 0; trendTick = 0; - audioTick = 0; + audioTick = (foxAudioMode == FOXHUNT_AUDIO_BEEP) ? FOXHUNT_RATE_SLOW_TICKS : 0; + + // Prime the signal history flat at the current level so the sparkline scrolls + // in from a sensible baseline (also applies on return from the beacon). + { + uint8_t lvl = FOXHUNT_FillCount(curDbm); + for (uint8_t i = 0; i < FOXHUNT_HIST_LEN; i++) + histBuf[i] = lvl; + } + histHead = 0; + histTick = 0; + histEma = (int16_t)(curDbm * 8); } // Evaluate the TX gates for the beacon's TX VFO in the same precedence order as @@ -515,8 +631,7 @@ static void FOXHUNT_TxDeniedNotice(VfoState_t state) static void FOXHUNT_EnterBeacon(void) { foxBeacon = true; - foxAudioMode = FOXHUNT_AUDIO_OFF; - AUDIO_AudioPathOff(); + AUDIO_AudioPathOff(); // no RX audio while beaconing; foxAudioMode kept for the hunt gCurrentVfo = gTxVfo; // the VFO RADIO_SetTxParameters keys up beaconPhaseTx = true; } @@ -734,6 +849,64 @@ static void FOXHUNT_BeaconTick(void) FOXHUNT_TickDelay(); // tick delay + smooth backlight fade } +// --- Persistence (external flash) -------------------------------------------- +// Concatenated right after the VFO data in the VFO sector. NB: the 14 VFOs really +// span 0x9000..0x90E0 (224 B); the old 0x90D6 mapping bound was 10 B short and +// overlapped the last VFO (470 MHz VFO1 @ 0x90D0..0x90DF), so the config sits at +// 0x90E0, just past the real end. Normal saves are read-modify-write (Append=false) +// so they preserve these bytes, and the VFO mapping is extended to 0x90E5 +// (eeprom_compat.c) so aircopy clones them with the VFOs. A factory reset clears it. +#define FOXHUNT_CFG_ADDR 0x0090E0u +#define FOXHUNT_CFG_MAGIC 0xF4u // tells a written config from erased flash (0xFF) + +// RAM mirror of the bytes last written to flash, so FOXHUNT_SaveConfig only touches +// the flash when a value actually changed. +static uint8_t foxCfgSaved[5]; + +// Pack the live settings into the 5-byte on-flash layout. +static void FOXHUNT_ConfigPack(uint8_t out[5]) +{ + out[0] = FOXHUNT_CFG_MAGIC; + out[1] = attStep; + out[2] = foxGraphMode; + out[3] = foxAudioMode; + out[4] = beaconIdle; +} + +// Restore persisted settings; erased/invalid flash leaves the defaults in place. +static void FOXHUNT_LoadConfig(void) +{ + uint8_t cfg[5]; + PY25Q16_ReadBuffer(FOXHUNT_CFG_ADDR, cfg, sizeof(cfg)); + + if (cfg[0] == FOXHUNT_CFG_MAGIC) { // valid, saved config + if (cfg[1] <= 3) attStep = cfg[1]; + if (cfg[2] <= FOXHUNT_GRAPH_HIST) foxGraphMode = cfg[2]; + if (cfg[3] <= FOXHUNT_AUDIO_STATION) foxAudioMode = cfg[3]; + if (cfg[4] >= FOXHUNT_BEACON_IDLE_MIN && cfg[4] <= FOXHUNT_BEACON_IDLE_MAX + && (cfg[4] % FOXHUNT_BEACON_IDLE_STEP) == 0) + beaconIdle = cfg[4]; + } + + FOXHUNT_ConfigPack(foxCfgSaved); // mirror the loaded (or default) state +} + +// Write the settings to flash, but only when they changed since the last write. +// Called on the 500 ms tick (so any change persists within ~0.5 s and survives a +// power-off, not just a clean EXIT) and once more on leaving Fox Hunt. The RAM +// compare avoids re-reading the 4 KB sector on every quiet tick. +static void FOXHUNT_SaveConfig(void) +{ + uint8_t cfg[5]; + FOXHUNT_ConfigPack(cfg); + + if (memcmp(cfg, foxCfgSaved, sizeof(cfg)) == 0) + return; + + PY25Q16_WriteBuffer(FOXHUNT_CFG_ADDR, cfg, sizeof(cfg), false); + memcpy(foxCfgSaved, cfg, sizeof(cfg)); +} + void APP_RunFoxHunt(void) { // Finish any pending backlight fade, then start with the screen on and a full @@ -774,9 +947,13 @@ void APP_RunFoxHunt(void) sprintf(beaconMsg, "%s BEACON", call); } - // Start in the hunt (RX) sub-mode. - attStep = 0; - FOXHUNT_EnterHunt(); + // Start in the hunt (RX) sub-mode, S-meter staircase gauge by default, then + // restore any persisted settings (attenuator, gauge, audio, beacon idle). + attStep = 0; + foxGraphMode = FOXHUNT_GRAPH_BAR; + foxAudioMode = FOXHUNT_AUDIO_OFF; + FOXHUNT_LoadConfig(); // may override att / gauge / audio / idle + FOXHUNT_EnterHunt(); // applies the restored attStep and audio mode // Prime the key state with whatever is held right now, so the side key that // launched Fox Hunt (still down on a long-press assignment) is not taken for @@ -807,6 +984,8 @@ void APP_RunFoxHunt(void) trendTick = 0; } + FOXHUNT_HistSample(); // feed the smoothed signal-history sparkline + FOXHUNT_Draw(); ST7565_BlitStatusLine(); @@ -835,6 +1014,10 @@ void APP_RunFoxHunt(void) FOXHUNT_TickDelay(); // tick delay + smooth backlight fade } + // Persist the session's settings so they survive a power cycle (covers EXIT + // and the sleep auto power-off, both of which just clear foxRunning). + FOXHUNT_SaveConfig(); + // Mute any pending tone, drop the PA (safety), then restore the normal VFO // selection and RX config. AUDIO_AudioPathOff(); diff --git a/App/bitmaps.c b/App/bitmaps.c index 56c8e929..a6c617de 100644 --- a/App/bitmaps.c +++ b/App/bitmaps.c @@ -374,6 +374,28 @@ const uint8_t BITMAP_FoxHuntFlat[11] = 0b00010010, 0b00010010 }; + +const uint8_t BITMAP_FoxHuntBars[11] = +{ // ascending bars = S-meter (staircase) gauge mode (bit0 = top row) + 0b01000000, + 0b01000000, + 0b00000000, + 0b01110000, + 0b01110000, + 0b00000000, + 0b01111100, + 0b01111100, + 0b00000000, + 0b01111111, + 0b01111111 +}; + +const uint8_t BITMAP_FoxHuntGraph[15] = +{ // sine wave = signal-history gauge mode (bit0 = top row) + 0b00001000, 0b00000100, 0b00000010, 0b00000100, 0b00001000, + 0b00010000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, + 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000 +}; #endif #ifndef ENABLE_CUSTOM_MENU_LAYOUT diff --git a/App/bitmaps.h b/App/bitmaps.h index c72b41d5..7fa04f59 100644 --- a/App/bitmaps.h +++ b/App/bitmaps.h @@ -51,6 +51,8 @@ extern const uint8_t BITMAP_NOAA[12]; extern const uint8_t BITMAP_FoxHuntUp[11]; extern const uint8_t BITMAP_FoxHuntDown[11]; extern const uint8_t BITMAP_FoxHuntFlat[11]; + extern const uint8_t BITMAP_FoxHuntBars[11]; + extern const uint8_t BITMAP_FoxHuntGraph[15]; #endif #ifndef ENABLE_CUSTOM_MENU_LAYOUT diff --git a/App/driver/eeprom_compat.c b/App/driver/eeprom_compat.c index d880e97c..44790800 100644 --- a/App/driver/eeprom_compat.c +++ b/App/driver/eeprom_compat.c @@ -51,7 +51,13 @@ static const AddrMapping_t ADDR_MAPPINGS[] = { _MK_MAPPING(0x008000, 0x008000, 0x00886E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000) 0x008000 -> 0x00880E // List name * 4 Bytes 0x00880E -> 0x00886E - _MK_MAPPING(0x009000, 0x009000, 0x0090D6), // 14 VFO * 16 Bytes (ex 0x001000) + _MK_MAPPING(0x009000, 0x009000, 0x0090E5), // 14 VFO * 16 Bytes = 0x9000 -> 0x90E0 (the old + // 0x90D6 bound was 10 B short: it truncated the + // 470 MHz VFO1 record at 0x90D0 -> 0x90DF) + // Fox Hunt settings * 5 Bytes 0x90E0 -> 0x90E5 + // (ENABLE_FEAT_F4HWN_FOXHUNT, written directly by + // app/foxhunt.c; concatenated here so aircopy clones + // them together with the VFOs) _MK_MAPPING(0x00A000, 0x00A000, 0x00A170), // Settings * 16 Bytes (ex 0x004000) 0x00A000 -> 0x00A010 // Settings * 16 Bytes (ex 0x005000) 0x00A010 -> 0x00A020 From f371795ef8de66b89cbe826720fbde69beea8bf7 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 2 Aug 2026 05:02:48 +0200 Subject: [PATCH 24/42] Update next version --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 1734f9f3..ec73c156 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -83,7 +83,7 @@ "ENABLE_UART_RW_BK_REGS": false, "ENABLE_SWD": false, "VERSION_STRING_1": "v0.22", - "VERSION_STRING_2": "v5.7.1" + "VERSION_STRING_2": "v5.8.0" } }, { From 18e9de38e0e1ec926f3d686080c8bba334792da7 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 2 Aug 2026 05:03:14 +0200 Subject: [PATCH 25/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 107552 -> 108284 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index a2c253d894646188b3d51d2877675f90f4291913..1613277a3a48fc358bfbbc36454903d22b2fb79c 100755 GIT binary patch delta 9609 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 Date: Sun, 2 Aug 2026 05:22:37 +0200 Subject: [PATCH 26/42] Fox Hunt: factor shared beacon draw code, -156 B flash --- App/app/foxhunt.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 37fc6e27..0fa144a3 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -331,6 +331,25 @@ static void FOXHUNT_DrawStatusBattery(void) } } +// Right-aligned frequency on the bottom line (line 6), shared by the hunt and +// beacon screens. +static void FOXHUNT_DrawFreqBR(uint32_t freq) +{ + sprintf(str, "%u.%05u", freq / 100000, freq % 100000); + UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); +} + +// Common beacon-screen frame: clear, the BEACON tag, the battery, and the TX +// frequency. Shared by the beacon draw and the TX-denied notice. +static void FOXHUNT_BeaconChrome(void) +{ + UI_DisplayClear(); + UI_StatusClear(); + GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 28); + FOXHUNT_DrawStatusBattery(); + FOXHUNT_DrawFreqBR(gTxVfo->pTX->Frequency); +} + static void FOXHUNT_Draw(void) { const uint8_t *trendIcon; @@ -407,8 +426,7 @@ static void FOXHUNT_Draw(void) // Attenuator as an inverse label (left), tuned frequency (right). sprintf(str, "ATT %ddB", FOXHUNT_ATT_DB[attStep]); GUI_DisplaySmallestInverse(str, 4, 6, false, true, 4 + strlen(str) * 4); - sprintf(str, "%u.%05u", gRxVfo->pRX->Frequency / 100000, gRxVfo->pRX->Frequency % 100000); - UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); + FOXHUNT_DrawFreqBR(gRxVfo->pRX->Frequency); } // Map a navigation key to a logical step (+1 = up/increase, -1 = down/decrease), @@ -604,20 +622,13 @@ static VfoState_t FOXHUNT_TxState(void) // reading cleanly. static void FOXHUNT_TxDeniedNotice(VfoState_t state) { - UI_DisplayClear(); - UI_StatusClear(); - - GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 28); - FOXHUNT_DrawStatusBattery(); + // Frame (clear + BEACON tag + battery + barred TX frequency). + FOXHUNT_BeaconChrome(); // Centred, gFontBig — same wording and font as the main screen's VFO state, // on line 1 so it sits exactly where the beacon's "TX" / "IDLE" text appears. UI_PrintString(VfoStateStr[state], 0, 127, 1, 8); - // Bottom-right: the barred TX frequency, so it is clear what was refused. - sprintf(str, "%u.%05u", gTxVfo->pTX->Frequency / 100000, gTxVfo->pTX->Frequency % 100000); - UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); - ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); @@ -728,12 +739,8 @@ static void FOXHUNT_BeaconTransmit(void) static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft) { - UI_DisplayClear(); - UI_StatusClear(); - - // Status line: BEACON tag (left) + battery (right), same style as FOX HUNT. - GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 28); - FOXHUNT_DrawStatusBattery(); + // Frame (clear + BEACON tag + battery + TX frequency). + FOXHUNT_BeaconChrome(); // Centre, on two lines: the state, and below it the idle countdown (idle only). if (txNow) { @@ -747,10 +754,6 @@ static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft) // Bottom-left: the idle-duration setting as an inverse label (ATT style). sprintf(str, "IDLE %02u", beaconIdle); GUI_DisplaySmallestInverse(str, 4, 6, false, true, 4 + strlen(str) * 4); - - // Bottom-right: the working (TX) frequency. - sprintf(str, "%u.%05u", gTxVfo->pTX->Frequency / 100000, gTxVfo->pTX->Frequency % 100000); - UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); } static void FOXHUNT_BeaconKeys(void) From fe602b075d9ceac8bf7064d01f060b6223efd9a0 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 2 Aug 2026 05:23:43 +0200 Subject: [PATCH 27/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 108284 -> 108128 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 1613277a3a48fc358bfbbc36454903d22b2fb79c..e0279f2fbc461a2a5649cfccf8cc0adfa80cff22 100755 GIT binary patch delta 8000 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 Date: Sun, 2 Aug 2026 05:50:40 +0200 Subject: [PATCH 28/42] Fix: handle restart in modal apps --- App/app/breakout.c | 7 +++++++ App/app/foxhunt.c | 7 +++++++ App/app/spectrum.c | 7 +++++++ App/app/uart.c | 15 ++++++++++++++- App/app/uart.h | 2 +- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/App/app/breakout.c b/App/app/breakout.c index 6059eb63..ea0be553 100644 --- a/App/app/breakout.c +++ b/App/app/breakout.c @@ -16,6 +16,10 @@ #include "app/breakout.h" +#if defined(ENABLE_UART) || defined(ENABLE_USB) +#include "app/uart.h" +#endif + #ifdef ENABLE_FEAT_F4HWN_K5VIEWER #include "k5viewer.h" #endif @@ -359,6 +363,9 @@ void APP_RunBreakout(void) { while(isInitialized) { +#if defined(ENABLE_UART) || defined(ENABLE_USB) + UART_ServiceCommands(); +#endif Tick(); if(!isPaused) { diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 0fa144a3..ab34ff00 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -18,6 +18,10 @@ #ifdef ENABLE_FEAT_F4HWN_FOXHUNT +#if defined(ENABLE_UART) || defined(ENABLE_USB) +#include "app/uart.h" +#endif + #ifdef ENABLE_FEAT_F4HWN_K5VIEWER #include "k5viewer.h" #endif @@ -965,6 +969,9 @@ void APP_RunFoxHunt(void) foxRunning = true; while (foxRunning) { +#if defined(ENABLE_UART) || defined(ENABLE_USB) + UART_ServiceCommands(); +#endif if (foxBeacon) { FOXHUNT_BeaconTick(); continue; diff --git a/App/app/spectrum.c b/App/app/spectrum.c index d4830b07..f86cb8a1 100644 --- a/App/app/spectrum.c +++ b/App/app/spectrum.c @@ -18,6 +18,10 @@ #include "audio.h" #include "misc.h" +#if defined(ENABLE_UART) || defined(ENABLE_USB) +#include "app/uart.h" +#endif + #ifdef ENABLE_SCAN_RANGES #include "chFrScanner.h" #endif @@ -2608,6 +2612,9 @@ void APP_RunSpectrum() while (isInitialized) { +#if defined(ENABLE_UART) || defined(ENABLE_USB) + UART_ServiceCommands(); +#endif Tick(); } diff --git a/App/app/uart.c b/App/app/uart.c index 7d14e65e..5c052430 100644 --- a/App/app/uart.c +++ b/App/app/uart.c @@ -866,4 +866,17 @@ void UART_HandleCommand(uint32_t Port) #ifdef ENABLE_FEAT_F4HWN_K5VIEWER gUART_LockK5Viewer = 20; // lock the K5Viewer stream #endif -} \ No newline at end of file +} + +void UART_ServiceCommands(void) +{ +#ifdef ENABLE_USB + if (UART_IsCommandAvailable(UART_PORT_VCP)) + UART_HandleCommand(UART_PORT_VCP); +#endif + +#ifdef ENABLE_UART + if (UART_IsCommandAvailable(UART_PORT_UART)) + UART_HandleCommand(UART_PORT_UART); +#endif +} diff --git a/App/app/uart.h b/App/app/uart.h index cac62817..45f5e5ce 100644 --- a/App/app/uart.h +++ b/App/app/uart.h @@ -32,6 +32,6 @@ enum bool UART_IsCommandAvailable(uint32_t Port); void UART_HandleCommand(uint32_t Port); +void UART_ServiceCommands(void); #endif - From 3e5795255d29d5b0e89ad76f98d51466d0d76f1a Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 2 Aug 2026 05:51:35 +0200 Subject: [PATCH 29/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 108128 -> 108176 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index e0279f2fbc461a2a5649cfccf8cc0adfa80cff22..1e00c28ef5a7fa27ca1711858e569d948f85f998 100755 GIT binary patch delta 12985 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 Date: Sun, 2 Aug 2026 17:34:01 +0200 Subject: [PATCH 30/42] Fix RX mode restore after scan transitions (Issue #480) --- App/app/action.c | 6 ++++++ App/app/main.c | 6 ++++++ App/ui/main.c | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/App/app/action.c b/App/app/action.c index 22f64b76..27186e6d 100644 --- a/App/app/action.c +++ b/App/app/action.c @@ -425,6 +425,12 @@ void ACTION_FM(void) gMonitor = false; + if (gScanStateDir != SCAN_OFF) { + // Stop the channel/frequency scan before switching to the FM radio. + gScanKeepResult = false; + CHFRSCANNER_Stop(); + } + RADIO_SelectVfos(); RADIO_SetupRegisters(true); diff --git a/App/app/main.c b/App/app/main.c index 2ef9adc1..1550de58 100644 --- a/App/app/main.c +++ b/App/app/main.c @@ -924,6 +924,12 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld) return; } #endif + if (gScanStateDir != SCAN_OFF) { + // Stop the channel/frequency scan before saving the RX mode for the CTCSS/DCS scan. + gScanKeepResult = false; + CHFRSCANNER_Stop(); + } + // scan the CTCSS/DCS code gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF; diff --git a/App/ui/main.c b/App/ui/main.c index a6fe990e..66b1204c 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -1581,7 +1581,11 @@ void UI_DisplayMain(void) } } else { - if(RxOnVfofrequency == frequency && !isMainOnly()) { + if(RxOnVfofrequency == frequency && !isMainOnly() +#if defined(ENABLE_FEAT_F4HWN_SCAN_FASTER) && defined(ENABLE_FEAT_F4HWN_SCAN_RSSI) + && !CHFRSCANNER_HasScanRssiSparkline() +#endif + ) { //UI_PrintStringSmallNormal(">>", 8, 0, line); //memcpy(p_line0 + 14, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); GUI_DisplaySmallest(">>", 8, RxLine == 0 ? 1 : 33, false, true); From 602dfad6f33f0f45ed060b231e1295b54cab9fd2 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Sun, 2 Aug 2026 17:35:46 +0200 Subject: [PATCH 31/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 108176 -> 108232 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 1e00c28ef5a7fa27ca1711858e569d948f85f998..36c6cf73a8a78cd32c97ae806ea83234dbe84da8 100755 GIT binary patch delta 19815 zcmZX630#%M`v1&X-~h6TD2MedAm9-J5do28aRCpwo0*!L8%pJ|ZolxFg1ctrGS!Qc zsg;G9si2XSrIwkMw{t2>Q*T=8$^CU>&VK&iIePE!_xb#z@0sPDnRn)yXP$ZHndf!g ziJ)&!1g+~&=dCYkP^7)R_lpP>t!F1xM*QAZ<FHC9DmYFn7`2c>>CsYd~QtL^n3-z(@D zHZ{vgZ?Wb0HL)F8FVJ;N->W!$mz(N>W#U!nhf|Z%?>6qB^0Tm{isXIoP8# z8ZGDTq2`2om;KP-yKzLfHJ<2(A|yxH7rhc6?}|sXn3|$ale8}8F4akvF38zg9)jv` zJE)jNaxiabp1DsA=^10C zI;|zj5+RRsv@C24Zj20^|Vo9{@dg+c`Er07)C7-kD z%yE`fKq4$7{u8qFN=JsyWZEyvd<5vNVQ3nqV{u>lK1^lfgIxCLn*bh_4yNGHAkrCD$3#Y|E=R;v~RPbODlV;Z*tl;?{;mb#n06~rQX9gc}ui3 zm-flD=z89;g~($ZBrQbFWf%I^sTVl?ypD}5D5C#nYYK|H)%&TD=!}?;xc>#po-25o zu3+ZEG|Je#LT%o4XL^mPwohJMeURMSuOn)Cs$WksYCFqw9g3a`YaSRR)0!gY9`q-= zFnKRKSone>=m_gu)C0^nwdkGvX3y60pi_Iwl|SuRGbLUvGmqt94)NHd_N!i14!uZX zv=eIIe$3A=_@fSXIZQQC`-A1Xtf*fu{U@vIH?Q zvCsM^&{XzY|CDZBd}GY<^`u9Tl^EhJua^_6{X(!@z`{$?)U7_1+?^Gam_n*uRF?}v zRI<8~gy2vQ)dk6u*efO7!iPA%xDeipSkGMc@aNgyk{Ei09W6-R_w zeU;TcqNmH*E05&UPuN%ZtzphbGHD?*4row!^?LbF?EL|0+ArO-xgHevWh-r#Dlh-d z``G0o;^n*8r2$#FLB0`&C(UYIie)O;%EzyJMK>ZnHGw&xRz-7)g*KO>KFJ8PspVH$ zMQIsrV9QHWsGe;v9Y9C2OQqwrsUCf`F+jQ?`2!EZT2nN~)rZN`*|@Sy(d8v&y=f)e zUuKN{1LN)_uX2$L1(sANc{00FHiW*wa?8_VGaw7EyMuHpd81c_j@)sF$v?2V@|yH2 z7d0-g2D`6H);G3#`8#gos_A*nt;WXK^Q4E$=Fe+t@NgabqkJq)XZaOrv^0aGCz2xQZvKIzs(MfFkz{!f9tt@EJ zP*8j1pcvZ0W(;~iZHL1ImL#@&mrWoHF%j#n%R%xZE^6p*j<;O7tk$VziRBI+9=^rl zg3QCy*eiog^bR{P*obz{4Njv!G3AiwX;|C*A!(HEVOuK4RzzS~b_SvVzn>6! zKS}+{ynIihC0H(VM9Y&L9)8Sm$gCp@mas~(iDJ+(jbZWy-_~-4RY$_)Pgp_K^5Pgj zM3HUng*6wH@;M((BN>Nnopc_4+nG`Rxs~V@h_7^u-@lz2qe_(;5kwNpyIZ~d1IDZL zkzrm1iOEpe3du`VF>(t_ADTs%u(3loC*1K|Fw8QKqVbIyV@kOiZ3&LiT0Hy`3pbl0 z2RJ8~8_22Aq}Lr=C;44A#9R|{$&p~6jCX~z&1OCA&%QKgW*u`h^vO4;Tk@+FOh=|B zHWxcGQOal8gqoBP zg^y%VTc}*hme!1?f3b5l)94OXHf$VNapSP`@C#laFL4un5JsV9Cx&Ix4916*sqbQC z)v%J`N!`A1jW;LOlb*!(_4&uDAFF{RBP#h1Hg9+){gpKjUrIk~lL z&?)7UUMjB#iw$A7Ma-dqmmOep6-F-8mmff#A6kv#NZM`zr@Cl zN(-^NmGYzBU@*MmlL?sb!% z_iP@%*6rc1u-LIzups?oV`Ige#OBonn~~u9Tfh{S`RF`4ku^VBtWbH_sYk1W>mZJV z&@qkE)8njWTrTa-8pb8jv263W*NxNtw5QRQQLB=F_UQ>o=G#}Uv{Hl7JgPjtQFL}M z8~fM+I)+7#?}moc$D8R;_T2b1YGfP7r=-PrOtlHK<7)l(E-TNBrJ_ zoKng8ZRf`CqDlYukPO*cH+XYmCZR1J{;ESo6d7G?v`HyPvG*rrLFk;E&`gi9c@tA; zJ6k_74T@Vke#6+giDeK*DU;T!J3##JSlguZ;3Mt~qLja67bfM#=o};?!$xyda-M_q z>}m~?-7M{iEa+mRpBPVlY}XS7)YEq92_>a2c4hLcl#`C#rIN3+xl>}h?Q-PQD&;2s?sB`ecP%yQ7g*P*WnWwKlq5<|ume-8Xb@9AX$rgS zF%q#qxOqA&dQu-d$FtSgXgH%DMK(Q2j3#iao9|(BpImL6gE@=Z-^Bn~QW-4|^$I1V z2Fo(?A;&~xEhS9L#yT-in;WM4Z@W|3(P{dacip00qI=MCj>XNdG3T^4MVBM&qv`#V z_PB}yi-1}S&50JvL4{o5%&#UH!B&Mlj0Mj~r^zgP#!6bs+Gi}r{1weiq668unVB?+ zEuI;pxbI+Z%$yiI#=jC%sFa`eir-1tR8{g;7CdVyHvcuVjOHo+DdtK$=_Qs$XXhky zvZdHg4ElJtYmMu+t5Om{O%hlu^nf znR8ZJx6aOMb`Kxm(x6QRBu=4EiS#s4YQkSAUq&UjT>eA@TY*t;C0!;Kq zoxzyvSIc7^E%vyK_fFLX6w-l^5O-_}!z44!iHCwZhMlQ1LW}X&CDDT{>8VNDZ(Pde zI16dsTux8tSt_8^ZuaKaD9W-0%vPV5VxIw68V}NSl69{$EGsB9}*e+Z?1SXgO?RyNS{cE=nU!R*3 zR)v_zscn}(Gbhv%Q)G?~K73(stDj$W%)PuF?9(bZw!sDCz%RsjAbM8 zslLe^NM}9RF>iX5^vJTk zXm-a1nW9fEsL81H@P%GTExA8bFY^0OmrS)fk~qc1SGZlg)h%DHkBcFVtx7q_VKFzA z6WjSqE6WKRJvZ7k2W>xYRv4_8G{nc>_Rlg?!*`cRuQc&?tK$-B7D`c$t;#%tt(~iF zm@w2f2Ktq4RDdW{kk&J9Xob0ReLQBM+^Y%nbL*v{|9$?uhZxGtZ(JH~7N;ja@8syP zyZH?NtC!3uBUG=|m-;*;@l?E75qR_7OMPpufnLP=h&@|SrdP0)WTdflOLRjrN()Zv zVnYmk6J?7q^sOwYijrNvzUJJa$rfttTwiR7$JkOJ2U5(-?5P-Iyv1oJ#u!UP;5@kr z8%jDT?c)di>io>1R~o1;+CmIhU!d|;SG4)EJs0fj=bt+BE{Ra%%D!}HFpih(9m@R+UEl{F!7CF5)P-Cax=lTEthNzbqW#_dFZve;iX0joVvgD`W{u*U6?HIJ{+XSa z_dLyMt9X{un0-)2&tiMd*}t=T^`5laU^#+~doC@+?XS+5bIQTrXE@k-dUZL|7 zYpmVH%h-Sy4$}i|v_6HZ@4=$*2}_$lHq7Ix&LF3koktzEeEtd89!CFjC52{rX2C-G zO56As^Jqw*G~T$6y}ob~{TI8tuz-$WrbW4Q4V$zmn?A>0S#*p>vat7{Ky~mC%o<-kg*-MO6W}}xZz!~nxB?-a(JjX8u$z|;Jk}TSTr7X=CZ(iC? zKV#v`hJ>v3YchVbIXGjJmZi{nY~ivzMS2TsT{Z@qP4My}Xq#or)3CSBT3!~C?Voc| zgR|B`ws(1fI0ao@o)cN`4i7N0!lu9p=Qhh+VN`TF!iKF#q?1|Q3UhFVBcs-d-T2^& zv5I>x)@7wmJny^mW!lERTA4@ZwDFbiEAWafFKy4Rb2#~Ihaz>BxsN5Tah5r`HV3>m z$18q+_M)HOo)+~U`Jj_Oijrg4b8Cb`+PuaTxyeDXY!xQWDXMc~JSW$brFHV^Q15xv z%l9g<`TuHH?0hRRmnd7DywIUamaI;ox-F#wODV_g(w`n-br;1u7;V&$sNA`Y8_Mi zBMsGE^J;R#d7p##_NtL_#y3w#H#+!8=YV>Wt+0k7&*qDLC=#|$6?p_!r-lB!dNo8( zr@#|xb?_kX2ty|vZu!BjkB?vF;D38)zUWq~??&qpyRf1N`;*wEK2#806O^2j*pfZ~ z(%JS`6KEAX{Axn<6*u;S9cQrEx27o==NH(GSGx^4>3$cv6Ch7T-oM<3k!nU6kvbNr z(M-cCMe2}yiZQfWvE#wB1MWjc9cd%XM5KDMl}&n_Gj=rPLh(A& zltfFIv*~F%lg-+gt>|#Drj1i@x^!-QCA{1pW{mCha7@q9@L>gy?nPi<^E^ z?F1a8I1gs}_w)@fIXHjI8H&|?!u6jgk2$DbgR;H-YUCeA{^PTI;M@^i3r_Qkvh9Jq zsQEM_%(^t0n$)L8&iC=BydAus-*S-ig-*A9)cj!cC}MrQgID|S!J7LErsYdOELkx{ z=l9`^!VbTu4Q};`o*iQs-ivK$@#pF~_-HrnS#8r*EN&I4zdhx;;;IgQ(bGfM58-)F zkvX|u(TkiW-3x0v$h-+A-7akh|HYH7o4u-oTRmfRI}rZh8LPX3@LNwd^op#2WsF#r zI;!vBL;a?qk;dTfI{1A5wq$ei#)q13 zA={T%8&CT5?p#lM7;R!SEihL;7|j8nuzqy#B!pt-zC=ioj`h*hP6!vff=KsLU3qxG zx`cd>*gTq?vR&{-&j4?nfqpaqWrIB<%nNne`T<65=`i!~8ZDNK*In7E+K3Z)N^K#U z-^y;a)_!PxRTS9b7^yixf5(Hk|a-5zDGBHw~@-t|Td+hgzGzcT-h zT!_uw4~8qWuuy*R1=zi8=MY8c5%$u~nUNjb<^LAqhr^J}Ibr^tY3d@Uo1bjU{P3v4 z*yN1T*A8~`LpVbPS)&ZI2kS^DS@Ns*LrP^3+Aek~c1~ER_~4z2(a*~cN|?jRnmxT|IemlO-SY|^&KB>TOjFo}y)m%^e0i&aF~FtenxD4@?n~5i z2@7dW>fFKII7ro@!V5JC-ztSNmzyse3C`qWcE*TX#vw7$d0%LoBI@ls!D~PUh%L;4-BOP*tP>{Fft!I zps(2Ci8@${4&>|)$BV>Vt4QtOPV!gI404Z$!t@&oEj<)O61fqsMx&0Np^dGF;!xHo zI=YCNJ{=3SeetKe6dpIr`K*+VX7fIa39s^O)hTwMn4$w#$@QP5KvCZN+0v~0t~rC% z=GlW|8gbzSChXuAcML2>k7157A&{QipIkG0a0V#d!T(@WKTiuA0h`zZ+8tx-KQE%a z*!Q37V>do*C!t|d0GQ&-*K z-sCY@0mEby%l&d%m{@|d2lqpXQnuyGr67^<&|bQoojhcu-I()Gad;-|q|pZ0Xsg2H z`K;`4O89KwhvnRM*)m=RVxpQ!v4Qut`VK>2GZL z5ivX4j|>mn;tfWRu4u#LP0W8JHn!z6QG+tg&T!I&1d){bdwf32{AxhArccC^VA2U| zxhoW+TmC|{IE*!XwK#hE$HF2QWT0k0*F#D+vFNX3Rd>15&w70QNcbgBE(tZXB!=dO z!7Tp#*9G(kw(IL3VYgd&6f?-8zgZf#+Z$CCL~1MU;u>PhHz`m%zWin(O=Bg;vLjE3 zVeM}Ow<;>bhtPD|fm z+rKjzolxF4`;2hFfKDAI4`p}1n}k(7@_Q})l+}Ho4qcjk zKbA(bE8ma9y=mDG10qj58VxvvHHFEG9QXJMw)Tf~`W9>d!HDDVnI979RmOiXg>{A< zSz#?C_jx_bI*}D~#Q9ZgNUDN;U{5e7Rt2>vaf$i#iGrdGaGf~zd;y(FsJ6DG2f9-# z4hhq7{5gVWcQGzM5RbB(1UDf*hMhYxjh3;pf5m7E+_-QynCf+pvI=UtX`_Wf8P`tT z<Uy2J^jIqrOL(#(+UrY(?tH+J7#DzX?jed_Y1{JzR$KO`}22DO(_T>ES1xN{zx+rM-VKmS+VK0DpuZR4K`?+LgjE@aC1U!V(mJ- zOwFiircKeT+{B5*D!XuDHJQ z@Q>KEpJInBf-?CIF4r_o!G;&B;&MXeU%Wxh@vDR}dQ&<1dENPX)F-A8>vLws#t947 zl&frWAGWyA`YZ%OI3_rVefg7i){65%xM=EkLAA-Ke+>ebY#@dimF`yEV?KVu-|K>h zCqie*vx0aV;}=XZzf@jn3*FQiH`W7fRIjy6#2IL!ImI%@oH%6y`qd{dp?*zytZlsc zaTvum5ZhznEur$WY{1V+vqn@YOxLU<%p-}Mk^J%8Z$7pD9ryWv&8s<|K0!Rg}KJRgh;^_Mh8ou04^QcP5vd_3Mi7lt@JW=^np z9A;AZdHmfAH& zVjxVX&x7VS^m0&hT~++5@D|!zA?HFfO4W-=bGL@K^vARCUD{O{u)HR+1;6G(>h1cq zTg(NopKoylCFfYfKYCz;)Ue-vO{&Qfik&`(glxJy?=3r+a^sqEwar9Q_2Df(KF9Z) z{Xg+IpY6ZBK>6mguwdp_-QkZy8wy$98?oBnsmzQ4--z8L9KR@J1Gy7WKEKfNV zqkAqf^h08pr$5t5v_5Y4{@)Qk;tOhyTjk-)nDkrvnCafj*sa7whzW>?+!?!p>Lypgcj0Z0~z(rh`;> z_)YgV^YYfW%Kv%lLHa3A540QJvbjnj|LO_CRP_pwuPZa2Hp5yt_jE;moacD!(*Zw^ ze^{$X%m*Xlh~abng2XeeK7PnE|NM5eoq@Jhfj&+T^s%1VPnQ(bc|!sQ^H6K9LC6VR zKWbEhcSD+p(Z?rx2j=G*uC)H=Nq7rkB7X#%@Ow7gJJ$SO1izJ|zo*cAcIo%L@C1*L zO{`p)*)=TfOqyDOP3JBfenwv=$STMywyP;1n~-dg>4eNgTm#ZaV;y9Xf#h9Gg|PR| zMSd+vE{@b&f#=xXGqKo{kDW=OFERU>w1OAV_6BDzSm7&YD6!Z3`FGAI2ftKGb7L!R zv>tE8X6Za&{SF+`}LxFbaiP4(Ip^^0mSka zJK9!YAmU=EhcT3WJE>+Pp3lc}k4hlAMXctJA+(Xb{>K73jYXeN!u4?W`DW~=-=9x` zyuWrn9Xoi;1ta~F6V?*?~XJ;VT{89uCmQ&$H;iv;&@TDUFI`YE^@s6ajV$acsLdZLp6I@sUhw z_3=SIU7C+i_lcGAHpnk-SH+mb4!xeu{wqNdeUz>ED>*ItDAmaOx9surfBO}%2_0}! zs2F|o2n#OOLebe->Ep%h_+KTN@A`$H$-zz(O@fNOywE=-ad|m8i`8t{Xg)*^#YGd9 z(aYDd?2Fy>%ltWz%!&_2#RYvBV=-Fp@bzv*b2WC8?dRjjZQhH`y0`->Wb~zc?MJ?` z=2CL>alz%cF@y~Aa_e;cZT>l%d}%7pWQQ*er(0O`<%+OlUhymx&-$~;mouwG?+1Wr z-(pz9Aqd3rXb935VW}K}aDs?K>dIe(YY`U$KnR6?5D>GF{*Ur?k=ZUA!=~cRoyg&; z+x&l+|8hd)$6lrJ(@OGMgQ2(H%XhO(dm4^P!|l1SX&>z`RduDjG_a5)$Ou=Ex z%TF=4JumEQh`n&q3B5ecivG@{X7=>odU)Qg{ku%>bZNTxtBv@O5;fTX_0Y@fao`ef zfJ*s>7lQKk-!Vls{zt0RphX>4d?YDGkIuV`p^(;8=?Imr9`*mJvD4EVE z87sMxFlfKaQ2U_$h!!vJ`>=iThDfdUkSt>R^|H8!^zaCOf;qn?p__g+>ug`*!~9%WM}5{6hK`|V0r!!w}bQs7%K*FI3SC*oOv z6*E$VFb{YEIExt&EG=eW2h!a>q#7|}Lat=sSv?>Q9y-8}#kLjoO}K1(D;& zI-&5h2r+Fvo103~X!PT}=sl6m*RU%upSRy=J1ttn6B5!n?kdOX}`9WJLcd75y=L$v6%? zn8!S}{MsO@W8YsJUsLQ-Mx~EnY=wE{(3MpYEmR)t4niMu^~)>0xB_jvxD2xtBHJCx zK<;AXE^w;?@dm`7e^`1U;&a)&>oM6Uy^!f72lM@bE9W8ar?`w{N$WqV$m^kaLj;^o z#T!Cfyf`qmT`%f#-x&(;wcGp!*MC;ab?1f~T~iX>ik;_HhXz*C?+?pN{BIc>%fC?< z+w5Eh&J!yv5iX>!1lHPmw*Q8yAr>l&qD~^P3U~_m8F~K(E&~2<;Z2J0?zeQf<|+~wfGn^H zLE|zW*wK&%m3)Y+!9p>>qj-5b($kTD0-gOC@=cHYLZl;5FAH(l7> zxs3gFvjUe6>9;cBwK?+ETKrzPHH2ofOt}oEkUBX5K6WeRq=rwxl|^XcKeFR2WXKPI z;8+~ybid#=LIJ5jna`2G5BLxeJDu6!G{CZd#U60A zyWCs>pXQ26g(=#K696;bPKvH_C|Vwc{?Sn$dQB5xXUBijoZZy7eJ_3tf}iD5CdUuA-s#czYz)*C;`tDz+Xs* zA(Ro`283kHK>8x$V&7kO3=@HRLVET^J~7DqTg)r>#9Qw1&s@UkrRai}*ShpLC8%07 z@?7uR=C`Yp+52|}#8f(^fNoAq^;UJS1vV!yV9q-=33qVJ{MdS-`(krnny_kurX&92 z*8b3s-Rrt1;wNePi!r=w0;{uA*OJ3HQ?){)BGxNY@8m<$r^Qbx5B@I16-`f&9Kme~y{| z72$WlXPt>|C7!PWK0taKa1n8#P>5A?7Mvhfj!;d7`uaJZ4?#Pt5l#li0tQ)?-HJ$Zj)yi9-{sqQFaUL!%c%jY2DbvNg`Cr-i^O-bFPpVUR(` zsYVb>NVqqV-T?6Zcexw)=iA(GmuFS>Q>fCT@VP!7u=sz89I9n^AKe+hkaQ0H@UHlU`;;euV zpNpUNHJYcu{(mTr_HpvTZdK0?kk!e<{VpEq_@`L~1Ks>#ii{E)HC|mby7b!rcwpDx z<*JGb(e zWz%73JJ@M=dh`L5=T;IRkQhifi}u76?SR$lm@6%y4?C^*_;{Z&5Wj1^&v!Xw`(57C znPQH^Vd8hs6}v)i_g%KH#!~x~P4XBcqM$CmhSWv?`tPfr4RmUo-aAXB2v2K&iP9&i zLY*dERnYDt?5w08DN>J1N0f8~RY)-^nosMbDixhZhfBLuG%5V1Bd=D~va=#@ipz-6E;gG&jcTe8ZTaP_a(9oLBA8Fqw~)s?>A~eOkJrroYjb+YblPc1mBC=4^8oj}422ZR{8llzZUoBe*Ut*KYDS`Cpp4tDIF>mMbH7!<=?@!VNjT(N=r%H#gmL|I&Mi-z@ZeskAYYmPGe*{$an(FZj;d zb)>NLHa{ZSBk7RHS~oRl(1HfH{4O3Wl|<13I#zl1=67XIiA5?sD*VC3|PutbNtD%q|?$ z7TcAEMdlZ3XrFjXPs?pSU22Y@J7}ads0%Hk-%1T#=uY~nWQwI@;i@GqiKRIS-ThBp zj)Q^wAO70Q6wY)rE-OHWc+@saCt_(C{aA|ZO4r9^JN&%L8*1*`C&?l{EpqW6q_(a! zeNcCY8hpP{9J_FASLox(=t>v=-aESb!7Z4dx4T32H{lWY&cfltmbW$s6Wg$1|9Q4I z@a(LV(v2q35UHda9hW`dYl7h~$oAKZ#1wCR;04#!nrBwDXzN|L#|{<3j1fJ){%UdY zC#A2t(c-W>9-)(p7tNAF;%HLc9q(-}JH%!Qf#dI5r66A=Ua<=`N2o+XSvZOf>Hvh@ zkJymjNBA#B!)fP8A-$EwOlNRCo8w{8j0*c)FvZ z*%kcX|H__xvc|;~zJ4&dsC)D{O;QB|b%uk`D97})K^6JK@@hAi8-9KczbQXu!1W{) z#>aSD&ae!USG#cy{3hH=0;lLHOQ)z-IQT86$qdJ6UHlXW&-UHo^8m@G3VhIEIY|3x z`UXpXB|v!mA!!rwA=D3&Iguv8-$j~}Nc+%%(iWUgYW{T9nN=Sq!}GAhHpe`tDxp?f zX5Zw?T!lojerDB8?sU!strg8W*zc~mB6W)0N>~D?>JMpMJl%a6H(ClqRA3ueBt^nw zBz&_==97FOfr-kL#wXFNZoOSgTjQYmE7?u{wsX3Ed8@MNCO1l(lhCn=(vL}WW66C` zUWpm(B!JlwX3W6-2WBNXmFRT9`^Zbh^LU^S5Cv0EBJxY5?a4Hoj%q)d3_Ajy+3rk% zPz>wm%P7;83en+_a`ljOYAM`+H~uOOFn~R$N|Ov&K!s8WY!AhUasM+0O19+(swqe&Hf|M2hsOs~zH~AXBsQRmPE1iCs^gphQ(*OP1LgwE(NzXgBTl_ue zEy%*}GpJs1-!0wDpetyx^n51G#LlxNla8b@((O#TGUSS*#r)W$oBS1NaSxhT9191J z^Z&fbC76~E`kLXlwaJ`PuVMtBj@{&A99iH=FaO<77G(a~< zMiWh=W~s_V_p5H`b)Plj^nLWWRbag z^y!z*w>D-5ojy;m^RFa)S@XKKw|9nFeA@AE$Mm7oi0$#|=D10;&ka6D^5^2MgC%2c zNT-*imAz>??JVu?O}B}LN9EDJqrdnb>OHpcm0&p!;>DPRLc~`AD}YYA8=QN-GOHLh z#+4W2%bZ+tgTLfcApe@DRNece@OtUqc!M`0Pds~3I+KSX@0LRPV85%9%KBi=2S{W4 z&^CqLD~0CMQ3*C22lJ=gdqMzVCRfDTdI zc1V2+X)oGOnpQ~lv`t!GNGC@N8;%&HSjghDoI2@#A;>daN-Cn`QTBx*TBO%{XzJQ> za$3X45@07L|V=`At$BXG|+Fu&opU#h80P3s)`d}ap2*p6ep!)8VF88O?V-LA6w!Q<8 zd6PD#TxruoMmYG#(&Q2vi}s!`p=tU(?q#^jA|``%>Cox=*xDQM8F;%E2AK#*;p<|1 zDxnEr_uoorQW$rN!@bCVO7fRrG76<`kI;qMJhy?2!dJ+dU=KNE5=2K#Uq9B3h$1XtRzXMc=X2gx!(;Q@USDadRr^%OL6+r2%EsOjk&2%0TV}X;&HD9h2=0Hw@5ENmR-& zdu!_tX>MZb=9W`!^f&Gzh`k#;*4bH~v+5e(E^REwNSmbl<=9AnkxUhs--Xhk3OX6e z&2|y2m(&A6g;P?&K)m3FG+v}uNoxkuq>vEDb)MvQ@M3B2KrEM$(os=nk7OT6C#auw z-Gr_)WDtbf8fo4jba|w-c@V9jO6kHN2)>&xNi`U9!CJKGjz1u5*?22a=%3 z;vv|(&b4P%(#Z-%?p*2Bp|q9;Nqi_x3!Cb`kINydyU&+M>1LXprE(idR$j8ufJi37 z`#iz*lsN~VPt@U#RNy{;%y*q{0uD(_&GZJo|33dj`m7oP;sxnSHGM8P1)rDQ;8>eAbSzyi9jKuRCdnHE`KvYz zfi_Bvd6vOu6}()p@ngO_c6^<+y0c1n@5EQ!=X)f74ShfVRcGzs`+UBmt9cImY{oB8 z8sX*W?F+vaEqK0zuk$JmQRbvZ;qn@0RsgFN?9Xl z2~CyiM$mDPVqc8_p`Vq4N756tRysM7wjo$OihfV0wvQc+g#;a;ZVb)J{?ZrP;^&39 z^ikP#wIqxvuk*cdZqvclNLPEE=izH7Vx;hHNXfa*drHT~(C6u!?ImOBNqi*G9y5-f zRA9HdGM@fOcefvS9PgtM(#nZ6UvbMReKC=CRUh-p{EBpXB1FzEDP$7%pH1!AA`m+L zqfg*WQz=PL(Day#PGRBDlg3K&dIvw}yv{dEwkPO9oX&<%rukvnPDN8V8DDi3d*@nY zWS(~Y)k=DmT0>iiAsXI@A+Dj7f3=+j=~IbkYI%guG@;5##2e}%v2&x5h9 zGvu9%zk!|XDjX4ou}*`W@or%cv+R$oQjsfg2n^WltFCa1 zKMdDR3fxr)%gAIjf0e7y&?0?B#qoGz2*T0)IQF7F1`EA#12{>HIe0(ZZe4H( zbR|L`O(+(ZY(bTT!Lt_sT)`qgEN=lPWk3Hq*dL6_F&|1#K1oxHi6hqBwJIL|WiB2U zc;P_@rZ}e&2W+~Iupsz=sUTQ8;P=Q63Y!_czi_c}pZ_Htev&4n2`aBeFVaBOcpwFc z+OJNf{X_8)>~%iRbCn;Jpl#?A@X2ZpX;mhMXOMH@##60P2Pfslkx<8agz1mp$}(RVlpzUb@fZj)2vsy%O$OvK?l=h>Bku~MgOAf zD*xKG+e~$jFCc00&wXV6XlO#MYD3JFT|;B0+~W~a#~jPy5YVJ+UV zMcQ6VO+ncpblzU+*IL>mcOF<&xN_7Zd=-=N3gCse`FHp#d>X_g^Xou^PS$ClK?vGT zlX7R%Z1ptkF{7m!v+05a$Rdr>?+o;GPYM<8Vm5=g>Lb20@-r z^BKTp`r_xoVS>}{V>4=-L#wnaJ)tdE_$p7hzN|t8O%oEp@MPtEo+QQA(fnWq_JJ#W zsx-2W#$?@hmzqac5yPe@gaxey8qXDYqy1mrgT93Gp$g64mDblmHlC7#pQ7_iN-%O^ z)y>4>JOZDs9teYBWENK)!e8qS^3DQwAQyUrSR{k-tQr_49efJP`ZVeGQ`j{ZNJ&pq z?I4|J8%%QVz<=q3^H~OxN|{Q(z__`RY`D+=$CFO}YE`n=%=P-XdR9ZUS9pfIZemVh_@@oGUz0YI_>OI8QqLG&NNvdFp%q%VrsB zG0&^+TtBaB(?l`yF}Uox!ksRZ3#_^zj2OGZI`X=X+~-@|D!5ub_)z;taL+C8HU5WG z^9=rdn7z{KXJ}E;7cdlM8iMpgV7tE0V*{xk`hkH|L?AUxUmi#W2U5@I2Lw_?az6u; z&SI%#E=@?Oa<0$u=PYX#+&07`u6D2DD)%a1gC%*DPmx}jOLJ???#maqgP89DHW1ef zJPx9Yi3nJYaoiRX^9Qh@Ao?6U6O+>&NCqY$Jq4Hs%#`lWrJJd$omprkrO&p%Gml1x zD6Y8LKmI4ZL)9VMaZT2~>qV$Z;lH3gfm0%sw2SDm2qDn_4bhVVp`P-QbaN5y7keG) zb_l~W2u}b%0l&7FG|+<3nS;J2n*BrI%ru5*Mm|b3Cmtgj?O37_`KOT{KaOZFts{Aqxqd>O(M$U6s|corMVGVofH^!sWWKYQ_{2X#gL z*;9#T#ss3teBwdgi481A7LKruQxHN|ygS>>anve$aDk8zikPwQR zZy^jp_yNLDgdZaeLwFb=E^Wvc2qO@FgD?`|z7MfyAhaSKjqohO7=#xPc0qUvVJt!! zVONAcgrcKL)QiLWNhl&(WW*yh0zH5{pg(XDg$E%V28;n72POm4fjPi4z(0U`paED0 ztOk~2l=0590=e z=|C1Bo{Qf1K`34-o{0{KI{gtJ2n+)z0Ly_nzfy@0`5+!oJf;ZhpT!{NK0z)2;L^bmn_Z7a%?MHch0TOAFt|Iq#IT5kbFu z-w7riNZ_1M2#&B2obSjAvQjW|6zT+?W#B0xwRlR%asoYyke=U5H{Yi5(3eBrp$SRT z|5G%I#Np`(@)&-Xkfow%qf~|>FegoVhZaXWP*SW08KGeQzoi}T(DbtRu@S}KZKA@5 zBCf^Jem)^x0?*9R6^w+Zh delta 19910 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 Date: Mon, 3 Aug 2026 01:18:25 +0200 Subject: [PATCH 32/42] Show progressive CW beacon text --- App/app/foxhunt.c | 92 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index ab34ff00..115a38da 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -88,6 +88,7 @@ #define FOXHUNT_BEACON_IDLE_MAX 60 // longest idle gap (s) #define FOXHUNT_BEACON_IDLE_STEP 5 // idle adjust step (s) #define FOXHUNT_CALLSIGN_ADDR 0x00A0C8u // boot message line 1 in SPI flash +#define FOXHUNT_CALLSIGN_MAX 12 // maximum boot-message characters used by the beacon // Attenuator via the BK4829 PGA (REG_13 bits 0..2) — the last gain stage before // the RSSI detector, so it scales the reading linearly. Reducing the early LNA @@ -136,10 +137,12 @@ static uint8_t beaconIdle; // configured silence between IDs (s) static uint8_t beaconIdleLeft; // seconds left in the current silence static uint8_t beaconIdleTick; // tick counter that clocks the idle countdown static char beaconMsg[24]; // CW message, e.g. "F4HWN BEACON" +static uint8_t beaconCharsSent; // characters completed in the current burst static void FOXHUNT_EnterHunt(void); static void FOXHUNT_EnterBeacon(void); static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft); +static void FOXHUNT_UpdateBeaconProgress(uint8_t visibleChars); static void FOXHUNT_SaveConfig(void); // Read the calibrated signal level of the current RX VFO, in dBm. @@ -699,12 +702,16 @@ static uint8_t FOXHUNT_MorseByte(char c) // Send one character as modulated CW: key the running TX tone on per element, // muting the modulation (carrier stays up) between them. Returns true if aborted. -static bool FOXHUNT_MorseChar(char c) +static bool FOXHUNT_MorseChar(char c, uint8_t visibleChars) { uint8_t code = FOXHUNT_MorseByte(c); - if (code == 0) // space / unknown -> word gap - return FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 4); + if (code == 0) { // space / unknown -> word gap + if (FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 4)) + return true; + FOXHUNT_UpdateBeaconProgress(visibleChars); + return false; + } uint8_t bit = 0x80; while (!(code & bit)) bit >>= 1; // skip to the sentinel bit @@ -716,6 +723,12 @@ static bool FOXHUNT_MorseChar(char c) BK4819_EnterTxMute(); if (FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS)) return true; // intra gap } + + // Reveal the character once all its CW elements have been transmitted. The + // remaining two units keep the completed character visible during the rest + // of the standard three-unit inter-character gap. + FOXHUNT_UpdateBeaconProgress(visibleChars); + // Inter-character gap is 3 units; one already elapsed after the last element. return FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 2); } @@ -732,7 +745,7 @@ static void FOXHUNT_BeaconTransmit(void) bool stop = false; for (uint8_t i = 0; !stop && beaconMsg[i]; i++) - stop = FOXHUNT_MorseChar(beaconMsg[i]); + stop = FOXHUNT_MorseChar(beaconMsg[i], i + 1u); // Key down: mute, drop the PA and restore RX for the silent gap. If the burst // was interrupted, FOXHUNT_TxDelay already set the target mode (quit or hunt). @@ -741,14 +754,72 @@ static void FOXHUNT_BeaconTransmit(void) RADIO_SetupRegisters(true); } +// Draw the transmitted portion of " BEACON" on two normal-font lines at +// their final positions: the boot message first, then BEACON below it. +static void FOXHUNT_DrawBeaconMessage(uint8_t visibleChars) +{ + static const char suffix[] = "BEACON"; + const char *separator = strchr(beaconMsg, ' '); + + if (separator == NULL) { + return; + } + + const size_t callLen = (size_t)(separator - beaconMsg); + const size_t visibleCallLen = MIN((size_t)visibleChars, callLen); + char call[FOXHUNT_CALLSIGN_MAX + 1]; + memcpy(call, beaconMsg, visibleCallLen); + call[visibleCallLen] = '\0'; + + const uint8_t callX = (uint8_t)((LCD_WIDTH - callLen * 8u) / 2u); + UI_PrintString(call, callX, 0, 2, 8); + + if ((size_t)visibleChars > callLen + 1u) { + const size_t visibleSuffixLen = MIN((size_t)visibleChars - callLen - 1u, + sizeof(suffix) - 1u); + char visibleSuffix[sizeof(suffix)]; + memcpy(visibleSuffix, suffix, visibleSuffixLen); + visibleSuffix[visibleSuffixLen] = '\0'; + UI_PrintString(visibleSuffix, + (uint8_t)((LCD_WIDTH - (sizeof(suffix) - 1u) * 8u) / 2u), + 0, 4, 8); + } +} + +// Update only the line pair whose latest character changed so screen refreshes +// do not lengthen the Morse timing more than necessary. +static void FOXHUNT_UpdateBeaconProgress(uint8_t visibleChars) +{ + const char *separator = strchr(beaconMsg, ' '); + const size_t callLen = separator != NULL ? (size_t)(separator - beaconMsg) : 0u; + + beaconCharsSent = visibleChars; + + if ((size_t)visibleChars <= callLen) { + memset(gFrameBuffer[2], 0, sizeof(gFrameBuffer[2])); + memset(gFrameBuffer[3], 0, sizeof(gFrameBuffer[3])); + FOXHUNT_DrawBeaconMessage(beaconCharsSent); + ST7565_BlitLine(2); + ST7565_BlitLine(3); + } else if ((size_t)visibleChars > callLen + 1u) { + memset(gFrameBuffer[4], 0, sizeof(gFrameBuffer[4])); + memset(gFrameBuffer[5], 0, sizeof(gFrameBuffer[5])); + FOXHUNT_DrawBeaconMessage(beaconCharsSent); + ST7565_BlitLine(4); + ST7565_BlitLine(5); + } +} + static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft) { // Frame (clear + BEACON tag + battery + TX frequency). FOXHUNT_BeaconChrome(); - // Centre, on two lines: the state, and below it the idle countdown (idle only). + // The TX layout starts one line higher so the bottom information remains + // visible below the two progressively completed message lines. if (txNow) { - UI_PrintString("TX", 0, 127, 1, 10); + UI_PrintString("TX", 0, 127, 0, 10); + FOXHUNT_DrawBeaconMessage(beaconCharsSent); } else { UI_PrintString("IDLE", 0, 127, 1, 10); sprintf(str, "%02us", idleLeft); @@ -807,6 +878,7 @@ static void FOXHUNT_BeaconTick(void) return; } + beaconCharsSent = 0; FOXHUNT_BeaconDraw(true, 0); ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); @@ -935,11 +1007,11 @@ void APP_RunFoxHunt(void) // Build the CW message " BEACON": the callsign is the boot message // (line 1), sanitised to what Morse can send; empty/erased falls back to FOX. { - char call[16]; + char call[FOXHUNT_CALLSIGN_MAX + 1]; uint8_t n = 0; - PY25Q16_ReadBuffer(FOXHUNT_CALLSIGN_ADDR, call, sizeof(call) - 1); - call[sizeof(call) - 1] = '\0'; - for (uint8_t i = 0; i < sizeof(call) - 1; i++) { + PY25Q16_ReadBuffer(FOXHUNT_CALLSIGN_ADDR, call, FOXHUNT_CALLSIGN_MAX); + call[FOXHUNT_CALLSIGN_MAX] = '\0'; + for (uint8_t i = 0; i < FOXHUNT_CALLSIGN_MAX; i++) { char c = call[i]; if (c == '\0' || (uint8_t)c == 0xFF) break; From d5cde97e5b46fe1861df7d21358eb2d9a680e2aa Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Mon, 3 Aug 2026 01:18:55 +0200 Subject: [PATCH 33/42] Update rolling Fusion development firmware --- archive/f4hwn.fusion.development.bin | Bin 108232 -> 108576 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/archive/f4hwn.fusion.development.bin b/archive/f4hwn.fusion.development.bin index 36c6cf73a8a78cd32c97ae806ea83234dbe84da8..9461d5b31e4dccc026cd69646e662c014dc5268f 100755 GIT binary patch delta 8898 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 Date: Mon, 3 Aug 2026 23:35:02 +0200 Subject: [PATCH 34/42] Rework Fox Hunt/Beacon for ARDF: fox IDs, TX window, unified keys --- App/app/foxhunt.c | 445 +++++++++++++++++++++++++------------ App/driver/eeprom_compat.c | 4 +- 2 files changed, 305 insertions(+), 144 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 115a38da..4b7be3c4 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -77,19 +77,47 @@ #define FOXHUNT_AUDIO_STATION 2 // --- Beacon (fox) sub-mode --------------------------------------------------- -// Turns the radio into the hidden transmitter: each cycle keys up on the TX VFO -// and sends the CW message (" BEACON") in Morse, then stays silent for the -// (adjustable) idle gap. The carrier stays up during the message; only the tone -// modulation is keyed on/off (EnterTxMute/ExitTxMute) = MCW on FM. +// Turns the radio into the hidden transmitter: each cycle keys up on the TX VFO and +// repeats the CW fox identifier (MOE..MO5, or " MOE") in Morse for the TX window, +// then stays silent for the (adjustable) idle gap. The carrier stays up during the +// window; only the tone modulation is keyed on/off (EnterTxMute/ExitTxMute) = MCW on FM. #define FOXHUNT_BEACON_TONE_HZ 1000 // CW tone pitch (Hz) -#define FOXHUNT_MORSE_UNIT_MS 80 // one Morse time unit (~15 WPM) +#define FOXHUNT_MORSE_UNIT_MS 100 // one Morse time unit (~12 WPM, ARDF pace) #define FOXHUNT_BEACON_IDLE_DEF 30 // default silence between IDs (s) #define FOXHUNT_BEACON_IDLE_MIN 5 // shortest idle gap (s) -#define FOXHUNT_BEACON_IDLE_MAX 60 // longest idle gap (s) +#define FOXHUNT_BEACON_IDLE_MAX 240 // longest idle gap (s) — 4 min = the ARDF + // silence of a 5-fox cycle (60 s TX x4) #define FOXHUNT_BEACON_IDLE_STEP 5 // idle adjust step (s) +// TX window: the ID is repeated for this many seconds each cycle (a real ARDF fox keys +// up for a fixed slot, not a single one-shot). 60 s = the classic ARDF slot. +#define FOXHUNT_BEACON_TX_DEF 30 // default TX window (s) +#define FOXHUNT_BEACON_TX_MIN 5 // shortest TX window (s) +#define FOXHUNT_BEACON_TX_MAX 60 // longest TX window (s) +#define FOXHUNT_BEACON_TX_STEP 5 // TX adjust step (s) #define FOXHUNT_CALLSIGN_ADDR 0x00A0C8u // boot message line 1 in SPI flash #define FOXHUNT_CALLSIGN_MAX 12 // maximum boot-message characters used by the beacon +// Fox identifier (3 key). MOE..MO5 are the five standard IARU ARDF foxes ("MO" + 1..5 +// dits: E I S H 5); MO is the ARDF finish/home beacon (transmitted continuously on a real +// course — here it rides the normal TX/IDLE cycle, so set a short IDLE for a near-constant +// MO); CALL prefixes the operator's callsign (legal ID on the ham bands): " MOE". +// Pure MOE..MO5 / MO (no callsign) suit casual / PMR fox games. +#define FOXHUNT_FOX_MOE 0 +#define FOXHUNT_FOX_MOI 1 +#define FOXHUNT_FOX_MOS 2 +#define FOXHUNT_FOX_MOH 3 +#define FOXHUNT_FOX_MO5 4 +#define FOXHUNT_FOX_MO 5 +#define FOXHUNT_FOX_CALL 6 +#define FOXHUNT_FOX_COUNT 7 + +// Framebuffer lines for the transmitted message (gFontBig spans two lines each): +// CALL id shows the callsign on _CALL and the "MOx" below on _ID; a pure single-word +// fox (MOE..MO5) is centred on _ONE. +#define FOXHUNT_MSG_LINE_CALL 1 +#define FOXHUNT_MSG_LINE_ID 3 +#define FOXHUNT_MSG_LINE_ONE 2 + // Attenuator via the BK4829 PGA (REG_13 bits 0..2) — the last gain stage before // the RSSI detector, so it scales the reading linearly. Reducing the early LNA // alone barely moved the reading on strong signals (mixer + PGA re-amplify). @@ -106,6 +134,7 @@ static uint8_t foxGraphMode; // FOXHUNT_GRAPH_BAR / _HIST, cycled by the 2 key static uint8_t attStep; static int16_t curDbm; static int16_t peakDbm; +static int16_t minDbm; // lowest level held since the last reset (body-scan null) static int16_t trendRef; static int16_t trendDelta; static uint8_t trendTick; @@ -130,19 +159,28 @@ static const uint8_t FOXHUNT_MORSE_DIGIT[10] = { 0x3F, 0x2F, 0x27, 0x23, 0x21, 0x20, 0x30, 0x38, 0x3C, 0x3E, // 0..9 }; +// Trailing character of each fox id: MOE / MOI / MOS / MOH / MO5 (index = FOXHUNT_FOX_*). +static const char FOXHUNT_FOX_TAIL[5] = {'E', 'I', 'S', 'H', '5'}; + // Beacon sub-mode state. static bool foxBeacon; // false = hunt (RX), true = beacon (TX) static bool beaconPhaseTx; // true = transmit this tick, false = idle gap static uint8_t beaconIdle; // configured silence between IDs (s) static uint8_t beaconIdleLeft; // seconds left in the current silence static uint8_t beaconIdleTick; // tick counter that clocks the idle countdown -static char beaconMsg[24]; // CW message, e.g. "F4HWN BEACON" +static char beaconMsg[24]; // CW message, e.g. "F4HWN MOE" or "MOS" static uint8_t beaconCharsSent; // characters completed in the current burst +static uint8_t beaconTx; // TX window length (s): the ID repeats for this long +static uint16_t beaconTxMsLeft; // ms left in the current TX window (drained as it plays) +static uint8_t beaconTxSecShown; // whole-second value last painted on the TX line +static uint8_t foxFox; // selected fox identifier (FOXHUNT_FOX_*) +static char foxCall[FOXHUNT_CALLSIGN_MAX + 1]; // sanitised callsign for the CALL id static void FOXHUNT_EnterHunt(void); static void FOXHUNT_EnterBeacon(void); static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft); static void FOXHUNT_UpdateBeaconProgress(uint8_t visibleChars); +static void FOXHUNT_BuildBeaconMsg(void); static void FOXHUNT_SaveConfig(void); // Read the calibrated signal level of the current RX VFO, in dBm. @@ -320,6 +358,25 @@ static void FOXHUNT_DrawHist(void) } } +// Push the status line and the full frame buffer to the LCD, then mirror to K5Viewer. +// Factored out because the same argument-less sequence runs after every full redraw +// (hunt loop, beacon idle, beacon burst, TX-denied notice). +static void FOXHUNT_BlitScreen(void) +{ + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + K5VIEWER_Update(false); +#endif +} + +// Draw a left-anchored inverse tag in the smallest font (the PK / MN / ATT / beacon +// setting style). The box spans the text width, so the caller only gives x and the line. +static void FOXHUNT_Tag(const char *s, uint8_t x, uint8_t line) +{ + GUI_DisplaySmallestInverse(s, x, line, false, true, (uint8_t)(x + strlen(s) * 4)); +} + // Battery icon plus the optional voltage/percentage text, top-right of the status // line — shared by the hunt and beacon screens. static void FOXHUNT_DrawStatusBattery(void) @@ -408,10 +465,13 @@ static void FOXHUNT_Draw(void) UI_PrintStringSmallNormal(str, 127 - 3 * 7 - 2 - strlen(str) * 7, 0, 1); } - // Context line: peak hold (left) and S-meter (right) as small inverse labels - // (scan-list tag style, 4 px/char). + // Context line: peak hold (left), min hold (centre) and S-meter (right) as small + // inverse labels (scan-list tag style, 4 px/char). PK and MN bracket a body-scan + // rotation — the deeper MN sits below PK, the sharper the null. sprintf(str, "PK %d", peakDbm); - GUI_DisplaySmallestInverse(str, 4, 2, false, true, 4 + strlen(str) * 4); + FOXHUNT_Tag(str, 4, 2); + sprintf(str, "MN %d", minDbm); + FOXHUNT_Tag(str, (uint8_t)((LCD_WIDTH - strlen(str) * 4) / 2), 2); FOXHUNT_BuildS(sMeter, curDbm); GUI_DisplaySmallestInverse(sMeter, 126 - strlen(sMeter) * 4, 2, false, true, 125); @@ -432,37 +492,53 @@ static void FOXHUNT_Draw(void) // Attenuator as an inverse label (left), tuned frequency (right). sprintf(str, "ATT %ddB", FOXHUNT_ATT_DB[attStep]); - GUI_DisplaySmallestInverse(str, 4, 6, false, true, 4 + strlen(str) * 4); + FOXHUNT_Tag(str, 4, 6); FOXHUNT_DrawFreqBR(gRxVfo->pRX->Frequency); } -// Map a navigation key to a logical step (+1 = up/increase, -1 = down/decrease), -// honouring the SET_NAV up/down orientation (UV-K1 vs UV-K5), like the rest of -// the firmware (see MAIN_Key_UP_DOWN / spectrum GetDirection). -static int8_t FOXHUNT_NavDir(KEY_Code_t key) +// One key = one setting, each press cycling to the next value and wrapping — the same +// scheme for the hunt gauges and the beacon settings, so there are no navigation arrows +// to learn. FOXHUNT_ApplyAtt is re-asserted for the attenuator; the beacon values are +// read where they take effect (TX window at the burst start, idle at the burst end, fox +// at the next repeat), so cycling any of them is safe at any time, TX included. + +// Attenuator: 0 -> -6 -> -15 -> -27 -> 0 dB. +static void FOXHUNT_AttCycle(void) { - int8_t dir = (key == KEY_UP) ? 1 : -1; - return gEeprom.SET_NAV ? dir : -dir; + attStep = (uint8_t)((attStep + 1) & 3); + FOXHUNT_ApplyAtt(); } -// Change the attenuator by one step in the given direction. -static void FOXHUNT_AttStep(int8_t dir) +// Fox identifier: MOE -> MOI -> MOS -> MOH -> MO5 -> CALL -> MOE. +static void FOXHUNT_FoxCycle(void) { - if (dir > 0) { - if (attStep < 3) { attStep++; FOXHUNT_ApplyAtt(); } - } else { - if (attStep > 0) { attStep--; FOXHUNT_ApplyAtt(); } - } + foxFox = (uint8_t)((foxFox + 1) % FOXHUNT_FOX_COUNT); } -// Change the beacon idle gap by one step in the given direction (shared by the -// idle-phase keys and the mid-transmission adjust). -static void FOXHUNT_IdleStep(int8_t dir) +// TX window: 5 s up to 60 s, then back to 5 s. +static void FOXHUNT_TxCycle(void) { - if (dir > 0) { - if (beaconIdle < FOXHUNT_BEACON_IDLE_MAX) beaconIdle += FOXHUNT_BEACON_IDLE_STEP; - } else { - if (beaconIdle > FOXHUNT_BEACON_IDLE_MIN) beaconIdle -= FOXHUNT_BEACON_IDLE_STEP; + beaconTx = (beaconTx >= FOXHUNT_BEACON_TX_MAX) + ? FOXHUNT_BEACON_TX_MIN : (uint8_t)(beaconTx + FOXHUNT_BEACON_TX_STEP); +} + +// Idle gap: 5 s up to 240 s, then back to 5 s. +static void FOXHUNT_IdleCycle(void) +{ + beaconIdle = (beaconIdle >= FOXHUNT_BEACON_IDLE_MAX) + ? FOXHUNT_BEACON_IDLE_MIN : (uint8_t)(beaconIdle + FOXHUNT_BEACON_IDLE_STEP); +} + +// Apply a beacon number key; returns true when it changed a setting so the caller can +// refresh. The keys follow the on-screen layout: 1 = TX (top-left), 2 = IDLE (below it), +// 3 = FOX (right). Shared by both beacon phases. +static bool FOXHUNT_BeaconKey(KEY_Code_t key) +{ + switch (key) { + case KEY_1: FOXHUNT_TxCycle(); return true; + case KEY_2: FOXHUNT_IdleCycle(); return true; + case KEY_3: FOXHUNT_FoxCycle(); return true; + default: return false; } } @@ -534,32 +610,26 @@ static void FOXHUNT_HandleKeys(void) case KEY_EXIT: foxRunning = false; break; - case KEY_UP: - case KEY_DOWN: - // Arrows follow SET_NAV; the 4/0 alternates below stay fixed. - FOXHUNT_AttStep(FOXHUNT_NavDir(kbd.current)); - break; - case KEY_4: - FOXHUNT_AttStep(1); - break; - case KEY_0: - FOXHUNT_AttStep(-1); - break; - case KEY_MENU: - // Reset the peak hold and the trend reference. - peakDbm = curDbm; - trendRef = curDbm; - break; case KEY_1: + // Toggle the main gauge: S-meter staircase <-> full-width history. + foxGraphMode ^= 1; + break; + case KEY_2: // Cycle the audio: silent -> Geiger beep -> station audio -> silent. foxAudioMode = (uint8_t)((foxAudioMode + 1) % 3); FOXHUNT_SetAudio(); if (foxAudioMode == FOXHUNT_AUDIO_BEEP) audioTick = FOXHUNT_RATE_SLOW_TICKS; // blip promptly break; - case KEY_2: - // Toggle the main gauge: S-meter staircase <-> full-width history. - foxGraphMode ^= 1; + case KEY_3: + // Cycle the attenuator (0 -> -6 -> -15 -> -27 dB, then back to 0). + FOXHUNT_AttCycle(); + break; + case KEY_MENU: + // Reset the peak / min hold and the trend reference (before each body scan). + peakDbm = curDbm; + minDbm = curDbm; + trendRef = curDbm; break; case KEY_SIDE1: case KEY_SIDE2: @@ -585,6 +655,7 @@ static void FOXHUNT_EnterHunt(void) curDbm = FOXHUNT_ReadDbm(); peakDbm = curDbm; + minDbm = curDbm; trendRef = curDbm; trendDelta = 0; trendTick = 0; @@ -636,8 +707,7 @@ static void FOXHUNT_TxDeniedNotice(VfoState_t state) // on line 1 so it sits exactly where the beacon's "TX" / "IDLE" text appears. UI_PrintString(VfoStateStr[state], 0, 127, 1, 8); - ST7565_BlitStatusLine(); - ST7565_BlitFullScreen(); + FOXHUNT_BlitScreen(); // Hold the notice ~1 s while keeping the backlight fade alive. for (uint8_t i = 0; i < 20; i++) @@ -654,16 +724,42 @@ static void FOXHUNT_EnterBeacon(void) beaconPhaseTx = true; } -// Sleep in short slices while watching the keypad, so a burst stays interactive: -// EXIT cuts it mid-air (returns true), and UP/DOWN retune the idle gap live. +// Paint the TX line (line 0): "TX" left, remaining-window seconds right. Kept separate +// so FOXHUNT_TxDelay can refresh just this line each second, live, without redrawing the +// whole screen mid-Morse. Records the value shown so the caller only repaints on change. +static void FOXHUNT_DrawTxSeconds(void) +{ + const uint8_t sec = (uint8_t)((beaconTxMsLeft + 999u) / 1000u); + memset(gFrameBuffer[0], 0, sizeof(gFrameBuffer[0])); + UI_PrintStringSmallNormal("TX", 1, 0, 0); + sprintf(str, "%02us", sec); + UI_PrintStringSmallNormal(str, (uint8_t)(127 - strlen(str) * 7), 0, 0); + beaconTxSecShown = sec; +} + +// Sleep in short slices while watching the keypad, so a burst stays interactive and the +// TX-window countdown (beaconTxMsLeft) drains in real time. EXIT leaves Fox Hunt and a +// side key aborts back to the hunt (both return true). The 1/2/3 keys edit the beacon +// settings live, exactly as in the idle phase: the TX window (1) and idle gap (2) take +// effect at the upcoming window / gap, and a FOX change (3) at the next repeat (the +// message is rebuilt there, never under the running loop). static bool FOXHUNT_TxDelay(uint16_t ms) { while (ms) { const uint16_t slice = (ms > 10) ? 10 : ms; // 10 ms: same fade rate as idle SYSTEM_DelayMs(slice); ms -= slice; + beaconTxMsLeft = (beaconTxMsLeft > slice) ? (beaconTxMsLeft - slice) : 0; BACKLIGHT_Update(); // keep any brightness fade moving in TX + // Tick the remaining-window seconds live: repaint only line 0 when the whole + // second changes, so the countdown drains smoothly through a long ID instead of + // jumping once per repeat (a one-line blit barely dents the Morse timing). + if ((uint8_t)((beaconTxMsLeft + 999u) / 1000u) != beaconTxSecShown) { + FOXHUNT_DrawTxSeconds(); + ST7565_BlitLine(0); + } + kbd.prev = kbd.current; kbd.current = KEYBOARD_GetKey(); if (kbd.current == KEY_INVALID || kbd.current == kbd.prev) @@ -679,11 +775,14 @@ static bool FOXHUNT_TxDelay(uint16_t ms) foxBeacon = false; // abort the burst and switch back to hunt return true; } - if (kbd.current == KEY_UP || kbd.current == KEY_DOWN) { - // The gap is only read once the burst ends, so it is safe to change - // now; refresh the "IDLE nn" label so the change is visible at once. - FOXHUNT_IdleStep(FOXHUNT_NavDir(kbd.current)); - FOXHUNT_BeaconDraw(true, 0); + if (kbd.current == KEY_MENU) { + // Cut the transmission short but stay in Beacon: aborting the burst without + // clearing foxBeacon/foxRunning drops the loop straight into a fresh idle + // gap of the configured IDLE length. + return true; + } + if (FOXHUNT_BeaconKey(kbd.current)) { + FOXHUNT_BeaconDraw(true, 0); // show the new value immediately ST7565_BlitFullScreen(); } } @@ -733,8 +832,10 @@ static bool FOXHUNT_MorseChar(char c, uint8_t visibleChars) return FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 2); } -// One beacon burst: transmit the CW identification message once, at the TX VFO's -// configured power. Carrier stays up; the tone is keyed per Morse element (MCW). +// One beacon cycle: repeat the CW identification for the whole TX window, at the TX +// VFO's configured power. Carrier stays up across the window; the tone is keyed per +// Morse element (MCW), and the ID is re-sent until the window drains — a real ARDF fox +// keys up for a fixed slot rather than sending a single one-shot. static void FOXHUNT_BeaconTransmit(void) { RADIO_SetTxParameters(); // key up: carrier + PA @@ -743,9 +844,28 @@ static void FOXHUNT_BeaconTransmit(void) BK4819_TransmitTone(false, FOXHUNT_BEACON_TONE_HZ); BK4819_EnterTxMute(); + beaconTxMsLeft = (uint16_t)beaconTx * 1000u; // drained inside FOXHUNT_TxDelay + bool stop = false; - for (uint8_t i = 0; !stop && beaconMsg[i]; i++) - stop = FOXHUNT_MorseChar(beaconMsg[i], i + 1u); + while (!stop && beaconTxMsLeft > 0) { + // Rebuild from the current fox at the repeat boundary — this is where a FOX + // change made live (during the previous repeat or the idle gap) takes effect, + // never mid-message. + FOXHUNT_BuildBeaconMsg(); + + // Redraw once per repeat (remaining-window countdown + reset progress), in the + // muted gap so it never stretches a Morse element. + beaconCharsSent = 0; + FOXHUNT_BeaconDraw(true, 0); + FOXHUNT_BlitScreen(); + + for (uint8_t i = 0; !stop && beaconMsg[i]; i++) + stop = FOXHUNT_MorseChar(beaconMsg[i], i + 1u); + + // Word gap before the next repeat, only while the window still has room. + if (!stop && beaconTxMsLeft > 0) + stop = FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 7); + } // Key down: mute, drop the PA and restore RX for the silent gap. If the burst // was interrupted, FOXHUNT_TxDelay already set the target mode (quit or hunt). @@ -754,14 +874,49 @@ static void FOXHUNT_BeaconTransmit(void) RADIO_SetupRegisters(true); } -// Draw the transmitted portion of " BEACON" on two normal-font lines at -// their final positions: the boot message first, then BEACON below it. +// Build the CW message from the current fox id: " MOE" for CALL (falls back to a +// bare MOE when no callsign is set), otherwise the pure "MOx" of the chosen fox. +static void FOXHUNT_BuildBeaconMsg(void) +{ + if (foxFox == FOXHUNT_FOX_CALL) { + if (foxCall[0] != '\0') + sprintf(beaconMsg, "%s MOE", foxCall); + else + strcpy(beaconMsg, "MOE"); + } else if (foxFox == FOXHUNT_FOX_MO) { + strcpy(beaconMsg, "MO"); // ARDF finish/home beacon + } else { + sprintf(beaconMsg, "MO%c", FOXHUNT_FOX_TAIL[foxFox]); + } +} + +// Short label for the FOX setting: "FOX CALL" or "FOX MOx". +static void FOXHUNT_FoxLabel(char *out) +{ + if (foxFox == FOXHUNT_FOX_CALL) + strcpy(out, "FOX CALL"); + else if (foxFox == FOXHUNT_FOX_MO) + strcpy(out, "FOX MO"); + else + sprintf(out, "FOX MO%c", FOXHUNT_FOX_TAIL[foxFox]); +} + +// Draw the transmitted portion of the message. A CALL id splits on the space: callsign +// on the upper line, "MOx" below. A pure fox (no space) is centred on one line. Each +// revealed prefix keeps the anchor of the full string, so characters appear in place +// instead of re-centring as they arrive. static void FOXHUNT_DrawBeaconMessage(uint8_t visibleChars) { - static const char suffix[] = "BEACON"; const char *separator = strchr(beaconMsg, ' '); - if (separator == NULL) { + if (separator == NULL) { // pure fox id (MOE..MO5) + const size_t idLen = strlen(beaconMsg); + const size_t visLen = MIN((size_t)visibleChars, idLen); + char id[sizeof(beaconMsg)]; + memcpy(id, beaconMsg, visLen); + id[visLen] = '\0'; + UI_PrintString(id, (uint8_t)((LCD_WIDTH - idLen * 8u) / 2u), 0, + FOXHUNT_MSG_LINE_ONE, 8); return; } @@ -770,65 +925,74 @@ static void FOXHUNT_DrawBeaconMessage(uint8_t visibleChars) char call[FOXHUNT_CALLSIGN_MAX + 1]; memcpy(call, beaconMsg, visibleCallLen); call[visibleCallLen] = '\0'; - - const uint8_t callX = (uint8_t)((LCD_WIDTH - callLen * 8u) / 2u); - UI_PrintString(call, callX, 0, 2, 8); + UI_PrintString(call, (uint8_t)((LCD_WIDTH - callLen * 8u) / 2u), 0, + FOXHUNT_MSG_LINE_CALL, 8); if ((size_t)visibleChars > callLen + 1u) { - const size_t visibleSuffixLen = MIN((size_t)visibleChars - callLen - 1u, - sizeof(suffix) - 1u); - char visibleSuffix[sizeof(suffix)]; - memcpy(visibleSuffix, suffix, visibleSuffixLen); - visibleSuffix[visibleSuffixLen] = '\0'; - UI_PrintString(visibleSuffix, - (uint8_t)((LCD_WIDTH - (sizeof(suffix) - 1u) * 8u) / 2u), - 0, 4, 8); + const char *id = separator + 1; + const size_t idLen = strlen(id); + const size_t visibleIdLen = MIN((size_t)visibleChars - callLen - 1u, idLen); + char idbuf[8]; + memcpy(idbuf, id, visibleIdLen); + idbuf[visibleIdLen] = '\0'; + UI_PrintString(idbuf, (uint8_t)((LCD_WIDTH - idLen * 8u) / 2u), 0, + FOXHUNT_MSG_LINE_ID, 8); } } -// Update only the line pair whose latest character changed so screen refreshes -// do not lengthen the Morse timing more than necessary. +// Update only the line pair whose latest character changed so screen refreshes do not +// lengthen the Morse timing more than necessary. static void FOXHUNT_UpdateBeaconProgress(uint8_t visibleChars) { const char *separator = strchr(beaconMsg, ' '); - const size_t callLen = separator != NULL ? (size_t)(separator - beaconMsg) : 0u; + uint8_t topLine; beaconCharsSent = visibleChars; - if ((size_t)visibleChars <= callLen) { - memset(gFrameBuffer[2], 0, sizeof(gFrameBuffer[2])); - memset(gFrameBuffer[3], 0, sizeof(gFrameBuffer[3])); - FOXHUNT_DrawBeaconMessage(beaconCharsSent); - ST7565_BlitLine(2); - ST7565_BlitLine(3); - } else if ((size_t)visibleChars > callLen + 1u) { - memset(gFrameBuffer[4], 0, sizeof(gFrameBuffer[4])); - memset(gFrameBuffer[5], 0, sizeof(gFrameBuffer[5])); - FOXHUNT_DrawBeaconMessage(beaconCharsSent); - ST7565_BlitLine(4); - ST7565_BlitLine(5); + if (separator == NULL) { // pure fox id + topLine = FOXHUNT_MSG_LINE_ONE; + } else { + const size_t callLen = (size_t)(separator - beaconMsg); + if ((size_t)visibleChars == callLen + 1u) // the space: nothing new to show + return; + topLine = ((size_t)visibleChars <= callLen) + ? FOXHUNT_MSG_LINE_CALL + : FOXHUNT_MSG_LINE_ID; } + + memset(gFrameBuffer[topLine], 0, sizeof(gFrameBuffer[topLine])); + memset(gFrameBuffer[topLine + 1], 0, sizeof(gFrameBuffer[topLine + 1])); + FOXHUNT_DrawBeaconMessage(beaconCharsSent); + ST7565_BlitLine(topLine); + ST7565_BlitLine(topLine + 1); } static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft) { - // Frame (clear + BEACON tag + battery + TX frequency). + // Frame (clear + BEACON tag + battery + TX frequency on the bottom-right). FOXHUNT_BeaconChrome(); - // The TX layout starts one line higher so the bottom information remains - // visible below the two progressively completed message lines. if (txNow) { - UI_PrintString("TX", 0, 127, 0, 10); + // Top line: "TX" + remaining window seconds (refreshed live in FOXHUNT_TxDelay). + FOXHUNT_DrawTxSeconds(); FOXHUNT_DrawBeaconMessage(beaconCharsSent); } else { + // Silence phase: big "IDLE" with the countdown to the next burst below it. UI_PrintString("IDLE", 0, 127, 1, 10); sprintf(str, "%02us", idleLeft); UI_PrintString(str, 0, 127, 3, 10); } - // Bottom-left: the idle-duration setting as an inverse label (ATT style). - sprintf(str, "IDLE %02u", beaconIdle); - GUI_DisplaySmallestInverse(str, 4, 6, false, true, 4 + strlen(str) * 4); + // Bottom-left column: 1 = TX window over 2 = IDLE gap. Bottom-right: 3 = FOX id over + // the freq (drawn by FOXHUNT_BeaconChrome). All three are inverse tags; each has its + // own number key, editable in either phase, so there is no cursor to show. + sprintf(str, "TX %us", beaconTx); + FOXHUNT_Tag(str, 4, 5); + sprintf(str, "IDLE %us", beaconIdle); + FOXHUNT_Tag(str, 4, 6); + + FOXHUNT_FoxLabel(str); + FOXHUNT_Tag(str, (uint8_t)(125 - strlen(str) * 4), 5); } static void FOXHUNT_BeaconKeys(void) @@ -849,12 +1013,14 @@ static void FOXHUNT_BeaconKeys(void) case KEY_SIDE2: foxBeacon = false; // toggle back to the hunt break; - case KEY_UP: - case KEY_DOWN: - // Idle duration, arrows following the SET_NAV orientation. - FOXHUNT_IdleStep(FOXHUNT_NavDir(kbd.current)); + case KEY_MENU: + // Restart a full idle interval now (the TX-phase M drops here too). + beaconIdleLeft = beaconIdle; + beaconIdleTick = 0; break; default: + // 1 = TX window, 2 = idle gap, 3 = fox (same keys as during TX). + FOXHUNT_BeaconKey(kbd.current); break; } } @@ -878,14 +1044,10 @@ static void FOXHUNT_BeaconTick(void) return; } - beaconCharsSent = 0; - FOXHUNT_BeaconDraw(true, 0); - ST7565_BlitStatusLine(); - ST7565_BlitFullScreen(); -#ifdef ENABLE_FEAT_F4HWN_K5VIEWER - K5VIEWER_Update(false); -#endif - FOXHUNT_BeaconTransmit(); // may clear foxBeacon (abort) + // The burst repeats the ID for the whole TX window, redrawing the screen + // itself each repeat (remaining-window countdown); it may clear foxBeacon + // (side-key abort) or foxRunning (EXIT). + FOXHUNT_BeaconTransmit(); beaconPhaseTx = false; beaconIdleLeft = beaconIdle; @@ -910,11 +1072,7 @@ static void FOXHUNT_BeaconTick(void) } FOXHUNT_BeaconDraw(false, beaconIdleLeft); - ST7565_BlitStatusLine(); - ST7565_BlitFullScreen(); -#ifdef ENABLE_FEAT_F4HWN_K5VIEWER - K5VIEWER_Update(false); -#endif + FOXHUNT_BlitScreen(); if (++beaconIdleTick >= (1000 / FOXHUNT_TICK_MS)) { // one second elapsed beaconIdleTick = 0; @@ -933,29 +1091,32 @@ static void FOXHUNT_BeaconTick(void) // span 0x9000..0x90E0 (224 B); the old 0x90D6 mapping bound was 10 B short and // overlapped the last VFO (470 MHz VFO1 @ 0x90D0..0x90DF), so the config sits at // 0x90E0, just past the real end. Normal saves are read-modify-write (Append=false) -// so they preserve these bytes, and the VFO mapping is extended to 0x90E5 +// so they preserve these bytes, and the VFO mapping is extended to 0x90E7 // (eeprom_compat.c) so aircopy clones them with the VFOs. A factory reset clears it. #define FOXHUNT_CFG_ADDR 0x0090E0u #define FOXHUNT_CFG_MAGIC 0xF4u // tells a written config from erased flash (0xFF) +#define FOXHUNT_CFG_LEN 7 // magic + att + graph + audio + idle + fox + tx // RAM mirror of the bytes last written to flash, so FOXHUNT_SaveConfig only touches // the flash when a value actually changed. -static uint8_t foxCfgSaved[5]; +static uint8_t foxCfgSaved[FOXHUNT_CFG_LEN]; -// Pack the live settings into the 5-byte on-flash layout. -static void FOXHUNT_ConfigPack(uint8_t out[5]) +// Pack the live settings into the on-flash layout. +static void FOXHUNT_ConfigPack(uint8_t out[FOXHUNT_CFG_LEN]) { out[0] = FOXHUNT_CFG_MAGIC; out[1] = attStep; out[2] = foxGraphMode; out[3] = foxAudioMode; out[4] = beaconIdle; + out[5] = foxFox; + out[6] = beaconTx; } // Restore persisted settings; erased/invalid flash leaves the defaults in place. static void FOXHUNT_LoadConfig(void) { - uint8_t cfg[5]; + uint8_t cfg[FOXHUNT_CFG_LEN]; PY25Q16_ReadBuffer(FOXHUNT_CFG_ADDR, cfg, sizeof(cfg)); if (cfg[0] == FOXHUNT_CFG_MAGIC) { // valid, saved config @@ -965,6 +1126,10 @@ static void FOXHUNT_LoadConfig(void) if (cfg[4] >= FOXHUNT_BEACON_IDLE_MIN && cfg[4] <= FOXHUNT_BEACON_IDLE_MAX && (cfg[4] % FOXHUNT_BEACON_IDLE_STEP) == 0) beaconIdle = cfg[4]; + if (cfg[5] < FOXHUNT_FOX_COUNT) foxFox = cfg[5]; + if (cfg[6] >= FOXHUNT_BEACON_TX_MIN && cfg[6] <= FOXHUNT_BEACON_TX_MAX + && (cfg[6] % FOXHUNT_BEACON_TX_STEP) == 0) + beaconTx = cfg[6]; } FOXHUNT_ConfigPack(foxCfgSaved); // mirror the loaded (or default) state @@ -976,7 +1141,7 @@ static void FOXHUNT_LoadConfig(void) // compare avoids re-reading the 4 KB sector on every quiet tick. static void FOXHUNT_SaveConfig(void) { - uint8_t cfg[5]; + uint8_t cfg[FOXHUNT_CFG_LEN]; FOXHUNT_ConfigPack(cfg); if (memcmp(cfg, foxCfgSaved, sizeof(cfg)) == 0) @@ -1000,12 +1165,14 @@ void APP_RunFoxHunt(void) gCurrentVfo = gTxVfo; RADIO_SetupRegisters(true); - // Beacon defaults. + // Beacon defaults (LoadConfig may override fox / tx / idle below). beaconIdle = FOXHUNT_BEACON_IDLE_DEF; + beaconTx = FOXHUNT_BEACON_TX_DEF; + foxFox = FOXHUNT_FOX_CALL; // identified beacon by default (legal on ham) beaconPhaseTx = false; - // Build the CW message " BEACON": the callsign is the boot message - // (line 1), sanitised to what Morse can send; empty/erased falls back to FOX. + // Read the callsign from the boot message (line 1), sanitised to what Morse can + // send; empty/erased leaves foxCall empty (the CALL id then falls back to bare MOE). { char call[FOXHUNT_CALLSIGN_MAX + 1]; uint8_t n = 0; @@ -1018,21 +1185,19 @@ void APP_RunFoxHunt(void) if (c >= 'a' && c <= 'z') c -= 32; if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '/') - call[n++] = c; + foxCall[n++] = c; } - call[n] = '\0'; - if (n == 0) - strcpy(call, "FOX"); - sprintf(beaconMsg, "%s BEACON", call); + foxCall[n] = '\0'; } - // Start in the hunt (RX) sub-mode, S-meter staircase gauge by default, then - // restore any persisted settings (attenuator, gauge, audio, beacon idle). + // Start in the hunt (RX) sub-mode, S-meter staircase gauge by default, then restore + // any persisted settings (attenuator, gauge, audio, beacon idle / fox / tx). attStep = 0; foxGraphMode = FOXHUNT_GRAPH_BAR; foxAudioMode = FOXHUNT_AUDIO_OFF; - FOXHUNT_LoadConfig(); // may override att / gauge / audio / idle - FOXHUNT_EnterHunt(); // applies the restored attStep and audio mode + FOXHUNT_LoadConfig(); // may override att / gauge / audio / idle / fox / tx + FOXHUNT_BuildBeaconMsg(); // assemble the CW message from the (restored) fox id + FOXHUNT_EnterHunt(); // applies the restored attStep and audio mode // Prime the key state with whatever is held right now, so the side key that // launched Fox Hunt (still down on a long-press assignment) is not taken for @@ -1059,6 +1224,8 @@ void APP_RunFoxHunt(void) curDbm = FOXHUNT_ReadDbm(); if (curDbm > peakDbm) peakDbm = curDbm; + if (curDbm < minDbm) + minDbm = curDbm; if (++trendTick >= FOXHUNT_TREND_TICKS) { trendDelta = curDbm - trendRef; @@ -1070,13 +1237,7 @@ void APP_RunFoxHunt(void) FOXHUNT_Draw(); - ST7565_BlitStatusLine(); - ST7565_BlitFullScreen(); - -#ifdef ENABLE_FEAT_F4HWN_K5VIEWER - // Mirror the screen to K5Viewer (sends only changed chunks). - K5VIEWER_Update(false); -#endif + FOXHUNT_BlitScreen(); // status + full frame + K5Viewer mirror // Beep mode: Geiger blip whose rate/pitch track the level (silent below floor). if (foxAudioMode == FOXHUNT_AUDIO_BEEP && curDbm >= FOXHUNT_SILENCE_DBM) { diff --git a/App/driver/eeprom_compat.c b/App/driver/eeprom_compat.c index 44790800..ed9d9c7c 100644 --- a/App/driver/eeprom_compat.c +++ b/App/driver/eeprom_compat.c @@ -51,10 +51,10 @@ static const AddrMapping_t ADDR_MAPPINGS[] = { _MK_MAPPING(0x008000, 0x008000, 0x00886E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000) 0x008000 -> 0x00880E // List name * 4 Bytes 0x00880E -> 0x00886E - _MK_MAPPING(0x009000, 0x009000, 0x0090E5), // 14 VFO * 16 Bytes = 0x9000 -> 0x90E0 (the old + _MK_MAPPING(0x009000, 0x009000, 0x0090E7), // 14 VFO * 16 Bytes = 0x9000 -> 0x90E0 (the old // 0x90D6 bound was 10 B short: it truncated the // 470 MHz VFO1 record at 0x90D0 -> 0x90DF) - // Fox Hunt settings * 5 Bytes 0x90E0 -> 0x90E5 + // Fox Hunt settings * 7 Bytes 0x90E0 -> 0x90E7 // (ENABLE_FEAT_F4HWN_FOXHUNT, written directly by // app/foxhunt.c; concatenated here so aircopy clones // them together with the VFOs) From 04e8d47130ea0659ddbff9cf84263ff2864cee1c Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 01:16:06 +0200 Subject: [PATCH 35/42] Add F + number reverse-cycle and Beacon TX bitmap --- App/app/foxhunt.c | 137 ++++++++++++++++++++++++++++++++++------------ App/bitmaps.c | 38 ++++++++++++- App/bitmaps.h | 1 + 3 files changed, 137 insertions(+), 39 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 4b7be3c4..37ce1c0c 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -377,6 +377,15 @@ static void FOXHUNT_Tag(const char *s, uint8_t x, uint8_t line) GUI_DisplaySmallestInverse(s, x, line, false, true, (uint8_t)(x + strlen(s) * 4)); } +// Mirror the firmware's status-bar F indicator: when the F key is armed, a number key +// steps its setting backwards. Same glyph and column as the main screens (status.c), so +// it reads identically — Fox Hunt just renders its own status line, hence the redraw. +static void FOXHUNT_DrawFKey(void) +{ + if (gWasFKeyPressed) + memcpy(gStatusLine + 69, gFontF, sizeof(gFontF)); +} + // Battery icon plus the optional voltage/percentage text, top-right of the status // line — shared by the hunt and beacon screens. static void FOXHUNT_DrawStatusBattery(void) @@ -409,8 +418,9 @@ static void FOXHUNT_BeaconChrome(void) { UI_DisplayClear(); UI_StatusClear(); - GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 28); + GUI_DisplaySmallestInverse("BEACON", 2, 0, true, true, 26); FOXHUNT_DrawStatusBattery(); + FOXHUNT_DrawFKey(); FOXHUNT_DrawFreqBR(gTxVfo->pTX->Frequency); } @@ -428,6 +438,7 @@ static void FOXHUNT_Draw(void) // Battery (icon + optional percentage/voltage) top-right, as on the main screens. FOXHUNT_DrawStatusBattery(); + FOXHUNT_DrawFKey(); // Gauge-mode icon (2 key), between the label and the audio icon: ascending // bars for the S-meter staircase, a sine wave for the signal history. Each @@ -498,46 +509,60 @@ static void FOXHUNT_Draw(void) // One key = one setting, each press cycling to the next value and wrapping — the same // scheme for the hunt gauges and the beacon settings, so there are no navigation arrows -// to learn. FOXHUNT_ApplyAtt is re-asserted for the attenuator; the beacon values are -// read where they take effect (TX window at the burst start, idle at the burst end, fox -// at the next repeat), so cycling any of them is safe at any time, TX included. +// to learn. dir is +1 for a plain press, -1 when the F key armed a reverse step. The +// beacon values are read where they take effect (TX window at the burst start, idle at +// the burst end, fox at the next repeat), so cycling any of them is safe at any time. -// Attenuator: 0 -> -6 -> -15 -> -27 -> 0 dB. -static void FOXHUNT_AttCycle(void) +// Wrap a 0..count-1 index one step forward (dir > 0) or backward, both ways round. +static uint8_t FOXHUNT_WrapStep(uint8_t v, uint8_t count, int8_t dir) { - attStep = (uint8_t)((attStep + 1) & 3); + return (uint8_t)((v + (dir > 0 ? 1u : (unsigned)(count - 1u))) % count); +} + +// Step a lo..hi value by step, wrapping lo<->hi at the ends. +static uint8_t FOXHUNT_RangeStep(uint8_t v, uint8_t lo, uint8_t hi, uint8_t step, int8_t dir) +{ + if (dir > 0) + return (v >= hi) ? lo : (uint8_t)(v + step); + return (v <= lo) ? hi : (uint8_t)(v - step); +} + +// Attenuator: 0 -> -6 -> -15 -> -27 dB (F reverses). +static void FOXHUNT_AttCycle(int8_t dir) +{ + attStep = FOXHUNT_WrapStep(attStep, 4, dir); FOXHUNT_ApplyAtt(); } -// Fox identifier: MOE -> MOI -> MOS -> MOH -> MO5 -> CALL -> MOE. -static void FOXHUNT_FoxCycle(void) +// Fox identifier: MOE -> MOI -> MOS -> MOH -> MO5 -> MO -> CALL (F reverses). +static void FOXHUNT_FoxCycle(int8_t dir) { - foxFox = (uint8_t)((foxFox + 1) % FOXHUNT_FOX_COUNT); + foxFox = FOXHUNT_WrapStep(foxFox, FOXHUNT_FOX_COUNT, dir); } -// TX window: 5 s up to 60 s, then back to 5 s. -static void FOXHUNT_TxCycle(void) +// TX window: 5..60 s (F reverses). +static void FOXHUNT_TxCycle(int8_t dir) { - beaconTx = (beaconTx >= FOXHUNT_BEACON_TX_MAX) - ? FOXHUNT_BEACON_TX_MIN : (uint8_t)(beaconTx + FOXHUNT_BEACON_TX_STEP); + beaconTx = FOXHUNT_RangeStep(beaconTx, FOXHUNT_BEACON_TX_MIN, FOXHUNT_BEACON_TX_MAX, + FOXHUNT_BEACON_TX_STEP, dir); } -// Idle gap: 5 s up to 240 s, then back to 5 s. -static void FOXHUNT_IdleCycle(void) +// Idle gap: 5..240 s (F reverses). +static void FOXHUNT_IdleCycle(int8_t dir) { - beaconIdle = (beaconIdle >= FOXHUNT_BEACON_IDLE_MAX) - ? FOXHUNT_BEACON_IDLE_MIN : (uint8_t)(beaconIdle + FOXHUNT_BEACON_IDLE_STEP); + beaconIdle = FOXHUNT_RangeStep(beaconIdle, FOXHUNT_BEACON_IDLE_MIN, FOXHUNT_BEACON_IDLE_MAX, + FOXHUNT_BEACON_IDLE_STEP, dir); } -// Apply a beacon number key; returns true when it changed a setting so the caller can -// refresh. The keys follow the on-screen layout: 1 = TX (top-left), 2 = IDLE (below it), -// 3 = FOX (right). Shared by both beacon phases. -static bool FOXHUNT_BeaconKey(KEY_Code_t key) +// Apply a beacon number key in the given direction; returns true when it changed a +// setting so the caller can refresh. Keys follow the on-screen layout: 1 = TX (top-left), +// 2 = IDLE (below it), 3 = FOX (right). Shared by both beacon phases. +static bool FOXHUNT_BeaconKey(KEY_Code_t key, int8_t dir) { switch (key) { - case KEY_1: FOXHUNT_TxCycle(); return true; - case KEY_2: FOXHUNT_IdleCycle(); return true; - case KEY_3: FOXHUNT_FoxCycle(); return true; + case KEY_1: FOXHUNT_TxCycle(dir); return true; + case KEY_2: FOXHUNT_IdleCycle(dir); return true; + case KEY_3: FOXHUNT_FoxCycle(dir); return true; default: return false; } } @@ -606,6 +631,12 @@ static void FOXHUNT_HandleKeys(void) BACKLIGHT_TurnOn(); // any keypress wakes the screen and re-arms the timers + if (kbd.current == KEY_F) { // arm / disarm a reverse step for the next number key + gWasFKeyPressed = !gWasFKeyPressed; + return; + } + const int8_t dir = gWasFKeyPressed ? -1 : 1; + switch (kbd.current) { case KEY_EXIT: foxRunning = false; @@ -615,15 +646,15 @@ static void FOXHUNT_HandleKeys(void) foxGraphMode ^= 1; break; case KEY_2: - // Cycle the audio: silent -> Geiger beep -> station audio -> silent. - foxAudioMode = (uint8_t)((foxAudioMode + 1) % 3); + // Cycle the audio: silent -> Geiger beep -> station audio (F reverses). + foxAudioMode = FOXHUNT_WrapStep(foxAudioMode, 3, dir); FOXHUNT_SetAudio(); if (foxAudioMode == FOXHUNT_AUDIO_BEEP) audioTick = FOXHUNT_RATE_SLOW_TICKS; // blip promptly break; case KEY_3: - // Cycle the attenuator (0 -> -6 -> -15 -> -27 dB, then back to 0). - FOXHUNT_AttCycle(); + // Cycle the attenuator (0 -> -6 -> -15 -> -27 dB; F reverses). + FOXHUNT_AttCycle(dir); break; case KEY_MENU: // Reset the peak / min hold and the trend reference (before each body scan). @@ -639,6 +670,8 @@ static void FOXHUNT_HandleKeys(void) default: break; } + + gWasFKeyPressed = false; // any non-F key consumes (or cancels) the reverse arm } // (Re)enter the hunt (RX) sub-mode: fixed front-end gain, attenuator and audio mode @@ -781,9 +814,16 @@ static bool FOXHUNT_TxDelay(uint16_t ms) // gap of the configured IDLE length. return true; } - if (FOXHUNT_BeaconKey(kbd.current)) { + if (kbd.current == KEY_F) { // arm / disarm the reverse step + gWasFKeyPressed = !gWasFKeyPressed; + FOXHUNT_BeaconDraw(true, 0); // reflect the F indicator in the status line + FOXHUNT_BlitScreen(); + continue; + } + if (FOXHUNT_BeaconKey(kbd.current, gWasFKeyPressed ? -1 : 1)) { + gWasFKeyPressed = false; // consumed; also clears the F indicator FOXHUNT_BeaconDraw(true, 0); // show the new value immediately - ST7565_BlitFullScreen(); + FOXHUNT_BlitScreen(); } } return false; @@ -854,14 +894,27 @@ static void FOXHUNT_BeaconTransmit(void) FOXHUNT_BuildBeaconMsg(); // Redraw once per repeat (remaining-window countdown + reset progress), in the - // muted gap so it never stretches a Morse element. + // muted gap so it never stretches a Morse element. Local LCD only here — the + // K5Viewer frame is pushed after the ID (below), when the text is complete. beaconCharsSent = 0; FOXHUNT_BeaconDraw(true, 0); - FOXHUNT_BlitScreen(); + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); for (uint8_t i = 0; !stop && beaconMsg[i]; i++) stop = FOXHUNT_MorseChar(beaconMsg[i], i + 1u); +#ifdef ENABLE_FEAT_F4HWN_K5VIEWER + // Service the K5Viewer link in the muted gap (never during a keyed element, so + // the Morse timing stays intact): ParseInput refills the keep-alive that Update + // drains — without it the link dies within ~15 repeats over a long TX window — + // and Update then mirrors the now-complete ID frame plus the live seconds. + if (!stop) { + K5VIEWER_ParseInput(); + K5VIEWER_Update(false); + } +#endif + // Word gap before the next repeat, only while the window still has room. if (!stop && beaconTxMsLeft > 0) stop = FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 7); @@ -973,7 +1026,9 @@ static void FOXHUNT_BeaconDraw(bool txNow, uint8_t idleLeft) FOXHUNT_BeaconChrome(); if (txNow) { - // Top line: "TX" + remaining window seconds (refreshed live in FOXHUNT_TxDelay). + // On-air icon in the status bar (only while the carrier is up), then the top + // line "TX" + remaining window seconds (refreshed live in FOXHUNT_TxDelay). + memcpy(gStatusLine + 48, BITMAP_FoxHuntTx, sizeof(BITMAP_FoxHuntTx)); FOXHUNT_DrawTxSeconds(); FOXHUNT_DrawBeaconMessage(beaconCharsSent); } else { @@ -1005,6 +1060,11 @@ static void FOXHUNT_BeaconKeys(void) BACKLIGHT_TurnOn(); // any keypress wakes the screen and re-arms the timers + if (kbd.current == KEY_F) { // arm / disarm a reverse step for the next number key + gWasFKeyPressed = !gWasFKeyPressed; + return; + } + switch (kbd.current) { case KEY_EXIT: foxRunning = false; // leave Fox Hunt entirely @@ -1019,10 +1079,12 @@ static void FOXHUNT_BeaconKeys(void) beaconIdleTick = 0; break; default: - // 1 = TX window, 2 = idle gap, 3 = fox (same keys as during TX). - FOXHUNT_BeaconKey(kbd.current); + // 1 = TX window, 2 = idle gap, 3 = fox (F reverses); same keys as during TX. + FOXHUNT_BeaconKey(kbd.current, gWasFKeyPressed ? -1 : 1); break; } + + gWasFKeyPressed = false; // any non-F key consumes (or cancels) the reverse arm } // One iteration of the beacon loop: either transmit a burst, or count down the @@ -1203,6 +1265,7 @@ void APP_RunFoxHunt(void) // launched Fox Hunt (still down on a long-press assignment) is not taken for // a fresh press and does not immediately toggle to the beacon. kbd.prev = kbd.current = KEYBOARD_GetKey(); + gWasFKeyPressed = false; // start with the reverse-step arm cleared foxRunning = true; while (foxRunning) { @@ -1261,6 +1324,8 @@ void APP_RunFoxHunt(void) // and the sleep auto power-off, both of which just clear foxRunning). FOXHUNT_SaveConfig(); + gWasFKeyPressed = false; // don't leak a pending reverse-step arm to the main screen + // Mute any pending tone, drop the PA (safety), then restore the normal VFO // selection and RX config. AUDIO_AudioPathOff(); diff --git a/App/bitmaps.c b/App/bitmaps.c index a6c617de..141a7026 100644 --- a/App/bitmaps.c +++ b/App/bitmaps.c @@ -392,9 +392,41 @@ const uint8_t BITMAP_FoxHuntBars[11] = const uint8_t BITMAP_FoxHuntGraph[15] = { // sine wave = signal-history gauge mode (bit0 = top row) - 0b00001000, 0b00000100, 0b00000010, 0b00000100, 0b00001000, - 0b00010000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, - 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000 + 0b00001000, + 0b00000100, + 0b00000010, + 0b00000100, + 0b00001000, + 0b00010000, + 0b00100000, + 0b00010000, + 0b00001000, + 0b00000100, + 0b00000010, + 0b00000100, + 0b00001000, + 0b00010000, + 0b00100000 +}; + +const uint8_t BITMAP_FoxHuntTx[16] = +{ + 0b00011100, + 0b00100010, + 0b01000001, + 0b00011100, + 0b00100010, + 0b00000000, + 0b00001000, + 0b00011100, + 0b00011100, + 0b00001000, + 0b00000000, + 0b00100010, + 0b00011100, + 0b01000001, + 0b00100010, + 0b00011100 }; #endif diff --git a/App/bitmaps.h b/App/bitmaps.h index 7fa04f59..f64c332e 100644 --- a/App/bitmaps.h +++ b/App/bitmaps.h @@ -53,6 +53,7 @@ extern const uint8_t BITMAP_NOAA[12]; extern const uint8_t BITMAP_FoxHuntFlat[11]; extern const uint8_t BITMAP_FoxHuntBars[11]; extern const uint8_t BITMAP_FoxHuntGraph[15]; + extern const uint8_t BITMAP_FoxHuntTx[16]; #endif #ifndef ENABLE_CUSTOM_MENU_LAYOUT From fb9491caa5f794a5c6a014867e6812b22bc66a95 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 01:44:35 +0200 Subject: [PATCH 36/42] Factor duplicated Fox Hunt helpers (-32 B flash) --- App/app/foxhunt.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index 37ce1c0c..f458c6e2 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -211,24 +211,26 @@ static void FOXHUNT_SetAudio(void) BK4819_SetAF(BK4819_AF_MUTE); } +// Clamped linear map of dbm over the [FLOOR, CEIL] window onto [lo, hi] (hi may sit +// below lo for an inverted mapping). Shared by the Geiger pitch and blip-rate ramps. +static int32_t FOXHUNT_LerpDbm(int16_t dbm, int32_t lo, int32_t hi) +{ + if (dbm <= FOXHUNT_DBM_FLOOR) return lo; + if (dbm >= FOXHUNT_DBM_CEIL) return hi; + return lo + ((int32_t)(dbm - FOXHUNT_DBM_FLOOR) * (hi - lo)) / + (FOXHUNT_DBM_CEIL - FOXHUNT_DBM_FLOOR); +} + // Map a dBm value to a Geiger tone frequency (higher signal, higher pitch). static uint16_t FOXHUNT_DbmToTone(int16_t dbm) { - if (dbm <= FOXHUNT_DBM_FLOOR) return FOXHUNT_TONE_MIN; - if (dbm >= FOXHUNT_DBM_CEIL) return FOXHUNT_TONE_MAX; - return FOXHUNT_TONE_MIN + - (uint16_t)(((int32_t)(dbm - FOXHUNT_DBM_FLOOR) * (FOXHUNT_TONE_MAX - FOXHUNT_TONE_MIN)) / - (FOXHUNT_DBM_CEIL - FOXHUNT_DBM_FLOOR)); + return (uint16_t)FOXHUNT_LerpDbm(dbm, FOXHUNT_TONE_MIN, FOXHUNT_TONE_MAX); } // Ticks between two blips: fewer ticks = faster clicking as the signal rises. static uint8_t FOXHUNT_BlipPeriod(int16_t dbm) { - if (dbm <= FOXHUNT_DBM_FLOOR) return FOXHUNT_RATE_SLOW_TICKS; - if (dbm >= FOXHUNT_DBM_CEIL) return FOXHUNT_RATE_FAST_TICKS; - return FOXHUNT_RATE_SLOW_TICKS - - (uint8_t)(((int32_t)(dbm - FOXHUNT_DBM_FLOOR) * (FOXHUNT_RATE_SLOW_TICKS - FOXHUNT_RATE_FAST_TICKS)) / - (FOXHUNT_DBM_CEIL - FOXHUNT_DBM_FLOOR)); + return (uint8_t)FOXHUNT_LerpDbm(dbm, FOXHUNT_RATE_SLOW_TICKS, FOXHUNT_RATE_FAST_TICKS); } // Emit one short blip at the given pitch, then hand the chip back to RX. @@ -386,6 +388,12 @@ static void FOXHUNT_DrawFKey(void) memcpy(gStatusLine + 69, gFontF, sizeof(gFontF)); } +// Draw a string right-aligned in the small (7 px) font: its right edge lands at rightX. +static void FOXHUNT_DrawRightSmall(const char *s, uint8_t rightX, uint8_t line) +{ + UI_PrintStringSmallNormal(s, (uint8_t)(rightX - strlen(s) * 7), 0, line); +} + // Battery icon plus the optional voltage/percentage text, top-right of the status // line — shared by the hunt and beacon screens. static void FOXHUNT_DrawStatusBattery(void) @@ -409,7 +417,7 @@ static void FOXHUNT_DrawStatusBattery(void) static void FOXHUNT_DrawFreqBR(uint32_t freq) { sprintf(str, "%u.%05u", freq / 100000, freq % 100000); - UI_PrintStringSmallNormal(str, 126 - strlen(str) * 7, 0, 6); + FOXHUNT_DrawRightSmall(str, 126, 6); } // Common beacon-screen frame: clear, the BEACON tag, the battery, and the TX @@ -473,7 +481,7 @@ static void FOXHUNT_Draw(void) if (trendDelta != 0) { sprintf(str, "%+03d", trendDelta); // sign + 2 digits, e.g. "+05" / "-12" UI_PrintStringSmallNormal("dBm", 127 - 3 * 7, 0, 1); - UI_PrintStringSmallNormal(str, 127 - 3 * 7 - 2 - strlen(str) * 7, 0, 1); + FOXHUNT_DrawRightSmall(str, 127 - 3 * 7 - 2, 1); // value left of "dBm" } // Context line: peak hold (left), min hold (centre) and S-meter (right) as small @@ -766,7 +774,7 @@ static void FOXHUNT_DrawTxSeconds(void) memset(gFrameBuffer[0], 0, sizeof(gFrameBuffer[0])); UI_PrintStringSmallNormal("TX", 1, 0, 0); sprintf(str, "%02us", sec); - UI_PrintStringSmallNormal(str, (uint8_t)(127 - strlen(str) * 7), 0, 0); + FOXHUNT_DrawRightSmall(str, 127, 0); beaconTxSecShown = sec; } From 926787ddf302aeaa29780f9ccbb01e698a55050b Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 02:22:58 +0200 Subject: [PATCH 37/42] Trim Fox Hunt buffers and drop hot-path divisions (-20 B flash) --- App/app/foxhunt.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index f458c6e2..d34af3ff 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -122,9 +122,9 @@ // the RSSI detector, so it scales the reading linearly. Reducing the early LNA // alone barely moved the reading on strong signals (mixer + PGA re-amplify). // pgaTab (bk4829.c) = {-33,-27,-21,-15,-9,-6,-3,0}; index 7 (= 0 dB) matches the -// RX default (0x03DF), so step 0 leaves the gain untouched. -static const uint8_t FOXHUNT_ATT_PGA[4] = {7, 5, 3, 1}; // 0, -6, -15, -27 dB -static const uint8_t FOXHUNT_ATT_DB[4] = {0, 6, 15, 27}; +// RX default (0x03DF), so step 0 leaves the gain untouched. The PGA indices per step +// are {7,5,3,1} = 7 - 2*attStep (computed in FOXHUNT_ApplyAtt, no table needed). +static const uint8_t FOXHUNT_ATT_DB[4] = {0, 6, 15, 27}; // 0, -6, -15, -27 dB static KeyboardState kbd = {KEY_INVALID, KEY_INVALID, 0}; @@ -146,7 +146,7 @@ static uint8_t histHead; // index of the oldest sample (next write slot) static uint8_t histTick; // decimation counter (0..FOXHUNT_HIST_DECIM-1) static int16_t histEma; // EMA-smoothed level feed, dBm in 1/8 units (x8 fixed) -static char str[16]; +static char str[14]; // widest write is the freq "1300.00000" (10 chars) + NUL, with slack // Sentinel-prefixed Morse patterns: after the leading 1 sentinel bit, each lower // bit is one element read MSB-first (0 = dit, 1 = dah). 0 = unsupported char. @@ -168,7 +168,7 @@ static bool beaconPhaseTx; // true = transmit this tick, false = idle gap static uint8_t beaconIdle; // configured silence between IDs (s) static uint8_t beaconIdleLeft; // seconds left in the current silence static uint8_t beaconIdleTick; // tick counter that clocks the idle countdown -static char beaconMsg[24]; // CW message, e.g. "F4HWN MOE" or "MOS" +static char beaconMsg[17]; // CW message: 12-char call + " MOE" + NUL, e.g. "F4HWN MOE" static uint8_t beaconCharsSent; // characters completed in the current burst static uint8_t beaconTx; // TX window length (s): the ID repeats for this long static uint16_t beaconTxMsLeft; // ms left in the current TX window (drained as it plays) @@ -193,7 +193,7 @@ static int16_t FOXHUNT_ReadDbm(void) static void FOXHUNT_ApplyAtt(void) { uint16_t reg = BK4819_ReadRegister(BK4819_REG_13); - reg = (reg & ~0x7u) | (uint16_t)FOXHUNT_ATT_PGA[attStep]; // PGA = REG_13 bits 0..2 + reg = (reg & ~0x7u) | (uint16_t)(7u - 2u * attStep); // PGA {7,5,3,1}, REG_13 bits 0..2 BK4819_WriteRegister(BK4819_REG_13, reg); } @@ -335,8 +335,11 @@ static void FOXHUNT_DrawHist(void) FOXHUNT_GRAPH_X0 + FOXHUNT_HIST_LEN - 1, FOXHUNT_GRAPH_BOT, true); uint8_t prevY = 0; + uint8_t idx = histHead; // ring index, wrapped by increment (no per-column modulo) for (uint8_t c = 0; c < FOXHUNT_HIST_LEN; c++) { - uint8_t lvl = histBuf[(histHead + c) % FOXHUNT_HIST_LEN]; // oldest -> newest + uint8_t lvl = histBuf[idx]; // oldest -> newest + if (++idx >= FOXHUNT_HIST_LEN) + idx = 0; if (lvl > FOXHUNT_SEG_COUNT) lvl = FOXHUNT_SEG_COUNT; uint8_t x = FOXHUNT_GRAPH_X0 + c; @@ -1266,8 +1269,9 @@ void APP_RunFoxHunt(void) foxGraphMode = FOXHUNT_GRAPH_BAR; foxAudioMode = FOXHUNT_AUDIO_OFF; FOXHUNT_LoadConfig(); // may override att / gauge / audio / idle / fox / tx - FOXHUNT_BuildBeaconMsg(); // assemble the CW message from the (restored) fox id FOXHUNT_EnterHunt(); // applies the restored attStep and audio mode + // beaconMsg is (re)built by FOXHUNT_BeaconTransmit before every burst, and nothing + // reads it before the first burst, so no need to assemble it here. // Prime the key state with whatever is held right now, so the side key that // launched Fox Hunt (still down on a long-press assignment) is not taken for From f904b87172440ba7c7fa950d390ac59afa6ded3c Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 03:28:16 +0200 Subject: [PATCH 38/42] Update README --- README.md | 339 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 212 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index b201db2e..5fd0b5f4 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Ol ## Table of Contents -* [My Features](#main-features) +* [Main features and improvements from F4HWN](#main-features-and-improvements-from-f4hwn) * [Main Features from Egzumer](#main-features-from-egzumer) * [Manual](#manual) * [Compiling and Building from Docker](#compiling-and-Building-from-docker) @@ -55,133 +55,218 @@ Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Ol * [Other sources of information](#other-sources-of-information) * [License](#license) -## Main features and improvements from F4HWN: +## Main features and improvements from F4HWN -* Fusion is now the reference edition of the project: - * all-in-one firmware for UV-K1 and UV-K5 V3, - * spectrum analyzer made by Fagci, - * commercial FM radio support, - * Vox and Aircopy support, - * screenshots and K5Viewer support, - * advanced RX audio profiles and Audio Scope, - * first-responder oriented options, - * small breakout game, -* improve default power settings level: - * Low1 to Low5 (<~20mW, ~125mW, ~250mW, ~500mW, ~1W), - * Mid ~2W, - * High ~5W, - * User (see SetPwr), -* improve S-Meter (IARU Region 1 Technical Recommendation R.1 for VHF/UHF - [read more](https://hamwaves.com/decibel/en/)), - * S-Meter (S0/S9) Level EEPROM settings that were introduced in the Egzumer firmware are now ignored and replaced by hardcoded values to comply with the IARU Recommendation. -* improve bandscope (Spectrum Analyser): - * add channel name, - * add save of some spectrum parameters, -* improve UI: - * menu index is always visible, even if a menu is selected, - * s-meter new design (Classic or Tiny), - * MAIN ONLY screen mode, - * DUAL and CROSS screen mode, - * RX blink on VFO RX, - * RX LED blink, - * Squelch level and Monitor, - * Step value, - * CTCSS or DCS value, - * KeyLock message, - * last RX, - * move BatTxt menu from 34/63 to 30/63 (just after BatSave menu 29/63), - * rename BackLt to BLTime, - * rename BltTRX to BLTxRx, - * improve memory channel input, - * improve keyboard frequency input, - * add percent and gauge to Air Copy, - * improve audio bar, - * add backlight fading, - * add Audio Scope on TX, - * and more... -* new menu entries and changes: - * add SetPwr menu to set User power (<20mW, 125mW, 250mW, 500mW, 1W, 2W or 5W), - * add SetPTT menu to set PTT mode (Classic or OnePush), - * add SetTOT menu to set TOT alert (Off, Sound, Visual, All), - * add SetCtr menu to set contrast (0 to 15), - * add SetInv menu to set screen in invert mode (Off or On), - * add SetEOT menu to set EOT (End Of Transmission) alert (Off, Sound, Visual, All), - * add SetMet menu to set s-meter style (Classic or Tiny), - * add SetLck menu to set what is locked (Keys or Keys + PTT), - * add SetGUI menu to set font size on the VFO baseline (Classic or Tiny), - * add SetRxA menu to select RX audio profiles, - * add TXLock menu to open TX on channel, - * add SetTmr menu to set RX and TX timers (Off or On), - * add SetOff menu to set the delay before the transceiver goes into deep sleep (Off or 1 minute to 2 hours), - * add SetNFM menu to set Narrow width (12.5kHz or 6.25kHz), - * add SetVol menu to adjust RX audio volume, - * add SetScn menu to set Scan mode - * rename BatVol menu (52/63) to SysInf, which displays the firmware version in addition to the battery status, - * improve PonMsg menu, - * improve BackLt menu, - * improve TxTOut menu, - * improve ScnRev menu (CARRIER from 250ms to 20s, STOP, TIMEOUT from 5s to 2m) - * improve KeyLck menu (OFF, delay from 15s to 10m) - * add HAM CA F Lock band (for Canadian zone), - * add PMR 446 F Lock band, - * add FRS/GMRS/MURS F Lock band, - * add SetNav hidden menu to select the navigation layout according to the radio model, - * remove blink and SOS functionality, - * remove AM Fix menu (AM Fix is ENABLED by default), - * add support of 3500mAh battery, -* improve status bar: - * add SetPtt mode in status bar, - * change font and bitmaps, - * move USB icon to left of battery information, - * add RX and TX timers, -* improve channel scanning: - * support up to 24 scan lists, - * each memory channel can be assigned to `OFF`, to one list (`01` to `24`), or to `ALL`, - * `ALL` scans every channel except those set to `OFF`, - * named scan lists are shown in the UI and status bar when available, - * if the selected scan list is empty or invalid, the firmware automatically jumps to the next valid one, - * very fast scan mode (around 150 freq/s), - * 64 frequencies exclusions, -* add resume mode on startup (scan, spectrum analyzer and FM radio), -* improve VFO persistence and restore behavior: - * save the Squelch level adjusted with F + UP or F + DOWN, - * restore the full VFO state on long press of EXIT, -* new actions: - * RX MODE, - * MAIN ONLY, - * PTT, - * WIDE NARROW, - * 1750Hz, - * MUTE, - * POWER HIGH, - * REMOVE OFFSET, - * BEAM, - * RF LOG, -* new key combinations: - * add the F + UP or F + DOWN key combination to dynamically change the Squelch level, - * add the F + F1 or F + F2 key combination to dynamically change the Step, - * add F + 8 to quickly switch backlight between BLMin and BLMax on demand (this bypass BackLt strategy), - * add F + 9 to return to BackLt strategy, - * add long press on MENU, in * SCAN mode, to exclude the current memory channel, - * add direct scan list selection while scanning with two digits (`00` = `ALL`, `01` to `24` = scan list). -* many fix: - * squelch, - * s-meter, - * DTMF overlaying, - * scan range limit, - * clean display on startup, - * no more PWM noise, - * K5Viewer/serial key handling, - * spectrum freeze on USB-C unplug, - * Audio Scope behavior in OnePush mode and after DTMF/1750, - * and more... -* enabled AIR COPY -* disabled ENABLE_DTMF_CALLING, -* disabled SCRAMBLER, -* remove 200Tx, 350Tx and 500Tx, -* unlock TX on all bands needs only to be repeat 3 times, -* code refactoring and many memory optimization, -* stream the live screen of the Quansheng K5 to K5Viewer and capture screenshots over a USB-to-Serial cable, -* and more... +### Fusion edition + +Fusion is the reference edition of the project. It provides an all-in-one firmware for the UV-K1 and UV-K5 V3, including: + +- Fagci's spectrum analyzer, +- broadcast FM radio, +- VOX and AirCopy, +- BEAM wireless channel transfer, +- K5Viewer screen mirroring, screenshots and remote keyboard control, +- advanced RX audio profiles and Audio Scope, +- first-responder-oriented controls, +- the Breakout game, +- automatic RX/TX activity logging with RF Log, +- full Fox Hunt and Morse Beacon support. + +### Radio and signal handling + +- Reworked output-power levels: + - `Low 1`: below approximately 20 mW, + - `Low 2`: approximately 125 mW, + - `Low 3`: approximately 250 mW, + - `Low 4`: approximately 500 mW, + - `Low 5`: approximately 1 W, + - `Mid`: approximately 2 W, + - `High`: approximately 5 W, + - `User`: configurable through `SetPwr`. +- S-meter calibrated according to the [IARU Region 1 recommendation for VHF/UHF](https://hamwaves.com/decibel/en/): + - fixed S0 to S9+ values replace the former EEPROM S-meter thresholds, + - Classic and Tiny display styles are available. +- Configurable 12.5 kHz or 6.25 kHz narrow-FM bandwidth. +- Per-channel TX lock. +- Adjustable RX audio volume. +- Advanced RX audio profiles for FM and AM reception. +- Regional frequency-lock profiles for amateur bands, PMR446, FRS, GMRS and MURS. +- Support for 1600, 2200 and 3500 mAh battery profiles. + +### Spectrum analyzer + +- Channel names displayed in the spectrum view. +- Persistent spectrum settings. +- Faster and smoother spectrum rendering. +- Improved behavior when freezing the spectrum or disconnecting USB-C. +- Spectrum analyzer state can be restored automatically at startup. + +### Scanning + +- Support for up to 24 named scan lists. +- Each memory channel can be assigned to: + - `OFF`, + - one scan list from `01` to `24`, + - `ALL`. +- The `ALL` list scans every channel except those assigned to `OFF`. +- Automatic selection of the next valid list when the requested list is empty. +- Direct scan-list selection while scanning: + - `00` selects `ALL`, + - `01` to `24` select the corresponding list. +- Long press on `MENU` while scanning to exclude the current memory channel. +- Up to 64 frequency exclusions. +- Very fast scanning mode, reaching approximately 150 frequencies per second. +- Scan progress, RSSI and detected CTCSS/DCS information. +- Configurable scan resume behavior. +- Scan state can be restored automatically at startup. + +### User interface + +- Improved VFO screen with: + - Classic and Tiny S-meter styles, + - Classic and Tiny frequency-information layouts, + - `MAIN ONLY`, `DUAL` and `CROSS` display modes, + - RX activity indication on the active VFO, + - optional RX LED blinking, + - squelch, monitor, step and CTCSS/DCS information, + - last-RX indication, + - RX and TX timers. +- Improved status bar with updated fonts and icons. +- Menu index remains visible while editing an entry. +- Improved frequency and memory-channel input. +- Improved audio-level display. +- AirCopy progress percentage and gauge. +- Smooth backlight fading. +- Manual backlight controls for quickly switching between minimum and maximum brightness. +- Configurable contrast and inverted-display mode. +- Configurable navigation layout for the different radio models. +- Improved power-on message and optional startup logo. +- System-information pages for: + - firmware version and build information, + - battery information, + - Flash and SRAM usage, + - project and documentation QR codes. + +### Audio and transmission controls + +- Classic and OnePush PTT modes. +- Configurable timeout-timer alerts: + - disabled, + - sound, + - visual, + - sound and visual. +- Configurable end-of-transmission alerts using the same modes. +- Audio Scope during RX and TX. +- Improved Audio Scope behavior with OnePush PTT, DTMF and the 1750 Hz tone. +- Configurable automatic deep-sleep timeout. +- Quick actions for: + - RX mode, + - main-VFO-only display, + - PTT, + - wide/narrow bandwidth, + - 1750 Hz tone, + - mute, + - RX audio profile, + - maximum power, + - offset removal. + +### Fox Hunt and Beacon + +- Dedicated Fox Hunt receiver with: + - calibrated S-meter display, + - scrolling signal-history graph, + - peak, minimum and trend indicators, + - selectable RF attenuation, + - silent, Geiger-style and received-audio modes. +- Integrated Morse Beacon transmitter with: + - `MOE`, `MOI`, `MOS`, `MOH`, `MO5` and `MO` identifiers, + - optional callsign identification, + - configurable TX and idle periods, + - live TX and idle countdowns, + - persisted Beacon settings, + - interactive control during transmission, + - TX-lock, modulation and battery-safety checks. +- Fox Hunt and Beacon screens are mirrored to K5Viewer. + +### RF Log + +- Automatic logging of RX and TX activity when RF Log is enabled. +- Logs stored in the radio's external Flash memory. +- Recorded information includes: + - RX or TX direction, + - frequency and channel, + - channel name, + - activity duration, + - S-meter level, + - battery voltage. +- On-radio history with RX/TX filtering and detailed views. +- Live RF Log dashboard and history access through K5Viewer. + +### Connectivity and data transfer + +- Live screen streaming to K5Viewer over a USB serial connection. +- Screenshot capture and download. +- Remote keyboard control from K5Viewer. +- Automatic K5Viewer reconnection after a USB disconnect. +- RF Log monitoring and analytics in K5Viewer. +- BEAM transfer of complete channel settings between compatible radios. +- Improved AirCopy interface and progress reporting. + +### Settings and controls + +- New or extended menu entries: + - `SetPwr`: configurable User output power, + - `SetPTT`: Classic or OnePush PTT, + - `SetTOT`: timeout-timer alert, + - `SetEOT`: end-of-transmission alert, + - `SetCtr`: display contrast, + - `SetInv`: inverted display, + - `SetLck`: keypad or keypad-and-PTT lock, + - `SetMet`: S-meter style, + - `SetGUI`: VFO information style, + - `SetRxA`: RX audio profile, + - `SetTmr`: RX and TX timers, + - `SetOff`: automatic deep-sleep delay, + - `SetNFM`: narrow-FM bandwidth, + - `SetVol`: RX audio volume, + - `SetScn`: scan mode, + - `SetNav`: radio-specific navigation layout. +- Improved `PonMsg`, `BackLt`, `TxTOut`, `ScnRev` and `KeyLck` menus. +- Full VFO state restoration with a long press on `EXIT`. +- Squelch changes made with `F + UP` or `F + DOWN` are persisted. + +### Keyboard shortcuts and assignable actions + +- `F + UP` or `F + DOWN`: adjust the squelch level. +- `F + F1` or `F + F2`: adjust the frequency step. +- `F + 8`: temporarily switch the backlight between minimum and maximum brightness. +- `F + 9`: return to the configured backlight strategy. +- Configurable short- and long-press actions include: + - RX mode, + - main-VFO-only display, + - virtual PTT, + - wide/narrow bandwidth, + - 1750 Hz tone, + - mute, + - RX audio profile, + - maximum power, + - offset removal, + - BEAM, + - RF Log, + - Fox Hunt / Beacon. + +### Reliability and optimization + +- Improved squelch and S-meter behavior. +- Fixed DTMF overlay issues. +- Fixed scan-range limits. +- Cleaner startup display. +- Removed PWM-related audio noise. +- Improved serial and K5Viewer key handling. +- Improved VFO persistence and restoration. +- Extensive code refactoring and memory optimization. +- DTMF calling and the scrambler remain disabled in Fusion. +- Legacy AM Fix code is not used by this firmware. ## Main features from Egzumer: * many of OneOfEleven mods: From c45b7d2deb031ace440425d639f624c84aa618ca Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 03:33:12 +0200 Subject: [PATCH 39/42] Update README --- README.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 5fd0b5f4..29593840 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,9 @@ Anyway, have fun. > _FR - A propos de CHIRP, comme pour beaucoup d'autres firmwares, vous devez utiliser un pilote dédié. Le driver CHIRP correspondant est désormais fourni avec chaque release de ce dépôt, ce qui permet de récupérer ensemble le firmware et son pilote depuis la page des [Releases](https://github.com/armel/uv-k1-k5v3-firmware-custom/releases)._ > [!CAUTION] -> EN - I recommend to backup your calibration data with [uvtools2](https://armel.github.io/uvtools2/) just after flashing this firmware. It's a good reflex to have. +> EN - I recommend backing up your calibration data with [UV Studio](https://armel.github.io/uvstudio/#dump-calib) immediately after flashing this firmware. It is a good habit to adopt. > -> _FR - Je recommande de sauvegarder vos données de calibration avec [uvtools2](https://armel.github.io/uvtools2/) juste après avoir flashé ce firmware. C'est un bon réflexe à avoir._ +> _FR - Je recommande de sauvegarder vos données de calibration avec [UV Studio](https://armel.github.io/uvstudio/#dump-calib) juste après avoir flashé ce firmware. C'est un bon réflexe à adopter._ # Donations @@ -50,7 +50,7 @@ Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Ol * [Main Features from Egzumer](#main-features-from-egzumer) * [Manual](#manual) * [Compiling and Building from Docker](#compiling-and-Building-from-docker) -* [Flashing the Firmware with UVTools2](#flashing-the-firmware-with-uvtools2) +* [Flashing the Firmware with UV Studio](#flashing-the-firmware-with-uv-studio) * [Credits](#credits) * [Other sources of information](#other-sources-of-information) * [License](#license) @@ -65,7 +65,7 @@ Fusion is the reference edition of the project. It provides an all-in-one firmwa - broadcast FM radio, - VOX and AirCopy, - BEAM wireless channel transfer, -- K5Viewer screen mirroring, screenshots and remote keyboard control, +- [UV Studio](https://armel.github.io/uvstudio/) with integrated K5Viewer screen mirroring, screenshots and remote keyboard control, - advanced RX audio profiles and Audio Scope, - first-responder-oriented controls, - the Breakout game, @@ -186,7 +186,7 @@ Fusion is the reference edition of the project. It provides an all-in-one firmwa - persisted Beacon settings, - interactive control during transmission, - TX-lock, modulation and battery-safety checks. -- Fox Hunt and Beacon screens are mirrored to K5Viewer. +- Fox Hunt and Beacon screens are mirrored to UV Studio's integrated K5Viewer. ### RF Log @@ -200,15 +200,16 @@ Fusion is the reference edition of the project. It provides an all-in-one firmwa - S-meter level, - battery voltage. - On-radio history with RX/TX filtering and detailed views. -- Live RF Log dashboard and history access through K5Viewer. +- Live RF Log dashboard and history access through UV Studio. ### Connectivity and data transfer -- Live screen streaming to K5Viewer over a USB serial connection. +- Live screen streaming to [UV Studio](https://armel.github.io/uvstudio/) over a USB serial connection. - Screenshot capture and download. -- Remote keyboard control from K5Viewer. -- Automatic K5Viewer reconnection after a USB disconnect. -- RF Log monitoring and analytics in K5Viewer. +- Remote keyboard control through the integrated K5Viewer. +- Automatic reconnection after a USB disconnect. +- RF Log monitoring, analytics and CSV export. +- Firmware flashing, calibration backup and restore, and boot-logo management from the same interface. - BEAM transfer of complete channel settings between compatible radios. - Improved AirCopy interface and progress reporting. @@ -386,30 +387,30 @@ remains an explicit Git operation. - The first run may take a few minutes while Docker builds the base image. - Each build runs inside Docker, so your host environment remains clean. -## Flashing the Firmware with UVTools2 +## Flashing the Firmware with UV Studio -You can flash the UV-K5 V3 and UV-K1 directly from your web browser using the cross-platform WebSerial-based [UVTools2](https://armel.github.io/uvtools2/). +You can flash the UV-K5 V3 and UV-K1 directly from your web browser using the Web Serial-based [UV Studio](https://armel.github.io/uvstudio/). -It works on Chrome, Chromium and Edge (desktop versions), and does not require installing any driver or software on your computer. +UV Studio combines firmware flashing, calibration maintenance, boot-logo management, K5Viewer and RF Log in a single interface. It requires no application installation, server or account. Use a desktop browser with Web Serial support, such as Chrome, Brave, Edge, Opera or Firefox 151+. ## Steps to flash the firmware -- Open UVTools2 in [flash](https://armel.github.io/uvtools2/?mode=flash) mode (or click the Flash Firmware tab). +- Open the [Flash Firmware](https://armel.github.io/uvstudio/#flash) view in UV Studio. - Connect your radio to your computer using a compatible USB programming cable (USB-C or Baofeng/Kenwood like double jack USB cable). - Make sure your radio is in **DFU mode (flash mode)**. -- Select the firmware .bin file on your computer. +- Select an official F4HWN Fusion release from the catalog or load a local `.bin` firmware file. - Click on `Flash Firmware`, then select the serial port associated with your radio. - The progress bar will guide you through the flashing steps. -Once finished, your radio restart with the new firmware. +Once finished, your radio restarts with the new firmware. ## Steps to dump or restore calibration data -[UVTools2](https://armel.github.io/uvtools2/) can also dump and restore calibration data, which is highly recommended. It’s best to create a dump right after installing F4HWN firmware, and to restore it before installing another firmware (or when returning to the stock firmware, for example). +[UV Studio](https://armel.github.io/uvstudio/) can also dump and restore calibration data, which is highly recommended. It is best to create a dump immediately after installing the F4HWN firmware, and to restore it before installing another firmware or returning to the stock firmware. ### Dump -- Open UVTools2 in [dump](https://armel.github.io/uvtools2/?mode=dump) mode (or click the Dump Calib tab). +- Open the [Dump Calibration](https://armel.github.io/uvstudio/#dump-calib) view in UV Studio. - Power on your radio in **normal mode**. - Click `Dump Calibration Data`. @@ -420,9 +421,9 @@ When the process is complete, click `Download calibration.dat` to save the file ### Restore -- Open UVTools2 in [restore](https://armel.github.io/uvtools2/?mode=restore) mode (or click the Restore Calib tab). +- Open the [Restore Calibration](https://armel.github.io/uvstudio/#restore-calib) view in UV Studio. - Power on your radio in **normal mode**. -- Select your calibration.dat file on your computer. +- Select your `calibration.dat` file on your computer. Click `Restore Calibration Data` and wait until the process fully completes. From 3518ab829424febf3b93563f1e1d6ad60e9c592c Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 04:09:02 +0200 Subject: [PATCH 40/42] Fix restart command during Beacon TX --- App/app/foxhunt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/App/app/foxhunt.c b/App/app/foxhunt.c index d34af3ff..9246c5ba 100644 --- a/App/app/foxhunt.c +++ b/App/app/foxhunt.c @@ -912,9 +912,15 @@ static void FOXHUNT_BeaconTransmit(void) ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); - for (uint8_t i = 0; !stop && beaconMsg[i]; i++) + for (uint8_t i = 0; !stop && beaconMsg[i]; i++) { stop = FOXHUNT_MorseChar(beaconMsg[i], i + 1u); +#if defined(ENABLE_UART) || defined(ENABLE_USB) + // Service maintenance commands in the muted inter-character gap. + UART_ServiceCommands(); +#endif + } + #ifdef ENABLE_FEAT_F4HWN_K5VIEWER // Service the K5Viewer link in the muted gap (never during a keyed element, so // the Morse timing stays intact): ParseInput refills the keep-alive that Update From 39f46a8f93bd8e0fbdce3937a96c1369665c1efe Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 14:41:27 +0200 Subject: [PATCH 41/42] Update donors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29593840..6b9e0511 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Anyway, have fun. # Donations -Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ, Carlos EA1IJ, Brian M7YLF and Giuseppe IT9LLH for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 +Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ, Carlos EA1IJ, Brian M7YLF, Giuseppe IT9LLH and 邓 月 for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 ## Table of Contents From 1e4698409b7e428a47863623e0375621152de541 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Tue, 4 Aug 2026 17:15:56 +0200 Subject: [PATCH 42/42] Prepare new version 5.8.0 --- archive/f4hwn.fusion.v5.8.0.bin | Bin 0 -> 109276 bytes archive/f4hwn.fusion.v5.8.0.sa818.bin | Bin 0 -> 109276 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 archive/f4hwn.fusion.v5.8.0.bin create mode 100755 archive/f4hwn.fusion.v5.8.0.sa818.bin diff --git a/archive/f4hwn.fusion.v5.8.0.bin b/archive/f4hwn.fusion.v5.8.0.bin new file mode 100755 index 0000000000000000000000000000000000000000..04e70d5108943ca7b5de6cacb2370a4771a377c6 GIT binary patch literal 109276 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�SGLo(~Q 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

    `9E8k3bO;{z+Lo;)y_*k1a@1!O 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 literal 0 HcmV?d00001 diff --git a/archive/f4hwn.fusion.v5.8.0.sa818.bin b/archive/f4hwn.fusion.v5.8.0.sa818.bin new file mode 100755 index 0000000000000000000000000000000000000000..d4c86c661f00270e5c15e122564668fa653ab58a GIT binary patch literal 109276 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%0A;UHTy}qIFHGGvYhMmk4_#3~Vu= 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 CV`@