add some code

This commit is contained in:
2025-09-05 13:25:11 +08:00
parent 9ff0a99e7a
commit 3cf1229a85
8911 changed files with 2535396 additions and 0 deletions

14
CMakeLists.txt Executable file
View File

@@ -0,0 +1,14 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(PROJECT_VER "1.9.0")
# Add this line to disable the specific warning
add_compile_options(-Wno-missing-field-initializers)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(xiaozhi)

22
LICENSE Normal file
View File

@@ -0,0 +1,22 @@
MIT License
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
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

659
dependencies.lock Normal file
View File

@@ -0,0 +1,659 @@
dependencies:
78/esp-ml307:
component_hash: 97a1eeb5274d841bbfbe50ef6b6976f028b0f53e57aee95eda57f49048d02fb9
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 3.3.0
78/esp-opus:
component_hash: 8182b733f071d7bfe1e837f4c9f8649a63e4c937177f089e65772880c02f2e17
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com
type: service
version: 1.0.5
78/esp-opus-encoder:
component_hash: b80e5b6d6dc4bf6b0bf1a3729f52b80500e9e6b1003b3e827b78ba738283a296
dependencies:
- name: 78/esp-opus
registry_url: https://components.espressif.com
require: private
version: ^1.0.5
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.4.1
78/esp-wifi-connect:
component_hash: 752e62d469a341495368b6a3f812afdbe37569ea5b4460f4eedec42253118e8c
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.5.2
78/esp_lcd_nv3023:
component_hash: fa88abfc19a312eb5e6f2ffa187e0a9faf67e01e758bfb979d3f9d92561a494f
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
78/xiaozhi-fonts:
component_hash: d9cc3aad735638e558cee514103b25d2cb60afc78ef53709ffeea443b4d1c835
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.5.1
chmorgan/esp-libhelix-mp3:
component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53
dependencies:
- name: idf
require: private
version: '>=4.1.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.3
espressif/adc_battery_estimation:
component_hash: a63de81f60adddd5204ed8f286754f1186f16a2fc0f2119152a9d36771f9526a
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 0.2.0
espressif/adc_mic:
component_hash: ca6ef69bba4dc0d3e0ce53937635ed2734d38ac947881da81b8526e6851a71a4
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: espressif/esp_codec_dev
registry_url: https://components.espressif.com
require: private
version: ^1.3.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 0.2.1
espressif/button:
component_hash: f53face2ab21fa0ffaf4cf0f6e513d393f56df6586bb2ad1146120f03f19ee05
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: idf
require: private
version: '>=4.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 4.1.3
espressif/cmake_utilities:
component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
dependencies:
- name: idf
require: private
version: '>=4.1'
source:
registry_url: https://components.espressif.com
type: service
version: 0.5.3
espressif/dl_fft:
component_hash: 7dadbd644c0d7ba4733cc3726ec4cff6edf27b043725e1115861dec1609a3d28
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com
type: service
version: 0.3.1
espressif/esp-dsp:
component_hash: 619639efc18cfa361a9e423739b9b0ffc14991effc6c027f955c2f2c3bf1754b
dependencies:
- name: idf
require: private
version: '>=4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.6.0
espressif/esp-sr:
component_hash: 12733d9b4aef5d5e295f35c4671835d605992d00583fcd2f8d21166f62c6b071
dependencies:
- name: espressif/dl_fft
registry_url: https://components.espressif.com
require: private
version: '>=0.2.0'
- name: espressif/esp-dsp
registry_url: https://components.espressif.com
require: private
version: 1.6.0
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.1.5
espressif/esp32-camera:
component_hash: b209707f12aff1683c5c9dfaff3fa60f0eca687f2bf74f133cdef68fbae86028
dependencies:
- name: espressif/esp_jpeg
registry_url: https://components.espressif.com
require: public
version: ^1.3.0
- name: idf
require: private
version: '>=5.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.1.2
espressif/esp_codec_dev:
component_hash: 3a1df01ee46d64c55155341bb6f4834db33db7dbd9b637e476e1eab64d01295a
dependencies:
- name: idf
require: private
version: '>=4.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.4.0
espressif/esp_io_expander:
component_hash: fbc0de4082fc7c207dc98a93a0ed83d1a929a4ecee83cc567afb406f3ee6d4a6
dependencies:
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.0.1
espressif/esp_io_expander_tca9554:
component_hash: 8a9e3a7dbef589a54f814ff22e9121da86bce19d0e1ccffa53f5df6bb346a140
dependencies:
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: public
version: ^1.0.1
- name: idf
require: private
version: '>=5.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.0.0
espressif/esp_io_expander_tca95xx_16bit:
component_hash: f0c87a480d3e341fcfa3f7d00890270da1325a294a7d26ddeb5af5fb3ce8ba54
dependencies:
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: public
version: ^1.0.1
- name: idf
require: private
version: '>=5.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.0.0
espressif/esp_jpeg:
component_hash: defb83669293cbf86d0fa86b475ba5517aceed04ed70db435388c151ab37b5d7
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com
type: service
version: 1.3.1
espressif/esp_lcd_axs15231b:
component_hash: 654890185757826d1d23925afa4bccf874acd7f15aa6fadca1bc0ef408b2d273
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/esp_lcd_gc9a01:
component_hash: 09ddc8f5c9d718a659ffa30a4040e1ae75077e68492c38aec8c2beaaa7b3a9bc
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.0.1
espressif/esp_lcd_ili9341:
component_hash: 31f1b793aa2110dd2ae071c21ccbff0a4eb20d9a4ee40b6294c0dc0ad9552c4e
dependencies:
- name: idf
require: private
version: '>=4.4'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
source:
registry_url: https://components.espressif.com/
type: service
version: 1.2.0
espressif/esp_lcd_panel_io_additions:
component_hash: 213d5c4a3c322a48c9f993d6bc2372206d34af95db34e87a3e02601bdcad7ce8
dependencies:
- name: idf
require: private
version: '>=4.4.2'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: public
version: ^1
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/esp_lcd_spd2010:
component_hash: 8637c97feeb8d83ba637599f6bf4ef30e83595486930e7df17ffa24f3fef1242
dependencies:
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.2
espressif/esp_lcd_st77916:
component_hash: 5fa0f8b1274576d4484e2b8d9358e2a5d09c721511bef0dce6a55b4206b5f0e9
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/esp_lcd_st7796:
component_hash: 00ab2872c56a4037e6d1efda104ef0da00c5296865f8f938cc7cc2fc3e99f962
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32
- esp32s2
- esp32s3
- esp32p4
version: 1.3.2
espressif/esp_lcd_touch:
component_hash: 779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4
dependencies:
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.1.2
espressif/esp_lcd_touch_cst816s:
component_hash: 51dfa9cee38d8a20f4b625d7f89120dff08c8557e613e09dfb31f53d48648235
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.0.4
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.0
espressif/esp_lcd_touch_ft5x06:
component_hash: abaec05f46a793549b60afdda9eff86e3c8e87782c8c169007911232388d2858
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.0.4
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.7
espressif/esp_lcd_touch_gt1151:
component_hash: 69dd86cd5fad2442e3bf15c8c4ddddbe9e8739bdb26cd5f2c5249601b4c3cc38
dependencies:
- name: idf
require: private
version: '>=4.4.2'
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.0.4
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.5~2
espressif/esp_lcd_touch_gt911:
component_hash: acc1c184358aa29ef72506f618c9c76a8cc2bf12af38a2bff3d44d84f3a08857
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.1.0
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.3
espressif/esp_lvgl_port:
component_hash: e720c95cf0667554a204591bb5fade4655fb2990465557041200fa44b5bc7556
dependencies:
- name: idf
require: private
version: '>=4.4'
- name: lvgl/lvgl
registry_url: https://components.espressif.com
require: public
version: '>=8,<10'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.6.0
espressif/esp_mmap_assets:
component_hash: 9b6eea296488103300f31a9e0fe9096f830b99341332a0dfccd7e3ce43814302
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.3.1~2
espressif/esp_new_jpeg:
component_hash: 7c07831bbf11d15f84f42dc0e127094c78063b03d0dce688495773656f998d2b
dependencies: []
source:
registry_url: https://components.espressif.com
type: service
targets:
- esp32
- esp32s2
- esp32s3
- esp32p4
- esp32c2
- esp32c3
- esp32c5
- esp32c6
version: 0.5.1
espressif/freetype:
component_hash: cd5e2d8458e6e8d73f1120ac474467cabb669d8ea4b25050bf6a348c1e89225e
dependencies:
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com
type: service
version: 2.13.3~1
espressif/knob:
component_hash: a389d980693ad195b2160de22a72f3391694230188ab16b8f3c7ec4410a7c417
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
espressif/led_strip:
component_hash: 223998f10cae6d81f2ad2dd3c1103c2221be298c708e37917482b0153f3ec64e
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 3.0.1~1
espressif2022/esp_emote_gfx:
component_hash: c95160503ccd2ce4c3cf4194888005ca14f0f47a4cd0bb3f6d5f003733a2c3de
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_new_jpeg
registry_url: https://components.espressif.com
require: private
version: 0.5.*
- name: espressif/freetype
registry_url: https://components.espressif.com
require: private
version: 2.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0~2
espressif2022/image_player:
component_hash: 8d09974862ba5323c0c97b77deb3be81ca7bd83e60f77265504c086cd69cc5cf
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.0~1
idf:
source:
type: idf
version: 5.5.0
lvgl/lvgl:
component_hash: b702d642e03e95928046d5c6726558e6444e112420c77efa5fdb6650b0a13c5d
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 9.3.0
tny-robotics/sh1106-esp-idf:
component_hash: 7be190d7c58cd635adf8b74b3a841f8245f2f82f36d135a64d8e53cfab39124d
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
txp666/otto-emoji-gif-component:
component_hash: 22580fe159d3fae35f1c44634e883726f503424eb0c96bc1ee9b2cf9e32b6f2f
dependencies:
- name: idf
require: private
version: '>=5.4.0'
- name: lvgl/lvgl
registry_url: https://components.espressif.com
require: private
version: '>=9.0'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32s3
- esp32
- esp32c3
- esp32c6
- esp32h2
- esp32p4
version: 1.0.2
waveshare/esp_lcd_sh8601:
component_hash: 1a2829e9db4e0515bad6ce83368f199dec60519fbba40251d6c8249f5d070ae1
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.2
waveshare/esp_lcd_touch_cst9217:
component_hash: c5da844e73ab7b7e02938901e71f38deed94b26976045fb4517e7fc1e8dc4db5
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.1.0
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.3
wvirgil123/sscma_client:
component_hash: bf7d4a1f157303f4850d0b9b465c733ce38e8689ff40ac4743a44520524c41d5
dependencies:
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: private
version: ^1.0.1
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.2
direct_dependencies:
- 78/esp-ml307
- 78/esp-opus-encoder
- 78/esp-wifi-connect
- 78/esp_lcd_nv3023
- 78/xiaozhi-fonts
- chmorgan/esp-libhelix-mp3
- espressif/adc_battery_estimation
- espressif/adc_mic
- espressif/button
- espressif/esp-sr
- espressif/esp32-camera
- espressif/esp_codec_dev
- espressif/esp_io_expander_tca9554
- espressif/esp_io_expander_tca95xx_16bit
- espressif/esp_lcd_axs15231b
- espressif/esp_lcd_gc9a01
- espressif/esp_lcd_ili9341
- espressif/esp_lcd_panel_io_additions
- espressif/esp_lcd_spd2010
- espressif/esp_lcd_st77916
- espressif/esp_lcd_st7796
- espressif/esp_lcd_touch_cst816s
- espressif/esp_lcd_touch_ft5x06
- espressif/esp_lcd_touch_gt1151
- espressif/esp_lcd_touch_gt911
- espressif/esp_lvgl_port
- espressif/esp_mmap_assets
- espressif/knob
- espressif/led_strip
- espressif2022/esp_emote_gfx
- espressif2022/image_player
- idf
- lvgl/lvgl
- tny-robotics/sh1106-esp-idf
- txp666/otto-emoji-gif-component
- waveshare/esp_lcd_sh8601
- waveshare/esp_lcd_touch_cst9217
- wvirgil123/sscma_client
manifest_hash: 1af3184e8179db5dd2d5a0a78e420c425305f4b1d7378a0340ce6fbbffd67c14
target: esp32s3
version: 2.0.0

BIN
main/.DS_Store vendored Normal file

Binary file not shown.

399
main/CMakeLists.txt Normal file
View File

@@ -0,0 +1,399 @@
set(SOURCES "audio/audio_codec.cc"
"audio/audio_service.cc"
"audio/codecs/no_audio_codec.cc"
"audio/codecs/box_audio_codec.cc"
"audio/codecs/es8311_audio_codec.cc"
"audio/codecs/es8374_audio_codec.cc"
"audio/codecs/es8388_audio_codec.cc"
"audio/codecs/es8389_audio_codec.cc"
"audio/codecs/dummy_audio_codec.cc"
"audio/processors/audio_debugger.cc"
"led/single_led.cc"
"led/circular_strip.cc"
"led/gpio_led.cc"
"display/display.cc"
"display/lcd_display.cc"
"display/oled_display.cc"
"protocols/protocol.cc"
"protocols/mqtt_protocol.cc"
"protocols/websocket_protocol.cc"
"mcp_server.cc"
"system_info.cc"
"application.cc"
"ota.cc"
"settings.cc"
"device_state_event.cc"
"main.cc"
)
set(INCLUDE_DIRS "." "display" "audio" "protocols")
# 添加板级公共文件
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 配置添加对应的板级文件
if(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI)
set(BOARD_TYPE "bread-compact-wifi")
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ML307)
set(BOARD_TYPE "bread-compact-ml307")
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")
elseif(CONFIG_BOARD_TYPE_DF_K10)
set(BOARD_TYPE "df-k10")
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")
elseif(CONFIG_BOARD_TYPE_ESP_BOX)
set(BOARD_TYPE "esp-box")
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")
elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_2)
set(BOARD_TYPE "kevin-box-2")
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")
elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V4_DEV)
set(BOARD_TYPE "kevin-sp-v4-dev")
elseif(CONFIG_BOARD_TYPE_KEVIN_YUYING_313LCD)
set(BOARD_TYPE "kevin-yuying-313lcd")
elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV)
set(BOARD_TYPE "lichuang-dev")
elseif(CONFIG_BOARD_TYPE_LICHUANG_C3_DEV)
set(BOARD_TYPE "lichuang-c3-dev")
elseif(CONFIG_BOARD_TYPE_MAGICLICK_2P4)
set(BOARD_TYPE "magiclick-2p4")
elseif(CONFIG_BOARD_TYPE_MAGICLICK_2P5)
set(BOARD_TYPE "magiclick-2p5")
elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3)
set(BOARD_TYPE "magiclick-c3")
elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3_V2)
set(BOARD_TYPE "magiclick-c3-v2")
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_S3)
set(BOARD_TYPE "m5stack-core-s3")
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_TAB5)
set(BOARD_TYPE "m5stack-tab5")
elseif(CONFIG_BOARD_TYPE_ATOMS3_ECHO_BASE)
set(BOARD_TYPE "atoms3-echo-base")
elseif(CONFIG_BOARD_TYPE_ATOMS3R_ECHO_BASE)
set(BOARD_TYPE "atoms3r-echo-base")
elseif(CONFIG_BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE)
set(BOARD_TYPE "atoms3r-cam-m12-echo-base")
elseif(CONFIG_BOARD_TYPE_ATOM_ECHOS3R)
set(BOARD_TYPE "atom-echos3r")
elseif(CONFIG_BOARD_TYPE_ATOMMATRIX_ECHO_BASE)
set(BOARD_TYPE "atommatrix-echo-base")
elseif(CONFIG_BOARD_TYPE_XMINI_C3_V3)
set(BOARD_TYPE "xmini-c3-v3")
elseif(CONFIG_BOARD_TYPE_XMINI_C3_4G)
set(BOARD_TYPE "xmini-c3-4g")
elseif(CONFIG_BOARD_TYPE_XMINI_C3)
set(BOARD_TYPE "xmini-c3")
elseif(CONFIG_BOARD_TYPE_ESP32S3_KORVO2_V3)
set(BOARD_TYPE "esp32s3-korvo2-v3")
elseif(CONFIG_BOARD_TYPE_ESP_SPARKBOT)
set(BOARD_TYPE "esp-sparkbot")
elseif(CONFIG_BOARD_TYPE_ESP_SPOT_S3)
set(BOARD_TYPE "esp-spot-s3")
elseif(CONFIG_BOARD_TYPE_ESP_HI)
set(BOARD_TYPE "esp-hi")
elseif(CONFIG_BOARD_TYPE_ECHOEAR)
set(BOARD_TYPE "echoear")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06)
set(BOARD_TYPE "waveshare-s3-touch-amoled-2.06")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75)
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85C)
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85c")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85)
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_46)
set(BOARD_TYPE "esp32-s3-touch-lcd-1.46")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5)
set(BOARD_TYPE "esp32-s3-touch-lcd-3.5")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5B)
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.5b")
elseif(CONFIG_BOARD_TYPE_ESP32C6_LCD_1_69)
set(BOARD_TYPE "waveshare-c6-lcd-1.69")
elseif(CONFIG_BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43)
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.43")
elseif(CONFIG_BOARD_TYPE_ESP32P4_NANO)
set(BOARD_TYPE "waveshare-p4-nano")
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-4b")
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-xc")
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_LCD)
set(BOARD_TYPE "bread-compact-wifi-lcd")
elseif(CONFIG_BOARD_TYPE_TUDOUZI)
set(BOARD_TYPE "tudouzi")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CIRCLE_S3)
set(BOARD_TYPE "lilygo-t-circle-s3")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1)
set(BOARD_TYPE "lilygo-t-cameraplus-s3")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2)
set(BOARD_TYPE "lilygo-t-cameraplus-s3")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA)
set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora")
elseif(CONFIG_BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY)
set(BOARD_TYPE "lilygo-t-display-s3-pro-mvsrlora")
elseif(CONFIG_BOARD_TYPE_MOVECALL_MOJI_ESP32S3)
set(BOARD_TYPE "movecall-moji-esp32s3")
elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3)
set(BOARD_TYPE "movecall-cuican-esp32s3")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3)
set(BOARD_TYPE "atk-dnesp32s3")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX)
set(BOARD_TYPE "atk-dnesp32s3-box")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX0)
set(BOARD_TYPE "atk-dnesp32s3-box0")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI)
set(BOARD_TYPE "atk-dnesp32s3-box2-wifi")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_4G)
set(BOARD_TYPE "atk-dnesp32s3-box2-4g")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_WIFI)
set(BOARD_TYPE "atk-dnesp32s3m-wifi")
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_4G)
set(BOARD_TYPE "atk-dnesp32s3m-4g")
elseif(CONFIG_BOARD_TYPE_DU_CHATX)
set(BOARD_TYPE "du-chatx")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Taiji_Pi)
set(BOARD_TYPE "taiji-pi-s3")
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(BOARD_TYPE "xingzhi-cube-0.85tft-ml307")
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(BOARD_TYPE "xingzhi-cube-0.96oled-ml307")
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(BOARD_TYPE "xingzhi-cube-1.54tft-ml307")
elseif(CONFIG_BOARD_TYPE_SENSECAP_WATCHER)
set(BOARD_TYPE "sensecap-watcher")
elseif(CONFIG_BOARD_TYPE_DOIT_S3_AIBOX)
set(BOARD_TYPE "doit-s3-aibox")
elseif(CONFIG_BOARD_TYPE_MIXGO_NOVA)
set(BOARD_TYPE "mixgo-nova")
elseif(CONFIG_BOARD_TYPE_GENJUTECH_S3_1_54TFT)
set(BOARD_TYPE "genjutech-s3-1.54tft")
elseif(CONFIG_BOARD_TYPE_ESP32_CGC)
set(BOARD_TYPE "esp32-cgc")
elseif(CONFIG_BOARD_TYPE_ESP32_CGC_144)
set(BOARD_TYPE "esp32-cgc-144")
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board)
set(BOARD_TYPE "esp-s3-lcd-ev-board")
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
set(BOARD_TYPE "esp-s3-lcd-ev-board-2")
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI)
set(BOARD_TYPE "zhengchen-1.54tft-wifi")
elseif(CONFIG_BOARD_TYPE_MINSI_K08_DUAL)
set(BOARD_TYPE "minsi-k08-dual")
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(BOARD_TYPE "sp-esp32-s3-1.54-muma")
elseif(CONFIG_BOARD_TYPE_ESP32_S3_1_28_BOX)
set(BOARD_TYPE "sp-esp32-s3-1.28-box")
elseif(CONFIG_BOARD_TYPE_OTTO_ROBOT)
set(BOARD_TYPE "otto-robot")
elseif(CONFIG_BOARD_TYPE_ELECTRON_BOT)
set(BOARD_TYPE "electron-bot")
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_CAM)
set(BOARD_TYPE "bread-compact-wifi-s3cam")
elseif(CONFIG_BOARD_TYPE_JIUCHUAN)
set(BOARD_TYPE "jiuchuan-s3")
elseif(CONFIG_BOARD_TYPE_LABPLUS_MPYTHON_V3)
set(BOARD_TYPE "labplus-mpython-v3")
elseif(CONFIG_BOARD_TYPE_LABPLUS_LEDONG_V2)
set(BOARD_TYPE "labplus-ledong-v2")
elseif(CONFIG_BOARD_TYPE_SURFER_C3_1_14TFT)
set(BOARD_TYPE "surfer-c3-1.14tft")
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})
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)
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")
endif()
# 根据Kconfig选择语言目录
if(CONFIG_LANGUAGE_ZH_CN)
set(LANG_DIR "zh-CN")
elseif(CONFIG_LANGUAGE_ZH_TW)
set(LANG_DIR "zh-TW")
elseif(CONFIG_LANGUAGE_EN_US)
set(LANG_DIR "en-US")
elseif(CONFIG_LANGUAGE_JA_JP)
set(LANG_DIR "ja-JP")
elseif(CONFIG_LANGUAGE_KO_KR)
set(LANG_DIR "ko-KR")
elseif(CONFIG_LANGUAGE_VI_VN)
set(LANG_DIR "vi-VN")
elseif(CONFIG_LANGUAGE_TH_TH)
set(LANG_DIR "th-TH")
elseif(CONFIG_LANGUAGE_DE_DE)
set(LANG_DIR "de-DE")
elseif(CONFIG_LANGUAGE_FR_FR)
set(LANG_DIR "fr-FR")
elseif(CONFIG_LANGUAGE_ES_ES)
set(LANG_DIR "es-ES")
elseif(CONFIG_LANGUAGE_IT_IT)
set(LANG_DIR "it-IT")
elseif(CONFIG_LANGUAGE_RU_RU)
set(LANG_DIR "ru-RU")
elseif(CONFIG_LANGUAGE_AR_SA)
set(LANG_DIR "ar-SA")
elseif(CONFIG_LANGUAGE_HI_IN)
set(LANG_DIR "hi-IN")
elseif(CONFIG_LANGUAGE_PT_PT)
set(LANG_DIR "pt-PT")
elseif(CONFIG_LANGUAGE_PL_PL)
set(LANG_DIR "pl-PL")
elseif(CONFIG_LANGUAGE_CS_CZ)
set(LANG_DIR "cs-CZ")
elseif(CONFIG_LANGUAGE_FI_FI)
set(LANG_DIR "fi-FI")
elseif(CONFIG_LANGUAGE_TR_TR)
set(LANG_DIR "tr-TR")
elseif(CONFIG_LANGUAGE_ID_ID)
set(LANG_DIR "id-ID")
elseif(CONFIG_LANGUAGE_UK_UA)
set(LANG_DIR "uk-UA")
elseif(CONFIG_LANGUAGE_RO_RO)
set(LANG_DIR "ro-RO")
endif()
# 定义生成路径
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/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/locales/${LANG_DIR}/*.ogg)
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.ogg)
# 如果目标芯片是 ESP32则排除特定文件
if(CONFIG_IDF_TARGET_ESP32)
list(REMOVE_ITEM SOURCES "audio/codecs/box_audio_codec.cc"
"audio/codecs/es8388_audio_codec.cc"
"audio/codecs/es8389_audio_codec.cc"
"led/gpio_led.cc"
)
endif()
idf_component_register(SRCS ${SOURCES}
EMBED_FILES ${LANG_SOUNDS} ${COMMON_SOUNDS}
INCLUDE_DIRS ${INCLUDE_DIRS}
WHOLE_ARCHIVE
)
# 使用 target_compile_definitions 来定义 BOARD_TYPE, BOARD_NAME
# 如果 BOARD_NAME 为空,则使用 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}\"
)
# 添加生成规则
add_custom_command(
OUTPUT ${LANG_HEADER}
COMMAND python ${PROJECT_DIR}/scripts/gen_lang.py
--language "${LANG_DIR}"
--output "${LANG_HEADER}"
DEPENDS
${LANG_JSON}
${PROJECT_DIR}/scripts/gen_lang.py
COMMENT "Generating ${LANG_DIR} language config"
)
# 强制建立生成依赖
add_custom_target(lang_header ALL
DEPENDS ${LANG_HEADER}
)
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})
# List all files to download
set(FILES_TO_DOWNLOAD "")
list(APPEND FILES_TO_DOWNLOAD "Anger_enter.aaf" "Anger_loop.aaf" "Anger_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "happy_enter.aaf" "happy_loop.aaf" "happ_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "sad_enter.aaf" "sad_loop.aaf" "sad_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "scorn_enter.aaf" "scorn_loop.aaf" "scorn_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "left_enter.aaf" "left_loop.aaf" "left_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "right_enter.aaf" "right_loop.aaf" "right_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "asking.aaf" "blink_once.aaf" "blink_quick.aaf")
list(APPEND FILES_TO_DOWNLOAD "connecting.aaf" "panic_enter.aaf" "panic_loop.aaf")
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}")
# 检查本地文件是否存在
if(EXISTS ${LOCAL_FILE})
message(STATUS "File ${FILENAME} already exists, skipping download")
else()
message(STATUS "Downloading ${FILENAME}")
file(DOWNLOAD ${REMOTE_FILE} ${LOCAL_FILE}
STATUS DOWNLOAD_STATUS)
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
if(NOT STATUS_CODE EQUAL 0)
message(FATAL_ERROR "Failed to download ${FILENAME} from ${URL}")
endif()
endif()
endforeach()
spiffs_create_partition_assets(
assets_A
${SPIFFS_DIR}
FLASH_IN_PROJECT
MMAP_FILE_SUPPORT_FORMAT ".aaf"
)
endif()
if(CONFIG_BOARD_TYPE_ECHOEAR)
idf_build_get_property(build_components BUILD_COMPONENTS)
foreach(COMPONENT ${build_components})
if(COMPONENT MATCHES "esp_emote_gfx" OR COMPONENT MATCHES "espressif2022__esp_emote_gfx")
set(EMOTE_GFX_COMPONENT ${COMPONENT})
idf_component_get_property(EMOTE_GFX_COMPONENT_PATH ${EMOTE_GFX_COMPONENT} COMPONENT_DIR)
set(SPIFFS_DIR "${EMOTE_GFX_COMPONENT_PATH}/emoji_normal")
break()
endif()
endforeach()
spiffs_create_partition_assets(
assets_A
${SPIFFS_DIR}
FLASH_IN_PROJECT
MMAP_FILE_SUPPORT_FORMAT ".aaf, ttf, bin"
IMPORT_INC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}
)
endif()

544
main/Kconfig.projbuild Normal file
View File

@@ -0,0 +1,544 @@
menu "Xiaozhi Assistant"
config OTA_URL
string "Default OTA URL"
default "https://api.tenclass.net/xiaozhi/ota/"
help
The application will access this URL to check for new firmwares and server address.
choice
prompt "Default Language"
default LANGUAGE_ZH_CN
help
Select device display language
config LANGUAGE_ZH_CN
bool "Chinese"
config LANGUAGE_ZH_TW
bool "Chinese Traditional"
config LANGUAGE_EN_US
bool "English"
config LANGUAGE_JA_JP
bool "Japanese"
config LANGUAGE_KO_KR
bool "Korean"
config LANGUAGE_VI_VN
bool "Vietnamese"
config LANGUAGE_TH_TH
bool "Thai"
config LANGUAGE_DE_DE
bool "German"
config LANGUAGE_FR_FR
bool "French"
config LANGUAGE_ES_ES
bool "Spanish"
config LANGUAGE_IT_IT
bool "Italian"
config LANGUAGE_RU_RU
bool "Russian"
config LANGUAGE_AR_SA
bool "Arabic"
config LANGUAGE_HI_IN
bool "Hindi"
config LANGUAGE_PT_PT
bool "Portuguese"
config LANGUAGE_PL_PL
bool "Polish"
config LANGUAGE_CS_CZ
bool "Czech"
config LANGUAGE_FI_FI
bool "Finnish"
config LANGUAGE_TR_TR
bool "Turkish"
config LANGUAGE_ID_ID
bool "Indonesian"
config LANGUAGE_UK_UA
bool "Ukrainian"
config LANGUAGE_RO_RO
bool "Romanian"
endchoice
choice BOARD_TYPE
prompt "Board Type"
default BOARD_TYPE_BREAD_COMPACT_WIFI
help
Board type. 开发板类型
config BOARD_TYPE_BREAD_COMPACT_WIFI
bool "面包板新版接线WiFi"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_WIFI_LCD
bool "面包板新版接线WiFi+ LCD"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
bool "面包板新版接线WiFi+ LCD + Camera"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_ML307
bool "面包板新版接线ML307 AT"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_ESP32
bool "面包板WiFi ESP32 DevKit"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_BREAD_COMPACT_ESP32_LCD
bool "面包板WiFi+ LCD ESP32 DevKit"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_XMINI_C3_V3
bool "虾哥 Mini C3 V3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_XMINI_C3_4G
bool "虾哥 Mini C3 4G"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_XMINI_C3
bool "虾哥 Mini C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_ESP32S3_KORVO2_V3
bool "ESP32S3_KORVO2_V3开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_SPARKBOT
bool "ESP-SparkBot开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_SPOT_S3
bool "ESP-Spot-S3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_HI
bool "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"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_BOX
bool "ESP BOX"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_BOX_LITE
bool "ESP BOX Lite"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_BOX_1
bool "Kevin Box 1"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_BOX_2
bool "Kevin Box 2"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_C3
bool "Kevin C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_KEVIN_SP_V3_DEV
bool "Kevin SP V3开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_SP_V4_DEV
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开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LICHUANG_DEV
bool "立创·实战派ESP32-S3开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LICHUANG_C3_DEV
bool "立创·实战派ESP32-C3开发板"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_DF_K10
bool "DFRobot 行空板 k10"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_DF_S3_AI_CAM
bool "DFRobot ESP32-S3 AI智能摄像头模块"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MAGICLICK_2P4
bool "神奇按钮 Magiclick_2.4"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MAGICLICK_2P5
bool "神奇按钮 Magiclick_2.5"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MAGICLICK_C3
bool "神奇按钮 Magiclick_C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_MAGICLICK_C3_V2
bool "神奇按钮 Magiclick_C3_v2"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_M5STACK_CORE_S3
bool "M5Stack CoreS3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_CORE_TAB5
bool "M5Stack Tab5"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_ATOMS3_ECHO_BASE
bool "AtomS3 + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATOMS3R_ECHO_BASE
bool "AtomS3R + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE
bool "AtomS3R CAM/M12 + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATOM_ECHOS3R
bool "AtomEchoS3R"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
bool "AtomMatrix + Echo Base"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_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
bool "Waveshare ESP32-S3-Touch-LCD-1.85"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Touch_LCD_1_46
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32C6_LCD_1_69
bool "Waveshare ESP32-C6-LCD-1.69"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_ESP32C6_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
bool "Waveshare ESP32-S3-Touch-LCD-3.5"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5B
bool "Waveshare ESP32-S3-Touch-LCD-3.5B"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32P4_NANO
bool "Waveshare ESP32-P4-NANO"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_ESP32P4_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
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
bool "土豆子"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_CIRCLE_S3
bool "LILYGO T-Circle-S3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1
bool "LILYGO T-CameraPlus-S3_V1_0_V1_1"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2
bool "LILYGO T-CameraPlus-S3_V1_2"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA
bool "LILYGO T-Display-S3-Pro-MVSRLora"
depends on IDF_TARGET_ESP32S3
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_MOVECALL_MOJI_ESP32S3
bool "Movecall Moji 小智AI衍生版"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MOVECALL_CUICAN_ESP32S3
bool "Movecall CuiCan 璀璨·AI吊坠"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3
bool "正点原子DNESP32S3开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX
bool "正点原子DNESP32S3-BOX"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX0
bool "正点原子DNESP32S3-BOX0"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI
bool "正点原子DNESP32S3-BOX2-WIFI"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX2_4G
bool "正点原子DNESP32S3-BOX2-4G"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3M_WIFI
bool "正点原子DNESP32S3M-WIFI"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3M_4G
bool "正点原子DNESP32S3M-4G"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_DU_CHATX
bool "嘟嘟开发板CHATX(wifi)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Taiji_Pi
bool "太极小派esp32s3"
depends on IDF_TARGET_ESP32S3
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
bool "无名科技星智0.85(ML307)"
depends on IDF_TARGET_ESP32S3
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
bool "无名科技星智0.96(ML307)"
depends on IDF_TARGET_ESP32S3
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
bool "无名科技星智1.54(ML307)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_SENSECAP_WATCHER
bool "SenseCAP Watcher"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_DOIT_S3_AIBOX
bool "四博智联AI陪伴盒子"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MIXGO_NOVA
bool "元控·青春"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_GENJUTECH_S3_1_54TFT
bool "亘具科技1.54(s3)"
depends on IDF_TARGET_ESP32S3
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
config BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307
bool "征辰科技1.54(ML307)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MINSI_K08_DUAL
bool "敏思科技K08(DUAL)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_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
bool "Spotpear ESP32-S3-1.28-BOX"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_OTTO_ROBOT
bool "ottoRobot"
depends on IDF_TARGET_ESP32S3
select LV_USE_GIF
select LV_GIF_CACHE_DECODE_DATA
config BOARD_TYPE_ELECTRON_BOT
bool "electronBot"
depends on IDF_TARGET_ESP32S3
select LV_USE_GIF
select LV_GIF_CACHE_DECODE_DATA
config BOARD_TYPE_JIUCHUAN
bool "九川智能"
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"
depends on IDF_TARGET_ESP32C3
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
bool "乐鑫ESP32_S3_LCD_EV_Board-MB_V1.5"
endchoice
choice DISPLAY_OLED_TYPE
depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_ESP32
prompt "OLED Type"
default OLED_SSD1306_128X32
help
OLED 屏幕类型选择
config OLED_SSD1306_128X32
bool "SSD1306, 分辨率128*32"
config OLED_SSD1306_128X64
bool "SSD1306, 分辨率128*64"
config OLED_SH1106_128X64
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
prompt "LCD Type"
default LCD_ST7789_240X320
help
屏幕类型选择
config LCD_ST7789_240X320
bool "ST7789, 分辨率240*320, IPS"
config LCD_ST7789_240X320_NO_IPS
bool "ST7789, 分辨率240*320, 非IPS"
config LCD_ST7789_170X320
bool "ST7789, 分辨率170*320"
config LCD_ST7789_172X320
bool "ST7789, 分辨率172*320"
config LCD_ST7789_240X280
bool "ST7789, 分辨率240*280"
config LCD_ST7789_240X240
bool "ST7789, 分辨率240*240"
config LCD_ST7789_240X240_7PIN
bool "ST7789, 分辨率240*240, 7PIN"
config LCD_ST7789_240X135
bool "ST7789, 分辨率240*135"
config LCD_ST7735_128X160
bool "ST7735, 分辨率128*160"
config LCD_ST7735_128X128
bool "ST7735, 分辨率128*128"
config LCD_ST7796_320X480
bool "ST7796, 分辨率320*480 IPS"
config LCD_ST7796_320X480_NO_IPS
bool "ST7796, 分辨率320*480, 非IPS"
config LCD_ILI9341_240X320
bool "ILI9341, 分辨率240*320"
config LCD_ILI9341_240X320_NO_IPS
bool "ILI9341, 分辨率240*320, 非IPS"
config LCD_GC9A01_240X240
bool "GC9A01, 分辨率240*240, 圆屏"
config LCD_TYPE_800_1280_10_1_INCH
bool "Waveshare 101M-8001280-IPS-CT-K Display"
config LCD_TYPE_800_1280_10_1_INCH_A
bool "Waveshare 10.1-DSI-TOUCH-A Display"
config LCD_TYPE_800_800_3_4_INCH
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C with 800*800 3.4inch round display"
config LCD_TYPE_720_720_4_INCH
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C with 720*720 4inch round display"
config LCD_CUSTOM
bool "自定义屏幕参数"
endchoice
choice DISPLAY_ESP32S3_KORVO2_V3
depends on BOARD_TYPE_ESP32S3_KORVO2_V3
prompt "ESP32S3_KORVO2_V3 LCD Type"
default LCD_ST7789
help
屏幕类型选择
config LCD_ST7789
bool "ST7789, 分辨率240*280"
config LCD_ILI9341
bool "ILI9341, 分辨率240*320"
endchoice
config USE_WECHAT_MESSAGE_STYLE
bool "Enable WeChat Message Style"
default n
help
使用微信聊天界面风格
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)
help
支持 ESP32 C3、ESP32 C5 与 ESP32 C6增加ESP32支持需要开启PSRAM
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_CUSTOM_WAKE_WORD
bool "Enable Custom Wake Word Detection"
default n
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM && (!USE_AFE_WAKE_WORD)
help
需要 ESP32 S3 与 PSRAM 支持
config CUSTOM_WAKE_WORD
string "Custom Wake Word"
default "xiao tu dou"
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词,中文用拼音表示,每个字之间用空格隔开
config CUSTOM_WAKE_WORD_DISPLAY
string "Custom Wake Word Display"
default "小土豆"
depends on USE_CUSTOM_WAKE_WORD
help
唤醒后发送给服务器的问候语
config CUSTOM_WAKE_WORD_THRESHOLD
int "Custom Wake Word Threshold (%)"
default 20
range 1 99
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词阈值范围1-99越小越敏感默认10
config USE_AUDIO_PROCESSOR
bool "Enable Audio Noise Reduction"
default y
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
help
需要 ESP32 S3 与 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_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
help
因为性能不够,不建议和微信聊天界面风格同时开启
config USE_SERVER_AEC
bool "Enable Server-Side AEC (Unstable)"
default n
depends on USE_AUDIO_PROCESSOR
help
启用服务器端 AEC需要服务器支持
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 配置数据
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用于接收音频调试数据
config RECEIVE_CUSTOM_MESSAGE
bool "Enable Custom Message Reception"
default n
help
启用接收自定义消息功能,允许设备接收来自服务器的自定义消息(最好通过 MQTT 协议)
choice I2S_TYPE_TAIJIPI_S3
depends on BOARD_TYPE_ESP32S3_Taiji_Pi
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
endmenu

869
main/application.cc Normal file
View File

@@ -0,0 +1,869 @@
#include "application.h"
#include "board.h"
#include "display.h"
#include "system_info.h"
#include "audio_codec.h"
#include "mqtt_protocol.h"
#include "websocket_protocol.h"
#include "assets/lang_config.h"
#include "mcp_server.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"
static const char* const STATE_STRINGS[] = {
"unknown",
"starting",
"configuring",
"idle",
"connecting",
"listening",
"speaking",
"upgrading",
"activating",
"audio_testing",
"fatal_error",
"invalid_state"
};
Application::Application() {
event_group_ = xEventGroupCreate();
#if CONFIG_USE_DEVICE_AEC && CONFIG_USE_SERVER_AEC
#error "CONFIG_USE_DEVICE_AEC and CONFIG_USE_SERVER_AEC cannot be enabled at the same time"
#elif CONFIG_USE_DEVICE_AEC
aec_mode_ = kAecOnDeviceSide;
#elif CONFIG_USE_SERVER_AEC
aec_mode_ = kAecOnServerSide;
#else
aec_mode_ = kAecOff;
#endif
esp_timer_create_args_t clock_timer_args = {
.callback = [](void* arg) {
Application* app = (Application*)arg;
app->OnClockTimer();
},
.arg = this,
.dispatch_method = ESP_TIMER_TASK,
.name = "clock_timer",
.skip_unhandled_events = true
};
esp_timer_create(&clock_timer_args, &clock_timer_handle_);
}
Application::~Application() {
if (clock_timer_handle_ != nullptr) {
esp_timer_stop(clock_timer_handle_);
esp_timer_delete(clock_timer_handle_);
}
vEventGroupDelete(event_group_);
}
void Application::CheckNewVersion(Ota& ota) {
const int MAX_RETRY = 10;
int retry_count = 0;
int retry_delay = 10; // 初始重试延迟为10秒
auto& board = Board::GetInstance();
while (true) {
SetDeviceState(kDeviceStateActivating);
auto display = board.GetDisplay();
display->SetStatus(Lang::Strings::CHECKING_NEW_VERSION);
if (!ota.CheckVersion()) {
retry_count++;
if (retry_count >= MAX_RETRY) {
ESP_LOGE(TAG, "Too many retries, exit version check");
return;
}
char buffer[256];
snprintf(buffer, sizeof(buffer), Lang::Strings::CHECK_NEW_VERSION_FAILED, retry_delay, ota.GetCheckVersionUrl().c_str());
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++) {
vTaskDelay(pdMS_TO_TICKS(1000));
if (device_state_ == kDeviceStateIdle) {
break;
}
}
retry_delay *= 2; // 每次重试后延迟时间翻倍
continue;
}
retry_count = 0;
retry_delay = 10; // 重置重试延迟时间
if (ota.HasNewVersion()) {
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) + 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) {
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));
// 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();
return; // This line will never be reached after reboot
}
}
// No new version, mark the current version as valid
ota.MarkCurrentVersionValid();
if (!ota.HasActivationCode() && !ota.HasActivationChallenge()) {
xEventGroupSetBits(event_group_, MAIN_EVENT_CHECK_NEW_VERSION_DONE);
// Exit the loop if done checking new version
break;
}
display->SetStatus(Lang::Strings::ACTIVATION);
// Activation code is shown to the user and waiting for the user to input
if (ota.HasActivationCode()) {
ShowActivationCode(ota.GetActivationCode(), ota.GetActivationMessage());
}
// This will block the loop until the activation is done or timeout
for (int i = 0; i < 10; ++i) {
ESP_LOGI(TAG, "Activating... %d/%d", i + 1, 10);
esp_err_t err = ota.Activate();
if (err == ESP_OK) {
xEventGroupSetBits(event_group_, MAIN_EVENT_CHECK_NEW_VERSION_DONE);
break;
} else if (err == ESP_ERR_TIMEOUT) {
vTaskDelay(pdMS_TO_TICKS(3000));
} else {
vTaskDelay(pdMS_TO_TICKS(10000));
}
if (device_state_ == kDeviceStateIdle) {
break;
}
}
}
}
void Application::ShowActivationCode(const std::string& code, const std::string& message) {
struct digit_sound {
char digit;
const std::string_view& sound;
};
static const std::array<digit_sound, 10> digit_sounds{{
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(), "link", Lang::Sounds::OGG_ACTIVATION);
for (const auto& digit : code) {
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
[digit](const digit_sound& ds) { return ds.digit == digit; });
if (it != digit_sounds.end()) {
audio_service_.PlaySound(it->sound);
}
}
}
void Application::Alert(const char* status, const char* message, const char* emotion, const std::string_view& sound) {
ESP_LOGW(TAG, "Alert [%s] %s: %s", emotion, status, message);
auto display = Board::GetInstance().GetDisplay();
display->SetStatus(status);
display->SetEmotion(emotion);
display->SetChatMessage("system", message);
if (!sound.empty()) {
audio_service_.PlaySound(sound);
}
}
void Application::DismissAlert() {
if (device_state_ == kDeviceStateIdle) {
auto display = Board::GetInstance().GetDisplay();
display->SetStatus(Lang::Strings::STANDBY);
display->SetEmotion("neutral");
display->SetChatMessage("system", "");
}
}
void Application::ToggleChatState() {
if (device_state_ == kDeviceStateActivating) {
SetDeviceState(kDeviceStateIdle);
return;
} else if (device_state_ == kDeviceStateWifiConfiguring) {
audio_service_.EnableAudioTesting(true);
SetDeviceState(kDeviceStateAudioTesting);
return;
} else if (device_state_ == kDeviceStateAudioTesting) {
audio_service_.EnableAudioTesting(false);
SetDeviceState(kDeviceStateWifiConfiguring);
return;
}
if (!protocol_) {
ESP_LOGE(TAG, "Protocol not initialized");
return;
}
if (device_state_ == kDeviceStateIdle) {
Schedule([this]() {
if (!protocol_->IsAudioChannelOpened()) {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
return;
}
}
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
});
} else if (device_state_ == kDeviceStateSpeaking) {
Schedule([this]() {
AbortSpeaking(kAbortReasonNone);
});
} else if (device_state_ == kDeviceStateListening) {
Schedule([this]() {
protocol_->CloseAudioChannel();
});
}
}
void Application::StartListening() {
if (device_state_ == kDeviceStateActivating) {
SetDeviceState(kDeviceStateIdle);
return;
} else if (device_state_ == kDeviceStateWifiConfiguring) {
audio_service_.EnableAudioTesting(true);
SetDeviceState(kDeviceStateAudioTesting);
return;
}
if (!protocol_) {
ESP_LOGE(TAG, "Protocol not initialized");
return;
}
if (device_state_ == kDeviceStateIdle) {
Schedule([this]() {
if (!protocol_->IsAudioChannelOpened()) {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
return;
}
}
SetListeningMode(kListeningModeManualStop);
});
} else if (device_state_ == kDeviceStateSpeaking) {
Schedule([this]() {
AbortSpeaking(kAbortReasonNone);
SetListeningMode(kListeningModeManualStop);
});
}
}
void Application::StopListening() {
if (device_state_ == kDeviceStateAudioTesting) {
audio_service_.EnableAudioTesting(false);
SetDeviceState(kDeviceStateWifiConfiguring);
return;
}
const std::array<int, 3> valid_states = {
kDeviceStateListening,
kDeviceStateSpeaking,
kDeviceStateIdle,
};
// If not valid, do nothing
if (std::find(valid_states.begin(), valid_states.end(), device_state_) == valid_states.end()) {
return;
}
Schedule([this]() {
if (device_state_ == kDeviceStateListening) {
protocol_->SendStopListening();
SetDeviceState(kDeviceStateIdle);
}
});
}
void Application::Start() {
auto& board = Board::GetInstance();
SetDeviceState(kDeviceStateStarting);
/* Setup the display */
auto display = board.GetDisplay();
/* Setup the audio service */
auto codec = board.GetAudioCodec();
audio_service_.Initialize(codec);
audio_service_.Start();
AudioServiceCallbacks callbacks;
callbacks.on_send_queue_available = [this]() {
xEventGroupSetBits(event_group_, MAIN_EVENT_SEND_AUDIO);
};
callbacks.on_wake_word_detected = [this](const std::string& wake_word) {
xEventGroupSetBits(event_group_, MAIN_EVENT_WAKE_WORD_DETECTED);
};
callbacks.on_vad_change = [this](bool speaking) {
xEventGroupSetBits(event_group_, MAIN_EVENT_VAD_CHANGE);
};
audio_service_.SetCallbacks(callbacks);
/* Start the clock timer to update the status bar */
esp_timer_start_periodic(clock_timer_handle_, 1000000);
/* Wait for the network to be ready */
board.StartNetwork();
// Update the status bar immediately to show the network state
display->UpdateStatusBar(true);
// Check for new firmware version or get the MQTT broker address
Ota ota;
CheckNewVersion(ota);
// Initialize the protocol
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
// Add MCP common tools before initializing the protocol
McpServer::GetInstance().AddCommonTools();
if (ota.HasMqttConfig()) {
protocol_ = std::make_unique<MqttProtocol>();
} else if (ota.HasWebsocketConfig()) {
protocol_ = std::make_unique<WebsocketProtocol>();
} else {
ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT");
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);
});
protocol_->OnIncomingAudio([this](std::unique_ptr<AudioStreamPacket> packet) {
if (device_state_ == kDeviceStateSpeaking) {
audio_service_.PushPacketToDecodeQueue(std::move(packet));
}
});
protocol_->OnAudioChannelOpened([this, codec, &board]() {
board.SetPowerSaveMode(false);
if (protocol_->server_sample_rate() != codec->output_sample_rate()) {
ESP_LOGW(TAG, "Server sample rate %d does not match device output sample rate %d, resampling may cause distortion",
protocol_->server_sample_rate(), codec->output_sample_rate());
}
});
protocol_->OnAudioChannelClosed([this, &board]() {
board.SetPowerSaveMode(true);
Schedule([this]() {
auto display = Board::GetInstance().GetDisplay();
display->SetChatMessage("system", "");
SetDeviceState(kDeviceStateIdle);
});
});
protocol_->OnIncomingJson([this, display](const cJSON* root) {
// Parse JSON data
auto type = cJSON_GetObjectItem(root, "type");
if (strcmp(type->valuestring, "tts") == 0) {
auto state = cJSON_GetObjectItem(root, "state");
if (strcmp(state->valuestring, "start") == 0) {
Schedule([this]() {
aborted_ = false;
if (device_state_ == kDeviceStateIdle || device_state_ == kDeviceStateListening) {
SetDeviceState(kDeviceStateSpeaking);
}
});
} else if (strcmp(state->valuestring, "stop") == 0) {
Schedule([this]() {
if (device_state_ == kDeviceStateSpeaking) {
if (listening_mode_ == kListeningModeManualStop) {
SetDeviceState(kDeviceStateIdle);
} else {
SetDeviceState(kDeviceStateListening);
}
}
});
} else if (strcmp(state->valuestring, "sentence_start") == 0) {
auto text = cJSON_GetObjectItem(root, "text");
if (cJSON_IsString(text)) {
ESP_LOGI(TAG, "<< %s", text->valuestring);
Schedule([this, display, message = std::string(text->valuestring)]() {
display->SetChatMessage("assistant", message.c_str());
});
}
}
} else if (strcmp(type->valuestring, "stt") == 0) {
auto text = cJSON_GetObjectItem(root, "text");
if (cJSON_IsString(text)) {
ESP_LOGI(TAG, ">> %s", text->valuestring);
Schedule([this, display, message = std::string(text->valuestring)]() {
display->SetChatMessage("user", message.c_str());
});
}
} else if (strcmp(type->valuestring, "llm") == 0) {
auto emotion = cJSON_GetObjectItem(root, "emotion");
if (cJSON_IsString(emotion)) {
Schedule([this, display, emotion_str = std::string(emotion->valuestring)]() {
display->SetEmotion(emotion_str.c_str());
});
}
} else if (strcmp(type->valuestring, "mcp") == 0) {
auto payload = cJSON_GetObjectItem(root, "payload");
if (cJSON_IsObject(payload)) {
McpServer::GetInstance().ParseMessage(payload);
}
} else if (strcmp(type->valuestring, "system") == 0) {
auto command = cJSON_GetObjectItem(root, "command");
if (cJSON_IsString(command)) {
ESP_LOGI(TAG, "System command: %s", command->valuestring);
if (strcmp(command->valuestring, "reboot") == 0) {
// Do a reboot if user requests a OTA update
Schedule([this]() {
Reboot();
});
} else {
ESP_LOGW(TAG, "Unknown system command: %s", command->valuestring);
}
}
} else if (strcmp(type->valuestring, "alert") == 0) {
auto status = cJSON_GetObjectItem(root, "status");
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::OGG_VIBRATION);
} else {
ESP_LOGW(TAG, "Alert command requires status, message and emotion");
}
#if CONFIG_RECEIVE_CUSTOM_MESSAGE
} else if (strcmp(type->valuestring, "custom") == 0) {
auto payload = cJSON_GetObjectItem(root, "payload");
ESP_LOGI(TAG, "Received custom message: %s", cJSON_PrintUnformatted(root));
if (cJSON_IsObject(payload)) {
Schedule([this, display, payload_str = std::string(cJSON_PrintUnformatted(payload))]() {
display->SetChatMessage("system", payload_str.c_str());
});
} else {
ESP_LOGW(TAG, "Invalid custom message format: missing payload");
}
#endif
} else {
ESP_LOGW(TAG, "Unknown message type: %s", type->valuestring);
}
});
bool protocol_started = protocol_->Start();
SetDeviceState(kDeviceStateIdle);
has_server_time_ = ota.HasServerTime();
if (protocol_started) {
std::string message = std::string(Lang::Strings::VERSION) + ota.GetCurrentVersion();
display->ShowNotification(message.c_str());
display->SetChatMessage("system", "");
// Play the success sound to indicate the device is ready
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
}
// Print heap stats
SystemInfo::PrintHeapStats();
}
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();
}
}
// Add a async task to MainLoop
void Application::Schedule(std::function<void()> callback) {
{
std::lock_guard<std::mutex> lock(mutex_);
main_tasks_.push_back(std::move(callback));
}
xEventGroupSetBits(event_group_, MAIN_EVENT_SCHEDULE);
}
// The Main Event Loop controls the chat state and websocket connection
// 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_ERROR, pdTRUE, pdFALSE, portMAX_DELAY);
if (bits & MAIN_EVENT_ERROR) {
SetDeviceState(kDeviceStateIdle);
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))) {
break;
}
}
}
if (bits & MAIN_EVENT_WAKE_WORD_DETECTED) {
OnWakeWordDetected();
}
if (bits & MAIN_EVENT_VAD_CHANGE) {
if (device_state_ == kDeviceStateListening) {
auto led = Board::GetInstance().GetLed();
led->OnStateChanged();
}
}
if (bits & MAIN_EVENT_SCHEDULE) {
std::unique_lock<std::mutex> lock(mutex_);
auto tasks = std::move(main_tasks_);
lock.unlock();
for (auto& task : tasks) {
task();
}
}
}
}
void Application::OnWakeWordDetected() {
if (!protocol_) {
return;
}
if (device_state_ == kDeviceStateIdle) {
audio_service_.EncodeWakeWord();
if (!protocol_->IsAudioChannelOpened()) {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
audio_service_.EnableWakeWordDetection(true);
return;
}
}
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
// 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) {
AbortSpeaking(kAbortReasonWakeWordDetected);
} else if (device_state_ == kDeviceStateActivating) {
SetDeviceState(kDeviceStateIdle);
}
}
void Application::AbortSpeaking(AbortReason reason) {
ESP_LOGI(TAG, "Abort speaking");
aborted_ = true;
protocol_->SendAbortSpeaking(reason);
}
void Application::SetListeningMode(ListeningMode mode) {
listening_mode_ = mode;
SetDeviceState(kDeviceStateListening);
}
void Application::SetDeviceState(DeviceState state) {
if (device_state_ == state) {
return;
}
clock_ticks_ = 0;
auto previous_state = device_state_;
device_state_ = state;
ESP_LOGI(TAG, "STATE: %s", STATE_STRINGS[device_state_]);
// Send the state change event
DeviceStateEventManager::GetInstance().PostStateChangeEvent(previous_state, state);
auto& board = Board::GetInstance();
auto display = board.GetDisplay();
auto led = board.GetLed();
led->OnStateChanged();
// 当从idle状态变成其他任何状态时停止音乐播放
if (previous_state == kDeviceStateIdle && state != kDeviceStateIdle) {
auto music = board.GetMusic();
if (music) {
ESP_LOGI(TAG, "Stopping music streaming due to state change: %s -> %s",
STATE_STRINGS[previous_state], STATE_STRINGS[state]);
music->StopStreaming();
}
}
switch (state) {
case kDeviceStateUnknown:
case kDeviceStateIdle:
display->SetStatus(Lang::Strings::STANDBY);
display->SetEmotion("neutral");
audio_service_.EnableVoiceProcessing(false);
audio_service_.EnableWakeWordDetection(true);
break;
case kDeviceStateConnecting:
display->SetStatus(Lang::Strings::CONNECTING);
display->SetEmotion("neutral");
display->SetChatMessage("system", "");
break;
case kDeviceStateListening:
display->SetStatus(Lang::Strings::LISTENING);
display->SetEmotion("neutral");
// Make sure the audio processor is running
if (!audio_service_.IsAudioProcessorRunning()) {
// Send the start listening command
protocol_->SendStartListening(listening_mode_);
audio_service_.EnableVoiceProcessing(true);
audio_service_.EnableWakeWordDetection(false);
}
break;
case kDeviceStateSpeaking:
display->SetStatus(Lang::Strings::SPEAKING);
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_.ResetDecoder();
break;
default:
// Do nothing
break;
}
}
void Application::Reboot() {
ESP_LOGI(TAG, "Rebooting...");
esp_restart();
}
void Application::WakeWordInvoke(const std::string& wake_word) {
if (device_state_ == kDeviceStateIdle) {
ToggleChatState();
Schedule([this, wake_word]() {
if (protocol_) {
protocol_->SendWakeWordDetected(wake_word);
}
});
} else if (device_state_ == kDeviceStateSpeaking) {
Schedule([this]() {
AbortSpeaking(kAbortReasonNone);
});
} else if (device_state_ == kDeviceStateListening) {
Schedule([this]() {
if (protocol_) {
protocol_->CloseAudioChannel();
}
});
}
}
bool Application::CanEnterSleepMode() {
if (device_state_ != kDeviceStateIdle) {
return false;
}
if (protocol_ && protocol_->IsAudioChannelOpened()) {
return false;
}
if (!audio_service_.IsIdle()) {
return false;
}
// Now it is safe to enter sleep mode
return true;
}
void Application::SendMcpMessage(const std::string& payload) {
Schedule([this, payload]() {
if (protocol_) {
protocol_->SendMcpMessage(payload);
}
});
}
void Application::SetAecMode(AecMode mode) {
aec_mode_ = mode;
Schedule([this]() {
auto& board = Board::GetInstance();
auto display = board.GetDisplay();
switch (aec_mode_) {
case kAecOff:
audio_service_.EnableDeviceAec(false);
display->ShowNotification(Lang::Strings::RTC_MODE_OFF);
break;
case kAecOnServerSide:
audio_service_.EnableDeviceAec(false);
display->ShowNotification(Lang::Strings::RTC_MODE_ON);
break;
case kAecOnDeviceSide:
audio_service_.EnableDeviceAec(true);
display->ShowNotification(Lang::Strings::RTC_MODE_ON);
break;
}
// If the AEC mode is changed, close the audio channel
if (protocol_ && protocol_->IsAudioChannelOpened()) {
protocol_->CloseAudioChannel();
}
});
}
// 新增:接收外部音频数据(如音乐播放)
void Application::AddAudioData(AudioStreamPacket&& packet) {
auto codec = Board::GetInstance().GetAudioCodec();
if (device_state_ == kDeviceStateIdle && codec->output_enabled()) {
// packet.payload包含的是原始PCM数据int16_t
if (packet.payload.size() >= 2) {
size_t num_samples = packet.payload.size() / sizeof(int16_t);
std::vector<int16_t> pcm_data(num_samples);
memcpy(pcm_data.data(), packet.payload.data(), packet.payload.size());
// 检查采样率是否匹配,如果不匹配则进行简单重采样
if (packet.sample_rate != codec->output_sample_rate()) {
// ESP_LOGI(TAG, "Resampling music audio from %d to %d Hz",
// packet.sample_rate, codec->output_sample_rate());
// 验证采样率参数
if (packet.sample_rate <= 0 || codec->output_sample_rate() <= 0) {
ESP_LOGE(TAG, "Invalid sample rates: %d -> %d",
packet.sample_rate, codec->output_sample_rate());
return;
}
std::vector<int16_t> resampled;
if (packet.sample_rate > codec->output_sample_rate()) {
ESP_LOGI(TAG, "Music playback: Adjust the sampling rate from %d Hz switch to %d Hz",
codec->output_sample_rate(), packet.sample_rate);
// 尝试动态切换采样率
if (codec->SetOutputSampleRate(packet.sample_rate)) {
ESP_LOGI(TAG, "Successfully switched to music playback sampling rate: %d Hz", packet.sample_rate);
} else {
ESP_LOGW(TAG, "Unable to switch sampling rate, continue using current sampling rate: %d Hz", codec->output_sample_rate());
}
} else {
// 上采样:线性插值
float upsample_ratio = codec->output_sample_rate() / static_cast<float>(packet.sample_rate);
size_t expected_size = static_cast<size_t>(pcm_data.size() * upsample_ratio + 0.5f);
resampled.reserve(expected_size);
for (size_t i = 0; i < pcm_data.size(); ++i) {
// 添加原始样本
resampled.push_back(pcm_data[i]);
// 计算需要插值的样本数
int interpolation_count = static_cast<int>(upsample_ratio) - 1;
if (interpolation_count > 0 && i + 1 < pcm_data.size()) {
int16_t current = pcm_data[i];
int16_t next = pcm_data[i + 1];
for (int j = 1; j <= interpolation_count; ++j) {
float t = static_cast<float>(j) / (interpolation_count + 1);
int16_t interpolated = static_cast<int16_t>(current + (next - current) * t);
resampled.push_back(interpolated);
}
} else if (interpolation_count > 0) {
// 最后一个样本,直接重复
for (int j = 1; j <= interpolation_count; ++j) {
resampled.push_back(pcm_data[i]);
}
}
}
ESP_LOGI(TAG, "Upsampled %d -> %d samples (ratio: %.2f)",
pcm_data.size(), resampled.size(), upsample_ratio);
}
pcm_data = std::move(resampled);
}
// 确保音频输出已启用
if (!codec->output_enabled()) {
codec->EnableOutput(true);
}
// 发送PCM数据到音频编解码器
codec->OutputData(pcm_data);
audio_service_.UpdateOutputTimestamp();
}
}
}
void Application::PlaySound(const std::string_view& sound) {
audio_service_.PlaySound(sound);
}

93
main/application.h Normal file
View File

@@ -0,0 +1,93 @@
#ifndef _APPLICATION_H_
#define _APPLICATION_H_
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include <freertos/task.h>
#include <esp_timer.h>
#include <string>
#include <mutex>
#include <deque>
#include <memory>
#include "protocol.h"
#include "ota.h"
#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)
enum AecMode {
kAecOff,
kAecOnDeviceSide,
kAecOnServerSide,
};
class Application {
public:
static Application& GetInstance() {
static Application instance;
return instance;
}
// 删除拷贝构造函数和赋值运算符
Application(const Application&) = delete;
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);
void SetDeviceState(DeviceState state);
void Alert(const char* status, const char* message, const char* emotion = "", const std::string_view& sound = "");
void DismissAlert();
void AbortSpeaking(AbortReason reason);
void ToggleChatState();
void StartListening();
void StopListening();
void Reboot();
void WakeWordInvoke(const std::string& wake_word);
bool CanEnterSleepMode();
void SendMcpMessage(const std::string& payload);
void SetAecMode(AecMode mode);
AecMode GetAecMode() const { return aec_mode_; }
// 新增:接收外部音频数据(如音乐播放)
void AddAudioData(AudioStreamPacket&& packet);
void PlaySound(const std::string_view& sound);
AudioService& GetAudioService() { return audio_service_; }
private:
Application();
~Application();
std::mutex mutex_;
std::deque<std::function<void()>> main_tasks_;
std::unique_ptr<Protocol> protocol_;
EventGroupHandle_t event_group_ = nullptr;
esp_timer_handle_t clock_timer_handle_ = nullptr;
volatile DeviceState device_state_ = kDeviceStateUnknown;
ListeningMode listening_mode_ = kListeningModeAutoStop;
AecMode aec_mode_ = kAecOff;
std::string last_error_message_;
AudioService audio_service_;
bool has_server_time_ = false;
bool aborted_ = false;
int clock_ticks_ = 0;
TaskHandle_t check_new_version_task_handle_ = nullptr;
void OnWakeWordDetected();
void CheckNewVersion(Ota& ota);
void ShowActivationCode(const std::string& code, const std::string& message);
void OnClockTimer();
void SetListeningMode(ListeningMode mode);
};
#endif // _APPLICATION_H_

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

213
main/assets/lang_config.h Normal file
View File

@@ -0,0 +1,213 @@
// Auto-generated language config
// Language: zh-CN with en-US fallback
#pragma once
#include <string_view>
#ifndef zh_cn
#define zh_cn // 預設語言
#endif
namespace Lang {
// 语言元数据
constexpr const char* CODE = "zh-CN";
// 字符串资源 (en-US as fallback for missing keys)
namespace Strings {
constexpr const char* ACCESS_VIA_BROWSER = ",浏览器访问 ";
constexpr const char* ACTIVATION = "激活设备";
constexpr const char* BATTERY_CHARGING = "正在充电";
constexpr const char* BATTERY_FULL = "电量已满";
constexpr const char* BATTERY_LOW = "电量不足";
constexpr const char* BATTERY_NEED_CHARGE = "电量低,请充电";
constexpr const char* CHECKING_NEW_VERSION = "检查新版本...";
constexpr const char* CHECK_NEW_VERSION_FAILED = "检查新版本失败,将在 %d 秒后重试:%s";
constexpr const char* CONNECTED_TO = "已连接 ";
constexpr const char* CONNECTING = "连接中...";
constexpr const char* CONNECTION_SUCCESSFUL = "Connection Successful";
constexpr const char* CONNECT_TO = "连接 ";
constexpr const char* CONNECT_TO_HOTSPOT = "手机连接热点 ";
constexpr const char* DETECTING_MODULE = "检测模组...";
constexpr const char* ENTERING_WIFI_CONFIG_MODE = "进入配网模式...";
constexpr const char* ERROR = "错误";
constexpr const char* INFO = "信息";
constexpr const char* INITIALIZING = "正在初始化...";
constexpr const char* LISTENING = "聆听中...";
constexpr const char* LOADING_PROTOCOL = "登录服务器...";
constexpr const char* MAX_VOLUME = "最大音量";
constexpr const char* MUTED = "已静音";
constexpr const char* NEW_VERSION = "新版本 ";
constexpr const char* OTA_UPGRADE = "OTA 升级";
constexpr const char* PIN_ERROR = "请插入 SIM 卡";
constexpr const char* REGISTERING_NETWORK = "等待网络...";
constexpr const char* REG_ERROR = "无法接入网络,请检查流量卡状态";
constexpr const char* RTC_MODE_OFF = "AEC 关闭";
constexpr const char* RTC_MODE_ON = "AEC 开启";
constexpr const char* SCANNING_WIFI = "扫描 Wi-Fi...";
constexpr const char* SERVER_ERROR = "发送失败,请检查网络";
constexpr const char* SERVER_NOT_CONNECTED = "无法连接服务,请稍后再试";
constexpr const char* SERVER_NOT_FOUND = "正在寻找可用服务";
constexpr const char* SERVER_TIMEOUT = "等待响应超时";
constexpr const char* SPEAKING = "说话中...";
constexpr const char* STANDBY = "待命";
constexpr const char* SWITCH_TO_4G_NETWORK = "切换到 4G...";
constexpr const char* SWITCH_TO_WIFI_NETWORK = "切换到 Wi-Fi...";
constexpr const char* UPGRADE_FAILED = "升级失败";
constexpr const char* UPGRADING = "正在升级系统...";
constexpr const char* VERSION = "版本 ";
constexpr const char* VOLUME = "音量 ";
constexpr const char* WARNING = "警告";
constexpr const char* WIFI_CONFIG_MODE = "配网模式";
}
// 音效资源 (en-US as fallback for missing audio files)
namespace Sounds {
extern const char ogg_0_start[] asm("_binary_0_ogg_start");
extern const char ogg_0_end[] asm("_binary_0_ogg_end");
static const std::string_view OGG_0 {
static_cast<const char*>(ogg_0_start),
static_cast<size_t>(ogg_0_end - ogg_0_start)
};
extern const char ogg_1_start[] asm("_binary_1_ogg_start");
extern const char ogg_1_end[] asm("_binary_1_ogg_end");
static const std::string_view OGG_1 {
static_cast<const char*>(ogg_1_start),
static_cast<size_t>(ogg_1_end - ogg_1_start)
};
extern const char ogg_2_start[] asm("_binary_2_ogg_start");
extern const char ogg_2_end[] asm("_binary_2_ogg_end");
static const std::string_view OGG_2 {
static_cast<const char*>(ogg_2_start),
static_cast<size_t>(ogg_2_end - ogg_2_start)
};
extern const char ogg_3_start[] asm("_binary_3_ogg_start");
extern const char ogg_3_end[] asm("_binary_3_ogg_end");
static const std::string_view OGG_3 {
static_cast<const char*>(ogg_3_start),
static_cast<size_t>(ogg_3_end - ogg_3_start)
};
extern const char ogg_4_start[] asm("_binary_4_ogg_start");
extern const char ogg_4_end[] asm("_binary_4_ogg_end");
static const std::string_view OGG_4 {
static_cast<const char*>(ogg_4_start),
static_cast<size_t>(ogg_4_end - ogg_4_start)
};
extern const char ogg_5_start[] asm("_binary_5_ogg_start");
extern const char ogg_5_end[] asm("_binary_5_ogg_end");
static const std::string_view OGG_5 {
static_cast<const char*>(ogg_5_start),
static_cast<size_t>(ogg_5_end - ogg_5_start)
};
extern const char ogg_6_start[] asm("_binary_6_ogg_start");
extern const char ogg_6_end[] asm("_binary_6_ogg_end");
static const std::string_view OGG_6 {
static_cast<const char*>(ogg_6_start),
static_cast<size_t>(ogg_6_end - ogg_6_start)
};
extern const char ogg_7_start[] asm("_binary_7_ogg_start");
extern const char ogg_7_end[] asm("_binary_7_ogg_end");
static const std::string_view OGG_7 {
static_cast<const char*>(ogg_7_start),
static_cast<size_t>(ogg_7_end - ogg_7_start)
};
extern const char ogg_8_start[] asm("_binary_8_ogg_start");
extern const char ogg_8_end[] asm("_binary_8_ogg_end");
static const std::string_view OGG_8 {
static_cast<const char*>(ogg_8_start),
static_cast<size_t>(ogg_8_end - ogg_8_start)
};
extern const char ogg_9_start[] asm("_binary_9_ogg_start");
extern const char ogg_9_end[] asm("_binary_9_ogg_end");
static const std::string_view OGG_9 {
static_cast<const char*>(ogg_9_start),
static_cast<size_t>(ogg_9_end - ogg_9_start)
};
extern const char ogg_activation_start[] asm("_binary_activation_ogg_start");
extern const char ogg_activation_end[] asm("_binary_activation_ogg_end");
static const std::string_view OGG_ACTIVATION {
static_cast<const char*>(ogg_activation_start),
static_cast<size_t>(ogg_activation_end - ogg_activation_start)
};
extern const char ogg_err_pin_start[] asm("_binary_err_pin_ogg_start");
extern const char ogg_err_pin_end[] asm("_binary_err_pin_ogg_end");
static const std::string_view OGG_ERR_PIN {
static_cast<const char*>(ogg_err_pin_start),
static_cast<size_t>(ogg_err_pin_end - ogg_err_pin_start)
};
extern const char ogg_err_reg_start[] asm("_binary_err_reg_ogg_start");
extern const char ogg_err_reg_end[] asm("_binary_err_reg_ogg_end");
static const std::string_view OGG_ERR_REG {
static_cast<const char*>(ogg_err_reg_start),
static_cast<size_t>(ogg_err_reg_end - ogg_err_reg_start)
};
extern const char ogg_exclamation_start[] asm("_binary_exclamation_ogg_start");
extern const char ogg_exclamation_end[] asm("_binary_exclamation_ogg_end");
static const std::string_view OGG_EXCLAMATION {
static_cast<const char*>(ogg_exclamation_start),
static_cast<size_t>(ogg_exclamation_end - ogg_exclamation_start)
};
extern const char ogg_low_battery_start[] asm("_binary_low_battery_ogg_start");
extern const char ogg_low_battery_end[] asm("_binary_low_battery_ogg_end");
static const std::string_view OGG_LOW_BATTERY {
static_cast<const char*>(ogg_low_battery_start),
static_cast<size_t>(ogg_low_battery_end - ogg_low_battery_start)
};
extern const char ogg_popup_start[] asm("_binary_popup_ogg_start");
extern const char ogg_popup_end[] asm("_binary_popup_ogg_end");
static const std::string_view OGG_POPUP {
static_cast<const char*>(ogg_popup_start),
static_cast<size_t>(ogg_popup_end - ogg_popup_start)
};
extern const char ogg_success_start[] asm("_binary_success_ogg_start");
extern const char ogg_success_end[] asm("_binary_success_ogg_end");
static const std::string_view OGG_SUCCESS {
static_cast<const char*>(ogg_success_start),
static_cast<size_t>(ogg_success_end - ogg_success_start)
};
extern const char ogg_upgrade_start[] asm("_binary_upgrade_ogg_start");
extern const char ogg_upgrade_end[] asm("_binary_upgrade_ogg_end");
static const std::string_view OGG_UPGRADE {
static_cast<const char*>(ogg_upgrade_start),
static_cast<size_t>(ogg_upgrade_end - ogg_upgrade_start)
};
extern const char ogg_vibration_start[] asm("_binary_vibration_ogg_start");
extern const char ogg_vibration_end[] asm("_binary_vibration_ogg_end");
static const std::string_view OGG_VIBRATION {
static_cast<const char*>(ogg_vibration_start),
static_cast<size_t>(ogg_vibration_end - ogg_vibration_start)
};
extern const char ogg_welcome_start[] asm("_binary_welcome_ogg_start");
extern const char ogg_welcome_end[] asm("_binary_welcome_ogg_end");
static const std::string_view OGG_WELCOME {
static_cast<const char*>(ogg_welcome_start),
static_cast<size_t>(ogg_welcome_end - ogg_welcome_start)
};
extern const char ogg_wificonfig_start[] asm("_binary_wificonfig_ogg_start");
extern const char ogg_wificonfig_end[] asm("_binary_wificonfig_ogg_end");
static const std::string_view OGG_WIFICONFIG {
static_cast<const char*>(ogg_wificonfig_start),
static_cast<size_t>(ogg_wificonfig_end - ogg_wificonfig_start)
};
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
{
"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 مُشغل"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
{
"language": {
"type" :"de-DE"
},
"strings": {
"WARNING":"Warnung",
"INFO":"Information",
"ERROR":"Fehler",
"VERSION": "Version ",
"LOADING_PROTOCOL":"Verbindung zum Server...",
"INITIALIZING":"Initialisierung...",
"PIN_ERROR":"Bitte SIM-Karte einlegen",
"REG_ERROR":"Netzwerkverbindung fehlgeschlagen, bitte Datenkartenstatus prüfen",
"DETECTING_MODULE":"Modul erkennen...",
"REGISTERING_NETWORK":"Auf Netzwerk warten...",
"CHECKING_NEW_VERSION":"Neue Version prüfen...",
"CHECK_NEW_VERSION_FAILED":"Neue Version prüfen fehlgeschlagen, Wiederholung in %d Sekunden: %s",
"SWITCH_TO_WIFI_NETWORK":"Zu Wi-Fi wechseln...",
"SWITCH_TO_4G_NETWORK":"Zu 4G wechseln...",
"STANDBY":"Bereitschaft",
"CONNECT_TO":"Verbinden zu ",
"CONNECTING":"Verbindung wird hergestellt...",
"CONNECTED_TO":"Verbunden mit ",
"LISTENING":"Zuhören...",
"SPEAKING":"Sprechen...",
"SERVER_NOT_FOUND":"Verfügbaren Service suchen",
"SERVER_NOT_CONNECTED":"Service-Verbindung fehlgeschlagen, bitte später versuchen",
"SERVER_TIMEOUT":"Antwort-Timeout",
"SERVER_ERROR":"Senden fehlgeschlagen, bitte Netzwerk prüfen",
"CONNECT_TO_HOTSPOT":"Handy mit Hotspot verbinden ",
"ACCESS_VIA_BROWSER":"Browser öffnen ",
"WIFI_CONFIG_MODE":"Netzwerkkonfigurationsmodus",
"ENTERING_WIFI_CONFIG_MODE":"Netzwerkkonfigurationsmodus eingeben...",
"SCANNING_WIFI":"Wi-Fi scannen...",
"NEW_VERSION": "Neue Version ",
"OTA_UPGRADE":"OTA-Upgrade",
"UPGRADING":"System wird aktualisiert...",
"UPGRADE_FAILED":"Upgrade fehlgeschlagen",
"ACTIVATION":"Gerät aktivieren",
"BATTERY_LOW":"Niedriger Batteriestand",
"BATTERY_CHARGING":"Wird geladen",
"BATTERY_FULL":"Batterie voll",
"BATTERY_NEED_CHARGE":"Niedriger Batteriestand, bitte aufladen",
"VOLUME":"Lautstärke ",
"MUTED":"Stummgeschaltet",
"MAX_VOLUME":"Maximale Lautstärke",
"RTC_MODE_OFF":"AEC aus",
"RTC_MODE_ON":"AEC ein"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,59 @@
{
"language": {
"type": "en-US"
},
"strings": {
"WARNING": "Warning",
"INFO": "Information",
"ERROR": "Error",
"VERSION": "Ver ",
"LOADING_PROTOCOL": "Logging in...",
"INITIALIZING": "Initializing...",
"PIN_ERROR": "Please insert SIM card",
"REG_ERROR": "Unable to access network, please check SIM card status",
"DETECTING_MODULE": "Detecting module...",
"REGISTERING_NETWORK": "Waiting for network...",
"CHECKING_NEW_VERSION": "Checking for new version...",
"CHECK_NEW_VERSION_FAILED": "Check for new version failed, will retry in %d seconds: %s",
"SWITCH_TO_WIFI_NETWORK": "Switching to Wi-Fi...",
"SWITCH_TO_4G_NETWORK": "Switching to 4G...",
"STANDBY": "Standby",
"CONNECT_TO": "Connect to ",
"CONNECTING": "Connecting...",
"CONNECTION_SUCCESSFUL": "Connection Successful",
"CONNECTED_TO": "Connected to ",
"LISTENING": "Listening...",
"SPEAKING": "Speaking...",
"SERVER_NOT_FOUND": "Looking for available service",
"SERVER_NOT_CONNECTED": "Unable to connect to service, please try again later",
"SERVER_TIMEOUT": "Waiting for response timeout",
"SERVER_ERROR": "Sending failed, please check the network",
"CONNECT_TO_HOTSPOT": "Hotspot: ",
"ACCESS_VIA_BROWSER": " Config URL: ",
"WIFI_CONFIG_MODE": "Wi-Fi Configuration Mode",
"ENTERING_WIFI_CONFIG_MODE": "Entering Wi-Fi configuration mode...",
"SCANNING_WIFI": "Scanning Wi-Fi...",
"NEW_VERSION": "New version ",
"OTA_UPGRADE": "OTA Upgrade",
"UPGRADING": "System is upgrading...",
"UPGRADE_FAILED": "Upgrade failed",
"ACTIVATION": "Activation",
"BATTERY_LOW": "Low battery",
"BATTERY_CHARGING": "Charging",
"BATTERY_FULL": "Battery full",
"BATTERY_NEED_CHARGE": "Low battery, please charge",
"VOLUME": "Volume ",
"MUTED": "Muted",
"MAX_VOLUME": "Max volume",
"RTC_MODE_OFF": "AEC Off",
"RTC_MODE_ON": "AEC On"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
{
"language": {
"type" :"es-ES"
},
"strings": {
"WARNING":"Advertencia",
"INFO":"Información",
"ERROR":"Error",
"VERSION": "Versión ",
"LOADING_PROTOCOL":"Conectando al servidor...",
"INITIALIZING":"Inicializando...",
"PIN_ERROR":"Por favor inserte la tarjeta SIM",
"REG_ERROR":"No se puede acceder a la red, verifique el estado de la tarjeta de datos",
"DETECTING_MODULE":"Detectando módulo...",
"REGISTERING_NETWORK":"Esperando red...",
"CHECKING_NEW_VERSION":"Verificando nueva versión...",
"CHECK_NEW_VERSION_FAILED":"Error al verificar nueva versión, reintentando en %d segundos: %s",
"SWITCH_TO_WIFI_NETWORK":"Cambiando a Wi-Fi...",
"SWITCH_TO_4G_NETWORK":"Cambiando a 4G...",
"STANDBY":"En espera",
"CONNECT_TO":"Conectar a ",
"CONNECTING":"Conectando...",
"CONNECTED_TO":"Conectado a ",
"LISTENING":"Escuchando...",
"SPEAKING":"Hablando...",
"SERVER_NOT_FOUND":"Buscando servicio disponible",
"SERVER_NOT_CONNECTED":"No se puede conectar al servicio, inténtelo más tarde",
"SERVER_TIMEOUT":"Tiempo de espera agotado",
"SERVER_ERROR":"Error de envío, verifique la red",
"CONNECT_TO_HOTSPOT":"Conectar teléfono al punto de acceso ",
"ACCESS_VIA_BROWSER":"acceder mediante navegador ",
"WIFI_CONFIG_MODE":"Modo configuración de red",
"ENTERING_WIFI_CONFIG_MODE":"Entrando en modo configuración de red...",
"SCANNING_WIFI":"Escaneando Wi-Fi...",
"NEW_VERSION": "Nueva versión ",
"OTA_UPGRADE":"Actualización OTA",
"UPGRADING":"Actualizando sistema...",
"UPGRADE_FAILED":"Actualización fallida",
"ACTIVATION":"Activación del dispositivo",
"BATTERY_LOW":"Batería baja",
"BATTERY_CHARGING":"Cargando",
"BATTERY_FULL":"Batería llena",
"BATTERY_NEED_CHARGE":"Batería baja, por favor cargar",
"VOLUME":"Volumen ",
"MUTED":"Silenciado",
"MAX_VOLUME":"Volumen máximo",
"RTC_MODE_OFF":"AEC desactivado",
"RTC_MODE_ON":"AEC activado"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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