diff --git a/components/app_composition/src/runtime/app_composition_default_runtime.c b/components/app_composition/src/runtime/app_composition_default_runtime.c index 9b239d4..53a5862 100644 --- a/components/app_composition/src/runtime/app_composition_default_runtime.c +++ b/components/app_composition/src/runtime/app_composition_default_runtime.c @@ -130,6 +130,17 @@ static esp_err_t app_composition_run_plan_a_boot_sequence(void) return err; } +#if CONFIG_TQ_SCREEN_ENABLE + if (lcd_ready) { + esp_err_t expression_err = control_plane_request_boot_expression(); + if (expression_err != ESP_OK) { + ESP_LOGW(TAG, + "Boot LCD expression request failed: %s", + esp_err_to_name(expression_err)); + } + } +#endif + #if CONFIG_TQ_BOOT_TURNTABLE_CALIBRATION_ENABLE app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_TURNTABLE_CALIBRATION, "turntable_calibration", diff --git a/components/control_plane/src/multimodal/control_plane_multimodal_session_service.c b/components/control_plane/src/multimodal/control_plane_multimodal_session_service.c index dedbf9a..b2f1ec7 100644 --- a/components/control_plane/src/multimodal/control_plane_multimodal_session_service.c +++ b/components/control_plane/src/multimodal/control_plane_multimodal_session_service.c @@ -82,6 +82,7 @@ #define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_TASK_STACK_BYTES 4096U #define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_TASK_PRIORITY 5U #define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_QUEUE_LEN 4U +#define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_IDLE_EXIT_MS 5000U #define CONTROL_PLANE_MULTIMODAL_BINARY_SUMMARY_INTERVAL 200U #define CONTROL_PLANE_UPLINK_READY_WAIT_MS 6000U #define CONTROL_PLANE_UPLINK_READY_POLL_MS 20U @@ -446,8 +447,14 @@ static void local_responding_event_worker(void *arg) local_responding_event_msg_t msg = {0}; while (true) { - if (xQueueReceive(s_local_responding_event_queue, &msg, portMAX_DELAY) != pdTRUE) { - continue; + TickType_t idle_ticks = pdMS_TO_TICKS(CONTROL_PLANE_LOCAL_RESPONDING_EVENT_IDLE_EXIT_MS); + if (idle_ticks == 0) { + idle_ticks = 1; + } + if (xQueueReceive(s_local_responding_event_queue, &msg, idle_ticks) != pdTRUE) { + s_local_responding_event_task = NULL; + vTaskDelete(NULL); + return; } bool should_send = false; diff --git a/components/control_plane/src/runtime/control_plane_runtime_workers.c b/components/control_plane/src/runtime/control_plane_runtime_workers.c index e4bec18..e2c2f46 100644 --- a/components/control_plane/src/runtime/control_plane_runtime_workers.c +++ b/components/control_plane/src/runtime/control_plane_runtime_workers.c @@ -23,7 +23,7 @@ #define CONTROL_PLANE_MODEL_CMD_TASK_STACK_SIZE (1024 * 4) #define CONTROL_PLANE_DIRECTION_TASK_STACK_SIZE (1024 * 4) #define CONTROL_PLANE_LCD_RENDER_LOOP_TASK_STACK_SIZE (1024 * 12) -#define CONTROL_PLANE_WIFI_STATE_TASK_STACK_SIZE (1024 * 6) +#define CONTROL_PLANE_WIFI_STATE_TASK_STACK_SIZE (1024 * 12) #define CONTROL_PLANE_TASK_MONITOR_TASK_STACK_SIZE (1024 * 6) #define CONTROL_PLANE_MODEL_CMD_QUEUE_LEN 4 #define CONTROL_PLANE_MODEL_CMD_RECV_TIMEOUT_MS 200 diff --git a/components/platform/src/multimodal/audio_pipeline.c b/components/platform/src/multimodal/audio_pipeline.c index cc06bae..11d7681 100644 --- a/components/platform/src/multimodal/audio_pipeline.c +++ b/components/platform/src/multimodal/audio_pipeline.c @@ -18,6 +18,7 @@ #include "esp_err.h" #include "esp_heap_caps.h" #include "esp_log.h" +#include "esp_timer.h" #include "esp_opus_dec.h" #include "esp_opus_enc.h" #include "freertos/FreeRTOS.h" @@ -232,7 +233,6 @@ #define MULTIMODAL_PCM_SAMPLE_BYTES 2U #define MULTIMODAL_MIN_DECODER_PCM_BUFFER_BYTES 2048U #define MULTIMODAL_DECODER_BUFFER_GUARD_BYTES 512U -#define MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_TASK_STACK_BYTES 4096U #define MULTIMODAL_AUDIO_DOWNSTREAM_TX_BOUNCE_BYTES 3200U #define MULTIMODAL_AUDIO_DEFAULT_MIC_CHANNEL ((uint8_t)CONFIG_MULTIMODAL_AUDIO_MIC_CHANNEL) @@ -273,7 +273,6 @@ typedef struct { uint8_t *downstream_tx_bounce_buf; size_t downstream_tx_bounce_buf_bytes; uint32_t downstream_playback_generation; - uint32_t downstream_audio_activity_generation; volatile bool downstream_decoder_reset_pending; bool downstream_playback_in_progress; bool downstream_output_muted; @@ -281,8 +280,7 @@ typedef struct { bool downstream_output_primed; bool downstream_response_active; bool downstream_response_end_received; - TaskHandle_t downstream_idle_mute_task; - bool downstream_idle_mute_stop_requested; + esp_timer_handle_t downstream_idle_mute_timer; QueueHandle_t downstream_playback_queue; bool downstream_playback_queue_with_caps; TaskHandle_t downstream_playback_task; diff --git a/components/platform/src/multimodal/audio_pipeline/audio_pipeline_runtime_impl.c b/components/platform/src/multimodal/audio_pipeline/audio_pipeline_runtime_impl.c index fdb3c67..8982d2c 100644 --- a/components/platform/src/multimodal/audio_pipeline/audio_pipeline_runtime_impl.c +++ b/components/platform/src/multimodal/audio_pipeline/audio_pipeline_runtime_impl.c @@ -206,46 +206,24 @@ static void audio_set_uplink_send_task(multimodal_audio_ctx_t *ctx, TaskHandle_t portEXIT_CRITICAL(&s_audio_runtime_lock); } -static bool audio_get_downstream_idle_mute_stop_requested(const multimodal_audio_ctx_t *ctx) +static esp_timer_handle_t audio_get_downstream_idle_mute_timer(const multimodal_audio_ctx_t *ctx) { - bool stop_requested = true; + esp_timer_handle_t timer = NULL; portENTER_CRITICAL(&s_audio_runtime_lock); if (ctx != NULL) { - stop_requested = ctx->downstream_idle_mute_stop_requested; + timer = ctx->downstream_idle_mute_timer; } portEXIT_CRITICAL(&s_audio_runtime_lock); - return stop_requested; + return timer; } -static void audio_set_downstream_idle_mute_stop_requested(multimodal_audio_ctx_t *ctx, bool stop_requested) +static void audio_set_downstream_idle_mute_timer(multimodal_audio_ctx_t *ctx, esp_timer_handle_t timer) { portENTER_CRITICAL(&s_audio_runtime_lock); if (ctx != NULL) { - ctx->downstream_idle_mute_stop_requested = stop_requested; - } - portEXIT_CRITICAL(&s_audio_runtime_lock); -} - -static TaskHandle_t audio_get_downstream_idle_mute_task(const multimodal_audio_ctx_t *ctx) -{ - TaskHandle_t task = NULL; - - portENTER_CRITICAL(&s_audio_runtime_lock); - if (ctx != NULL) { - task = ctx->downstream_idle_mute_task; - } - portEXIT_CRITICAL(&s_audio_runtime_lock); - - return task; -} - -static void audio_set_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx, TaskHandle_t task) -{ - portENTER_CRITICAL(&s_audio_runtime_lock); - if (ctx != NULL) { - ctx->downstream_idle_mute_task = task; + ctx->downstream_idle_mute_timer = timer; } portEXIT_CRITICAL(&s_audio_runtime_lock); } @@ -1118,32 +1096,6 @@ static bool clear_downstream_decoder_reset_pending(uint32_t expected_generation) return cleared; } -static uint32_t snapshot_downstream_audio_activity_generation(void) -{ - uint32_t generation = 0U; - - portENTER_CRITICAL(&s_audio_runtime_lock); - generation = s_audio.downstream_audio_activity_generation; - portEXIT_CRITICAL(&s_audio_runtime_lock); - - return generation; -} - -static uint32_t advance_downstream_audio_activity_generation(void) -{ - uint32_t generation = 0U; - - portENTER_CRITICAL(&s_audio_runtime_lock); - s_audio.downstream_audio_activity_generation++; - if (s_audio.downstream_audio_activity_generation == 0U) { - s_audio.downstream_audio_activity_generation = 1U; - } - generation = s_audio.downstream_audio_activity_generation; - portEXIT_CRITICAL(&s_audio_runtime_lock); - - return generation; -} - static void snapshot_downstream_output_mute_state(bool *out_known, bool *out_muted) { if (out_known == NULL || out_muted == NULL) { @@ -1337,71 +1289,30 @@ static esp_err_t set_downstream_output_mute_if_needed(multimodal_audio_ctx_t *ct return (esp_err_t)ret; } -static TickType_t get_downstream_idle_mute_timeout_ticks(void) +static uint32_t get_downstream_idle_mute_timeout_ms(void) { uint32_t timeout_ms = (uint32_t)CONFIG_MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_MS; if (timeout_ms < 50U) { timeout_ms = 50U; } - - TickType_t ticks = pdMS_TO_TICKS(timeout_ms); - return ticks == 0 ? 1 : ticks; + return timeout_ms; } -static void downstream_idle_mute_task(void *arg) +static void downstream_idle_mute_timer_cb(void *arg) { multimodal_audio_ctx_t *ctx = (multimodal_audio_ctx_t *)arg; - TickType_t idle_timeout_ticks = get_downstream_idle_mute_timeout_ticks(); + if (ctx == NULL || snapshot_downstream_response_active()) { + return; + } + if (ctx->initialized && ctx->codec_dev != NULL) { + (void)set_downstream_output_mute_if_needed(ctx, true, "Idle mute"); + } ESP_LOGI(TAG, - "Downstream idle mute task started (timeout=%ums)", - (unsigned)CONFIG_MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_MS); - - while (ctx != NULL && !audio_get_downstream_idle_mute_stop_requested(ctx)) { - (void)ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - if (audio_get_downstream_idle_mute_stop_requested(ctx)) { - break; - } - - uint32_t observed_generation = snapshot_downstream_audio_activity_generation(); - while (!audio_get_downstream_idle_mute_stop_requested(ctx)) { - uint32_t notify_count = ulTaskNotifyTake(pdTRUE, idle_timeout_ticks); - if (audio_get_downstream_idle_mute_stop_requested(ctx)) { - break; - } - if (notify_count > 0U) { - observed_generation = snapshot_downstream_audio_activity_generation(); - continue; - } - - uint32_t current_generation = snapshot_downstream_audio_activity_generation(); - if (current_generation != observed_generation) { - observed_generation = current_generation; - continue; - } - - if (snapshot_downstream_response_active()) { - continue; - } - - if (ctx->initialized && ctx->codec_dev != NULL) { - (void)set_downstream_output_mute_if_needed(ctx, true, "Idle mute"); - } - ESP_LOGI(TAG, - "Downstream idle mute after %ums (response_active=%d)", - (unsigned)CONFIG_MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_MS, - snapshot_downstream_response_active() ? 1 : 0); - maybe_notify_downstream_playback_completed_after_drain("idle"); - break; - } - } - - if (ctx != NULL) { - audio_set_downstream_idle_mute_task(ctx, NULL); - audio_set_downstream_idle_mute_stop_requested(ctx, false); - } - ESP_LOGI(TAG, "Downstream idle mute task stopped"); - delete_audio_task_with_caps(NULL); + "Downstream idle mute after %ums (response_active=%d)", + (unsigned)get_downstream_idle_mute_timeout_ms(), + snapshot_downstream_response_active() ? 1 : 0); + maybe_notify_downstream_playback_completed_after_drain("idle"); } static esp_err_t ensure_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx) @@ -1409,38 +1320,39 @@ static esp_err_t ensure_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx) if (ctx == NULL) { return ESP_ERR_INVALID_ARG; } - if (audio_get_downstream_idle_mute_task(ctx) != NULL) { + if (audio_get_downstream_idle_mute_timer(ctx) != NULL) { return ESP_OK; } - audio_set_downstream_idle_mute_stop_requested(ctx, false); - TaskHandle_t task = NULL; - BaseType_t created = create_audio_task_with_caps(downstream_idle_mute_task, - "mm_audio_idle_mute", - MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_TASK_STACK_BYTES, - ctx, - 4, - &task, - false, - MULTIMODAL_AUDIO_CORE_ID); - if (created != pdPASS) { - audio_set_downstream_idle_mute_task(ctx, NULL); - return ESP_ERR_NO_MEM; + const esp_timer_create_args_t timer_args = { + .callback = downstream_idle_mute_timer_cb, + .arg = ctx, + .dispatch_method = ESP_TIMER_TASK, + .name = "mm_audio_idle_mute", + .skip_unhandled_events = true, + }; + esp_timer_handle_t timer = NULL; + esp_err_t err = esp_timer_create(&timer_args, &timer); + if (err != ESP_OK) { + return err; } - audio_set_downstream_idle_mute_task(ctx, task); + audio_set_downstream_idle_mute_timer(ctx, timer); + ESP_LOGI(TAG, + "Downstream idle mute timer ready (timeout=%ums)", + (unsigned)get_downstream_idle_mute_timeout_ms()); return ESP_OK; } static void notify_downstream_audio_active(multimodal_audio_ctx_t *ctx) { - TaskHandle_t task = audio_get_downstream_idle_mute_task(ctx); - if (ctx == NULL || task == NULL) { + esp_timer_handle_t timer = audio_get_downstream_idle_mute_timer(ctx); + if (ctx == NULL || timer == NULL) { return; } - (void)advance_downstream_audio_activity_generation(); - xTaskNotifyGive(task); + (void)esp_timer_stop(timer); + (void)esp_timer_start_once(timer, (uint64_t)get_downstream_idle_mute_timeout_ms() * 1000ULL); } static esp_err_t ensure_downstream_tx_bounce_buffer(multimodal_audio_ctx_t *ctx) @@ -1566,6 +1478,7 @@ static esp_err_t prime_downstream_output_path(multimodal_audio_ctx_t *ctx) static esp_err_t stop_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx, int timeout_ms) { + (void)timeout_ms; if (timeout_ms < 0) { return ESP_ERR_INVALID_ARG; } @@ -1574,34 +1487,22 @@ static esp_err_t stop_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx, int return ESP_OK; } - TaskHandle_t task = audio_get_downstream_idle_mute_task(ctx); - if (task == NULL) { - audio_set_downstream_idle_mute_stop_requested(ctx, false); + esp_timer_handle_t timer = audio_get_downstream_idle_mute_timer(ctx); + if (timer == NULL) { return ESP_OK; } - audio_set_downstream_idle_mute_stop_requested(ctx, true); - xTaskNotifyGive(task); - if (timeout_ms == 0) { - return ESP_OK; + esp_err_t stop_err = esp_timer_stop(timer); + if (stop_err != ESP_OK && stop_err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, "Downstream idle mute timer stop failed: %s", esp_err_to_name(stop_err)); } - - int effective_timeout_ms = timeout_ms; - int waited_ms = 0; - while (audio_get_downstream_idle_mute_task(ctx) != NULL && waited_ms < effective_timeout_ms) { - vTaskDelay(pdMS_TO_TICKS(20)); - waited_ms += 20; + esp_err_t delete_err = esp_timer_delete(timer); + if (delete_err != ESP_OK) { + ESP_LOGW(TAG, "Downstream idle mute timer delete failed: %s", esp_err_to_name(delete_err)); + return delete_err; } - esp_err_t result = ESP_OK; - task = audio_get_downstream_idle_mute_task(ctx); - if (task != NULL) { - ESP_LOGW(TAG, "Downstream idle mute task stop timeout, force delete"); - delete_audio_task_with_caps(task); - audio_set_downstream_idle_mute_task(ctx, NULL); - result = ESP_ERR_TIMEOUT; - } - audio_set_downstream_idle_mute_stop_requested(ctx, false); - return result; + audio_set_downstream_idle_mute_timer(ctx, NULL); + return ESP_OK; } static void downstream_playback_task(void *arg) diff --git a/components/platform/src/wifi_portal_bridge.cpp b/components/platform/src/wifi_portal_bridge.cpp index f930366..8c0cc89 100644 --- a/components/platform/src/wifi_portal_bridge.cpp +++ b/components/platform/src/wifi_portal_bridge.cpp @@ -173,16 +173,11 @@ static void seed_default_credentials(const char *ssid, const char *password) return; } - if (saved_count > 0U) { - ESP_LOGI(TAG, - "Configured Wi-Fi SSID \"%s\" overrides %u saved credential candidate(s)", - ssid, - (unsigned)saved_count); - manager.Clear(); - } - manager.AddSsid(ssid, password != NULL ? password : ""); - ESP_LOGI(TAG, "Configured Wi-Fi credentials for SSID \"%s\"", ssid); + ESP_LOGI(TAG, + "Ensured configured Wi-Fi credentials for SSID \"%s\" with %u previous candidate(s)", + ssid, + (unsigned)saved_count); } static int normalize_connect_timeout_ms(int timeout_ms) diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 7fbb00d..67e257f 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -77,8 +77,8 @@ CONFIG_MDNS_MEMORY_ALLOC_SPIRAM=y CONFIG_MULTIMODAL_DEVICE_ID="" CONFIG_MULTIMODAL_SERIAL_NUMBER="" -CONFIG_MULTIMODAL_WIFI_SSID="" -CONFIG_MULTIMODAL_WIFI_PASSWORD="" +CONFIG_MULTIMODAL_WIFI_SSID="csy2" +CONFIG_MULTIMODAL_WIFI_PASSWORD="csy19881023" CONFIG_ESPTOOLPY_MONITOR_BAUD=921600 CONFIG_ESP_CONSOLE_UART_BAUDRATE=921600 CONFIG_MULTIMODAL_DEVICE_TOKEN_URL="https://gz.api.talkingq.com/token/api/device/token"