From 984787d73613604034433de8303e3e12e989ef5e Mon Sep 17 00:00:00 2001 From: "CSBOOK\\44744" <447449914@qq.com> Date: Sun, 28 Jun 2026 18:14:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8D=95=E5=87=BBSW2?= =?UTF-8?q?=E6=8A=BD=E7=AD=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/runtime/control_plane_system_events.c | 14 ++ components/domain/include/domain.h | 2 + .../src/runtime/domain_runtime_adapters.c | 58 +++++++ components/platform/CMakeLists.txt | 18 +++ components/platform/include/platform.h | 10 ++ components/platform/src/lcd_direct.c | 57 +++++++ components/platform/src/lcd_direct_assets.c | 150 +++++++++++++++++- 7 files changed, 301 insertions(+), 8 deletions(-) diff --git a/components/control_plane/src/runtime/control_plane_system_events.c b/components/control_plane/src/runtime/control_plane_system_events.c index adc14f0..8aceed4 100644 --- a/components/control_plane/src/runtime/control_plane_system_events.c +++ b/components/control_plane/src/runtime/control_plane_system_events.c @@ -123,6 +123,20 @@ static void control_plane_dispatch_key_event(const control_plane_key_event_t *ev event->press_duration_ms, event->click_count); + if (event->key_id == CONTROL_PLANE_KEY_ID_SW2) { + if (event->type == CONTROL_PLANE_KEY_EVENT_SHORT_PRESS) { + const domain_expression_request_t request = { + .id = DOMAIN_EXPRESSION_CHOUQIAN, + .trigger = DOMAIN_EXPRESSION_TRIGGER_SW2_SINGLE_CLICK, + }; + esp_err_t expr_err = domain_runtime_request_expression(&request); + if (expr_err != ESP_OK && expr_err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, "SW2 single-click chouqian expression failed: %s", esp_err_to_name(expr_err)); + } + } + return; + } + if (event->key_id != CONTROL_PLANE_KEY_ID_PTT) { return; } diff --git a/components/domain/include/domain.h b/components/domain/include/domain.h index 80d3eaf..b640385 100644 --- a/components/domain/include/domain.h +++ b/components/domain/include/domain.h @@ -88,6 +88,7 @@ typedef enum { DOMAIN_EXPRESSION_WEALTH_SPIN, DOMAIN_EXPRESSION_WEALTH_DIRECTION, DOMAIN_EXPRESSION_MUYU, + DOMAIN_EXPRESSION_CHOUQIAN, } domain_expression_id_t; typedef enum { @@ -100,6 +101,7 @@ typedef enum { DOMAIN_EXPRESSION_TRIGGER_MODEL_DIRECTION, DOMAIN_EXPRESSION_TRIGGER_DAILY_FORTUNE, DOMAIN_EXPRESSION_TRIGGER_PTT_DOUBLE_CLICK, + DOMAIN_EXPRESSION_TRIGGER_SW2_SINGLE_CLICK, } 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 c1a9923..32ffdea 100644 --- a/components/domain/src/runtime/domain_runtime_adapters.c +++ b/components/domain/src/runtime/domain_runtime_adapters.c @@ -12,6 +12,7 @@ #include "domain_internal.h" #include "platform.h" +#include "esp_random.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" @@ -77,6 +78,13 @@ static const uint8_t s_server_error_frame_order[] = {0, 1, 2, 1, 0}; static const uint8_t s_wifi_disconnected_frame_order[] = {0, 1, 2, 3, 2, 1, 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 char *const s_chouqian_result_asset_dirs[] = { + "chouqian_buyun", + "chouqian_heping", + "chouqian_shangshang", + "chouqian_xiaoji", + "chouqian_zhongshang", +}; /* * Wealth-direction reveal asset directories, indexed parallel to the direction @@ -95,6 +103,7 @@ static const char *const s_wealth_direction_asset_dirs[] = { }; #define DOMAIN_WEALTH_DIRECTION_FRAME_MS 100U +#define DOMAIN_CHOUQIAN_FRAME_MS 500U #define DOMAIN_AUTH_KEY_STORE_NAMESPACE "auth_key" #define DOMAIN_AUTH_STATE_STORE_NAMESPACE "auth" @@ -1244,6 +1253,55 @@ static esp_err_t domain_resolve_expression_platform_request( return ESP_OK; } + if (request->id == DOMAIN_EXPRESSION_CHOUQIAN) { + static platform_lcd_presentation_step_t s_chouqian_steps[6]; + const size_t result_count = sizeof(s_chouqian_result_asset_dirs) / + sizeof(s_chouqian_result_asset_dirs[0]); + const char *result_asset = s_chouqian_result_asset_dirs[esp_random() % result_count]; + + s_chouqian_steps[0] = (platform_lcd_presentation_step_t) { + .asset_dir = "chouqian_qianzhi", + .frame_index = 0, + .delay_ms = DOMAIN_CHOUQIAN_FRAME_MS, + }; + s_chouqian_steps[1] = (platform_lcd_presentation_step_t) { + .asset_dir = "chouqian_qianzhi", + .frame_index = 1, + .delay_ms = DOMAIN_CHOUQIAN_FRAME_MS, + }; + s_chouqian_steps[2] = (platform_lcd_presentation_step_t) { + .asset_dir = "chouqian_qianzhi", + .frame_index = 2, + .delay_ms = DOMAIN_CHOUQIAN_FRAME_MS, + }; + s_chouqian_steps[3] = (platform_lcd_presentation_step_t) { + .asset_dir = result_asset, + .frame_index = 0, + .delay_ms = DOMAIN_CHOUQIAN_FRAME_MS, + }; + s_chouqian_steps[4] = (platform_lcd_presentation_step_t) { + .asset_dir = result_asset, + .frame_index = 1, + .delay_ms = DOMAIN_CHOUQIAN_FRAME_MS, + }; + s_chouqian_steps[5] = (platform_lcd_presentation_step_t) { + .asset_dir = result_asset, + .frame_index = 2, + .delay_ms = DOMAIN_CHOUQIAN_FRAME_MS, + }; + + *out_platform_request = (platform_lcd_presentation_request_t) { + .kind = PLATFORM_LCD_PRESENTATION_STEP_SEQUENCE, + .priority = 125, + .interrupt_current = true, + .return_to_idle = true, + .steps = s_chouqian_steps, + .step_count = sizeof(s_chouqian_steps) / sizeof(s_chouqian_steps[0]), + }; + ESP_LOGI(TAG, "Chouqian result asset=%s", result_asset); + return ESP_OK; + } + const domain_expression_catalog_entry_t *entry = domain_find_expression_entry(request->id); if (entry == NULL) { ESP_LOGW(TAG, "Unknown expression request id=%d trigger=%d", diff --git a/components/platform/CMakeLists.txt b/components/platform/CMakeLists.txt index bc87d31..b509946 100644 --- a/components/platform/CMakeLists.txt +++ b/components/platform/CMakeLists.txt @@ -73,6 +73,24 @@ set(platform_lcd_flash_assets muyu0 muyu1 muyu2 + chouqian_qianzhi0 + chouqian_qianzhi1 + chouqian_qianzhi2 + chouqian_buyun0 + chouqian_buyun1 + chouqian_buyun2 + chouqian_heping0 + chouqian_heping1 + chouqian_heping2 + chouqian_shangshang0 + chouqian_shangshang1 + chouqian_shangshang2 + chouqian_xiaoji0 + chouqian_xiaoji1 + chouqian_xiaoji2 + chouqian_zhongshang0 + chouqian_zhongshang1 + chouqian_zhongshang2 ) set(platform_lcd_flash_asset_files) foreach(lcd_rle_asset IN LISTS platform_lcd_flash_assets) diff --git a/components/platform/include/platform.h b/components/platform/include/platform.h index 06175b8..0b57cb9 100644 --- a/components/platform/include/platform.h +++ b/components/platform/include/platform.h @@ -350,13 +350,21 @@ esp_err_t platform_stop_lcd_render_loop(int timeout_ms); #define PLATFORM_LCD_PRESENTATION_FRAME_ORDER_MAX 16 #define PLATFORM_LCD_PRESENTATION_ASSET_DIR_MAX 32 +#define PLATFORM_LCD_PRESENTATION_STEP_MAX 12 typedef enum { PLATFORM_LCD_PRESENTATION_IDLE = 0, PLATFORM_LCD_PRESENTATION_ASSET_SEQUENCE, PLATFORM_LCD_PRESENTATION_SLOT_REELS, + PLATFORM_LCD_PRESENTATION_STEP_SEQUENCE, } platform_lcd_presentation_kind_t; +typedef struct { + const char *asset_dir; + uint8_t frame_index; + uint32_t delay_ms; +} platform_lcd_presentation_step_t; + typedef struct { platform_lcd_presentation_kind_t kind; uint8_t priority; @@ -368,6 +376,8 @@ typedef struct { uint16_t repeat_count; uint32_t frame_ms; uint32_t duration_ms; + const platform_lcd_presentation_step_t *steps; + size_t step_count; } platform_lcd_presentation_request_t; /** diff --git a/components/platform/src/lcd_direct.c b/components/platform/src/lcd_direct.c index 0efc316..f921ff0 100644 --- a/components/platform/src/lcd_direct.c +++ b/components/platform/src/lcd_direct.c @@ -50,6 +50,8 @@ typedef struct { uint16_t repeat_count; uint32_t frame_ms; uint32_t duration_ms; + platform_lcd_presentation_step_t steps[PLATFORM_LCD_PRESENTATION_STEP_MAX]; + size_t step_count; } lcd_direct_request_t; typedef struct { @@ -644,6 +646,43 @@ static esp_err_t lcd_direct_play_asset_sequence(const lcd_direct_request_t *requ return ESP_OK; } +static esp_err_t lcd_direct_play_step_sequence(const lcd_direct_request_t *request) +{ + ESP_RETURN_ON_FALSE(request != NULL, + ESP_ERR_INVALID_ARG, + TAG, + "invalid step sequence"); + + for (size_t i = 0; i < request->step_count; ++i) { + bool stop = false; + portENTER_CRITICAL(&s_state_lock); + stop = s_stop_requested || s_pending_valid; + portEXIT_CRITICAL(&s_state_lock); + if (stop) { + return ESP_ERR_INVALID_STATE; + } + + const platform_lcd_presentation_step_t *step = &request->steps[i]; + const lcd_direct_image_t *frame = lcd_direct_asset_frame(step->asset_dir, step->frame_index); + ESP_RETURN_ON_FALSE(frame != NULL, + ESP_ERR_NOT_FOUND, + TAG, + "LCD step frame not found asset=%s frame=%u", + step->asset_dir != NULL ? step->asset_dir : "", + (unsigned)step->frame_index); + + ESP_RETURN_ON_ERROR(lcd_direct_draw_rle_image(frame, NULL, 0), + TAG, + "draw step frame failed"); + + uint32_t delay_ms = step->delay_ms > 0U ? step->delay_ms : 100U; + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + } + + lcd_direct_signal_completion(); + return ESP_OK; +} + static esp_err_t lcd_direct_play_basic_face_until_pending(void) { const lcd_direct_request_t request = { @@ -768,6 +807,17 @@ void lcd_direct_start_render_loop(void) s_pending_valid = true; portEXIT_CRITICAL(&s_state_lock); } + } else if (request.kind == PLATFORM_LCD_PRESENTATION_STEP_SEQUENCE) { + draw_err = lcd_direct_play_step_sequence(&request); + if (draw_err == ESP_OK && request.return_to_idle) { + lcd_direct_request_t idle = { + .kind = PLATFORM_LCD_PRESENTATION_IDLE, + }; + portENTER_CRITICAL(&s_state_lock); + s_pending = idle; + s_pending_valid = true; + portEXIT_CRITICAL(&s_state_lock); + } } else { draw_err = lcd_direct_draw_test_pattern(&request); } @@ -872,6 +922,13 @@ esp_err_t lcd_direct_request_presentation(const platform_lcd_presentation_reques } memcpy(copied.frame_order, request->frame_order, copied.frame_order_count); } + if (request->steps != NULL && request->step_count > 0U) { + copied.step_count = request->step_count; + if (copied.step_count > PLATFORM_LCD_PRESENTATION_STEP_MAX) { + copied.step_count = PLATFORM_LCD_PRESENTATION_STEP_MAX; + } + memcpy(copied.steps, request->steps, copied.step_count * sizeof(copied.steps[0])); + } TaskHandle_t task = NULL; portENTER_CRITICAL(&s_state_lock); diff --git a/components/platform/src/lcd_direct_assets.c b/components/platform/src/lcd_direct_assets.c index 7ac242c..dc841de 100644 --- a/components/platform/src/lcd_direct_assets.c +++ b/components/platform/src/lcd_direct_assets.c @@ -39,6 +39,106 @@ static const lcd_direct_image_t s_muyu_frames[] = { }, }; +static const lcd_direct_image_t s_chouqian_qianzhi_frames[] = { + { + .path = LCD_ASSET_BASE_PATH "chouqian_qianzhi0.rle", + .run_count = 74056U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_qianzhi1.rle", + .run_count = 73259U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_qianzhi2.rle", + .run_count = 72906U, + }, +}; + +static const lcd_direct_image_t s_chouqian_buyun_frames[] = { + { + .path = LCD_ASSET_BASE_PATH "chouqian_buyun0.rle", + .run_count = 72370U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_buyun1.rle", + .run_count = 72552U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_buyun2.rle", + .run_count = 72757U, + }, +}; + +static const lcd_direct_image_t s_chouqian_heping_frames[] = { + { + .path = LCD_ASSET_BASE_PATH "chouqian_heping0.rle", + .run_count = 72370U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_heping1.rle", + .run_count = 73049U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_heping2.rle", + .run_count = 73365U, + }, +}; + +static const lcd_direct_image_t s_chouqian_shangshang_frames[] = { + { + .path = LCD_ASSET_BASE_PATH "chouqian_shangshang0.rle", + .run_count = 72370U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_shangshang1.rle", + .run_count = 72944U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_shangshang2.rle", + .run_count = 73190U, + }, +}; + +static const lcd_direct_image_t s_chouqian_xiaoji_frames[] = { + { + .path = LCD_ASSET_BASE_PATH "chouqian_xiaoji0.rle", + .run_count = 72370U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_xiaoji1.rle", + .run_count = 72827U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_xiaoji2.rle", + .run_count = 73006U, + }, +}; + +static const lcd_direct_image_t s_chouqian_zhongshang_frames[] = { + { + .path = LCD_ASSET_BASE_PATH "chouqian_zhongshang0.rle", + .run_count = 72370U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_zhongshang1.rle", + .run_count = 72135U, + }, + { + .path = LCD_ASSET_BASE_PATH "chouqian_zhongshang2.rle", + .run_count = 72292U, + }, +}; + +static const lcd_direct_image_t *lcd_direct_frame_from_array(const lcd_direct_image_t *frames, + size_t frame_count, + uint8_t frame_index) +{ + if (frame_index >= frame_count) { + return NULL; + } + return &frames[frame_index]; +} + const lcd_direct_image_t *lcd_direct_default_image(void) { return &s_default_image; @@ -51,17 +151,51 @@ const lcd_direct_image_t *lcd_direct_asset_frame(const char *asset_dir, uint8_t } if (strcmp(asset_dir, "jichubiaoqing") == 0) { - if (frame_index < sizeof(s_basic_face_frames) / sizeof(s_basic_face_frames[0])) { - return &s_basic_face_frames[frame_index]; - } - return NULL; + return lcd_direct_frame_from_array(s_basic_face_frames, + sizeof(s_basic_face_frames) / sizeof(s_basic_face_frames[0]), + frame_index); } if (strcmp(asset_dir, "muyu") == 0) { - if (frame_index < sizeof(s_muyu_frames) / sizeof(s_muyu_frames[0])) { - return &s_muyu_frames[frame_index]; - } - return NULL; + return lcd_direct_frame_from_array(s_muyu_frames, + sizeof(s_muyu_frames) / sizeof(s_muyu_frames[0]), + frame_index); + } + + if (strcmp(asset_dir, "chouqian_qianzhi") == 0) { + return lcd_direct_frame_from_array(s_chouqian_qianzhi_frames, + sizeof(s_chouqian_qianzhi_frames) / sizeof(s_chouqian_qianzhi_frames[0]), + frame_index); + } + + if (strcmp(asset_dir, "chouqian_buyun") == 0) { + return lcd_direct_frame_from_array(s_chouqian_buyun_frames, + sizeof(s_chouqian_buyun_frames) / sizeof(s_chouqian_buyun_frames[0]), + frame_index); + } + + if (strcmp(asset_dir, "chouqian_heping") == 0) { + return lcd_direct_frame_from_array(s_chouqian_heping_frames, + sizeof(s_chouqian_heping_frames) / sizeof(s_chouqian_heping_frames[0]), + frame_index); + } + + if (strcmp(asset_dir, "chouqian_shangshang") == 0) { + return lcd_direct_frame_from_array(s_chouqian_shangshang_frames, + sizeof(s_chouqian_shangshang_frames) / sizeof(s_chouqian_shangshang_frames[0]), + frame_index); + } + + if (strcmp(asset_dir, "chouqian_xiaoji") == 0) { + return lcd_direct_frame_from_array(s_chouqian_xiaoji_frames, + sizeof(s_chouqian_xiaoji_frames) / sizeof(s_chouqian_xiaoji_frames[0]), + frame_index); + } + + if (strcmp(asset_dir, "chouqian_zhongshang") == 0) { + return lcd_direct_frame_from_array(s_chouqian_zhongshang_frames, + sizeof(s_chouqian_zhongshang_frames) / sizeof(s_chouqian_zhongshang_frames[0]), + frame_index); } return NULL;