forked from xiaozhi/xiaozhi-esp32
Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43ef2f4e7f | ||
|
|
3f54330ac9 | ||
|
|
99a4fc94bf | ||
|
|
c052903ade | ||
|
|
6a4ec9dbbd | ||
|
|
7a85430465 | ||
|
|
e8ed16bb42 | ||
|
|
3176a45ebe | ||
|
|
a601a5cbc1 | ||
|
|
ac03f8097d | ||
|
|
92238612b6 | ||
|
|
c62ab7b239 | ||
|
|
992be9a636 | ||
|
|
60ad1c5afc | ||
|
|
4854bda302 | ||
|
|
1ccd5108c3 | ||
|
|
1d1f9ff1ff | ||
|
|
8373a26f85 | ||
|
|
6a28a98c8b | ||
|
|
549399b795 | ||
|
|
3ee2195340 | ||
|
|
2fd0ff0b2a | ||
|
|
911fee2d85 | ||
|
|
68b0e225a2 | ||
|
|
dd45d0de26 | ||
|
|
916ea39fad | ||
|
|
983d86a334 | ||
|
|
e7fc9ed489 | ||
|
|
e329fcc6b8 | ||
|
|
d3e7fee828 | ||
|
|
96e39bea1b | ||
|
|
a8687f3736 | ||
|
|
8d58bdb21b | ||
|
|
4616fa3486 | ||
|
|
f11f84dfbd | ||
|
|
f418c16b2c | ||
|
|
a1e1f73886 | ||
|
|
d2e99bae34 | ||
|
|
d188415949 | ||
|
|
5018f6c03a | ||
|
|
b413e3ec03 | ||
|
|
fe7ae99a4d | ||
|
|
147d71b9f1 | ||
|
|
384da9fd0f | ||
|
|
ae40f72a39 | ||
|
|
d0ba3a923c | ||
|
|
76c19a0f2d | ||
|
|
f79506d58b | ||
|
|
469ee2d92a | ||
|
|
57c2c64047 | ||
|
|
4048647ef8 | ||
|
|
bce662d135 | ||
|
|
d04b08133f | ||
|
|
897239e997 | ||
|
|
83f6f8c703 | ||
|
|
3a3dfc003e | ||
|
|
fc355605f5 | ||
|
|
5d3f597137 | ||
|
|
3e37551923 | ||
|
|
d09537ed5c | ||
|
|
86921f4862 | ||
|
|
7af366b7b2 | ||
|
|
ddbb24942d | ||
|
|
610a4a0703 | ||
|
|
7cd37427b2 | ||
|
|
2d772dad68 | ||
|
|
156eb15f58 | ||
|
|
c59c515706 | ||
|
|
44b8d5e4c1 | ||
|
|
cc07ef447e | ||
|
|
cf4afde88e | ||
|
|
d6b1414967 | ||
|
|
00dd89079b | ||
|
|
cfb635d870 | ||
|
|
9ae34d3b45 | ||
|
|
08b8b04c6c | ||
|
|
f890acfc7c | ||
|
|
a4fe4d8d99 | ||
|
|
593b495139 | ||
|
|
2a02dd65be | ||
|
|
845b760db3 | ||
|
|
f86637cf1c | ||
|
|
363073658a | ||
|
|
da228f2582 | ||
|
|
36476f05cd | ||
|
|
90602d3802 | ||
|
|
b2e1c5bb5c | ||
|
|
d58d55cfe7 | ||
|
|
cd23e0f155 | ||
|
|
26d9ff283f | ||
|
|
fb85019c3c | ||
|
|
4859d57fea | ||
|
|
03394fe38d | ||
|
|
e0e12450c5 | ||
|
|
e5ac40aac8 | ||
|
|
345c8be467 | ||
|
|
def6301292 | ||
|
|
df7cbdfcb6 | ||
|
|
d38763d5ef | ||
|
|
e90e540933 | ||
|
|
656bf3c7fa | ||
|
|
ca35b0761b | ||
|
|
b031a829c0 | ||
|
|
3c11cceb43 | ||
|
|
15f233e773 | ||
|
|
721b58f8c7 | ||
|
|
eb0bba2c89 |
117
.github/workflows/build.yml
vendored
117
.github/workflows/build.yml
vendored
@@ -1,32 +1,111 @@
|
||||
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 variants to build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
variants: ${{ steps.select.outputs.variants }}
|
||||
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 variant list
|
||||
run: |
|
||||
echo "all_variants=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: select
|
||||
name: Select variants based on changes
|
||||
env:
|
||||
ALL_VARIANTS: ${{ steps.list.outputs.all_variants }}
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
|
||||
# push 到 main 分支,编译全部变体
|
||||
if [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "variants=$ALL_VARIANTS" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 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 -e "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/common/* ]]; 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 "variants=$ALL_VARIANTS" >> $GITHUB_OUTPUT
|
||||
else
|
||||
if [[ ${#AFFECTED[@]} -eq 0 ]]; then
|
||||
echo "variants=[]" >> $GITHUB_OUTPUT
|
||||
else
|
||||
BOARDS_JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||
FILTERED=$(echo "$ALL_VARIANTS" | jq -c --argjson boards "$BOARDS_JSON" 'map(select(.board as $b | $boards | index($b)))')
|
||||
echo "variants=$FILTERED" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
|
||||
build:
|
||||
name: Build ${{ matrix.name }}
|
||||
needs: prepare
|
||||
if: ${{ needs.prepare.outputs.variants != '[]' }}
|
||||
strategy:
|
||||
fail-fast: false # 单个变体失败不影响其它变体
|
||||
matrix:
|
||||
include: ${{ fromJson(needs.prepare.outputs.variants) }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: espressif/idf:release-v5.5
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build current variant
|
||||
shell: bash
|
||||
run: |
|
||||
source $IDF_PATH/export.sh
|
||||
python scripts/release.py ${{ matrix.board }} --name ${{ matrix.name }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: xiaozhi_${{ matrix.name }}_${{ github.sha }}.bin
|
||||
path: build/merged-binary.bin
|
||||
if-no-files-found: error
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -13,6 +13,7 @@ main/assets/lang_config.h
|
||||
main/mmap_generate_emoji.h
|
||||
.DS_Store
|
||||
.cache
|
||||
main/mmap_generate_emoji.h
|
||||
*.pyc
|
||||
*.bin
|
||||
*.bin
|
||||
mmap_generate_*.h
|
||||
.clangd
|
||||
|
||||
@@ -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.4")
|
||||
|
||||
# Add this line to disable the specific warning
|
||||
add_compile_options(-Wno-missing-field-initializers)
|
||||
|
||||
3
LICENSE
3
LICENSE
@@ -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
|
||||
|
||||
37
README.md
37
README.md
@@ -1,26 +1,24 @@
|
||||
# An MCP-based Chatbot | 一个基于 MCP 的聊天机器人
|
||||
# An MCP-based Chatbot
|
||||
|
||||
(中文 | [English](README_en.md) | [日本語](README_ja.md))
|
||||
|
||||
## 视频
|
||||
## 介绍
|
||||
|
||||
👉 [人类:给 AI 装摄像头 vs AI:当场发现主人三天没洗头【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [手工打造你的 AI 女友,新手入门教程【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
## 介绍
|
||||
|
||||
这是一个由虾哥开源的 ESP32 项目,以 MIT 许可证发布,允许任何人免费使用,或用于商业用途。
|
||||
|
||||
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
|
||||
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:1011329060
|
||||
|
||||
### 基于 MCP 控制万物
|
||||
|
||||
小智 AI 聊天机器人作为一个语音交互入口,利用 Qwen / DeepSeek 等大模型的 AI 能力,通过 MCP 协议实现多端控制。
|
||||
|
||||

|
||||
<img src="docs/mcp-based-graph.jpg" alt="通过MCP控制万物" width="320">
|
||||
|
||||
### 版本说明
|
||||
|
||||
当前 v2 版本与 v1 版本分区表不兼容,所以无法从 v1 版本通过 OTA 升级到 v2 版本。分区表说明参见 [partitions/v2/README.md](partitions/v2/README.md)。
|
||||
|
||||
使用 v1 版本的所有硬件,可以通过手动烧录固件来升级到 v2 版本。
|
||||
|
||||
v1 的稳定版本为 1.9.2,可以通过 `git checkout v1` 来切换到 v1 版本,该分支会持续维护到 2026 年 2 月。
|
||||
|
||||
### 已实现功能
|
||||
|
||||
@@ -36,6 +34,7 @@
|
||||
- 支持 ESP32-C3、ESP32-S3、ESP32-P4 芯片平台
|
||||
- 通过设备端 MCP 实现设备控制(音量、灯光、电机、GPIO 等)
|
||||
- 通过云端 MCP 扩展大模型能力(智能家居控制、PC桌面操作、知识搜索、邮件收发等)
|
||||
- 自定义唤醒词、字体、表情与聊天背景,支持网页端在线修改 ([自定义Assets生成器](https://github.com/78/xiaozhi-assets-generator))
|
||||
|
||||
## 硬件
|
||||
|
||||
@@ -122,7 +121,7 @@
|
||||
|
||||
### 开发者文档
|
||||
|
||||
- [自定义开发板指南](main/boards/README.md) - 学习如何为小智 AI 创建自定义开发板
|
||||
- [自定义开发板指南](docs/custom-board.md) - 学习如何为小智 AI 创建自定义开发板
|
||||
- [MCP 协议物联网控制用法说明](docs/mcp-usage.md) - 了解如何通过 MCP 协议控制物联网设备
|
||||
- [MCP 协议交互流程](docs/mcp-protocol.md) - 设备端 MCP 协议的实现方式
|
||||
- [MQTT + UDP 混合通信协议文档](docs/mqtt-udp.md)
|
||||
@@ -130,7 +129,7 @@
|
||||
|
||||
## 大模型配置
|
||||
|
||||
如果你已经拥有一个的小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
|
||||
👉 [后台操作视频教程(旧版界面)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
|
||||
@@ -150,6 +149,14 @@
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) 思澈科技的蓝牙芯片固件
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) 移远提供的 QuecPython 固件
|
||||
|
||||
## 关于项目
|
||||
|
||||
这是一个由虾哥开源的 ESP32 项目,以 MIT 许可证发布,允许任何人免费使用,修改或用于商业用途。
|
||||
|
||||
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
|
||||
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:1011329060
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#78/xiaozhi-esp32&Date">
|
||||
|
||||
41
README_en.md
41
README_en.md
@@ -2,25 +2,23 @@
|
||||
|
||||
(English | [中文](README.md) | [日本語](README_ja.md))
|
||||
|
||||
## Video
|
||||
## Introduction
|
||||
|
||||
👉 [Human: Give AI a camera vs AI: Instantly finds out the owner hasn't washed hair for three days【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [Handcraft your AI girlfriend, beginner's guide【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
## Introduction
|
||||
|
||||
This is an open-source ESP32 project, released under the MIT license, allowing anyone to use it for free, including for commercial purposes.
|
||||
|
||||
We hope this project helps everyone understand AI hardware development and apply rapidly evolving large language models to real hardware devices.
|
||||
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join the QQ group: 1011329060
|
||||
|
||||
### Control Everything with MCP
|
||||
|
||||
As a voice interaction entry, the XiaoZhi AI chatbot leverages the AI capabilities of large models like Qwen / DeepSeek, and achieves multi-terminal control via the MCP protocol.
|
||||
|
||||

|
||||
<img src="docs/mcp-based-graph.jpg" alt="Control everything via MCP" width="320">
|
||||
|
||||
## Version Notes
|
||||
|
||||
The current v2 version is incompatible with the v1 partition table, so it is not possible to upgrade from v1 to v2 via OTA. For partition table details, see [partitions/v2/README.md](partitions/v2/README.md).
|
||||
|
||||
All hardware running v1 can be upgraded to v2 by manually flashing the firmware.
|
||||
|
||||
The stable version of v1 is 1.9.2. You can switch to v1 by running `git checkout v1`. The v1 branch will be maintained until February 2026.
|
||||
|
||||
### Features Implemented
|
||||
|
||||
@@ -36,6 +34,7 @@ As a voice interaction entry, the XiaoZhi AI chatbot leverages the AI capabiliti
|
||||
- Supports ESP32-C3, ESP32-S3, ESP32-P4 chip platforms
|
||||
- Device-side MCP for device control (Speaker, LED, Servo, GPIO, etc.)
|
||||
- Cloud-side MCP to extend large model capabilities (smart home control, PC desktop operation, knowledge search, email, etc.)
|
||||
- Customizable wake words, fonts, emojis, and chat backgrounds with online web-based editing ([Custom Assets Generator](https://github.com/78/xiaozhi-assets-generator))
|
||||
|
||||
## Hardware
|
||||
|
||||
@@ -122,9 +121,10 @@ The firmware connects to the official [xiaozhi.me](https://xiaozhi.me) server by
|
||||
|
||||
### Developer Documentation
|
||||
|
||||
- [Custom Board Guide](main/boards/README.md) - Learn how to create custom boards for XiaoZhi AI
|
||||
- [Custom Board Guide](docs/custom-board.md) - Learn how to create custom boards for XiaoZhi AI
|
||||
- [MCP Protocol IoT Control Usage](docs/mcp-usage.md) - Learn how to control IoT devices via MCP protocol
|
||||
- [MCP Protocol Interaction Flow](docs/mcp-protocol.md) - Device-side MCP protocol implementation
|
||||
- [MQTT + UDP Hybrid Communication Protocol Document](docs/mqtt-udp.md)
|
||||
- [A detailed WebSocket communication protocol document](docs/websocket.md)
|
||||
|
||||
## Large Model Configuration
|
||||
@@ -145,6 +145,21 @@ Other client projects using the XiaoZhi communication protocol:
|
||||
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Python client
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Android client
|
||||
- [100askTeam/xiaozhi-linux](http://github.com/100askTeam/xiaozhi-linux) Linux client by 100ask
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) Bluetooth chip firmware by Sichuan
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) QuecPython firmware by Quectel
|
||||
|
||||
Custom Assets Tools:
|
||||
|
||||
- [78/xiaozhi-assets-generator](https://github.com/78/xiaozhi-assets-generator) Custom Assets Generator (Wake words, fonts, emojis, backgrounds)
|
||||
|
||||
## About the Project
|
||||
|
||||
This is an open-source ESP32 project, released under the MIT license, allowing anyone to use it for free, including for commercial purposes.
|
||||
|
||||
We hope this project helps everyone understand AI hardware development and apply rapidly evolving large language models to real hardware devices.
|
||||
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join the QQ group: 1011329060
|
||||
|
||||
## Star History
|
||||
|
||||
|
||||
37
README_ja.md
37
README_ja.md
@@ -2,25 +2,23 @@
|
||||
|
||||
(日本語 | [中文](README.md) | [English](README_en.md))
|
||||
|
||||
## 動画
|
||||
## はじめに
|
||||
|
||||
👉 [人間:AIにカメラを装着 vs AI:その場で飼い主が3日間髪を洗っていないことを発見【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [手作りでAIガールフレンドを作る、初心者入門チュートリアル【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
## イントロダクション
|
||||
|
||||
これはエビ兄さんがオープンソースで公開しているESP32プロジェクトで、MITライセンスのもと、誰でも無料で、商用利用も可能です。
|
||||
|
||||
このプロジェクトを通じて、AIハードウェア開発を理解し、急速に進化する大規模言語モデルを実際のハードウェアデバイスに応用できるようになることを目指しています。
|
||||
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、QQグループ:1011329060 にご参加ください。
|
||||
|
||||
### MCPであらゆるものを制御
|
||||
|
||||
シャオジーAIチャットボットは音声インタラクションの入口として、Qwen / DeepSeekなどの大規模モデルのAI能力を活用し、MCPプロトコルを通じてマルチエンド制御を実現します。
|
||||
|
||||

|
||||
<img src="docs/mcp-based-graph.jpg" alt="MCPであらゆるものを制御" width="320">
|
||||
|
||||
## バージョンノート
|
||||
|
||||
現在のv2バージョンはv1パーティションテーブルと互換性がないため、v1からv2へOTAでアップグレードすることはできません。パーティションテーブルの詳細については、[partitions/v2/README.md](partitions/v2/README.md)をご参照ください。
|
||||
|
||||
v1を実行しているすべてのハードウェアは、ファームウェアを手動で書き込むことでv2にアップグレードできます。
|
||||
|
||||
v1の安定版は1.9.2です。`git checkout v1`でv1に切り替えることができます。v1ブランチは2026年2月まで継続的にメンテナンスされます。
|
||||
|
||||
### 実装済み機能
|
||||
|
||||
@@ -36,6 +34,7 @@
|
||||
- ESP32-C3、ESP32-S3、ESP32-P4チッププラットフォーム対応
|
||||
- デバイス側MCPによるデバイス制御(音量・明るさ調整、アクション制御など)
|
||||
- クラウド側MCPで大規模モデル能力を拡張(スマートホーム制御、PCデスクトップ操作、知識検索、メール送受信など)
|
||||
- カスタマイズ可能なウェイクワード、フォント、絵文字、チャット背景、オンラインWeb編集に対応 ([カスタムアセットジェネレーター](https://github.com/78/xiaozhi-assets-generator))
|
||||
|
||||
## ハードウェア
|
||||
|
||||
@@ -122,9 +121,10 @@ Feishuドキュメントチュートリアルをご覧ください:
|
||||
|
||||
### 開発者ドキュメント
|
||||
|
||||
- [カスタム開発ボードガイド](main/boards/README.md) - シャオジーAI用のカスタム開発ボード作成方法
|
||||
- [カスタム開発ボードガイド](docs/custom-board.md) - シャオジーAI用のカスタム開発ボード作成方法
|
||||
- [MCPプロトコルIoT制御使用法](docs/mcp-usage.md) - MCPプロトコルでIoTデバイスを制御する方法
|
||||
- [MCPプロトコルインタラクションフロー](docs/mcp-protocol.md) - デバイス側MCPプロトコルの実装方法
|
||||
- [MQTT + UDP ハイブリッド通信プロトコルドキュメント](docs/mqtt-udp.md)
|
||||
- [詳細なWebSocket通信プロトコルドキュメント](docs/websocket.md)
|
||||
|
||||
## 大規模モデル設定
|
||||
@@ -145,6 +145,17 @@ Feishuドキュメントチュートリアルをご覧ください:
|
||||
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Pythonクライアント
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Androidクライアント
|
||||
- [100askTeam/xiaozhi-linux](http://github.com/100askTeam/xiaozhi-linux) 百問科技提供のLinuxクライアント
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) 思澈科技のBluetoothチップファームウェア
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) 移遠提供のQuecPythonファームウェア
|
||||
|
||||
## プロジェクトについて
|
||||
|
||||
これはエビ兄さんがオープンソースで公開しているESP32プロジェクトで、MITライセンスのもと、誰でも無料で、商用利用も可能です。
|
||||
|
||||
このプロジェクトを通じて、AIハードウェア開発を理解し、急速に進化する大規模言語モデルを実際のハードウェアデバイスに応用できるようになることを目指しています。
|
||||
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、QQグループ:1011329060 にご参加ください。
|
||||
|
||||
## スター履歴
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
### 1. 创建新的开发板目录
|
||||
|
||||
首先在`boards/`目录下创建一个新的目录,例如`my-custom-board/`:
|
||||
首先在`boards/`目录下创建一个新的目录,命名方式应使用 `[品牌名]-[开发板类型]` 的形式,例如 `m5stack-tab5`:
|
||||
|
||||
```bash
|
||||
mkdir main/boards/my-custom-board
|
||||
@@ -87,24 +87,51 @@ mkdir main/boards/my-custom-board
|
||||
|
||||
#### config.json
|
||||
|
||||
在`config.json`中定义编译配置:
|
||||
在`config.json`中定义编译配置,这个文件用于 `scripts/release.py` 脚本自动化编译:
|
||||
|
||||
```json
|
||||
{
|
||||
"target": "esp32s3", // 目标芯片型号: esp32, esp32s3, esp32c3等
|
||||
"target": "esp32s3", // 目标芯片型号: esp32, esp32s3, esp32c3, esp32c6, esp32p4等
|
||||
"builds": [
|
||||
{
|
||||
"name": "my-custom-board", // 开发板名称
|
||||
"name": "my-custom-board", // 开发板名称,用于生成固件包
|
||||
"sdkconfig_append": [
|
||||
// 额外需要的编译配置
|
||||
// 特别 Flash 大小配置
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v1/8m.csv\""
|
||||
// 特别分区表配置
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**配置项说明:**
|
||||
- `target`: 目标芯片型号,必须与硬件匹配
|
||||
- `name`: 编译输出的固件包名称,建议与目录名一致
|
||||
- `sdkconfig_append`: 额外的 sdkconfig 配置项数组,会追加到默认配置中
|
||||
|
||||
**常用的 sdkconfig_append 配置:**
|
||||
```json
|
||||
// Flash 大小
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y" // 4MB Flash
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y" // 8MB Flash
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y" // 16MB Flash
|
||||
|
||||
// 分区表
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/4m.csv\"" // 4MB 分区表
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"" // 8MB 分区表
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/16m.csv\"" // 16MB 分区表
|
||||
|
||||
// 语言配置
|
||||
"CONFIG_LANGUAGE_EN_US=y" // 英语
|
||||
"CONFIG_LANGUAGE_ZH_CN=y" // 简体中文
|
||||
|
||||
// 唤醒词配置
|
||||
"CONFIG_USE_DEVICE_AEC=y" // 启用设备端 AEC
|
||||
"CONFIG_WAKE_WORD_DISABLED=y" // 禁用唤醒词
|
||||
```
|
||||
|
||||
### 3. 编写板级初始化代码
|
||||
|
||||
创建一个`my_custom_board.cc`文件,实现开发板的所有初始化逻辑。
|
||||
@@ -131,10 +158,6 @@ mkdir main/boards/my-custom-board
|
||||
|
||||
#define TAG "MyCustomBoard"
|
||||
|
||||
// 声明字体
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
class MyCustomBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t codec_i2c_bus_;
|
||||
@@ -212,12 +235,7 @@ private:
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y,
|
||||
DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = font_emoji_32_init(),
|
||||
});
|
||||
DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
// MCP Tools 初始化
|
||||
@@ -269,7 +287,106 @@ public:
|
||||
DECLARE_BOARD(MyCustomBoard);
|
||||
```
|
||||
|
||||
### 4. 创建README.md
|
||||
### 4. 添加构建系统配置
|
||||
|
||||
#### 在 Kconfig.projbuild 中添加开发板选项
|
||||
|
||||
打开 `main/Kconfig.projbuild` 文件,在 `choice BOARD_TYPE` 部分添加新的开发板配置项:
|
||||
|
||||
```kconfig
|
||||
choice BOARD_TYPE
|
||||
prompt "Board Type"
|
||||
default BOARD_TYPE_BREAD_COMPACT_WIFI
|
||||
help
|
||||
Board type. 开发板类型
|
||||
|
||||
# ... 其他开发板选项 ...
|
||||
|
||||
config BOARD_TYPE_MY_CUSTOM_BOARD
|
||||
bool "My Custom Board (我的自定义开发板)"
|
||||
depends on IDF_TARGET_ESP32S3 # 根据你的目标芯片修改
|
||||
endchoice
|
||||
```
|
||||
|
||||
**注意事项:**
|
||||
- `BOARD_TYPE_MY_CUSTOM_BOARD` 是配置项名称,需要全大写,使用下划线分隔
|
||||
- `depends on` 指定了目标芯片类型(如 `IDF_TARGET_ESP32S3`、`IDF_TARGET_ESP32C3` 等)
|
||||
- 描述文字可以使用中英文
|
||||
|
||||
#### 在 CMakeLists.txt 中添加开发板配置
|
||||
|
||||
打开 `main/CMakeLists.txt` 文件,在开发板类型判断部分添加新的配置:
|
||||
|
||||
```cmake
|
||||
# 在 elseif 链中添加你的开发板配置
|
||||
elseif(CONFIG_BOARD_TYPE_MY_CUSTOM_BOARD)
|
||||
set(BOARD_TYPE "my-custom-board") # 与目录名一致
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) # 根据屏幕大小选择合适的字体
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64) # 可选,如果需要表情显示
|
||||
endif()
|
||||
```
|
||||
|
||||
**字体和表情配置说明:**
|
||||
|
||||
根据屏幕分辨率选择合适的字体大小:
|
||||
- 小屏幕(128x64 OLED):`font_puhui_basic_14_1` / `font_awesome_14_1`
|
||||
- 中小屏幕(240x240):`font_puhui_basic_16_4` / `font_awesome_16_4`
|
||||
- 中等屏幕(240x320):`font_puhui_basic_20_4` / `font_awesome_20_4`
|
||||
- 大屏幕(480x320+):`font_puhui_basic_30_4` / `font_awesome_30_4`
|
||||
|
||||
表情集合选项:
|
||||
- `twemoji_32` - 32x32 像素表情(小屏幕)
|
||||
- `twemoji_64` - 64x64 像素表情(大屏幕)
|
||||
|
||||
### 5. 配置和编译
|
||||
|
||||
#### 方法一:使用 idf.py 手动配置
|
||||
|
||||
1. **设置目标芯片**(首次配置或更换芯片时):
|
||||
```bash
|
||||
# 对于 ESP32-S3
|
||||
idf.py set-target esp32s3
|
||||
|
||||
# 对于 ESP32-C3
|
||||
idf.py set-target esp32c3
|
||||
|
||||
# 对于 ESP32
|
||||
idf.py set-target esp32
|
||||
```
|
||||
|
||||
2. **清理旧配置**:
|
||||
```bash
|
||||
idf.py fullclean
|
||||
```
|
||||
|
||||
3. **进入配置菜单**:
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
在菜单中导航到:`Xiaozhi Assistant` -> `Board Type`,选择你的自定义开发板。
|
||||
|
||||
4. **编译和烧录**:
|
||||
```bash
|
||||
idf.py build
|
||||
idf.py flash monitor
|
||||
```
|
||||
|
||||
#### 方法二:使用 release.py 脚本(推荐)
|
||||
|
||||
如果你的开发板目录下有 `config.json` 文件,可以使用此脚本自动完成配置和编译:
|
||||
|
||||
```bash
|
||||
python scripts/release.py my-custom-board
|
||||
```
|
||||
|
||||
此脚本会自动:
|
||||
- 读取 `config.json` 中的 `target` 配置并设置目标芯片
|
||||
- 应用 `sdkconfig_append` 中的编译选项
|
||||
- 完成编译并打包固件
|
||||
|
||||
### 6. 创建README.md
|
||||
|
||||
在README.md中说明开发板的特性、硬件要求、编译和烧录步骤:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Define source files
|
||||
set(SOURCES "audio/audio_codec.cc"
|
||||
"audio/audio_service.cc"
|
||||
"audio/codecs/no_audio_codec.cc"
|
||||
@@ -14,6 +15,15 @@ set(SOURCES "audio/audio_codec.cc"
|
||||
"display/display.cc"
|
||||
"display/lcd_display.cc"
|
||||
"display/oled_display.cc"
|
||||
"display/lvgl_display/lvgl_display.cc"
|
||||
"display/emote_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"
|
||||
"display/lvgl_display/jpg/image_to_jpeg.cpp"
|
||||
"protocols/protocol.cc"
|
||||
"protocols/mqtt_protocol.cc"
|
||||
"protocols/websocket_protocol.cc"
|
||||
@@ -23,218 +33,521 @@ 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" "display/lvgl_display/jpg" "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 配置添加对应的板级文件
|
||||
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)
|
||||
foreach(COMPONENT ${build_components})
|
||||
if(COMPONENT MATCHES "${PATTERN}")
|
||||
set(${COMPONENT_VAR} ${COMPONENT} PARENT_SCOPE)
|
||||
idf_component_get_property(COMPONENT_PATH ${COMPONENT} COMPONENT_DIR)
|
||||
set(${PATH_VAR} "${COMPONENT_PATH}" PARENT_SCOPE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Set default BUILTIN_TEXT_FONT and BUILTIN_ICON_FONT
|
||||
set(BUILTIN_TEXT_FONT font_puhui_14_1)
|
||||
set(BUILTIN_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(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ML307)
|
||||
set(BOARD_TYPE "bread-compact-ml307")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_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(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_DF_K10)
|
||||
set(BOARD_TYPE "df-k10")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_DF_S3_AI_CAM)
|
||||
set(BOARD_TYPE "df-s3-ai-cam")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_BOX_3)
|
||||
set(BOARD_TYPE "esp-box-3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_BOX)
|
||||
set(BOARD_TYPE "esp-box")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_BOX_LITE)
|
||||
set(BOARD_TYPE "esp-box-lite")
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_1)
|
||||
set(BOARD_TYPE "kevin-box-1")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_2)
|
||||
set(BOARD_TYPE "kevin-box-2")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_C3)
|
||||
set(BOARD_TYPE "kevin-c3")
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V3_DEV)
|
||||
set(BOARD_TYPE "kevin-sp-v3-dev")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V4_DEV)
|
||||
set(BOARD_TYPE "kevin-sp-v4-dev")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_YUYING_313LCD)
|
||||
set(BOARD_TYPE "kevin-yuying-313lcd")
|
||||
elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV_S3)
|
||||
set(BOARD_TYPE "lichuang-dev")
|
||||
elseif(CONFIG_BOARD_TYPE_LICHUANG_C3_DEV)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV_C3)
|
||||
set(BOARD_TYPE "lichuang-c3-dev")
|
||||
elseif(CONFIG_BOARD_TYPE_MAGICLICK_2P4)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_MAGICLICK_S3_2P4)
|
||||
set(BOARD_TYPE "magiclick-2p4")
|
||||
elseif(CONFIG_BOARD_TYPE_MAGICLICK_2P5)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_MAGICLICK_S3_2P5)
|
||||
set(BOARD_TYPE "magiclick-2p5")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3)
|
||||
set(BOARD_TYPE "magiclick-c3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3_V2)
|
||||
set(BOARD_TYPE "magiclick-c3-v2")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_S3)
|
||||
set(BOARD_TYPE "m5stack-core-s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_TAB5)
|
||||
set(BOARD_TYPE "m5stack-tab5")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMS3_ECHO_BASE)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_ATOM_S3_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMS3R_ECHO_BASE)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_ATOM_S3R_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3r-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_ATOM_S3R_CAM_M12_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3r-cam-m12-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMMATRIX_ECHO_BASE)
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_ATOM_ECHOS3R)
|
||||
set(BOARD_TYPE "atom-echos3r")
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_ATOM_MATRIX_ECHO_BASE)
|
||||
set(BOARD_TYPE "atommatrix-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3_V3)
|
||||
set(BOARD_TYPE "xmini-c3-v3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3_4G)
|
||||
set(BOARD_TYPE "xmini-c3-4g")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3)
|
||||
set(BOARD_TYPE "xmini-c3")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_KORVO2_V3)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_KORVO2_V3)
|
||||
set(BOARD_TYPE "esp32s3-korvo2-v3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_SPARKBOT)
|
||||
set(BOARD_TYPE "esp-sparkbot")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_SPOT_S3)
|
||||
set(BOARD_TYPE "esp-spot-s3")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_HI)
|
||||
set(BOARD_TYPE "esp-hi")
|
||||
# Set ESP_HI emoji directory for DEFAULT_ASSETS_EXTRA_FILES
|
||||
set(DEFAULT_ASSETS_EXTRA_FILES "${CMAKE_BINARY_DIR}/emoji")
|
||||
elseif(CONFIG_BOARD_TYPE_ECHOEAR)
|
||||
set(BOARD_TYPE "echoear")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD)
|
||||
set(BOARD_TYPE "waveshare-s3-audio-board")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8)
|
||||
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-amoled-2.06")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-lcd-4b")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85C)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-lcd-1.83")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C)
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85c")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85)
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_46)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46)
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-1.46")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5)
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-3.5")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5B)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.5b")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32C6_LCD_1_69)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.49")
|
||||
set(LVGL_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(LVGL_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_LCD_1_69)
|
||||
set(BOARD_TYPE "waveshare-c6-lcd-1.69")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43)
|
||||
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.43")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32P4_NANO)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_NANO)
|
||||
set(BOARD_TYPE "waveshare-p4-nano")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B)
|
||||
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-4b")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B)
|
||||
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-7b")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC)
|
||||
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-xc")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_P4_FUNCTION_EV_BOARD)
|
||||
set(BOARD_TYPE "esp-p4-function-ev-board")
|
||||
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_LCD)
|
||||
set(BOARD_TYPE "bread-compact-wifi-lcd")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_TUDOUZI)
|
||||
set(BOARD_TYPE "tudouzi")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CIRCLE_S3)
|
||||
set(BOARD_TYPE "lilygo-t-circle-s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1)
|
||||
set(BOARD_TYPE "lilygo-t-cameraplus-s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2)
|
||||
set(BOARD_TYPE "lilygo-t-cameraplus-s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA)
|
||||
set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY)
|
||||
set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_P4)
|
||||
set(BOARD_TYPE "lilygo-t-display-p4")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_MOVECALL_MOJI_ESP32S3)
|
||||
set(BOARD_TYPE "movecall-moji-esp32s3")
|
||||
elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3)
|
||||
set(BOARD_TYPE "movecall-cuican-esp32s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3)
|
||||
set(BOARD_TYPE "atk-dnesp32s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX0)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box0")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box2-wifi")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_4G)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box2-4g")
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box2-4g")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_WIFI)
|
||||
set(BOARD_TYPE "atk-dnesp32s3m-wifi")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_4G)
|
||||
set(BOARD_TYPE "atk-dnesp32s3m-4g")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_DU_CHATX)
|
||||
set(BOARD_TYPE "du-chatx")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Taiji_Pi)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_TAIJI_PI_S3)
|
||||
set(BOARD_TYPE "taiji-pi-s3")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_85TFT_WIFI)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_0_85TFT_WIFI)
|
||||
set(BOARD_TYPE "xingzhi-cube-0.85tft-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_85TFT_ML307)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_0_85TFT_ML307)
|
||||
set(BOARD_TYPE "xingzhi-cube-0.85tft-ml307")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_96OLED_WIFI)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_0_96OLED_WIFI)
|
||||
set(BOARD_TYPE "xingzhi-cube-0.96oled-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_0_96OLED_ML307)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_0_96OLED_ML307)
|
||||
set(BOARD_TYPE "xingzhi-cube-0.96oled-ml307")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_1_54TFT_WIFI)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_1_54TFT_WIFI)
|
||||
set(BOARD_TYPE "xingzhi-cube-1.54tft-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_1_54TFT_ML307)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_1_54TFT_ML307)
|
||||
set(BOARD_TYPE "xingzhi-cube-1.54tft-ml307")
|
||||
elseif(CONFIG_BOARD_TYPE_SENSECAP_WATCHER)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER)
|
||||
set(BOARD_TYPE "sensecap-watcher")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_DOIT_S3_AIBOX)
|
||||
set(BOARD_TYPE "doit-s3-aibox")
|
||||
elseif(CONFIG_BOARD_TYPE_MIXGO_NOVA)
|
||||
set(BOARD_TYPE "mixgo-nova")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_GENJUTECH_S3_1_54TFT)
|
||||
set(BOARD_TYPE "genjutech-s3-1.54tft")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32_CGC)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_CGC)
|
||||
set(BOARD_TYPE "esp32-cgc")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32_CGC_144)
|
||||
set(BOARD_TYPE "esp32-cgc-144")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_CGC_144)
|
||||
set(BOARD_TYPE "esp32-cgc-144")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board)
|
||||
set(BOARD_TYPE "esp-s3-lcd-ev-board")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
|
||||
set(BOARD_TYPE "esp-s3-lcd-ev-board-2")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI)
|
||||
set(BOARD_TYPE "zhengchen-1.54tft-wifi")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_MINSI_K08_DUAL)
|
||||
set(BOARD_TYPE "minsi-k08-dual")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307)
|
||||
set(BOARD_TYPE "zhengchen-1.54tft-ml307")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32_S3_1_54_MUMA)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_SPOTPEAR_ESP32_S3_1_54_MUMA)
|
||||
set(BOARD_TYPE "sp-esp32-s3-1.54-muma")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32_S3_1_28_BOX)
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_SPOTPEAR_ESP32_S3_1_28_BOX)
|
||||
set(BOARD_TYPE "sp-esp32-s3-1.28-box")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_OTTO_ROBOT)
|
||||
set(BOARD_TYPE "otto-robot")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
elseif(CONFIG_BOARD_TYPE_ELECTRON_BOT)
|
||||
set(BOARD_TYPE "electron-bot")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_20_4)
|
||||
set(BUILTIN_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(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_16_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_JIUCHUAN)
|
||||
set(BOARD_TYPE "jiuchuan-s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LABPLUS_MPYTHON_V3)
|
||||
set(BOARD_TYPE "labplus-mpython-v3")
|
||||
set(BOARD_TYPE "labplus-mpython-v3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_LABPLUS_LEDONG_V2)
|
||||
set(BOARD_TYPE "labplus-ledong-v2")
|
||||
set(BOARD_TYPE "labplus-ledong-v2")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_SURFER_C3_1_14TFT)
|
||||
set(BOARD_TYPE "surfer-c3-1.14tft")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
|
||||
elseif(CONFIG_BOARD_TYPE_YUNLIAO_S3)
|
||||
set(BOARD_TYPE "yunliao-s3")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
elseif(CONFIG_BOARD_TYPE_WIRELESS_TAG_WTP4C5MP07S)
|
||||
set(BOARD_TYPE "wireless-tag-wtp4c5mp07s")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_30_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_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()
|
||||
list(APPEND SOURCES "audio/processors/no_audio_processor.cc")
|
||||
endif()
|
||||
if(CONFIG_USE_AFE_WAKE_WORD)
|
||||
if(CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4)
|
||||
list(APPEND SOURCES "audio/wake_words/afe_wake_word.cc")
|
||||
elseif(CONFIG_USE_ESP_WAKE_WORD)
|
||||
list(APPEND SOURCES "audio/wake_words/esp_wake_word.cc")
|
||||
elseif(CONFIG_USE_CUSTOM_WAKE_WORD)
|
||||
list(APPEND SOURCES "audio/wake_words/custom_wake_word.cc")
|
||||
else()
|
||||
list(APPEND SOURCES "audio/wake_words/esp_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,19 +556,114 @@ 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")
|
||||
elseif(CONFIG_LANGUAGE_BG_BG)
|
||||
set(LANG_DIR "bg-BG")
|
||||
elseif(CONFIG_LANGUAGE_CA_ES)
|
||||
set(LANG_DIR "ca-ES")
|
||||
elseif(CONFIG_LANGUAGE_DA_DK)
|
||||
set(LANG_DIR "da-DK")
|
||||
elseif(CONFIG_LANGUAGE_EL_GR)
|
||||
set(LANG_DIR "el-GR")
|
||||
elseif(CONFIG_LANGUAGE_FA_IR)
|
||||
set(LANG_DIR "fa-IR")
|
||||
elseif(CONFIG_LANGUAGE_FIL_PH)
|
||||
set(LANG_DIR "fil-PH")
|
||||
elseif(CONFIG_LANGUAGE_HE_IL)
|
||||
set(LANG_DIR "he-IL")
|
||||
elseif(CONFIG_LANGUAGE_HR_HR)
|
||||
set(LANG_DIR "hr-HR")
|
||||
elseif(CONFIG_LANGUAGE_HU_HU)
|
||||
set(LANG_DIR "hu-HU")
|
||||
elseif(CONFIG_LANGUAGE_MS_MY)
|
||||
set(LANG_DIR "ms-MY")
|
||||
elseif(CONFIG_LANGUAGE_NB_NO)
|
||||
set(LANG_DIR "nb-NO")
|
||||
elseif(CONFIG_LANGUAGE_NL_NL)
|
||||
set(LANG_DIR "nl-NL")
|
||||
elseif(CONFIG_LANGUAGE_SK_SK)
|
||||
set(LANG_DIR "sk-SK")
|
||||
elseif(CONFIG_LANGUAGE_SL_SI)
|
||||
set(LANG_DIR "sl-SI")
|
||||
elseif(CONFIG_LANGUAGE_SV_SE)
|
||||
set(LANG_DIR "sv-SE")
|
||||
elseif(CONFIG_LANGUAGE_SR_RS)
|
||||
set(LANG_DIR "sr-RS")
|
||||
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)
|
||||
|
||||
# 如果目标芯片是 ESP32,则排除特定文件
|
||||
# Collect current language audio files
|
||||
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/*.ogg)
|
||||
|
||||
# If not en-US, collect en-US audio files as fallback for missing files
|
||||
if(NOT LANG_DIR STREQUAL "en-US")
|
||||
file(GLOB EN_US_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/en-US/*.ogg)
|
||||
|
||||
# Extract filenames (without path) from current language
|
||||
set(EXISTING_NAMES "")
|
||||
foreach(SOUND_FILE ${LANG_SOUNDS})
|
||||
get_filename_component(FILENAME ${SOUND_FILE} NAME)
|
||||
list(APPEND EXISTING_NAMES ${FILENAME})
|
||||
endforeach()
|
||||
|
||||
# Only add en-US audio files that are missing in current language
|
||||
foreach(EN_SOUND ${EN_US_SOUNDS})
|
||||
get_filename_component(FILENAME ${EN_SOUND} NAME)
|
||||
if(NOT ${FILENAME} IN_LIST EXISTING_NAMES)
|
||||
list(APPEND LANG_SOUNDS ${EN_SOUND})
|
||||
message(STATUS "Using en-US fallback for missing audio: ${FILENAME}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.ogg)
|
||||
|
||||
# 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"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/boards/common/esp32_camera.cc"
|
||||
"display/lvgl_display/jpg/image_to_jpeg.cpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -265,20 +673,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 BUILTIN_TEXT_FONT=${BUILTIN_TEXT_FONT} BUILTIN_ICON_FONT=${BUILTIN_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,15 +695,27 @@ add_custom_command(
|
||||
COMMENT "Generating ${LANG_DIR} language config"
|
||||
)
|
||||
|
||||
# 强制建立生成依赖
|
||||
# Force build generation dependencies
|
||||
add_custom_target(lang_header ALL
|
||||
DEPENDS ${LANG_HEADER}
|
||||
)
|
||||
|
||||
# Find ESP-SR component dynamically
|
||||
find_component_by_pattern("espressif__esp-sr" ESP_SR_COMPONENT ESP_SR_COMPONENT_PATH)
|
||||
if(ESP_SR_COMPONENT_PATH)
|
||||
set(ESP_SR_MODEL_PATH "${ESP_SR_COMPONENT_PATH}/model")
|
||||
endif()
|
||||
|
||||
# Find xiaozhi-fonts component dynamically
|
||||
find_component_by_pattern("xiaozhi-fonts" XIAOZHI_FONTS_COMPONENT XIAOZHI_FONTS_COMPONENT_PATH)
|
||||
if(XIAOZHI_FONTS_COMPONENT_PATH)
|
||||
set(XIAOZHI_FONTS_PATH "${XIAOZHI_FONTS_COMPONENT_PATH}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_BOARD_TYPE_ESP_HI)
|
||||
set(URL "https://github.com/espressif2022/image_player/raw/main/test_apps/test_8bit")
|
||||
set(SPIFFS_DIR "${CMAKE_BINARY_DIR}/emoji")
|
||||
file(MAKE_DIRECTORY ${SPIFFS_DIR})
|
||||
set(EMOJI_DIR "${CMAKE_BINARY_DIR}/emoji")
|
||||
file(MAKE_DIRECTORY ${EMOJI_DIR})
|
||||
|
||||
# List all files to download
|
||||
set(FILES_TO_DOWNLOAD "")
|
||||
@@ -310,9 +731,9 @@ list(APPEND FILES_TO_DOWNLOAD "panic_return.aaf" "wake.aaf")
|
||||
|
||||
foreach(FILENAME IN LISTS FILES_TO_DOWNLOAD)
|
||||
set(REMOTE_FILE "${URL}/${FILENAME}")
|
||||
set(LOCAL_FILE "${SPIFFS_DIR}/${FILENAME}")
|
||||
set(LOCAL_FILE "${EMOJI_DIR}/${FILENAME}")
|
||||
|
||||
# 检查本地文件是否存在
|
||||
# Check if local file exists
|
||||
if(EXISTS ${LOCAL_FILE})
|
||||
message(STATUS "File ${FILENAME} already exists, skipping download")
|
||||
else()
|
||||
@@ -326,10 +747,134 @@ foreach(FILENAME IN LISTS FILES_TO_DOWNLOAD)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
spiffs_create_partition_assets(
|
||||
assets_A
|
||||
${SPIFFS_DIR}
|
||||
FLASH_IN_PROJECT
|
||||
MMAP_FILE_SUPPORT_FORMAT ".aaf"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# Function to build default assets based on configuration
|
||||
function(build_default_assets_bin)
|
||||
# Set output path for generated assets.bin
|
||||
set(GENERATED_ASSETS_BIN "${CMAKE_BINARY_DIR}/generated_assets.bin")
|
||||
|
||||
# Prepare arguments for build script
|
||||
set(BUILD_ARGS
|
||||
"--sdkconfig" "${SDKCONFIG}"
|
||||
"--output" "${GENERATED_ASSETS_BIN}"
|
||||
)
|
||||
|
||||
# Add builtin text font if defined
|
||||
if(BUILTIN_TEXT_FONT)
|
||||
list(APPEND BUILD_ARGS "--builtin_text_font" "${BUILTIN_TEXT_FONT}")
|
||||
endif()
|
||||
|
||||
# Add default emoji collection if defined
|
||||
if(DEFAULT_EMOJI_COLLECTION)
|
||||
list(APPEND BUILD_ARGS "--emoji_collection" "${DEFAULT_EMOJI_COLLECTION}")
|
||||
endif()
|
||||
|
||||
# Add default assets extra files if defined
|
||||
if(DEFAULT_ASSETS_EXTRA_FILES)
|
||||
list(APPEND BUILD_ARGS "--extra_files" "${DEFAULT_ASSETS_EXTRA_FILES}")
|
||||
endif()
|
||||
|
||||
list(APPEND BUILD_ARGS "--esp_sr_model_path" "${ESP_SR_MODEL_PATH}")
|
||||
list(APPEND BUILD_ARGS "--xiaozhi_fonts_path" "${XIAOZHI_FONTS_PATH}")
|
||||
|
||||
# Create custom command to build assets
|
||||
add_custom_command(
|
||||
OUTPUT ${GENERATED_ASSETS_BIN}
|
||||
COMMAND python ${PROJECT_DIR}/scripts/build_default_assets.py ${BUILD_ARGS}
|
||||
DEPENDS
|
||||
${SDKCONFIG}
|
||||
${PROJECT_DIR}/scripts/build_default_assets.py
|
||||
COMMENT "Building default assets.bin based on configuration"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# Create target for generated assets
|
||||
add_custom_target(generated_default_assets ALL
|
||||
DEPENDS ${GENERATED_ASSETS_BIN}
|
||||
)
|
||||
|
||||
# Set the generated file path in parent scope
|
||||
set(GENERATED_ASSETS_LOCAL_FILE ${GENERATED_ASSETS_BIN} PARENT_SCOPE)
|
||||
|
||||
message(STATUS "Default assets build configured: ${GENERATED_ASSETS_BIN}")
|
||||
endfunction()
|
||||
|
||||
|
||||
# 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()
|
||||
|
||||
|
||||
partition_table_get_partition_info(size "--partition-name assets" "size")
|
||||
partition_table_get_partition_info(offset "--partition-name assets" "offset")
|
||||
if ("${size}" AND "${offset}")
|
||||
# Flash assets based on configuration
|
||||
if(CONFIG_FLASH_DEFAULT_ASSETS)
|
||||
# Build default assets based on configuration
|
||||
build_default_assets_bin()
|
||||
esptool_py_flash_to_partition(flash "assets" "${GENERATED_ASSETS_LOCAL_FILE}")
|
||||
message(STATUS "Generated default assets flash configured: ${GENERATED_ASSETS_LOCAL_FILE} -> assets partition")
|
||||
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()
|
||||
else()
|
||||
message(STATUS "Assets partition not found, using v1 partition table")
|
||||
endif()
|
||||
|
||||
@@ -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_DEFAULT_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,74 @@ 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"
|
||||
config LANGUAGE_BG_BG
|
||||
bool "Bulgarian"
|
||||
config LANGUAGE_CA_ES
|
||||
bool "Catalan"
|
||||
config LANGUAGE_DA_DK
|
||||
bool "Danish"
|
||||
config LANGUAGE_EL_GR
|
||||
bool "Greek"
|
||||
config LANGUAGE_FA_IR
|
||||
bool "Persian"
|
||||
config LANGUAGE_FIL_PH
|
||||
bool "Filipino"
|
||||
config LANGUAGE_HE_IL
|
||||
bool "Hebrew"
|
||||
config LANGUAGE_HR_HR
|
||||
bool "Croatian"
|
||||
config LANGUAGE_HU_HU
|
||||
bool "Hungarian"
|
||||
config LANGUAGE_MS_MY
|
||||
bool "Malay"
|
||||
config LANGUAGE_NB_NO
|
||||
bool "Norwegian"
|
||||
config LANGUAGE_NL_NL
|
||||
bool "Dutch"
|
||||
config LANGUAGE_SK_SK
|
||||
bool "Slovak"
|
||||
config LANGUAGE_SL_SI
|
||||
bool "Slovenian"
|
||||
config LANGUAGE_SV_SE
|
||||
bool "Swedish"
|
||||
config LANGUAGE_SR_RS
|
||||
bool "Serbian"
|
||||
endchoice
|
||||
|
||||
choice BOARD_TYPE
|
||||
@@ -29,58 +118,58 @@ choice BOARD_TYPE
|
||||
help
|
||||
Board type. 开发板类型
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI
|
||||
bool "面包板新版接线(WiFi)"
|
||||
bool "Bread Compact WiFi (面包板)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI_LCD
|
||||
bool "面包板新版接线(WiFi)+ LCD"
|
||||
bool "Bread Compact WiFi + LCD (面包板)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
bool "面包板新版接线(WiFi)+ LCD + Camera"
|
||||
bool "Bread Compact WiFi + LCD + Camera (面包板)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_ML307
|
||||
bool "面包板新版接线(ML307 AT)"
|
||||
bool "Bread Compact ML307/EC801E (面包板 4G)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_ESP32
|
||||
bool "面包板(WiFi) ESP32 DevKit"
|
||||
bool "Bread Compact ESP32 DevKit (面包板)"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_BREAD_COMPACT_ESP32_LCD
|
||||
bool "面包板(WiFi+ LCD) ESP32 DevKit"
|
||||
bool "Bread Compact ESP32 DevKit + LCD (面包板)"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_XMINI_C3_V3
|
||||
bool "虾哥 Mini C3 V3"
|
||||
bool "Xmini C3 V3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_XMINI_C3_4G
|
||||
bool "虾哥 Mini C3 4G"
|
||||
bool "Xmini C3 4G"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_XMINI_C3
|
||||
bool "虾哥 Mini C3"
|
||||
bool "Xmini C3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_ESP32S3_KORVO2_V3
|
||||
bool "ESP32S3_KORVO2_V3开发板"
|
||||
config BOARD_TYPE_ESP_KORVO2_V3
|
||||
bool "Espressif Korvo2 V3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_SPARKBOT
|
||||
bool "ESP-SparkBot开发板"
|
||||
bool "Espressif SparkBot"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_SPOT_S3
|
||||
bool "ESP-Spot-S3"
|
||||
bool "Espressif Spot-S3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_HI
|
||||
bool "ESP-HI"
|
||||
bool "Espressif ESP-HI"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_ECHOEAR
|
||||
bool "EchoEar"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX_3
|
||||
bool "ESP BOX 3"
|
||||
bool "Espressif ESP-BOX-3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX
|
||||
bool "ESP BOX"
|
||||
bool "Espressif ESP-BOX"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX_LITE
|
||||
bool "ESP BOX Lite"
|
||||
bool "Espressif ESP-BOX-Lite"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_BOX_1
|
||||
bool "Kevin Box 1"
|
||||
config BOARD_TYPE_ESP_P4_FUNCTION_EV_BOARD
|
||||
bool "Espressif ESP-P4-Function-EV-Board"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_ECHOEAR
|
||||
bool "EchoEar"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_BOX_2
|
||||
bool "Kevin Box 2"
|
||||
@@ -89,25 +178,25 @@ choice BOARD_TYPE
|
||||
bool "Kevin C3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_KEVIN_SP_V3_DEV
|
||||
bool "Kevin SP V3开发板"
|
||||
bool "Kevin SP V3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_SP_V4_DEV
|
||||
bool "Kevin SP V4开发板"
|
||||
bool "Kevin SP V4"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32_CGC
|
||||
bool "ESP32 CGC"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_ESP32_CGC_144
|
||||
bool "ESP32 CGC 144"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_KEVIN_YUYING_313LCD
|
||||
bool "鱼鹰科技3.13LCD开发板"
|
||||
bool "鱼鹰科技 3.13LCD"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LICHUANG_DEV
|
||||
bool "立创·实战派ESP32-S3开发板"
|
||||
config BOARD_TYPE_CGC
|
||||
bool "CGC"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_CGC_144
|
||||
bool "CGC 144"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_LICHUANG_DEV_S3
|
||||
bool "立创·实战派 ESP32-S3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LICHUANG_C3_DEV
|
||||
bool "立创·实战派ESP32-C3开发板"
|
||||
config BOARD_TYPE_LICHUANG_DEV_C3
|
||||
bool "立创·实战派 ESP32-C3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_DF_K10
|
||||
bool "DFRobot 行空板 k10"
|
||||
@@ -115,10 +204,10 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_DF_S3_AI_CAM
|
||||
bool "DFRobot ESP32-S3 AI智能摄像头模块"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MAGICLICK_2P4
|
||||
config BOARD_TYPE_MAGICLICK_S3_2P4
|
||||
bool "神奇按钮 Magiclick_2.4"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MAGICLICK_2P5
|
||||
config BOARD_TYPE_MAGICLICK_S3_2P5
|
||||
bool "神奇按钮 Magiclick_2.5"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MAGICLICK_C3
|
||||
@@ -133,52 +222,73 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_M5STACK_CORE_TAB5
|
||||
bool "M5Stack Tab5"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_ATOMS3_ECHO_BASE
|
||||
bool "AtomS3 + Echo Base"
|
||||
config BOARD_TYPE_M5STACK_ATOM_S3_ECHO_BASE
|
||||
bool "M5Stack AtomS3 + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOMS3R_ECHO_BASE
|
||||
bool "AtomS3R + Echo Base"
|
||||
config BOARD_TYPE_M5STACK_ATOM_S3R_ECHO_BASE
|
||||
bool "M5Stack AtomS3R + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE
|
||||
bool "AtomS3R CAM/M12 + Echo Base"
|
||||
config BOARD_TYPE_M5STACK_ATOM_S3R_CAM_M12_ECHO_BASE
|
||||
bool "M5Stack AtomS3R CAM/M12 + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
|
||||
bool "AtomMatrix + Echo Base"
|
||||
config BOARD_TYPE_M5STACK_ATOM_ECHOS3R
|
||||
bool "M5Stack AtomEchoS3R"
|
||||
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_ESP32S3_Touch_AMOLED_1_8
|
||||
config BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
|
||||
bool "Waveshare ESP32-S3-Audio-Board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_85C
|
||||
config BOARD_TYPE_WAVESHARE_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
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-4B"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.85C"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_85
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.85"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_46
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32C6_LCD_1_69
|
||||
config BOARD_TYPE_WAVESHARE_C6_LCD_1_69
|
||||
bool "Waveshare ESP32-C6-LCD-1.69"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43
|
||||
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43
|
||||
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5
|
||||
config BOARD_TYPE_WAVESHARE_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
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.5"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5B
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.5B"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32P4_NANO
|
||||
config BOARD_TYPE_WAVESHARE_P4_NANO
|
||||
bool "Waveshare ESP32-P4-NANO"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B
|
||||
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4B"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC
|
||||
config BOARD_TYPE_WAVESHARE_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"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_TUDOUZI
|
||||
@@ -199,6 +309,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY
|
||||
bool "LILYGO T-Display-S3-Pro-MVSRLora_No_Battery"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LILYGO_T_DISPLAY_P4
|
||||
bool "LILYGO T-Display-P4"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_MOVECALL_MOJI_ESP32S3
|
||||
bool "Movecall Moji 小智AI衍生版"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -218,7 +331,7 @@ choice BOARD_TYPE
|
||||
bool "正点原子DNESP32S3-BOX2-WIFI"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3_BOX2_4G
|
||||
bool "正点原子DNESP32S3-BOX2-4G"
|
||||
bool "正点原子DNESP32S3-BOX2-4G"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3M_WIFI
|
||||
bool "正点原子DNESP32S3M-WIFI"
|
||||
@@ -229,29 +342,29 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_DU_CHATX
|
||||
bool "嘟嘟开发板CHATX(wifi)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Taiji_Pi
|
||||
config BOARD_TYPE_TAIJI_PI_S3
|
||||
bool "太极小派esp32s3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_85TFT_WIFI
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_85TFT_WIFI
|
||||
bool "无名科技星智0.85(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_85TFT_ML307
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_85TFT_ML307
|
||||
bool "无名科技星智0.85(ML307)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_96OLED_WIFI
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_96OLED_WIFI
|
||||
bool "无名科技星智0.96(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_96OLED_ML307
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_96OLED_ML307
|
||||
bool "无名科技星智0.96(ML307)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_Cube_1_54TFT_WIFI
|
||||
config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_WIFI
|
||||
bool "无名科技星智1.54(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_Cube_1_54TFT_ML307
|
||||
config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_ML307
|
||||
bool "无名科技星智1.54(ML307)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SENSECAP_WATCHER
|
||||
bool "SenseCAP Watcher"
|
||||
config BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER
|
||||
bool "Seeed Studio SenseCAP Watcher"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_DOIT_S3_AIBOX
|
||||
bool "四博智联AI陪伴盒子"
|
||||
@@ -265,6 +378,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
|
||||
@@ -274,10 +390,10 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_MINSI_K08_DUAL
|
||||
bool "敏思科技K08(DUAL)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32_S3_1_54_MUMA
|
||||
config BOARD_TYPE_SPOTPEAR_ESP32_S3_1_54_MUMA
|
||||
bool "Spotpear ESP32-S3-1.54-MUMA"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32_S3_1_28_BOX
|
||||
config BOARD_TYPE_SPOTPEAR_ESP32_S3_1_28_BOX
|
||||
bool "Spotpear ESP32-S3-1.28-BOX"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_OTTO_ROBOT
|
||||
@@ -292,24 +408,48 @@ choice BOARD_TYPE
|
||||
select LV_GIF_CACHE_DECODE_DATA
|
||||
config BOARD_TYPE_JIUCHUAN
|
||||
bool "九川智能"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LABPLUS_MPYTHON_V3
|
||||
bool "labplus mpython_v3 board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LABPLUS_LEDONG_V2
|
||||
bool "labplus ledong_v2 board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SURFER_C3_1_14TFT
|
||||
bool "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
|
||||
config BOARD_TYPE_WIRELESS_TAG_WTP4C5MP07S
|
||||
bool "Wireless-Tag WTP4C5MP07S"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
endchoice
|
||||
|
||||
choice
|
||||
depends on BOARD_TYPE_LILYGO_T_DISPLAY_P4
|
||||
prompt "Select the screen type"
|
||||
default SCREEN_TYPE_HI8561
|
||||
config SCREEN_TYPE_HI8561
|
||||
bool "HI8561"
|
||||
config SCREEN_TYPE_RM69A10
|
||||
bool "RM69A10"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
depends on BOARD_TYPE_LILYGO_T_DISPLAY_P4
|
||||
prompt "Select the color format of the screen"
|
||||
default SCREEN_PIXEL_FORMAT_RGB565
|
||||
config SCREEN_PIXEL_FORMAT_RGB565
|
||||
bool "RGB565"
|
||||
config SCREEN_PIXEL_FORMAT_RGB888
|
||||
bool "RGB888"
|
||||
endchoice
|
||||
|
||||
choice ESP_S3_LCD_EV_Board_Version_TYPE
|
||||
depends on BOARD_TYPE_ESP_S3_LCD_EV_Board
|
||||
prompt "EV_BOARD Type"
|
||||
default ESP_S3_LCD_EV_Board_1p4
|
||||
help
|
||||
开发板硬件版本型号选择
|
||||
config ESP_S3_LCD_EV_Board_1p4
|
||||
bool "乐鑫ESP32_S3_LCD_EV_Board-MB_V1.4"
|
||||
config ESP_S3_LCD_EV_Board_1p5
|
||||
@@ -321,51 +461,51 @@ choice DISPLAY_OLED_TYPE
|
||||
prompt "OLED Type"
|
||||
default OLED_SSD1306_128X32
|
||||
help
|
||||
OLED 屏幕类型选择
|
||||
OLED Monochrome Display Type
|
||||
config OLED_SSD1306_128X32
|
||||
bool "SSD1306, 分辨率128*32"
|
||||
bool "SSD1306 128*32"
|
||||
config OLED_SSD1306_128X64
|
||||
bool "SSD1306, 分辨率128*64"
|
||||
bool "SSD1306 128*64"
|
||||
config OLED_SH1106_128X64
|
||||
bool "SH1106, 分辨率128*64"
|
||||
bool "SH1106 128*64"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_LCD_TYPE
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_ESP32_CGC || BOARD_TYPE_ESP32P4_NANO || BOARD_TYPE_ESP32P4_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_WAVESHARE_P4_NANO || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
prompt "LCD Type"
|
||||
default LCD_ST7789_240X320
|
||||
help
|
||||
屏幕类型选择
|
||||
LCD Display Type
|
||||
config LCD_ST7789_240X320
|
||||
bool "ST7789, 分辨率240*320, IPS"
|
||||
bool "ST7789 240*320, IPS"
|
||||
config LCD_ST7789_240X320_NO_IPS
|
||||
bool "ST7789, 分辨率240*320, 非IPS"
|
||||
bool "ST7789 240*320, Non-IPS"
|
||||
config LCD_ST7789_170X320
|
||||
bool "ST7789, 分辨率170*320"
|
||||
bool "ST7789 170*320"
|
||||
config LCD_ST7789_172X320
|
||||
bool "ST7789, 分辨率172*320"
|
||||
bool "ST7789 172*320"
|
||||
config LCD_ST7789_240X280
|
||||
bool "ST7789, 分辨率240*280"
|
||||
bool "ST7789 240*280"
|
||||
config LCD_ST7789_240X240
|
||||
bool "ST7789, 分辨率240*240"
|
||||
bool "ST7789 240*240"
|
||||
config LCD_ST7789_240X240_7PIN
|
||||
bool "ST7789, 分辨率240*240, 7PIN"
|
||||
bool "ST7789 240*240, 7PIN"
|
||||
config LCD_ST7789_240X135
|
||||
bool "ST7789, 分辨率240*135"
|
||||
bool "ST7789 240*135"
|
||||
config LCD_ST7735_128X160
|
||||
bool "ST7735, 分辨率128*160"
|
||||
bool "ST7735 128*160"
|
||||
config LCD_ST7735_128X128
|
||||
bool "ST7735, 分辨率128*128"
|
||||
bool "ST7735 128*128"
|
||||
config LCD_ST7796_320X480
|
||||
bool "ST7796, 分辨率320*480 IPS"
|
||||
bool "ST7796 320*480 IPS"
|
||||
config LCD_ST7796_320X480_NO_IPS
|
||||
bool "ST7796, 分辨率320*480, 非IPS"
|
||||
bool "ST7796 320*480, Non-IPS"
|
||||
config LCD_ILI9341_240X320
|
||||
bool "ILI9341, 分辨率240*320"
|
||||
bool "ILI9341 240*320"
|
||||
config LCD_ILI9341_240X320_NO_IPS
|
||||
bool "ILI9341, 分辨率240*320, 非IPS"
|
||||
bool "ILI9341 240*320, Non-IPS"
|
||||
config LCD_GC9A01_240X240
|
||||
bool "GC9A01, 分辨率240*240, 圆屏"
|
||||
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
|
||||
@@ -375,119 +515,211 @@ choice DISPLAY_LCD_TYPE
|
||||
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 "自定义屏幕参数"
|
||||
bool "Custom LCD (自定义屏幕参数)"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_KORVO2_V3
|
||||
depends on BOARD_TYPE_ESP32S3_KORVO2_V3
|
||||
depends on BOARD_TYPE_ESP_KORVO2_V3
|
||||
prompt "ESP32S3_KORVO2_V3 LCD Type"
|
||||
default LCD_ST7789
|
||||
default ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
help
|
||||
屏幕类型选择
|
||||
config LCD_ST7789
|
||||
bool "ST7789, 分辨率240*280"
|
||||
config LCD_ILI9341
|
||||
bool "ILI9341, 分辨率240*320"
|
||||
LCD Display Type
|
||||
config ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
bool "ST7789 240*280"
|
||||
config ESP32S3_KORVO2_V3_LCD_ILI9341
|
||||
bool "ILI9341 240*320"
|
||||
endchoice
|
||||
|
||||
config USE_WECHAT_MESSAGE_STYLE
|
||||
bool "Enable WeChat Message Style"
|
||||
default n
|
||||
choice DISPLAY_ESP32S3_AUDIO_BOARD
|
||||
depends on BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
|
||||
prompt "ESP32S3_AUDIO_BOARD LCD Type"
|
||||
default AUDIO_BOARD_LCD_JD9853
|
||||
help
|
||||
使用微信聊天界面风格
|
||||
LCD Display Type
|
||||
config AUDIO_BOARD_LCD_JD9853
|
||||
bool "JD9853 320*172"
|
||||
config AUDIO_BOARD_LCD_ST7789
|
||||
bool "ST7789 240*320"
|
||||
endchoice
|
||||
|
||||
config USE_ESP_WAKE_WORD
|
||||
bool "Enable Wake Word Detection (without AFE)"
|
||||
default n
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || (IDF_TARGET_ESP32 && SPIRAM)
|
||||
choice DISPLAY_STYLE
|
||||
prompt "Select display style"
|
||||
default USE_DEFAULT_MESSAGE_STYLE
|
||||
help
|
||||
支持 ESP32 C3、ESP32 C5 与 ESP32 C6,增加ESP32支持(需要开启PSRAM)
|
||||
Select display style for Xiaozhi device
|
||||
|
||||
config USE_AFE_WAKE_WORD
|
||||
bool "Enable Wake Word Detection (AFE)"
|
||||
default y
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
config USE_DEFAULT_MESSAGE_STYLE
|
||||
bool "Enable default message style"
|
||||
|
||||
config USE_CUSTOM_WAKE_WORD
|
||||
bool "Enable Custom Wake Word Detection"
|
||||
default n
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM && (!USE_AFE_WAKE_WORD)
|
||||
config USE_WECHAT_MESSAGE_STYLE
|
||||
bool "Enable WeChat Message 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
|
||||
endchoice
|
||||
|
||||
choice WAKE_WORD_TYPE
|
||||
prompt "Wake Word Implementation Type"
|
||||
default USE_AFE_WAKE_WORD if (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
default WAKE_WORD_DISABLED
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
|
||||
Choose the type of wake word implementation to use
|
||||
|
||||
config WAKE_WORD_DISABLED
|
||||
bool "Disabled"
|
||||
help
|
||||
Disable wake word detection
|
||||
|
||||
config USE_ESP_WAKE_WORD
|
||||
bool "Wakenet model without AFE"
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || (IDF_TARGET_ESP32 && SPIRAM)
|
||||
help
|
||||
Support ESP32 C3、ESP32 C5 与 ESP32 C6, and (ESP32 with PSRAM)
|
||||
|
||||
config USE_AFE_WAKE_WORD
|
||||
bool "Wakenet model with AFE"
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
Support AEC if available, requires ESP32 S3 and PSRAM
|
||||
|
||||
config USE_CUSTOM_WAKE_WORD
|
||||
bool "Multinet model (Custom Wake Word)"
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
Requires ESP32 S3 and PSRAM
|
||||
|
||||
endchoice
|
||||
|
||||
config CUSTOM_WAKE_WORD
|
||||
string "Custom Wake Word"
|
||||
default "ni hao xiao zhi"
|
||||
default "xiao tu dou"
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
自定义唤醒词,用汉语拼音表示
|
||||
Custom Wake Word, use pinyin for Chinese, separated by spaces
|
||||
|
||||
config CUSTOM_WAKE_WORD_DISPLAY
|
||||
string "Custom Wake Word Display"
|
||||
default "你好小智"
|
||||
default "小土豆"
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
自定义唤醒词对应问候语
|
||||
|
||||
|
||||
Greeting sent to the server after wake word detection
|
||||
|
||||
config CUSTOM_WAKE_WORD_THRESHOLD
|
||||
int "Custom Wake Word Threshold (%)"
|
||||
default 20
|
||||
range 1 99
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
Custom Wake Word Threshold, range 1-99, the smaller the more sensitive, default 20
|
||||
|
||||
config SEND_WAKE_WORD_DATA
|
||||
bool "Send Wake Word Data"
|
||||
default y
|
||||
depends on USE_AFE_WAKE_WORD || USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
Send wake word data to the server as the first message of the conversation and wait for response
|
||||
|
||||
config USE_AUDIO_PROCESSOR
|
||||
bool "Enable Audio Noise Reduction"
|
||||
default y
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
Requires ESP32 S3 and PSRAM
|
||||
|
||||
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_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)
|
||||
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.
|
||||
|
||||
config USE_SERVER_AEC
|
||||
bool "Enable Server-Side AEC (Unstable)"
|
||||
default n
|
||||
depends on USE_AUDIO_PROCESSOR
|
||||
help
|
||||
启用服务器端 AEC,需要服务器支持
|
||||
To work perperly, server-side AEC requires server support
|
||||
|
||||
config USE_AUDIO_DEBUGGER
|
||||
bool "Enable Audio Debugger"
|
||||
default n
|
||||
help
|
||||
启用音频调试功能,通过UDP发送音频数据
|
||||
|
||||
config USE_ACOUSTIC_WIFI_PROVISIONING
|
||||
bool "Enable Acoustic WiFi Provisioning"
|
||||
default n
|
||||
help
|
||||
启用声波配网功能,使用音频信号传输 WiFi 配置数据
|
||||
Enable audio debugger, send audio data through UDP to the host machine
|
||||
|
||||
config AUDIO_DEBUG_UDP_SERVER
|
||||
string "Audio Debug UDP Server Address"
|
||||
default "192.168.2.100:8000"
|
||||
depends on USE_AUDIO_DEBUGGER
|
||||
help
|
||||
UDP服务器地址,格式: IP:PORT,用于接收音频调试数据
|
||||
UDP server address, format: IP:PORT, used to receive audio debugging data
|
||||
|
||||
config USE_ACOUSTIC_WIFI_PROVISIONING
|
||||
bool "Enable Acoustic WiFi Provisioning"
|
||||
default n
|
||||
help
|
||||
Enable acoustic WiFi provisioning, use audio signal to transmit WiFi configuration data
|
||||
|
||||
config RECEIVE_CUSTOM_MESSAGE
|
||||
bool "Enable Custom Message Reception"
|
||||
default n
|
||||
help
|
||||
启用接收自定义消息功能,允许设备接收来自服务器的自定义消息(最好通过 MQTT 协议)
|
||||
Enable custom message reception, allow the device to receive custom messages from the server (preferably through the MQTT protocol)
|
||||
|
||||
choice I2S_TYPE_TAIJIPI_S3
|
||||
depends on BOARD_TYPE_ESP32S3_Taiji_Pi
|
||||
prompt "taiji-pi-S3 I2S Type"
|
||||
default TAIJIPAI_I2S_TYPE_STD
|
||||
menu "Camera Configuration"
|
||||
depends on !IDF_TARGET_ESP32
|
||||
|
||||
config XIAOZHI_ENABLE_HARDWARE_JPEG_ENCODER
|
||||
bool "Enable Hardware JPEG Encoder"
|
||||
default y
|
||||
depends on SOC_JPEG_ENCODE_SUPPORTED
|
||||
help
|
||||
Use hardware JPEG encoder on ESP32-P4 to encode image to JPEG.
|
||||
See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details.
|
||||
|
||||
config XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
bool "Enable Camera Debug Mode"
|
||||
default n
|
||||
help
|
||||
Enable camera debug mode, print camera debug information to the console.
|
||||
Only works on boards that support camera.
|
||||
|
||||
config XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
|
||||
bool "Enable software camera buffer endianness swapping (USE WITH CAUTION)"
|
||||
default n
|
||||
depends on !CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER
|
||||
help
|
||||
This option treats the camera buffer as a uint16_t[] array and performs byte-swapping (endianness conversion) on each element.
|
||||
|
||||
Should only be modified by development board integration engineers.
|
||||
|
||||
**Incorrect usage may result in incorrect image colors!**
|
||||
|
||||
ATTENTION: If the option CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER is available for your sensor, please use that instead.
|
||||
endmenu
|
||||
|
||||
menu "TAIJIPAI_S3_CONFIG"
|
||||
depends on BOARD_TYPE_TAIJI_PI_S3
|
||||
choice I2S_TYPE_TAIJIPI_S3
|
||||
prompt "taiji-pi-S3 I2S Type"
|
||||
default TAIJIPAI_I2S_TYPE_STD
|
||||
help
|
||||
I2S 类型选择
|
||||
config TAIJIPAI_I2S_TYPE_STD
|
||||
bool "I2S Type STD"
|
||||
config TAIJIPAI_I2S_TYPE_PDM
|
||||
bool "I2S Type PDM"
|
||||
endchoice
|
||||
|
||||
config I2S_USE_2SLOT
|
||||
bool "Enable I2S 2 Slot"
|
||||
default y
|
||||
help
|
||||
I2S 类型选择
|
||||
config TAIJIPAI_I2S_TYPE_STD
|
||||
bool "I2S Type STD"
|
||||
config TAIJIPAI_I2S_TYPE_PDM
|
||||
bool "I2S Type PDM"
|
||||
endchoice
|
||||
启动双声道
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -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,57 @@ Application::~Application() {
|
||||
vEventGroupDelete(event_group_);
|
||||
}
|
||||
|
||||
void Application::CheckAssetsVersion() {
|
||||
auto& board = Board::GetInstance();
|
||||
auto display = board.GetDisplay();
|
||||
auto& assets = Assets::GetInstance();
|
||||
|
||||
if (!assets.partition_valid()) {
|
||||
ESP_LOGW(TAG, "Assets partition is disabled 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");
|
||||
|
||||
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 +138,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 +156,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 +201,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 +226,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);
|
||||
@@ -331,6 +352,9 @@ void Application::Start() {
|
||||
/* Setup the display */
|
||||
auto display = board.GetDisplay();
|
||||
|
||||
// Print board name/version info
|
||||
display->SetChatMessage("system", SystemInfo::GetUserAgent().c_str());
|
||||
|
||||
/* Setup the audio service */
|
||||
auto codec = board.GetAudioCodec();
|
||||
audio_service_.Initialize(codec);
|
||||
@@ -348,6 +372,12 @@ void Application::Start() {
|
||||
};
|
||||
audio_service_.SetCallbacks(callbacks);
|
||||
|
||||
// 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_);
|
||||
|
||||
/* Start the clock timer to update the status bar */
|
||||
esp_timer_start_periodic(clock_timer_handle_, 1000000);
|
||||
|
||||
@@ -357,6 +387,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 +398,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 +411,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 +508,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 +530,7 @@ void Application::Start() {
|
||||
});
|
||||
bool protocol_started = protocol_->Start();
|
||||
|
||||
SystemInfo::PrintHeapStats();
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
|
||||
has_server_time_ = ota.HasServerTime();
|
||||
@@ -499,27 +539,7 @@ 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);
|
||||
}
|
||||
|
||||
// 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();
|
||||
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,23 +556,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 +596,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +630,7 @@ void Application::OnWakeWordDetected() {
|
||||
|
||||
auto wake_word = audio_service_.GetLastWakeWord();
|
||||
ESP_LOGI(TAG, "Wake word detected: %s", wake_word.c_str());
|
||||
#if CONFIG_USE_AFE_WAKE_WORD || CONFIG_USE_CUSTOM_WAKE_WORD
|
||||
#if CONFIG_SEND_WAKE_WORD_DATA
|
||||
// Encode and send the wake word data to the server
|
||||
while (auto packet = audio_service_.PopWakeWordPacket()) {
|
||||
protocol_->SendAudio(std::move(packet));
|
||||
@@ -609,7 +641,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 +653,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) {
|
||||
@@ -677,11 +711,7 @@ void Application::SetDeviceState(DeviceState state) {
|
||||
if (listening_mode_ != kListeningModeRealtime) {
|
||||
audio_service_.EnableVoiceProcessing(false);
|
||||
// Only AFE wake word can be detected in speaking mode
|
||||
#if CONFIG_USE_AFE_WAKE_WORD
|
||||
audio_service_.EnableWakeWordDetection(true);
|
||||
#else
|
||||
audio_service_.EnableWakeWordDetection(false);
|
||||
#endif
|
||||
audio_service_.EnableWakeWordDetection(audio_service_.IsAfeWakeWord());
|
||||
}
|
||||
audio_service_.ResetDecoder();
|
||||
break;
|
||||
@@ -693,17 +723,100 @@ 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 (!protocol_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_state_ == kDeviceStateIdle) {
|
||||
ToggleChatState();
|
||||
Schedule([this, wake_word]() {
|
||||
if (protocol_) {
|
||||
protocol_->SendWakeWordDetected(wake_word);
|
||||
audio_service_.EncodeWakeWord();
|
||||
|
||||
if (!protocol_->IsAudioChannelOpened()) {
|
||||
SetDeviceState(kDeviceStateConnecting);
|
||||
if (!protocol_->OpenAudioChannel()) {
|
||||
audio_service_.EnableWakeWordDetection(true);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Wake word detected: %s", wake_word.c_str());
|
||||
#if CONFIG_USE_AFE_WAKE_WORD || CONFIG_USE_CUSTOM_WAKE_WORD
|
||||
// Encode and send the wake word data to the server
|
||||
while (auto packet = audio_service_.PopWakeWordPacket()) {
|
||||
protocol_->SendAudio(std::move(packet));
|
||||
}
|
||||
// Set the chat state to wake word detected
|
||||
protocol_->SendWakeWordDetected(wake_word);
|
||||
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
|
||||
#else
|
||||
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
|
||||
// Play the pop up sound to indicate the wake word is detected
|
||||
audio_service_.PlaySound(Lang::Sounds::OGG_POPUP);
|
||||
#endif
|
||||
} else if (device_state_ == kDeviceStateSpeaking) {
|
||||
Schedule([this]() {
|
||||
AbortSpeaking(kAbortReasonNone);
|
||||
@@ -735,11 +848,18 @@ 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_) {
|
||||
protocol_->SendMcpMessage(payload);
|
||||
} else {
|
||||
Schedule([this, payload = std::move(payload)]() {
|
||||
protocol_->SendMcpMessage(payload);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Application::SetAecMode(AecMode mode) {
|
||||
|
||||
@@ -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_
|
||||
|
||||
517
main/assets.cc
Normal file
517
main/assets.cc
Normal file
@@ -0,0 +1,517 @@
|
||||
#include "assets.h"
|
||||
#include "board.h"
|
||||
#include "display.h"
|
||||
#include "application.h"
|
||||
#include "lvgl_theme.h"
|
||||
#include "emote_display.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() {
|
||||
// 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");
|
||||
cJSON* eaf = cJSON_GetObjectItem(emoji, "eaf");
|
||||
if (cJSON_IsString(name) && cJSON_IsString(file) && (NULL== eaf)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
ESP_LOGI(TAG, "Refreshing display theme...");
|
||||
|
||||
auto current_theme = display->GetTheme();
|
||||
if (current_theme != nullptr) {
|
||||
display->SetTheme(current_theme);
|
||||
}
|
||||
#elif defined(CONFIG_USE_EMOTE_MESSAGE_STYLE)
|
||||
auto &board = Board::GetInstance();
|
||||
auto display = board.GetDisplay();
|
||||
auto emote_display = dynamic_cast<emote::EmoteDisplay*>(display);
|
||||
|
||||
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 (emote_display) {
|
||||
emote_display->AddTextFont(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)) {
|
||||
int emoji_count = cJSON_GetArraySize(emoji_collection);
|
||||
if (emote_display) {
|
||||
for (int i = 0; i < emoji_count; i++) {
|
||||
cJSON* icon = cJSON_GetArrayItem(emoji_collection, i);
|
||||
if (cJSON_IsObject(icon)) {
|
||||
cJSON* name = cJSON_GetObjectItem(icon, "name");
|
||||
cJSON* file = cJSON_GetObjectItem(icon, "file");
|
||||
|
||||
if (cJSON_IsString(name) && cJSON_IsString(file)) {
|
||||
if (GetAssetData(file->valuestring, ptr, size)) {
|
||||
cJSON* eaf = cJSON_GetObjectItem(icon, "eaf");
|
||||
bool lack_value = false;
|
||||
bool loop_value = false;
|
||||
int fps_value = 0;
|
||||
|
||||
if (cJSON_IsObject(eaf)) {
|
||||
cJSON* lack = cJSON_GetObjectItem(eaf, "lack");
|
||||
cJSON* loop = cJSON_GetObjectItem(eaf, "loop");
|
||||
cJSON* fps = cJSON_GetObjectItem(eaf, "fps");
|
||||
|
||||
lack_value = lack ? cJSON_IsTrue(lack) : false;
|
||||
loop_value = loop ? cJSON_IsTrue(loop) : false;
|
||||
fps_value = fps ? fps->valueint : 0;
|
||||
|
||||
emote_display->AddEmojiData(name->valuestring, ptr, size,
|
||||
static_cast<uint8_t>(fps_value),
|
||||
loop_value, lack_value);
|
||||
}
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Emoji \"%10s\" image file %s is not found", name->valuestring, file->valuestring);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* icon_collection = cJSON_GetObjectItem(root, "icon_collection");
|
||||
if (cJSON_IsArray(icon_collection)) {
|
||||
if (emote_display) {
|
||||
int icon_count = cJSON_GetArraySize(icon_collection);
|
||||
for (int i = 0; i < icon_count; i++) {
|
||||
cJSON* icon = cJSON_GetArrayItem(icon_collection, i);
|
||||
if (cJSON_IsObject(icon)) {
|
||||
cJSON* name = cJSON_GetObjectItem(icon, "name");
|
||||
cJSON* file = cJSON_GetObjectItem(icon, "file");
|
||||
|
||||
if (cJSON_IsString(name) && cJSON_IsString(file)) {
|
||||
if (GetAssetData(file->valuestring, ptr, size)) {
|
||||
emote_display->AddIconData(name->valuestring, ptr, size);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Icon \"%10s\" image file %s is not found", name->valuestring, file->valuestring);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* layout_json = cJSON_GetObjectItem(root, "layout");
|
||||
if (cJSON_IsArray(layout_json)) {
|
||||
int layout_count = cJSON_GetArraySize(layout_json);
|
||||
|
||||
for (int i = 0; i < layout_count; i++) {
|
||||
cJSON* layout_item = cJSON_GetArrayItem(layout_json, i);
|
||||
if (cJSON_IsObject(layout_item)) {
|
||||
cJSON* name = cJSON_GetObjectItem(layout_item, "name");
|
||||
cJSON* align = cJSON_GetObjectItem(layout_item, "align");
|
||||
cJSON* x = cJSON_GetObjectItem(layout_item, "x");
|
||||
cJSON* y = cJSON_GetObjectItem(layout_item, "y");
|
||||
cJSON* width = cJSON_GetObjectItem(layout_item, "width");
|
||||
cJSON* height = cJSON_GetObjectItem(layout_item, "height");
|
||||
|
||||
if (cJSON_IsString(name) && cJSON_IsString(align) && cJSON_IsNumber(x) && cJSON_IsNumber(y)) {
|
||||
int width_val = cJSON_IsNumber(width) ? width->valueint : 0;
|
||||
int height_val = cJSON_IsNumber(height) ? height->valueint : 0;
|
||||
|
||||
if (emote_display) {
|
||||
emote_display->AddLayoutData(name->valuestring, align->valuestring,
|
||||
x->valueint, y->valueint, width_val, height_val);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Invalid layout item %d: missing required fields", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 定义扇区大小为4KB(ESP32的标准扇区大小)
|
||||
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;
|
||||
}
|
||||
52
main/assets.h
Normal file
52
main/assets.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef ASSETS_H
|
||||
#define ASSETS_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <esp_partition.h>
|
||||
#include <model_path.h>
|
||||
|
||||
|
||||
struct Asset {
|
||||
size_t size;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
class Assets {
|
||||
public:
|
||||
static Assets& GetInstance() {
|
||||
static Assets instance;
|
||||
return instance;
|
||||
}
|
||||
~Assets();
|
||||
|
||||
bool Download(std::string url, std::function<void(int progress, size_t speed)> progress_callback);
|
||||
bool Apply();
|
||||
bool GetAssetData(const std::string& name, void*& ptr, size_t& size);
|
||||
|
||||
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();
|
||||
Assets(const Assets&) = delete;
|
||||
Assets& operator=(const Assets&) = delete;
|
||||
|
||||
bool InitializePartition();
|
||||
uint32_t CalculateChecksum(const char* data, uint32_t length);
|
||||
|
||||
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
|
||||
BIN
main/assets/common/exclamation.ogg
Normal file
BIN
main/assets/common/exclamation.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/low_battery.ogg
Normal file
BIN
main/assets/common/low_battery.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/popup.ogg
Normal file
BIN
main/assets/common/popup.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/success.ogg
Normal file
BIN
main/assets/common/success.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/vibration.ogg
Normal file
BIN
main/assets/common/vibration.ogg
Normal file
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.
BIN
main/assets/locales/ar-SA/0.ogg
Normal file
BIN
main/assets/locales/ar-SA/0.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/1.ogg
Normal file
BIN
main/assets/locales/ar-SA/1.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/2.ogg
Normal file
BIN
main/assets/locales/ar-SA/2.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/3.ogg
Normal file
BIN
main/assets/locales/ar-SA/3.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/4.ogg
Normal file
BIN
main/assets/locales/ar-SA/4.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/5.ogg
Normal file
BIN
main/assets/locales/ar-SA/5.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/6.ogg
Normal file
BIN
main/assets/locales/ar-SA/6.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/7.ogg
Normal file
BIN
main/assets/locales/ar-SA/7.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/8.ogg
Normal file
BIN
main/assets/locales/ar-SA/8.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/9.ogg
Normal file
BIN
main/assets/locales/ar-SA/9.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/activation.ogg
Normal file
BIN
main/assets/locales/ar-SA/activation.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/err_pin.ogg
Normal file
BIN
main/assets/locales/ar-SA/err_pin.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/err_reg.ogg
Normal file
BIN
main/assets/locales/ar-SA/err_reg.ogg
Normal file
Binary file not shown.
55
main/assets/locales/ar-SA/language.json
Normal file
55
main/assets/locales/ar-SA/language.json
Normal 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": "مرحباً، صديقي!"
|
||||
}
|
||||
}
|
||||
BIN
main/assets/locales/ar-SA/upgrade.ogg
Normal file
BIN
main/assets/locales/ar-SA/upgrade.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/welcome.ogg
Normal file
BIN
main/assets/locales/ar-SA/welcome.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/wificonfig.ogg
Normal file
BIN
main/assets/locales/ar-SA/wificonfig.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/0.ogg
Normal file
BIN
main/assets/locales/bg-BG/0.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/1.ogg
Normal file
BIN
main/assets/locales/bg-BG/1.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/2.ogg
Normal file
BIN
main/assets/locales/bg-BG/2.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/3.ogg
Normal file
BIN
main/assets/locales/bg-BG/3.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/4.ogg
Normal file
BIN
main/assets/locales/bg-BG/4.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/5.ogg
Normal file
BIN
main/assets/locales/bg-BG/5.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/6.ogg
Normal file
BIN
main/assets/locales/bg-BG/6.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/7.ogg
Normal file
BIN
main/assets/locales/bg-BG/7.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/8.ogg
Normal file
BIN
main/assets/locales/bg-BG/8.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/9.ogg
Normal file
BIN
main/assets/locales/bg-BG/9.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/activation.ogg
Normal file
BIN
main/assets/locales/bg-BG/activation.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/err_pin.ogg
Normal file
BIN
main/assets/locales/bg-BG/err_pin.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/err_reg.ogg
Normal file
BIN
main/assets/locales/bg-BG/err_reg.ogg
Normal file
Binary file not shown.
57
main/assets/locales/bg-BG/language.json
Normal file
57
main/assets/locales/bg-BG/language.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"language": {
|
||||
"type": "bg-BG"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING": "Предупреждение",
|
||||
"INFO": "Информация",
|
||||
"ERROR": "Грешка",
|
||||
"VERSION": "Версия ",
|
||||
"LOADING_PROTOCOL": "Влизане в системата...",
|
||||
"INITIALIZING": "Инициализация...",
|
||||
"PIN_ERROR": "Моля, поставете SIM карта",
|
||||
"REG_ERROR": "Не може да се осъществи достъп до мрежата, моля проверете статуса на SIM картата",
|
||||
"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": "Свързване...",
|
||||
"CONNECTION_SUCCESSFUL": "Успешно свързване",
|
||||
"CONNECTED_TO": "Свързан към ",
|
||||
"LISTENING": "Слушане...",
|
||||
"SPEAKING": "Говорене...",
|
||||
"SERVER_NOT_FOUND": "Търсене на налична услуга",
|
||||
"SERVER_NOT_CONNECTED": "Не може да се свърже с услугата, моля опитайте по-късно",
|
||||
"SERVER_TIMEOUT": "Времето за изчакване на отговор изтече",
|
||||
"SERVER_ERROR": "Неуспешно изпращане, моля проверете мрежата",
|
||||
"CONNECT_TO_HOTSPOT": "Горещa точка: ",
|
||||
"ACCESS_VIA_BROWSER": " Конфигурационен URL: ",
|
||||
"WIFI_CONFIG_MODE": "Режим на конфигуриране на Wi-Fi",
|
||||
"ENTERING_WIFI_CONFIG_MODE": "Влизане в режим на конфигуриране на Wi-Fi...",
|
||||
"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 включен",
|
||||
"PLEASE_WAIT": "Моля, изчакайте...",
|
||||
"FOUND_NEW_ASSETS": "Намерени нови ресурси: %s",
|
||||
"DOWNLOAD_ASSETS_FAILED": "Неуспешно изтегляне на ресурси",
|
||||
"LOADING_ASSETS": "Зареждане на ресурси...",
|
||||
"HELLO_MY_FRIEND": "Здравей, мой приятел!"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
main/assets/locales/bg-BG/upgrade.ogg
Normal file
BIN
main/assets/locales/bg-BG/upgrade.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/welcome.ogg
Normal file
BIN
main/assets/locales/bg-BG/welcome.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/bg-BG/wificonfig.ogg
Normal file
BIN
main/assets/locales/bg-BG/wificonfig.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/0.ogg
Normal file
BIN
main/assets/locales/ca-ES/0.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/1.ogg
Normal file
BIN
main/assets/locales/ca-ES/1.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/2.ogg
Normal file
BIN
main/assets/locales/ca-ES/2.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/3.ogg
Normal file
BIN
main/assets/locales/ca-ES/3.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/4.ogg
Normal file
BIN
main/assets/locales/ca-ES/4.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/5.ogg
Normal file
BIN
main/assets/locales/ca-ES/5.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/6.ogg
Normal file
BIN
main/assets/locales/ca-ES/6.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/7.ogg
Normal file
BIN
main/assets/locales/ca-ES/7.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ca-ES/8.ogg
Normal file
BIN
main/assets/locales/ca-ES/8.ogg
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user