diff options
Diffstat (limited to 'main/state_machine.c')
| -rw-r--r-- | main/state_machine.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/main/state_machine.c b/main/state_machine.c index 5e688bc..eb2548c 100644 --- a/main/state_machine.c +++ b/main/state_machine.c @@ -4,15 +4,22 @@ #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" #include "freertos/task.h" #include "display.h" +#include "jpeg_decoder.h" #include "local_screens.h" #include "state_client.h" static const char *TAG = "state"; static esp_timer_handle_t s_idle_timer; +// Serializes whole transitions (state write + display side-effects). +// Without it, concurrent wake+sleep callers (HTTP task, touch task, idle +// timer) can interleave display_wake/display_sleep after the state lock +// is dropped and leave the backlight not matching st->state. +static SemaphoreHandle_t s_transition_mutex; // ms = idle_timeout_ms snapshotted under the caller's state lock. // ms == 0 disables the timer (caller's idle_timeout_ms feature). @@ -31,6 +38,8 @@ static void idle_timer_fired(void *arg) esp_err_t state_machine_init(void) { + s_transition_mutex = xSemaphoreCreateMutex(); + if (!s_transition_mutex) return ESP_ERR_NO_MEM; esp_timer_create_args_t args = { .callback = &idle_timer_fired, .name = "viewport_idle", @@ -43,11 +52,14 @@ esp_err_t state_machine_set(viewport_run_state_t target) if (target != VIEWPORT_STATE_AWAKE && target != VIEWPORT_STATE_ASLEEP) return ESP_ERR_INVALID_ARG; + xSemaphoreTake(s_transition_mutex, portMAX_DELAY); + viewport_state_lock(); viewport_state_t *st = viewport_state_get(); if (st->state == target) { viewport_state_unlock(); + xSemaphoreGive(s_transition_mutex); return ESP_OK; // idempotent no-op } st->state = target; @@ -63,8 +75,16 @@ esp_err_t state_machine_set(viewport_run_state_t target) // backlight comes up. Without the delay, esp_lcd_panel_draw_bitmap // returns before the panel has been refreshed and the user sees // a flash of the previous /frame's contents. - if (configured) local_screens_show_loading(); - else local_screens_show_info(); + // + // Decoder lock: the stream decode-task paints under this lock, + // and concurrent esp_lcd_panel_draw_bitmap calls from two tasks + // aren't safe. If the decoder is busy >500 ms a live frame is + // painting anyway — skip the placeholder and just light up. + if (jpeg_decoder_try_lock(500)) { + if (configured) local_screens_show_loading(); + else local_screens_show_info(); + jpeg_decoder_unlock(); + } vTaskDelay(pdMS_TO_TICKS(33)); display_wake(); } @@ -75,6 +95,7 @@ esp_err_t state_machine_set(viewport_run_state_t target) if (display_is_up()) display_sleep(); ESP_LOGI(TAG, "ASLEEP"); } + xSemaphoreGive(s_transition_mutex); return ESP_OK; } |
