From 2c80e5530a0fcaa598a19a95c53e71dd70d10630 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 20 May 2026 11:11:07 +0000 Subject: [PATCH 1/3] fix(badge): preserve audio mutex ownership on reset timeout Co-authored-by: andrew867 --- .../projects/dashcdg_badge/main/badge_rx.c | 29 ++++++++++++------- .../projects/dashcdg_badge/main/sfx_touch.c | 9 ++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/platform/espidf/projects/dashcdg_badge/main/badge_rx.c b/platform/espidf/projects/dashcdg_badge/main/badge_rx.c index 203ab51..c48afb9 100644 --- a/platform/espidf/projects/dashcdg_badge/main/badge_rx.c +++ b/platform/espidf/projects/dashcdg_badge/main/badge_rx.c @@ -4199,7 +4199,7 @@ static int badge_rx_reset_for_new_session_locked(uint64_t local_now_ms) return 0; } -static void handle_session_info(const struct dashcdg_packet_view *view) +static int handle_session_info(const struct dashcdg_packet_view *view) { int same_session; @@ -4231,11 +4231,16 @@ static void handle_session_info(const struct dashcdg_packet_view *view) } else { s_session_epoch_sender_floor_ms = view->header.sender_time_ms; } - return; + return 1; } if (badge_rx_reset_for_new_session_locked(dashcdg_clock_now_ms()) != 0) { - return; + /* + * badge_rx_reset_for_new_session_locked drops s_mtx before heavyweight reset work. + * A non-zero return means it failed to re-acquire s_mtx before the bounded timeout, + * so the pump must not perform its normal unconditional give for this datagram. + */ + return 0; } s_active_session_start_ms = view->v4_session_info.session_start_ms; @@ -4251,6 +4256,7 @@ static void handle_session_info(const struct dashcdg_packet_view *view) memcpy(s_stats.song_id, view->v4_session_info.song_id, DASHCDG_MAX_SONG_ID); s_stats.song_id[DASHCDG_MAX_SONG_ID] = '\0'; s_stats.v4_session_count++; + return 1; } static void handle_clock_sync(const struct dashcdg_packet_view *view, uint64_t local_now_ms) @@ -4759,14 +4765,14 @@ static void badge_rx_process_repair_datagram(const uint8_t *buf, size_t buflen) } } -static void rx_one_datagram(uint8_t *buf, size_t buflen, uint64_t local_now_ms) +static int rx_one_datagram(uint8_t *buf, size_t buflen, uint64_t local_now_ms) { struct dashcdg_packet_view view; uint64_t seq; if (!dashcdg_protocol_parse_packet(&view, buf, buflen)) { s_stats.parse_failures++; - return; + return 1; } seq = view.header.sequence; @@ -4785,8 +4791,7 @@ static void rx_one_datagram(uint8_t *buf, size_t buflen, uint64_t local_now_ms) switch (view.header.type) { case DASHCDG_PACKET_V4_SESSION_INFO: - handle_session_info(&view); - break; + return handle_session_info(&view); case DASHCDG_PACKET_V4_CLOCK_SYNC: handle_clock_sync(&view, local_now_ms); /* `drain_cdg_to_idle` walks CDG jitter + audio; skip CDG drain when video decode is off. */ @@ -4833,6 +4838,7 @@ static void rx_one_datagram(uint8_t *buf, size_t buflen, uint64_t local_now_ms) default: break; } + return 1; } static void badge_rx_deferred_audio_drain_if_pending_locked(uint64_t local_now_ms) @@ -4942,8 +4948,9 @@ static void badge_rx_pump_main_fd(int pump_fd, uint8_t *buf, size_t buf_cap) #if defined(CONFIG_DASHCDG_BADGE_PERF_PROBES) && CONFIG_DASHCDG_BADGE_PERF_PROBES const int64_t t_hold0 = esp_timer_get_time(); #endif + int still_holds_mtx; s_stats.datagrams++; - rx_one_datagram(buf, (size_t)n, now_ms); + still_holds_mtx = rx_one_datagram(buf, (size_t)n, now_ms); #if defined(CONFIG_DASHCDG_BADGE_PERF_PROBES) && CONFIG_DASHCDG_BADGE_PERF_PROBES { int64_t dt_hold = esp_timer_get_time() - t_hold0; @@ -4953,8 +4960,10 @@ static void badge_rx_pump_main_fd(int pump_fd, uint8_t *buf, size_t buf_cap) } } #endif - xSemaphoreGive(s_mtx); - badge_rx_pump_flush_deferred_audio_drain(now_ms); + if (still_holds_mtx) { + xSemaphoreGive(s_mtx); + badge_rx_pump_flush_deferred_audio_drain(now_ms); + } dashcdg_platform_hw_note_karaoke_mcast_rx(now_ms); /* * T7: mark progress (not just heartbeat) so the liveness sweep can tell diff --git a/platform/espidf/projects/dashcdg_badge/main/sfx_touch.c b/platform/espidf/projects/dashcdg_badge/main/sfx_touch.c index 6ef7bee..6bd1996 100644 --- a/platform/espidf/projects/dashcdg_badge/main/sfx_touch.c +++ b/platform/espidf/projects/dashcdg_badge/main/sfx_touch.c @@ -5,6 +5,7 @@ #include "audio_mgr.h" #include "badge_exec.h" +#include "platform_hw.h" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" @@ -38,6 +39,14 @@ static void sfx_task_fn(void *arg) /* Best-effort: do not crash if audio_mgr init fails. */ (void)dashcdg_audio_mgr_init(); + /* + * The chirp uses the shared DAC path at 24 kHz. Do not let a UI touch tear down an + * active karaoke RX stream (48 kHz line rate) just to reopen the DAC for SFX. + */ + if (dashcdg_platform_hw_dac_route_owner() == DASHCDG_DAC_ROUTE_KARAOKE_RX) { + continue; + } + /* 80 ms chirp @ 24 kHz. */ enum { FS = 24000, MS = 80, N = (FS * MS) / 1000 }; static int16_t pcm[N]; From 9e8b56b36880bd88b2fe89d0fb1fe6b40e409fc3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 20 May 2026 11:18:11 +0000 Subject: [PATCH 2/3] fix(badge): avoid boot reason format truncation Co-authored-by: andrew867 --- .../projects/dashcdg_badge/main/badge_exec.c | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/platform/espidf/projects/dashcdg_badge/main/badge_exec.c b/platform/espidf/projects/dashcdg_badge/main/badge_exec.c index 757919c..9252e80 100644 --- a/platform/espidf/projects/dashcdg_badge/main/badge_exec.c +++ b/platform/espidf/projects/dashcdg_badge/main/badge_exec.c @@ -277,6 +277,19 @@ int dashcdg_badge_exec_get_boot_complete_state(void) return 0; } +static void badge_exec_append_text(char *out, size_t out_len, size_t *off, const char *text) +{ + if (out == NULL || out_len == 0U || off == NULL || text == NULL) { + return; + } + while (*text != '\0' && *off + 1U < out_len) { + out[*off] = *text; + (*off)++; + text++; + } + out[*off] = '\0'; +} + /* * Build a short human-readable reason describing why the boot was DEGRADED. Each contributing bit * adds its short tag to a comma-separated list. NOMINAL boots produce "ok". @@ -380,10 +393,14 @@ esp_err_t dashcdg_badge_exec_decide_boot_complete(void) if ((bits & hw_any) == 0U) { BADGE_EXEC_MISSING_APPEND(hw_any, "hw"); } #undef BADGE_EXEC_MISSING_APPEND char merged[sizeof(reason)]; - snprintf(merged, sizeof(merged), "missing=%s%s%s", - missing, - reason[0] ? "," : "", - reason[0] ? reason : ""); + size_t merged_off = 0U; + merged[0] = '\0'; + badge_exec_append_text(merged, sizeof(merged), &merged_off, "missing="); + badge_exec_append_text(merged, sizeof(merged), &merged_off, missing); + if (reason[0] != '\0') { + badge_exec_append_text(merged, sizeof(merged), &merged_off, ","); + badge_exec_append_text(merged, sizeof(merged), &merged_off, reason); + } return dashcdg_badge_exec_set_boot_complete(true, merged); } return dashcdg_badge_exec_set_boot_complete(degraded, reason); From f1c7ef6e689cf388b2f5ef25bad006cc812747a6 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 20 May 2026 11:18:52 +0000 Subject: [PATCH 3/3] fix(badge): avoid wifi credential copy truncation warnings Co-authored-by: andrew867 --- .../projects/dashcdg_badge/main/wifi_touch_ui.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/platform/espidf/projects/dashcdg_badge/main/wifi_touch_ui.c b/platform/espidf/projects/dashcdg_badge/main/wifi_touch_ui.c index 5a4ff71..6fa7f7c 100644 --- a/platform/espidf/projects/dashcdg_badge/main/wifi_touch_ui.c +++ b/platform/espidf/projects/dashcdg_badge/main/wifi_touch_ui.c @@ -304,10 +304,22 @@ static void wifi_touch_clamp_ps_none_if_rx_active(void) /** ESP-IDF `wifi_config_t` SSID/password are fixed arrays; avoid `strncpy(..., n-1)` — GCC stringop-truncation. */ static void wifi_touch_copy_to_cfg_field(uint8_t *dst, size_t dst_sz, const char *src) { + size_t i = 0U; + if (dst == NULL || dst_sz == 0U) { return; } - snprintf((char *)dst, dst_sz, "%s", (src != NULL) ? src : ""); + if (src == NULL) { + src = ""; + } + while (src[i] != '\0' && i + 1U < dst_sz) { + dst[i] = (uint8_t)src[i]; + i++; + } + dst[i] = '\0'; + if (i + 1U < dst_sz) { + memset(dst + i + 1U, 0, dst_sz - i - 1U); + } } static esp_netif_t *s_wifi_sta_netif; static const char *NVS_NS = "dashcfg";