From 38b8ff07cf9ea64ac779416f78710703775a2e33 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Sat, 4 Jul 2026 14:15:31 +0200 Subject: [PATCH] rework refresh display --- zephcore/helpers/ui-button/ui_pages.c | 17 ++++++----- zephcore/helpers/ui-button/ui_task.c | 29 ++++++++++++++++++- .../helpers/ui-joystick/joystick_ui_hooks.cpp | 8 ----- zephcore/helpers/ui/ui_headless_stubs.c | 2 -- zephcore/helpers/ui/ui_task.h | 6 ---- zephcore/src/main_repeater.cpp | 14 ++++----- 6 files changed, 43 insertions(+), 33 deletions(-) diff --git a/zephcore/helpers/ui-button/ui_pages.c b/zephcore/helpers/ui-button/ui_pages.c index fc5460f..e2af79d 100644 --- a/zephcore/helpers/ui-button/ui_pages.c +++ b/zephcore/helpers/ui-button/ui_pages.c @@ -63,7 +63,6 @@ LOG_MODULE_REGISTER(ui_pages, CONFIG_ZEPHCORE_BOARD_LOG_LEVEL); #define UI_COLOR_TITLE 0xffde /* warm white */ #define UI_COLOR_LABEL 0x8410 /* muted gray */ #define UI_COLOR_VALUE MC_COLOR_WHITE -#define UI_COLOR_SECONDARY 0xbdf7 /* soft gray-white */ #define UI_COLOR_OK 0x07e0 #define UI_COLOR_ACTIVE UI_COLOR_OK #define UI_COLOR_WARN 0xffa0 @@ -383,6 +382,14 @@ static bool use_compact_color_home(void) return mc_display_has_color() && DISP_W <= 180 && DISP_H <= 100; } +/* Short label for the current LoRa radio state, shared across pages. */ +static const char *radio_state_label(void) +{ + return state.lora_tx_active ? "TX" : + state.lora_in_rx ? "RX" : + state.lora_radio_ready ? "RDY" : "WAIT"; +} + static uint8_t clamp_activity_delta(uint32_t delta) { return (delta > 15U) ? 15U : (uint8_t)delta; @@ -491,9 +498,7 @@ static void render_messages(void) int y = CONTENT_Y; uint16_t ble_color = state.ble_connected ? UI_COLOR_OK : UI_COLOR_WARN; const char *ble = state.ble_connected ? "BLE OK" : "BLE ADV"; - const char *radio = state.lora_tx_active ? "TX" : - (state.lora_in_rx ? "RX" : - (state.lora_radio_ready ? "RDY" : "WAIT")); + const char *radio = radio_state_label(); uint16_t radio_color = state.lora_tx_active ? UI_COLOR_TX : state.lora_in_rx ? UI_COLOR_RX : state.lora_radio_ready ? UI_COLOR_OK @@ -632,9 +637,7 @@ static void render_radio(void) uint32_t freq_frac = (state.lora_freq_hz % 1000000 + 500) / 1000; uint16_t bw_int = state.lora_bw_khz_x10 / 10; uint16_t bw_frac = state.lora_bw_khz_x10 % 10; - const char *packet_state = state.lora_tx_active ? "TX" : - (state.lora_in_rx ? "RX" : - (state.lora_radio_ready ? "RDY" : "WAIT")); + const char *packet_state = radio_state_label(); const char *rx_mode = state.lora_rx_duty_cycle ? "DC" : "CONT"; uint16_t warn_color = (state.lora_apc_enabled && state.lora_apc_reduction > 0) ? UI_COLOR_WARN : UI_COLOR_OK; diff --git a/zephcore/helpers/ui-button/ui_task.c b/zephcore/helpers/ui-button/ui_task.c index 6c077ae..445ef3b 100644 --- a/zephcore/helpers/ui-button/ui_task.c +++ b/zephcore/helpers/ui-button/ui_task.c @@ -185,6 +185,7 @@ static void splash_work_handler(struct k_work *work) } static void schedule_render(void); +static void schedule_render_auto(void); static void advert_defer_handler(struct k_work *work) { @@ -882,6 +883,10 @@ void ui_set_radio_params(uint32_t freq_hz, uint8_t sf, uint16_t bw_khz_x10, uint8_t cr, int8_t tx_power, int16_t noise_floor) { struct ui_state *s = get_state(); + bool changed = s->lora_freq_hz != freq_hz || s->lora_sf != sf || + s->lora_bw_khz_x10 != bw_khz_x10 || s->lora_cr != cr || + s->lora_tx_power != tx_power || + s->lora_noise_floor != noise_floor; s->lora_freq_hz = freq_hz; s->lora_sf = sf; @@ -889,6 +894,10 @@ void ui_set_radio_params(uint32_t freq_hz, uint8_t sf, uint16_t bw_khz_x10, s->lora_cr = cr; s->lora_tx_power = tx_power; s->lora_noise_floor = noise_floor; + + if (changed) { + schedule_render_auto(); + } } void ui_set_radio_runtime(int8_t effective_tx_power, bool apc_enabled, @@ -898,6 +907,17 @@ void ui_set_radio_runtime(int8_t effective_tx_power, bool apc_enabled, bool radio_ready, bool in_rx, bool tx_active) { struct ui_state *s = get_state(); + bool changed = s->lora_effective_tx_power != effective_tx_power || + s->lora_apc_enabled != apc_enabled || + s->lora_apc_reduction != apc_reduction || + s->lora_apc_margin_x10 != apc_margin_x10 || + s->lora_apc_target_margin != apc_target_margin || + s->lora_sync_word != sync_word || + s->lora_preamble_len != preamble_len || + s->lora_rx_duty_cycle != rx_duty_cycle || + s->lora_radio_ready != radio_ready || + s->lora_in_rx != in_rx || + s->lora_tx_active != tx_active; s->lora_effective_tx_power = effective_tx_power; s->lora_apc_enabled = apc_enabled; @@ -910,6 +930,10 @@ void ui_set_radio_runtime(int8_t effective_tx_power, bool apc_enabled, s->lora_radio_ready = radio_ready; s->lora_in_rx = in_rx; s->lora_tx_active = tx_active; + + if (changed) { + schedule_render_auto(); + } } void ui_set_radio_stats(uint32_t packets_rx, uint32_t packets_tx, @@ -1080,7 +1104,10 @@ void ui_set_offgrid_mode(bool enabled) s->offgrid_enabled = enabled; } -void ui_refresh_display(void) +/* Schedule a redraw for an automatic (non-interactive) state update, e.g. a + * live radio value changing. Skips EPD panels, which only repaint on real + * events to avoid ~2s flashes. */ +static void schedule_render_auto(void) { if (!ui_initialized) { return; diff --git a/zephcore/helpers/ui-joystick/joystick_ui_hooks.cpp b/zephcore/helpers/ui-joystick/joystick_ui_hooks.cpp index e6e341a..a453307 100644 --- a/zephcore/helpers/ui-joystick/joystick_ui_hooks.cpp +++ b/zephcore/helpers/ui-joystick/joystick_ui_hooks.cpp @@ -266,14 +266,6 @@ extern "C" void ui_set_ble_enabled(bool enabled) } } -extern "C" void ui_refresh_display(void) -{ - if (s_task) { - s_task->forceRefresh(); - } -} - - /* ===== Pull-model no-ops ===== * The joystick UI reads all hardware state on demand at render time, so these * push-model hooks from the old button UI have no work to do. */ diff --git a/zephcore/helpers/ui/ui_headless_stubs.c b/zephcore/helpers/ui/ui_headless_stubs.c index 8112e62..c11a495 100644 --- a/zephcore/helpers/ui/ui_headless_stubs.c +++ b/zephcore/helpers/ui/ui_headless_stubs.c @@ -68,8 +68,6 @@ WEAK void ui_set_radio_stats(uint32_t packets_rx, uint32_t packets_tx, ARG_UNUSED(packets_rx); ARG_UNUSED(packets_tx); ARG_UNUSED(packets_err); } -WEAK void ui_refresh_display(void) { } - WEAK void ui_set_gps_data(bool has_fix, uint8_t sats, int32_t lat_mdeg, int32_t lon_mdeg, int32_t alt_mm) { diff --git a/zephcore/helpers/ui/ui_task.h b/zephcore/helpers/ui/ui_task.h index 334cfca..be98a0a 100644 --- a/zephcore/helpers/ui/ui_task.h +++ b/zephcore/helpers/ui/ui_task.h @@ -99,12 +99,6 @@ void ui_set_radio_runtime(int8_t effective_tx_power, bool apc_enabled, void ui_set_radio_stats(uint32_t packets_rx, uint32_t packets_tx, uint32_t packets_err); -/** - * Request an immediate display redraw for the current UI state. - * No-op on headless builds. - */ -void ui_refresh_display(void); - /** * Update GPS data for display. */ diff --git a/zephcore/src/main_repeater.cpp b/zephcore/src/main_repeater.cpp index 98ad7f1..2cce46f 100644 --- a/zephcore/src/main_repeater.cpp +++ b/zephcore/src/main_repeater.cpp @@ -141,7 +141,7 @@ K_TIMER_DEFINE(housekeeping_timer, housekeeping_timer_fn, NULL); /* Forward declarations */ #ifdef ZEPHCORE_LORA static RepeaterMesh *repeater_mesh_ptr; -static void refresh_repeater_ui_radio_state(bool redraw); +static void refresh_repeater_ui_radio_state(void); #endif /* Print string to USB serial */ @@ -234,7 +234,7 @@ static void process_cli_commands(void) while (repeater_mesh_ptr && k_msgq_get(&cli_cmd_queue, &c, K_NO_WAIT) == 0) { cli_reply_buf[0] = '\0'; repeater_mesh_ptr->handleCommand(0, c.buf, cli_reply_buf); - refresh_repeater_ui_radio_state(true); + refresh_repeater_ui_radio_state(); if (cli_reply_buf[0] != '\0') { cli_print("\r\n -> "); cli_print(cli_reply_buf); @@ -361,7 +361,7 @@ static mesh::SimpleMeshTables mesh_tables; /* RepeaterMesh requires: board, radio, ms_clock, rng, rtc, tables */ static RepeaterMesh repeater_mesh(zephyr_board, lora_radio, ms_clock, zephyr_rng, rtc_clock, mesh_tables); -static void refresh_repeater_ui_radio_state(bool redraw) +static void refresh_repeater_ui_radio_state(void) { if (!repeater_mesh_ptr) { return; @@ -404,10 +404,6 @@ static void refresh_repeater_ui_radio_state(bool redraw) lora_radio.getPacketsRecv(), lora_radio.getPacketsSent(), lora_radio.getPacketsRecvErrors()); - - if (redraw) { - ui_refresh_display(); - } } #endif @@ -478,7 +474,7 @@ static void repeater_event_loop(void) #ifdef ZEPHCORE_LORA /* Refresh live radio/APC state (noise floor, TX power * reduction, RX/TX mode, packet counters). */ - refresh_repeater_ui_radio_state(true); + refresh_repeater_ui_radio_state(); /* Battery is now refreshed lazily from ui_pages_render() with * a 30 s freshness guard — no periodic ADC fire here. */ @@ -637,7 +633,7 @@ int main(void) /* Feed initial UI state from loaded prefs */ ui_set_node_name(prefs->node_name); - refresh_repeater_ui_radio_state(false); + refresh_repeater_ui_radio_state(); ui_set_battery_provider(get_battery_mv); ui_set_battery(zephyr_board.getBattMilliVolts(), 0); ui_set_gps_available(gps_is_available());