Compare commits

...

66 Commits

Author SHA1 Message Date
Terrence
fe7ae99a4d Bump to 2.0.1 2025-09-14 18:25:22 +08:00
Xiaoxia
147d71b9f1 feat: add snapshot mcp tool (#1196)
* use main task to execute tool calls

* feat: add snapshot mcp tool

* fix compiling errors

* 取消 audio input 的 pin core,core1留给显示,可能会对aec性能有影响

* update ml307 version

* remove v1 theme colors
2025-09-14 15:16:49 +08:00
zczc365
384da9fd0f fix:小智云聊compile error (#1195) 2025-09-14 13:51:19 +08:00
Xiaoxia
ae40f72a39 fix: crash if GIF version is 87a (#1194)
* fix: no tool call reply after self.reboot

* fix: 87a gif error

* append display info to board info
2025-09-13 16:53:10 +08:00
zczc365
d0ba3a923c 添加小智云聊-S3并修改8388支持AEC (#1179) 2025-09-13 14:38:16 +08:00
Terrence
76c19a0f2d fix: compiling errors 2025-09-12 15:55:55 +08:00
Terrence
f79506d58b feat: add manual upgrade firmware 2025-09-12 08:45:29 +08:00
Terrence
469ee2d92a rename withSystemTools to withUserTools 2025-09-11 04:22:33 +08:00
Xiaoxia
57c2c64047 feat: Add gif support (#1183)
* feat: Add gif support

* fix: compiling errors

* fix remove bg image
2025-09-11 03:53:12 +08:00
Xiaoxia
4048647ef8 feat: Add lvgl display theme control (#1180)
* feat: Add lvgl display theme control

* fix: compiling errors

* move light/dark themes to lcd display

* fix compile errors

---------

Co-authored-by: Xiaoxia <terrence.huang@tenclass.com>
2025-09-10 18:43:47 +08:00
Terrence
bce662d135 feat: default to flash non assets 2025-09-10 01:02:23 +08:00
Xiaoxia
d04b08133f Move fonts / assets definition from main/boards to CMakeLists.txt (#1174)
* update surfer-c3-1.14tft font size

* Move fonts / assets definition from main/boards to CMakeLists.txt

* fix c3 compiling errors

---------

Co-authored-by: Xiaoxia <terrence.huang@tenclass.com>
2025-09-08 17:30:18 +08:00
Terrence
897239e997 fix: c3 lcd stack protected error 2025-09-05 07:55:36 +08:00
Xiaoxia
83f6f8c703 Switch to 2.0 branch (#1152)
* Adapt boards to v2 partition tables

* fix esp log error

* fix display style

* reset emotion after download assets

* fix compiling

* update assets default url

* Add user only tools

* Add image cache

* smaller cache and buffer, more heap

* use MAIN_EVENT_CLOCK_TICK to avoid audio glitches

* bump to 2.0.0

* fix compiling errors

---------

Co-authored-by: Xiaoxia <terrence.huang@tenclass.com>
2025-09-04 15:41:28 +08:00
Johnson
3a3dfc003e Fix build error with esp_emote_gfx (#1159)
'bool' is defined in header '<stdbool.h>'; this is probably fixable by adding '#include <stdbool.h>'
   11 | #include "decoder/gfx_aaf_format.h"
2025-09-04 15:18:22 +08:00
Xiaoxia
fc355605f5 fix compiling errors (#1161) 2025-09-04 15:17:32 +08:00
Xiaoxia
5d3f597137 Bump to v1.9.0 (#1157)
* update v2 partition table readme

* feat: Add user only tool

* Add image cache

* smaller cache and buffer, more heap

* use MAIN_EVENT_CLOCK_TICK to avoid audio glitches

* fix: esp_psram_get_size not found in c3

* Bump to 1.9.0
2025-09-04 12:30:26 +08:00
ggc121238
3e37551923 add waveshare-s3-audio-board (#1139)
* add waveshare-s3-audio-board

* Modify the product link in the readme of the waveshare esp32s3-audio-board

* Modify reset time
2025-09-01 10:50:39 +08:00
Xiaoxia
d09537ed5c Add V2 parition tables (#1137)
* v1.9.0: update font icons, add mqtt reconnect

* Add v2 parition tables
2025-08-29 09:04:23 +08:00
Create123
86921f4862 Add M5Stack AtomEchoS3R Board. (#1123)
Signed-off-by: hlym123 <lwylwt@qq.com>
2025-08-26 14:05:10 +08:00
Terrence
7af366b7b2 fix: ES7120_SEL_MIC1 => ES7210_SEL_MIC1 2025-08-23 16:05:49 +08:00
Xiaoxia
ddbb24942d v1.8.9: Upgrade component versions (#1118) 2025-08-23 07:12:14 +08:00
Ben
610a4a0703 Update README.md (#1115)
delete '的'
2025-08-22 18:49:26 +08:00
香草味的纳西妲喵
7cd37427b2 feat: 添加批量转换OGG音频的相关脚本,移动声波配网HTML文件到scripts文件夹下 (#1107)
* feat: 添加批量转换OGG音频的相关脚本,移动声波配网HTML文件到scripts文件夹下

* Rename

* moved README.md
2025-08-22 00:53:18 +08:00
laride
2d772dad68 fix: resolve some audio issues on esp-hi (#1027)
* fix: resolve crash when closing codec dev on esp-hi

* fix: fix incorrect status display in non-zh-CN languages

* fix: reduce noise when not in Speaking state
2025-08-19 11:50:00 +08:00
Terrence
156eb15f58 fix: dual mic without afe 2025-08-16 03:08:00 +08:00
Xiaoxia
c59c515706 v1.8.8: release with esp-sr==2.1.4 and without font placeholder (#1086) 2025-08-15 04:50:33 +08:00
Terrence
44b8d5e4c1 fix: c3 wakeword not working with esp-sr 2.1.5 2025-08-15 01:07:00 +08:00
Xiaoxia
cc07ef447e Revert "camera 优化:在原有的RGB565处理下,容易超时改为JPEG格式 (#1029)" (#1085)
This reverts commit d6b1414967.
2025-08-14 22:23:29 +08:00
Ky1eYang
cf4afde88e add: 添加声音检测的可视化以及声波demod的准确度 (#1077)
Co-authored-by: yangkaiyue <yangkaiyue1@tenclass.com>
2025-08-14 22:11:56 +08:00
Dong Ning
d6b1414967 camera 优化:在原有的RGB565处理下,容易超时改为JPEG格式 (#1029)
* camera 优化

feat(camera): 修改摄像头配置为JPEG格式并优化图像处理逻辑

将摄像头输出格式从RGB565改为JPEG以提高传输效率,同时调整JPEG质量为10
重构预览图像处理逻辑,支持直接处理JPEG格式并自动转换为RGB565
优化Explain方法中的JPEG队列处理,减少内存分配和拷贝操作

* 修复代码缩进

调整代码缩进格式以提升可读性

* fix(esp32_camera): 修复RGB565格式预览图像的字节序问题

添加字节交换处理,将大端序转换为小端序,确保预览图像显示正确

* 使用旧的处理方式

* refactor(esp32_camera): 移除preview_buffer_直接使用preview_image_.data
2025-08-14 22:11:15 +08:00
Terrence
00dd89079b Bump to 1.8.7 2025-08-13 11:50:27 +08:00
vritser
cfb635d870 feat: 适配 ESP-S3-EV-Board-2 开发板 (#1043)
* feat: 适配 ESP-S3-EV-Board-2 开发板

* fix: config name

* fix: ev_board type choice

* fix: remove version config

---------

Co-authored-by: vritser <vritser@gmail.com>
2025-08-12 20:21:18 +08:00
Xiaoxia
9ae34d3b45 feat: Add locales with OGG sounds (#1057)
* fix jiuchuan build problem

* feat: Add locales with OGG sounds

* fix building echoear

* Support ogg files frame duration <= 60
2025-08-12 18:41:00 +08:00
Terrence
08b8b04c6c remove data mutex from read/write 2025-08-12 17:11:57 +08:00
Terrence
f890acfc7c fix i2s race condition error 2025-08-12 14:54:16 +08:00
Terrence
a4fe4d8d99 fix firmware image size 2025-08-12 14:53:17 +08:00
Xiaoxia
593b495139 xmin-c3 share MCP tool and sleep mode can be disabled (#1054) 2025-08-09 03:08:42 +08:00
Xiaoxia
2a02dd65be fix ReadAudioData frame duration (#1051) 2025-08-08 21:50:28 +08:00
virgil
845b760db3 fix: Delete the esp_jpeg_simd component to resolve function conflicts (#1049) 2025-08-08 21:00:34 +08:00
Xiaoxia
f86637cf1c fix: codec unexpectedly closed by timer after open (#1046)
Co-authored-by: Xiaoxia <terrence.huang@tenclass.com>
2025-08-08 15:39:12 +08:00
Xiaoxia
363073658a fix: OTA buffer overflow caused by slow SetChatMessage (#1031) 2025-08-06 01:16:52 +08:00
laride
da228f2582 fix: ci idf.py not found (#1030) 2025-08-05 22:18:28 +08:00
laride
36476f05cd feat: add build CI (#1028) 2025-08-05 20:03:37 +08:00
flying1425
90602d3802 waveshare-c6-lcd-1.69 新增电池电量显示功能及电池供电状态下的PWR按键开关机功能。 (#1020)
* 新增电池电量显示功能及电池供电状态下的PWR按键开关机功能。

* 代码风格优化

---------

Co-authored-by: flyingtjy <flyingtjy@gmail.com>
2025-08-04 22:38:13 +08:00
Zxczzzzzzz
b2e1c5bb5c 添加了一个声波配网的HTML界面 (#996)
* Add HTML page for sonic-based Wi-Fi provisioning

* Add HTML page for sonic-based Wi-Fi provisioning

* Add soundwave provisioning UI and fix bugs

* Add soundwave provisioning UI and fix bugs

* Move sonic_wifi_config.html to the docs folder

---------

Co-authored-by: luyuhan <xiaolumylove@icloud.com>
2025-08-02 14:13:35 +08:00
Terrence
d58d55cfe7 Bump to 1.8.5 2025-08-02 01:27:14 +08:00
espressif2022
cd23e0f155 feat: add emote_gfx UI for EchoEar (#1022)
* feat: add emote_gfx UI for EchoEar

* feat: delete local assets
2025-08-01 18:07:13 +08:00
Xiaoxia
26d9ff283f Fix custom wakeword for dual mic (#1018) 2025-08-01 13:30:17 +08:00
Xiaoxia
fb85019c3c change bread-compact-wifi-s3cam test gpio num (#1017) 2025-08-01 05:28:27 +08:00
HonestQiao
4859d57fea 修复esp32-p4配网客户端无法连接、连接获取不到ip或者无法打开配置页面的问题 (#1012) 2025-07-31 05:14:17 +08:00
Xiaoxia
03394fe38d update the sleep time of xmini-c3 with wake word to 300s (#1007) 2025-07-30 15:25:39 +08:00
jake12355
e0e12450c5 jiuchuan-s3修改按键定义取消不对话自动关机修复屏幕显示不全 (#997)
* jiuchuan-s3修改按键定义取消不对话自动关机修复屏幕显示不全

* jiuchuan-s3修改按键定义取消不对话自动关机修复屏幕显示不全
2025-07-29 17:28:40 +08:00
Xiaoxia
e5ac40aac8 fix audio pm (#1004) 2025-07-29 15:25:40 +08:00
Xiaoxia
345c8be467 Add custom wakeword threshold option (#1003) 2025-07-29 10:56:52 +08:00
香草味的纳西妲喵
def6301292 增加其他分辨率表情转换选项 (#987)
* Create requirements.txt

* Update README.md

* add: 增加其他尺寸表情选项
2025-07-26 02:31:09 +08:00
Xiaoxia
df7cbdfcb6 fix esp-hi crashing in esp_codec_dev_close() (#984) 2025-07-25 10:36:56 +08:00
Terrence
d38763d5ef Reduce SRAM usage of audio tasks 2025-07-25 08:27:12 +08:00
LILYGO_L
e90e540933 增强T-CameraPlus-S3麦克风接收音量 (#958)
* Adapt for LilyGO-T-Circle-S3 device

* Adapt for LilyGO-T-Circle-S3 device

* Remove comments and modify the size of the lilygo-t-circle-s3 image

* Modify the code style and format to Google C++

* Modify the code style and format to Google C++

* Fixed bugs in the LILYGO T-Circle-S3 board and added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Merge branch 'main' of https://github.com/Llgok/xiaozhi-esp32

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Fix the color display issue for T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Update T-CameraPlus-S3_V1.2 Version Xiaozhi Example

* Resolve the issue where the camera on the T-CameraPlus-S3_V1.2 board cannot be used normally.

* Enhance microphone reception volume

* fix the issue where voice wake-up is not working

* fix the issue where voice wake-up is not working
2025-07-23 23:02:45 +08:00
Ky1eYang
656bf3c7fa FIX: 修复双声道声波配网失效, 添加屏幕打印SSID/密码 (#971)
* debug: 添加声波配网的log打印点display

* fix: 修复双声道下声波配网失效的问题

* fix: codec可能为nullptr的问题(需要从单例board获取)

* Update afsk_demod.cc

fix coding style

---------

Co-authored-by: yangkaiyue <yangkaiyue1@tenclass.com>
Co-authored-by: Xiaoxia <terrence@tenclass.com>
2025-07-23 22:59:07 +08:00
Y1hsiaochunnn
ca35b0761b Update README.md (#968)
The README text description is incorrect. It needs to be corrected.
2025-07-23 22:47:19 +08:00
Terrence
b031a829c0 Bump to 1.8.2 2025-07-22 22:43:41 +08:00
Xiaoxia
3c11cceb43 增加自定义唤醒词启动失败的提升 (#965) 2025-07-22 18:57:25 +08:00
Y1hsiaochunnn
15f233e773 Add compatibility for Waveshare ESP32-S3-Touch-AMOLED-2.06 (#960)
* Add Waveshare ESP32-S3-Touch-AMOLED-2.06

* Update some configuration settings

* Add configuration to the configuration file

* Fix the abnormal areas
2025-07-22 18:02:31 +08:00
Forairaaaaa
721b58f8c7 Fix atoms3 backlight control (#959) 2025-07-22 17:55:33 +08:00
Xiaoxia
eb0bba2c89 Update LICENSE 2025-07-22 10:06:11 +08:00
735 changed files with 14471 additions and 7125 deletions

View File

@@ -1,32 +1,106 @@
name: Build and Test
name: Build Boards
on:
push:
branches:
- main
- ci/* # for ci test
pull_request:
branches:
- main
permissions:
contents: read
jobs:
build:
prepare:
name: Determine boards to build
runs-on: ubuntu-latest
outputs:
boards: ${{ steps.select.outputs.boards }}
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Espressif IoT Development Framework (ESP-IDF)
# You may pin to the exact commit or the version.
# uses: espressif/esp-idf-ci-action@8cd22ae10042fadc37890e81e9988a9113e7b506
uses: espressif/esp-idf-ci-action@v1.1.0
- name: Checkout
uses: actions/checkout@v4
with:
# Relative path under $GITHUB_WORKSPACE to place the repository
#path: # optional, default is
# Version of ESP-IDF docker image to use
esp_idf_version: release-v5.4
# ESP32 variant to build for
target: esp32s3
# Command to run inside the docker container (default: builds the project)
# command: # optional, default is idf.py build
fetch-depth: 0
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- id: list
name: Get all board list
run: |
echo "all_boards=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
- id: select
name: Select boards based on changes
env:
ALL_BOARDS: ${{ steps.list.outputs.all_boards }}
run: |
EVENT_NAME="${{ github.event_name }}"
# For push to main branch, build all boards
if [[ "$EVENT_NAME" == "push" ]]; then
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
exit 0
fi
# For pull_request
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
echo "Base: $BASE_SHA, Head: $HEAD_SHA"
CHANGED=$(git diff --name-only $BASE_SHA $HEAD_SHA || true)
echo "Changed files:\n$CHANGED"
NEED_ALL=0
declare -A AFFECTED
while IFS= read -r file; do
if [[ "$file" == main/* && "$file" != main/boards/* ]]; then
NEED_ALL=1
fi
if [[ "$file" == main/boards/* ]]; then
board=$(echo "$file" | cut -d '/' -f3)
AFFECTED[$board]=1
fi
done <<< "$CHANGED"
if [[ "$NEED_ALL" -eq 1 ]]; then
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
else
if [[ ${#AFFECTED[@]} -eq 0 ]]; then
echo "boards=[]" >> $GITHUB_OUTPUT
else
JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
echo "boards=$JSON" >> $GITHUB_OUTPUT
fi
fi
build:
name: Build ${{ matrix.board }}
needs: prepare
if: ${{ needs.prepare.outputs.boards != '[]' }}
strategy:
fail-fast: false # 单个 board 失败不影响其它 board
matrix:
board: ${{ fromJson(needs.prepare.outputs.boards) }}
runs-on: ubuntu-latest
container:
image: espressif/idf:release-v5.4
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build current board
shell: bash
run: |
source $IDF_PATH/export.sh
python scripts/release.py ${{ matrix.board }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: xiaozhi_${{ matrix.board }}_${{ github.sha }}.bin
path: build/merged-binary.bin
if-no-files-found: error

4
.gitignore vendored
View File

@@ -13,6 +13,6 @@ main/assets/lang_config.h
main/mmap_generate_emoji.h
.DS_Store
.cache
main/mmap_generate_emoji.h
*.pyc
*.bin
*.bin
mmap_generate_*.h

View File

@@ -4,7 +4,7 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(PROJECT_VER "1.8.1")
set(PROJECT_VER "2.0.1")
# Add this line to disable the specific warning
add_compile_options(-Wno-missing-field-initializers)

View File

@@ -1,6 +1,7 @@
MIT License
Copyright (c) 2024 Xiaoxia
Copyright (c) 2025 Shenzhen Xinzhi Future Technology Co., Ltd.
Copyright (c) 2025 Project Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -130,7 +130,7 @@
## 大模型配置
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
👉 [后台操作视频教程(旧版界面)](https://www.bilibili.com/video/BV1jUCUY2EKM/)

View File

@@ -1,3 +1,39 @@
# Define default assets files (Absolute url starting with http or https is supported)
set(ASSETS_URL_PREFIX "https://files.xiaozhi.me/assets/default/")
set(ASSETS_PUHUI_COMMON_14_1 "${ASSETS_URL_PREFIX}none-font_puhui_common_14_1-none.bin")
set(ASSETS_XIAOZHI_WAKENET_ONLY "${ASSETS_URL_PREFIX}wn9_nihaoxiaozhi_tts-none-none.bin")
set(ASSETS_XIAOZHI_PUHUI_COMMON_14_1 "${ASSETS_URL_PREFIX}wn9_nihaoxiaozhi_tts-font_puhui_common_14_1-none.bin")
set(ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32 "${ASSETS_URL_PREFIX}wn9_nihaoxiaozhi_tts-font_puhui_common_16_4-emojis_32.bin")
set(ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64 "${ASSETS_URL_PREFIX}wn9_nihaoxiaozhi_tts-font_puhui_common_16_4-emojis_64.bin")
set(ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64 "${ASSETS_URL_PREFIX}wn9_nihaoxiaozhi_tts-font_puhui_common_20_4-emojis_64.bin")
set(ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64 "${ASSETS_URL_PREFIX}wn9_nihaoxiaozhi_tts-font_puhui_common_30_4-emojis_64.bin")
set(ASSETS_XIAOZHI_S_WAKENET_ONLY "${ASSETS_URL_PREFIX}wn9s_nihaoxiaozhi-none-none.bin")
set(ASSETS_XIAOZHI_S_PUHUI_COMMON_14_1 "${ASSETS_URL_PREFIX}wn9s_nihaoxiaozhi-font_puhui_common_14_1-none.bin")
set(ASSETS_XIAOZHI_S_PUHUI_COMMON_16_4_EMOJI_32 "${ASSETS_URL_PREFIX}wn9s_nihaoxiaozhi-font_puhui_common_16_4-emojis_32.bin")
set(ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_32 "${ASSETS_URL_PREFIX}wn9s_nihaoxiaozhi-font_puhui_common_20_4-emojis_32.bin")
set(ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_64 "${ASSETS_URL_PREFIX}wn9s_nihaoxiaozhi-font_puhui_common_20_4-emojis_64.bin")
set(ASSETS_XIAOZHI_S_PUHUI_COMMON_30_4_EMOJI_64 "${ASSETS_URL_PREFIX}wn9s_nihaoxiaozhi-font_puhui_common_30_4-emojis_64.bin")
# Embedded font files defined in `xiaozhi-fonts` component
# Basic fonts include ASCII and about 600 characters used in assets/locales
set(FONT_PUHUI_BASIC_14_1 font_puhui_basic_14_1)
set(FONT_PUHUI_BASIC_16_4 font_puhui_basic_16_4)
set(FONT_PUHUI_BASIC_20_4 font_puhui_basic_20_4)
set(FONT_PUHUI_BASIC_30_4 font_puhui_basic_30_4)
# Common fonts include about 7000 common characters generated with DeepSeek R1 tokenizer
set(FONT_PUHUI_COMMON_14_1 font_puhui_14_1)
set(FONT_PUHUI_COMMON_16_4 font_puhui_16_4)
set(FONT_PUHUI_COMMON_20_4 font_puhui_20_4)
set(FONT_PUHUI_COMMON_30_4 font_puhui_30_4)
set(FONT_AWESOME_14_1 font_awesome_14_1)
set(FONT_AWESOME_30_1 font_awesome_30_1)
set(FONT_AWESOME_16_4 font_awesome_16_4)
set(FONT_AWESOME_20_4 font_awesome_20_4)
set(FONT_AWESOME_30_4 font_awesome_30_4)
# Define source files
set(SOURCES "audio/audio_codec.cc"
"audio/audio_service.cc"
"audio/codecs/no_audio_codec.cc"
@@ -14,6 +50,13 @@ set(SOURCES "audio/audio_codec.cc"
"display/display.cc"
"display/lcd_display.cc"
"display/oled_display.cc"
"display/lvgl_display/lvgl_display.cc"
"display/lvgl_display/emoji_collection.cc"
"display/lvgl_display/lvgl_theme.cc"
"display/lvgl_display/lvgl_font.cc"
"display/lvgl_display/lvgl_image.cc"
"display/lvgl_display/gif/lvgl_gif.cc"
"display/lvgl_display/gif/gifdec.c"
"protocols/protocol.cc"
"protocols/mqtt_protocol.cc"
"protocols/websocket_protocol.cc"
@@ -23,204 +66,470 @@ set(SOURCES "audio/audio_codec.cc"
"ota.cc"
"settings.cc"
"device_state_event.cc"
"assets.cc"
"main.cc"
)
set(INCLUDE_DIRS "." "display" "audio" "protocols")
set(INCLUDE_DIRS "." "display" "display/lvgl_display" "audio" "protocols")
# 添加板级公共文件
# Add board common files
file(GLOB BOARD_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/common/*.cc)
list(APPEND SOURCES ${BOARD_COMMON_SOURCES})
list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/boards/common)
# 根据 BOARD_TYPE 配置添加对应的板级文件
# Set default LVGL_TEXT_FONT and LVGL_ICON_FONT
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
# Add board files according to BOARD_TYPE
# Set default assets if the board uses partition table V2
if(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI)
set(BOARD_TYPE "bread-compact-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ML307)
set(BOARD_TYPE "bread-compact-ml307")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ESP32)
set(BOARD_TYPE "bread-compact-esp32")
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ESP32_LCD)
set(BOARD_TYPE "bread-compact-esp32-lcd")
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
elseif(CONFIG_BOARD_TYPE_DF_K10)
set(BOARD_TYPE "df-k10")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_DF_S3_AI_CAM)
set(BOARD_TYPE "df-s3-ai-cam")
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_WAKENET_ONLY})
elseif(CONFIG_BOARD_TYPE_ESP_BOX_3)
set(BOARD_TYPE "esp-box-3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP_BOX)
set(BOARD_TYPE "esp-box")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP_BOX_LITE)
set(BOARD_TYPE "esp-box-lite")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_1)
set(BOARD_TYPE "kevin-box-1")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_2)
set(BOARD_TYPE "kevin-box-2")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_KEVIN_C3)
set(BOARD_TYPE "kevin-c3")
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_WAKENET_ONLY})
elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V3_DEV)
set(BOARD_TYPE "kevin-sp-v3-dev")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V4_DEV)
set(BOARD_TYPE "kevin-sp-v4-dev")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_KEVIN_YUYING_313LCD)
set(BOARD_TYPE "kevin-yuying-313lcd")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV)
set(BOARD_TYPE "lichuang-dev")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_LICHUANG_C3_DEV)
set(BOARD_TYPE "lichuang-c3-dev")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_MAGICLICK_2P4)
set(BOARD_TYPE "magiclick-2p4")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_MAGICLICK_2P5)
set(BOARD_TYPE "magiclick-2p5")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3)
set(BOARD_TYPE "magiclick-c3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3_V2)
set(BOARD_TYPE "magiclick-c3-v2")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_S3)
set(BOARD_TYPE "m5stack-core-s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_TAB5)
set(BOARD_TYPE "m5stack-tab5")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATOMS3_ECHO_BASE)
set(BOARD_TYPE "atoms3-echo-base")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ATOMS3R_ECHO_BASE)
set(BOARD_TYPE "atoms3r-echo-base")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE)
set(BOARD_TYPE "atoms3r-cam-m12-echo-base")
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_WAKENET_ONLY})
elseif(CONFIG_BOARD_TYPE_ATOM_ECHOS3R)
set(BOARD_TYPE "atom-echos3r")
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_WAKENET_ONLY})
elseif(CONFIG_BOARD_TYPE_ATOMMATRIX_ECHO_BASE)
set(BOARD_TYPE "atommatrix-echo-base")
elseif(CONFIG_BOARD_TYPE_XMINI_C3_V3)
set(BOARD_TYPE "xmini-c3-v3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_XMINI_C3_4G)
set(BOARD_TYPE "xmini-c3-4g")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_XMINI_C3)
set(BOARD_TYPE "xmini-c3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_ESP32S3_KORVO2_V3)
set(BOARD_TYPE "esp32s3-korvo2-v3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP_SPARKBOT)
set(BOARD_TYPE "esp-sparkbot")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP_SPOT_S3)
set(BOARD_TYPE "esp-spot-s3")
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_WAKENET_ONLY})
elseif(CONFIG_BOARD_TYPE_ESP_HI)
set(BOARD_TYPE "esp-hi")
elseif(CONFIG_BOARD_TYPE_ECHOEAR)
set(BOARD_TYPE "echoear")
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
elseif(CONFIG_BOARD_TYPE_ESP32S3_AUDIO_BOARD)
set(BOARD_TYPE "waveshare-s3-audio-board")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06)
set(BOARD_TYPE "waveshare-s3-touch-amoled-2.06")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75)
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85C)
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85c")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85)
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_46)
set(BOARD_TYPE "esp32-s3-touch-lcd-1.46")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5)
set(BOARD_TYPE "esp32-s3-touch-lcd-3.5")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5B)
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.5b")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ESP32C6_LCD_1_69)
set(BOARD_TYPE "waveshare-c6-lcd-1.69")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43)
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.43")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32P4_NANO)
set(BOARD_TYPE "waveshare-p4-nano")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-4b")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-xc")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_LCD)
set(BOARD_TYPE "bread-compact-wifi-lcd")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_TUDOUZI)
set(BOARD_TYPE "tudouzi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CIRCLE_S3)
set(BOARD_TYPE "lilygo-t-circle-s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1)
set(BOARD_TYPE "lilygo-t-cameraplus-s3")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2)
set(BOARD_TYPE "lilygo-t-cameraplus-s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA)
set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY)
set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_MOVECALL_MOJI_ESP32S3)
set(BOARD_TYPE "movecall-moji-esp32s3")
elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3)
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3)
set(BOARD_TYPE "movecall-cuican-esp32s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3)
set(BOARD_TYPE "atk-dnesp32s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX)
set(BOARD_TYPE "atk-dnesp32s3-box")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX0)
set(BOARD_TYPE "atk-dnesp32s3-box0")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI)
set(BOARD_TYPE "atk-dnesp32s3-box2-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_4G)
set(BOARD_TYPE "atk-dnesp32s3-box2-4g")
set(BOARD_TYPE "atk-dnesp32s3-box2-4g")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_WIFI)
set(BOARD_TYPE "atk-dnesp32s3m-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_4G)
set(BOARD_TYPE "atk-dnesp32s3m-4g")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_DU_CHATX)
set(BOARD_TYPE "du-chatx")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ESP32S3_Taiji_Pi)
set(BOARD_TYPE "taiji-pi-s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_85TFT_WIFI)
set(BOARD_TYPE "xingzhi-cube-0.85tft-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_85TFT_ML307)
set(BOARD_TYPE "xingzhi-cube-0.85tft-ml307")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_96OLED_WIFI)
set(BOARD_TYPE "xingzhi-cube-0.96oled-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_96OLED_ML307)
set(BOARD_TYPE "xingzhi-cube-0.96oled-ml307")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_14_1})
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_1_54TFT_WIFI)
set(BOARD_TYPE "xingzhi-cube-1.54tft-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_1_54TFT_ML307)
set(BOARD_TYPE "xingzhi-cube-1.54tft-ml307")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_SENSECAP_WATCHER)
set(BOARD_TYPE "sensecap-watcher")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_DOIT_S3_AIBOX)
set(BOARD_TYPE "doit-s3-aibox")
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_WAKENET_ONLY})
elseif(CONFIG_BOARD_TYPE_MIXGO_NOVA)
set(BOARD_TYPE "mixgo-nova")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_GENJUTECH_S3_1_54TFT)
set(BOARD_TYPE "genjutech-s3-1.54tft")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32_CGC)
set(BOARD_TYPE "esp32-cgc")
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
elseif(CONFIG_BOARD_TYPE_ESP32_CGC_144)
set(BOARD_TYPE "esp32-cgc-144")
set(BOARD_TYPE "esp32-cgc-144")
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_14_1})
set(LVGL_ICON_FONT ${FONT_AWESOME_14_1})
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board)
set(BOARD_TYPE "esp-s3-lcd-ev-board")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
set(BOARD_TYPE "esp-s3-lcd-ev-board-2")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_30_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_30_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI)
set(BOARD_TYPE "zhengchen-1.54tft-wifi")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_MINSI_K08_DUAL)
set(BOARD_TYPE "minsi-k08-dual")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307)
set(BOARD_TYPE "zhengchen-1.54tft-ml307")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_ESP32_S3_1_54_MUMA)
set(BOARD_TYPE "sp-esp32-s3-1.54-muma")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_ESP32_S3_1_28_BOX)
set(BOARD_TYPE "sp-esp32-s3-1.28-box")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_OTTO_ROBOT)
set(BOARD_TYPE "otto-robot")
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
elseif(CONFIG_BOARD_TYPE_ELECTRON_BOT)
set(BOARD_TYPE "electron-bot")
set(LVGL_TEXT_FONT ${FONT_PUHUI_COMMON_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_CAM)
set(BOARD_TYPE "bread-compact-wifi-s3cam")
elseif(CONFIG_BOARD_TYPE_JIUCHUAN )
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_16_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_16_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_JIUCHUAN)
set(BOARD_TYPE "jiuchuan-s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_LABPLUS_MPYTHON_V3)
set(BOARD_TYPE "labplus-mpython-v3")
set(BOARD_TYPE "labplus-mpython-v3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_LABPLUS_LEDONG_V2)
set(BOARD_TYPE "labplus-ledong-v2")
set(BOARD_TYPE "labplus-ledong-v2")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
elseif(CONFIG_BOARD_TYPE_SURFER_C3_1_14TFT)
set(BOARD_TYPE "surfer-c3-1.14tft")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_32})
elseif(CONFIG_BOARD_TYPE_YUNLIAO_S3)
set(BOARD_TYPE "yunliao-s3")
set(LVGL_TEXT_FONT ${FONT_PUHUI_BASIC_20_4})
set(LVGL_ICON_FONT ${FONT_AWESOME_20_4})
set(DEFAULT_ASSETS ${ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64})
endif()
file(GLOB BOARD_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc
${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.c
)
list(APPEND SOURCES ${BOARD_SOURCES})
# Select audio processor according to Kconfig
if(CONFIG_USE_AUDIO_PROCESSOR)
list(APPEND SOURCES "audio/processors/afe_audio_processor.cc")
else()
@@ -234,7 +543,7 @@ elseif(CONFIG_USE_CUSTOM_WAKE_WORD)
list(APPEND SOURCES "audio/wake_words/custom_wake_word.cc")
endif()
# 根据Kconfig选择语言目录
# Select language directory according to Kconfig
if(CONFIG_LANGUAGE_ZH_CN)
set(LANG_DIR "zh-CN")
elseif(CONFIG_LANGUAGE_ZH_TW)
@@ -243,18 +552,55 @@ elseif(CONFIG_LANGUAGE_EN_US)
set(LANG_DIR "en-US")
elseif(CONFIG_LANGUAGE_JA_JP)
set(LANG_DIR "ja-JP")
elseif(CONFIG_LANGUAGE_KO_KR)
set(LANG_DIR "ko-KR")
elseif(CONFIG_LANGUAGE_VI_VN)
set(LANG_DIR "vi-VN")
elseif(CONFIG_LANGUAGE_TH_TH)
set(LANG_DIR "th-TH")
elseif(CONFIG_LANGUAGE_DE_DE)
set(LANG_DIR "de-DE")
elseif(CONFIG_LANGUAGE_FR_FR)
set(LANG_DIR "fr-FR")
elseif(CONFIG_LANGUAGE_ES_ES)
set(LANG_DIR "es-ES")
elseif(CONFIG_LANGUAGE_IT_IT)
set(LANG_DIR "it-IT")
elseif(CONFIG_LANGUAGE_RU_RU)
set(LANG_DIR "ru-RU")
elseif(CONFIG_LANGUAGE_AR_SA)
set(LANG_DIR "ar-SA")
elseif(CONFIG_LANGUAGE_HI_IN)
set(LANG_DIR "hi-IN")
elseif(CONFIG_LANGUAGE_PT_PT)
set(LANG_DIR "pt-PT")
elseif(CONFIG_LANGUAGE_PL_PL)
set(LANG_DIR "pl-PL")
elseif(CONFIG_LANGUAGE_CS_CZ)
set(LANG_DIR "cs-CZ")
elseif(CONFIG_LANGUAGE_FI_FI)
set(LANG_DIR "fi-FI")
elseif(CONFIG_LANGUAGE_TR_TR)
set(LANG_DIR "tr-TR")
elseif(CONFIG_LANGUAGE_ID_ID)
set(LANG_DIR "id-ID")
elseif(CONFIG_LANGUAGE_UK_UA)
set(LANG_DIR "uk-UA")
elseif(CONFIG_LANGUAGE_RO_RO)
set(LANG_DIR "ro-RO")
endif()
# 定义生成路径
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
# Define generation path
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/language.json")
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/*.p3)
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.p3)
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/*.ogg)
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.ogg)
# 如果目标芯片是 ESP32则排除特定文件
# If target chip is ESP32, exclude specific files to avoid build errors
if(CONFIG_IDF_TARGET_ESP32)
list(REMOVE_ITEM SOURCES "audio/codecs/box_audio_codec.cc"
"audio/codecs/es8388_audio_codec.cc"
"audio/codecs/es8389_audio_codec.cc"
"led/gpio_led.cc"
)
endif()
@@ -265,20 +611,21 @@ idf_component_register(SRCS ${SOURCES}
WHOLE_ARCHIVE
)
# 使用 target_compile_definitions 来定义 BOARD_TYPE, BOARD_NAME
# 如果 BOARD_NAME 为空,则使用 BOARD_TYPE
# Use target_compile_definitions to define BOARD_TYPE, BOARD_NAME
# If BOARD_NAME is empty, use BOARD_TYPE
if(NOT BOARD_NAME)
set(BOARD_NAME ${BOARD_TYPE})
endif()
target_compile_definitions(${COMPONENT_LIB}
PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\" BOARD_NAME=\"${BOARD_NAME}\"
PRIVATE DEFAULT_ASSETS=\"${DEFAULT_ASSETS}\" LVGL_TEXT_FONT=${LVGL_TEXT_FONT} LVGL_ICON_FONT=${LVGL_ICON_FONT}
)
# 添加生成规则
# Add generation rules
add_custom_command(
OUTPUT ${LANG_HEADER}
COMMAND python ${PROJECT_DIR}/scripts/gen_lang.py
--input "${LANG_JSON}"
--language "${LANG_DIR}"
--output "${LANG_HEADER}"
DEPENDS
${LANG_JSON}
@@ -286,7 +633,7 @@ add_custom_command(
COMMENT "Generating ${LANG_DIR} language config"
)
# 强制建立生成依赖
# Force build generation dependencies
add_custom_target(lang_header ALL
DEPENDS ${LANG_HEADER}
)
@@ -312,7 +659,7 @@ foreach(FILENAME IN LISTS FILES_TO_DOWNLOAD)
set(REMOTE_FILE "${URL}/${FILENAME}")
set(LOCAL_FILE "${SPIFFS_DIR}/${FILENAME}")
# 检查本地文件是否存在
# Check if local file exists
if(EXISTS ${LOCAL_FILE})
message(STATUS "File ${FILENAME} already exists, skipping download")
else()
@@ -332,4 +679,153 @@ spiffs_create_partition_assets(
FLASH_IN_PROJECT
MMAP_FILE_SUPPORT_FORMAT ".aaf"
)
endif()
endif()
if(CONFIG_BOARD_TYPE_ECHOEAR)
idf_build_get_property(build_components BUILD_COMPONENTS)
foreach(COMPONENT ${build_components})
if(COMPONENT MATCHES "esp_emote_gfx" OR COMPONENT MATCHES "espressif2022__esp_emote_gfx")
set(EMOTE_GFX_COMPONENT ${COMPONENT})
idf_component_get_property(EMOTE_GFX_COMPONENT_PATH ${EMOTE_GFX_COMPONENT} COMPONENT_DIR)
set(SPIFFS_DIR "${EMOTE_GFX_COMPONENT_PATH}/emoji_normal")
break()
endif()
endforeach()
spiffs_create_partition_assets(
assets_A
${SPIFFS_DIR}
FLASH_IN_PROJECT
MMAP_FILE_SUPPORT_FORMAT ".aaf, ttf, bin"
IMPORT_INC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}
)
endif()
# Font configuration validation function
function(validate_font_config board_name text_font default_assets)
if(text_font)
# Check if DEFAULT_ASSETS contains font
if(default_assets AND default_assets MATCHES "font_")
# Rule 1: If DEFAULT_ASSETS uses font, LVGL_TEXT_FONT must be BASIC
if(NOT text_font MATCHES "basic")
message(FATAL_ERROR "Font config error for ${board_name}: DEFAULT_ASSETS contains COMMON font but LVGL_TEXT_FONT is not BASIC (${text_font})")
endif()
else()
# Rule 2: If no DEFAULT_ASSETS or DEFAULT_ASSETS doesn't contain font_, LVGL_TEXT_FONT must not be BASIC
if(text_font MATCHES "basic")
message(FATAL_ERROR "Font config error for ${board_name}: No DEFAULT_ASSETS with COMMON font but LVGL_TEXT_FONT is not COMMON (${text_font})")
endif()
endif()
# Pass validation
message(STATUS "Font config validation passed for ${board_name}: LVGL_TEXT_FONT=${text_font}, DEFAULT_ASSETS=${default_assets}")
endif()
endfunction()
# DEFAULT_ASSETS prefix validation function
function(validate_default_assets_prefix board_name default_assets)
if(default_assets)
# Check for ESP32S3/P4 target - DEFAULT_ASSETS cannot start with "wn9s_"
if(CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4)
if(default_assets MATCHES "^wn9s_")
message(FATAL_ERROR "Assets config error for ${board_name}: DEFAULT_ASSETS cannot start with 'wn9s_' for ESP32S3 target (${default_assets})")
endif()
endif()
# Check for ESP32C3/C6 target - DEFAULT_ASSETS cannot start with "wn9_"
if(CONFIG_IDF_TARGET_ESP32C3 OR CONFIG_IDF_TARGET_ESP32C6)
if(default_assets MATCHES "^wn9_")
message(FATAL_ERROR "Assets config error for ${board_name}: DEFAULT_ASSETS cannot start with 'wn9_' for ESP32C3/C6 target (${default_assets})")
endif()
endif()
# Pass validation
message(STATUS "Assets prefix validation passed for ${board_name}: DEFAULT_ASSETS=${default_assets}")
endif()
endfunction()
# Global font configuration validation
# This will validate the current board's font configuration
if(LVGL_TEXT_FONT)
validate_font_config("${BOARD_TYPE}" "${LVGL_TEXT_FONT}" "${DEFAULT_ASSETS}")
endif()
# Global DEFAULT_ASSETS prefix validation
# This will validate the current board's DEFAULT_ASSETS prefix configuration
if(DEFAULT_ASSETS)
validate_default_assets_prefix("${BOARD_TYPE}" "${DEFAULT_ASSETS}")
endif()
# Function to get local assets file path (handles both URL and local file)
function(get_assets_local_file assets_source assets_local_file_var)
# Check if it's a URL (starts with http:// or https://)
if(assets_source MATCHES "^https?://")
# It's a URL, download it
get_filename_component(ASSETS_FILENAME "${assets_source}" NAME)
set(ASSETS_LOCAL_FILE "${CMAKE_BINARY_DIR}/${ASSETS_FILENAME}")
set(ASSETS_TEMP_FILE "${CMAKE_BINARY_DIR}/${ASSETS_FILENAME}.tmp")
# Check if local file exists
if(EXISTS ${ASSETS_LOCAL_FILE})
message(STATUS "Assets file ${ASSETS_FILENAME} already exists, skipping download")
else()
message(STATUS "Downloading ${ASSETS_FILENAME}")
# Clean up any existing temp file
if(EXISTS ${ASSETS_TEMP_FILE})
file(REMOVE ${ASSETS_TEMP_FILE})
endif()
# Download to temporary file first
file(DOWNLOAD ${assets_source} ${ASSETS_TEMP_FILE}
STATUS DOWNLOAD_STATUS)
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
if(NOT STATUS_CODE EQUAL 0)
# Clean up temp file on failure
if(EXISTS ${ASSETS_TEMP_FILE})
file(REMOVE ${ASSETS_TEMP_FILE})
endif()
message(FATAL_ERROR "Failed to download ${ASSETS_FILENAME} from ${assets_source}")
endif()
# Move temp file to final location (atomic operation)
file(RENAME ${ASSETS_TEMP_FILE} ${ASSETS_LOCAL_FILE})
message(STATUS "Successfully downloaded ${ASSETS_FILENAME}")
endif()
else()
# It's a local file path
if(IS_ABSOLUTE "${assets_source}")
set(ASSETS_LOCAL_FILE "${assets_source}")
else()
set(ASSETS_LOCAL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${assets_source}")
endif()
# Check if local file exists
if(NOT EXISTS ${ASSETS_LOCAL_FILE})
message(FATAL_ERROR "Assets file not found: ${ASSETS_LOCAL_FILE}")
endif()
message(STATUS "Using assets file: ${ASSETS_LOCAL_FILE}")
endif()
set(${assets_local_file_var} ${ASSETS_LOCAL_FILE} PARENT_SCOPE)
endfunction()
# Flash assets based on configuration
if(CONFIG_FLASH_DEFAULT_ASSETS)
# Flash default assets
if(DEFAULT_ASSETS)
get_assets_local_file("${DEFAULT_ASSETS}" ASSETS_LOCAL_FILE)
esptool_py_flash_to_partition(flash "assets" "${ASSETS_LOCAL_FILE}")
message(STATUS "Default assets download and flash configured: ${DEFAULT_ASSETS} -> assets partition")
else()
message(WARNING "FLASH_DEFAULT_ASSETS is enabled but no DEFAULT_ASSETS is defined for board ${BOARD_TYPE}")
endif()
elseif(CONFIG_FLASH_CUSTOM_ASSETS)
# Flash custom assets
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_NONE_ASSETS)
message(STATUS "Assets flashing disabled (FLASH_NONE_ASSETS)")
endif()

View File

@@ -6,6 +6,27 @@ config OTA_URL
help
The application will access this URL to check for new firmwares and server address.
choice
prompt "Flash Assets"
default FLASH_NONE_ASSETS
help
Select the assets to flash.
config FLASH_NONE_ASSETS
bool "Do not flash assets"
config FLASH_DEFAULT_ASSETS
bool "Flash Default Assets"
config FLASH_CUSTOM_ASSETS
bool "Flash Custom Assets"
endchoice
config CUSTOM_ASSETS_FILE
depends on FLASH_CUSTOM_ASSETS
string "Custom Assets File"
default "assets.bin"
help
The custom assets file to flash.
It can be a local file relative to the project directory or a remote url.
choice
prompt "Default Language"
@@ -21,6 +42,42 @@ choice
bool "English"
config LANGUAGE_JA_JP
bool "Japanese"
config LANGUAGE_KO_KR
bool "Korean"
config LANGUAGE_VI_VN
bool "Vietnamese"
config LANGUAGE_TH_TH
bool "Thai"
config LANGUAGE_DE_DE
bool "German"
config LANGUAGE_FR_FR
bool "French"
config LANGUAGE_ES_ES
bool "Spanish"
config LANGUAGE_IT_IT
bool "Italian"
config LANGUAGE_RU_RU
bool "Russian"
config LANGUAGE_AR_SA
bool "Arabic"
config LANGUAGE_HI_IN
bool "Hindi"
config LANGUAGE_PT_PT
bool "Portuguese"
config LANGUAGE_PL_PL
bool "Polish"
config LANGUAGE_CS_CZ
bool "Czech"
config LANGUAGE_FI_FI
bool "Finnish"
config LANGUAGE_TR_TR
bool "Turkish"
config LANGUAGE_ID_ID
bool "Indonesian"
config LANGUAGE_UK_UA
bool "Ukrainian"
config LANGUAGE_RO_RO
bool "Romanian"
endchoice
choice BOARD_TYPE
@@ -142,12 +199,20 @@ choice BOARD_TYPE
config BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE
bool "AtomS3R CAM/M12 + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATOM_ECHOS3R
bool "AtomEchoS3R"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
bool "AtomMatrix + Echo Base"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_ESP32S3_AUDIO_BOARD
bool "Waveshare ESP32-S3-Audio-Board"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
depends on IDF_TARGET_ESP32S3
@@ -265,6 +330,9 @@ choice BOARD_TYPE
config BOARD_TYPE_ESP_S3_LCD_EV_Board
bool "乐鑫ESP S3 LCD EV Board开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_S3_LCD_EV_Board_2
bool "乐鑫ESP S3 LCD EV Board 2开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI
bool "征辰科技1.54(WIFI)"
depends on IDF_TARGET_ESP32S3
@@ -302,6 +370,9 @@ choice BOARD_TYPE
config BOARD_TYPE_SURFER_C3_1_14TFT
bool "Surfer-C3-1-14TFT"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_YUNLIAO_S3
bool "小智云聊-S3"
depends on IDF_TARGET_ESP32S3
endchoice
choice ESP_S3_LCD_EV_Board_Version_TYPE
@@ -381,15 +452,27 @@ endchoice
choice DISPLAY_ESP32S3_KORVO2_V3
depends on BOARD_TYPE_ESP32S3_KORVO2_V3
prompt "ESP32S3_KORVO2_V3 LCD Type"
default LCD_ST7789
default ESP32S3_KORVO2_V3_LCD_ST7789
help
屏幕类型选择
config LCD_ST7789
config ESP32S3_KORVO2_V3_LCD_ST7789
bool "ST7789, 分辨率240*280"
config LCD_ILI9341
config ESP32S3_KORVO2_V3_LCD_ILI9341
bool "ILI9341, 分辨率240*320"
endchoice
choice DISPLAY_ESP32S3_AUDIO_BOARD
depends on BOARD_TYPE_ESP32S3_AUDIO_BOARD
prompt "ESP32S3_AUDIO_BOARD LCD Type"
default AUDIO_BOARD_LCD_JD9853
help
屏幕类型选择
config AUDIO_BOARD_LCD_JD9853
bool "JD9853, 分辨率320*172"
config AUDIO_BOARD_LCD_ST7789
bool "ST7789, 分辨率240*320"
endchoice
config USE_WECHAT_MESSAGE_STYLE
bool "Enable WeChat Message Style"
default n
@@ -419,19 +502,26 @@ config USE_CUSTOM_WAKE_WORD
config CUSTOM_WAKE_WORD
string "Custom Wake Word"
default "ni hao xiao zhi"
default "xiao tu dou"
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词,用汉语拼音表示
自定义唤醒词,中文用拼音表示,每个字之间用空格隔开
config CUSTOM_WAKE_WORD_DISPLAY
string "Custom Wake Word Display"
default "你好小智"
default "小土豆"
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词对应问候语
唤醒后发送给服务器的问候语
config CUSTOM_WAKE_WORD_THRESHOLD
int "Custom Wake Word Threshold (%)"
default 20
range 1 99
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词阈值范围1-99越小越敏感默认10
config USE_AUDIO_PROCESSOR
bool "Enable Audio Noise Reduction"
default y
@@ -442,7 +532,7 @@ config USE_AUDIO_PROCESSOR
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 || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3)
help
因为性能不够,不建议和微信聊天界面风格同时开启

View File

@@ -5,15 +5,17 @@
#include "audio_codec.h"
#include "mqtt_protocol.h"
#include "websocket_protocol.h"
#include "font_awesome_symbols.h"
#include "assets/lang_config.h"
#include "mcp_server.h"
#include "assets.h"
#include "settings.h"
#include <cstring>
#include <esp_log.h>
#include <cJSON.h>
#include <driver/gpio.h>
#include <arpa/inet.h>
#include <font_awesome.h>
#define TAG "Application"
@@ -49,7 +51,7 @@ Application::Application() {
esp_timer_create_args_t clock_timer_args = {
.callback = [](void* arg) {
Application* app = (Application*)arg;
app->OnClockTimer();
xEventGroupSetBits(app->event_group_, MAIN_EVENT_CLOCK_TICK);
},
.arg = this,
.dispatch_method = ESP_TIMER_TASK,
@@ -67,6 +69,65 @@ Application::~Application() {
vEventGroupDelete(event_group_);
}
void Application::CheckAssetsVersion() {
auto& board = Board::GetInstance();
auto display = board.GetDisplay();
auto assets = board.GetAssets();
if (!assets) {
ESP_LOGE(TAG, "Assets is not set for board %s", BOARD_NAME);
return;
}
if (!assets->partition_valid()) {
ESP_LOGE(TAG, "Assets partition is not valid for board %s", BOARD_NAME);
return;
}
Settings settings("assets", true);
// Check if there is a new assets need to be downloaded
std::string download_url = settings.GetString("download_url");
if (!download_url.empty()) {
settings.EraseKey("download_url");
}
if (download_url.empty() && !assets->checksum_valid()) {
download_url = assets->default_assets_url();
}
if (!download_url.empty()) {
char message[256];
snprintf(message, sizeof(message), Lang::Strings::FOUND_NEW_ASSETS, download_url.c_str());
Alert(Lang::Strings::LOADING_ASSETS, message, "cloud_arrow_down", Lang::Sounds::OGG_UPGRADE);
// Wait for the audio service to be idle for 3 seconds
vTaskDelay(pdMS_TO_TICKS(3000));
SetDeviceState(kDeviceStateUpgrading);
board.SetPowerSaveMode(false);
display->SetChatMessage("system", Lang::Strings::PLEASE_WAIT);
bool success = assets->Download(download_url, [display](int progress, size_t speed) -> void {
std::thread([display, progress, speed]() {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
display->SetChatMessage("system", buffer);
}).detach();
});
board.SetPowerSaveMode(true);
vTaskDelay(pdMS_TO_TICKS(1000));
if (!success) {
Alert(Lang::Strings::ERROR, Lang::Strings::DOWNLOAD_ASSETS_FAILED, "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
vTaskDelay(pdMS_TO_TICKS(2000));
return;
}
}
// Apply assets
assets->Apply();
display->SetChatMessage("system", "");
display->SetEmotion("microchip_ai");
}
void Application::CheckNewVersion(Ota& ota) {
const int MAX_RETRY = 10;
int retry_count = 0;
@@ -85,9 +146,9 @@ void Application::CheckNewVersion(Ota& ota) {
return;
}
char buffer[128];
char buffer[256];
snprintf(buffer, sizeof(buffer), Lang::Strings::CHECK_NEW_VERSION_FAILED, retry_delay, ota.GetCheckVersionUrl().c_str());
Alert(Lang::Strings::ERROR, buffer, "sad", Lang::Sounds::P3_EXCLAMATION);
Alert(Lang::Strings::ERROR, buffer, "cloud_slash", Lang::Sounds::OGG_EXCLAMATION);
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", retry_delay, retry_count, MAX_RETRY);
for (int i = 0; i < retry_delay; i++) {
@@ -103,42 +164,10 @@ void Application::CheckNewVersion(Ota& ota) {
retry_delay = 10; // 重置重试延迟时间
if (ota.HasNewVersion()) {
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE);
vTaskDelay(pdMS_TO_TICKS(3000));
SetDeviceState(kDeviceStateUpgrading);
display->SetIcon(FONT_AWESOME_DOWNLOAD);
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota.GetFirmwareVersion();
display->SetChatMessage("system", message.c_str());
board.SetPowerSaveMode(false);
audio_service_.Stop();
vTaskDelay(pdMS_TO_TICKS(1000));
bool upgrade_success = ota.StartUpgrade([display](int progress, size_t speed) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
display->SetChatMessage("system", buffer);
});
if (!upgrade_success) {
// Upgrade failed, restart audio service and continue running
ESP_LOGE(TAG, "Firmware upgrade failed, restarting audio service and continuing operation...");
audio_service_.Start(); // Restart audio service
board.SetPowerSaveMode(true); // Restore power save mode
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "sad", Lang::Sounds::P3_EXCLAMATION);
vTaskDelay(pdMS_TO_TICKS(3000));
// Continue to normal operation (don't break, just fall through)
} else {
// Upgrade success, reboot immediately
ESP_LOGI(TAG, "Firmware upgrade successful, rebooting...");
display->SetChatMessage("system", "Upgrade successful, rebooting...");
vTaskDelay(pdMS_TO_TICKS(1000)); // Brief pause to show message
Reboot();
if (UpgradeFirmware(ota)) {
return; // This line will never be reached after reboot
}
// If upgrade failed, continue to normal operation (don't break, just fall through)
}
// No new version, mark the current version as valid
@@ -180,20 +209,20 @@ void Application::ShowActivationCode(const std::string& code, const std::string&
const std::string_view& sound;
};
static const std::array<digit_sound, 10> digit_sounds{{
digit_sound{'0', Lang::Sounds::P3_0},
digit_sound{'1', Lang::Sounds::P3_1},
digit_sound{'2', Lang::Sounds::P3_2},
digit_sound{'3', Lang::Sounds::P3_3},
digit_sound{'4', Lang::Sounds::P3_4},
digit_sound{'5', Lang::Sounds::P3_5},
digit_sound{'6', Lang::Sounds::P3_6},
digit_sound{'7', Lang::Sounds::P3_7},
digit_sound{'8', Lang::Sounds::P3_8},
digit_sound{'9', Lang::Sounds::P3_9}
digit_sound{'0', Lang::Sounds::OGG_0},
digit_sound{'1', Lang::Sounds::OGG_1},
digit_sound{'2', Lang::Sounds::OGG_2},
digit_sound{'3', Lang::Sounds::OGG_3},
digit_sound{'4', Lang::Sounds::OGG_4},
digit_sound{'5', Lang::Sounds::OGG_5},
digit_sound{'6', Lang::Sounds::OGG_6},
digit_sound{'7', Lang::Sounds::OGG_7},
digit_sound{'8', Lang::Sounds::OGG_8},
digit_sound{'9', Lang::Sounds::OGG_9}
}};
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::P3_ACTIVATION);
Alert(Lang::Strings::ACTIVATION, message.c_str(), "link", Lang::Sounds::OGG_ACTIVATION);
for (const auto& digit : code) {
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
@@ -205,7 +234,7 @@ void Application::ShowActivationCode(const std::string& code, const std::string&
}
void Application::Alert(const char* status, const char* message, const char* emotion, const std::string_view& sound) {
ESP_LOGW(TAG, "Alert %s: %s [%s]", status, message, emotion);
ESP_LOGW(TAG, "Alert [%s] %s: %s", emotion, status, message);
auto display = Board::GetInstance().GetDisplay();
display->SetStatus(status);
display->SetEmotion(emotion);
@@ -357,6 +386,9 @@ void Application::Start() {
// Update the status bar immediately to show the network state
display->UpdateStatusBar(true);
// Check for new assets version
CheckAssetsVersion();
// Check for new firmware version or get the MQTT broker address
Ota ota;
CheckNewVersion(ota);
@@ -365,7 +397,9 @@ void Application::Start() {
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
// Add MCP common tools before initializing the protocol
McpServer::GetInstance().AddCommonTools();
auto& mcp_server = McpServer::GetInstance();
mcp_server.AddCommonTools();
mcp_server.AddUserOnlyTools();
if (ota.HasMqttConfig()) {
protocol_ = std::make_unique<MqttProtocol>();
@@ -376,6 +410,10 @@ void Application::Start() {
protocol_ = std::make_unique<MqttProtocol>();
}
protocol_->OnConnected([this]() {
DismissAlert();
});
protocol_->OnNetworkError([this](const std::string& message) {
last_error_message_ = message;
xEventGroupSetBits(event_group_, MAIN_EVENT_ERROR);
@@ -469,7 +507,7 @@ void Application::Start() {
auto message = cJSON_GetObjectItem(root, "message");
auto emotion = cJSON_GetObjectItem(root, "emotion");
if (cJSON_IsString(status) && cJSON_IsString(message) && cJSON_IsString(emotion)) {
Alert(status->valuestring, message->valuestring, emotion->valuestring, Lang::Sounds::P3_VIBRATION);
Alert(status->valuestring, message->valuestring, emotion->valuestring, Lang::Sounds::OGG_VIBRATION);
} else {
ESP_LOGW(TAG, "Alert command requires status, message and emotion");
}
@@ -491,6 +529,7 @@ void Application::Start() {
});
bool protocol_started = protocol_->Start();
SystemInfo::PrintHeapStats();
SetDeviceState(kDeviceStateIdle);
has_server_time_ = ota.HasServerTime();
@@ -499,28 +538,14 @@ void Application::Start() {
display->ShowNotification(message.c_str());
display->SetChatMessage("system", "");
// Play the success sound to indicate the device is ready
audio_service_.PlaySound(Lang::Sounds::P3_SUCCESS);
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
}
// Print heap stats
SystemInfo::PrintHeapStats();
// Enter the main event loop
MainEventLoop();
}
void Application::OnClockTimer() {
clock_ticks_++;
auto display = Board::GetInstance().GetDisplay();
display->UpdateStatusBar();
// Print the debug info every 10 seconds
if (clock_ticks_ % 10 == 0) {
// SystemInfo::PrintTaskCpuUsage(pdMS_TO_TICKS(1000));
// SystemInfo::PrintTaskList();
SystemInfo::PrintHeapStats();
}
// Start the main event loop task with priority 3
xTaskCreate([](void* arg) {
((Application*)arg)->MainEventLoop();
vTaskDelete(NULL);
}, "main_event_loop", 2048 * 4, this, 3, &main_event_loop_task_handle_);
}
// Add a async task to MainLoop
@@ -536,23 +561,22 @@ void Application::Schedule(std::function<void()> callback) {
// If other tasks need to access the websocket or chat state,
// they should use Schedule to call this function
void Application::MainEventLoop() {
// Raise the priority of the main event loop to avoid being interrupted by background tasks (which has priority 2)
vTaskPrioritySet(NULL, 3);
while (true) {
auto bits = xEventGroupWaitBits(event_group_, MAIN_EVENT_SCHEDULE |
MAIN_EVENT_SEND_AUDIO |
MAIN_EVENT_WAKE_WORD_DETECTED |
MAIN_EVENT_VAD_CHANGE |
MAIN_EVENT_CLOCK_TICK |
MAIN_EVENT_ERROR, pdTRUE, pdFALSE, portMAX_DELAY);
if (bits & MAIN_EVENT_ERROR) {
SetDeviceState(kDeviceStateIdle);
Alert(Lang::Strings::ERROR, last_error_message_.c_str(), "sad", Lang::Sounds::P3_EXCLAMATION);
Alert(Lang::Strings::ERROR, last_error_message_.c_str(), "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
}
if (bits & MAIN_EVENT_SEND_AUDIO) {
while (auto packet = audio_service_.PopPacketFromSendQueue()) {
if (!protocol_->SendAudio(std::move(packet))) {
if (protocol_ && !protocol_->SendAudio(std::move(packet))) {
break;
}
}
@@ -577,6 +601,19 @@ void Application::MainEventLoop() {
task();
}
}
if (bits & MAIN_EVENT_CLOCK_TICK) {
clock_ticks_++;
auto display = Board::GetInstance().GetDisplay();
display->UpdateStatusBar();
// Print the debug info every 10 seconds
if (clock_ticks_ % 10 == 0) {
// SystemInfo::PrintTaskCpuUsage(pdMS_TO_TICKS(1000));
// SystemInfo::PrintTaskList();
SystemInfo::PrintHeapStats();
}
}
}
}
@@ -609,7 +646,7 @@ void Application::OnWakeWordDetected() {
#else
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
// Play the pop up sound to indicate the wake word is detected
audio_service_.PlaySound(Lang::Sounds::P3_POPUP);
audio_service_.PlaySound(Lang::Sounds::OGG_POPUP);
#endif
} else if (device_state_ == kDeviceStateSpeaking) {
AbortSpeaking(kAbortReasonWakeWordDetected);
@@ -621,7 +658,9 @@ void Application::OnWakeWordDetected() {
void Application::AbortSpeaking(AbortReason reason) {
ESP_LOGI(TAG, "Abort speaking");
aborted_ = true;
protocol_->SendAbortSpeaking(reason);
if (protocol_) {
protocol_->SendAbortSpeaking(reason);
}
}
void Application::SetListeningMode(ListeningMode mode) {
@@ -693,9 +732,70 @@ void Application::SetDeviceState(DeviceState state) {
void Application::Reboot() {
ESP_LOGI(TAG, "Rebooting...");
// Disconnect the audio channel
if (protocol_ && protocol_->IsAudioChannelOpened()) {
protocol_->CloseAudioChannel();
}
protocol_.reset();
audio_service_.Stop();
vTaskDelay(pdMS_TO_TICKS(1000));
esp_restart();
}
bool Application::UpgradeFirmware(Ota& ota, const std::string& url) {
auto& board = Board::GetInstance();
auto display = board.GetDisplay();
// Use provided URL or get from OTA object
std::string upgrade_url = url.empty() ? ota.GetFirmwareUrl() : url;
std::string version_info = url.empty() ? ota.GetFirmwareVersion() : "(Manual upgrade)";
// Close audio channel if it's open
if (protocol_ && protocol_->IsAudioChannelOpened()) {
ESP_LOGI(TAG, "Closing audio channel before firmware upgrade");
protocol_->CloseAudioChannel();
}
ESP_LOGI(TAG, "Starting firmware upgrade from URL: %s", upgrade_url.c_str());
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "download", Lang::Sounds::OGG_UPGRADE);
vTaskDelay(pdMS_TO_TICKS(3000));
SetDeviceState(kDeviceStateUpgrading);
std::string message = std::string(Lang::Strings::NEW_VERSION) + version_info;
display->SetChatMessage("system", message.c_str());
board.SetPowerSaveMode(false);
audio_service_.Stop();
vTaskDelay(pdMS_TO_TICKS(1000));
bool upgrade_success = ota.StartUpgradeFromUrl(upgrade_url, [display](int progress, size_t speed) {
std::thread([display, progress, speed]() {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
display->SetChatMessage("system", buffer);
}).detach();
});
if (!upgrade_success) {
// Upgrade failed, restart audio service and continue running
ESP_LOGE(TAG, "Firmware upgrade failed, restarting audio service and continuing operation...");
audio_service_.Start(); // Restart audio service
board.SetPowerSaveMode(true); // Restore power save mode
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
vTaskDelay(pdMS_TO_TICKS(3000));
return false;
} else {
// Upgrade success, reboot immediately
ESP_LOGI(TAG, "Firmware upgrade successful, rebooting...");
display->SetChatMessage("system", "Upgrade successful, rebooting...");
vTaskDelay(pdMS_TO_TICKS(1000)); // Brief pause to show message
Reboot();
return true;
}
}
void Application::WakeWordInvoke(const std::string& wake_word) {
if (device_state_ == kDeviceStateIdle) {
ToggleChatState();
@@ -735,11 +835,20 @@ bool Application::CanEnterSleepMode() {
}
void Application::SendMcpMessage(const std::string& payload) {
Schedule([this, payload]() {
if (protocol_) {
if (protocol_ == nullptr) {
return;
}
// Make sure you are using main thread to send MCP message
if (xTaskGetCurrentTaskHandle() == main_event_loop_task_handle_) {
ESP_LOGI(TAG, "Send MCP message in main thread");
protocol_->SendMcpMessage(payload);
} else {
ESP_LOGI(TAG, "Send MCP message in sub thread");
Schedule([this, payload = std::move(payload)]() {
protocol_->SendMcpMessage(payload);
}
});
});
}
}
void Application::SetAecMode(AecMode mode) {

View File

@@ -9,7 +9,6 @@
#include <string>
#include <mutex>
#include <deque>
#include <vector>
#include <memory>
#include "protocol.h"
@@ -17,12 +16,15 @@
#include "audio_service.h"
#include "device_state_event.h"
#define MAIN_EVENT_SCHEDULE (1 << 0)
#define MAIN_EVENT_SEND_AUDIO (1 << 1)
#define MAIN_EVENT_WAKE_WORD_DETECTED (1 << 2)
#define MAIN_EVENT_VAD_CHANGE (1 << 3)
#define MAIN_EVENT_ERROR (1 << 4)
#define MAIN_EVENT_CHECK_NEW_VERSION_DONE (1 << 5)
#define MAIN_EVENT_CLOCK_TICK (1 << 6)
enum AecMode {
kAecOff,
@@ -41,6 +43,7 @@ public:
Application& operator=(const Application&) = delete;
void Start();
void MainEventLoop();
DeviceState GetDeviceState() const { return device_state_; }
bool IsVoiceDetected() const { return audio_service_.IsVoiceDetected(); }
void Schedule(std::function<void()> callback);
@@ -53,6 +56,7 @@ public:
void StopListening();
void Reboot();
void WakeWordInvoke(const std::string& wake_word);
bool UpgradeFirmware(Ota& ota, const std::string& url = "");
bool CanEnterSleepMode();
void SendMcpMessage(const std::string& payload);
void SetAecMode(AecMode mode);
@@ -79,13 +83,28 @@ private:
bool aborted_ = false;
int clock_ticks_ = 0;
TaskHandle_t check_new_version_task_handle_ = nullptr;
TaskHandle_t main_event_loop_task_handle_ = nullptr;
void MainEventLoop();
void OnWakeWordDetected();
void CheckNewVersion(Ota& ota);
void CheckAssetsVersion();
void ShowActivationCode(const std::string& code, const std::string& message);
void OnClockTimer();
void SetListeningMode(ListeningMode mode);
};
class TaskPriorityReset {
public:
TaskPriorityReset(BaseType_t priority) {
original_priority_ = uxTaskPriorityGet(NULL);
vTaskPrioritySet(NULL, priority);
}
~TaskPriorityReset() {
vTaskPrioritySet(NULL, original_priority_);
}
private:
BaseType_t original_priority_;
};
#endif // _APPLICATION_H_

406
main/assets.cc Normal file
View File

@@ -0,0 +1,406 @@
#include "assets.h"
#include "board.h"
#include "display.h"
#include "application.h"
#include "lvgl_theme.h"
#include <esp_log.h>
#include <spi_flash_mmap.h>
#include <esp_timer.h>
#include <cbin_font.h>
#define TAG "Assets"
struct mmap_assets_table {
char asset_name[32]; /*!< Name of the asset */
uint32_t asset_size; /*!< Size of the asset */
uint32_t asset_offset; /*!< Offset of the asset */
uint16_t asset_width; /*!< Width of the asset */
uint16_t asset_height; /*!< Height of the asset */
};
Assets::Assets(std::string default_assets_url) {
if (default_assets_url.find("http") == 0) {
default_assets_url_ = default_assets_url;
} else {
ESP_LOGE(TAG, "The default assets url is not a http url: %s", default_assets_url.c_str());
}
// Initialize the partition
InitializePartition();
}
Assets::~Assets() {
if (mmap_handle_ != 0) {
esp_partition_munmap(mmap_handle_);
}
}
uint32_t Assets::CalculateChecksum(const char* data, uint32_t length) {
uint32_t checksum = 0;
for (uint32_t i = 0; i < length; i++) {
checksum += data[i];
}
return checksum & 0xFFFF;
}
bool Assets::InitializePartition() {
partition_valid_ = false;
checksum_valid_ = false;
assets_.clear();
partition_ = esp_partition_find_first(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, "assets");
if (partition_ == nullptr) {
ESP_LOGI(TAG, "No assets partition found");
return false;
}
int free_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
uint32_t storage_size = free_pages * 64 * 1024;
ESP_LOGI(TAG, "The storage free size is %ld KB", storage_size / 1024);
ESP_LOGI(TAG, "The partition size is %ld KB", partition_->size / 1024);
if (storage_size < partition_->size) {
ESP_LOGE(TAG, "The free size %ld KB is less than assets partition required %ld KB", storage_size / 1024, partition_->size / 1024);
return false;
}
esp_err_t err = esp_partition_mmap(partition_, 0, partition_->size, ESP_PARTITION_MMAP_DATA, (const void**)&mmap_root_, &mmap_handle_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mmap assets partition: %s", esp_err_to_name(err));
return false;
}
partition_valid_ = true;
uint32_t stored_files = *(uint32_t*)(mmap_root_ + 0);
uint32_t stored_chksum = *(uint32_t*)(mmap_root_ + 4);
uint32_t stored_len = *(uint32_t*)(mmap_root_ + 8);
if (stored_len > partition_->size - 12) {
ESP_LOGD(TAG, "The stored_len (0x%lx) is greater than the partition size (0x%lx) - 12", stored_len, partition_->size);
return false;
}
auto start_time = esp_timer_get_time();
uint32_t calculated_checksum = CalculateChecksum(mmap_root_ + 12, stored_len);
auto end_time = esp_timer_get_time();
ESP_LOGI(TAG, "The checksum calculation time is %d ms", int((end_time - start_time) / 1000));
if (calculated_checksum != stored_chksum) {
ESP_LOGE(TAG, "The calculated checksum (0x%lx) does not match the stored checksum (0x%lx)", calculated_checksum, stored_chksum);
return false;
}
checksum_valid_ = true;
for (uint32_t i = 0; i < stored_files; i++) {
auto item = (const mmap_assets_table*)(mmap_root_ + 12 + i * sizeof(mmap_assets_table));
auto asset = Asset{
.size = static_cast<size_t>(item->asset_size),
.offset = static_cast<size_t>(12 + sizeof(mmap_assets_table) * stored_files + item->asset_offset)
};
assets_[item->asset_name] = asset;
}
return checksum_valid_;
}
bool Assets::Apply() {
void* ptr = nullptr;
size_t size = 0;
if (!GetAssetData("index.json", ptr, size)) {
ESP_LOGE(TAG, "The index.json file is not found");
return false;
}
cJSON* root = cJSON_ParseWithLength(static_cast<char*>(ptr), size);
if (root == nullptr) {
ESP_LOGE(TAG, "The index.json file is not valid");
return false;
}
cJSON* version = cJSON_GetObjectItem(root, "version");
if (cJSON_IsNumber(version)) {
if (version->valuedouble > 1) {
ESP_LOGE(TAG, "The assets version %d is not supported, please upgrade the firmware", version->valueint);
return false;
}
}
cJSON* srmodels = cJSON_GetObjectItem(root, "srmodels");
if (cJSON_IsString(srmodels)) {
std::string srmodels_file = srmodels->valuestring;
if (GetAssetData(srmodels_file, ptr, size)) {
if (models_list_ != nullptr) {
esp_srmodel_deinit(models_list_);
models_list_ = nullptr;
}
models_list_ = srmodel_load(static_cast<uint8_t*>(ptr));
if (models_list_ != nullptr) {
auto& app = Application::GetInstance();
app.GetAudioService().SetModelsList(models_list_);
} else {
ESP_LOGE(TAG, "Failed to load srmodels.bin");
}
} else {
ESP_LOGE(TAG, "The srmodels file %s is not found", srmodels_file.c_str());
}
}
#ifdef HAVE_LVGL
auto& theme_manager = LvglThemeManager::GetInstance();
auto light_theme = theme_manager.GetTheme("light");
auto dark_theme = theme_manager.GetTheme("dark");
cJSON* font = cJSON_GetObjectItem(root, "text_font");
if (cJSON_IsString(font)) {
std::string fonts_text_file = font->valuestring;
if (GetAssetData(fonts_text_file, ptr, size)) {
auto text_font = std::make_shared<LvglCBinFont>(ptr);
if (text_font->font() == nullptr) {
ESP_LOGE(TAG, "Failed to load fonts.bin");
return false;
}
if (light_theme != nullptr) {
light_theme->set_text_font(text_font);
}
if (dark_theme != nullptr) {
dark_theme->set_text_font(text_font);
}
} else {
ESP_LOGE(TAG, "The font file %s is not found", fonts_text_file.c_str());
}
}
cJSON* emoji_collection = cJSON_GetObjectItem(root, "emoji_collection");
if (cJSON_IsArray(emoji_collection)) {
auto custom_emoji_collection = std::make_shared<EmojiCollection>();
int emoji_count = cJSON_GetArraySize(emoji_collection);
for (int i = 0; i < emoji_count; i++) {
cJSON* emoji = cJSON_GetArrayItem(emoji_collection, i);
if (cJSON_IsObject(emoji)) {
cJSON* name = cJSON_GetObjectItem(emoji, "name");
cJSON* file = cJSON_GetObjectItem(emoji, "file");
if (cJSON_IsString(name) && cJSON_IsString(file)) {
if (!GetAssetData(file->valuestring, ptr, size)) {
ESP_LOGE(TAG, "Emoji %s image file %s is not found", name->valuestring, file->valuestring);
continue;
}
custom_emoji_collection->AddEmoji(name->valuestring, new LvglRawImage(ptr, size));
}
}
}
if (light_theme != nullptr) {
light_theme->set_emoji_collection(custom_emoji_collection);
}
if (dark_theme != nullptr) {
dark_theme->set_emoji_collection(custom_emoji_collection);
}
}
cJSON* skin = cJSON_GetObjectItem(root, "skin");
if (cJSON_IsObject(skin)) {
cJSON* light_skin = cJSON_GetObjectItem(skin, "light");
if (cJSON_IsObject(light_skin) && light_theme != nullptr) {
cJSON* text_color = cJSON_GetObjectItem(light_skin, "text_color");
cJSON* background_color = cJSON_GetObjectItem(light_skin, "background_color");
cJSON* background_image = cJSON_GetObjectItem(light_skin, "background_image");
if (cJSON_IsString(text_color)) {
light_theme->set_text_color(LvglTheme::ParseColor(text_color->valuestring));
}
if (cJSON_IsString(background_color)) {
light_theme->set_background_color(LvglTheme::ParseColor(background_color->valuestring));
light_theme->set_chat_background_color(LvglTheme::ParseColor(background_color->valuestring));
}
if (cJSON_IsString(background_image)) {
if (!GetAssetData(background_image->valuestring, ptr, size)) {
ESP_LOGE(TAG, "The background image file %s is not found", background_image->valuestring);
return false;
}
auto background_image = std::make_shared<LvglCBinImage>(ptr);
light_theme->set_background_image(background_image);
}
}
cJSON* dark_skin = cJSON_GetObjectItem(skin, "dark");
if (cJSON_IsObject(dark_skin) && dark_theme != nullptr) {
cJSON* text_color = cJSON_GetObjectItem(dark_skin, "text_color");
cJSON* background_color = cJSON_GetObjectItem(dark_skin, "background_color");
cJSON* background_image = cJSON_GetObjectItem(dark_skin, "background_image");
if (cJSON_IsString(text_color)) {
dark_theme->set_text_color(LvglTheme::ParseColor(text_color->valuestring));
}
if (cJSON_IsString(background_color)) {
dark_theme->set_background_color(LvglTheme::ParseColor(background_color->valuestring));
dark_theme->set_chat_background_color(LvglTheme::ParseColor(background_color->valuestring));
}
if (cJSON_IsString(background_image)) {
if (!GetAssetData(background_image->valuestring, ptr, size)) {
ESP_LOGE(TAG, "The background image file %s is not found", background_image->valuestring);
return false;
}
auto background_image = std::make_shared<LvglCBinImage>(ptr);
dark_theme->set_background_image(background_image);
}
}
}
#endif
auto display = Board::GetInstance().GetDisplay();
ESP_LOGI(TAG, "Refreshing display theme...");
auto current_theme = display->GetTheme();
if (current_theme != nullptr) {
display->SetTheme(current_theme);
}
cJSON_Delete(root);
return true;
}
bool Assets::Download(std::string url, std::function<void(int progress, size_t speed)> progress_callback) {
ESP_LOGI(TAG, "Downloading new version of assets from %s", url.c_str());
// 取消当前资源分区的内存映射
if (mmap_handle_ != 0) {
esp_partition_munmap(mmap_handle_);
mmap_handle_ = 0;
mmap_root_ = nullptr;
}
checksum_valid_ = false;
assets_.clear();
// 下载新的资源文件
auto network = Board::GetInstance().GetNetwork();
auto http = network->CreateHttp(0);
if (!http->Open("GET", url)) {
ESP_LOGE(TAG, "Failed to open HTTP connection");
return false;
}
if (http->GetStatusCode() != 200) {
ESP_LOGE(TAG, "Failed to get assets, status code: %d", http->GetStatusCode());
return false;
}
size_t content_length = http->GetBodyLength();
if (content_length == 0) {
ESP_LOGE(TAG, "Failed to get content length");
return false;
}
if (content_length > partition_->size) {
ESP_LOGE(TAG, "Assets file size (%u) is larger than partition size (%lu)", content_length, partition_->size);
return false;
}
// 定义扇区大小为4KBESP32的标准扇区大小
const size_t SECTOR_SIZE = esp_partition_get_main_flash_sector_size();
// 计算需要擦除的扇区数量
size_t sectors_to_erase = (content_length + SECTOR_SIZE - 1) / SECTOR_SIZE; // 向上取整
size_t total_erase_size = sectors_to_erase * SECTOR_SIZE;
ESP_LOGI(TAG, "Sector size: %u, content length: %u, sectors to erase: %u, total erase size: %u",
SECTOR_SIZE, content_length, sectors_to_erase, total_erase_size);
// 写入新的资源文件到分区一边erase一边写入
char buffer[512];
size_t total_written = 0;
size_t recent_written = 0;
size_t current_sector = 0;
auto last_calc_time = esp_timer_get_time();
while (true) {
int ret = http->Read(buffer, sizeof(buffer));
if (ret < 0) {
ESP_LOGE(TAG, "Failed to read HTTP data: %s", esp_err_to_name(ret));
return false;
}
if (ret == 0) {
break;
}
// 检查是否需要擦除新的扇区
size_t write_end_offset = total_written + ret;
size_t needed_sectors = (write_end_offset + SECTOR_SIZE - 1) / SECTOR_SIZE;
// 擦除需要的新扇区
while (current_sector < needed_sectors) {
size_t sector_start = current_sector * SECTOR_SIZE;
size_t sector_end = (current_sector + 1) * SECTOR_SIZE;
// 确保擦除范围不超过分区大小
if (sector_end > partition_->size) {
ESP_LOGE(TAG, "Sector end (%u) exceeds partition size (%lu)", sector_end, partition_->size);
return false;
}
ESP_LOGD(TAG, "Erasing sector %u (offset: %u, size: %u)", current_sector, sector_start, SECTOR_SIZE);
esp_err_t err = esp_partition_erase_range(partition_, sector_start, SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase sector %u at offset %u: %s", current_sector, sector_start, esp_err_to_name(err));
return false;
}
current_sector++;
}
// 写入数据到分区
esp_err_t err = esp_partition_write(partition_, total_written, buffer, ret);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write to assets partition at offset %u: %s", total_written, esp_err_to_name(err));
return false;
}
total_written += ret;
recent_written += ret;
// 计算进度和速度
if (esp_timer_get_time() - last_calc_time >= 1000000 || total_written == content_length || ret == 0) {
size_t progress = total_written * 100 / content_length;
size_t speed = recent_written; // 每秒的字节数
ESP_LOGI(TAG, "Progress: %u%% (%u/%u), Speed: %u B/s, Sectors erased: %u",
progress, total_written, content_length, speed, current_sector);
if (progress_callback) {
progress_callback(progress, speed);
}
last_calc_time = esp_timer_get_time();
recent_written = 0; // 重置最近写入的字节数
}
}
http->Close();
if (total_written != content_length) {
ESP_LOGE(TAG, "Downloaded size (%u) does not match expected size (%u)", total_written, content_length);
return false;
}
ESP_LOGI(TAG, "Assets download completed, total written: %u bytes, total sectors erased: %u",
total_written, current_sector);
// 重新初始化资源分区
if (!InitializePartition()) {
ESP_LOGE(TAG, "Failed to re-initialize assets partition");
return false;
}
return true;
}
bool Assets::GetAssetData(const std::string& name, void*& ptr, size_t& size) {
auto asset = assets_.find(name);
if (asset == assets_.end()) {
return false;
}
auto data = (const char*)(mmap_root_ + asset->second.offset);
if (data[0] != 'Z' || data[1] != 'Z') {
ESP_LOGE(TAG, "The asset %s is not valid with magic %02x%02x", name.c_str(), data[0], data[1]);
return false;
}
ptr = static_cast<void*>(const_cast<char*>(data + 2));
size = asset->second.size;
return true;
}

65
main/assets.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef ASSETS_H
#define ASSETS_H
#include <map>
#include <string>
#include <functional>
#include <cJSON.h>
#include <esp_partition.h>
#include <model_path.h>
// All combinations of wakenet_model, text_font, emoji_collection can be found from the following url:
// https://github.com/78/xiaozhi-fonts/releases/tag/assets
#define ASSETS_PUHUI_COMMON_14_1 "none-font_puhui_common_14_1-none.bin"
#define ASSETS_XIAOZHI_WAKENET "wn9_nihaoxiaozhi_tts-none-none.bin"
#define ASSETS_XIAOZHI_WAKENET_SMALL "wn9s_nihaoxiaozhi-none-none.bin"
#define ASSETS_XIAOZHI_PUHUI_COMMON_14_1 "wn9_nihaoxiaozhi_tts-font_puhui_common_14_1-none.bin"
#define ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32 "wn9_nihaoxiaozhi_tts-font_puhui_common_16_4-emojis_32.bin"
#define ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64 "wn9_nihaoxiaozhi_tts-font_puhui_common_16_4-emojis_64.bin"
#define ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64 "wn9_nihaoxiaozhi_tts-font_puhui_common_20_4-emojis_64.bin"
#define ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64 "wn9_nihaoxiaozhi_tts-font_puhui_common_30_4-emojis_64.bin"
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_14_1 "wn9s_nihaoxiaozhi-font_puhui_common_14_1-none.bin"
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_16_4_EMOJI_32 "wn9s_nihaoxiaozhi-font_puhui_common_16_4-emojis_32.bin"
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_32 "wn9s_nihaoxiaozhi-font_puhui_common_20_4-emojis_32.bin"
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_64 "wn9s_nihaoxiaozhi-font_puhui_common_20_4-emojis_64.bin"
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_30_4_EMOJI_64 "wn9s_nihaoxiaozhi-font_puhui_common_30_4-emojis_64.bin"
struct Asset {
size_t size;
size_t offset;
};
class Assets {
public:
Assets(std::string default_assets_url);
~Assets();
bool Download(std::string url, std::function<void(int progress, size_t speed)> progress_callback);
bool Apply();
inline bool partition_valid() const { return partition_valid_; }
inline bool checksum_valid() const { return checksum_valid_; }
inline std::string default_assets_url() const { return default_assets_url_; }
private:
Assets(const Assets&) = delete;
Assets& operator=(const Assets&) = delete;
bool InitializePartition();
uint32_t CalculateChecksum(const char* data, uint32_t length);
bool GetAssetData(const std::string& name, void*& ptr, size_t& size);
const esp_partition_t* partition_ = nullptr;
esp_partition_mmap_handle_t mmap_handle_ = 0;
const char* mmap_root_ = nullptr;
bool partition_valid_ = false;
bool checksum_valid_ = false;
std::string default_assets_url_;
srmodel_list_t* models_list_ = nullptr;
std::map<std::string, Asset> assets_;
};
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,55 @@
{
"language": {
"type": "ar-SA"
},
"strings": {
"WARNING": "تحذير",
"INFO": "معلومات",
"ERROR": "خطأ",
"VERSION": "الإصدار ",
"LOADING_PROTOCOL": "الاتصال بالخادم...",
"INITIALIZING": "التهيئة...",
"PIN_ERROR": "يرجى إدخال بطاقة SIM",
"REG_ERROR": "لا يمكن الوصول إلى الشبكة، يرجى التحقق من حالة بطاقة البيانات",
"DETECTING_MODULE": "اكتشاف الوحدة...",
"REGISTERING_NETWORK": "انتظار الشبكة...",
"CHECKING_NEW_VERSION": "فحص الإصدار الجديد...",
"CHECK_NEW_VERSION_FAILED": "فشل فحص الإصدار الجديد، سيتم المحاولة خلال %d ثانية: %s",
"SWITCH_TO_WIFI_NETWORK": "التبديل إلى Wi-Fi...",
"SWITCH_TO_4G_NETWORK": "التبديل إلى 4G...",
"STANDBY": "في الانتظار",
"CONNECT_TO": "الاتصال بـ ",
"CONNECTING": "جاري الاتصال...",
"CONNECTED_TO": "متصل بـ ",
"LISTENING": "الاستماع...",
"SPEAKING": "التحدث...",
"SERVER_NOT_FOUND": "البحث عن خدمة متاحة",
"SERVER_NOT_CONNECTED": "لا يمكن الاتصال بالخدمة، يرجى المحاولة لاحقاً",
"SERVER_TIMEOUT": "انتهت مهلة الاستجابة",
"SERVER_ERROR": "فشل الإرسال، يرجى التحقق من الشبكة",
"CONNECT_TO_HOTSPOT": "اتصل الهاتف بنقطة الاتصال ",
"ACCESS_VIA_BROWSER": "،الوصول عبر المتصفح ",
"WIFI_CONFIG_MODE": "وضع تكوين الشبكة",
"ENTERING_WIFI_CONFIG_MODE": "الدخول في وضع تكوين الشبكة...",
"SCANNING_WIFI": "فحص Wi-Fi...",
"NEW_VERSION": "إصدار جديد ",
"OTA_UPGRADE": "تحديث OTA",
"UPGRADING": "تحديث النظام...",
"UPGRADE_FAILED": "فشل التحديث",
"ACTIVATION": "تفعيل الجهاز",
"BATTERY_LOW": "البطارية منخفضة",
"BATTERY_CHARGING": "جاري الشحن",
"BATTERY_FULL": "البطارية ممتلئة",
"BATTERY_NEED_CHARGE": "البطارية منخفضة، يرجى الشحن",
"VOLUME": "الصوت ",
"MUTED": "صامت",
"MAX_VOLUME": "أقصى صوت",
"RTC_MODE_OFF": "AEC مُوقف",
"RTC_MODE_ON": "AEC مُشغل",
"DOWNLOAD_ASSETS_FAILED": "فشل في تنزيل الموارد",
"LOADING_ASSETS": "جاري تحميل الموارد...",
"PLEASE_WAIT": "يرجى الانتظار...",
"FOUND_NEW_ASSETS": "تم العثور على موارد جديدة: %s",
"HELLO_MY_FRIEND": "مرحباً، صديقي!"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,55 @@
{
"language": {
"type": "cs-CZ"
},
"strings": {
"WARNING": "Varování",
"INFO": "Informace",
"ERROR": "Chyba",
"VERSION": "Verze ",
"LOADING_PROTOCOL": "Připojování k serveru...",
"INITIALIZING": "Inicializace...",
"PIN_ERROR": "Prosím vložte SIM kartu",
"REG_ERROR": "Nelze se připojit k síti, zkontrolujte stav datové karty",
"DETECTING_MODULE": "Detekce modulu...",
"REGISTERING_NETWORK": "Čekání na síť...",
"CHECKING_NEW_VERSION": "Kontrola nové verze...",
"CHECK_NEW_VERSION_FAILED": "Kontrola nové verze selhala, opakování za %d sekund: %s",
"SWITCH_TO_WIFI_NETWORK": "Přepínání na Wi-Fi...",
"SWITCH_TO_4G_NETWORK": "Přepínání na 4G...",
"STANDBY": "Pohotovost",
"CONNECT_TO": "Připojit k ",
"CONNECTING": "Připojování...",
"CONNECTED_TO": "Připojeno k ",
"LISTENING": "Naslouchání...",
"SPEAKING": "Mluvení...",
"SERVER_NOT_FOUND": "Hledání dostupné služby",
"SERVER_NOT_CONNECTED": "Nelze se připojit ke službě, zkuste to později",
"SERVER_TIMEOUT": "Čas odpovědi vypršel",
"SERVER_ERROR": "Odeslání selhalo, zkontrolujte síť",
"CONNECT_TO_HOTSPOT": "Připojte telefon k hotspotu ",
"ACCESS_VIA_BROWSER": "přístup přes prohlížeč ",
"WIFI_CONFIG_MODE": "Režim konfigurace sítě",
"ENTERING_WIFI_CONFIG_MODE": "Vstup do režimu konfigurace sítě...",
"SCANNING_WIFI": "Skenování Wi-Fi...",
"NEW_VERSION": "Nová verze ",
"OTA_UPGRADE": "OTA upgrade",
"UPGRADING": "Aktualizace systému...",
"UPGRADE_FAILED": "Upgrade selhal",
"ACTIVATION": "Aktivace zařízení",
"BATTERY_LOW": "Slabá baterie",
"BATTERY_CHARGING": "Nabíjení",
"BATTERY_FULL": "Baterie plná",
"BATTERY_NEED_CHARGE": "Slabá baterie, prosím nabijte",
"VOLUME": "Hlasitost ",
"MUTED": "Ztlumeno",
"MAX_VOLUME": "Maximální hlasitost",
"RTC_MODE_OFF": "AEC vypnuto",
"RTC_MODE_ON": "AEC zapnuto",
"DOWNLOAD_ASSETS_FAILED": "Nepodařilo se stáhnout prostředky",
"LOADING_ASSETS": "Načítání prostředků...",
"PLEASE_WAIT": "Prosím čekejte...",
"FOUND_NEW_ASSETS": "Nalezeny nové prostředky: %s",
"HELLO_MY_FRIEND": "Ahoj, můj příteli!"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More