Add English system sounds
This commit is contained in:
+12
-13
@@ -115,6 +115,18 @@ if(CONFIG_USE_AUDIO_PROCESSING)
|
||||
list(APPEND SOURCES "audio_processing/audio_processor.cc" "audio_processing/wake_word_detect.cc")
|
||||
endif()
|
||||
|
||||
# 根据Kconfig选择语言目录
|
||||
if(CONFIG_LANGUAGE_ZH_CN)
|
||||
set(LANG_DIR "zh-CN")
|
||||
elseif(CONFIG_LANGUAGE_EN_US)
|
||||
set(LANG_DIR "en-US")
|
||||
endif()
|
||||
|
||||
# 定义生成路径
|
||||
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
|
||||
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
|
||||
file(GLOB ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/*.p3)
|
||||
|
||||
# 如果目标芯片是 ESP32,则排除特定文件
|
||||
if(CONFIG_IDF_TARGET_ESP32)
|
||||
# 排除 "audio_codecs/box_audio_codec.cc" 和 "audio_codecs/cores3_audio_codec.cc"
|
||||
@@ -123,8 +135,6 @@ if(CONFIG_IDF_TARGET_ESP32)
|
||||
"audio_codecs/es8388_audio_codec.cc")
|
||||
endif()
|
||||
|
||||
file(GLOB ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets/zh/*.p3)
|
||||
|
||||
idf_component_register(SRCS ${SOURCES}
|
||||
EMBED_FILES ${ASSETS}
|
||||
INCLUDE_DIRS ${INCLUDE_DIRS}
|
||||
@@ -136,17 +146,6 @@ target_compile_definitions(${COMPONENT_LIB}
|
||||
PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\"
|
||||
)
|
||||
|
||||
# 根据Kconfig选择语言目录
|
||||
if(CONFIG_LANGUAGE_ZH)
|
||||
set(LANG_DIR "zh")
|
||||
elseif(CONFIG_LANGUAGE_EN)
|
||||
set(LANG_DIR "en-US")
|
||||
endif()
|
||||
|
||||
# 定义生成路径
|
||||
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
|
||||
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
|
||||
|
||||
# 添加生成规则
|
||||
add_custom_command(
|
||||
OUTPUT ${LANG_HEADER}
|
||||
|
||||
@@ -9,13 +9,13 @@ config OTA_VERSION_URL
|
||||
|
||||
choice
|
||||
prompt "语言选择"
|
||||
default LANGUAGE_ZH
|
||||
default LANGUAGE_ZH_CN
|
||||
help
|
||||
Select device display language
|
||||
|
||||
config LANGUAGE_ZH
|
||||
config LANGUAGE_ZH_CN
|
||||
bool "Chinese"
|
||||
config LANGUAGE_EN
|
||||
config LANGUAGE_EN_US
|
||||
bool "English"
|
||||
endchoice
|
||||
|
||||
|
||||
+38
-37
@@ -1,7 +1,6 @@
|
||||
#include "application.h"
|
||||
#include "board.h"
|
||||
#include "display.h"
|
||||
#include "ssd1306_display.h"
|
||||
#include "system_info.h"
|
||||
#include "ml307_ssl_transport.h"
|
||||
#include "audio_codec.h"
|
||||
@@ -9,7 +8,6 @@
|
||||
#include "websocket_protocol.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "assets/zh/binary.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <cstring>
|
||||
@@ -60,17 +58,17 @@ void Application::CheckNewVersion() {
|
||||
if (!ota_.CheckVersion()) {
|
||||
retry_count++;
|
||||
if (retry_count >= MAX_RETRY) {
|
||||
ESP_LOGE(TAG, "版本检查失败次数过多,退出检查");
|
||||
ESP_LOGE(TAG, "Too many retries, exit version check");
|
||||
return;
|
||||
}
|
||||
ESP_LOGW(TAG, "版本检查失败,%d秒后重试 (%d/%d)", 60, retry_count, MAX_RETRY);
|
||||
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", 60, retry_count, MAX_RETRY);
|
||||
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||
continue;
|
||||
}
|
||||
retry_count = 0;
|
||||
|
||||
if (ota_.HasNewVersion()) {
|
||||
Alert("OTA 升级", "正在升级系统", "happy", std::string_view(p3_upgrade_start, p3_upgrade_end - p3_upgrade_start));
|
||||
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE);
|
||||
// Wait for the chat state to be idle
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
@@ -81,7 +79,8 @@ void Application::CheckNewVersion() {
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
display->SetChatMessage("system", "新版本 " + ota_.GetFirmwareVersion());
|
||||
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota_.GetFirmwareVersion();
|
||||
display->SetChatMessage("system", message.c_str());
|
||||
|
||||
auto& board = Board::GetInstance();
|
||||
board.SetPowerSaveMode(false);
|
||||
@@ -108,7 +107,7 @@ void Application::CheckNewVersion() {
|
||||
});
|
||||
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
display->SetStatus("更新失败");
|
||||
display->SetStatus(Lang::Strings::UPGRADE_FAILED);
|
||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
Reboot();
|
||||
@@ -119,7 +118,8 @@ void Application::CheckNewVersion() {
|
||||
|
||||
// No new version, mark the current version as valid
|
||||
ota_.MarkCurrentVersionValid();
|
||||
display->ShowNotification(Lang::Strings::VERSION + " " + ota_.GetCurrentVersion());
|
||||
std::string message = std::string(Lang::Strings::VERSION) + ota_.GetCurrentVersion();
|
||||
display->ShowNotification(message.c_str());
|
||||
|
||||
if (ota_.HasActivationCode()) {
|
||||
// Activation code is valid
|
||||
@@ -144,24 +144,23 @@ void Application::ShowActivationCode() {
|
||||
|
||||
struct digit_sound {
|
||||
char digit;
|
||||
const char* data;
|
||||
size_t size;
|
||||
const std::string_view& sound;
|
||||
};
|
||||
static const std::array<digit_sound, 10> digit_sounds{{
|
||||
digit_sound{'0', p3_0_start, size_t(p3_0_end - p3_0_start)},
|
||||
digit_sound{'1', p3_1_start, size_t(p3_1_end - p3_1_start)},
|
||||
digit_sound{'2', p3_2_start, size_t(p3_2_end - p3_2_start)},
|
||||
digit_sound{'3', p3_3_start, size_t(p3_3_end - p3_3_start)},
|
||||
digit_sound{'4', p3_4_start, size_t(p3_4_end - p3_4_start)},
|
||||
digit_sound{'5', p3_5_start, size_t(p3_5_end - p3_5_start)},
|
||||
digit_sound{'6', p3_6_start, size_t(p3_6_end - p3_6_start)},
|
||||
digit_sound{'7', p3_7_start, size_t(p3_7_end - p3_7_start)},
|
||||
digit_sound{'8', p3_8_start, size_t(p3_8_end - p3_8_start)},
|
||||
digit_sound{'9', p3_9_start, size_t(p3_9_end - p3_9_start)}
|
||||
digit_sound{'0', Lang::Sounds::P3_0},
|
||||
digit_sound{'1', Lang::Sounds::P3_1},
|
||||
digit_sound{'2', Lang::Sounds::P3_2},
|
||||
digit_sound{'3', Lang::Sounds::P3_3},
|
||||
digit_sound{'4', Lang::Sounds::P3_4},
|
||||
digit_sound{'5', Lang::Sounds::P3_5},
|
||||
digit_sound{'6', Lang::Sounds::P3_6},
|
||||
digit_sound{'7', Lang::Sounds::P3_7},
|
||||
digit_sound{'8', Lang::Sounds::P3_8},
|
||||
digit_sound{'9', Lang::Sounds::P3_9}
|
||||
}};
|
||||
|
||||
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
|
||||
Alert("激活设备", message, "happy", std::string_view(p3_activation_start, p3_activation_end - p3_activation_start));
|
||||
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::P3_ACTIVATION);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
background_task_->WaitForCompletion();
|
||||
|
||||
@@ -169,13 +168,13 @@ void Application::ShowActivationCode() {
|
||||
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()) {
|
||||
PlayLocalFile(it->data, it->size);
|
||||
PlayLocalFile(it->sound.data(), it->sound.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::Alert(const std::string& status, const std::string& message, const std::string& emotion, const std::string_view& sound) {
|
||||
ESP_LOGW(TAG, "Alert %s: %s [%s]", status.c_str(), message.c_str(), emotion.c_str());
|
||||
void Application::Alert(const char* status, const char* message, const char* emotion, const std::string_view& sound) {
|
||||
ESP_LOGW(TAG, "Alert %s: %s [%s]", status, message, emotion);
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetStatus(status);
|
||||
display->SetEmotion(emotion);
|
||||
@@ -220,7 +219,7 @@ void Application::ToggleChatState() {
|
||||
if (device_state_ == kDeviceStateIdle) {
|
||||
SetDeviceState(kDeviceStateConnecting);
|
||||
if (!protocol_->OpenAudioChannel()) {
|
||||
Alert("ERROR", Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
||||
Alert(Lang::Strings::ERROR, Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
return;
|
||||
}
|
||||
@@ -254,7 +253,7 @@ void Application::StartListening() {
|
||||
SetDeviceState(kDeviceStateConnecting);
|
||||
if (!protocol_->OpenAudioChannel()) {
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
Alert("ERROR", Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
||||
Alert(Lang::Strings::ERROR, Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -328,14 +327,14 @@ void Application::Start() {
|
||||
board.StartNetwork();
|
||||
|
||||
// Initialize the protocol
|
||||
display->SetStatus(Lang::Strings::LOADING_PROTOCOL + "...");
|
||||
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
||||
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
|
||||
protocol_ = std::make_unique<WebsocketProtocol>();
|
||||
#else
|
||||
protocol_ = std::make_unique<MqttProtocol>();
|
||||
#endif
|
||||
protocol_->OnNetworkError([this](const std::string& message) {
|
||||
Alert("ERROR", message, "sad");
|
||||
Alert(Lang::Strings::ERROR, message.c_str(), "sad");
|
||||
});
|
||||
protocol_->OnIncomingAudio([this](std::vector<uint8_t>&& data) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@@ -346,11 +345,11 @@ void Application::Start() {
|
||||
protocol_->OnAudioChannelOpened([this, codec, &board]() {
|
||||
board.SetPowerSaveMode(false);
|
||||
if (protocol_->server_sample_rate() != codec->output_sample_rate()) {
|
||||
ESP_LOGW(TAG, "服务器的音频采样率 %d 与设备输出的采样率 %d 不一致,重采样后可能会失真",
|
||||
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());
|
||||
}
|
||||
SetDecodeSampleRate(protocol_->server_sample_rate());
|
||||
// 物联网设备描述符
|
||||
// IoT device descriptors
|
||||
last_iot_states_.clear();
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
protocol_->SendIotDescriptors(thing_manager.GetDescriptorsJson());
|
||||
@@ -392,7 +391,7 @@ void Application::Start() {
|
||||
if (text != NULL) {
|
||||
ESP_LOGI(TAG, "<< %s", text->valuestring);
|
||||
Schedule([this, display, message = std::string(text->valuestring)]() {
|
||||
display->SetChatMessage("assistant", message);
|
||||
display->SetChatMessage("assistant", message.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -401,14 +400,14 @@ void Application::Start() {
|
||||
if (text != NULL) {
|
||||
ESP_LOGI(TAG, ">> %s", text->valuestring);
|
||||
Schedule([this, display, message = std::string(text->valuestring)]() {
|
||||
display->SetChatMessage("user", message);
|
||||
display->SetChatMessage("user", message.c_str());
|
||||
});
|
||||
}
|
||||
} else if (strcmp(type->valuestring, "llm") == 0) {
|
||||
auto emotion = cJSON_GetObjectItem(root, "emotion");
|
||||
if (emotion != NULL) {
|
||||
Schedule([this, display, emotion_str = std::string(emotion->valuestring)]() {
|
||||
display->SetEmotion(emotion_str);
|
||||
display->SetEmotion(emotion_str.c_str());
|
||||
});
|
||||
}
|
||||
} else if (strcmp(type->valuestring, "iot") == 0) {
|
||||
@@ -428,6 +427,8 @@ void Application::Start() {
|
||||
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
|
||||
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
||||
ota_.SetHeader("Client-Id", board.GetUuid());
|
||||
ota_.SetHeader("X-Language", Lang::CODE);
|
||||
|
||||
xTaskCreate([](void* arg) {
|
||||
Application* app = (Application*)arg;
|
||||
app->CheckNewVersion();
|
||||
@@ -664,18 +665,18 @@ void Application::SetDeviceState(DeviceState state) {
|
||||
switch (state) {
|
||||
case kDeviceStateUnknown:
|
||||
case kDeviceStateIdle:
|
||||
display->SetStatus(Lang::Strings::STANDING_BY);
|
||||
display->SetStatus(Lang::Strings::STANDBY);
|
||||
display->SetEmotion("neutral");
|
||||
#ifdef CONFIG_USE_AUDIO_PROCESSING
|
||||
audio_processor_.Stop();
|
||||
#endif
|
||||
break;
|
||||
case kDeviceStateConnecting:
|
||||
display->SetStatus(Lang::Strings::CONNECTING+"...");
|
||||
display->SetStatus(Lang::Strings::CONNECTING);
|
||||
display->SetChatMessage("system", "");
|
||||
break;
|
||||
case kDeviceStateListening:
|
||||
display->SetStatus(Lang::Strings::LISTENING+"...");
|
||||
display->SetStatus(Lang::Strings::LISTENING);
|
||||
display->SetEmotion("neutral");
|
||||
ResetDecoder();
|
||||
opus_encoder_->ResetState();
|
||||
@@ -685,7 +686,7 @@ void Application::SetDeviceState(DeviceState state) {
|
||||
UpdateIotStates();
|
||||
break;
|
||||
case kDeviceStateSpeaking:
|
||||
display->SetStatus(Lang::Strings::SPEAKING+"...");
|
||||
display->SetStatus(Lang::Strings::SPEAKING);
|
||||
ResetDecoder();
|
||||
codec->EnableOutput(true);
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ public:
|
||||
bool IsVoiceDetected() const { return voice_detected_; }
|
||||
void Schedule(std::function<void()> callback);
|
||||
void SetDeviceState(DeviceState state);
|
||||
void Alert(const std::string& status, const std::string& message, const std::string& emotion = "", const std::string_view& sound = "");
|
||||
void Alert(const char* status, const char* message, const char* emotion = "", const std::string_view& sound = "");
|
||||
void AbortSpeaking(AbortReason reason);
|
||||
void ToggleChatState();
|
||||
void StartListening();
|
||||
|
||||
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.
@@ -3,32 +3,42 @@
|
||||
"type": "en"
|
||||
},
|
||||
"strings": {
|
||||
"VERSION": "Version",
|
||||
"LOADING_PROTOCOL":"Loading Protocol",
|
||||
"INITIALIZING":"Initializing",
|
||||
"NOTICE":"Notice",
|
||||
"VERSION": "Ver ",
|
||||
"LOADING_PROTOCOL": "Loading Protocol...",
|
||||
"INITIALIZING": "Initializing...",
|
||||
"DETECTING_MODULE": "Detecting module...",
|
||||
"REGISTERING_NETWORK": "Waiting for network...",
|
||||
|
||||
"STANDING_BY":"Standing By",
|
||||
"CONNECT":"Connect",
|
||||
"CONNECTING":"Connecting",
|
||||
"ERROR": "Error",
|
||||
"PIN_ERROR": "Please insert SIM card",
|
||||
"REG_ERROR": "Unable to access network, please check SIM card status",
|
||||
|
||||
"STANDBY": "Standby",
|
||||
"CONNECT_TO": "Connect to ",
|
||||
"CONNECTING": "Connecting...",
|
||||
"CONNECTION_SUCCESSFUL": "Connection Successful",
|
||||
"CONNECTED_TO": "Connected to ",
|
||||
|
||||
"LISTENING":"Listening",
|
||||
"SPEAKING":"Speaking",
|
||||
"LISTENING": "Listening...",
|
||||
"SPEAKING": "Speaking...",
|
||||
|
||||
"UNABLE_TO_CONNECT_TO_SERVICE": "Unable to connect to service",
|
||||
"WAITING_FOR_RESPONSE_TIMEOUT": "Waiting for response timeout",
|
||||
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK": "Sending failed, please check the network",
|
||||
|
||||
|
||||
|
||||
"CONNECT_MOBILE_PHONE_TO_HOTSPOT":"Connect mobile phone to hotspot",
|
||||
"ACCESS_VIA_BROWSER":"Access via browser",
|
||||
"WIFI_CONFIGURATION_MODE":"Wi-Fi Configuration Mode",
|
||||
"SCANNING_WIFI":"Scanning Wi-Fi",
|
||||
"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...",
|
||||
|
||||
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "Unable to establish audio channel",
|
||||
"TEST":"Test"
|
||||
"TEST": "Test",
|
||||
|
||||
"NEW_VERSION": "New version ",
|
||||
"OTA_UPGRADE": "OTA Upgrade",
|
||||
"UPGRADING": "System is upgrading...",
|
||||
"UPGRADE_FAILED": "Upgrade failed",
|
||||
"ACTIVATION": "Activation"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"language": {
|
||||
"type" :"zh-CN"
|
||||
},
|
||||
"strings": {
|
||||
"ERROR":"错误",
|
||||
"VERSION": "版本 ",
|
||||
"LOADING_PROTOCOL":"加载协议...",
|
||||
"INITIALIZING":"正在初始化...",
|
||||
"PIN_ERROR":"请插入 SIM 卡",
|
||||
"REG_ERROR":"无法接入网络,请检查流量卡状态",
|
||||
"DETECTING_MODULE":"检测模组...",
|
||||
"REGISTERING_NETWORK":"等待网络...",
|
||||
|
||||
"STANDBY":"待命",
|
||||
"CONNECT_TO":"连接 ",
|
||||
"CONNECTING":"连接中...",
|
||||
"CONNECTED_TO":"已连接 ",
|
||||
|
||||
"LISTENING":"聆听中...",
|
||||
"SPEAKING":"说话中...",
|
||||
|
||||
"UNABLE_TO_CONNECT_TO_SERVICE":"无法连接服务",
|
||||
"WAITING_FOR_RESPONSE_TIMEOUT":"等待响应超时",
|
||||
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"发送失败,请检查网络",
|
||||
|
||||
"CONNECT_TO_HOTSPOT":"手机连接热点 ",
|
||||
"ACCESS_VIA_BROWSER":",浏览器访问 ",
|
||||
"WIFI_CONFIG_MODE":"配网模式",
|
||||
"ENTERING_WIFI_CONFIG_MODE":"进入配网模式...",
|
||||
"SCANNING_WIFI":"扫描 Wi-Fi...",
|
||||
|
||||
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "无法建立音频通道",
|
||||
"TEST":"测试",
|
||||
|
||||
"NEW_VERSION": "新版本 ",
|
||||
"OTA_UPGRADE":"OTA 升级",
|
||||
"UPGRADING":"正在升级系统...",
|
||||
"UPGRADE_FAILED":"升级失败",
|
||||
"ACTIVATION":"激活设备"
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef BINARY_H
|
||||
#define BINARY_H
|
||||
|
||||
extern const char p3_err_reg_start[] asm("_binary_err_reg_p3_start");
|
||||
extern const char p3_err_reg_end[] asm("_binary_err_reg_p3_end");
|
||||
extern const char p3_err_pin_start[] asm("_binary_err_pin_p3_start");
|
||||
extern const char p3_err_pin_end[] asm("_binary_err_pin_p3_end");
|
||||
extern const char p3_wificonfig_start[] asm("_binary_wificonfig_p3_start");
|
||||
extern const char p3_wificonfig_end[] asm("_binary_wificonfig_p3_end");
|
||||
extern const char p3_upgrade_start[] asm("_binary_upgrade_p3_start");
|
||||
extern const char p3_upgrade_end[] asm("_binary_upgrade_p3_end");
|
||||
extern const char p3_activation_start[] asm("_binary_activation_p3_start");
|
||||
extern const char p3_activation_end[] asm("_binary_activation_p3_end");
|
||||
extern const char p3_welcome_start[] asm("_binary_welcome_p3_start");
|
||||
extern const char p3_welcome_end[] asm("_binary_welcome_p3_end");
|
||||
|
||||
extern const char p3_0_start[] asm("_binary_0_p3_start");
|
||||
extern const char p3_0_end[] asm("_binary_0_p3_end");
|
||||
extern const char p3_1_start[] asm("_binary_1_p3_start");
|
||||
extern const char p3_1_end[] asm("_binary_1_p3_end");
|
||||
extern const char p3_2_start[] asm("_binary_2_p3_start");
|
||||
extern const char p3_2_end[] asm("_binary_2_p3_end");
|
||||
extern const char p3_3_start[] asm("_binary_3_p3_start");
|
||||
extern const char p3_3_end[] asm("_binary_3_p3_end");
|
||||
extern const char p3_4_start[] asm("_binary_4_p3_start");
|
||||
extern const char p3_4_end[] asm("_binary_4_p3_end");
|
||||
extern const char p3_5_start[] asm("_binary_5_p3_start");
|
||||
extern const char p3_5_end[] asm("_binary_5_p3_end");
|
||||
extern const char p3_6_start[] asm("_binary_6_p3_start");
|
||||
extern const char p3_6_end[] asm("_binary_6_p3_end");
|
||||
extern const char p3_7_start[] asm("_binary_7_p3_start");
|
||||
extern const char p3_7_end[] asm("_binary_7_p3_end");
|
||||
extern const char p3_8_start[] asm("_binary_8_p3_start");
|
||||
extern const char p3_8_end[] asm("_binary_8_p3_end");
|
||||
extern const char p3_9_start[] asm("_binary_9_p3_start");
|
||||
extern const char p3_9_end[] asm("_binary_9_p3_end");
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"language": {
|
||||
"type" :"zh"
|
||||
},
|
||||
"strings": {
|
||||
"VERSION": "版本",
|
||||
"LOADING_PROTOCOL":"加载协议",
|
||||
"INITIALIZING":"正在初始化",
|
||||
"NOTICE":"通知",
|
||||
|
||||
"STANDING_BY":"待命",
|
||||
"CONNECT":"连接",
|
||||
"CONNECTING":"连接中",
|
||||
"CONNECTION_SUCCESSFUL":"连接成功",
|
||||
|
||||
"LISTENING":"聆听中",
|
||||
"SPEAKING":"说话中",
|
||||
|
||||
"UNABLE_TO_CONNECT_TO_SERVICE":"无法连接服务",
|
||||
"WAITING_FOR_RESPONSE_TIMEOUT":"等待响应超时",
|
||||
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"发送失败,请检查网络",
|
||||
|
||||
|
||||
|
||||
"CONNECT_MOBILE_PHONE_TO_HOTSPOT":"手机连接热点",
|
||||
"ACCESS_VIA_BROWSER":"浏览器访问",
|
||||
"WIFI_CONFIGURATION_MODE":"配网模式",
|
||||
"SCANNING_WIFI":"扫描 WIFI",
|
||||
|
||||
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "无法建立音频通道",
|
||||
"TEST":"测试"
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
#include "wifi_board.h"
|
||||
#include "audio_codecs/es8311_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "display/no_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
@@ -110,9 +110,9 @@ private:
|
||||
InitializeSpi();
|
||||
InitializeGc9107Display();
|
||||
InitializeButtons();
|
||||
display_->SetStatus("错误");
|
||||
display_->SetStatus(Lang::Strings::ERROR);
|
||||
display_->SetEmotion("sad");
|
||||
display_->SetChatMessage("system", "Echo Base\n未连接");
|
||||
display_->SetChatMessage("system", "Echo Base\nnot connected");
|
||||
|
||||
while (1) {
|
||||
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "wifi_board.h"
|
||||
#include "audio_codecs/es8311_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "display/no_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
@@ -158,9 +158,10 @@ private:
|
||||
InitializeSpi();
|
||||
InitializeGc9107Display();
|
||||
InitializeButtons();
|
||||
display_->SetStatus("错误");
|
||||
|
||||
display_->SetStatus(Lang::Strings::ERROR);
|
||||
display_->SetEmotion("sad");
|
||||
display_->SetChatMessage("system", "Echo Base\n未连接");
|
||||
display_->SetChatMessage("system", "Echo Base\nnot connected");
|
||||
|
||||
while (1) {
|
||||
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "system_info.h"
|
||||
#include "settings.h"
|
||||
#include "display/no_display.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_ota_ops.h>
|
||||
@@ -99,6 +100,7 @@ std::string Board::GetJson() {
|
||||
*/
|
||||
std::string json = "{";
|
||||
json += "\"version\":2,";
|
||||
json += "\"language\":\"" + std::string(Lang::CODE) + "\",";
|
||||
json += "\"flash_size\":" + std::to_string(SystemInfo::GetFlashSize()) + ",";
|
||||
json += "\"minimum_free_heap_size\":" + std::to_string(SystemInfo::GetMinimumFreeHeapSize()) + ",";
|
||||
json += "\"mac_address\":\"" + SystemInfo::GetMacAddress() + "\",";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "application.h"
|
||||
#include "display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "assets/zh/binary.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
@@ -25,7 +25,7 @@ std::string Ml307Board::GetBoardType() {
|
||||
|
||||
void Ml307Board::StartNetwork() {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetStatus("检测模组...");
|
||||
display->SetStatus(Lang::Strings::DETECTING_MODULE);
|
||||
modem_.SetDebug(false);
|
||||
modem_.SetBaudRate(921600);
|
||||
|
||||
@@ -45,13 +45,13 @@ void Ml307Board::StartNetwork() {
|
||||
void Ml307Board::WaitForNetworkReady() {
|
||||
auto& application = Application::GetInstance();
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetStatus("等待网络...");
|
||||
display->SetStatus(Lang::Strings::REGISTERING_NETWORK);
|
||||
int result = modem_.WaitForNetworkReady();
|
||||
if (result == -1) {
|
||||
application.Alert("PIN_ERROR", "请插入SIM卡", "sad", std::string_view(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start));
|
||||
application.Alert(Lang::Strings::ERROR, Lang::Strings::PIN_ERROR, "sad", Lang::Sounds::P3_ERR_PIN);
|
||||
return;
|
||||
} else if (result == -2) {
|
||||
application.Alert("REG_ERROR", "无法接入网络,请检查流量卡状态", "sad", std::string_view(p3_err_reg_start, p3_err_reg_end - p3_err_reg_start));
|
||||
application.Alert(Lang::Strings::ERROR, Lang::Strings::REG_ERROR, "sad", Lang::Sounds::P3_ERR_REG);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "system_info.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "settings.h"
|
||||
#include "assets/zh/binary.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <wifi_station.h>
|
||||
#include <wifi_configuration_ap.h>
|
||||
#include <ssid_manager.h>
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
static const char *TAG = "WifiBoard";
|
||||
|
||||
@@ -46,14 +45,14 @@ void WifiBoard::EnterWifiConfigMode() {
|
||||
wifi_ap.Start();
|
||||
|
||||
// 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
|
||||
std::string hint = Lang::Strings::CONNECT_MOBILE_PHONE_TO_HOTSPOT + " ";
|
||||
std::string hint = Lang::Strings::CONNECT_TO_HOTSPOT;
|
||||
hint += wifi_ap.GetSsid();
|
||||
hint += "\n"+ Lang::Strings::ACCESS_VIA_BROWSER + " ";
|
||||
hint += Lang::Strings::ACCESS_VIA_BROWSER;
|
||||
hint += wifi_ap.GetWebServerUrl();
|
||||
hint += "\n\n";
|
||||
|
||||
// 播报配置 WiFi 的提示
|
||||
application.Alert(Lang::Strings::WIFI_CONFIGURATION_MODE, hint, "", std::string(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start));
|
||||
application.Alert(Lang::Strings::WIFI_CONFIG_MODE, hint.c_str(), "", Lang::Sounds::P3_WIFICONFIG);
|
||||
|
||||
// Wait forever until reset after configuration
|
||||
while (true) {
|
||||
@@ -87,11 +86,16 @@ void WifiBoard::StartNetwork() {
|
||||
});
|
||||
wifi_station.OnConnect([this](const std::string& ssid) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->ShowNotification(std::string(Lang::Strings::CONNECT + " ") + ssid + "...", 30000);
|
||||
std::string notification = Lang::Strings::CONNECT_TO;
|
||||
notification += ssid;
|
||||
notification += "...";
|
||||
display->ShowNotification(notification.c_str(), 30000);
|
||||
});
|
||||
wifi_station.OnConnected([this](const std::string& ssid) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->ShowNotification(std::string(Lang::Strings::CONNECTION_SUCCESSFUL) + ssid);
|
||||
std::string notification = Lang::Strings::CONNECTED_TO;
|
||||
notification += ssid;
|
||||
display->ShowNotification(notification.c_str(), 30000);
|
||||
});
|
||||
wifi_station.Start();
|
||||
|
||||
@@ -167,12 +171,12 @@ void WifiBoard::SetPowerSaveMode(bool enabled) {
|
||||
}
|
||||
|
||||
void WifiBoard::ResetWifiConfiguration() {
|
||||
// Reset the wifi station
|
||||
// Set a flag and reboot the device to enter the network configuration mode
|
||||
{
|
||||
Settings settings("wifi", true);
|
||||
settings.SetInt("force_ap", 1);
|
||||
}
|
||||
GetDisplay()->ShowNotification("Enter the network configuration mode...");
|
||||
GetDisplay()->ShowNotification(Lang::Strings::ENTERING_WIFI_CONFIG_MODE);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
// Reboot the device
|
||||
esp_restart();
|
||||
|
||||
+12
-7
@@ -67,22 +67,26 @@ Display::~Display() {
|
||||
}
|
||||
}
|
||||
|
||||
void Display::SetStatus(const std::string &status) {
|
||||
void Display::SetStatus(const char* status) {
|
||||
DisplayLockGuard lock(this);
|
||||
if (status_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(status_label_, status.c_str());
|
||||
lv_label_set_text(status_label_, status);
|
||||
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
void Display::ShowNotification(const std::string ¬ification, int duration_ms) {
|
||||
ShowNotification(notification.c_str(), duration_ms);
|
||||
}
|
||||
|
||||
void Display::ShowNotification(const char* notification, int duration_ms) {
|
||||
DisplayLockGuard lock(this);
|
||||
if (notification_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(notification_label_, notification.c_str());
|
||||
lv_label_set_text(notification_label_, notification);
|
||||
lv_obj_clear_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
@@ -154,7 +158,7 @@ void Display::Update() {
|
||||
}
|
||||
|
||||
|
||||
void Display::SetEmotion(const std::string &emotion) {
|
||||
void Display::SetEmotion(const char* emotion) {
|
||||
struct Emotion {
|
||||
const char* icon;
|
||||
const char* text;
|
||||
@@ -185,8 +189,9 @@ void Display::SetEmotion(const std::string &emotion) {
|
||||
};
|
||||
|
||||
// 查找匹配的表情
|
||||
std::string_view emotion_view(emotion);
|
||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||
[&emotion](const Emotion& e) { return e.text == emotion; });
|
||||
[&emotion_view](const Emotion& e) { return e.text == emotion_view; });
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
if (emotion_label_ == nullptr) {
|
||||
@@ -209,12 +214,12 @@ void Display::SetIcon(const char* icon) {
|
||||
lv_label_set_text(emotion_label_, icon);
|
||||
}
|
||||
|
||||
void Display::SetChatMessage(const std::string &role, const std::string &content) {
|
||||
void Display::SetChatMessage(const char* role, const char* content) {
|
||||
DisplayLockGuard lock(this);
|
||||
if (chat_message_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(chat_message_label_, content.c_str());
|
||||
lv_label_set_text(chat_message_label_, content);
|
||||
}
|
||||
|
||||
void Display::SetBacklight(uint8_t brightness) {
|
||||
|
||||
@@ -18,10 +18,11 @@ public:
|
||||
Display();
|
||||
virtual ~Display();
|
||||
|
||||
virtual void SetStatus(const std::string &status);
|
||||
virtual void SetStatus(const char* status);
|
||||
virtual void ShowNotification(const char* notification, int duration_ms = 3000);
|
||||
virtual void ShowNotification(const std::string ¬ification, int duration_ms = 3000);
|
||||
virtual void SetEmotion(const std::string &emotion);
|
||||
virtual void SetChatMessage(const std::string &role, const std::string &content);
|
||||
virtual void SetEmotion(const char* emotion);
|
||||
virtual void SetChatMessage(const char* role, const char* content);
|
||||
virtual void SetIcon(const char* icon);
|
||||
virtual void SetBacklight(uint8_t brightness);
|
||||
|
||||
|
||||
@@ -257,15 +257,14 @@ void LcdDisplay::SetupUI() {
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(notification_label_, 1);
|
||||
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
|
||||
lv_label_set_text(notification_label_, "");
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
status_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(status_label_, 1);
|
||||
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
|
||||
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
lv_label_set_text(status_label_, Lang::Strings::INITIALIZING);
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(mute_label_, "");
|
||||
lv_obj_set_style_text_font(mute_label_, fonts_.icon_font, 0);
|
||||
@@ -275,7 +274,7 @@ void LcdDisplay::SetupUI() {
|
||||
lv_obj_set_style_text_font(battery_label_, fonts_.icon_font, 0);
|
||||
}
|
||||
|
||||
void LcdDisplay::SetEmotion(const std::string &emotion) {
|
||||
void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
struct Emotion {
|
||||
const char* icon;
|
||||
const char* text;
|
||||
@@ -306,8 +305,9 @@ void LcdDisplay::SetEmotion(const std::string &emotion) {
|
||||
};
|
||||
|
||||
// 查找匹配的表情
|
||||
std::string_view emotion_view(emotion);
|
||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||
[&emotion](const Emotion& e) { return e.text == emotion; });
|
||||
[&emotion_view](const Emotion& e) { return e.text == emotion_view; });
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
if (emotion_label_ == nullptr) {
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
DisplayFonts fonts);
|
||||
~LcdDisplay();
|
||||
|
||||
virtual void SetEmotion(const std::string &emotion) override;
|
||||
virtual void SetEmotion(const char* emotion) override;
|
||||
virtual void SetIcon(const char* icon) override;
|
||||
virtual void SetBacklight(uint8_t brightness) override;
|
||||
};
|
||||
|
||||
@@ -221,12 +221,12 @@ void Ssd1306Display::SetupUI_128x64() {
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(notification_label_, 1);
|
||||
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
|
||||
lv_label_set_text(notification_label_, "");
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
status_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(status_label_, 1);
|
||||
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
|
||||
lv_label_set_text(status_label_, Lang::Strings::INITIALIZING);
|
||||
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
@@ -296,10 +296,10 @@ void Ssd1306Display::SetupUI_128x32() {
|
||||
|
||||
status_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_style_pad_left(status_label_, 2, 0);
|
||||
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
|
||||
lv_label_set_text(status_label_, Lang::Strings::INITIALIZING);
|
||||
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
|
||||
lv_label_set_text(notification_label_, "");
|
||||
lv_obj_set_style_pad_left(notification_label_, 2, 0);
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
|
||||
+24
-11
@@ -6,18 +6,20 @@ import os
|
||||
HEADER_TEMPLATE = """// Auto-generated language config
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace Lang {{
|
||||
// 语言元数据
|
||||
constexpr std::string_view CODE_VIEW = "{lang_code}";
|
||||
const std::string CODE = std::string(CODE_VIEW);
|
||||
constexpr const char* CODE = "{lang_code}";
|
||||
|
||||
// 字符串资源
|
||||
namespace Strings {{
|
||||
{strings_view}
|
||||
{strings_string}
|
||||
{strings}
|
||||
}}
|
||||
|
||||
// 音效资源
|
||||
namespace Sounds {{
|
||||
{sounds}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
@@ -33,18 +35,29 @@ def generate_header(input_path, output_path):
|
||||
lang_code = data['language']['type']
|
||||
|
||||
# 生成字符串常量
|
||||
strings_view = []
|
||||
strings_string = []
|
||||
strings = []
|
||||
sounds = []
|
||||
for key, value in data['strings'].items():
|
||||
value = value.replace('"', '\\"')
|
||||
strings_view.append(f' constexpr std::string_view {key.upper()}_VIEW = "{value}";')
|
||||
strings_string.append(f' const std::string {key.upper()} = std::string({key.upper()}_VIEW);')
|
||||
strings.append(f' constexpr const char* {key.upper()} = "{value}";')
|
||||
|
||||
# 生成音效常量
|
||||
for file in os.listdir(os.path.dirname(input_path)):
|
||||
if file.endswith('.p3'):
|
||||
base_name = os.path.splitext(file)[0]
|
||||
sounds.append(f'''
|
||||
extern const char p3_{base_name}_start[] asm("_binary_{base_name}_p3_start");
|
||||
extern const char p3_{base_name}_end[] asm("_binary_{base_name}_p3_end");
|
||||
static const std::string_view P3_{base_name.upper()} {{
|
||||
static_cast<const char*>(p3_{base_name}_start),
|
||||
static_cast<size_t>(p3_{base_name}_end - p3_{base_name}_start)
|
||||
}};''')
|
||||
|
||||
# 填充模板
|
||||
content = HEADER_TEMPLATE.format(
|
||||
lang_code=lang_code,
|
||||
strings_view="\n".join(sorted(strings_view)),
|
||||
strings_string="\n".join(sorted(strings_string))
|
||||
strings="\n".join(sorted(strings)),
|
||||
sounds="\n".join(sorted(sounds))
|
||||
)
|
||||
|
||||
# 写入文件
|
||||
|
||||
Reference in New Issue
Block a user