mirror of
https://github.com/m5stack/StackChan.git
synced 2026-05-20 11:49:45 -07:00
Merge main into remote-dev
This commit is contained in:
@@ -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)
|
||||
|
||||
+1
-2
@@ -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
|
||||
|
||||
|
||||
+219
-96
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
|
||||
+138
-43
@@ -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.
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "app_app_center.h"
|
||||
#include <hal/hal.h>
|
||||
#include <mooncake.h>
|
||||
#include <mooncake_log.h>
|
||||
#include <assets/assets.h>
|
||||
#include <apps/common/common.h>
|
||||
#include <memory>
|
||||
|
||||
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<view::LoadingPage> loading_page;
|
||||
{
|
||||
LvglLockGuard lock;
|
||||
loading_page = std::make_unique<view::LoadingPage>(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<view::AppListPage>(_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<view::AppDetailPage>(_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<view::AppListPage>(_app_list);
|
||||
} else if (_app_detail_page->checkLaunch()) {
|
||||
mclog::tagInfo(getAppInfo().name, "launch app");
|
||||
_app_detail_page.reset();
|
||||
_app_install_page = std::make_unique<view::AppInstallPage>(_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);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include "view/view.h"
|
||||
#include <mooncake.h>
|
||||
|
||||
/**
|
||||
* @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_center::AppInfo_t> _app_list;
|
||||
std::unique_ptr<view::AppListPage> _app_list_page;
|
||||
std::unique_ptr<view::AppDetailPage> _app_detail_page;
|
||||
std::unique_ptr<view::AppInstallPage> _app_install_page;
|
||||
int _selected_index = -1;
|
||||
bool _launch_requested = false;
|
||||
};
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include <hal/hal.h>
|
||||
#include <smooth_lvgl.hpp>
|
||||
#include <uitk/short_namespace.hpp>
|
||||
#include <assets/assets.h>
|
||||
#include <mooncake_log.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace view {
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class AppListPage {
|
||||
public:
|
||||
AppListPage(const app_center::AppInfoList_t& app_list)
|
||||
|
||||
{
|
||||
_panel = std::make_unique<uitk::lvgl_cpp::Container>(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<uitk::lvgl_cpp::Container>(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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Button>(*_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<uitk::lvgl_cpp::Container> _panel;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Container> _title_panel;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _title;
|
||||
std::vector<std::unique_ptr<uitk::lvgl_cpp::Button>> _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<uitk::lvgl_cpp::Container>(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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Container>(*_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<uitk::lvgl_cpp::Button>(*_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<uitk::lvgl_cpp::Button>(*_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<uitk::lvgl_cpp::Container> _panel;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _title;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _desc_label;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Container> _btn_container;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Button> _btn_back;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Button> _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<uitk::lvgl_cpp::Container>(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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Bar>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Container> _panel;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _title;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _tips;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _progress;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Bar> _progress_bar;
|
||||
lv_image_dsc_t _bg_image;
|
||||
};
|
||||
|
||||
} // namespace view
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "app_dance.h"
|
||||
#include <hal/hal.h>
|
||||
#include <mooncake.h>
|
||||
#include <mooncake_log.h>
|
||||
#include <stackchan/stackchan.h>
|
||||
#include <apps/common/common.h>
|
||||
#include <assets/assets.h>
|
||||
|
||||
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<view::LoadingPage> loading_page;
|
||||
{
|
||||
LvglLockGuard lock;
|
||||
loading_page = std::make_unique<view::LoadingPage>(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::DefaultAvatar>();
|
||||
avatar->init(lv_screen_active());
|
||||
GetStackChan().attachAvatar(std::move(avatar));
|
||||
|
||||
/* ------------------------------- BLE events ------------------------------- */
|
||||
GetHAL().onBleAvatarData.connect([&](const char* data) {
|
||||
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include <mooncake.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
* @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();
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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<std::string> options)
|
||||
static inline int create_page_selector_and_wait(std::string_view label, const std::vector<std::string>& options)
|
||||
{
|
||||
GetHAL().lvglLock();
|
||||
auto page_selector = std::make_unique<view::PageSelector>(label, options);
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "app_ezdata.h"
|
||||
#include <hal/hal.h>
|
||||
#include <mooncake.h>
|
||||
#include <mooncake_log.h>
|
||||
#include <assets/assets.h>
|
||||
#include <stackchan/stackchan.h>
|
||||
|
||||
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::DefaultAvatar>();
|
||||
avatar->init(lv_screen_active());
|
||||
GetStackChan().attachAvatar(std::move(avatar));
|
||||
|
||||
// Create loading page
|
||||
_loading_page = std::make_unique<view::LoadingPage>(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<view::EzdataGuidePage>(code);
|
||||
});
|
||||
// _ezdata_guide_page = std::make_unique<view::EzdataGuidePage>("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);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include "view/view.h"
|
||||
#include <mooncake.h>
|
||||
#include <apps/common/common.h>
|
||||
|
||||
/**
|
||||
* @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<view::LoadingPage> _loading_page;
|
||||
std::unique_ptr<view::EzdataGuidePage> _ezdata_guide_page;
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include <hal/hal.h>
|
||||
#include <smooth_lvgl.hpp>
|
||||
#include <uitk/short_namespace.hpp>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace view {
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class EzdataGuidePage {
|
||||
public:
|
||||
EzdataGuidePage(std::string_view pairCode)
|
||||
{
|
||||
_panel = std::make_unique<uitk::lvgl_cpp::Container>(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<uitk::lvgl_cpp::Container>(*_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<uitk::lvgl_cpp::Container>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Label>(*_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<uitk::lvgl_cpp::Container> _panel;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Container> _panel_url;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Container> _panel_pair_code;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _title_url;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _msg_url;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _title_pair_code;
|
||||
std::unique_ptr<uitk::lvgl_cpp::Label> _msg_pair_code;
|
||||
};
|
||||
|
||||
} // namespace view
|
||||
@@ -394,6 +394,7 @@ void LauncherView::init(std::vector<mooncake::AppProps_t> appPorps)
|
||||
_lr_indicator_panels.back()->onClick().connect([scroll_to_nearby_icon]() { scroll_to_nearby_icon(-1); });
|
||||
|
||||
_lr_indicators_images.push_back(std::make_unique<Image>(_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<mooncake::AppProps_t> appPorps)
|
||||
_lr_indicator_panels.back()->onClick().connect([scroll_to_nearby_icon]() { scroll_to_nearby_icon(1); });
|
||||
|
||||
_lr_indicators_images.push_back(std::make_unique<Image>(_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);
|
||||
|
||||
|
||||
@@ -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<WifiSetupWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"Servo",
|
||||
{{"Calibration",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<ZeroCalibrationWorker>();
|
||||
}},
|
||||
{"LED Strips Test",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<RgbTestWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"Display",
|
||||
{{"Brightness",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<BrightnessSetupWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"System",
|
||||
{{"Timezone",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<TimezoneWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"About",
|
||||
{{fmt::format("FW Version: {}", common::FirmwareVersion),
|
||||
[&]() {
|
||||
_magic_count++;
|
||||
if (_magic_count >= 10) {
|
||||
_magic_count = 0;
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<FwVersionWorker>();
|
||||
}
|
||||
}},
|
||||
{"Factory Reset",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<FactoryResetWorker>();
|
||||
}}},
|
||||
}};
|
||||
_menu_sections = {
|
||||
{
|
||||
"Wi-Fi",
|
||||
{{"Change Wi-Fi",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_need_warm_reset = true;
|
||||
_worker = std::make_unique<WifiSetupWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"Device",
|
||||
{{"Brightness",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<BrightnessSetupWorker>();
|
||||
}},
|
||||
{"Volume",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<VolumeSetupWorker>();
|
||||
}},
|
||||
{"Timezone",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<TimezoneWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"Hardware Test",
|
||||
{{"Servo",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<ZeroCalibrationWorker>();
|
||||
}},
|
||||
{"RGB Strip",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<RgbTestWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"Account",
|
||||
{{"Unbind & Reset",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_need_warm_reset = true;
|
||||
_worker = std::make_unique<AccountWorker>();
|
||||
}}},
|
||||
},
|
||||
{
|
||||
"Firmware",
|
||||
{
|
||||
{fmt::format("Version: {}", common::FirmwareVersion),
|
||||
[&]() {
|
||||
_magic_count++;
|
||||
if (_magic_count >= 10) {
|
||||
_magic_count = 0;
|
||||
_destroy_menu = true;
|
||||
_worker = std::make_unique<FwVersionWorker>();
|
||||
}
|
||||
}},
|
||||
{"Check for Updates",
|
||||
[&]() {
|
||||
_destroy_menu = true;
|
||||
_need_warm_reset = true;
|
||||
_worker = std::make_unique<SystemUpdateWorker>();
|
||||
}},
|
||||
// {"Factory Reset",
|
||||
// [&]() {
|
||||
// _destroy_menu = true;
|
||||
// _worker = std::make_unique<FactoryResetWorker>();
|
||||
// }}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
LvglLockGuard lock;
|
||||
|
||||
@@ -146,6 +168,6 @@ void AppSetup::onClose()
|
||||
view::destroy_status_bar();
|
||||
|
||||
if (_need_warm_reset) {
|
||||
GetHAL().requestWarmReboot(3);
|
||||
GetHAL().requestWarmReboot(6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <hal/hal.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <apps/common/loading_page/loading_page.h>
|
||||
|
||||
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<view::LoadingPage>(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()
|
||||
{
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user