From fd437ec015c959da1944613c96689ee5c50d2ff2 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Fri, 18 Sep 2026 04:59:17 +0200 Subject: [PATCH] Refresh app slots during UV Studio updates --- App/app/uart.c | 2 ++ App/apps/app_menu.c | 35 +++++++++++++++++++++++++++++------ App/apps/app_overlay.c | 14 +++++++++++++- App/apps/app_overlay.h | 5 +++++ 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/App/app/uart.c b/App/app/uart.c index fbbc017b..49e65719 100644 --- a/App/app/uart.c +++ b/App/app/uart.c @@ -1304,6 +1304,8 @@ void UART_HandleCommand(uint32_t Port) gSerialConfigCountDown_500ms = 12; // keep serial mode alive (6 s) uint8_t slot = pUART_Command->Data[0]; uint8_t status = APP_ValidateSlot(slot, NULL); + if (status == APP_OK) + APP_NotifySlotChanged(); struct __attribute__((packed)) { Header_t Header; uint8_t Slot; diff --git a/App/apps/app_menu.c b/App/apps/app_menu.c index 24f86eed..bd1dc8bc 100644 --- a/App/apps/app_menu.c +++ b/App/apps/app_menu.c @@ -21,6 +21,7 @@ #include #include "apps/app_menu.h" #include "app/app.h" +#include "app/uart.h" #include "driver/backlight.h" #include "driver/st7565.h" #include "driver/keyboard.h" @@ -80,12 +81,21 @@ static void app_invert_name(uint8_t line) /* Debounced blocking key read, then wait for release (mirrors mb_get_key). */ static KEY_Code_t app_get_key(void) { +#if defined(ENABLE_UART) || defined(ENABLE_USB) + const uint8_t slot_revision = APP_SlotRevision(); +#endif + for (;;) { #ifdef ENABLE_FEAT_F4HWN_K5VIEWER /* APP_MenuOpen() is modal and does not return to APP_Update(). Keep * serial key injection and the viewer connection alive while waiting. */ K5VIEWER_ParseInput(); +#endif +#if defined(ENABLE_UART) || defined(ENABLE_USB) + UART_ServiceCommands(); + if (APP_SlotRevision() != slot_revision) + return KEY_INVALID; #endif APP_ModalBacklightTick(true); @@ -219,6 +229,16 @@ static void app_show_error(const app_header_t *header, uint8_t rc) _Static_assert(APP_MENU_SLOT_COUNT <= APP_SLOT_COUNT, "APP_MENU_SLOT_COUNT exceeds the physical app slot count"); +static void app_scan_slots(app_header_t hdr[APP_MENU_SLOT_COUNT], + bool installed[APP_MENU_SLOT_COUNT]) +{ + for (uint8_t slot = 0; slot < APP_MENU_SLOT_COUNT; slot++) + { + installed[slot] = APP_SlotInfo(slot, &hdr[slot]) == APP_OK && + (hdr[slot].flags & APP_FLAG_COMMITTED); + } +} + void APP_MenuOpen(void) { APP_ModalScreenSaverExit(); @@ -238,12 +258,8 @@ void APP_MenuOpen(void) * visible and selectable while scrolling. */ app_header_t hdr[APP_MENU_SLOT_COUNT]; bool installed[APP_MENU_SLOT_COUNT]; - - for (uint8_t slot = 0; slot < APP_MENU_SLOT_COUNT; slot++) - { - installed[slot] = APP_SlotInfo(slot, &hdr[slot]) == APP_OK && - (hdr[slot].flags & APP_FLAG_COMMITTED); - } + uint8_t slot_revision = APP_SlotRevision(); + app_scan_slots(hdr, installed); /* Remember the physical slot and scrolling window across menu openings. */ static uint8_t sel = 0; @@ -254,6 +270,13 @@ void APP_MenuOpen(void) for (;;) { + const uint8_t current_revision = APP_SlotRevision(); + if (current_revision != slot_revision) + { + app_scan_slots(hdr, installed); + slot_revision = current_revision; + } + UI_DisplayClear(); app_status_bar(); /* also wipes the VFO status line (DW, battery, ...) */ diff --git a/App/apps/app_overlay.c b/App/apps/app_overlay.c index e993ad9b..ff6bf58f 100644 --- a/App/apps/app_overlay.c +++ b/App/apps/app_overlay.c @@ -937,6 +937,18 @@ uint8_t APP_ValidateSlot(uint8_t slot, app_header_t *out_header) static bool app_shortcuts_cached; static uint8_t app_shortcut_mask; static uint8_t app_shortcut_slots[4]; +static uint8_t app_slot_revision; + +uint8_t APP_SlotRevision(void) +{ + return app_slot_revision; +} + +void APP_NotifySlotChanged(void) +{ + app_shortcuts_cached = false; + app_slot_revision++; +} static int8_t app_shortcut_index(uint8_t shortcut) { @@ -1238,7 +1250,7 @@ uint8_t APP_SlotErase(uint8_t slot) for (uint32_t off = 0; off < APP_SLOT_STRIDE; off += APP_SECTOR_SIZE) PY25Q16_SectorErase(base + off); PY25Q16_InvalidateCache(); - app_shortcuts_cached = false; + APP_NotifySlotChanged(); return APP_OK; } diff --git a/App/apps/app_overlay.h b/App/apps/app_overlay.h index 89c4f546..ce701b96 100644 --- a/App/apps/app_overlay.h +++ b/App/apps/app_overlay.h @@ -131,5 +131,10 @@ uint8_t APP_SlotInfo(uint8_t slot, app_header_t *out_header); uint8_t APP_SlotErase(uint8_t slot); uint8_t APP_SlotWrite(uint8_t slot, uint32_t offset, const uint8_t *data, uint32_t len); +/* Change token used by the modal Apps selector. A completed host install is + * published after validation; erasing a slot publishes directly. */ +uint8_t APP_SlotRevision(void); +void APP_NotifySlotChanged(void); + #endif /* APPS_APP_OVERLAY_H */