From dd34f9e0ec7eea28f140dd7358dff1c0e300ec82 Mon Sep 17 00:00:00 2001 From: Forairaaaaa Date: Mon, 20 Apr 2026 16:27:36 +0800 Subject: [PATCH] update firmware v1.2.4 (#16) --- firmware/CMakeLists.txt | 3 +- firmware/README.md | 3 +- firmware/dependencies.lock | 315 +- firmware/main/CMakeLists.txt | 106 +- firmware/main/Kconfig.projbuild | 181 +- .../main/apps/app_ai_agent/app_ai_agent.cpp | 3 +- .../apps/app_app_center/app_app_center.cpp | 125 + .../main/apps/app_app_center/app_app_center.h | 31 + firmware/main/apps/app_app_center/view/view.h | 278 + firmware/main/apps/app_avatar/app_avatar.cpp | 3 +- firmware/main/apps/app_dance/app_dance.cpp | 155 + firmware/main/apps/app_dance/app_dance.h | 38 + .../apps/app_espnow_ctrl/app_espnow_ctrl.cpp | 3 +- .../apps/app_espnow_ctrl/view/page_selector.h | 2 +- firmware/main/apps/app_ezdata/app_ezdata.cpp | 101 + firmware/main/apps/app_ezdata/app_ezdata.h | 27 + firmware/main/apps/app_ezdata/view/view.h | 84 + firmware/main/apps/app_launcher/view/view.cpp | 2 + firmware/main/apps/app_setup/app_setup.cpp | 136 +- .../main/apps/app_setup/workers/about.cpp | 33 + .../main/apps/app_setup/workers/account.cpp | 153 + .../apps/app_setup/workers/connectivity.cpp | 76 +- .../main/apps/app_setup/workers/servo.cpp | 272 +- .../main/apps/app_setup/workers/startup.cpp | 13 +- .../main/apps/app_setup/workers/system.cpp | 68 + .../main/apps/app_setup/workers/workers.h | 112 +- firmware/main/apps/apps.h | 3 + firmware/main/apps/common/common.h | 2 +- .../common/home_indicator/home_indicator.cpp | 4 +- .../apps/common/reminder/reminder_view.hpp | 6 +- .../apps/common/status_bar/status_bar.cpp | 24 +- firmware/main/assets/assets.cpp | 2 +- firmware/main/assets/assets.h | 21 - .../main/assets/assets_bin/app_center_bg.png | Bin 0 -> 29218 bytes .../main/assets/assets_bin/icon_ai_agent.bin | Bin 0 -> 84612 bytes .../assets/assets_bin/icon_app_center.bin | Bin 0 -> 84612 bytes .../assets/assets_bin/icon_bat_lightning.bin | Bin 0 -> 588 bytes firmware/main/assets/assets_bin/icon_bell.bin | Bin 0 -> 1740 bytes .../assets/assets_bin/icon_controller.bin | Bin 0 -> 84612 bytes .../main/assets/assets_bin/icon_dance.bin | Bin 0 -> 84612 bytes .../main/assets/assets_bin/icon_ezdata.bin | Bin 0 -> 84612 bytes firmware/main/assets/assets_bin/icon_home.bin | Bin 0 -> 3084 bytes .../assets/assets_bin/icon_indicator_left.bin | Bin 0 -> 6708 bytes .../assets_bin/icon_indicator_right.bin | Bin 0 -> 6708 bytes .../main/assets/assets_bin/icon_sentinel.bin | Bin 0 -> 84612 bytes .../main/assets/assets_bin/icon_setup.bin | Bin 0 -> 84612 bytes .../main/assets/assets_bin/icon_wifi_high.bin | Bin 0 -> 1212 bytes .../main/assets/assets_bin/icon_wifi_low.bin | Bin 0 -> 1212 bytes .../assets/assets_bin/icon_wifi_medium.bin | Bin 0 -> 1212 bytes .../assets/assets_bin/icon_wifi_slash.bin | Bin 0 -> 1212 bytes .../assets_bin/setup_stackchan_front_view.bin | Bin 0 -> 58980 bytes firmware/main/assets/images/icon_ai_agent.c | 4488 ---------------- firmware/main/assets/images/icon_app_store.c | 4488 ---------------- .../main/assets/images/icon_bat_lightning.c | 68 - firmware/main/assets/images/icon_bell.c | 126 - firmware/main/assets/images/icon_controller.c | 4736 ----------------- firmware/main/assets/images/icon_dance.c | 4488 ---------------- firmware/main/assets/images/icon_ezdata.c | 4488 ---------------- firmware/main/assets/images/icon_home.c | 196 - .../main/assets/images/icon_indicator_left.c | 407 -- .../main/assets/images/icon_indicator_right.c | 407 -- firmware/main/assets/images/icon_remote.c | 4488 ---------------- firmware/main/assets/images/icon_sentinel.c | 4488 ---------------- firmware/main/assets/images/icon_setup.c | 4488 ---------------- firmware/main/assets/images/icon_wifi_high.c | 99 - firmware/main/assets/images/icon_wifi_low.c | 99 - .../main/assets/images/icon_wifi_medium.c | 103 - firmware/main/assets/images/icon_wifi_slash.c | 103 - .../images/setup_stackchan_front_view.c | 3311 ------------ firmware/main/hal/board/cores3_audio_codec.cc | 2 + firmware/main/hal/board/hal_bridge.cc | 8 - firmware/main/hal/board/hal_bridge.h | 3 +- firmware/main/hal/board/stackchan.cc | 24 +- firmware/main/hal/board/stackchan_display.cc | 51 +- firmware/main/hal/board/stackchan_display.h | 5 +- firmware/main/hal/hal.cpp | 70 +- firmware/main/hal/hal.h | 62 +- firmware/main/hal/hal_account.cpp | 246 + firmware/main/hal/hal_app_center.cpp | 122 + firmware/main/hal/hal_ble.cpp | 14 +- firmware/main/hal/hal_ezdata.cpp | 465 ++ firmware/main/hal/hal_network.cpp | 11 +- firmware/main/hal/hal_ota.cpp | 67 + firmware/main/hal/hal_servo.cpp | 4 +- firmware/main/hal/hal_ws_avatar.cpp | 53 - firmware/main/hal/utils/bleprph/bleprph.c | 63 +- firmware/main/hal/utils/bleprph/bleprph.h | 8 +- firmware/main/hal/utils/bleprph/gatt_svr.c | 13 +- .../bleprph/nimble_peripheral_utils/scli.c | 62 +- firmware/main/idf_component.yml | 49 +- firmware/main/main.cpp | 3 + firmware/patches/xiaozhi-esp32.patch | 247 + firmware/repos.json | 14 +- firmware/sdkconfig.defaults | 6 +- 94 files changed, 3615 insertions(+), 41513 deletions(-) create mode 100644 firmware/main/apps/app_app_center/app_app_center.cpp create mode 100644 firmware/main/apps/app_app_center/app_app_center.h create mode 100644 firmware/main/apps/app_app_center/view/view.h create mode 100644 firmware/main/apps/app_dance/app_dance.cpp create mode 100644 firmware/main/apps/app_dance/app_dance.h create mode 100644 firmware/main/apps/app_ezdata/app_ezdata.cpp create mode 100644 firmware/main/apps/app_ezdata/app_ezdata.h create mode 100644 firmware/main/apps/app_ezdata/view/view.h create mode 100644 firmware/main/apps/app_setup/workers/account.cpp create mode 100644 firmware/main/assets/assets_bin/app_center_bg.png create mode 100644 firmware/main/assets/assets_bin/icon_ai_agent.bin create mode 100644 firmware/main/assets/assets_bin/icon_app_center.bin create mode 100644 firmware/main/assets/assets_bin/icon_bat_lightning.bin create mode 100644 firmware/main/assets/assets_bin/icon_bell.bin create mode 100644 firmware/main/assets/assets_bin/icon_controller.bin create mode 100644 firmware/main/assets/assets_bin/icon_dance.bin create mode 100644 firmware/main/assets/assets_bin/icon_ezdata.bin create mode 100644 firmware/main/assets/assets_bin/icon_home.bin create mode 100644 firmware/main/assets/assets_bin/icon_indicator_left.bin create mode 100644 firmware/main/assets/assets_bin/icon_indicator_right.bin create mode 100644 firmware/main/assets/assets_bin/icon_sentinel.bin create mode 100644 firmware/main/assets/assets_bin/icon_setup.bin create mode 100644 firmware/main/assets/assets_bin/icon_wifi_high.bin create mode 100644 firmware/main/assets/assets_bin/icon_wifi_low.bin create mode 100644 firmware/main/assets/assets_bin/icon_wifi_medium.bin create mode 100644 firmware/main/assets/assets_bin/icon_wifi_slash.bin create mode 100644 firmware/main/assets/assets_bin/setup_stackchan_front_view.bin delete mode 100644 firmware/main/assets/images/icon_ai_agent.c delete mode 100644 firmware/main/assets/images/icon_app_store.c delete mode 100644 firmware/main/assets/images/icon_bat_lightning.c delete mode 100644 firmware/main/assets/images/icon_bell.c delete mode 100644 firmware/main/assets/images/icon_controller.c delete mode 100644 firmware/main/assets/images/icon_dance.c delete mode 100644 firmware/main/assets/images/icon_ezdata.c delete mode 100644 firmware/main/assets/images/icon_home.c delete mode 100644 firmware/main/assets/images/icon_indicator_left.c delete mode 100644 firmware/main/assets/images/icon_indicator_right.c delete mode 100644 firmware/main/assets/images/icon_remote.c delete mode 100644 firmware/main/assets/images/icon_sentinel.c delete mode 100644 firmware/main/assets/images/icon_setup.c delete mode 100644 firmware/main/assets/images/icon_wifi_high.c delete mode 100644 firmware/main/assets/images/icon_wifi_low.c delete mode 100644 firmware/main/assets/images/icon_wifi_medium.c delete mode 100644 firmware/main/assets/images/icon_wifi_slash.c delete mode 100644 firmware/main/assets/images/setup_stackchan_front_view.c create mode 100644 firmware/main/hal/hal_account.cpp create mode 100644 firmware/main/hal/hal_app_center.cpp create mode 100644 firmware/main/hal/hal_ezdata.cpp create mode 100644 firmware/main/hal/hal_ota.cpp create mode 100644 firmware/patches/xiaozhi-esp32.patch diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index b5041a9..ed7e18b 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -2,7 +2,8 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(PROJECT_VER "2.1.0") +set(PROJECT_VER "1.2.4") +add_definitions(-DFIRMWARE_VERSION=\"${PROJECT_VER}\") # Add this line to disable the specific warning add_compile_options(-Wno-missing-field-initializers) diff --git a/firmware/README.md b/firmware/README.md index 72069c1..ffc20f2 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -1,4 +1,3 @@ -# StackChan Firmware ## Build @@ -10,7 +9,7 @@ python3 ./fetch_repos.py ### Tool Chains -[ESP-IDF v5.5.1](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32s3/index.html) +[ESP-IDF v5.5.4](https://docs.espressif.com/projects/esp-idf/en/v5.5.4/esp32s3/index.html) ### Build diff --git a/firmware/dependencies.lock b/firmware/dependencies.lock index 0acf4c4..325d398 100644 --- a/firmware/dependencies.lock +++ b/firmware/dependencies.lock @@ -1,40 +1,22 @@ dependencies: 78/esp-ml307: - component_hash: d4de9738baaaa5e6655c686a6083e699f3605de54dc83233ff3328cf55a4f543 + component_hash: 5231991281a2f48f0e34ec705c2982936264d8b14f6f9373e60b153fd4b62123 dependencies: + - name: 78/uart-uhci + registry_url: https://components.espressif.com + require: private + rules: + - if: target not in [esp32] + version: ~0.2.1 - name: idf require: private - version: '>=5.3' + version: '>=5.5.2' source: registry_url: https://components.espressif.com/ type: service - version: 3.5.3 - 78/esp-opus: - component_hash: 8182b733f071d7bfe1e837f4c9f8649a63e4c937177f089e65772880c02f2e17 - dependencies: - - name: idf - require: private - version: '>=5.0' - source: - registry_url: https://components.espressif.com - type: service - version: 1.0.5 - 78/esp-opus-encoder: - component_hash: b80e5b6d6dc4bf6b0bf1a3729f52b80500e9e6b1003b3e827b78ba738283a296 - dependencies: - - name: 78/esp-opus - registry_url: https://components.espressif.com - require: private - version: ^1.0.5 - - name: idf - require: private - version: '>=5.3' - source: - registry_url: https://components.espressif.com/ - type: service - version: 2.4.1 + version: 3.6.5 78/esp-wifi-connect: - component_hash: bf996fc603af1ff529668c788c7b38a8d94b1d43455af56d116d27ebb04b742a + component_hash: e64ce09a795dd3b4883e1f68be10b0dd11260331f021a5f0b1f3bfd9a25d413b dependencies: - name: idf require: private @@ -42,7 +24,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 3.0.2 + version: 3.1.2 78/esp_lcd_nv3023: component_hash: fa88abfc19a312eb5e6f2ffa187e0a9faf67e01e758bfb979d3f9d92561a494f dependencies: @@ -57,8 +39,36 @@ dependencies: registry_url: https://components.espressif.com/ type: service version: 1.0.0 + 78/uart-eth-modem: + component_hash: 7a33284e4ba22f420191be8021cd4fe3e49f5e50eea1db70370b217a18147d8e + dependencies: + - name: 78/uart-uhci + registry_url: https://components.espressif.com + require: private + version: ~0.2.1 + - name: espressif/iot_eth + registry_url: https://components.espressif.com + require: private + version: ^0.1.0 + - name: idf + require: private + version: '>=5.5.2' + source: + registry_url: https://components.espressif.com/ + type: service + version: 0.3.4 + 78/uart-uhci: + component_hash: 200eb10923cb750dddbee5504a36d7b5eaac611afbf52fb9066dc7130159f696 + dependencies: + - name: idf + require: private + version: '>=5.5.2' + source: + registry_url: https://components.espressif.com + type: service + version: 0.2.1 78/xiaozhi-fonts: - component_hash: e5526ea3c290742963ef6ab64023669260b72aefdc37bb218c34c618962ef2a8 + component_hash: 19ee829a7439702e18084a313b7b86017d3b8d17a094684575edc76bb6d11023 dependencies: - name: idf require: private @@ -66,7 +76,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 1.5.5 + version: 1.6.0 espressif/adc_battery_estimation: component_hash: b915167c87ed5a84b13d680bd011c2ed9a15121f1e247c6903141b9f138f3606 dependencies: @@ -82,7 +92,7 @@ dependencies: type: service version: 0.2.1 espressif/adc_mic: - component_hash: ca6ef69bba4dc0d3e0ce53937635ed2734d38ac947881da81b8526e6851a71a4 + component_hash: 3bb576d530564cb8e805fc34309d485de393f634651f3d31579fe3037b581d4f dependencies: - name: espressif/cmake_utilities registry_url: https://components.espressif.com @@ -98,7 +108,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 0.2.1 + version: 0.2.2 espressif/bmi270_sensor: component_hash: fac23a5ecd2effdac0fb0705988d853745b8ffb99a384f87a307b3b25d15d432 dependencies: @@ -118,7 +128,7 @@ dependencies: type: service version: 0.1.1 espressif/button: - component_hash: fccb18c37f1cfe0797b74a53a44d3f400f5fd01f4993b40052dfb7f401915089 + component_hash: d0afa32f0e50d60bc0c6fc23f7eea98adc6b02cfe70b590bc52c23c506745287 dependencies: - name: espressif/cmake_utilities registry_url: https://components.espressif.com @@ -130,7 +140,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 4.1.5 + version: 4.1.6 espressif/cmake_utilities: component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f dependencies: @@ -148,7 +158,7 @@ dependencies: require: private version: '>=5.0' source: - registry_url: https://components.espressif.com/ + registry_url: https://components.espressif.com type: service version: 0.3.1 espressif/esp-dsp: @@ -158,9 +168,58 @@ dependencies: require: private version: '>=4.2' source: - registry_url: https://components.espressif.com/ + registry_url: https://components.espressif.com type: service version: 1.7.0 + espressif/esp-sr: + component_hash: 46b1f70f8b561714b958d1c455213cca07162755d1b8df53498081199f15136f + dependencies: + - name: espressif/dl_fft + registry_url: https://components.espressif.com + require: private + version: '>=0.2.0' + - name: espressif/esp-dsp + registry_url: https://components.espressif.com + require: private + version: 1.7.0 + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 2.3.1 + espressif/esp32-camera: + component_hash: ac4228c825b891378bc0806869170d4ebc5d45ba8ebc519b4f8886a56ad2d123 + dependencies: + - name: espressif/esp_jpeg + registry_url: https://components.espressif.com + require: public + version: ^1.3.1 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com/ + type: service + version: 2.1.5 + espressif/esp_audio_codec: + component_hash: af4663830bc73eca58febcc34a976d003465e78ed57458aa00a14b231e392ca1 + dependencies: + - name: idf + require: private + version: '>=4.4' + source: + registry_url: https://components.espressif.com/ + type: service + version: 2.4.1 + espressif/esp_audio_effects: + component_hash: 8fa2bf7356a3c7fb9a9c7d2185aba474fa033b0506886c70752f67c42cd81b3f + dependencies: [] + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.2.1 espressif/esp_cam_sensor: component_hash: 35c1648ea87aac81da7a085d35f61b6d5ad88574bd0c5fdc4ab75efdef4ee6c1 dependencies: @@ -207,7 +266,7 @@ dependencies: type: service version: 1.0.1 espressif/esp_io_expander: - component_hash: abf3ea0d71407d79d15500550aa3ba433848459b0fa94717cf9478822593ee5d + component_hash: 7b7f91270172e46ca4597e3874f48d8412e280e8c295559f5922ec38656e3e5f dependencies: - name: idf require: private @@ -215,7 +274,7 @@ dependencies: source: registry_url: https://components.espressif.com type: service - version: 1.1.0 + version: 1.2.1 espressif/esp_io_expander_tca9554: component_hash: 8a9e3a7dbef589a54f814ff22e9121da86bce19d0e1ccffa53f5df6bb346a140 dependencies: @@ -231,19 +290,29 @@ dependencies: type: service version: 2.0.0 espressif/esp_io_expander_tca95xx_16bit: - component_hash: c384d55e429775d6a1eef26512fbc33bc41823745a8c2ad6d5927729f33a2c21 + component_hash: a9608ba5753ae2a72e79fccd376fc4283343c0306d23505fbf8a46fafdbde2a2 dependencies: - name: espressif/esp_io_expander registry_url: https://components.espressif.com require: public - version: ^1.0.1 + version: ^1.2.0 - name: idf require: private version: '>=5.2' source: registry_url: https://components.espressif.com/ type: service - version: 2.0.1 + version: 2.0.2 + espressif/esp_jpeg: + component_hash: defb83669293cbf86d0fa86b475ba5517aceed04ed70db435388c151ab37b5d7 + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com + type: service + version: 1.3.1 espressif/esp_lcd_axs15231b: component_hash: e614bd75827e95800e39df1ba9474166060ab26c3807d06df9cc312a27021cda dependencies: @@ -262,6 +331,20 @@ dependencies: registry_url: https://components.espressif.com/ type: service version: 1.0.1~1 + espressif/esp_lcd_co5300: + component_hash: 7004162c496b65a5e0ee7c92800c33c12b373ea70d07199318a182cb16c741b7 + dependencies: + - name: espressif/cmake_utilities + registry_url: https://components.espressif.com + require: private + version: 0.* + - name: idf + require: private + version: '>=5.4' + source: + registry_url: https://components.espressif.com/ + type: service + version: 2.0.3 espressif/esp_lcd_gc9a01: component_hash: 09ddc8f5c9d718a659ffa30a4040e1ae75077e68492c38aec8c2beaaa7b3a9bc dependencies: @@ -457,7 +540,7 @@ dependencies: type: service version: 1.0.1 espressif/esp_lvgl_port: - component_hash: 3264cc85d86a7c32b67d26a1353a57c67e7986bb293ebb1731801936b056e632 + component_hash: b6360960f47b6776462e7092861b3ea66477ffb762a01baa0aecbb3d74cd50f4 dependencies: - name: idf require: private @@ -469,7 +552,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 2.6.3 + version: 2.7.2 espressif/esp_mmap_assets: component_hash: 91d785326b03db15e2f7f1314d8c976d38f21aa5759b570dcbbc89bcf247fd27 dependencies: @@ -501,7 +584,7 @@ dependencies: - esp32c6 version: 0.6.1 espressif/esp_sccb_intf: - component_hash: 44dfa738680ccbc3705ae6940f59be603165f4f7e4d05c3eb5f433705fdc92be + component_hash: c071b189e49f40940722aea01a5489f873385cc39cd5b14012341135b85d1a9d dependencies: - name: idf require: private @@ -509,7 +592,7 @@ dependencies: source: registry_url: https://components.espressif.com type: service - version: 0.0.7 + version: 0.0.8 espressif/esp_video: component_hash: fbad1178f39cb5a81ed808c460c851b911a9858db833e2e667ada988022c0660 dependencies: @@ -560,18 +643,8 @@ dependencies: - esp32c6 - esp32c61 version: 1.3.1 - espressif/freetype: - component_hash: cd5e2d8458e6e8d73f1120ac474467cabb669d8ea4b25050bf6a348c1e89225e - dependencies: - - name: idf - require: private - version: '>=4.4' - source: - registry_url: https://components.espressif.com - type: service - version: 2.13.3~1 espressif/i2c_bus: - component_hash: 4e990dc11734316186b489b362c61d41f23f79d58bc169795cec215e528cba14 + component_hash: 804ec068d163570fd367b279a310ca383484630d2310c586b50def0bcf21de13 dependencies: - name: espressif/cmake_utilities registry_url: https://components.espressif.com @@ -583,7 +656,65 @@ dependencies: source: registry_url: https://components.espressif.com type: service - version: 1.5.0 + version: 1.5.1 + espressif/iot_eth: + component_hash: ffcea72f079264b6905e428a406cb6d2512dfede10d100c49d3486dd78dc1873 + dependencies: + - name: espressif/cmake_utilities + registry_url: https://components.espressif.com + require: private + version: '*' + - name: idf + require: private + version: '>=4.4' + source: + registry_url: https://components.espressif.com + type: service + version: 0.1.0 + espressif/iot_usbh_cdc: + component_hash: 6b30e8eeef1a3320a3bc0c27980c62826ed134b681be6f424366f3d78c291814 + dependencies: + - name: idf + require: private + version: '>=5.1' + - name: espressif/cmake_utilities + registry_url: https://components.espressif.com + require: private + version: '*' + source: + registry_url: https://components.espressif.com + type: service + targets: + - esp32s2 + - esp32s3 + - esp32p4 + version: 3.0.0 + espressif/iot_usbh_rndis: + component_hash: 0d91d9c79980fe0d2b59ecae9341d91852b7eb3356cc0e708f76425a3604ff5b + dependencies: + - name: espressif/cmake_utilities + registry_url: https://components.espressif.com + require: private + version: '*' + - name: espressif/iot_eth + registry_url: https://components.espressif.com + require: public + version: '*' + - name: espressif/iot_usbh_cdc + registry_url: https://components.espressif.com + require: public + version: ^3.0 + - name: idf + require: private + version: '>=5.2' + source: + registry_url: https://components.espressif.com/ + type: service + targets: + - esp32s2 + - esp32s3 + - esp32p4 + version: 0.3.1 espressif/knob: component_hash: 138ed090b4c9090a0a678f695b9d1884b368130c729b7333ed35bd7f4e8da80e dependencies: @@ -599,7 +730,7 @@ dependencies: type: service version: 1.0.2 espressif/led_strip: - component_hash: f0d1b7f93eb3ee57bcfd220656176b0b5616e1947f89ed44364555cf910c4840 + component_hash: 28621486f77229aaf81c71f5e15d6fbf36c2949cf11094e07090593e659e7639 dependencies: - name: idf require: private @@ -607,7 +738,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 3.0.2 + version: 3.0.3 espressif/usb_host_uvc: component_hash: b0cb9a3a2eaa09dc6e5cc3e47e04d0a73e47c2d3dcfb3afce959224a1fe5fb5e dependencies: @@ -631,32 +762,6 @@ dependencies: - esp32h4 - linux version: 2.3.1 - espressif2022/esp_emote_gfx: - component_hash: 67986ead33c11de895eb7ba9a069ea89949ec911ce7cf0989478cc9da2e54735 - dependencies: - - name: espressif/cmake_utilities - registry_url: https://components.espressif.com - require: private - version: 0.* - - name: espressif/esp_new_jpeg - registry_url: https://components.espressif.com - require: public - version: 0.6.* - - name: espressif/freetype - registry_url: https://components.espressif.com - require: private - version: 2.* - - 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: 2.0.0 espressif2022/image_player: component_hash: 0e42ed1c9665debd15f2f3e7e56519100e75e446410962226cb5e5402da3fa43 dependencies: @@ -674,14 +779,14 @@ dependencies: idf: source: type: idf - version: 5.5.1 + version: 5.5.4 lvgl/lvgl: - component_hash: b702d642e03e95928046d5c6726558e6444e112420c77efa5fdb6650b0a13c5d + component_hash: 17e68bfd21f0edf4c3ee838e2273da840bf3930e5dbc3bfa6c1190c3aed41f9f dependencies: [] source: registry_url: https://components.espressif.com/ type: service - version: 9.3.0 + version: 9.4.0 tny-robotics/sh1106-esp-idf: component_hash: 7be190d7c58cd635adf8b74b3a841f8245f2f82f36d135a64d8e53cfab39124d dependencies: [] @@ -690,7 +795,7 @@ dependencies: type: service version: 1.0.0 txp666/otto-emoji-gif-component: - component_hash: 5a722dd0a40014b31d5998ea5b21f0b53a99d1025626d765d08710b47636ee97 + component_hash: 8da812ae44707af319a20e164e8b544199fe401436167c206e684594e0a38c5d dependencies: - name: lvgl/lvgl registry_url: https://components.espressif.com @@ -699,7 +804,21 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 1.0.4 + version: 1.1.1 + waveshare/custom_io_expander_ch32v003: + component_hash: fefced27c762ed97a3523c9d90d66050deea7eeb7e9eae6328e4ab1a71125d26 + dependencies: + - name: espressif/esp_io_expander + registry_url: https://components.espressif.com + require: public + version: ^1.0.1 + - name: idf + require: private + version: '>=5.3' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.0.1 waveshare/esp_lcd_sh8601: component_hash: 1a2829e9db4e0515bad6ce83368f199dec60519fbba40251d6c8249f5d070ae1 dependencies: @@ -744,22 +863,25 @@ dependencies: version: 1.0.2 direct_dependencies: - 78/esp-ml307 -- 78/esp-opus-encoder - 78/esp-wifi-connect - 78/esp_lcd_nv3023 +- 78/uart-eth-modem - 78/xiaozhi-fonts - espressif/adc_battery_estimation - espressif/adc_mic - espressif/bmi270_sensor - espressif/button - espressif/cmake_utilities -- espressif/dl_fft -- espressif/esp-dsp +- espressif/esp-sr +- espressif/esp32-camera +- espressif/esp_audio_codec +- espressif/esp_audio_effects - espressif/esp_codec_dev - espressif/esp_image_effects - espressif/esp_io_expander_tca9554 - espressif/esp_io_expander_tca95xx_16bit - espressif/esp_lcd_axs15231b +- espressif/esp_lcd_co5300 - espressif/esp_lcd_gc9a01 - espressif/esp_lcd_ili9341 - espressif/esp_lcd_panel_io_additions @@ -776,17 +898,18 @@ direct_dependencies: - espressif/esp_mmap_assets - espressif/esp_new_jpeg - espressif/esp_video +- espressif/iot_usbh_rndis - espressif/knob - espressif/led_strip -- espressif2022/esp_emote_gfx - espressif2022/image_player - idf - lvgl/lvgl - tny-robotics/sh1106-esp-idf - txp666/otto-emoji-gif-component +- waveshare/custom_io_expander_ch32v003 - waveshare/esp_lcd_sh8601 - waveshare/esp_lcd_touch_cst9217 - wvirgil123/sscma_client -manifest_hash: 58298729f89f9edb041dac03ee9a91c4f6f97f277634f6349f91981c9b4b715f +manifest_hash: 350e17991f1a3226438480b027525b7cde67c34ed4ec6c5847cdfcb22e18dc4a target: esp32s3 version: 2.0.0 diff --git a/firmware/main/CMakeLists.txt b/firmware/main/CMakeLists.txt index 43c51aa..22cfebb 100644 --- a/firmware/main/CMakeLists.txt +++ b/firmware/main/CMakeLists.txt @@ -23,6 +23,7 @@ list(APPEND STACK_CHAN_SOURCES main.cpp) # Define source files set(SOURCES "audio/audio_codec.cc" "audio/audio_service.cc" + "audio/demuxer/ogg_demuxer.cc" "audio/codecs/no_audio_codec.cc" "audio/codecs/box_audio_codec.cc" "audio/codecs/es8311_audio_codec.cc" @@ -38,7 +39,7 @@ set(SOURCES "audio/audio_codec.cc" "display/lcd_display.cc" "display/oled_display.cc" "display/lvgl_display/lvgl_display.cc" - "display/emote_display.cc" + # "display/emote_display.cc" "display/lvgl_display/emoji_collection.cc" "display/lvgl_display/lvgl_theme.cc" "display/lvgl_display/lvgl_font.cc" @@ -63,15 +64,34 @@ set(SOURCES "audio/audio_codec.cc" # Transform relative paths to absolute paths from xiaozhi-esp32/main list(TRANSFORM SOURCES PREPEND "${XIAOZHI_MAIN_DIR}/") -set(INCLUDE_DIRS "." "display" "display/lvgl_display" "display/lvgl_display/jpg" "audio" "protocols") +set(INCLUDE_DIRS "." "display" "display/lvgl_display" "display/lvgl_display/jpg" "audio" "audio/demuxer" "protocols") # Transform include dirs to absolute paths from xiaozhi-esp32/main list(TRANSFORM INCLUDE_DIRS PREPEND "${XIAOZHI_MAIN_DIR}/") # Add board common files -file(GLOB BOARD_COMMON_SOURCES ${XIAOZHI_MAIN_DIR}/boards/common/*.cc) -list(APPEND SOURCES ${BOARD_COMMON_SOURCES} ${STACK_CHAN_SOURCES}) +list(APPEND SOURCES + "${XIAOZHI_MAIN_DIR}/boards/common/board.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/wifi_board.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/ml307_board.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/nt26_board.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/dual_network_board.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/adc_battery_monitor.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/afsk_demod.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/axp2101.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/backlight.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/button.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/i2c_device.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/knob.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/power_save_timer.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/press_to_talk_mcp_tool.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/sleep_timer.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/sy6970.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/system_reset.cc" + ${STACK_CHAN_SOURCES} +) list(APPEND INCLUDE_DIRS ${XIAOZHI_MAIN_DIR}/boards/common ${STACK_CHAN_INCLUDE_DIRS}) + idf_build_get_property(build_components BUILD_COMPONENTS) # Function to find component dynamically by pattern function(find_component_by_pattern PATTERN COMPONENT_VAR PATH_VAR) @@ -89,6 +109,8 @@ endfunction() set(BUILTIN_TEXT_FONT font_puhui_14_1) set(BUILTIN_ICON_FONT font_awesome_14_1) +set(EMOTE_RESOLUTION "320_240") + # Add board files according to BOARD_TYPE # Set default assets if the board uses partition table V2 if(CONFIG_BOARD_TYPE_M5STACK_STACK_CHAN) @@ -98,10 +120,17 @@ if(CONFIG_BOARD_TYPE_M5STACK_STACK_CHAN) set(DEFAULT_EMOJI_COLLECTION twemoji_64) endif() -file(GLOB BOARD_SOURCES - ${XIAOZHI_MAIN_DIR}/boards/${BOARD_TYPE}/*.cc - ${XIAOZHI_MAIN_DIR}/boards/${BOARD_TYPE}/*.c -) +if(MANUFACTURER) + file(GLOB BOARD_SOURCES + ${XIAOZHI_MAIN_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.cc + ${XIAOZHI_MAIN_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.c + ) +else() + file(GLOB BOARD_SOURCES + ${XIAOZHI_MAIN_DIR}/boards/${BOARD_TYPE}/*.cc + ${XIAOZHI_MAIN_DIR}/boards/${BOARD_TYPE}/*.c + ) +endif() list(APPEND SOURCES ${BOARD_SOURCES}) # Select audio processor according to Kconfig @@ -119,7 +148,7 @@ endif() # Auto Select Additional Sources if (CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING) - list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/boards/common/blufi.cpp") + list(APPEND SOURCES "boards/common/blufi.cpp") endif () # Select language directory according to Kconfig if(CONFIG_LANGUAGE_ZH_CN) @@ -228,7 +257,7 @@ if(NOT LANG_DIR STREQUAL "en-US") endforeach() endif() -# file(GLOB COMMON_SOUNDS ${XIAOZHI_MAIN_DIR}/assets/common/*.ogg) +# file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.ogg) file(GLOB COMMON_SOUNDS ${XIAOZHI_MAIN_DIR}/assets/common/*.ogg assets/sfx/*.ogg @@ -240,16 +269,53 @@ if(CONFIG_IDF_TARGET_ESP32) "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" + "boards/common/nt26_board.cc" + "boards/common/ml307_board.cc" + "boards/common/dual_network_board.cc" ) endif() +# Include EspVideo if target is ESP32S3 or ESP32P4 +if(CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4) + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/boards/common/esp_video.cc" + "${XIAOZHI_MAIN_DIR}/boards/common/rndis_board.cc" + ) +endif() + +# Include Esp32Camera if target is ESP32S3 +if(CONFIG_IDF_TARGET_ESP32S3) + list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/boards/common/esp32_camera.cc") +endif() + idf_component_register(SRCS ${SOURCES} EMBED_FILES ${LANG_SOUNDS} ${COMMON_SOUNDS} INCLUDE_DIRS ${INCLUDE_DIRS} WHOLE_ARCHIVE + PRIV_REQUIRES + esp_pm + esp_psram + esp_netif + esp_driver_gpio + esp_driver_uart + esp_driver_spi + esp_driver_i2c + esp_driver_i2s + esp_driver_jpeg + esp_driver_ppa + esp_app_format + app_update + spi_flash + console + efuse + bt + fatfs + ArduinoJson + esp-now + mooncake + mooncake_log + smooth_ui_toolkit ) # Use target_compile_definitions to define BOARD_TYPE, BOARD_NAME @@ -265,12 +331,12 @@ target_compile_definitions(${COMPONENT_LIB} # Add generation rules add_custom_command( OUTPUT ${LANG_HEADER} - COMMAND python ${PROJECT_DIR}/xiaozhi-esp32/scripts/gen_lang.py + COMMAND python ${XIAOZHI_MAIN_DIR}/../scripts/gen_lang.py --language "${LANG_DIR}" --output "${LANG_HEADER}" DEPENDS ${LANG_JSON} - ${PROJECT_DIR}/xiaozhi-esp32/scripts/gen_lang.py + ${XIAOZHI_MAIN_DIR}/../scripts/gen_lang.py COMMENT "Generating ${LANG_DIR} language config" ) @@ -328,7 +394,7 @@ endforeach() endif() -set(DEFAULT_ASSETS_EXTRA_FILES "${CMAKE_CURRENT_SOURCE_DIR}/assets/assets_bin") +set(DEFAULT_ASSETS_EXTRA_FILES "${CMAKE_CURRENT_SOURCE_DIR}/assets/assets_bin") # Function to build default assets based on configuration function(build_default_assets_bin) @@ -362,10 +428,10 @@ function(build_default_assets_bin) # Create custom command to build assets add_custom_command( OUTPUT ${GENERATED_ASSETS_BIN} - COMMAND python ${PROJECT_DIR}/xiaozhi-esp32/scripts/build_default_assets.py ${BUILD_ARGS} + COMMAND python ${XIAOZHI_MAIN_DIR}/../scripts/build_default_assets.py ${BUILD_ARGS} DEPENDS ${SDKCONFIG} - ${PROJECT_DIR}/xiaozhi-esp32/scripts/build_default_assets.py + ${XIAOZHI_MAIN_DIR}/../scripts/build_default_assets.py COMMENT "Building default assets.bin based on configuration" VERBATIM ) @@ -452,6 +518,14 @@ if ("${size}" AND "${offset}") get_assets_local_file("${CONFIG_CUSTOM_ASSETS_FILE}" ASSETS_LOCAL_FILE) esptool_py_flash_to_partition(flash "assets" "${ASSETS_LOCAL_FILE}") message(STATUS "Custom assets flash configured: ${ASSETS_LOCAL_FILE} -> assets partition") + elseif(CONFIG_FLASH_EXPRESSION_ASSETS) + set(ASSETS_NAME "expression_assets") + set(ASSETS_PARTITION "assets") + set(ASSETS_FILE "${CMAKE_BINARY_DIR}/${ASSETS_NAME}.bin") + + build_speaker_assets_bin("${ASSETS_PARTITION}" ${EMOTE_RESOLUTION} ${ASSETS_FILE} ${CONFIG_MMAP_FILE_NAME_LENGTH}) + message(STATUS "Generated emote assets: ${ASSETS_FILE} -> ${ASSETS_PARTITION} partition") + esptool_py_flash_to_partition(flash "${ASSETS_PARTITION}" "${ASSETS_FILE}") elseif(CONFIG_FLASH_NONE_ASSETS) message(STATUS "Assets flashing disabled (FLASH_NONE_ASSETS)") endif() diff --git a/firmware/main/Kconfig.projbuild b/firmware/main/Kconfig.projbuild index 6f503f3..304e48d 100644 --- a/firmware/main/Kconfig.projbuild +++ b/firmware/main/Kconfig.projbuild @@ -8,7 +8,8 @@ config OTA_URL choice prompt "Flash Assets" - default FLASH_DEFAULT_ASSETS + default FLASH_DEFAULT_ASSETS if !USE_EMOTE_MESSAGE_STYLE + default FLASH_EXPRESSION_ASSETS if USE_EMOTE_MESSAGE_STYLE help Select the assets to flash. @@ -16,8 +17,12 @@ choice bool "Do not flash assets" config FLASH_DEFAULT_ASSETS bool "Flash Default Assets" + depends on !USE_EMOTE_MESSAGE_STYLE config FLASH_CUSTOM_ASSETS bool "Flash Custom Assets" + config FLASH_EXPRESSION_ASSETS + bool "Flash Emote Assets" + depends on USE_EMOTE_MESSAGE_STYLE endchoice config CUSTOM_ASSETS_FILE @@ -129,6 +134,9 @@ choice BOARD_TYPE config BOARD_TYPE_BREAD_COMPACT_ML307 bool "Bread Compact ML307/EC801E (面包板 4G)" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_BREAD_COMPACT_NT26 + bool "Bread Compact NT26 (面包板 4G)" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_BREAD_COMPACT_ESP32 bool "Bread Compact ESP32 DevKit (面包板)" depends on IDF_TARGET_ESP32 @@ -147,9 +155,15 @@ choice BOARD_TYPE config BOARD_TYPE_ESP_KORVO2_V3 bool "Espressif Korvo2 V3" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_ESP_KORVO2_V3_RNDIS + bool "Espressif Korvo2 V3 RNDIS" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_ESP_SPARKBOT bool "Espressif SparkBot" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_ESP_SENSAIRSHUTTLE + bool "Espressif ESP-SensairShuttle" + depends on IDF_TARGET_ESP32C5 config BOARD_TYPE_ESP_SPOT_S3 bool "Espressif Spot-S3" depends on IDF_TARGET_ESP32S3 @@ -201,6 +215,15 @@ choice BOARD_TYPE config BOARD_TYPE_LICHUANG_DEV_C3 bool "立创·实战派 ESP32-C3" depends on IDF_TARGET_ESP32C3 + config BOARD_TYPE_EDA_TV_PRO + bool "EDA课程案例 EDA-TV-Pro" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_EDA_ROBOT_PRO + bool "EDA课程案例 EDA-Robot-Pro" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_EDA_SUPER_BEAR + bool "EDA课程案例 EDA-Super-Bear" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_DF_K10 bool "DFRobot 行空板 k10" depends on IDF_TARGET_ESP32S3 @@ -240,77 +263,110 @@ choice BOARD_TYPE config BOARD_TYPE_M5STACK_ATOM_ECHOS3R bool "M5Stack AtomEchoS3R" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_M5STACK_CARDPUTER_ADV + bool "M5Stack Cardputer Adv" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_M5STACK_ATOM_MATRIX_ECHO_BASE bool "M5Stack AtomMatrix + Echo Base" depends on IDF_TARGET_ESP32 - config BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD + config BOARD_TYPE_WAVESHARE_ESP32_TOUCH_LCD_3_5 + bool "Waveshare ESP32-Touch-LCD-3.5" + depends on IDF_TARGET_ESP32 + config BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD bool "Waveshare ESP32-S3-Audio-Board" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_8 bool "Waveshare ESP32-S3-Touch-AMOLED-1.8" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06 + config BOARD_TYPE_WAVESHARE_ESP32_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 + config BOARD_TYPE_WAVESHARE_ESP32_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 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75 bool "Waveshare ESP32-S3-Touch-AMOLED-1.75" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75C + bool "Waveshare ESP32-S3-Touch-AMOLED-1.75C" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_83 bool "Waveshare ESP32-S3-Touch-LCD-1.83" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4B bool "Waveshare ESP32-S3-Touch-LCD-4B" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C + bool "Waveshare ESP32-S3-Touch-LCD-4.3C" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85C bool "Waveshare ESP32-S3-Touch-LCD-1.85C" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85 bool "Waveshare ESP32-S3-Touch-LCD-1.85" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_46 bool "Waveshare ESP32-S3-Touch-LCD-1.46" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_C6_LCD_1_69 + config BOARD_TYPE_WAVESHARE_ESP32_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 + config BOARD_TYPE_WAVESHARE_ESP32_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 + config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_43 bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43" depends on IDF_TARGET_ESP32C6 - config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_32 + config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_32 bool "Waveshare ESP32-C6-Touch-AMOLOED-1.32" depends on IDF_TARGET_ESP32C6 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_32 + config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_8 + bool "Waveshare ESP32-C6-Touch-AMOLED-1.8" + depends on IDF_TARGET_ESP32C6 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_32 bool "Waveshare ESP32-S3-Touch-AMOLOED-1.32" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49 bool "Waveshare ESP32-S3-Touch-LCD-3.49" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5 + config BOARD_TYPE_WAVESHARE_ESP32_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" + config BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_1_54_v1 + bool "Waveshare ESP32-S3-ePaper-1.54_v1" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B + config BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_1_54_v2 + bool "Waveshare ESP32-S3-ePaper-1.54_v2" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2 + bool "Waveshare ESP32-S3-RLCD-4.2" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_5B bool "Waveshare ESP32-S3-Touch-LCD-3.5B" depends on IDF_TARGET_ESP32S3 - config BOARD_TYPE_WAVESHARE_P4_NANO + config BOARD_TYPE_WAVESHARE_ESP32_P4_NANO bool "Waveshare ESP32-P4-NANO" depends on IDF_TARGET_ESP32P4 - config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4B" depends on IDF_TARGET_ESP32P4 - config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-7B" depends on IDF_TARGET_ESP32P4 - config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC - bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C or ESP32-P4-WIFI6-Touch-LCD-4C" + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C + bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C" + depends on IDF_TARGET_ESP32P4 + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C + bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C" + depends on IDF_TARGET_ESP32P4 + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7 + bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-7" + depends on IDF_TARGET_ESP32P4 + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 + bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-8" + depends on IDF_TARGET_ESP32P4 + config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1 + bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-10.1" depends on IDF_TARGET_ESP32P4 config BOARD_TYPE_TUDOUZI bool "土豆子" @@ -390,6 +446,9 @@ choice BOARD_TYPE config BOARD_TYPE_XINGZHI_METAL_1_54_WIFI bool "无名科技星智1.54 METAL(wifi)" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_XINGZHI_ABS_2_0 + bool "无名科技星智ABS 2.0" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER bool "Seeed Studio SenseCAP Watcher" depends on IDF_TARGET_ESP32S3 @@ -414,6 +473,12 @@ choice BOARD_TYPE config BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307 bool "征辰科技1.54(ML307)" depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_ZHENGCHEN_CAM + bool "征辰科技AI Camera" + depends on IDF_TARGET_ESP32S3 + config BOARD_TYPE_ZHENGCHEN_CAM_ML307 + bool "征辰科技AI Camera(ML307)" + depends on IDF_TARGET_ESP32S3 config BOARD_TYPE_MINSI_K08_DUAL bool "敏思科技K08(DUAL)" depends on IDF_TARGET_ESP32S3 @@ -486,7 +551,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 || BOARD_TYPE_HU_087 + depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_NT26 || BOARD_TYPE_BREAD_COMPACT_ESP32 || BOARD_TYPE_HU_087 prompt "OLED Type" default OLED_SSD1306_128X32 help @@ -500,7 +565,7 @@ choice DISPLAY_OLED_TYPE endchoice choice DISPLAY_LCD_TYPE - depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_CGC || BOARD_TYPE_WAVESHARE_P4_NANO || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM + depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_CGC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM prompt "LCD Type" default LCD_ST7789_240X320 help @@ -535,20 +600,12 @@ choice DISPLAY_LCD_TYPE bool "ILI9341 240*320, Non-IPS" config LCD_GC9A01_240X240 bool "GC9A01 240*240 Circle" - config LCD_TYPE_800_1280_10_1_INCH - bool "Waveshare 101M-8001280-IPS-CT-K Display" - config LCD_TYPE_800_1280_10_1_INCH_A - bool "Waveshare 10.1-DSI-TOUCH-A Display" - config LCD_TYPE_800_800_3_4_INCH - bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C with 800*800 3.4inch round display" - config LCD_TYPE_720_720_4_INCH - bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C with 720*720 4inch round display" config LCD_CUSTOM bool "Custom LCD (自定义屏幕参数)" endchoice choice DISPLAY_ESP32S3_KORVO2_V3 - depends on BOARD_TYPE_ESP_KORVO2_V3 + depends on BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_ESP_KORVO2_V3_RNDIS prompt "ESP32S3_KORVO2_V3 LCD Type" default ESP32S3_KORVO2_V3_LCD_ST7789 help @@ -560,7 +617,7 @@ choice DISPLAY_ESP32S3_KORVO2_V3 endchoice choice DISPLAY_ESP32S3_AUDIO_BOARD - depends on BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD + depends on BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD prompt "ESP32S3_AUDIO_BOARD LCD Type" default AUDIO_BOARD_LCD_JD9853 help @@ -571,6 +628,19 @@ choice DISPLAY_ESP32S3_AUDIO_BOARD bool "ST7789 240*320" endchoice +choice DISPLAY_ESP32S3_TOUCH_LCD_1_85C + depends on BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85C + prompt "ESP32S3_TOUCH_LCD_1_85C version" + default VERSION_2_0 + help + hardware version + config VERSION_1_0 + bool "version 1.0" + config VERSION_2_0 + bool "version 2.0" +endchoice + + choice DISPLAY_STYLE prompt "Select display style" default USE_DEFAULT_MESSAGE_STYLE @@ -585,9 +655,22 @@ choice DISPLAY_STYLE config USE_EMOTE_MESSAGE_STYLE bool "Emote animation style" - depends on BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ECHOEAR || BOARD_TYPE_LICHUANG_DEV_S3 + depends on BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_3 \ + || BOARD_TYPE_ECHOEAR || BOARD_TYPE_LICHUANG_DEV_S3 \ + || BOARD_TYPE_ESP_SENSAIRSHUTTLE endchoice +config USE_MULTILINE_CHAT_MESSAGE + bool "Use multiline chat message display (default mode only)" + depends on USE_DEFAULT_MESSAGE_STYLE + default n + help + When enabled, the chat message area in the default display mode shows + multiple wrapped lines that grow upward from the bottom of the screen, + with auto-adaptive height. + When disabled (default), a single-line horizontally scrolling label + is shown at the bottom of the screen. + choice WAKE_WORD_TYPE prompt "Wake Word Implementation Type" default USE_AFE_WAKE_WORD if (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM @@ -649,6 +732,16 @@ config SEND_WAKE_WORD_DATA help Send wake word data to the server as the first message of the conversation and wait for response +config WAKE_WORD_DETECTION_IN_LISTENING + bool "Enable Wake Word Detection in Listening Mode" + default n + depends on USE_AFE_WAKE_WORD || USE_CUSTOM_WAKE_WORD + help + Enable wake word detection while in listening mode. + When enabled, the device can detect wake word during listening, + which allows interrupting the current conversation. + When disabled (default), wake word detection is turned off during listening. + config USE_AUDIO_PROCESSOR bool "Enable Audio Noise Reduction" default y @@ -660,10 +753,12 @@ config USE_DEVICE_AEC bool "Enable Device-Side AEC" default n depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE \ - || BOARD_TYPE_LICHUANG_DEV_S3 || BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83\ - || BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B \ - || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \ - || BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49) + || BOARD_TYPE_LICHUANG_DEV_S3 || BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75C || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_83\ + || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B \ + || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \ + || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7 || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1 \ + || BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49 || BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2 || BOARD_TYPE_ZHENGCHEN_CAM || BOARD_TYPE_ZHENGCHEN_CAM_ML307 \ + || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C) help To work properly, device-side AEC requires a clean output reference path from the speaker signal and physical acoustic isolation between the microphone and speaker. 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 ada6662..054dc44 100644 --- a/firmware/main/apps/app_ai_agent/app_ai_agent.cpp +++ b/firmware/main/apps/app_ai_agent/app_ai_agent.cpp @@ -20,7 +20,8 @@ AppAiAgent::AppAiAgent() // Configure App name setAppInfo().name = "AI.AGENT"; // Configure App icon - setAppInfo().icon = (void*)&icon_ai_agent; + static auto icon = assets::get_image("icon_ai_agent.bin"); + setAppInfo().icon = (void*)&icon; // Configure App theme color static uint32_t theme_color = 0x33CC99; setAppInfo().userData = (void*)&theme_color; diff --git a/firmware/main/apps/app_app_center/app_app_center.cpp b/firmware/main/apps/app_app_center/app_app_center.cpp new file mode 100644 index 0000000..5719d8a --- /dev/null +++ b/firmware/main/apps/app_app_center/app_app_center.cpp @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include "app_app_center.h" +#include +#include +#include +#include +#include +#include + +using namespace mooncake; +using namespace smooth_ui_toolkit::lvgl_cpp; + +AppAppCenter::AppAppCenter() +{ + // 配置 App 名 + setAppInfo().name = "APP.CENTER"; + // 配置 App 图标 + static auto icon = assets::get_image("icon_app_center.bin"); + setAppInfo().icon = (void*)&icon; + // 配置 App 主题颜色 + static uint32_t theme_color = 0xF4A354; + setAppInfo().userData = (void*)&theme_color; +} + +void AppAppCenter::onCreate() +{ + mclog::tagInfo(getAppInfo().name, "on create"); +} + +void AppAppCenter::onOpen() +{ + mclog::tagInfo(getAppInfo().name, "on open"); + + // Create loading page + std::unique_ptr loading_page; + { + LvglLockGuard lock; + loading_page = std::make_unique(0xF4A354, 0x332609); + } + + // Start network + GetHAL().startNetwork([&](std::string_view msg) { + LvglLockGuard lock; + loading_page->setMessage(msg); + }); + + // Fetch app list + { + LvglLockGuard lock; + loading_page->setMessage("Fetching app list..."); + } + _app_list = GetHAL().fetchAppList(); + + LvglLockGuard lock; + + // Destroy loading page + loading_page.reset(); + + _app_list_page = std::make_unique(_app_list); + + view::create_home_indicator([&]() { close(); }, 0xFFDF9A, 0x47330A); + view::create_status_bar(0xFFDF9A, 0x47330A); +} + +void AppAppCenter::onRunning() +{ + if (_launch_requested) { + GetHAL().launchApp(_app_list[_selected_index].firmwareUrl, [&](int percent) { + LvglLockGuard lock; + if (_app_install_page) { + _app_install_page->setProgress(percent); + } + }); + } + + LvglLockGuard lock; + + if (_app_list_page) { + _selected_index = _app_list_page->isSelected(); + if (_selected_index >= 0) { + mclog::tagInfo(getAppInfo().name, "selected index: {}", _selected_index); + _app_list_page.reset(); + _app_detail_page = std::make_unique(_app_list[_selected_index]); + } + } + + if (_app_detail_page) { + if (_app_detail_page->checkBack()) { + mclog::tagInfo(getAppInfo().name, "back to app list"); + _app_detail_page.reset(); + _app_list_page = std::make_unique(_app_list); + } else if (_app_detail_page->checkLaunch()) { + mclog::tagInfo(getAppInfo().name, "launch app"); + _app_detail_page.reset(); + _app_install_page = std::make_unique(_app_list[_selected_index]); + _launch_requested = true; + } + } + + view::update_home_indicator(); + view::update_status_bar(); +} + +void AppAppCenter::onClose() +{ + mclog::tagInfo(getAppInfo().name, "on close"); + + LvglLockGuard lock; + + _app_list.clear(); + _app_list_page.reset(); + _app_detail_page.reset(); + _app_install_page.reset(); + _selected_index = -1; + _launch_requested = false; + + view::destroy_home_indicator(); + view::destroy_status_bar(); + + GetHAL().requestWarmReboot(3); +} diff --git a/firmware/main/apps/app_app_center/app_app_center.h b/firmware/main/apps/app_app_center/app_app_center.h new file mode 100644 index 0000000..688b4d9 --- /dev/null +++ b/firmware/main/apps/app_app_center/app_app_center.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include "view/view.h" +#include + +/** + * @brief 派生 App + * + */ +class AppAppCenter : public mooncake::AppAbility { +public: + AppAppCenter(); + + // 重写生命周期回调 + void onCreate() override; + void onOpen() override; + void onRunning() override; + void onClose() override; + +private: + std::vector _app_list; + std::unique_ptr _app_list_page; + std::unique_ptr _app_detail_page; + std::unique_ptr _app_install_page; + int _selected_index = -1; + bool _launch_requested = false; +}; diff --git a/firmware/main/apps/app_app_center/view/view.h b/firmware/main/apps/app_app_center/view/view.h new file mode 100644 index 0000000..7c42912 --- /dev/null +++ b/firmware/main/apps/app_app_center/view/view.h @@ -0,0 +1,278 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace view { + +/** + * @brief + * + */ +class AppListPage { +public: + AppListPage(const app_center::AppInfoList_t& app_list) + + { + _panel = std::make_unique(lv_screen_active()); + _panel->setSize(320, 240); + _panel->setAlign(LV_ALIGN_CENTER); + _panel->setBgColor(lv_color_hex(0xFFFAD6)); + _panel->setFlexFlow(LV_FLEX_FLOW_COLUMN); + _panel->setFlexAlign(LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + _panel->setPadding(52, 72, 0, 0); + _panel->setPadRow(18); + _panel->setRadius(0); + _panel->setBorderWidth(0); + _panel->setScrollbarMode(LV_SCROLLBAR_MODE_ACTIVE); + + _bg_image = assets::get_image("app_center_bg.png"); + if (_bg_image.data_size != 0) { + lv_obj_set_style_bg_image_src(_panel->get(), &_bg_image, LV_PART_MAIN); + } + + _title_panel = std::make_unique(lv_screen_active()); + _title_panel->setSize(320, 28); + _title_panel->align(LV_ALIGN_TOP_MID, 0, 0); + _title_panel->setBgColor(lv_color_hex(0xF4A354)); + _title_panel->setPadding(0, 0, 0, 0); + _title_panel->setRadius(0); + _title_panel->setBorderWidth(0); + _title_panel->setScrollbarMode(LV_SCROLLBAR_MODE_ACTIVE); + + _title = std::make_unique(*_title_panel); + _title->setText("App Center"); + _title->setTextFont(&lv_font_montserrat_16); + _title->setTextColor(lv_color_hex(0xFFF8C7)); + _title->align(LV_ALIGN_CENTER, 0, 0); + + int index = 0; + for (const auto& app : app_list) { + auto btn = std::make_unique(*_panel); + btn->setSize(282, 52); + btn->setRadius(18); + btn->setBorderWidth(0); + btn->setShadowWidth(0); + btn->setBgColor(lv_color_hex(0xFFDF9A)); + + btn->label().setText(app.name); + btn->label().setTextFont(&lv_font_montserrat_20); + btn->label().setTextColor(lv_color_hex(0x47330A)); + btn->label().setLongMode(LV_LABEL_LONG_SCROLL_CIRCULAR); + btn->label().setWidth(220); + btn->label().setTextAlign(LV_TEXT_ALIGN_CENTER); + btn->label().setAlign(LV_ALIGN_CENTER); + + btn->onClick().connect([this, index]() { _clicked_index = index; }); + + _buttons.push_back(std::move(btn)); + index++; + } + } + + int isSelected() + { + int temp = _clicked_index; + _clicked_index = -1; + return temp; + } + +private: + std::unique_ptr _panel; + std::unique_ptr _title_panel; + std::unique_ptr _title; + std::vector> _buttons; + lv_image_dsc_t _bg_image; + + int _clicked_index = -1; +}; + +/** + * @brief + * + */ +class AppDetailPage { +public: + AppDetailPage(const app_center::AppInfo_t& app_info) + { + _panel = std::make_unique(lv_screen_active()); + _panel->setBgColor(lv_color_hex(0xFFFAD6)); + _panel->align(LV_ALIGN_CENTER, 0, 0); + _panel->setBorderWidth(0); + _panel->setSize(320, 240); + _panel->setRadius(0); + _panel->setFlexFlow(LV_FLEX_FLOW_COLUMN); + _panel->setFlexAlign(LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + _panel->setPadding(48, 72, 0, 0); + _panel->setPadRow(18); + _panel->setScrollbarMode(LV_SCROLLBAR_MODE_ACTIVE); + + _bg_image = assets::get_image("app_center_bg.png"); + if (_bg_image.data_size != 0) { + lv_obj_set_style_bg_image_src(_panel->get(), &_bg_image, LV_PART_MAIN); + } + + _title = std::make_unique(*_panel); + _title->setText(app_info.name); + _title->setTextFont(&lv_font_montserrat_20); + _title->setTextColor(lv_color_hex(0x47330A)); + _title->setTextAlign(LV_TEXT_ALIGN_CENTER); + _title->setLongMode(LV_LABEL_LONG_SCROLL_CIRCULAR); + _title->setWidth(220); + _title->setHeight(28); + + _desc_label = std::make_unique(*_panel); + _desc_label->setText(app_info.description); + _desc_label->setTextFont(&lv_font_montserrat_20); + _desc_label->setTextColor(lv_color_hex(0x47330A)); + _desc_label->setTextAlign(LV_TEXT_ALIGN_LEFT); + _desc_label->setWidth(260); + _desc_label->setLongMode(LV_LABEL_LONG_WRAP); + + _btn_container = std::make_unique(*_panel); + _btn_container->setSize(LV_PCT(100), 80); + _btn_container->setBgOpa(LV_OPA_TRANSP); + _btn_container->setBorderWidth(0); + _btn_container->setPadding(0, 0, 0, 0); + _btn_container->setPadColumn(28); + _btn_container->setFlexFlow(LV_FLEX_FLOW_ROW); + _btn_container->setFlexAlign(LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + + _btn_back = std::make_unique(*_btn_container); + _btn_back->setSize(112, 48); + _btn_back->setRadius(18); + _btn_back->setBgColor(lv_color_hex(0xFFDF9A)); + _btn_back->setBorderWidth(0); + _btn_back->setShadowWidth(0); + _btn_back->label().setText("Back"); + _btn_back->label().setTextFont(&lv_font_montserrat_20); + _btn_back->label().setTextColor(lv_color_hex(0x47330A)); + _btn_back->onClick().connect([this]() { _is_back = true; }); + + _btn_launch = std::make_unique(*_btn_container); + _btn_launch->setSize(112, 48); + _btn_launch->setRadius(18); + _btn_launch->setBgColor(lv_color_hex(0xFFAC6D)); + _btn_launch->setBorderWidth(0); + _btn_launch->setShadowWidth(0); + _btn_launch->label().setText("Launch"); + _btn_launch->label().setTextFont(&lv_font_montserrat_20); + _btn_launch->label().setTextColor(lv_color_hex(0x47330A)); + _btn_launch->onClick().connect([this]() { _is_launch = true; }); + } + + bool checkBack() + { + if (_is_back) { + _is_back = false; + return true; + } + return false; + } + + bool checkLaunch() + { + if (_is_launch) { + _is_launch = false; + return true; + } + return false; + } + +private: + std::unique_ptr _panel; + std::unique_ptr _title; + std::unique_ptr _desc_label; + std::unique_ptr _btn_container; + std::unique_ptr _btn_back; + std::unique_ptr _btn_launch; + lv_image_dsc_t _bg_image; + + bool _is_back = false; + bool _is_launch = false; +}; + +/** + * @brief + * + */ +class AppInstallPage { +public: + AppInstallPage(const app_center::AppInfo_t& app_info) + { + _panel = std::make_unique(lv_screen_active()); + _panel->setBgColor(lv_color_hex(0xFFFAD6)); + _panel->align(LV_ALIGN_CENTER, 0, 0); + _panel->setBorderWidth(0); + _panel->setSize(320, 240); + _panel->setRadius(0); + _panel->setPadding(0, 0, 0, 0); + + _bg_image = assets::get_image("app_center_bg.png"); + if (_bg_image.data_size != 0) { + lv_obj_set_style_bg_image_src(_panel->get(), &_bg_image, LV_PART_MAIN); + } + + _title = std::make_unique(*_panel); + _title->setText(app_info.name); + _title->setTextFont(&lv_font_montserrat_20); + _title->setTextColor(lv_color_hex(0x47330A)); + _title->setTextAlign(LV_TEXT_ALIGN_CENTER); + _title->align(LV_ALIGN_TOP_MID, 0, 15); + _title->setLongMode(LV_LABEL_LONG_SCROLL_CIRCULAR); + _title->setWidth(220); + _title->setHeight(28); + + _tips = std::make_unique(*_panel); + _tips->setText("Downloading..."); + _tips->setTextFont(&lv_font_montserrat_16); + _tips->setTextColor(lv_color_hex(0xA36135)); + _tips->setTextAlign(LV_TEXT_ALIGN_CENTER); + _tips->setLongMode(LV_LABEL_LONG_SCROLL_CIRCULAR); + _tips->align(LV_ALIGN_CENTER, 0, -40); + + _progress_bar = std::make_unique(*_panel); + _progress_bar->setSize(260, 92); + _progress_bar->setRadius(18); + _progress_bar->setRadius(0, LV_PART_INDICATOR); + _progress_bar->align(LV_ALIGN_CENTER, 0, 23); + _progress_bar->setBgColor(lv_color_hex(0xFFDF9A)); + _progress_bar->setBgColor(lv_color_hex(0xFF9E5D), LV_PART_INDICATOR); + _progress_bar->setBgOpa(LV_OPA_COVER); + _progress_bar->setRange(0, 100); + _progress_bar->setValue(0); + + _progress = std::make_unique(*_panel); + _progress->setTextFont(&lv_font_montserrat_24); + _progress->setTextColor(lv_color_hex(0x47330A)); + _progress->align(LV_ALIGN_CENTER, 0, 23); + _progress->setText(""); + } + + void setProgress(int percent) + { + _progress->setText(fmt::format("{}%", percent)); + _progress_bar->setValue(percent); + } + +private: + std::unique_ptr _panel; + std::unique_ptr _title; + std::unique_ptr _tips; + std::unique_ptr _progress; + std::unique_ptr _progress_bar; + lv_image_dsc_t _bg_image; +}; + +} // namespace view diff --git a/firmware/main/apps/app_avatar/app_avatar.cpp b/firmware/main/apps/app_avatar/app_avatar.cpp index 74d2f5c..d1e713d 100644 --- a/firmware/main/apps/app_avatar/app_avatar.cpp +++ b/firmware/main/apps/app_avatar/app_avatar.cpp @@ -47,7 +47,8 @@ AppAvatar::AppAvatar() // 配置 App 名 setAppInfo().name = "AVATAR"; // 配置 App 图标 - setAppInfo().icon = (void*)&icon_sentinel; + static auto icon = assets::get_image("icon_sentinel.bin"); + setAppInfo().icon = (void*)&icon; // 配置 App 主题颜色 static uint32_t theme_color = 0xFF6699; setAppInfo().userData = (void*)&theme_color; diff --git a/firmware/main/apps/app_dance/app_dance.cpp b/firmware/main/apps/app_dance/app_dance.cpp new file mode 100644 index 0000000..ebd3d4c --- /dev/null +++ b/firmware/main/apps/app_dance/app_dance.cpp @@ -0,0 +1,155 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include "app_dance.h" +#include +#include +#include +#include +#include +#include + +using namespace mooncake; +using namespace stackchan; + +AppDance::AppDance() +{ + // 配置 App 名 + setAppInfo().name = "DANCE"; + // 配置 App 图标 + static auto icon = assets::get_image("icon_dance.bin"); + setAppInfo().icon = (void*)&icon; + // 配置 App 主题颜色 + static uint32_t theme_color = 0xB77BFF; + setAppInfo().userData = (void*)&theme_color; +} + +// App 被安装时会被调用 +void AppDance::onCreate() +{ + mclog::tagInfo(getAppInfo().name, "on create"); +} + +void AppDance::onOpen() +{ + mclog::tagInfo(getAppInfo().name, "on open"); + + // Create loading page + std::unique_ptr loading_page; + { + LvglLockGuard lock; + loading_page = std::make_unique(0xB77BFF, 0x422268); + loading_page->setMessage("Starting\n BLE server..."); + } + + // Start BLE service + GetHAL().startBleServer(); + + 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 ------------------------------- */ + GetHAL().onBleAvatarData.connect([&](const char* data) { + std::lock_guard lock(_mutex); + if (_ble_avatar_data.update_flag) { + return; + } + _ble_avatar_data.update_flag = true; + _ble_avatar_data.data_ptr = (char*)data; + }); + + GetHAL().onBleMotionData.connect([&](const char* data) { + std::lock_guard lock(_mutex); + if (_ble_motion_data.update_flag) { + return; + } + _ble_motion_data.update_flag = true; + _ble_motion_data.data_ptr = (char*)data; + }); + + GetHAL().onBleRgbData.connect([&](const char* data) { + std::lock_guard lock(_mutex); + if (_ble_rgb_data.update_flag) { + return; + } + _ble_rgb_data.update_flag = true; + _ble_rgb_data.data_ptr = (char*)data; + }); + + /* ----------------------------- Common widgets ----------------------------- */ + view::create_home_indicator([&]() { close(); }, 0xB77BFF, 0x422268); + view::create_status_bar(0xB77BFF, 0x422268); +} + +void AppDance::onRunning() +{ + std::lock_guard lock(_mutex); + + LvglLockGuard lvgl_lock; + + if (_ble_avatar_data.update_flag) { + GetStackChan().updateAvatarFromJson(_ble_avatar_data.data_ptr); + _ble_avatar_data.update_flag = false; + _ble_avatar_data.data_ptr = nullptr; + } + + if (_ble_motion_data.update_flag) { + check_auto_angle_sync_mode(); + GetStackChan().updateMotionFromJson(_ble_motion_data.data_ptr); + _ble_motion_data.update_flag = false; + _ble_motion_data.data_ptr = nullptr; + } + + if (_ble_rgb_data.update_flag) { + GetStackChan().updateNeonLightFromJson(_ble_rgb_data.data_ptr); + _ble_rgb_data.update_flag = false; + _ble_rgb_data.data_ptr = nullptr; + } + + GetStackChan().update(); + + view::update_home_indicator(); + view::update_status_bar(); +} + +void AppDance::onClose() +{ + mclog::tagInfo(getAppInfo().name, "on close"); + + { + LvglLockGuard lock; + + GetStackChan().resetAvatar(); + + GetHAL().onBleAvatarData.clear(); + GetHAL().onBleMotionData.clear(); + + view::destroy_home_indicator(); + view::destroy_status_bar(); + } + + GetHAL().requestWarmReboot(5); +} + +void AppDance::check_auto_angle_sync_mode() +{ + auto& motion = GetStackChan().motion(); + + // If far from last command, enable auto angle sync + if (GetHAL().millis() - _last_motion_cmd_tick > 2000) { + motion.setAutoAngleSyncEnabled(true); + } else { + motion.setAutoAngleSyncEnabled(false); + } + + _last_motion_cmd_tick = GetHAL().millis(); +} diff --git a/firmware/main/apps/app_dance/app_dance.h b/firmware/main/apps/app_dance/app_dance.h new file mode 100644 index 0000000..6b51113 --- /dev/null +++ b/firmware/main/apps/app_dance/app_dance.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include +#include +#include + +/** + * @brief + * + */ +class AppDance : public mooncake::AppAbility { +public: + AppDance(); + + void onCreate() override; + void onOpen() override; + void onRunning() override; + void onClose() override; + +private: + std::mutex _mutex; + + struct BleHandlerData_t { + bool update_flag = false; + char* data_ptr = nullptr; + }; + BleHandlerData_t _ble_avatar_data; + BleHandlerData_t _ble_motion_data; + BleHandlerData_t _ble_rgb_data; + + uint32_t _last_motion_cmd_tick = 0; + + void check_auto_angle_sync_mode(); +}; 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 3752a23..f85ce60 100644 --- a/firmware/main/apps/app_espnow_ctrl/app_espnow_ctrl.cpp +++ b/firmware/main/apps/app_espnow_ctrl/app_espnow_ctrl.cpp @@ -26,7 +26,8 @@ AppEspnowControl::AppEspnowControl() // 配置 App 名 setAppInfo().name = "ESPNOW.REMOTE"; // 配置 App 图标 - setAppInfo().icon = (void*)&icon_controller; + static auto icon = assets::get_image("icon_controller.bin"); + setAppInfo().icon = (void*)&icon; // 配置 App 主题颜色 static uint32_t theme_color = 0x7ACE74; setAppInfo().userData = (void*)&theme_color; 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 330114c..abb2dc5 100644 --- a/firmware/main/apps/app_espnow_ctrl/view/page_selector.h +++ b/firmware/main/apps/app_espnow_ctrl/view/page_selector.h @@ -80,7 +80,7 @@ private: * @param options * @return int Selected option index */ -static inline int create_page_selector_and_wait(std::string_view label, const std::vector options) +static inline int create_page_selector_and_wait(std::string_view label, const std::vector& options) { GetHAL().lvglLock(); auto page_selector = std::make_unique(label, options); diff --git a/firmware/main/apps/app_ezdata/app_ezdata.cpp b/firmware/main/apps/app_ezdata/app_ezdata.cpp new file mode 100644 index 0000000..d6cf706 --- /dev/null +++ b/firmware/main/apps/app_ezdata/app_ezdata.cpp @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include "app_ezdata.h" +#include +#include +#include +#include +#include + +using namespace mooncake; +using namespace stackchan; + +AppEzdata::AppEzdata() +{ + // 配置 App 名 + setAppInfo().name = "EZDATA"; + // 配置 App 图标 + static auto icon = assets::get_image("icon_ezdata.bin"); + setAppInfo().icon = (void*)&icon; + // 配置 App 主题颜色 + static uint32_t theme_color = 0x60A5FA; + setAppInfo().userData = (void*)&theme_color; +} + +void AppEzdata::onCreate() +{ + mclog::tagInfo(getAppInfo().name, "on create"); +} + +void AppEzdata::onOpen() +{ + mclog::tagInfo(getAppInfo().name, "on open"); + + { + LvglLockGuard lock; + + // Create default avatar + auto avatar = std::make_unique(); + avatar->init(lv_screen_active()); + GetStackChan().attachAvatar(std::move(avatar)); + + // Create loading page + _loading_page = std::make_unique(0x60A5FA, 0x072448); + } + + // Start ezdata service + GetHAL().startEzDataService([&](std::string_view msg) { + LvglLockGuard lock; + _loading_page->setMessage(msg); + }); + + LvglLockGuard lock; + + /* --------------------------------- Events --------------------------------- */ + GetHAL().onEzdataPairCode.connect([this](std::string_view code) { + LvglLockGuard lock; + + // Destroy loading page + _loading_page.reset(); + + // Client connected + if (code.empty()) { + _ezdata_guide_page.reset(); + return; + } + + _ezdata_guide_page = std::make_unique(code); + }); + // _ezdata_guide_page = std::make_unique("941004"); + + /* ----------------------------- Common widgets ----------------------------- */ + view::create_home_indicator([&]() { close(); }, 0x93C3FE, 0x072448); + view::create_status_bar(0x93C3FE, 0x072448); +} + +void AppEzdata::onRunning() +{ + LvglLockGuard lock; + + GetStackChan().update(); + + view::update_home_indicator(); + view::update_status_bar(); +} + +void AppEzdata::onClose() +{ + mclog::tagInfo(getAppInfo().name, "on close"); + + LvglLockGuard lock; + + GetStackChan().resetAvatar(); + + view::destroy_home_indicator(); + view::destroy_status_bar(); + + GetHAL().requestWarmReboot(4); +} diff --git a/firmware/main/apps/app_ezdata/app_ezdata.h b/firmware/main/apps/app_ezdata/app_ezdata.h new file mode 100644 index 0000000..70f2647 --- /dev/null +++ b/firmware/main/apps/app_ezdata/app_ezdata.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include "view/view.h" +#include +#include + +/** + * @brief 派生 App + * + */ +class AppEzdata : public mooncake::AppAbility { +public: + AppEzdata(); + + void onCreate() override; + void onOpen() override; + void onRunning() override; + void onClose() override; + +private: + std::unique_ptr _loading_page; + std::unique_ptr _ezdata_guide_page; +}; diff --git a/firmware/main/apps/app_ezdata/view/view.h b/firmware/main/apps/app_ezdata/view/view.h new file mode 100644 index 0000000..d5980b7 --- /dev/null +++ b/firmware/main/apps/app_ezdata/view/view.h @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace view { + +/** + * @brief + * + */ +class EzdataGuidePage { +public: + EzdataGuidePage(std::string_view pairCode) + { + _panel = std::make_unique(lv_screen_active()); + _panel->setBgColor(lv_color_hex(0x60A5FA)); + _panel->align(LV_ALIGN_CENTER, 0, 0); + _panel->setBorderWidth(0); + _panel->setSize(320, 240); + _panel->setRadius(0); + _panel->setPadding(0, 0, 0, 0); + + _panel_url = std::make_unique(*_panel); + _panel_url->setScrollbarMode(LV_SCROLLBAR_MODE_OFF); + _panel_url->setBgColor(lv_color_hex(0xFFFFFF)); + _panel_url->align(LV_ALIGN_TOP_MID, 0, 42); + _panel_url->setBorderWidth(0); + _panel_url->setSize(296, 51); + _panel_url->setRadius(18); + + _panel_pair_code = std::make_unique(*_panel); + _panel_pair_code->setScrollbarMode(LV_SCROLLBAR_MODE_OFF); + _panel_pair_code->setBgColor(lv_color_hex(0xFFFFFF)); + _panel_pair_code->align(LV_ALIGN_TOP_MID, 0, 138); + _panel_pair_code->setBorderWidth(0); + _panel_pair_code->setSize(296, 86); + _panel_pair_code->setRadius(18); + + _title_url = std::make_unique(*_panel); + _title_url->setText("Ezdata Web client:"); + _title_url->setTextFont(&lv_font_montserrat_16); + _title_url->setTextColor(lv_color_hex(0x0E2648)); + _title_url->align(LV_ALIGN_TOP_LEFT, 27, 16); + + _msg_url = std::make_unique(*_panel_url); + _msg_url->setText("https://my.m5stack.com/ezdata2"); + _msg_url->setTextFont(&lv_font_montserrat_16); + _msg_url->setTextColor(lv_color_hex(0x0E2648)); + _msg_url->align(LV_ALIGN_CENTER, 0, 0); + + _title_pair_code = std::make_unique(*_panel); + _title_pair_code->setText("Pair Code:"); + _title_pair_code->setTextFont(&lv_font_montserrat_16); + _title_pair_code->setTextColor(lv_color_hex(0x0E2648)); + _title_pair_code->align(LV_ALIGN_TOP_LEFT, 27, 113); + + _msg_pair_code = std::make_unique(*_panel_pair_code); + _msg_pair_code->setText(pairCode); + _msg_pair_code->setTextFont(&lv_font_montserrat_24); + _msg_pair_code->setTextColor(lv_color_hex(0x0E2648)); + _msg_pair_code->align(LV_ALIGN_CENTER, 0, 0); + } + +private: + std::unique_ptr _panel; + std::unique_ptr _panel_url; + std::unique_ptr _panel_pair_code; + std::unique_ptr _title_url; + std::unique_ptr _msg_url; + std::unique_ptr _title_pair_code; + std::unique_ptr _msg_pair_code; +}; + +} // namespace view diff --git a/firmware/main/apps/app_launcher/view/view.cpp b/firmware/main/apps/app_launcher/view/view.cpp index cf0c939..e9bc15c 100644 --- a/firmware/main/apps/app_launcher/view/view.cpp +++ b/firmware/main/apps/app_launcher/view/view.cpp @@ -394,6 +394,7 @@ void LauncherView::init(std::vector appPorps) _lr_indicator_panels.back()->onClick().connect([scroll_to_nearby_icon]() { scroll_to_nearby_icon(-1); }); _lr_indicators_images.push_back(std::make_unique(_lr_indicator_panels.back()->get())); + static auto icon_indicator_left = assets::get_image("icon_indicator_left.bin"); _lr_indicators_images.back()->setSrc(&icon_indicator_left); _lr_indicators_images.back()->align(LV_ALIGN_CENTER, 0, 0); @@ -409,6 +410,7 @@ void LauncherView::init(std::vector appPorps) _lr_indicator_panels.back()->onClick().connect([scroll_to_nearby_icon]() { scroll_to_nearby_icon(1); }); _lr_indicators_images.push_back(std::make_unique(_lr_indicator_panels.back()->get())); + static auto icon_indicator_right = assets::get_image("icon_indicator_right.bin"); _lr_indicators_images.back()->setSrc(&icon_indicator_right); _lr_indicators_images.back()->align(LV_ALIGN_CENTER, 0, 0); diff --git a/firmware/main/apps/app_setup/app_setup.cpp b/firmware/main/apps/app_setup/app_setup.cpp index 822ea72..a50a917 100644 --- a/firmware/main/apps/app_setup/app_setup.cpp +++ b/firmware/main/apps/app_setup/app_setup.cpp @@ -20,7 +20,8 @@ AppSetup::AppSetup() // 配置 App 名 setAppInfo().name = "SETUP"; // 配置 App 图标 - setAppInfo().icon = (void*)&icon_setup; + static auto icon = assets::get_image("icon_setup.bin"); + setAppInfo().icon = (void*)&icon; // 配置 App 主题颜色 static uint32_t theme_color = 0xB3B3B3; setAppInfo().userData = (void*)&theme_color; @@ -41,61 +42,82 @@ void AppSetup::onOpen() _need_warm_reset = false; _magic_count = 0; - _menu_sections = {{ - "Connectivity", - {{"Set Up Wi-Fi", - [&]() { - _destroy_menu = true; - _need_warm_reset = true; - _worker = std::make_unique(); - }}}, - }, - { - "Servo", - {{"Calibration", - [&]() { - _destroy_menu = true; - _worker = std::make_unique(); - }}, - {"LED Strips Test", - [&]() { - _destroy_menu = true; - _worker = std::make_unique(); - }}}, - }, - { - "Display", - {{"Brightness", - [&]() { - _destroy_menu = true; - _worker = std::make_unique(); - }}}, - }, - { - "System", - {{"Timezone", - [&]() { - _destroy_menu = true; - _worker = std::make_unique(); - }}}, - }, - { - "About", - {{fmt::format("FW Version: {}", common::FirmwareVersion), - [&]() { - _magic_count++; - if (_magic_count >= 10) { - _magic_count = 0; - _destroy_menu = true; - _worker = std::make_unique(); - } - }}, - {"Factory Reset", - [&]() { - _destroy_menu = true; - _worker = std::make_unique(); - }}}, - }}; + _menu_sections = { + { + "Wi-Fi", + {{"Change Wi-Fi", + [&]() { + _destroy_menu = true; + _need_warm_reset = true; + _worker = std::make_unique(); + }}}, + }, + { + "Device", + {{"Brightness", + [&]() { + _destroy_menu = true; + _worker = std::make_unique(); + }}, + {"Volume", + [&]() { + _destroy_menu = true; + _worker = std::make_unique(); + }}, + {"Timezone", + [&]() { + _destroy_menu = true; + _worker = std::make_unique(); + }}}, + }, + { + "Hardware Test", + {{"Servo", + [&]() { + _destroy_menu = true; + _worker = std::make_unique(); + }}, + {"RGB Strip", + [&]() { + _destroy_menu = true; + _worker = std::make_unique(); + }}}, + }, + { + "Account", + {{"Unbind & Reset", + [&]() { + _destroy_menu = true; + _need_warm_reset = true; + _worker = std::make_unique(); + }}}, + }, + { + "Firmware", + { + {fmt::format("Version: {}", common::FirmwareVersion), + [&]() { + _magic_count++; + if (_magic_count >= 10) { + _magic_count = 0; + _destroy_menu = true; + _worker = std::make_unique(); + } + }}, + {"Check for Updates", + [&]() { + _destroy_menu = true; + _need_warm_reset = true; + _worker = std::make_unique(); + }}, + // {"Factory Reset", + // [&]() { + // _destroy_menu = true; + // _worker = std::make_unique(); + // }} + }, + }, + }; LvglLockGuard lock; @@ -146,6 +168,6 @@ void AppSetup::onClose() view::destroy_status_bar(); if (_need_warm_reset) { - GetHAL().requestWarmReboot(3); + GetHAL().requestWarmReboot(6); } } diff --git a/firmware/main/apps/app_setup/workers/about.cpp b/firmware/main/apps/app_setup/workers/about.cpp index 6eb7a3b..43ad8ae 100644 --- a/firmware/main/apps/app_setup/workers/about.cpp +++ b/firmware/main/apps/app_setup/workers/about.cpp @@ -13,6 +13,7 @@ #include #include #include +#include using namespace uitk; using namespace uitk::lvgl_cpp; @@ -294,3 +295,35 @@ void FwVersionWorker::update() _egg->update(); } } + +SystemUpdateWorker::SystemUpdateWorker() +{ + auto loading_page = std::make_unique(0xF6F6F6, 0x26206A); + GetHAL().lvglUnlock(); + + // Start network + GetHAL().startNetwork([&](std::string_view msg) { + LvglLockGuard lock; + loading_page->setMessage(msg); + }); + + // Update Firmware + bool result = GetHAL().updateFirmware([&](std::string_view msg) { + LvglLockGuard lock; + loading_page->setMessage(msg); + }); + + // Hold the result for a while + GetHAL().delay(3000); + + GetHAL().lvglLock(); + _is_done = true; +} + +SystemUpdateWorker::~SystemUpdateWorker() +{ +} + +void SystemUpdateWorker::update() +{ +} diff --git a/firmware/main/apps/app_setup/workers/account.cpp b/firmware/main/apps/app_setup/workers/account.cpp new file mode 100644 index 0000000..fc81885 --- /dev/null +++ b/firmware/main/apps/app_setup/workers/account.cpp @@ -0,0 +1,153 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +#include "workers.h" +#include +#include +#include + +using namespace uitk::lvgl_cpp; +using namespace setup_workers; + +static std::string _tag = "Setup-Account"; + +AccountWorker::PanelInfo::PanelInfo(lv_obj_t* parent, int posY, std::string_view title, std::string_view info) +{ + _panel = std::make_unique(parent); + _panel->setBgColor(lv_color_hex(0xB8D3FD)); + _panel->align(LV_ALIGN_TOP_MID, 0, posY); + _panel->setBorderWidth(0); + _panel->setSize(296, 108); + _panel->setPadding(0, 0, 0, 0); + _panel->setRadius(18); + _panel->removeFlag(LV_OBJ_FLAG_SCROLLABLE); + + _label_title = std::make_unique