From 7486b633467a775019c8fb7c6860f3cc0d2473d5 Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Tue, 13 Jan 2026 18:15:56 +0800 Subject: [PATCH] update firmware source code v0.13 --- firmware/CMakeLists.txt | 2 +- firmware/dependencies.lock | 100 +- firmware/main/CMakeLists.txt | 53 +- firmware/main/Kconfig.projbuild | 75 +- .../main/apps/app_ai_agent/app_ai_agent.cpp | 6 +- firmware/main/apps/app_avatar/app_avatar.cpp | 103 +- firmware/main/apps/app_avatar/app_avatar.h | 11 - .../apps/app_espnow_ctrl/app_espnow_ctrl.cpp | 10 + .../apps/app_espnow_ctrl/view/page_selector.h | 5 + .../main/apps/app_launcher/app_launcher.cpp | 36 +- .../main/apps/app_launcher/app_launcher.h | 6 +- firmware/main/apps/app_launcher/view/view.cpp | 35 +- firmware/main/apps/app_setup/app_setup.cpp | 52 +- firmware/main/apps/app_setup/app_setup.h | 5 +- firmware/main/apps/app_setup/view/view.cpp | 6 +- .../main/apps/app_setup/workers/about.cpp | 200 + .../apps/app_setup/workers/connectivity.cpp | 95 +- .../main/apps/app_setup/workers/display.cpp | 80 + .../main/apps/app_setup/workers/servo.cpp | 42 +- .../main/apps/app_setup/workers/startup.cpp | 136 + .../main/apps/app_setup/workers/workers.h | 119 +- .../main/apps/app_template/app_template.cpp | 34 +- .../main/apps/app_template/app_template.h | 4 +- firmware/main/apps/common/common.h | 4 +- .../common/home_indicator/home_indicator.cpp | 280 ++ .../common/home_indicator/home_indicator.h | 17 + firmware/main/apps/common/toast/toast.cpp | 229 ++ firmware/main/apps/common/toast/toast.h | 93 + firmware/main/assets/assets.h | 2 + firmware/main/assets/images/icon_home.c | 196 + .../images/setup_stackchan_front_view.c | 3311 +++++++++++++++++ firmware/main/hal/board/hal_bridge.cc | 11 +- firmware/main/hal/board/hal_bridge.h | 5 +- firmware/main/hal/board/stackchan.cc | 78 +- firmware/main/hal/board/stackchan_camera.cc | 191 +- firmware/main/hal/board/stackchan_display.cc | 34 +- firmware/main/hal/board/stackchan_display.h | 1 + firmware/main/hal/hal.cpp | 99 +- firmware/main/hal/hal.h | 67 +- firmware/main/hal/hal_ble.cpp | 88 +- firmware/main/hal/hal_espnow.cpp | 4 +- firmware/main/hal/hal_head_touch.cpp | 10 +- firmware/main/hal/hal_imu.cpp | 2 +- firmware/main/hal/hal_io_expander.cpp | 2 +- firmware/main/hal/hal_mcp.cpp | 91 +- firmware/main/hal/hal_servo.cpp | 2 +- firmware/main/hal/hal_ws_avatar.cpp | 120 +- .../simple_audio_player.cpp | 45 +- .../hal/utils/wifi_connect/wifi_station.cc | 8 +- .../hal/utils/wifi_connect/wifi_station.h | 13 +- firmware/main/idf_component.yml | 19 +- firmware/main/main.cpp | 13 + .../avatar/avatar/elements/element.h | 2 +- .../stackchan/avatar/decorators/angry.cpp | 61 +- .../stackchan/avatar/decorators/decorators.h | 60 +- .../stackchan/avatar/decorators/heart.cpp | 61 +- .../stackchan/avatar/decorators/sweat.cpp | 77 +- firmware/main/stackchan/modifiers/blink.h | 95 +- firmware/main/stackchan/modifiers/breath.h | 131 +- firmware/main/stackchan/modifiers/head_pet.h | 158 +- .../stackchan/modifiers/idle_expression.h | 91 + .../main/stackchan/modifiers/idle_motion.h | 132 +- firmware/main/stackchan/modifiers/imu.h | 132 +- firmware/main/stackchan/modifiers/modifiers.h | 1 + firmware/main/stackchan/modifiers/speaking.h | 160 +- firmware/main/stackchan/modifiers/timed.h | 62 +- firmware/main/stackchan/motion/servo.cpp | 11 +- firmware/main/stackchan/motion/servo.h | 11 +- firmware/main/stackchan/utils/timer.h | 165 - firmware/repos.json | 2 +- firmware/sdkconfig.defaults | 2 + 71 files changed, 6552 insertions(+), 1112 deletions(-) create mode 100644 firmware/main/apps/app_setup/workers/about.cpp create mode 100644 firmware/main/apps/app_setup/workers/display.cpp create mode 100644 firmware/main/apps/app_setup/workers/startup.cpp create mode 100644 firmware/main/apps/common/home_indicator/home_indicator.cpp create mode 100644 firmware/main/apps/common/home_indicator/home_indicator.h create mode 100644 firmware/main/apps/common/toast/toast.cpp create mode 100644 firmware/main/apps/common/toast/toast.h create mode 100644 firmware/main/assets/images/icon_home.c create mode 100644 firmware/main/assets/images/setup_stackchan_front_view.c create mode 100644 firmware/main/stackchan/modifiers/idle_expression.h delete mode 100644 firmware/main/stackchan/utils/timer.h diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index b9e0ac2..702cd2c 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -2,7 +2,7 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(PROJECT_VER "2.0.4") +set(PROJECT_VER "2.1.0") # Add this line to disable the specific warning add_compile_options(-Wno-missing-field-initializers) diff --git a/firmware/dependencies.lock b/firmware/dependencies.lock index 2b502ab..0acf4c4 100644 --- a/firmware/dependencies.lock +++ b/firmware/dependencies.lock @@ -1,6 +1,6 @@ dependencies: 78/esp-ml307: - component_hash: 57c8cc3309fb3da9195ec861cba3726b5cf24c362def803e7174c0b1d72e60e3 + component_hash: d4de9738baaaa5e6655c686a6083e699f3605de54dc83233ff3328cf55a4f543 dependencies: - name: idf require: private @@ -8,7 +8,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 3.3.7 + version: 3.5.3 78/esp-opus: component_hash: 8182b733f071d7bfe1e837f4c9f8649a63e4c937177f089e65772880c02f2e17 dependencies: @@ -34,7 +34,7 @@ dependencies: type: service version: 2.4.1 78/esp-wifi-connect: - component_hash: 2613d9970df9f2203c2c549991e3bad74847b0a7facffe6698f4341e0bf73589 + component_hash: bf996fc603af1ff529668c788c7b38a8d94b1d43455af56d116d27ebb04b742a dependencies: - name: idf require: private @@ -42,7 +42,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 2.6.1 + version: 3.0.2 78/esp_lcd_nv3023: component_hash: fa88abfc19a312eb5e6f2ffa187e0a9faf67e01e758bfb979d3f9d92561a494f dependencies: @@ -58,7 +58,7 @@ dependencies: type: service version: 1.0.0 78/xiaozhi-fonts: - component_hash: 51f67bcf9dec623de90d9deb72de50dfbc3634fb948b7abf27df65b386258b94 + component_hash: e5526ea3c290742963ef6ab64023669260b72aefdc37bb218c34c618962ef2a8 dependencies: - name: idf require: private @@ -66,7 +66,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 1.5.4 + version: 1.5.5 espressif/adc_battery_estimation: component_hash: b915167c87ed5a84b13d680bd011c2ed9a15121f1e247c6903141b9f138f3606 dependencies: @@ -99,8 +99,26 @@ dependencies: registry_url: https://components.espressif.com/ type: service version: 0.2.1 + espressif/bmi270_sensor: + component_hash: fac23a5ecd2effdac0fb0705988d853745b8ffb99a384f87a307b3b25d15d432 + dependencies: + - name: espressif/cmake_utilities + registry_url: https://components.espressif.com + require: private + version: 0.* + - name: espressif/i2c_bus + registry_url: https://components.espressif.com + require: public + version: '*' + - name: idf + require: private + version: '>=5.3' + source: + registry_url: https://components.espressif.com/ + type: service + version: 0.1.1 espressif/button: - component_hash: 4ed25fcf354b48aa5e5680b9e7549e38d7738f9b613c94a2e39119c100db9c95 + component_hash: fccb18c37f1cfe0797b74a53a44d3f400f5fd01f4993b40052dfb7f401915089 dependencies: - name: espressif/cmake_utilities registry_url: https://components.espressif.com @@ -112,7 +130,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 4.1.4 + version: 4.1.5 espressif/cmake_utilities: component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f dependencies: @@ -365,19 +383,19 @@ dependencies: type: service version: 1.2.1 espressif/esp_lcd_touch_cst816s: - component_hash: 51dfa9cee38d8a20f4b625d7f89120dff08c8557e613e09dfb31f53d48648235 + component_hash: 6b11c489952c121396d4eaf5804b45e3f1f8dcd2c548dc6f2cbedf68622b013d dependencies: - name: espressif/esp_lcd_touch registry_url: https://components.espressif.com require: public - version: ^1.0.4 + version: ^1.2.0 - name: idf require: private version: '>=4.4.2' source: registry_url: https://components.espressif.com/ type: service - version: 1.1.0 + version: 1.1.1 espressif/esp_lcd_touch_ft5x06: component_hash: abaec05f46a793549b60afdda9eff86e3c8e87782c8c169007911232388d2858 dependencies: @@ -393,39 +411,36 @@ dependencies: type: service version: 1.0.7 espressif/esp_lcd_touch_gt1151: - component_hash: 69dd86cd5fad2442e3bf15c8c4ddddbe9e8739bdb26cd5f2c5249601b4c3cc38 + component_hash: acd0fb87e8b58dc90cebda8438ee31c068975c15c040a62723843ca0420d38b6 dependencies: - - name: idf - require: private - version: '>=4.4.2' - name: espressif/esp_lcd_touch registry_url: https://components.espressif.com require: public - version: ^1.0.4 + version: ^1.2.0 + - name: idf + require: private + version: '>=4.4.2' source: registry_url: https://components.espressif.com/ type: service - version: 1.0.5~2 + version: 1.1.0 espressif/esp_lcd_touch_gt911: - component_hash: acc1c184358aa29ef72506f618c9c76a8cc2bf12af38a2bff3d44d84f3a08857 + component_hash: be02e243d18b9a661bc13b0d22c0a5cfa3f708cf04d6eb059772276c8c8a4d76 dependencies: - name: espressif/esp_lcd_touch registry_url: https://components.espressif.com require: public - version: ^1.1.0 + version: ^1.2.0 - name: idf require: private version: '>=4.4.2' source: registry_url: https://components.espressif.com/ type: service - version: 1.1.3 + version: 1.2.0~1 espressif/esp_lcd_touch_st7123: - component_hash: 3592f0dac4b3baf34c40679922026c1e22e9b925b9446e981cd1c23306ecfe65 + component_hash: 717080a55368a5ca3e3704081a75ddab3e0b8884e335e73b7094beb8ae55f195 dependencies: - - name: idf - require: private - version: '>=4.4.2' - name: espressif/cmake_utilities registry_url: https://components.espressif.com require: private @@ -434,12 +449,15 @@ dependencies: registry_url: https://components.espressif.com require: public version: ^1 + - name: idf + require: private + version: '>=4.4.2' source: registry_url: https://components.espressif.com/ type: service - version: 1.0.0 + version: 1.0.1 espressif/esp_lvgl_port: - component_hash: bfb2778c063b05a6c47c1a8de6d166ee4d911bc86fe0b3ff9e6bab06d2812033 + component_hash: 3264cc85d86a7c32b67d26a1353a57c67e7986bb293ebb1731801936b056e632 dependencies: - name: idf require: private @@ -451,7 +469,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 2.6.2 + version: 2.6.3 espressif/esp_mmap_assets: component_hash: 91d785326b03db15e2f7f1314d8c976d38f21aa5759b570dcbbc89bcf247fd27 dependencies: @@ -563,11 +581,11 @@ dependencies: require: private version: '>=4.0' source: - registry_url: https://components.espressif.com/ + registry_url: https://components.espressif.com type: service version: 1.5.0 espressif/knob: - component_hash: 23bb6b0f62d4a2bbfe8b65e182397541339b8e48d54cef15909f5d4f5bd43d29 + component_hash: 138ed090b4c9090a0a678f695b9d1884b368130c729b7333ed35bd7f4e8da80e dependencies: - name: espressif/cmake_utilities registry_url: https://components.espressif.com @@ -579,9 +597,9 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 1.0.1 + version: 1.0.2 espressif/led_strip: - component_hash: 223998f10cae6d81f2ad2dd3c1103c2221be298c708e37917482b0153f3ec64e + component_hash: f0d1b7f93eb3ee57bcfd220656176b0b5616e1947f89ed44364555cf910c4840 dependencies: - name: idf require: private @@ -589,7 +607,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 3.0.1~1 + version: 3.0.2 espressif/usb_host_uvc: component_hash: b0cb9a3a2eaa09dc6e5cc3e47e04d0a73e47c2d3dcfb3afce959224a1fe5fb5e dependencies: @@ -614,7 +632,7 @@ dependencies: - linux version: 2.3.1 espressif2022/esp_emote_gfx: - component_hash: 7478561e4e8bd0efd4307647ec7221da2519de4ff1cd0cb08dccfbd0161cadaa + component_hash: 67986ead33c11de895eb7ba9a069ea89949ec911ce7cf0989478cc9da2e54735 dependencies: - name: espressif/cmake_utilities registry_url: https://components.espressif.com @@ -622,7 +640,7 @@ dependencies: version: 0.* - name: espressif/esp_new_jpeg registry_url: https://components.espressif.com - require: private + require: public version: 0.6.* - name: espressif/freetype registry_url: https://components.espressif.com @@ -631,10 +649,14 @@ dependencies: - name: idf require: private version: '>=5.0' + - name: lvgl/lvgl + registry_url: https://components.espressif.com + require: public + version: '*' source: registry_url: https://components.espressif.com/ type: service - version: 1.2.0~1 + version: 2.0.0 espressif2022/image_player: component_hash: 0e42ed1c9665debd15f2f3e7e56519100e75e446410962226cb5e5402da3fa43 dependencies: @@ -693,7 +715,7 @@ dependencies: type: service version: 1.0.2 waveshare/esp_lcd_touch_cst9217: - component_hash: c5da844e73ab7b7e02938901e71f38deed94b26976045fb4517e7fc1e8dc4db5 + component_hash: 27a00845832b7987cacf4c4125cbed5415d940987583065b01870ac080930856 dependencies: - name: espressif/esp_lcd_touch registry_url: https://components.espressif.com @@ -705,7 +727,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 1.0.3 + version: 1.0.4 wvirgil123/sscma_client: component_hash: bf7d4a1f157303f4850d0b9b465c733ce38e8689ff40ac4743a44520524c41d5 dependencies: @@ -728,6 +750,7 @@ direct_dependencies: - 78/xiaozhi-fonts - espressif/adc_battery_estimation - espressif/adc_mic +- espressif/bmi270_sensor - espressif/button - espressif/cmake_utilities - espressif/dl_fft @@ -753,7 +776,6 @@ direct_dependencies: - espressif/esp_mmap_assets - espressif/esp_new_jpeg - espressif/esp_video -- espressif/i2c_bus - espressif/knob - espressif/led_strip - espressif2022/esp_emote_gfx @@ -765,6 +787,6 @@ direct_dependencies: - waveshare/esp_lcd_sh8601 - waveshare/esp_lcd_touch_cst9217 - wvirgil123/sscma_client -manifest_hash: 8b8d8d3a405eda302202a654ce1dfdbc17f486994ac285a18867b38f07a065c0 +manifest_hash: 58298729f89f9edb041dac03ee9a91c4f6f97f277634f6349f91981c9b4b715f target: esp32s3 version: 2.0.0 diff --git a/firmware/main/CMakeLists.txt b/firmware/main/CMakeLists.txt index c56336f..6eb786a 100644 --- a/firmware/main/CMakeLists.txt +++ b/firmware/main/CMakeLists.txt @@ -1,7 +1,6 @@ # Define xiaozhi source directory set(XIAOZHI_MAIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/main") - file(GLOB_RECURSE STACK_CHAN_SOURCES "apps/*.c" "apps/*.cc" @@ -47,6 +46,7 @@ set(SOURCES "audio/audio_codec.cc" "display/lvgl_display/gif/lvgl_gif.cc" "display/lvgl_display/gif/gifdec.c" "display/lvgl_display/jpg/image_to_jpeg.cpp" + "display/lvgl_display/jpg/jpeg_to_image.c" "protocols/protocol.cc" "protocols/mqtt_protocol.cc" "protocols/websocket_protocol.cc" @@ -55,8 +55,9 @@ set(SOURCES "audio/audio_codec.cc" "application.cc" "ota.cc" "settings.cc" - "device_state_event.cc" + "device_state_machine.cc" "assets.cc" + # "main.cc" ) # Transform relative paths to absolute paths from xiaozhi-esp32/main @@ -65,7 +66,6 @@ list(TRANSFORM SOURCES PREPEND "${XIAOZHI_MAIN_DIR}/") set(INCLUDE_DIRS "." "display" "display/lvgl_display" "display/lvgl_display/jpg" "audio" "protocols") # Transform include dirs to absolute paths from xiaozhi-esp32/main list(TRANSFORM INCLUDE_DIRS PREPEND "${XIAOZHI_MAIN_DIR}/") -list(APPEND INCLUDE_DIRS) # Add board common files file(GLOB BOARD_COMMON_SOURCES ${XIAOZHI_MAIN_DIR}/boards/common/*.cc) @@ -99,25 +99,28 @@ if(CONFIG_BOARD_TYPE_M5STACK_STACK_CHAN) endif() file(GLOB BOARD_SOURCES + ${XIAOZHI_MAIN_DIR}/boards/${BOARD_TYPE}/*.cc + ${XIAOZHI_MAIN_DIR}/boards/${BOARD_TYPE}/*.c ) list(APPEND SOURCES ${BOARD_SOURCES}) # Select audio processor according to Kconfig if(CONFIG_USE_AUDIO_PROCESSOR) - set(AUDIO_PROCESSOR_SRC "audio/processors/afe_audio_processor.cc") + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/audio/processors/afe_audio_processor.cc") else() - set(AUDIO_PROCESSOR_SRC "audio/processors/no_audio_processor.cc") + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/audio/processors/no_audio_processor.cc") endif() -list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/${AUDIO_PROCESSOR_SRC}") - if(CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4) - set(WAKE_WORD_SRCS "audio/wake_words/afe_wake_word.cc" "audio/wake_words/custom_wake_word.cc") + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/audio/wake_words/afe_wake_word.cc") + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/audio/wake_words/custom_wake_word.cc") else() - set(WAKE_WORD_SRCS "audio/wake_words/esp_wake_word.cc") + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/audio/wake_words/esp_wake_word.cc") endif() -list(TRANSFORM WAKE_WORD_SRCS PREPEND "${XIAOZHI_MAIN_DIR}/") -list(APPEND SOURCES ${WAKE_WORD_SRCS}) +# Auto Select Additional Sources +if (CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING) + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/boards/common/blufi.cpp") +endif () # Select language directory according to Kconfig if(CONFIG_LANGUAGE_ZH_CN) set(LANG_DIR "zh-CN") @@ -233,16 +236,14 @@ file(GLOB COMMON_SOUNDS # If target chip is ESP32, exclude specific files to avoid build errors if(CONFIG_IDF_TARGET_ESP32) - set(ESP32_EXCLUDE_FILES - "audio/codecs/box_audio_codec.cc" - "audio/codecs/es8388_audio_codec.cc" - "audio/codecs/es8389_audio_codec.cc" - "led/gpio_led.cc" - "boards/common/esp32_camera.cc" - "display/lvgl_display/jpg/image_to_jpeg.cpp" - ) - list(TRANSFORM ESP32_EXCLUDE_FILES PREPEND "${XIAOZHI_MAIN_DIR}/") - list(REMOVE_ITEM SOURCES ${ESP32_EXCLUDE_FILES}) + list(REMOVE_ITEM SOURCES "audio/codecs/box_audio_codec.cc" + "audio/codecs/es8388_audio_codec.cc" + "audio/codecs/es8389_audio_codec.cc" + "led/gpio_led.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/esp32_camera.cc" + "display/lvgl_display/jpg/image_to_jpeg.cpp" + "display/lvgl_display/jpg/jpeg_to_image.c" + ) endif() idf_component_register(SRCS ${SOURCES} @@ -264,12 +265,12 @@ target_compile_definitions(${COMPONENT_LIB} # Add generation rules add_custom_command( OUTPUT ${LANG_HEADER} - COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/gen_lang.py + COMMAND python ${PROJECT_DIR}/xiaozhi-esp32/scripts/gen_lang.py --language "${LANG_DIR}" --output "${LANG_HEADER}" DEPENDS ${LANG_JSON} - ${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/gen_lang.py + ${PROJECT_DIR}/xiaozhi-esp32/scripts/gen_lang.py COMMENT "Generating ${LANG_DIR} language config" ) @@ -360,10 +361,10 @@ function(build_default_assets_bin) # Create custom command to build assets add_custom_command( OUTPUT ${GENERATED_ASSETS_BIN} - COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/build_default_assets.py ${BUILD_ARGS} + COMMAND python ${PROJECT_DIR}/xiaozhi-esp32/scripts/build_default_assets.py ${BUILD_ARGS} DEPENDS ${SDKCONFIG} - ${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/build_default_assets.py + ${PROJECT_DIR}/xiaozhi-esp32/scripts/build_default_assets.py COMMENT "Building default assets.bin based on configuration" VERBATIM ) @@ -421,7 +422,7 @@ function(get_assets_local_file assets_source assets_local_file_var) if(IS_ABSOLUTE "${assets_source}") set(ASSETS_LOCAL_FILE "${assets_source}") else() - set(ASSETS_LOCAL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${assets_source}") + set(ASSETS_LOCAL_FILE "${XIAOZHI_MAIN_DIR}/${assets_source}") endif() # Check if local file exists diff --git a/firmware/main/Kconfig.projbuild b/firmware/main/Kconfig.projbuild index e1a3742..6f503f3 100644 --- a/firmware/main/Kconfig.projbuild +++ b/firmware/main/Kconfig.projbuild @@ -153,6 +153,9 @@ choice BOARD_TYPE config BOARD_TYPE_ESP_SPOT_S3 bool "Espressif Spot-S3" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_ESP_SPOT_C5 + bool "Espressif Spot-C5" + depends on IDF_TARGET_ESP32C5 config BOARD_TYPE_ESP_HI bool "Espressif ESP-HI" depends on IDF_TARGET_ESP32C3 @@ -249,6 +252,9 @@ choice BOARD_TYPE config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06 bool "Waveshare ESP32-S3-Touch-AMOLED-2.06" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_2_06 + bool "Waveshare ESP32-C6-Touch-AMOLED-2.06" + depends on IDF_TARGET_ESP32C6 config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75 bool "Waveshare ESP32-S3-Touch-AMOLED-1.75" depends on IDF_TARGET_ESP32S3 @@ -270,6 +276,9 @@ choice BOARD_TYPE config BOARD_TYPE_WAVESHARE_C6_LCD_1_69 bool "Waveshare ESP32-C6-LCD-1.69" depends on IDF_TARGET_ESP32C6 + config BOARD_TYPE_WAVESHARE_C6_TOUCH_LCD_1_83 + bool "Waveshare ESP32-C6-Touch-LCD-1.83" + depends on IDF_TARGET_ESP32C6 config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43 bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43" depends on IDF_TARGET_ESP32C6 @@ -285,6 +294,9 @@ choice BOARD_TYPE config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5 bool "Waveshare ESP32-S3-Touch-LCD-3.5" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_S3_ePaper_1_54 + bool "Waveshare ESP32-S3-ePaper-1.54" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B bool "Waveshare ESP32-S3-Touch-LCD-3.5B" depends on IDF_TARGET_ESP32S3 @@ -324,6 +336,9 @@ choice BOARD_TYPE config BOARD_TYPE_MOVECALL_MOJI_ESP32S3 bool "Movecall Moji 小智AI衍生版" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_MOVECALL_MOJI2_ESP32C5 + bool "Movecall Moji2.0 小智AI衍生版" + depends on IDF_TARGET_ESP32C5 config BOARD_TYPE_MOVECALL_CUICAN_ESP32S3 bool "Movecall CuiCan 璀璨·AI吊坠" depends on IDF_TARGET_ESP32S3 @@ -372,6 +387,9 @@ choice BOARD_TYPE config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_ML307 bool "无名科技星智1.54(ML307)" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_XINGZHI_METAL_1_54_WIFI + bool "无名科技星智1.54 METAL(wifi)" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER bool "Seeed Studio SenseCAP Watcher" depends on IDF_TARGET_ESP32S3 @@ -432,6 +450,9 @@ choice BOARD_TYPE config BOARD_TYPE_AIPI_LITE bool "AIPI-Lite" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_HU_087 + bool "HU-087" + depends on IDF_TARGET_ESP32S3 endchoice choice @@ -465,7 +486,7 @@ choice ESP_S3_LCD_EV_Board_Version_TYPE endchoice choice DISPLAY_OLED_TYPE - depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_ESP32 + depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_ESP32 || BOARD_TYPE_HU_087 prompt "OLED Type" default OLED_SSD1306_128X32 help @@ -659,6 +680,29 @@ config USE_AUDIO_DEBUGGER help Enable audio debugger, send audio data through UDP to the host machine +menu "WiFi Configuration Method" + help + WiFi Configuration Method Selection + config USE_HOTSPOT_WIFI_PROVISIONING + bool "Hotspot" + default y + help + Use WiFi Hotspot to transmit WiFi configuration data + config USE_ACOUSTIC_WIFI_PROVISIONING + bool "Acoustic" + help + Use audio signal to transmit WiFi configuration data + + config USE_ESP_BLUFI_WIFI_PROVISIONING + bool "Esp Blufi" + help + Use esp blufi protocol to transmit WiFi configuration data + select BT_ENABLED + select BT_BLE_42_FEATURES_SUPPORTED + select BT_BLE_BLUFI_ENABLE + select MBEDTLS_DHM_C +endmenu + config AUDIO_DEBUG_UDP_SERVER string "Audio Debug UDP Server Address" default "192.168.2.100:8000" @@ -666,12 +710,6 @@ config AUDIO_DEBUG_UDP_SERVER help UDP server address, format: IP:PORT, used to receive audio debugging data -config USE_ACOUSTIC_WIFI_PROVISIONING - bool "Enable Acoustic WiFi Provisioning" - default n - help - Enable acoustic WiFi provisioning, use audio signal to transmit WiFi configuration data - config RECEIVE_CUSTOM_MESSAGE bool "Enable Custom Message Reception" default n @@ -683,6 +721,16 @@ menu "Camera Configuration" comment "Warning: Please read the help text before modifying these settings." + config XIAOZHI_CAMERA_ALLOW_JPEG_INPUT + bool "Allow JPEG Input" + default n + help + Allow JPEG Input format for the camera. + + This option may need to be enabled when using a USB camera. + + Not currently supported when used simultaneously with XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE. + config XIAOZHI_ENABLE_HARDWARE_JPEG_ENCODER bool "Enable Hardware JPEG Encoder" default y @@ -691,6 +739,14 @@ menu "Camera Configuration" Use hardware JPEG encoder on ESP32-P4 to encode image to JPEG. See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details. + config XIAOZHI_ENABLE_HARDWARE_JPEG_DECODER + bool "Enable Hardware JPEG Decoder" + default n + depends on SOC_JPEG_DECODE_SUPPORTED && XIAOZHI_CAMERA_ALLOW_JPEG_INPUT + help + Use hardware JPEG decoder on ESP32-P4 to decode JPEG to image. + See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details. + config XIAOZHI_ENABLE_CAMERA_DEBUG_MODE bool "Enable Camera Debug Mode" default n @@ -699,7 +755,7 @@ menu "Camera Configuration" Only works on boards that support camera. config XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP - bool "Enable software camera buffer endianness swapping (USE WITH CAUTION)" + bool "Enable software camera buffer endianness swapping" default n depends on !CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER help @@ -714,12 +770,15 @@ menu "Camera Configuration" menuconfig XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE bool "Enable Camera Image Rotation" default n + depends on !XIAOZHI_CAMERA_ALLOW_JPEG_INPUT help Enable camera image rotation, rotate the camera image to the correct orientation. - On ESP32-P4, rotation is handled by PPA hardware. - On other chips, rotation is done in software with performance cost. - For 180° rotation, use HFlip + VFlip instead of this option. + Not currently supported when used simultaneously with XIAOZHI_CAMERA_ALLOW_JPEG_INPUT. + if XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE choice XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE prompt "Camera Image Rotation Angle (clockwise)" diff --git a/firmware/main/apps/app_ai_agent/app_ai_agent.cpp b/firmware/main/apps/app_ai_agent/app_ai_agent.cpp index 0caf95e..ada6662 100644 --- a/firmware/main/apps/app_ai_agent/app_ai_agent.cpp +++ b/firmware/main/apps/app_ai_agent/app_ai_agent.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include using namespace mooncake; using namespace smooth_ui_toolkit::lvgl_cpp; @@ -36,7 +38,9 @@ void AppAiAgent::onOpen() { mclog::tagInfo(getAppInfo().name, "on open"); - GetHAL().startXiaozhi(); + // Request to start Xiaozhi service + // All apps will be uninstall in next mooncake update + GetHAL().requestXiaozhiStart(); } // Called repeatedly while the App is running diff --git a/firmware/main/apps/app_avatar/app_avatar.cpp b/firmware/main/apps/app_avatar/app_avatar.cpp index fc66c19..7c909f4 100644 --- a/firmware/main/apps/app_avatar/app_avatar.cpp +++ b/firmware/main/apps/app_avatar/app_avatar.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,36 @@ using namespace mooncake; using namespace smooth_ui_toolkit::lvgl_cpp; using namespace stackchan; +class LoadingPage { +public: + LoadingPage() + { + _panel = std::make_unique(lv_screen_active()); + _panel->setBgColor(lv_color_hex(0x000000)); + _panel->align(LV_ALIGN_CENTER, 0, 0); + _panel->setSize(320, 240); + _panel->setBorderWidth(0); + _panel->setRadius(0); + + _msg = std::make_unique(_panel->get()); + _msg->setTextFont(&lv_font_montserrat_20); + _msg->setTextColor(lv_color_hex(0xFFFFFF)); + _msg->setTextAlign(LV_TEXT_ALIGN_CENTER); + _msg->align(LV_ALIGN_CENTER, 0, 0); + _msg->setText(""); + _msg->setWidth(220); + } + + void setMessage(std::string_view msg) + { + _msg->setText(msg); + } + +private: + std::unique_ptr _panel; + std::unique_ptr _msg; +}; + #include #include #include @@ -62,18 +93,32 @@ void AppAvatar::onOpen() { mclog::tagInfo(getAppInfo().name, "on open"); + // Craete loading page + std::unique_ptr loading_page; + { + LvglLockGuard lock; + loading_page = std::make_unique(); + } + + // Start avatar service + GetHAL().startWebSocketAvatarService([&](std::string_view msg) { + LvglLockGuard lock; + loading_page->setMessage(msg); + }); // GetHAL().startBleServer(); - GetHAL().startWebSocketAvatar(); LvglLockGuard lock; + // Destroy loading page + loading_page.reset(); + // Create default avatar auto avatar = std::make_unique(); avatar->init(lv_screen_active()); GetStackChan().attachAvatar(std::move(avatar)); /* ------------------------------- BLE events ------------------------------- */ - _ble_avatar_data.callback_id = GetHAL().onBleAvatarData.connect([&](const char* data) { + GetHAL().onBleAvatarData.connect([&](const char* data) { std::lock_guard lock(_mutex); if (_ble_avatar_data.update_flag) { return; @@ -82,7 +127,7 @@ void AppAvatar::onOpen() _ble_avatar_data.data_ptr = (char*)data; }); - _ble_motion_data.callback_id = GetHAL().onBleMotionData.connect([&](const char* data) { + GetHAL().onBleMotionData.connect([&](const char* data) { std::lock_guard lock(_mutex); if (_ble_motion_data.update_flag) { return; @@ -93,20 +138,20 @@ void AppAvatar::onOpen() /* ---------------------------- Websocket events ---------------------------- */ // Avatar control - _ws_callback_ids.avatar_id = GetHAL().onWsAvatarData.connect([&](std::string_view data) { + GetHAL().onWsAvatarData.connect([&](std::string_view data) { LvglLockGuard lvgl_lock; GetStackChan().updateAvatarFromJson(data.data()); }); // Motion control - _ws_callback_ids.motion_id = GetHAL().onWsMotionData.connect([&](std::string_view data) { + GetHAL().onWsMotionData.connect([&](std::string_view data) { LvglLockGuard lvgl_lock; check_auto_angle_sync_mode(); GetStackChan().updateMotionFromJson(data.data()); }); // Phone call handling - _ws_callback_ids.call_req_id = GetHAL().onWsCallRequest.connect([&](std::string caller) { + GetHAL().onWsCallRequest.connect([&](std::string caller) { if (_ws_call_view_id >= 0) { mclog::tagWarn(getAppInfo().name, "ws call view already exists"); return; @@ -145,7 +190,7 @@ void AppAvatar::onOpen() _ws_call_view_id = avatar.addDecorator(std::move(view)); }); - _ws_callback_ids.call_end_id = GetHAL().onWsCallEnd.connect([&](WsSignalSource source) { + GetHAL().onWsCallEnd.connect([&](WsSignalSource source) { if (source != WsSignalSource::Remote) { return; } @@ -168,11 +213,10 @@ void AppAvatar::onOpen() }); // Text message handling - _ws_callback_ids.text_msg_id = GetHAL().onWsTextMessage.connect([&](const WsTextMessage_t& message) { + GetHAL().onWsTextMessage.connect([&](const WsTextMessage_t& message) { LvglLockGuard lvgl_lock; auto& stackchan = GetStackChan(); - auto& avatar = stackchan.avatar(); stackchan.addModifier( std::make_unique(fmt::format("{} says: {}", message.name, message.content), 6000)); @@ -186,7 +230,7 @@ void AppAvatar::onOpen() } }); - _ws_callback_ids.dance_data_id = GetHAL().onWsDanceData.connect([&](std::string_view data) { + GetHAL().onWsDanceData.connect([&](std::string_view data) { LvglLockGuard lvgl_lock; auto sequence = stackchan::animation::parse_sequence_from_json(data.data()); if (!sequence.empty()) { @@ -194,8 +238,17 @@ void AppAvatar::onOpen() } }); + GetHAL().onWsLog.connect([&](CommonLogLevel level, std::string_view msg) { + auto type = static_cast(level); + uint32_t duration = type == view::ToastType::Error ? 12000 : 1600; + view::pop_a_toast(msg, type, duration); + }); + /* ------------------------------ Video window ------------------------------ */ _video_window = std::make_unique(lv_screen_active()); + + /* ----------------------------- Home Indicator ----------------------------- */ + view::create_home_indicator([&]() { close(); }); } void AppAvatar::onRunning() @@ -218,26 +271,34 @@ void AppAvatar::onRunning() } GetStackChan().update(); + + view::update_home_indicator(); } void AppAvatar::onClose() { mclog::tagInfo(getAppInfo().name, "on close"); - LvglLockGuard lock; + { + LvglLockGuard lock; + + GetStackChan().resetAvatar(); + _video_window.reset(); - GetStackChan().resetAvatar(); - _video_window.reset(); + GetHAL().onBleAvatarData.clear(); + GetHAL().onBleMotionData.clear(); - GetHAL().onBleAvatarData.disconnect(_ble_avatar_data.callback_id); - GetHAL().onBleMotionData.disconnect(_ble_motion_data.callback_id); + GetHAL().onWsAvatarData.clear(); + GetHAL().onWsMotionData.clear(); + GetHAL().onWsCallRequest.clear(); + GetHAL().onWsCallEnd.clear(); + GetHAL().onWsTextMessage.clear(); + GetHAL().onWsDanceData.clear(); + + view::destroy_home_indicator(); + } - GetHAL().onWsAvatarData.disconnect(_ws_callback_ids.avatar_id); - GetHAL().onWsMotionData.disconnect(_ws_callback_ids.motion_id); - GetHAL().onWsCallRequest.disconnect(_ws_callback_ids.call_req_id); - GetHAL().onWsCallEnd.disconnect(_ws_callback_ids.call_end_id); - GetHAL().onWsTextMessage.disconnect(_ws_callback_ids.text_msg_id); - GetHAL().onWsDanceData.disconnect(_ws_callback_ids.dance_data_id); + GetHAL().requestWarmReboot(1); } void AppAvatar::check_auto_angle_sync_mode() diff --git a/firmware/main/apps/app_avatar/app_avatar.h b/firmware/main/apps/app_avatar/app_avatar.h index ffd125d..218d03d 100644 --- a/firmware/main/apps/app_avatar/app_avatar.h +++ b/firmware/main/apps/app_avatar/app_avatar.h @@ -31,21 +31,10 @@ class AppAvatar : public mooncake::AppAbility { struct BleHandlerData_t { bool update_flag = false; char* data_ptr = nullptr; - int callback_id = -1; }; BleHandlerData_t _ble_avatar_data; BleHandlerData_t _ble_motion_data; - struct WsCallbackIds_t { - int avatar_id = -1; - int motion_id = -1; - int call_req_id = -1; - int call_end_id = -1; - int text_msg_id = -1; - int dance_data_id = -1; - }; - WsCallbackIds_t _ws_callback_ids; - int _ws_call_view_id = -1; uint32_t _last_motion_cmd_tick = 0; diff --git a/firmware/main/apps/app_espnow_ctrl/app_espnow_ctrl.cpp b/firmware/main/apps/app_espnow_ctrl/app_espnow_ctrl.cpp index 1db8540..bdc782f 100644 --- a/firmware/main/apps/app_espnow_ctrl/app_espnow_ctrl.cpp +++ b/firmware/main/apps/app_espnow_ctrl/app_espnow_ctrl.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,7 @@ void AppEspnowControl::onOpen() avatar->init(lv_screen_active()); stackchan.attachAvatar(std::move(avatar)); + stackchan.clearModifiers(); stackchan.addModifier(std::make_unique()); stackchan.addModifier(std::make_unique()); @@ -89,6 +91,8 @@ void AppEspnowControl::onOpen() stackchan.motion().setAutoAngleSyncEnabled(false); GetHAL().setLaserEnabled(false); + + view::create_home_indicator([&]() { close(); }); } void handle_received_data() @@ -178,6 +182,8 @@ void AppEspnowControl::onRunning() } GetStackChan().update(); + + view::update_home_indicator(); } void AppEspnowControl::onClose() @@ -185,4 +191,8 @@ void AppEspnowControl::onClose() mclog::tagInfo(getAppInfo().name, "on close"); LvglLockGuard lock; + + view::destroy_home_indicator(); + + GetHAL().requestWarmReboot(2); } diff --git a/firmware/main/apps/app_espnow_ctrl/view/page_selector.h b/firmware/main/apps/app_espnow_ctrl/view/page_selector.h index 5a78a51..eb37a0e 100644 --- a/firmware/main/apps/app_espnow_ctrl/view/page_selector.h +++ b/firmware/main/apps/app_espnow_ctrl/view/page_selector.h @@ -20,7 +20,11 @@ class PageSelector { { _panel = std::make_unique(lv_screen_active()); _panel->setPadding(0, 0, 0, 0); + _panel->setBgColor(lv_color_hex(0xF6F6F6)); + _panel->align(LV_ALIGN_CENTER, 0, 0); + _panel->setBorderWidth(0); _panel->setSize(320, 240); + _panel->setRadius(0); _label = std::make_unique(_panel->get()); _label->setText(label); @@ -36,6 +40,7 @@ class PageSelector { _btn_confirm = std::make_unique(_panel->get()); _btn_confirm->label().setText("ok"); + _btn_confirm->label().setTextFont(&lv_font_montserrat_24); _btn_confirm->setSize(70, 110); _btn_confirm->align(LV_ALIGN_CENTER, 110, 40); _btn_confirm->onClick().connect([&]() { _is_selected = true; }); diff --git a/firmware/main/apps/app_launcher/app_launcher.cpp b/firmware/main/apps/app_launcher/app_launcher.cpp index a655077..e1e3d20 100644 --- a/firmware/main/apps/app_launcher/app_launcher.cpp +++ b/firmware/main/apps/app_launcher/app_launcher.cpp @@ -26,21 +26,29 @@ void AppLauncher::onLauncherOpen() LvglLockGuard lock; - _view = std::make_unique(); - _view->init(getAppProps()); - _view->onAppClicked = [&](int appID) { - mclog::tagInfo(getAppInfo().name, "handle open app, app id: {}", appID); - openApp(appID); - }; + if (!_startup_checked && !GetHAL().isAppConfiged()) { + mclog::tagInfo(getAppInfo().name, "app not configured, start startup worker"); + _startup_worker = std::make_unique(); + } else { + create_launcher_view(); + } } void AppLauncher::onLauncherRunning() { LvglLockGuard lock; - _view->update(); - - screensaver_update(); + if (_startup_worker) { + _startup_worker->update(); + if (_startup_worker->isDone()) { + _startup_worker.reset(); + _startup_checked = true; + create_launcher_view(); + } + } else { + _view->update(); + screensaver_update(); + } GetStackChan().update(); } @@ -59,6 +67,16 @@ void AppLauncher::onLauncherDestroy() mclog::tagInfo(getAppInfo().name, "on close"); } +void AppLauncher::create_launcher_view() +{ + _view = std::make_unique(); + _view->init(getAppProps()); + _view->onAppClicked = [&](int appID) { + mclog::tagInfo(getAppInfo().name, "handle open app, app id: {}", appID); + openApp(appID); + }; +} + void AppLauncher::screensaver_update() { const uint32_t SCREENSAVER_TIMEOUT_MS = 30000; diff --git a/firmware/main/apps/app_launcher/app_launcher.h b/firmware/main/apps/app_launcher/app_launcher.h index 8dcd6eb..c62cca7 100644 --- a/firmware/main/apps/app_launcher/app_launcher.h +++ b/firmware/main/apps/app_launcher/app_launcher.h @@ -5,6 +5,7 @@ */ #pragma once #include "view/view.h" +#include #include #include #include @@ -21,7 +22,10 @@ class AppLauncher : public mooncake::templates::AppLauncherBase { private: std::unique_ptr _view; std::unique_ptr _screensaver; - + std::unique_ptr _startup_worker; uint32_t _screensaver_timecount = 0; + bool _startup_checked = false; + + void create_launcher_view(); void screensaver_update(); }; diff --git a/firmware/main/apps/app_launcher/view/view.cpp b/firmware/main/apps/app_launcher/view/view.cpp index 9c16218..3ce6812 100644 --- a/firmware/main/apps/app_launcher/view/view.cpp +++ b/firmware/main/apps/app_launcher/view/view.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -435,16 +436,34 @@ void LauncherView::init(std::vector appPorps) _dynamic_icon_label->init(icon_label_texts, _icon_gap, _panel->get()); /* ----------------------------- History restore ---------------------------- */ + bool need_restore = false; + int restore_icon_pos_x = -1; + + // If warm boot was requested + if (GetHAL().getWarmRebootTarget() >= 0) { + auto app_index = GetHAL().getWarmRebootTarget(); + mclog::tagInfo(_tag, "warm boot was requested, app index: {}", app_index); + app_index = uitk::clamp(app_index, 0, static_cast(appPorps.size()) - 1); + restore_icon_pos_x = app_index * _icon_gap; + need_restore = true; + GetHAL().clearWarmRebootRequest(); + } + if (_last_clicked_icon_pos_x != -1) { // mclog::tagInfo(_tag, "navigate to last clicked icon, pos x: {}", _last_clicked_icon_pos_x); - _panel->scrollBy(-_last_clicked_icon_pos_x, 0, LV_ANIM_OFF); + restore_icon_pos_x = _last_clicked_icon_pos_x; + need_restore = true; + _last_clicked_icon_pos_x = -1; + } - _dynamic_bg_color->jumpTo(_last_clicked_icon_pos_x / _icon_gap); - _page_indicator->jumpTo(_last_clicked_icon_pos_x / _icon_gap); - _dynamic_icon_label->jumpTo(_last_clicked_icon_pos_x / _icon_gap); + if (need_restore) { + _panel->scrollBy(-restore_icon_pos_x, 0, LV_ANIM_OFF); - _last_clicked_icon_pos_x = -1; - _state = STATE_NORMAL; + _dynamic_bg_color->jumpTo(restore_icon_pos_x / _icon_gap); + _page_indicator->jumpTo(restore_icon_pos_x / _icon_gap); + _dynamic_icon_label->jumpTo(restore_icon_pos_x / _icon_gap); + + _state = STATE_NORMAL; } // If first create @@ -461,11 +480,13 @@ void LauncherView::init(std::vector appPorps) _startup_anim->teleport(240, 120); _panel->setY(_startup_anim->directValue().x); _panel->setRadius(_startup_anim->directValue().y); - _startup_anim->move(0, 0); _state = STATE_STARTUP; } + + // Destory boot logo label + GetHAL().bootLogo.reset(); } void LauncherView::update() diff --git a/firmware/main/apps/app_setup/app_setup.cpp b/firmware/main/apps/app_setup/app_setup.cpp index f8800c5..fa40aaf 100644 --- a/firmware/main/apps/app_setup/app_setup.cpp +++ b/firmware/main/apps/app_setup/app_setup.cpp @@ -36,16 +36,19 @@ void AppSetup::onOpen() { mclog::tagInfo(getAppInfo().name, "on open"); - LvglLockGuard lock; + // Reset state + _destroy_menu = false; + _need_warm_reset = false; + _magic_count = 0; _menu_sections = {{ "Connectivity", - { - // {"Set Up Wi-Fi", - // [&]() { - // _destroy_menu = true; - // _worker = std::make_unique(); - // }}, + {{"Set Up Wi-Fi", + [&]() { + _destroy_menu = true; + _need_warm_reset = true; + _worker = std::make_unique(); + }}, {"App Bind Code", [&]() { _destroy_menu = true; @@ -66,15 +69,31 @@ void AppSetup::onOpen() }}}, }, { - "About", - {{fmt::format("FW Version: {}", common::FirmwareVersion), nullptr}}, + "Display", + {{"Brightness", + [&]() { + _destroy_menu = true; + _worker = std::make_unique(); + }}}, }, { - "End", - {{"Quit", [&]() { close(); }}}, + "About", + {{fmt::format("FW Version: {}", common::FirmwareVersion), + [&]() { + _magic_count++; + if (_magic_count >= 10) { + _magic_count = 0; + _destroy_menu = true; + _worker = std::make_unique(); + } + }}}, }}; + LvglLockGuard lock; + _menu_page = std::make_unique(_menu_sections); + + view::create_home_indicator([&]() { close(); }); } void AppSetup::onRunning() @@ -95,10 +114,13 @@ void AppSetup::onRunning() if (_worker->isDone()) { _worker.reset(); _menu_page = std::make_unique(_menu_sections); + view::create_home_indicator([&]() { close(); }); } } GetStackChan().update(); + + view::update_home_indicator(); } void AppSetup::onClose() @@ -107,5 +129,13 @@ void AppSetup::onClose() LvglLockGuard lock; + _menu_sections.clear(); _menu_page.reset(); + _worker.reset(); + + view::destroy_home_indicator(); + + if (_need_warm_reset) { + GetHAL().requestWarmReboot(3); + } } diff --git a/firmware/main/apps/app_setup/app_setup.h b/firmware/main/apps/app_setup/app_setup.h index 4eb05dc..13360bb 100644 --- a/firmware/main/apps/app_setup/app_setup.h +++ b/firmware/main/apps/app_setup/app_setup.h @@ -28,5 +28,8 @@ class AppSetup : public mooncake::AppAbility { std::vector _menu_sections; std::unique_ptr _menu_page; std::unique_ptr _worker; - bool _destroy_menu = false; + + bool _destroy_menu = false; + bool _need_warm_reset = false; + int _magic_count = 0; }; diff --git a/firmware/main/apps/app_setup/view/view.cpp b/firmware/main/apps/app_setup/view/view.cpp index 1b5368c..3b9f361 100644 --- a/firmware/main/apps/app_setup/view/view.cpp +++ b/firmware/main/apps/app_setup/view/view.cpp @@ -12,8 +12,8 @@ SelectMenuPage::SelectMenuPage(std::vector sections) : _sections(st { _pannel = std::make_unique(lv_screen_active()); _pannel->setSize(320, 240); - _pannel->setBgColor(lv_color_hex(0xffffff)); - _pannel->setPadding(10, 24, 0, 0); + _pannel->setBgColor(lv_color_hex(0xF6F6F6)); + _pannel->setPadding(10, 72, 0, 0); _pannel->setBorderWidth(0); _pannel->setRadius(0); _pannel->setScrollDir(LV_DIR_VER); @@ -70,7 +70,7 @@ void SelectMenuPage::create_item_button(int y, const MenuItem& item, int section btn->setBgColor(lv_color_hex(0xB8D3FD)); btn->setBorderWidth(0); btn->setShadowWidth(0); - btn->setRadius(12); + btn->setRadius(18); btn->label().setText(item.label); btn->label().setTextFont(&lv_font_montserrat_24); diff --git a/firmware/main/apps/app_setup/workers/about.cpp b/firmware/main/apps/app_setup/workers/about.cpp new file mode 100644 index 0000000..5c010fc --- /dev/null +++ b/firmware/main/apps/app_setup/workers/about.cpp @@ -0,0 +1,200 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include "workers.h" +#include +#include +#include +#include +#include +#include + +using namespace uitk; +using namespace uitk::lvgl_cpp; +using namespace uitk::games; +using namespace uitk::games::breakout; +using namespace setup_workers; + +static std::string _tag = "Setup-About"; + +class BreakoutLvgl : public Breakout { +public: + BreakoutLvgl() + { + _canvas = std::make_unique(lv_screen_active()); + _canvas->setSize(320, 240); + _canvas->align(LV_ALIGN_CENTER, 0, 0); + _canvas->setBgOpa(LV_OPA_COVER); + _canvas->setBgColor(lv_color_white()); + _canvas->createBuffer(320, 240, LV_COLOR_FORMAT_RGB565); + + auto create_button = [](int x, int w, bool* key_state) { + auto btn = std::make_unique