Fix TWDT starvation, vsync race, and UI responsiveness from review
Three bugs and two UX defects found on review, plus hardening: - The control loop fed the task watchdog then slept exactly the watchdog period (both 10s), tripping the TWDT fractionally late on every single iteration. Sleep is now sliced 1s with a reset per slice. Also set CONFIG_ESP_TASK_WDT_PANIC=y - the sdkconfig comment claimed a hung task panics the chip, but nothing actually made that true. - The LVGL flush called draw_bitmap (which only queues the framebuffer switch) and released LVGL immediately, letting it render the next frame into the buffer still being scanned out - the exact PRD 8.2 race the double-buffer design exists to prevent. display_present_frame() now blocks on a vsync handshake until the swap has latched. - WiFi reconnect slept up to 30s inside the system event handler, stalling all queued WiFi/IP events. Moved to an esp_timer. - The setpoint label, arc, and mode/room lines rendered the control loop's copy of state, which refreshes every 10s - every knob detent looked dead for up to 10 seconds. The UI now reads settings live; when the fallback ladder clamps the setpoint it shows both values. Room-select focus now shows which room is being selected. - z2m ISO_8601_local timestamps carry a UTC offset the parser ignored, which would shift apparent reading age by the local offset (5-6h in the US) and permanently trip the fallback ladder. Offset is now honoured. - Suppressed the cosmetic "control loop stopped" fault in the window between relay_init and the control task's first call-in at boot. - Explicit pullups on the encoder A/B lines. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d2e4c974dd
commit
4c7b120473
10 files changed
+206
-27
No files matched your search
+10
-1
@@ -310,7 +310,16 @@ static void control_task(void *arg)
|
||||
last_call = st.calling_for_heat;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(CONTROL_INTERVAL_S * 1000));
|
||||
/*
|
||||
* Sleep in 1s slices, feeding the task watchdog each one. A single
|
||||
* CONTROL_INTERVAL_S delay would finish fractionally *after* the TWDT
|
||||
* deadline every iteration (both are 10s) and trip it spuriously —
|
||||
* while still keeping the evaluation cadence at CONTROL_INTERVAL_S.
|
||||
*/
|
||||
for (int i = 0; i < CONTROL_INTERVAL_S; i++) {
|
||||
esp_task_wdt_reset();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -31,6 +31,7 @@ static bool s_initialised;
|
||||
|
||||
static bool s_heat_on;
|
||||
static bool s_requested;
|
||||
static bool s_ever_requested; /* control loop has called in at least once */
|
||||
static relay_fault_t s_fault;
|
||||
|
||||
static int64_t s_boot_us;
|
||||
@@ -221,7 +222,15 @@ static void safety_task(void *arg)
|
||||
if (!control_alive) {
|
||||
if (s_heat_on) {
|
||||
turn_off_locked(RELAY_FAULT_WATCHDOG);
|
||||
} else if (s_fault == RELAY_FAULT_NONE) {
|
||||
} else if (s_fault == RELAY_FAULT_NONE && s_ever_requested) {
|
||||
/*
|
||||
* Only fault once the control loop has *stopped* talking.
|
||||
* Before its first-ever call this is just boot ordering — the
|
||||
* relay is held off regardless (the seeded-stale watchdog is
|
||||
* the bounded-startup interlock), and flashing "control loop
|
||||
* stopped" on every power-up would teach the user to ignore
|
||||
* the one fault that matters most.
|
||||
*/
|
||||
s_fault = RELAY_FAULT_WATCHDOG;
|
||||
}
|
||||
s_requested = false;
|
||||
@@ -269,6 +278,7 @@ esp_err_t relay_init(void)
|
||||
s_last_start_us = 0;
|
||||
s_heat_on = false;
|
||||
s_requested = false;
|
||||
s_ever_requested = false;
|
||||
s_fault = RELAY_FAULT_NONE;
|
||||
|
||||
/*
|
||||
@@ -303,6 +313,7 @@ void relay_request_heat(bool want_heat)
|
||||
|
||||
xSemaphoreTake(s_lock, portMAX_DELAY);
|
||||
s_requested = want_heat;
|
||||
s_ever_requested = true;
|
||||
s_last_request_us = now_us();
|
||||
|
||||
/* Recovering from a watchdog trip: the control loop is talking again. */
|
||||
|
||||
Reference in new issue
Block a user