diff --git a/components/control_plane/src/runtime/control_plane_ota.c b/components/control_plane/src/runtime/control_plane_ota.c index 5e5c9e6..a5df4bc 100644 --- a/components/control_plane/src/runtime/control_plane_ota.c +++ b/components/control_plane/src/runtime/control_plane_ota.c @@ -235,6 +235,42 @@ static void control_plane_ota_progress(uint64_t received, } } +static void control_plane_ota_show_update_expression(void) +{ + const domain_expression_request_t request = { + .id = DOMAIN_EXPRESSION_OTA_UPDATE, + .trigger = DOMAIN_EXPRESSION_TRIGGER_OTA_UPDATE, + }; + + esp_err_t preheat_err = domain_runtime_preheat_expression(&request); + if (preheat_err != ESP_OK && preheat_err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, + "OTA expression preheat failed: %s", + esp_err_to_name(preheat_err)); + } + + esp_err_t request_err = domain_runtime_request_expression(&request); + if (request_err != ESP_OK && request_err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, + "OTA expression request failed: %s", + esp_err_to_name(request_err)); + } +} + +static void control_plane_ota_restore_idle_expression(void) +{ + const domain_expression_request_t request = { + .id = DOMAIN_EXPRESSION_IDLE, + .trigger = DOMAIN_EXPRESSION_TRIGGER_OTA_UPDATE, + }; + esp_err_t err = domain_runtime_request_expression(&request); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, + "Restore idle expression after OTA failed: %s", + esp_err_to_name(err)); + } +} + static void control_plane_ota_log_stack_headroom(const char *phase) { UBaseType_t high_water_bytes = uxTaskGetStackHighWaterMark(NULL) * sizeof(StackType_t); @@ -700,6 +736,7 @@ static void control_plane_ota_worker(void *arg) control_plane_ota_set_state(CONTROL_PLANE_OTA_STATE_DOWNLOADING, ESP_OK, response->http_status); + control_plane_ota_show_update_expression(); domain_runtime_behavior_set_keep_awake(true); err = domain_runtime_ota_install(&response->firmware, CONFIG_TQ_OTA_INSTALL_TIMEOUT_MS, @@ -710,6 +747,7 @@ static void control_plane_ota_worker(void *arg) domain_runtime_behavior_set_keep_awake(false); if (err != ESP_OK) { initial_check_pending = false; + control_plane_ota_restore_idle_expression(); control_plane_ota_release_voice_window(&voice_window); control_plane_ota_note_failure(err, response->http_status); ESP_LOGE(TAG, "OTA install failed: %s", esp_err_to_name(err)); diff --git a/components/domain/include/domain.h b/components/domain/include/domain.h index aa17fd7..e7dbbf3 100644 --- a/components/domain/include/domain.h +++ b/components/domain/include/domain.h @@ -163,6 +163,7 @@ typedef enum { DOMAIN_EXPRESSION_CHOUQIAN, DOMAIN_EXPRESSION_WUXING, DOMAIN_EXPRESSION_LISTENING, + DOMAIN_EXPRESSION_OTA_UPDATE, } domain_expression_id_t; typedef enum { @@ -179,6 +180,7 @@ typedef enum { DOMAIN_EXPRESSION_TRIGGER_SW2_SINGLE_CLICK, DOMAIN_EXPRESSION_TRIGGER_SW2_DOUBLE_CLICK, DOMAIN_EXPRESSION_TRIGGER_LOCAL_WAKE, + DOMAIN_EXPRESSION_TRIGGER_OTA_UPDATE, } domain_expression_trigger_t; typedef struct { diff --git a/components/domain/src/runtime/domain_runtime_adapters.c b/components/domain/src/runtime/domain_runtime_adapters.c index d687c06..b2d7af8 100644 --- a/components/domain/src/runtime/domain_runtime_adapters.c +++ b/components/domain/src/runtime/domain_runtime_adapters.c @@ -80,6 +80,7 @@ static const uint8_t s_wifi_connecting_frame_order[] = {0}; static const uint8_t s_basic_face_frame_order[] = {0, 1, 2}; static const uint8_t s_muyu_frame_order[] = {0, 1, 2, 1}; static const uint8_t s_listening_frame_order[] = {0, 1, 2}; +static const uint8_t s_ota_update_frame_order[] = {0, 1, 2}; static const char *const s_chouqian_result_asset_dirs[] = { "chouqian_buyun", "chouqian_heping", @@ -259,6 +260,21 @@ static const domain_expression_catalog_entry_t s_expression_catalog[] = { .frame_ms = 500, }, }, + { + .id = DOMAIN_EXPRESSION_OTA_UPDATE, + .platform_request = { + .kind = PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE, + .priority = 200, + .interrupt_current = true, + .return_to_idle = false, + .asset_dir = "ota", + .frame_order = s_ota_update_frame_order, + .frame_order_count = sizeof(s_ota_update_frame_order) / + sizeof(s_ota_update_frame_order[0]), + .repeat_count = 0, + .frame_ms = 200, + }, + }, }; static void snapshot_domain_wifi_behavior_hooks(domain_wifi_behavior_hooks_t *out_hooks) diff --git a/components/platform/CMakeLists.txt b/components/platform/CMakeLists.txt index da7a067..e52e033 100644 --- a/components/platform/CMakeLists.txt +++ b/components/platform/CMakeLists.txt @@ -96,6 +96,9 @@ set(platform_lcd_png_assets listening0 listening1 listening2 + ota1 + ota2 + ota3 muyu0 muyu1 muyu2 diff --git a/components/platform/assets/lcd/OTA.gif b/components/platform/assets/lcd/OTA.gif new file mode 100644 index 0000000..ec77094 Binary files /dev/null and b/components/platform/assets/lcd/OTA.gif differ diff --git a/components/platform/assets/lcd/ota1.png b/components/platform/assets/lcd/ota1.png new file mode 100644 index 0000000..5d2b457 Binary files /dev/null and b/components/platform/assets/lcd/ota1.png differ diff --git a/components/platform/assets/lcd/ota2.png b/components/platform/assets/lcd/ota2.png new file mode 100644 index 0000000..2403bae Binary files /dev/null and b/components/platform/assets/lcd/ota2.png differ diff --git a/components/platform/assets/lcd/ota3.png b/components/platform/assets/lcd/ota3.png new file mode 100644 index 0000000..dbba09a Binary files /dev/null and b/components/platform/assets/lcd/ota3.png differ diff --git a/components/platform/src/lcd_direct_assets.c b/components/platform/src/lcd_direct_assets.c index fc11247..e61be78 100644 --- a/components/platform/src/lcd_direct_assets.c +++ b/components/platform/src/lcd_direct_assets.c @@ -26,6 +26,12 @@ static const lcd_direct_image_t s_listening_frames[] = { {.path = LCD_ASSET_BASE_PATH "listening2.png"}, }; +static const lcd_direct_image_t s_ota_frames[] = { + {.path = LCD_ASSET_BASE_PATH "ota1.png"}, + {.path = LCD_ASSET_BASE_PATH "ota2.png"}, + {.path = LCD_ASSET_BASE_PATH "ota3.png"}, +}; + static const lcd_direct_image_t s_wifi_connecting_qr_frames[] = { {.path = LCD_ASSET_BASE_PATH "qrcode.png"}, }; @@ -258,6 +264,12 @@ const lcd_direct_image_t *lcd_direct_asset_frame(const char *asset_dir, uint8_t frame_index); } + if (strcmp(asset_dir, "ota") == 0) { + return lcd_direct_frame_from_array(s_ota_frames, + sizeof(s_ota_frames) / sizeof(s_ota_frames[0]), + frame_index); + } + if (strcmp(asset_dir, "wifi_connecting_qr") == 0) { return lcd_direct_frame_from_array( s_wifi_connecting_qr_frames, diff --git a/docs/lcd-expressions.md b/docs/lcd-expressions.md index 4776888..021063f 100644 --- a/docs/lcd-expressions.md +++ b/docs/lcd-expressions.md @@ -48,6 +48,7 @@ and legacy animation assets have been removed from the build. | `DOMAIN_EXPRESSION_WIFI_DISCONNECTED` | Wi-Fi state monitor worker | `PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE` | Draws a direct backend pattern selected from the mapped asset name. | | `DOMAIN_EXPRESSION_WEALTH_SPIN` | Model-command direction worker | `PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE` | Draws a direct backend pattern selected from `spin`. | | `DOMAIN_EXPRESSION_WEALTH_DIRECTION` | Model-command direction worker | `PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE` | Draws a direct backend pattern selected from the mapped direction asset name. | +| `DOMAIN_EXPRESSION_OTA_UPDATE` | OTA update worker | `PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE` | Loops the three-frame `ota` sequence during firmware download and installation. | Server error currently triggers only from: