forked from xiaozhi/xiaozhi-esp32
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
140aab8999 | ||
|
|
898109b348 | ||
|
|
10a05db4a1 | ||
|
|
35940f8bda | ||
|
|
db712fa078 | ||
|
|
ade1e3193d | ||
|
|
93915cd624 | ||
|
|
ff18da5a29 | ||
|
|
53cf361b58 | ||
|
|
bbdbbc4f28 | ||
|
|
6b2752a498 | ||
|
|
da2168ea73 | ||
|
|
9ec5f2f908 | ||
|
|
3a71c1e895 | ||
|
|
14a89cae33 | ||
|
|
3a2f6acc9a | ||
|
|
5bce5c3f70 | ||
|
|
730275e4a7 | ||
|
|
f183b881b7 | ||
|
|
af79b70fb5 | ||
|
|
1d1a0c43ba | ||
|
|
8f6691859c | ||
|
|
4114ff213e | ||
|
|
83d6fa9d26 | ||
|
|
d7f41b4b4d | ||
|
|
fed8cb4d86 | ||
|
|
bafc9def1a | ||
|
|
8ace1095e9 | ||
|
|
9b8db4a551 | ||
|
|
b889355d8d | ||
|
|
5e406b481c | ||
|
|
e19604b21e | ||
|
|
ac93e88d17 | ||
|
|
2d718a0cbc | ||
|
|
24c10a607c | ||
|
|
380f702637 | ||
|
|
4aef3d2a4e | ||
|
|
bc800921cf | ||
|
|
256a16e2fe | ||
|
|
554152cd00 | ||
|
|
503c7d8a2a | ||
|
|
84c932da4a | ||
|
|
a0adbfd774 | ||
|
|
252755f615 |
@@ -4,7 +4,7 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PROJECT_VER "1.1.0")
|
||||
set(PROJECT_VER "1.2.1")
|
||||
|
||||
# Add this line to disable the specific warning
|
||||
add_compile_options(-Wno-missing-field-initializers)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
- 支持国语、粤语、英语、日语、韩语 5 种语言识别 [SenseVoice](https://github.com/FunAudioLLM/SenseVoice)
|
||||
- 声纹识别,识别是谁在喊 AI 的名字 [3D Speaker](https://github.com/modelscope/3D-Speaker)
|
||||
- 大模型 TTS(火山引擎 或 CosyVoice)
|
||||
- 大模型 LLM(Qwen2.5 72B 或 豆包 API)
|
||||
- 大模型 LLM(Qwen, DeepSeek, Doubao)
|
||||
- 可配置的提示词和音色(自定义角色)
|
||||
- 短期记忆,每轮对话后自我总结
|
||||
- OLED / LCD 显示屏,显示信号强弱或对话内容
|
||||
|
||||
@@ -13,8 +13,6 @@ set(SOURCES "audio_codecs/audio_codec.cc"
|
||||
"display/ssd1306_display.cc"
|
||||
"boards/lilygo-t-circle-s3/esp_lcd_gc9d01n.c"
|
||||
"protocols/protocol.cc"
|
||||
"protocols/mqtt_protocol.cc"
|
||||
"protocols/websocket_protocol.cc"
|
||||
"iot/thing.cc"
|
||||
"iot/thing_manager.cc"
|
||||
"system_info.cc"
|
||||
@@ -50,7 +48,9 @@ elseif(CONFIG_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")
|
||||
set(BOARD_TYPE "kevin-c3")
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V3_DEV)
|
||||
set(BOARD_TYPE "kevin-sp-v3-dev")
|
||||
elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV)
|
||||
set(BOARD_TYPE "lichuang-dev")
|
||||
elseif(CONFIG_BOARD_TYPE_LICHUANG_C3_DEV)
|
||||
@@ -61,6 +61,8 @@ elseif(CONFIG_BOARD_TYPE_MAGICLICK_C3)
|
||||
set(BOARD_TYPE "magiclick-c3")
|
||||
elseif(CONFIG_BOARD_TYPE_M5STACK_CORE_S3)
|
||||
set(BOARD_TYPE "m5stack-core-s3")
|
||||
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_ATOMMATRIX_ECHO_BASE)
|
||||
@@ -73,6 +75,12 @@ elseif(CONFIG_BOARD_TYPE_ESP_SPARKBOT)
|
||||
set(BOARD_TYPE "esp-sparkbot")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
|
||||
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
|
||||
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_BREAD_COMPACT_WIFI_LCD)
|
||||
set(BOARD_TYPE "bread-compact-wifi-lcd")
|
||||
elseif(CONFIG_BOARD_TYPE_TUDOUZI)
|
||||
@@ -85,11 +93,25 @@ 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_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_OLED)
|
||||
set(BOARD_TYPE "xingzhi-cube-oled")
|
||||
elseif(CONFIG_BOARD_TYPE_XINGZHI_Cube_TFT)
|
||||
set(BOARD_TYPE "xingzhi-cube-tft")
|
||||
endif()
|
||||
file(GLOB BOARD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc)
|
||||
list(APPEND SOURCES ${BOARD_SOURCES})
|
||||
|
||||
if(CONFIG_IDF_TARGET_ESP32S3)
|
||||
if(CONFIG_CONNECTION_TYPE_MQTT_UDP)
|
||||
list(APPEND SOURCES "protocols/mqtt_protocol.cc")
|
||||
elseif(CONFIG_CONNECTION_TYPE_WEBSOCKET)
|
||||
list(APPEND SOURCES "protocols/websocket_protocol.cc")
|
||||
endif()
|
||||
|
||||
if(CONFIG_USE_AUDIO_PROCESSING)
|
||||
list(APPEND SOURCES "audio_processing/audio_processor.cc" "audio_processing/wake_word_detect.cc")
|
||||
endif()
|
||||
|
||||
@@ -101,8 +123,10 @@ 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/err_reg.p3" "assets/err_pin.p3" "assets/wificonfig.p3" "assets/upgrade.p3"
|
||||
EMBED_FILES ${ASSETS}
|
||||
INCLUDE_DIRS ${INCLUDE_DIRS}
|
||||
WHOLE_ARCHIVE
|
||||
)
|
||||
|
||||
@@ -52,6 +52,8 @@ choice BOARD_TYPE
|
||||
bool "Kevin Box 2"
|
||||
config BOARD_TYPE_KEVIN_C3
|
||||
bool "Kevin C3"
|
||||
config BOARD_TYPE_KEVIN_SP_V3_DEV
|
||||
bool "Kevin SP V3开发板"
|
||||
config BOARD_TYPE_LICHUANG_DEV
|
||||
bool "立创·实战派ESP32-S3开发板"
|
||||
config BOARD_TYPE_LICHUANG_C3_DEV
|
||||
@@ -62,6 +64,8 @@ choice BOARD_TYPE
|
||||
bool "神奇按钮 Magiclick_C3"
|
||||
config BOARD_TYPE_M5STACK_CORE_S3
|
||||
bool "M5Stack CoreS3"
|
||||
config BOARD_TYPE_ATOMS3_ECHO_BASE
|
||||
bool "AtomS3 + Echo Base"
|
||||
config BOARD_TYPE_ATOMS3R_ECHO_BASE
|
||||
bool "AtomS3R + Echo Base"
|
||||
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
|
||||
@@ -74,6 +78,12 @@ choice BOARD_TYPE
|
||||
bool "ESP-SparkBot开发板"
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_85C
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.85C"
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_85
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.85"
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_46
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
|
||||
config BOARD_TYPE_TUDOUZI
|
||||
bool "土豆子"
|
||||
config BOARD_TYPE_LILYGO_T_CIRCLE_S3
|
||||
@@ -84,6 +94,26 @@ choice BOARD_TYPE
|
||||
bool "正点原子DNESP32S3开发板"
|
||||
config BOARD_TYPE_ATK_DNESP32S3_BOX
|
||||
bool "正点原子DNESP32S3-BOX"
|
||||
config BOARD_TYPE_DU_CHATX
|
||||
bool "嘟嘟开发板CHATX(wifi)"
|
||||
config BOARD_TYPE_ESP32S3_Taiji_Pi
|
||||
bool "太极小派esp32s3"
|
||||
config BOARD_TYPE_XINGZHI_Cube_OLED
|
||||
bool "无名科技星智0.96"
|
||||
config BOARD_TYPE_XINGZHI_Cube_TFT
|
||||
bool "无名科技星智1.54"
|
||||
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"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_LCD_TYPE
|
||||
@@ -116,6 +146,12 @@ choice DISPLAY_LCD_TYPE
|
||||
bool "ILI9341, 分辨率240*320, 非IPS"
|
||||
config LCD_CUSTOM
|
||||
bool "自定义屏幕参数"
|
||||
endchoice
|
||||
endchoice
|
||||
|
||||
config USE_AUDIO_PROCESSING
|
||||
bool "启用语音唤醒与音频处理"
|
||||
default y
|
||||
depends on IDF_TARGET_ESP32S3 && USE_AFE
|
||||
help
|
||||
需要 ESP32 S3 与 AFE 支持
|
||||
endmenu
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "websocket_protocol.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "assets/zh/binary.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <esp_log.h>
|
||||
@@ -17,14 +18,6 @@
|
||||
|
||||
#define TAG "Application"
|
||||
|
||||
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");
|
||||
|
||||
static const char* const STATE_STRINGS[] = {
|
||||
"unknown",
|
||||
@@ -35,6 +28,7 @@ static const char* const STATE_STRINGS[] = {
|
||||
"listening",
|
||||
"speaking",
|
||||
"upgrading",
|
||||
"activating",
|
||||
"fatal_error",
|
||||
"invalid_state"
|
||||
};
|
||||
@@ -42,9 +36,6 @@ static const char* const STATE_STRINGS[] = {
|
||||
Application::Application() {
|
||||
event_group_ = xEventGroupCreate();
|
||||
background_task_ = new BackgroundTask(4096 * 8);
|
||||
|
||||
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
|
||||
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
@@ -60,79 +51,142 @@ void Application::CheckNewVersion() {
|
||||
// Check if there is a new firmware version available
|
||||
ota_.SetPostData(board.GetJson());
|
||||
|
||||
const int MAX_RETRY = 10;
|
||||
int retry_count = 0;
|
||||
|
||||
while (true) {
|
||||
if (ota_.CheckVersion()) {
|
||||
if (ota_.HasNewVersion()) {
|
||||
Alert("Info", "正在升级固件");
|
||||
// Wait for the chat state to be idle
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
} while (GetDeviceState() != kDeviceStateIdle);
|
||||
|
||||
// Use main task to do the upgrade, not cancelable
|
||||
Schedule([this, &board, display]() {
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
display->SetStatus("新版本 " + ota_.GetFirmwareVersion());
|
||||
|
||||
board.SetPowerSaveMode(false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
wake_word_detect_.StopDetection();
|
||||
#endif
|
||||
// 预先关闭音频输出,避免升级过程有音频操作
|
||||
board.GetAudioCodec()->EnableOutput(false);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
audio_decode_queue_.clear();
|
||||
}
|
||||
background_task_->WaitForCompletion();
|
||||
delete background_task_;
|
||||
background_task_ = nullptr;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
ota_.StartUpgrade([display](int progress, size_t speed) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %zuKB/s", progress, speed / 1024);
|
||||
display->SetStatus(buffer);
|
||||
});
|
||||
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
display->SetStatus("更新失败");
|
||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
esp_restart();
|
||||
});
|
||||
} else {
|
||||
ota_.MarkCurrentVersionValid();
|
||||
display->ShowNotification("版本 " + ota_.GetCurrentVersion());
|
||||
if (!ota_.CheckVersion()) {
|
||||
retry_count++;
|
||||
if (retry_count >= MAX_RETRY) {
|
||||
ESP_LOGE(TAG, "版本检查失败次数过多,退出检查");
|
||||
return;
|
||||
}
|
||||
ESP_LOGW(TAG, "版本检查失败,%d秒后重试 (%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));
|
||||
// Wait for the chat state to be idle
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
} while (GetDeviceState() != kDeviceStateIdle);
|
||||
|
||||
// Use main task to do the upgrade, not cancelable
|
||||
Schedule([this, display]() {
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
display->SetChatMessage("system", "新版本 " + ota_.GetFirmwareVersion());
|
||||
|
||||
auto& board = Board::GetInstance();
|
||||
board.SetPowerSaveMode(false);
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
wake_word_detect_.StopDetection();
|
||||
#endif
|
||||
// 预先关闭音频输出,避免升级过程有音频操作
|
||||
auto codec = board.GetAudioCodec();
|
||||
codec->EnableInput(false);
|
||||
codec->EnableOutput(false);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
audio_decode_queue_.clear();
|
||||
}
|
||||
background_task_->WaitForCompletion();
|
||||
delete background_task_;
|
||||
background_task_ = nullptr;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
ota_.StartUpgrade([display](int progress, size_t speed) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %zuKB/s", progress, speed / 1024);
|
||||
display->SetChatMessage("system", buffer);
|
||||
});
|
||||
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
display->SetStatus("更新失败");
|
||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
Reboot();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check again in 60 seconds
|
||||
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||
// No new version, mark the current version as valid
|
||||
ota_.MarkCurrentVersionValid();
|
||||
display->ShowNotification("版本 " + ota_.GetCurrentVersion());
|
||||
|
||||
if (ota_.HasActivationCode()) {
|
||||
// Activation code is valid
|
||||
SetDeviceState(kDeviceStateActivating);
|
||||
ShowActivationCode();
|
||||
// Check again in 60 seconds
|
||||
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||
continue;
|
||||
}
|
||||
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
display->SetChatMessage("system", "");
|
||||
|
||||
// Exit the loop if upgrade or idle
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::Alert(const std::string& title, const std::string& message) {
|
||||
ESP_LOGW(TAG, "Alert: %s, %s", title.c_str(), message.c_str());
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->ShowNotification(message);
|
||||
void Application::ShowActivationCode() {
|
||||
auto& message = ota_.GetActivationMessage();
|
||||
auto& code = ota_.GetActivationCode();
|
||||
|
||||
if (message == "进入配网模式") {
|
||||
PlayLocalFile(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start);
|
||||
} else if (message == "正在升级固件") {
|
||||
PlayLocalFile(p3_upgrade_start, p3_upgrade_end - p3_upgrade_start);
|
||||
} else if (message == "请插入SIM卡") {
|
||||
PlayLocalFile(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start);
|
||||
} else if (message == "无法接入网络,请检查流量卡状态") {
|
||||
PlayLocalFile(p3_err_reg_start, p3_err_reg_end - p3_err_reg_start);
|
||||
struct digit_sound {
|
||||
char digit;
|
||||
const char* data;
|
||||
size_t size;
|
||||
};
|
||||
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)}
|
||||
}};
|
||||
|
||||
// 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));
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
background_task_->WaitForCompletion();
|
||||
|
||||
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()) {
|
||||
PlayLocalFile(it->data, it->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());
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetStatus(status);
|
||||
display->SetEmotion(emotion);
|
||||
display->SetChatMessage("system", message);
|
||||
if (!sound.empty()) {
|
||||
PlayLocalFile(sound.data(), sound.size());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::PlayLocalFile(const char* data, size_t size) {
|
||||
ESP_LOGI(TAG, "PlayLocalFile: %zu bytes", size);
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
codec->EnableOutput(true);
|
||||
SetDecodeSampleRate(16000);
|
||||
for (const char* p = data; p < data + size; ) {
|
||||
auto p3 = (BinaryProtocol3*)p;
|
||||
@@ -151,6 +205,11 @@ void Application::PlayLocalFile(const char* data, size_t size) {
|
||||
|
||||
void Application::ToggleChatState() {
|
||||
Schedule([this]() {
|
||||
if (device_state_ == kDeviceStateActivating) {
|
||||
Reboot();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protocol_) {
|
||||
ESP_LOGE(TAG, "Protocol not initialized");
|
||||
return;
|
||||
@@ -159,7 +218,7 @@ void Application::ToggleChatState() {
|
||||
if (device_state_ == kDeviceStateIdle) {
|
||||
SetDeviceState(kDeviceStateConnecting);
|
||||
if (!protocol_->OpenAudioChannel()) {
|
||||
Alert("Error", "Failed to open audio channel");
|
||||
Alert("ERROR", "无法建立音频通道", "sad");
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
return;
|
||||
}
|
||||
@@ -177,6 +236,11 @@ void Application::ToggleChatState() {
|
||||
|
||||
void Application::StartListening() {
|
||||
Schedule([this]() {
|
||||
if (device_state_ == kDeviceStateActivating) {
|
||||
Reboot();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protocol_) {
|
||||
ESP_LOGE(TAG, "Protocol not initialized");
|
||||
return;
|
||||
@@ -188,7 +252,7 @@ void Application::StartListening() {
|
||||
SetDeviceState(kDeviceStateConnecting);
|
||||
if (!protocol_->OpenAudioChannel()) {
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
Alert("Error", "Failed to open audio channel");
|
||||
Alert("ERROR", "无法建立音频通道", "sad");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -225,6 +289,16 @@ void Application::Start() {
|
||||
opus_decode_sample_rate_ = codec->output_sample_rate();
|
||||
opus_decoder_ = std::make_unique<OpusDecoderWrapper>(opus_decode_sample_rate_, 1);
|
||||
opus_encoder_ = std::make_unique<OpusEncoderWrapper>(16000, 1, OPUS_FRAME_DURATION_MS);
|
||||
// For ML307 boards, we use complexity 5 to save bandwidth
|
||||
// For other boards, we use complexity 3 to save CPU
|
||||
if (board.GetBoardType() == "ml307") {
|
||||
ESP_LOGI(TAG, "ML307 board detected, setting opus encoder complexity to 5");
|
||||
opus_encoder_->SetComplexity(5);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "WiFi board detected, setting opus encoder complexity to 3");
|
||||
opus_encoder_->SetComplexity(3);
|
||||
}
|
||||
|
||||
if (codec->input_sample_rate() != 16000) {
|
||||
input_resampler_.Configure(codec->input_sample_rate(), 16000);
|
||||
reference_resampler_.Configure(codec->input_sample_rate(), 16000);
|
||||
@@ -252,14 +326,14 @@ void Application::Start() {
|
||||
board.StartNetwork();
|
||||
|
||||
// Initialize the protocol
|
||||
display->SetStatus("初始化协议");
|
||||
display->SetStatus("加载协议...");
|
||||
#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", std::move(message));
|
||||
Alert("ERROR", message, "sad");
|
||||
});
|
||||
protocol_->OnIncomingAudio([this](std::vector<uint8_t>&& data) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@@ -283,7 +357,7 @@ void Application::Start() {
|
||||
board.SetPowerSaveMode(true);
|
||||
Schedule([this]() {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetChatMessage("", "");
|
||||
display->SetChatMessage("system", "");
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
});
|
||||
});
|
||||
@@ -346,8 +420,12 @@ void Application::Start() {
|
||||
}
|
||||
}
|
||||
});
|
||||
protocol_->Start();
|
||||
|
||||
// Check for new firmware version or get the MQTT broker address
|
||||
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
|
||||
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
||||
ota_.SetHeader("Client-Id", board.GetUuid());
|
||||
xTaskCreate([](void* arg) {
|
||||
Application* app = (Application*)arg;
|
||||
app->CheckNewVersion();
|
||||
@@ -355,7 +433,7 @@ void Application::Start() {
|
||||
}, "check_new_version", 4096 * 2, this, 1, nullptr);
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
audio_processor_.Initialize(codec->input_channels(), codec->input_reference());
|
||||
audio_processor_.OnOutput([this](std::vector<int16_t>&& data) {
|
||||
background_task_->Schedule([this, data = std::move(data)]() mutable {
|
||||
@@ -458,7 +536,6 @@ void Application::ResetDecoder() {
|
||||
opus_decoder_->ResetState();
|
||||
audio_decode_queue_.clear();
|
||||
last_output_time_ = std::chrono::steady_clock::now();
|
||||
Board::GetInstance().GetAudioCodec()->EnableOutput(true);
|
||||
}
|
||||
|
||||
void Application::OutputAudio() {
|
||||
@@ -541,7 +618,7 @@ void Application::InputAudio() {
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
if (audio_processor_.IsRunning()) {
|
||||
audio_processor_.Input(data);
|
||||
}
|
||||
@@ -577,27 +654,30 @@ void Application::SetDeviceState(DeviceState state) {
|
||||
// The state is changed, wait for all background tasks to finish
|
||||
background_task_->WaitForCompletion();
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
auto led = Board::GetInstance().GetLed();
|
||||
auto& board = Board::GetInstance();
|
||||
auto codec = board.GetAudioCodec();
|
||||
auto display = board.GetDisplay();
|
||||
auto led = board.GetLed();
|
||||
led->OnStateChanged();
|
||||
switch (state) {
|
||||
case kDeviceStateUnknown:
|
||||
case kDeviceStateIdle:
|
||||
display->SetStatus("待命");
|
||||
display->SetEmotion("neutral");
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||
#ifdef CONFIG_USE_AUDIO_PROCESSING
|
||||
audio_processor_.Stop();
|
||||
#endif
|
||||
break;
|
||||
case kDeviceStateConnecting:
|
||||
display->SetStatus("连接中...");
|
||||
display->SetChatMessage("system", "");
|
||||
break;
|
||||
case kDeviceStateListening:
|
||||
display->SetStatus("聆听中...");
|
||||
display->SetEmotion("neutral");
|
||||
ResetDecoder();
|
||||
opus_encoder_->ResetState();
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
audio_processor_.Start();
|
||||
#endif
|
||||
UpdateIotStates();
|
||||
@@ -605,7 +685,8 @@ void Application::SetDeviceState(DeviceState state) {
|
||||
case kDeviceStateSpeaking:
|
||||
display->SetStatus("说话中...");
|
||||
ResetDecoder();
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
codec->EnableOutput(true);
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
audio_processor_.Stop();
|
||||
#endif
|
||||
break;
|
||||
@@ -639,3 +720,25 @@ void Application::UpdateIotStates() {
|
||||
protocol_->SendIotStates(states);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
AbortSpeaking(kAbortReasonNone);
|
||||
} else if (device_state_ == kDeviceStateListening) {
|
||||
if (protocol_) {
|
||||
protocol_->CloseAudioChannel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "ota.h"
|
||||
#include "background_task.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
#include "wake_word_detect.h"
|
||||
#include "audio_processor.h"
|
||||
#endif
|
||||
@@ -35,6 +35,7 @@ enum DeviceState {
|
||||
kDeviceStateListening,
|
||||
kDeviceStateSpeaking,
|
||||
kDeviceStateUpgrading,
|
||||
kDeviceStateActivating,
|
||||
kDeviceStateFatalError
|
||||
};
|
||||
|
||||
@@ -55,18 +56,20 @@ public:
|
||||
bool IsVoiceDetected() const { return voice_detected_; }
|
||||
void Schedule(std::function<void()> callback);
|
||||
void SetDeviceState(DeviceState state);
|
||||
void Alert(const std::string& title, const std::string& message);
|
||||
void Alert(const std::string& status, const std::string& message, const std::string& emotion = "", const std::string_view& sound = "");
|
||||
void AbortSpeaking(AbortReason reason);
|
||||
void ToggleChatState();
|
||||
void StartListening();
|
||||
void StopListening();
|
||||
void UpdateIotStates();
|
||||
void Reboot();
|
||||
void WakeWordInvoke(const std::string& wake_word);
|
||||
|
||||
private:
|
||||
Application();
|
||||
~Application();
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#if CONFIG_USE_AUDIO_PROCESSING
|
||||
WakeWordDetect wake_word_detect_;
|
||||
AudioProcessor audio_processor_;
|
||||
#endif
|
||||
@@ -100,6 +103,7 @@ private:
|
||||
void ResetDecoder();
|
||||
void SetDecodeSampleRate(int sample_rate);
|
||||
void CheckNewVersion();
|
||||
void ShowActivationCode();
|
||||
|
||||
void PlayLocalFile(const char* data, size_t size);
|
||||
};
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
main/assets/zh/0.p3
Normal file
BIN
main/assets/zh/0.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/1.p3
Normal file
BIN
main/assets/zh/1.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/2.p3
Normal file
BIN
main/assets/zh/2.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/3.p3
Normal file
BIN
main/assets/zh/3.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/4.p3
Normal file
BIN
main/assets/zh/4.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/5.p3
Normal file
BIN
main/assets/zh/5.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/6.p3
Normal file
BIN
main/assets/zh/6.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/7.p3
Normal file
BIN
main/assets/zh/7.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/8.p3
Normal file
BIN
main/assets/zh/8.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/9.p3
Normal file
BIN
main/assets/zh/9.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/activation.p3
Normal file
BIN
main/assets/zh/activation.p3
Normal file
Binary file not shown.
39
main/assets/zh/binary.h
Normal file
39
main/assets/zh/binary.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#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
|
||||
BIN
main/assets/zh/err_pin.p3
Normal file
BIN
main/assets/zh/err_pin.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/err_reg.p3
Normal file
BIN
main/assets/zh/err_reg.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/sounds.tar.gz
Normal file
BIN
main/assets/zh/sounds.tar.gz
Normal file
Binary file not shown.
BIN
main/assets/zh/upgrade.p3
Normal file
BIN
main/assets/zh/upgrade.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/welcome.p3
Normal file
BIN
main/assets/zh/welcome.p3
Normal file
Binary file not shown.
BIN
main/assets/zh/wificonfig.p3
Normal file
BIN
main/assets/zh/wificonfig.p3
Normal file
Binary file not shown.
@@ -149,7 +149,7 @@ void Es8388AudioCodec::EnableInput(bool enable) {
|
||||
.mclk_multiple = 0,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs));
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, 40.0));
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, 24.0));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||
}
|
||||
@@ -170,6 +170,14 @@ void Es8388AudioCodec::EnableOutput(bool enable) {
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_codec_dev_open(output_dev_, &fs));
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, output_volume_));
|
||||
|
||||
// Set analog output volume to 0dB, default is -45dB
|
||||
uint8_t reg_val = 30; // 0dB
|
||||
uint8_t regs[] = { 46, 47, 48, 49 }; // HP_LVOL, HP_RVOL, SPK_LVOL, SPK_RVOL
|
||||
for (uint8_t reg : regs) {
|
||||
ctrl_if_->write_reg(ctrl_if_, reg, 1, ®_val, 1);
|
||||
}
|
||||
|
||||
if (pa_pin_ != GPIO_NUM_NC) {
|
||||
gpio_set_level(pa_pin_, 1);
|
||||
}
|
||||
@@ -194,4 +202,4 @@ int Es8388AudioCodec::Write(const int16_t* data, int samples) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_write(output_dev_, (void*)data, samples * sizeof(int16_t)));
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ NoAudioCodec::~NoAudioCodec() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NoAudioCodecDuplex::NoAudioCodecDuplex(int input_sample_rate, int output_sample_rate, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din) {
|
||||
duplex_ = true;
|
||||
input_sample_rate_ = input_sample_rate;
|
||||
@@ -201,6 +200,76 @@ NoAudioCodecSimplex::NoAudioCodecSimplex(int input_sample_rate, int output_sampl
|
||||
ESP_LOGI(TAG, "Simplex channels created");
|
||||
}
|
||||
|
||||
NoAudioCodecSimplex::NoAudioCodecSimplex(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, i2s_std_slot_mask_t spk_slot_mask, gpio_num_t mic_sck, gpio_num_t mic_ws, gpio_num_t mic_din, i2s_std_slot_mask_t mic_slot_mask){
|
||||
duplex_ = false;
|
||||
input_sample_rate_ = input_sample_rate;
|
||||
output_sample_rate_ = output_sample_rate;
|
||||
|
||||
// Create a new channel for speaker
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
.id = (i2s_port_t)0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 6,
|
||||
.dma_frame_num = 240,
|
||||
.auto_clear_after_cb = true,
|
||||
.auto_clear_before_cb = false,
|
||||
.intr_priority = 0,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle_, nullptr));
|
||||
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = {
|
||||
.sample_rate_hz = (uint32_t)output_sample_rate_,
|
||||
.clk_src = I2S_CLK_SRC_DEFAULT,
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
|
||||
#ifdef I2S_HW_VERSION_2
|
||||
.ext_clk_freq_hz = 0,
|
||||
#endif
|
||||
|
||||
},
|
||||
.slot_cfg = {
|
||||
.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT,
|
||||
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
|
||||
.slot_mode = I2S_SLOT_MODE_MONO,
|
||||
.slot_mask = spk_slot_mask,
|
||||
.ws_width = I2S_DATA_BIT_WIDTH_32BIT,
|
||||
.ws_pol = false,
|
||||
.bit_shift = true,
|
||||
#ifdef I2S_HW_VERSION_2
|
||||
.left_align = true,
|
||||
.big_endian = false,
|
||||
.bit_order_lsb = false
|
||||
#endif
|
||||
|
||||
},
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = spk_bclk,
|
||||
.ws = spk_ws,
|
||||
.dout = spk_dout,
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
.ws_inv = false
|
||||
}
|
||||
}
|
||||
};
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
|
||||
|
||||
// Create a new channel for MIC
|
||||
chan_cfg.id = (i2s_port_t)1;
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, nullptr, &rx_handle_));
|
||||
std_cfg.clk_cfg.sample_rate_hz = (uint32_t)input_sample_rate_;
|
||||
std_cfg.slot_cfg.slot_mask = mic_slot_mask;
|
||||
std_cfg.gpio_cfg.bclk = mic_sck;
|
||||
std_cfg.gpio_cfg.ws = mic_ws;
|
||||
std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED;
|
||||
std_cfg.gpio_cfg.din = mic_din;
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
|
||||
ESP_LOGI(TAG, "Simplex channels created");
|
||||
}
|
||||
|
||||
NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, gpio_num_t mic_sck, gpio_num_t mic_din) {
|
||||
duplex_ = false;
|
||||
input_sample_rate_ = input_sample_rate;
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
class NoAudioCodecSimplex : public NoAudioCodec {
|
||||
public:
|
||||
NoAudioCodecSimplex(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, gpio_num_t mic_sck, gpio_num_t mic_ws, gpio_num_t mic_din);
|
||||
NoAudioCodecSimplex(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, i2s_std_slot_mask_t spk_slot_mask, gpio_num_t mic_sck, gpio_num_t mic_ws, gpio_num_t mic_din, i2s_std_slot_mask_t mic_slot_mask);
|
||||
};
|
||||
|
||||
class NoAudioCodecSimplexPdm : public NoAudioCodec {
|
||||
|
||||
@@ -5,33 +5,25 @@
|
||||
#define TAG "BackgroundTask"
|
||||
|
||||
BackgroundTask::BackgroundTask(uint32_t stack_size) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
task_stack_ = (StackType_t*)heap_caps_malloc(stack_size, MALLOC_CAP_SPIRAM);
|
||||
background_task_handle_ = xTaskCreateStatic([](void* arg) {
|
||||
BackgroundTask* task = (BackgroundTask*)arg;
|
||||
task->BackgroundTaskLoop();
|
||||
}, "background_task", stack_size, this, 1, task_stack_, &task_buffer_);
|
||||
#else
|
||||
xTaskCreate([](void* arg) {
|
||||
BackgroundTask* task = (BackgroundTask*)arg;
|
||||
task->BackgroundTaskLoop();
|
||||
}, "background_task", stack_size, this, 1, &background_task_handle_);
|
||||
#endif
|
||||
}
|
||||
|
||||
BackgroundTask::~BackgroundTask() {
|
||||
if (background_task_handle_ != nullptr) {
|
||||
vTaskDelete(background_task_handle_);
|
||||
}
|
||||
if (task_stack_ != nullptr) {
|
||||
heap_caps_free(task_stack_);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundTask::Schedule(std::function<void()> callback) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (active_tasks_ >= 30) {
|
||||
ESP_LOGW(TAG, "active_tasks_ == %u", active_tasks_.load());
|
||||
int free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
if (free_sram < 10000) {
|
||||
ESP_LOGW(TAG, "active_tasks_ == %u, free_sram == %u", active_tasks_.load(), free_sram);
|
||||
}
|
||||
}
|
||||
active_tasks_++;
|
||||
main_tasks_.emplace_back([this, cb = std::move(callback)]() {
|
||||
|
||||
@@ -23,10 +23,6 @@ private:
|
||||
TaskHandle_t background_task_handle_ = nullptr;
|
||||
std::atomic<size_t> active_tasks_{0};
|
||||
|
||||
TaskHandle_t task_ = nullptr;
|
||||
StaticTask_t task_buffer_;
|
||||
StackType_t* task_stack_ = nullptr;
|
||||
|
||||
void BackgroundTaskLoop();
|
||||
};
|
||||
|
||||
|
||||
9
main/boards/atk-dnesp32s3-box/config.json
Normal file
9
main/boards/atk-dnesp32s3-box/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "atk-dnesp32s3-box",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -162,15 +162,20 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8388AudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new Es8388AudioCodec(i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
GPIO_NUM_NC, AUDIO_CODEC_ES8388_ADDR);
|
||||
|
||||
audio_codec->SetOutputVolume(AUDIO_DEFAULT_OUTPUT_VOLUME); //设置默认音量
|
||||
}
|
||||
return audio_codec;
|
||||
static Es8388AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_0,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
GPIO_NUM_NC,
|
||||
AUDIO_CODEC_ES8388_ADDR
|
||||
);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
@@ -178,4 +183,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(atk_dnesp32s3);
|
||||
DECLARE_BOARD(atk_dnesp32s3);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_DEFAULT_OUTPUT_VOLUME 90
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_3
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_9
|
||||
|
||||
9
main/boards/atk-dnesp32s3/config.json
Normal file
9
main/boards/atk-dnesp32s3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "atk-dnesp32s3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -122,13 +122,20 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new Es8311AudioCodec(i2c_bus_, I2C_NUM_1, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_GPIO_PA, AUDIO_CODEC_ES8311_ADDR, false);
|
||||
}
|
||||
return audio_codec;
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_1,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_GPIO_PA,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
false);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
12
main/boards/atommatrix-echo-base/config.json
Normal file
12
main/boards/atommatrix-echo-base/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"target": "esp32",
|
||||
"builds": [
|
||||
{
|
||||
"name": "atommatrix-echo-base",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_4M.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
49
main/boards/atoms3-echo-base/README.md
Normal file
49
main/boards/atoms3-echo-base/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 编译配置命令
|
||||
|
||||
**配置编译目标为 ESP32S3:**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32s3
|
||||
```
|
||||
|
||||
**打开 menuconfig:**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子:**
|
||||
|
||||
```
|
||||
Xiaozhi Assistant -> Board Type -> AtomS3 + Echo Base
|
||||
```
|
||||
|
||||
**关闭语音唤醒:**
|
||||
|
||||
```
|
||||
Xiaozhi Assistant -> [ ] 启用语音唤醒与音频处理 -> Unselect
|
||||
```
|
||||
|
||||
**修改 flash 大小:**
|
||||
|
||||
```
|
||||
Serial flasher config -> Flash size -> 8 MB
|
||||
```
|
||||
|
||||
**修改分区表:**
|
||||
|
||||
```
|
||||
Partition Table -> Custom partition CSV file -> partitions_8M.csv
|
||||
```
|
||||
|
||||
**关闭片外 PSRAM:**
|
||||
|
||||
```
|
||||
Component config -> ESP PSRAM -> [ ] Support for external, SPI-connected RAM -> Unselect
|
||||
```
|
||||
|
||||
**编译:**
|
||||
|
||||
```bash
|
||||
idf.py build
|
||||
```
|
||||
238
main/boards/atoms3-echo-base/atoms3_echo_base.cc
Normal file
238
main/boards/atoms3-echo-base/atoms3_echo_base.cc
Normal file
@@ -0,0 +1,238 @@
|
||||
#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 <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_gc9a01.h>
|
||||
|
||||
#define TAG "AtomS3+EchoBase"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
static const gc9a01_lcd_init_cmd_t gc9107_lcd_init_cmds[] = {
|
||||
// {cmd, { data }, data_size, delay_ms}
|
||||
{0xfe, (uint8_t[]){0x00}, 0, 0},
|
||||
{0xef, (uint8_t[]){0x00}, 0, 0},
|
||||
{0xb0, (uint8_t[]){0xc0}, 1, 0},
|
||||
{0xb2, (uint8_t[]){0x2f}, 1, 0},
|
||||
{0xb3, (uint8_t[]){0x03}, 1, 0},
|
||||
{0xb6, (uint8_t[]){0x19}, 1, 0},
|
||||
{0xb7, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xac, (uint8_t[]){0xcb}, 1, 0},
|
||||
{0xab, (uint8_t[]){0x0e}, 1, 0},
|
||||
{0xb4, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xa8, (uint8_t[]){0x19}, 1, 0},
|
||||
{0xb8, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xe8, (uint8_t[]){0x24}, 1, 0},
|
||||
{0xe9, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xea, (uint8_t[]){0x22}, 1, 0},
|
||||
{0xc6, (uint8_t[]){0x30}, 1, 0},
|
||||
{0xc7, (uint8_t[]){0x18}, 1, 0},
|
||||
{0xf0,
|
||||
(uint8_t[]){0x1f, 0x28, 0x04, 0x3e, 0x2a, 0x2e, 0x20, 0x00, 0x0c, 0x06,
|
||||
0x00, 0x1c, 0x1f, 0x0f},
|
||||
14, 0},
|
||||
{0xf1,
|
||||
(uint8_t[]){0x00, 0x2d, 0x2f, 0x3c, 0x6f, 0x1c, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x07, 0x0d, 0x11, 0x0f},
|
||||
14, 0},
|
||||
};
|
||||
|
||||
class AtomS3EchoBaseBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Display* display_;
|
||||
Button boot_button_;
|
||||
bool is_echo_base_connected_ = false;
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_1,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void I2cDetect() {
|
||||
is_echo_base_connected_ = false;
|
||||
uint8_t echo_base_connected_flag = 0x00;
|
||||
uint8_t address;
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
|
||||
for (int i = 0; i < 128; i += 16) {
|
||||
printf("%02x: ", i);
|
||||
for (int j = 0; j < 16; j++) {
|
||||
fflush(stdout);
|
||||
address = i + j;
|
||||
esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
|
||||
if (ret == ESP_OK) {
|
||||
printf("%02x ", address);
|
||||
if (address == 0x18) {
|
||||
echo_base_connected_flag |= 0xF0;
|
||||
} else if (address == 0x43) {
|
||||
echo_base_connected_flag |= 0x0F;
|
||||
}
|
||||
} else if (ret == ESP_ERR_TIMEOUT) {
|
||||
printf("UU ");
|
||||
} else {
|
||||
printf("-- ");
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
is_echo_base_connected_ = (echo_base_connected_flag == 0xFF);
|
||||
}
|
||||
|
||||
void CheckEchoBaseConnection() {
|
||||
if (is_echo_base_connected_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pop error page
|
||||
InitializeSpi();
|
||||
InitializeGc9107Display();
|
||||
InitializeButtons();
|
||||
display_->SetStatus("错误");
|
||||
display_->SetEmotion("sad");
|
||||
display_->SetChatMessage("system", "Echo Base\n未连接");
|
||||
|
||||
while (1) {
|
||||
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// Rerun detection
|
||||
I2cDetect();
|
||||
if (is_echo_base_connected_) {
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
I2cDetect();
|
||||
if (is_echo_base_connected_) {
|
||||
ESP_LOGI(TAG, "Atomic Echo Base is reconnected");
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = GPIO_NUM_21;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = GPIO_NUM_17;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeGc9107Display() {
|
||||
ESP_LOGI(TAG, "Init GC9107 display");
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = GPIO_NUM_15;
|
||||
io_config.dc_gpio_num = GPIO_NUM_33;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &io_handle));
|
||||
|
||||
ESP_LOGI(TAG, "Install GC9A01 panel driver");
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
gc9a01_vendor_config_t gc9107_vendor_config = {
|
||||
.init_cmds = gc9107_lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(gc9107_lcd_init_cmds) / sizeof(gc9a01_lcd_init_cmd_t),
|
||||
};
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_34; // Set to -1 if not use
|
||||
panel_config.rgb_endian = LCD_RGB_ENDIAN_BGR;
|
||||
panel_config.bits_per_pixel = 16; // Implemented by LCD command `3Ah` (16/18)
|
||||
panel_config.vendor_config = &gc9107_vendor_config;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
|
||||
|
||||
display_ = new LcdDisplay(io_handle, panel_handle, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = font_emoji_32_init(),
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
}
|
||||
|
||||
public:
|
||||
AtomS3EchoBaseBoard() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
I2cDetect();
|
||||
CheckEchoBaseConnection();
|
||||
InitializeSpi();
|
||||
InitializeGc9107Display();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_1,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_GPIO_PA,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
false);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(AtomS3EchoBaseBoard);
|
||||
43
main/boards/atoms3-echo-base/config.h
Normal file
43
main/boards/atoms3-echo-base/config.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
// AtomS3+EchoBase Board configuration
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_NC
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_8
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_7
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_5
|
||||
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_38
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_39
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_GPIO_PA GPIO_NUM_NC
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_NC
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_41
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 128
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 32
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_16
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
14
main/boards/atoms3-echo-base/config.json
Normal file
14
main/boards/atoms3-echo-base/config.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "atoms3-echo-base",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM=n",
|
||||
"CONFIG_USE_AUDIO_PROCESSING=n",
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_8M.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -96,6 +96,7 @@ private:
|
||||
Lp5562* lp5562_;
|
||||
Display* display_;
|
||||
Button boot_button_;
|
||||
bool is_echo_base_connected_ = false;
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
@@ -119,6 +120,8 @@ private:
|
||||
}
|
||||
|
||||
void I2cDetect() {
|
||||
is_echo_base_connected_ = false;
|
||||
uint8_t echo_base_connected_flag = 0x00;
|
||||
uint8_t address;
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
|
||||
for (int i = 0; i < 128; i += 16) {
|
||||
@@ -129,6 +132,11 @@ private:
|
||||
esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
|
||||
if (ret == ESP_OK) {
|
||||
printf("%02x ", address);
|
||||
if (address == 0x18) {
|
||||
echo_base_connected_flag |= 0xF0;
|
||||
} else if (address == 0x43) {
|
||||
echo_base_connected_flag |= 0x0F;
|
||||
}
|
||||
} else if (ret == ESP_ERR_TIMEOUT) {
|
||||
printf("UU ");
|
||||
} else {
|
||||
@@ -137,6 +145,39 @@ private:
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
is_echo_base_connected_ = (echo_base_connected_flag == 0xFF);
|
||||
}
|
||||
|
||||
void CheckEchoBaseConnection() {
|
||||
if (is_echo_base_connected_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pop error page
|
||||
InitializeLp5562();
|
||||
InitializeSpi();
|
||||
InitializeGc9107Display();
|
||||
InitializeButtons();
|
||||
display_->SetStatus("错误");
|
||||
display_->SetEmotion("sad");
|
||||
display_->SetChatMessage("system", "Echo Base\n未连接");
|
||||
|
||||
while (1) {
|
||||
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
// Rerun detection
|
||||
I2cDetect();
|
||||
if (is_echo_base_connected_) {
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
I2cDetect();
|
||||
if (is_echo_base_connected_) {
|
||||
ESP_LOGI(TAG, "Atomic Echo Base is reconnected");
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitializePi4ioe() {
|
||||
@@ -224,6 +265,7 @@ public:
|
||||
AtomS3rEchoBaseBoard() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
I2cDetect();
|
||||
CheckEchoBaseConnection();
|
||||
InitializePi4ioe();
|
||||
InitializeLp5562();
|
||||
InitializeSpi();
|
||||
@@ -233,13 +275,20 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new Es8311AudioCodec(i2c_bus_, I2C_NUM_1, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_GPIO_PA, AUDIO_CODEC_ES8311_ADDR, false);
|
||||
}
|
||||
return audio_codec;
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_1,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_GPIO_PA,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
false);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
|
||||
12
main/boards/atoms3r-echo-base/config.json
Normal file
12
main/boards/atoms3r-echo-base/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "atoms3r-echo-base",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_8M.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -30,7 +30,22 @@
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define TOUCH_BUTTON_GPIO GPIO_NUM_5
|
||||
#define ASR_BUTTON_GPIO GPIO_NUM_19
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_2
|
||||
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_4
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_15
|
||||
#define DISPLAY_WIDTH 128
|
||||
|
||||
#if CONFIG_OLED_SSD1306_128X32
|
||||
#define DISPLAY_HEIGHT 32
|
||||
#elif CONFIG_OLED_SSD1306_128X64
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#else
|
||||
#error "未选择 OLED 屏幕类型"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
|
||||
21
main/boards/bread-compact-esp32/config.json
Normal file
21
main/boards/bread-compact-esp32/config.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"target": "esp32",
|
||||
"builds": [
|
||||
{
|
||||
"name": "bread-compact-esp32",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_4M.csv\"",
|
||||
"CONFIG_OLED_SSD1306_128X64=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bread-compact-esp32-128x32",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_4M.csv\"",
|
||||
"CONFIG_OLED_SSD1306_128X32=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,18 +6,40 @@
|
||||
#include "config.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "led/single_led.h"
|
||||
|
||||
#include "display/ssd1306_display.h"
|
||||
#include <wifi_station.h>
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
|
||||
#define TAG "ESP32-MarsbearSupport"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_14_1);
|
||||
LV_FONT_DECLARE(font_awesome_14_1);
|
||||
|
||||
|
||||
class CompactWifiBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
Button touch_button_;
|
||||
Button asr_button_;
|
||||
|
||||
i2c_master_bus_handle_t display_i2c_bus_;
|
||||
|
||||
void InitializeDisplayI2c() {
|
||||
i2c_master_bus_config_t bus_config = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = DISPLAY_SDA_PIN,
|
||||
.scl_io_num = DISPLAY_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &display_i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
|
||||
@@ -39,6 +61,12 @@ private:
|
||||
gpio_set_level(BUILTIN_LED_GPIO, 1);
|
||||
app.ToggleChatState();
|
||||
});
|
||||
|
||||
asr_button_.OnClick([this]() {
|
||||
std::string wake_word="你好小智";
|
||||
Application::GetInstance().WakeWordInvoke(wake_word);
|
||||
});
|
||||
|
||||
touch_button_.OnPressDown([this]() {
|
||||
gpio_set_level(BUILTIN_LED_GPIO, 1);
|
||||
Application::GetInstance().StartListening();
|
||||
@@ -57,8 +85,9 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
CompactWifiBoard() : boot_button_(BOOT_BUTTON_GPIO), touch_button_(TOUCH_BUTTON_GPIO)
|
||||
CompactWifiBoard() : boot_button_(BOOT_BUTTON_GPIO), touch_button_(TOUCH_BUTTON_GPIO), asr_button_(ASR_BUTTON_GPIO)
|
||||
{
|
||||
InitializeDisplayI2c();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
}
|
||||
@@ -75,6 +104,12 @@ public:
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
static Ssd1306Display display(display_i2c_bus_, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y,
|
||||
&font_puhui_14_1, &font_awesome_14_1);
|
||||
return &display;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CompactWifiBoard);
|
||||
|
||||
@@ -36,7 +36,15 @@
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_41
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_42
|
||||
#define DISPLAY_WIDTH 128
|
||||
|
||||
#if CONFIG_OLED_SSD1306_128X32
|
||||
#define DISPLAY_HEIGHT 32
|
||||
#elif CONFIG_OLED_SSD1306_128X64
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#else
|
||||
#error "未选择 OLED 屏幕类型"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
|
||||
|
||||
17
main/boards/bread-compact-ml307/config.json
Normal file
17
main/boards/bread-compact-ml307/config.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "bread-compact-ml307",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_OLED_SSD1306_128X32=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bread-compact-ml307-128x64",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_OLED_SSD1306_128X64=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -37,7 +37,15 @@
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_41
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_42
|
||||
#define DISPLAY_WIDTH 128
|
||||
|
||||
#if CONFIG_OLED_SSD1306_128X32
|
||||
#define DISPLAY_HEIGHT 32
|
||||
#elif CONFIG_OLED_SSD1306_128X64
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#else
|
||||
#error "未选择 OLED 屏幕类型"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
|
||||
|
||||
17
main/boards/bread-compact-wifi/config.json
Normal file
17
main/boards/bread-compact-wifi/config.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "bread-compact-wifi",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_OLED_SSD1306_128X32=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bread-compact-wifi-128x64",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_OLED_SSD1306_128X64=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,14 +1,46 @@
|
||||
#include "board.h"
|
||||
#include "system_info.h"
|
||||
#include "settings.h"
|
||||
#include "display/no_display.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_chip_info.h>
|
||||
#include <esp_random.h>
|
||||
|
||||
#define TAG "Board"
|
||||
|
||||
Board::Board() {
|
||||
Settings settings("board", true);
|
||||
uuid_ = settings.GetString("uuid");
|
||||
if (uuid_.empty()) {
|
||||
uuid_ = GenerateUuid();
|
||||
settings.SetString("uuid", uuid_);
|
||||
}
|
||||
ESP_LOGI(TAG, "UUID: %s", uuid_.c_str());
|
||||
}
|
||||
|
||||
std::string Board::GenerateUuid() {
|
||||
// UUID v4 需要 16 字节的随机数据
|
||||
uint8_t uuid[16];
|
||||
|
||||
// 使用 ESP32 的硬件随机数生成器
|
||||
esp_fill_random(uuid, sizeof(uuid));
|
||||
|
||||
// 设置版本 (版本 4) 和变体位
|
||||
uuid[6] = (uuid[6] & 0x0F) | 0x40; // 版本 4
|
||||
uuid[8] = (uuid[8] & 0x3F) | 0x80; // 变体 1
|
||||
|
||||
// 将字节转换为标准的 UUID 字符串格式
|
||||
char uuid_str[37];
|
||||
snprintf(uuid_str, sizeof(uuid_str),
|
||||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
uuid[0], uuid[1], uuid[2], uuid[3],
|
||||
uuid[4], uuid[5], uuid[6], uuid[7],
|
||||
uuid[8], uuid[9], uuid[10], uuid[11],
|
||||
uuid[12], uuid[13], uuid[14], uuid[15]);
|
||||
|
||||
return std::string(uuid_str);
|
||||
}
|
||||
|
||||
bool Board::GetBatteryLevel(int &level, bool& charging) {
|
||||
@@ -28,10 +60,12 @@ Led* Board::GetLed() {
|
||||
std::string Board::GetJson() {
|
||||
/*
|
||||
{
|
||||
"version": 2,
|
||||
"flash_size": 4194304,
|
||||
"psram_size": 0,
|
||||
"minimum_free_heap_size": 123456,
|
||||
"mac_address": "00:00:00:00:00:00",
|
||||
"uuid": "00000000-0000-0000-0000-000000000000",
|
||||
"chip_model_name": "esp32s3",
|
||||
"chip_info": {
|
||||
"model": 1,
|
||||
@@ -57,13 +91,18 @@ std::string Board::GetJson() {
|
||||
],
|
||||
"ota": {
|
||||
"label": "ota_0"
|
||||
},
|
||||
"board": {
|
||||
...
|
||||
}
|
||||
}
|
||||
*/
|
||||
std::string json = "{";
|
||||
json += "\"version\":2,";
|
||||
json += "\"flash_size\":" + std::to_string(SystemInfo::GetFlashSize()) + ",";
|
||||
json += "\"minimum_free_heap_size\":" + std::to_string(SystemInfo::GetMinimumFreeHeapSize()) + ",";
|
||||
json += "\"mac_address\":\"" + SystemInfo::GetMacAddress() + "\",";
|
||||
json += "\"uuid\":\"" + uuid_ + "\",";
|
||||
json += "\"chip_model_name\":\"" + SystemInfo::GetChipModelName() + "\",";
|
||||
json += "\"chip_info\":{";
|
||||
|
||||
|
||||
@@ -20,18 +20,20 @@ private:
|
||||
|
||||
protected:
|
||||
Board();
|
||||
std::string GenerateUuid();
|
||||
|
||||
// 软件生成的设备唯一标识
|
||||
std::string uuid_;
|
||||
|
||||
public:
|
||||
static Board& GetInstance() {
|
||||
static Board* instance = nullptr;
|
||||
if (nullptr == instance) {
|
||||
instance = static_cast<Board*>(create_board());
|
||||
}
|
||||
static Board* instance = static_cast<Board*>(create_board());
|
||||
return *instance;
|
||||
}
|
||||
|
||||
virtual void StartNetwork() = 0;
|
||||
virtual ~Board() = default;
|
||||
virtual std::string GetBoardType() = 0;
|
||||
virtual std::string GetUuid() { return uuid_; }
|
||||
virtual Led* GetLed();
|
||||
virtual AudioCodec* GetAudioCodec() = 0;
|
||||
virtual Display* GetDisplay();
|
||||
@@ -39,7 +41,7 @@ public:
|
||||
virtual WebSocket* CreateWebSocket() = 0;
|
||||
virtual Mqtt* CreateMqtt() = 0;
|
||||
virtual Udp* CreateUdp() = 0;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) = 0;
|
||||
virtual void StartNetwork() = 0;
|
||||
virtual const char* GetNetworkStateIcon() = 0;
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging);
|
||||
virtual std::string GetJson();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "application.h"
|
||||
#include "display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "assets/zh/binary.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
@@ -11,33 +12,20 @@
|
||||
#include <web_socket.h>
|
||||
#include <ml307_mqtt.h>
|
||||
#include <ml307_udp.h>
|
||||
#include <opus_encoder.h>
|
||||
|
||||
static const char *TAG = "Ml307Board";
|
||||
|
||||
static std::string csq_to_string(int csq) {
|
||||
if (csq == -1) {
|
||||
return "No network";
|
||||
} else if (csq >= 0 && csq <= 9) {
|
||||
return "Very bad";
|
||||
} else if (csq >= 10 && csq <= 14) {
|
||||
return "Bad";
|
||||
} else if (csq >= 15 && csq <= 19) {
|
||||
return "Fair";
|
||||
} else if (csq >= 20 && csq <= 24) {
|
||||
return "Good";
|
||||
} else if (csq >= 25 && csq <= 31) {
|
||||
return "Very good";
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
|
||||
Ml307Board::Ml307Board(gpio_num_t tx_pin, gpio_num_t rx_pin, size_t rx_buffer_size) : modem_(tx_pin, rx_pin, rx_buffer_size) {
|
||||
}
|
||||
|
||||
std::string Ml307Board::GetBoardType() {
|
||||
return "ml307";
|
||||
}
|
||||
|
||||
void Ml307Board::StartNetwork() {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetStatus("初始化模块");
|
||||
display->SetStatus("检测模组...");
|
||||
modem_.SetDebug(false);
|
||||
modem_.SetBaudRate(921600);
|
||||
|
||||
@@ -60,10 +48,10 @@ void Ml307Board::WaitForNetworkReady() {
|
||||
display->SetStatus("等待网络...");
|
||||
int result = modem_.WaitForNetworkReady();
|
||||
if (result == -1) {
|
||||
application.Alert("Error", "请插入SIM卡");
|
||||
application.Alert("PIN_ERROR", "请插入SIM卡", "sad", std::string_view(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start));
|
||||
return;
|
||||
} else if (result == -2) {
|
||||
application.Alert("Error", "无法接入网络,请检查流量卡状态");
|
||||
application.Alert("REG_ERROR", "无法接入网络,请检查流量卡状态", "sad", std::string_view(p3_err_reg_start, p3_err_reg_end - p3_err_reg_start));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -95,16 +83,6 @@ Udp* Ml307Board::CreateUdp() {
|
||||
return new Ml307Udp(modem_, 0);
|
||||
}
|
||||
|
||||
bool Ml307Board::GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) {
|
||||
if (!modem_.network_ready()) {
|
||||
return false;
|
||||
}
|
||||
network_name = modem_.GetCarrierName();
|
||||
signal_quality = modem_.GetCsq();
|
||||
signal_quality_text = csq_to_string(signal_quality);
|
||||
return signal_quality != -1;
|
||||
}
|
||||
|
||||
const char* Ml307Board::GetNetworkStateIcon() {
|
||||
if (!modem_.network_ready()) {
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
|
||||
@@ -13,12 +13,12 @@ protected:
|
||||
|
||||
public:
|
||||
Ml307Board(gpio_num_t tx_pin, gpio_num_t rx_pin, size_t rx_buffer_size = 4096);
|
||||
virtual std::string GetBoardType() override;
|
||||
virtual void StartNetwork() override;
|
||||
virtual Http* CreateHttp() override;
|
||||
virtual WebSocket* CreateWebSocket() override;
|
||||
virtual Mqtt* CreateMqtt() override;
|
||||
virtual Udp* CreateUdp() override;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
|
||||
virtual const char* GetNetworkStateIcon() override;
|
||||
virtual void SetPowerSaveMode(bool enabled) override;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "system_info.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "settings.h"
|
||||
#include "assets/zh/binary.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
@@ -22,20 +23,6 @@
|
||||
|
||||
static const char *TAG = "WifiBoard";
|
||||
|
||||
static std::string rssi_to_string(int rssi) {
|
||||
if (rssi >= -55) {
|
||||
return "Very good";
|
||||
} else if (rssi >= -65) {
|
||||
return "Good";
|
||||
} else if (rssi >= -75) {
|
||||
return "Fair";
|
||||
} else if (rssi >= -85) {
|
||||
return "Poor";
|
||||
} else {
|
||||
return "No network";
|
||||
}
|
||||
}
|
||||
|
||||
WifiBoard::WifiBoard() {
|
||||
Settings settings("wifi", true);
|
||||
wifi_config_mode_ = settings.GetInt("force_ap") == 1;
|
||||
@@ -45,9 +32,12 @@ WifiBoard::WifiBoard() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string WifiBoard::GetBoardType() {
|
||||
return "wifi";
|
||||
}
|
||||
|
||||
void WifiBoard::EnterWifiConfigMode() {
|
||||
auto& application = Application::GetInstance();
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
application.SetDeviceState(kDeviceStateWifiConfiguring);
|
||||
|
||||
auto& wifi_ap = WifiConfigurationAp::GetInstance();
|
||||
@@ -55,15 +45,14 @@ void WifiBoard::EnterWifiConfigMode() {
|
||||
wifi_ap.Start();
|
||||
|
||||
// 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
|
||||
std::string hint = "请在手机上连接热点 ";
|
||||
std::string hint = "手机连接热点 ";
|
||||
hint += wifi_ap.GetSsid();
|
||||
hint += ",然后打开浏览器访问 ";
|
||||
hint += "\n浏览器访问 ";
|
||||
hint += wifi_ap.GetWebServerUrl();
|
||||
|
||||
display->SetStatus(hint);
|
||||
hint += "\n\n";
|
||||
|
||||
// 播报配置 WiFi 的提示
|
||||
application.Alert("Info", "进入配网模式");
|
||||
application.Alert("配网模式", hint, "", std::string_view(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start));
|
||||
|
||||
// Wait forever until reset after configuration
|
||||
while (true) {
|
||||
@@ -93,11 +82,11 @@ void WifiBoard::StartNetwork() {
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
wifi_station.OnScanBegin([this]() {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->ShowNotification("正在扫描 WiFi 网络", 30000);
|
||||
display->ShowNotification("扫描 WiFi...", 30000);
|
||||
});
|
||||
wifi_station.OnConnect([this](const std::string& ssid) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->ShowNotification(std::string("正在连接 ") + ssid, 30000);
|
||||
display->ShowNotification(std::string("连接 ") + ssid + "...", 30000);
|
||||
});
|
||||
wifi_station.OnConnected([this](const std::string& ssid) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
@@ -138,24 +127,6 @@ Udp* WifiBoard::CreateUdp() {
|
||||
return new EspUdp();
|
||||
}
|
||||
|
||||
bool WifiBoard::GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) {
|
||||
if (wifi_config_mode_) {
|
||||
auto& wifi_ap = WifiConfigurationAp::GetInstance();
|
||||
network_name = wifi_ap.GetSsid();
|
||||
signal_quality = -99;
|
||||
signal_quality_text = wifi_ap.GetWebServerUrl();
|
||||
return true;
|
||||
}
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
if (!wifi_station.IsConnected()) {
|
||||
return false;
|
||||
}
|
||||
network_name = wifi_station.GetSsid();
|
||||
signal_quality = wifi_station.GetRssi();
|
||||
signal_quality_text = rssi_to_string(signal_quality);
|
||||
return signal_quality != -1;
|
||||
}
|
||||
|
||||
const char* WifiBoard::GetNetworkStateIcon() {
|
||||
if (wifi_config_mode_) {
|
||||
return FONT_AWESOME_WIFI;
|
||||
|
||||
@@ -12,12 +12,12 @@ protected:
|
||||
virtual std::string GetBoardJson() override;
|
||||
|
||||
public:
|
||||
virtual std::string GetBoardType() override;
|
||||
virtual void StartNetwork() override;
|
||||
virtual Http* CreateHttp() override;
|
||||
virtual WebSocket* CreateWebSocket() override;
|
||||
virtual Mqtt* CreateMqtt() override;
|
||||
virtual Udp* CreateUdp() override;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
|
||||
virtual const char* GetNetworkStateIcon() override;
|
||||
virtual void SetPowerSaveMode(bool enabled) override;
|
||||
virtual void ResetWifiConfiguration();
|
||||
|
||||
40
main/boards/du-chatx/config.h
Normal file
40
main/boards/du-chatx/config.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_39
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_38
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_7
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_40
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_42
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_2
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_48
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define TOUCH_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_9
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_18
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_17
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_8
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_20
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_16
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 160
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_INVERT_COLOR false
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_RGB
|
||||
#define DISPLAY_OFFSET_X 2
|
||||
#define DISPLAY_OFFSET_Y 1
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
9
main/boards/du-chatx/config.json
Normal file
9
main/boards/du-chatx/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "du-chatx",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
130
main/boards/du-chatx/du-chatx-wifi.cc
Normal file
130
main/boards/du-chatx/du-chatx-wifi.cc
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "wifi_board.h"
|
||||
#include "audio_codecs/no_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "led/single_led.h"
|
||||
|
||||
#include <wifi_station.h>
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/spi_common.h>
|
||||
|
||||
#if defined(LCD_ILI9341_240X320) || defined(LCD_ILI9341_240X320_NO_IPS)
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#endif
|
||||
|
||||
#define TAG "DuChatX"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
class DuChatX : public WifiBoard {
|
||||
private:
|
||||
|
||||
Button boot_button_;
|
||||
LcdDisplay* display_;
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
#if defined(LCD_ILI9341_240X320) || defined(LCD_ILI9341_240X320_NO_IPS)
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
|
||||
#else
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
#endif
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
|
||||
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
display_ = new LcdDisplay(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = DISPLAY_HEIGHT >= 240 ? font_emoji_64_init() : font_emoji_32_init(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
DuChatX() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
static SingleLed led(BUILTIN_LED_GPIO);
|
||||
return &led;
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(DuChatX);
|
||||
9
main/boards/esp-box-3/config.json
Normal file
9
main/boards/esp-box-3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp-box-3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -134,6 +134,7 @@ private:
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -146,13 +147,20 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new BoxAudioCodec(i2c_bus_, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
}
|
||||
return audio_codec;
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
|
||||
98
main/boards/esp-sparkbot/chassis.cc
Normal file
98
main/boards/esp-sparkbot/chassis.cc
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
ESP-SparkBot 的底座
|
||||
https://gitee.com/esp-friends/esp_sparkbot/tree/master/example/tank/c2_tracked_chassis
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "iot/thing.h"
|
||||
#include "board.h"
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/uart.h>
|
||||
#include <esp_log.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "boards/esp-sparkbot/config.h"
|
||||
|
||||
#define TAG "Chassis"
|
||||
|
||||
namespace iot {
|
||||
|
||||
class Chassis : public Thing {
|
||||
private:
|
||||
light_mode_t light_mode_ = LIGHT_MODE_ALWAYS_ON;
|
||||
|
||||
void SendUartMessage(const char * command_str) {
|
||||
uint8_t len = strlen(command_str);
|
||||
uart_write_bytes(ECHO_UART_PORT_NUM, command_str, len);
|
||||
ESP_LOGI(TAG, "Sent command: %s", command_str);
|
||||
}
|
||||
|
||||
void InitializeEchoUart() {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = ECHO_UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||
ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, UART_ECHO_TXD, UART_ECHO_RXD, UART_ECHO_RTS, UART_ECHO_CTS));
|
||||
|
||||
SendUartMessage("w2");
|
||||
}
|
||||
|
||||
public:
|
||||
Chassis() : Thing("Chassis", "小机器人的底座:有履带可以移动;可以调整灯光效果"), light_mode_(LIGHT_MODE_ALWAYS_ON) {
|
||||
InitializeEchoUart();
|
||||
|
||||
// 定义设备的属性
|
||||
properties_.AddNumberProperty("light_mode", "灯光效果编号", [this]() -> int {
|
||||
return (light_mode_ - 2 <= 0) ? 1 : light_mode_ - 2;
|
||||
});
|
||||
|
||||
// 定义设备可以被远程执行的指令
|
||||
methods_.AddMethod("GoForward", "向前走", ParameterList(), [this](const ParameterList& parameters) {
|
||||
SendUartMessage("x0.0 y1.0");
|
||||
});
|
||||
|
||||
methods_.AddMethod("GoBack", "向后退", ParameterList(), [this](const ParameterList& parameters) {
|
||||
SendUartMessage("x0.0 y-1.0");
|
||||
});
|
||||
|
||||
methods_.AddMethod("TurnLeft", "向左转", ParameterList(), [this](const ParameterList& parameters) {
|
||||
SendUartMessage("x-1.0 y0.0");
|
||||
});
|
||||
|
||||
methods_.AddMethod("TurnRight", "向右转", ParameterList(), [this](const ParameterList& parameters) {
|
||||
SendUartMessage("x1.0 y0.0");
|
||||
});
|
||||
|
||||
methods_.AddMethod("Dance", "跳舞", ParameterList(), [this](const ParameterList& parameters) {
|
||||
SendUartMessage("d1");
|
||||
light_mode_ = LIGHT_MODE_MAX;
|
||||
});
|
||||
|
||||
methods_.AddMethod("SwitchLightMode", "打开灯", ParameterList({
|
||||
Parameter("lightmode", "1到6之间的整数", kValueTypeNumber, true)
|
||||
}), [this](const ParameterList& parameters) {
|
||||
char command_str[5] = {'w', 0, 0};
|
||||
char mode = static_cast<char>(parameters["lightmode"].number()) + 2;
|
||||
|
||||
ESP_LOGI(TAG, "Input Light Mode: %c", (mode + '0'));
|
||||
|
||||
if (mode >= 3 && mode <= 8) {
|
||||
command_str[1] = mode + '0';
|
||||
SendUartMessage(command_str);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace iot
|
||||
|
||||
DECLARE_THING(Chassis);
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/uart.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 16000
|
||||
@@ -26,8 +27,8 @@
|
||||
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 240
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
@@ -42,5 +43,31 @@
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_46
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define UART_ECHO_TXD GPIO_NUM_38
|
||||
#define UART_ECHO_RXD GPIO_NUM_48
|
||||
#define UART_ECHO_RTS (-1)
|
||||
#define UART_ECHO_CTS (-1)
|
||||
|
||||
#define MOTOR_SPEED_MAX 100
|
||||
#define MOTOR_SPEED_80 80
|
||||
#define MOTOR_SPEED_60 60
|
||||
#define MOTOR_SPEED_MIN 0
|
||||
|
||||
#define ECHO_UART_PORT_NUM UART_NUM_1
|
||||
#define ECHO_UART_BAUD_RATE (115200)
|
||||
#define BUF_SIZE (1024)
|
||||
|
||||
typedef enum {
|
||||
LIGHT_MODE_CHARGING_BREATH = 0,
|
||||
LIGHT_MODE_POWER_LOW,
|
||||
LIGHT_MODE_ALWAYS_ON,
|
||||
LIGHT_MODE_BLINK,
|
||||
LIGHT_MODE_WHITE_BREATH_SLOW,
|
||||
LIGHT_MODE_WHITE_BREATH_FAST,
|
||||
LIGHT_MODE_FLOWING,
|
||||
LIGHT_MODE_SHOW,
|
||||
LIGHT_MODE_SLEEP,
|
||||
LIGHT_MODE_MAX
|
||||
} light_mode_t;
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
|
||||
9
main/boards/esp-sparkbot/config.json
Normal file
9
main/boards/esp-sparkbot/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp-sparkbot",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -126,6 +126,8 @@ private:
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
thing_manager.AddThing(iot::CreateThing("Chassis"));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
9
main/boards/esp32-s3-touch-amoled-1.8/config.json
Normal file
9
main/boards/esp32-s3-touch-amoled-1.8/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-amoled-1.8",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
68
main/boards/esp32-s3-touch-lcd-1.46/config.h
Normal file
68
main/boards/esp32-s3-touch-lcd-1.46/config.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_2
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_15
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_39
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_47
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_48
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_38
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_10
|
||||
#define I2C_SDA_IO GPIO_NUM_11
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
|
||||
#define DISPLAY_WIDTH 412
|
||||
#define DISPLAY_HEIGHT 412
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define QSPI_LCD_H_RES (412)
|
||||
#define QSPI_LCD_V_RES (412)
|
||||
#define QSPI_LCD_BIT_PER_PIXEL (16)
|
||||
|
||||
#define QSPI_LCD_HOST SPI2_HOST
|
||||
#define QSPI_PIN_NUM_LCD_PCLK GPIO_NUM_40
|
||||
#define QSPI_PIN_NUM_LCD_CS GPIO_NUM_21
|
||||
#define QSPI_PIN_NUM_LCD_DATA0 GPIO_NUM_46
|
||||
#define QSPI_PIN_NUM_LCD_DATA1 GPIO_NUM_45
|
||||
#define QSPI_PIN_NUM_LCD_DATA2 GPIO_NUM_42
|
||||
#define QSPI_PIN_NUM_LCD_DATA3 GPIO_NUM_41
|
||||
#define QSPI_PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
#define QSPI_PIN_NUM_LCD_BL GPIO_NUM_5
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define TP_PORT (I2C_NUM_1)
|
||||
#define TP_PIN_NUM_SDA (I2C_SDA_IO)
|
||||
#define TP_PIN_NUM_SCL (I2C_SCL_IO)
|
||||
#define TP_PIN_NUM_RST (GPIO_NUM_NC)
|
||||
#define TP_PIN_NUM_INT (GPIO_NUM_4)
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN QSPI_PIN_NUM_LCD_BL
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define TAIJIPI_SPD2010_PANEL_BUS_QSPI_CONFIG(sclk, d0, d1, d2, d3, max_trans_sz) \
|
||||
{ \
|
||||
.data0_io_num = d0, \
|
||||
.data1_io_num = d1, \
|
||||
.sclk_io_num = sclk, \
|
||||
.data2_io_num = d2, \
|
||||
.data3_io_num = d3, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
9
main/boards/esp32-s3-touch-lcd-1.46/config.json
Normal file
9
main/boards/esp32-s3-touch-lcd-1.46/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-lcd-1.46",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
199
main/boards/esp32-s3-touch-lcd-1.46/esp32-s3-touch-lcd-1.46.cc
Normal file
199
main/boards/esp32-s3-touch-lcd-1.46/esp32-s3-touch-lcd-1.46.cc
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "wifi_board.h"
|
||||
#include "audio_codecs/no_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "iot/thing_manager.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_spd2010.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
#include "lcd_display.h"
|
||||
#define TAG "waveshare_lcd_1_46"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
|
||||
// 在waveshare_lcd_1_46类之前添加新的显示类
|
||||
class CustomLcdDisplay : public LcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_area_t * area = (lv_area_t *)lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
area->x1 = (x1 >> 2) << 2; // round the start of coordinate down to the nearest 4M number
|
||||
area->x2 = ((x2 >> 2) << 2) + 3; // round the end of coordinate up to the nearest 4N+3 number
|
||||
}
|
||||
|
||||
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle,
|
||||
esp_lcd_panel_handle_t panel_handle,
|
||||
gpio_num_t backlight_pin,
|
||||
bool backlight_output_invert,
|
||||
int width,
|
||||
int height,
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
bool mirror_x,
|
||||
bool mirror_y,
|
||||
bool swap_xy)
|
||||
: LcdDisplay(io_handle, panel_handle, backlight_pin, backlight_output_invert,
|
||||
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy,
|
||||
{
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = font_emoji_64_init(),
|
||||
}) {
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
LcdDisplay* display_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void i2c_dev_tca9554_init(void)
|
||||
{
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
|
||||
// uint32_t input_level_mask = 0;
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_INPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输入
|
||||
// ret = esp_io_expander_get_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, &input_level_mask); // 获取引脚 EXIO0 和 EXIO1 的电平状态,存放在 input_level_mask 中
|
||||
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO2 和 EXIO3 模式为输出
|
||||
// ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, 1); // 将引脚电平设置为 1
|
||||
// ret = esp_io_expander_print_state(io_expander); // 打印引脚状态
|
||||
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输出
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
|
||||
const spi_bus_config_t bus_config = TAIJIPI_SPD2010_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
|
||||
QSPI_PIN_NUM_LCD_DATA0,
|
||||
QSPI_PIN_NUM_LCD_DATA1,
|
||||
QSPI_PIN_NUM_LCD_DATA2,
|
||||
QSPI_PIN_NUM_LCD_DATA3,
|
||||
QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void Initializespd2010Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
|
||||
const esp_lcd_panel_io_spi_config_t io_config = SPD2010_PANEL_IO_QSPI_CONFIG(QSPI_PIN_NUM_LCD_CS, NULL, NULL);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)QSPI_LCD_HOST, &io_config, &panel_io));
|
||||
|
||||
ESP_LOGI(TAG, "Install SPD2010 panel driver");
|
||||
|
||||
spd2010_vendor_config_t vendor_config = {
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = QSPI_PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||
.bits_per_pixel = QSPI_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_spd2010(panel_io, &panel_config, &panel));
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
display_ = new CustomLcdDisplay(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
i2c_dev_tca9554_init();
|
||||
InitializeSpi();
|
||||
Initializespd2010Display();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, I2S_STD_SLOT_LEFT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN, I2S_STD_SLOT_RIGHT); // I2S_STD_SLOT_LEFT / I2S_STD_SLOT_RIGHT / I2S_STD_SLOT_BOTH
|
||||
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
67
main/boards/esp32-s3-touch-lcd-1.85/config.h
Normal file
67
main/boards/esp32-s3-touch-lcd-1.85/config.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_2
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_15
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_39
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_47
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_48
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_38
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_10
|
||||
#define I2C_SDA_IO GPIO_NUM_11
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
|
||||
#define DISPLAY_WIDTH 360
|
||||
#define DISPLAY_HEIGHT 360
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define QSPI_LCD_H_RES (360)
|
||||
#define QSPI_LCD_V_RES (360)
|
||||
#define QSPI_LCD_BIT_PER_PIXEL (16)
|
||||
|
||||
#define QSPI_LCD_HOST SPI2_HOST
|
||||
#define QSPI_PIN_NUM_LCD_PCLK GPIO_NUM_40
|
||||
#define QSPI_PIN_NUM_LCD_CS GPIO_NUM_21
|
||||
#define QSPI_PIN_NUM_LCD_DATA0 GPIO_NUM_46
|
||||
#define QSPI_PIN_NUM_LCD_DATA1 GPIO_NUM_45
|
||||
#define QSPI_PIN_NUM_LCD_DATA2 GPIO_NUM_42
|
||||
#define QSPI_PIN_NUM_LCD_DATA3 GPIO_NUM_41
|
||||
#define QSPI_PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
#define QSPI_PIN_NUM_LCD_BL GPIO_NUM_5
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define TP_PORT (I2C_NUM_1)
|
||||
#define TP_PIN_NUM_SDA (GPIO_NUM_1)
|
||||
#define TP_PIN_NUM_SCL (GPIO_NUM_3)
|
||||
#define TP_PIN_NUM_RST (GPIO_NUM_NC)
|
||||
#define TP_PIN_NUM_INT (GPIO_NUM_4)
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN QSPI_PIN_NUM_LCD_BL
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(sclk, d0, d1, d2, d3, max_trans_sz) \
|
||||
{ \
|
||||
.data0_io_num = d0, \
|
||||
.data1_io_num = d1, \
|
||||
.sclk_io_num = sclk, \
|
||||
.data2_io_num = d2, \
|
||||
.data3_io_num = d3, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
9
main/boards/esp32-s3-touch-lcd-1.85/config.json
Normal file
9
main/boards/esp32-s3-touch-lcd-1.85/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-lcd-1.85",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
163
main/boards/esp32-s3-touch-lcd-1.85/esp32-s3-touch-lcd-1.85.cc
Normal file
163
main/boards/esp32-s3-touch-lcd-1.85/esp32-s3-touch-lcd-1.85.cc
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "wifi_board.h"
|
||||
#include "audio_codecs/no_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "iot/thing_manager.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_st77916.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
|
||||
#define TAG "waveshare_lcd_1_85"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
LcdDisplay* display_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void i2c_dev_tca9554_init(void)
|
||||
{
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
|
||||
// uint32_t input_level_mask = 0;
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_INPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输入
|
||||
// ret = esp_io_expander_get_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, &input_level_mask); // 获取引脚 EXIO0 和 EXIO1 的电平状态,存放在 input_level_mask 中
|
||||
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO2 和 EXIO3 模式为输出
|
||||
// ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, 1); // 将引脚电平设置为 1
|
||||
// ret = esp_io_expander_print_state(io_expander); // 打印引脚状态
|
||||
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输出
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
|
||||
const spi_bus_config_t bus_config = TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
|
||||
QSPI_PIN_NUM_LCD_DATA0,
|
||||
QSPI_PIN_NUM_LCD_DATA1,
|
||||
QSPI_PIN_NUM_LCD_DATA2,
|
||||
QSPI_PIN_NUM_LCD_DATA3,
|
||||
QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void Initializest77916Display() {
|
||||
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
|
||||
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(QSPI_PIN_NUM_LCD_CS, NULL, NULL);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)QSPI_LCD_HOST, &io_config, &panel_io));
|
||||
|
||||
ESP_LOGI(TAG, "Install ST77916 panel driver");
|
||||
|
||||
st77916_vendor_config_t vendor_config = {
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = QSPI_PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||
.bits_per_pixel = QSPI_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(panel_io, &panel_config, &panel));
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
|
||||
display_ = new LcdDisplay(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = font_emoji_64_init(),
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
i2c_dev_tca9554_init();
|
||||
InitializeSpi();
|
||||
Initializest77916Display();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, I2S_STD_SLOT_BOTH, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN, I2S_STD_SLOT_RIGHT); // I2S_STD_SLOT_LEFT / I2S_STD_SLOT_RIGHT / I2S_STD_SLOT_BOTH
|
||||
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
67
main/boards/esp32-s3-touch-lcd-1.85c/config.h
Normal file
67
main/boards/esp32-s3-touch-lcd-1.85c/config.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_2
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_15
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_39
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_47
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_48
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_38
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_10
|
||||
#define I2C_SDA_IO GPIO_NUM_11
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000
|
||||
|
||||
#define DISPLAY_WIDTH 360
|
||||
#define DISPLAY_HEIGHT 360
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define QSPI_LCD_H_RES (360)
|
||||
#define QSPI_LCD_V_RES (360)
|
||||
#define QSPI_LCD_BIT_PER_PIXEL (16)
|
||||
|
||||
#define QSPI_LCD_HOST SPI2_HOST
|
||||
#define QSPI_PIN_NUM_LCD_PCLK GPIO_NUM_40
|
||||
#define QSPI_PIN_NUM_LCD_CS GPIO_NUM_21
|
||||
#define QSPI_PIN_NUM_LCD_DATA0 GPIO_NUM_46
|
||||
#define QSPI_PIN_NUM_LCD_DATA1 GPIO_NUM_45
|
||||
#define QSPI_PIN_NUM_LCD_DATA2 GPIO_NUM_42
|
||||
#define QSPI_PIN_NUM_LCD_DATA3 GPIO_NUM_41
|
||||
#define QSPI_PIN_NUM_LCD_RST GPIO_NUM_NC
|
||||
#define QSPI_PIN_NUM_LCD_BL GPIO_NUM_5
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define TP_PORT (I2C_NUM_1)
|
||||
#define TP_PIN_NUM_SDA (I2C_SDA_IO)
|
||||
#define TP_PIN_NUM_SCL (I2C_SCL_IO)
|
||||
#define TP_PIN_NUM_RST (GPIO_NUM_NC)
|
||||
#define TP_PIN_NUM_INT (GPIO_NUM_4)
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN QSPI_PIN_NUM_LCD_BL
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(sclk, d0, d1, d2, d3, max_trans_sz) \
|
||||
{ \
|
||||
.data0_io_num = d0, \
|
||||
.data1_io_num = d1, \
|
||||
.sclk_io_num = sclk, \
|
||||
.data2_io_num = d2, \
|
||||
.data3_io_num = d3, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
9
main/boards/esp32-s3-touch-lcd-1.85c/config.json
Normal file
9
main/boards/esp32-s3-touch-lcd-1.85c/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-lcd-1.85c",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
162
main/boards/esp32-s3-touch-lcd-1.85c/esp32-s3-touch-lcd-1.85c.cc
Normal file
162
main/boards/esp32-s3-touch-lcd-1.85c/esp32-s3-touch-lcd-1.85c.cc
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "wifi_board.h"
|
||||
#include "audio_codecs/no_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "iot/thing_manager.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_st77916.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp_io_expander_tca9554.h"
|
||||
|
||||
#define TAG "waveshare_lcd_1_85c"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
LcdDisplay* display_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void i2c_dev_tca9554_init(void)
|
||||
{
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error");
|
||||
|
||||
// uint32_t input_level_mask = 0;
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_INPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输入
|
||||
// ret = esp_io_expander_get_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, &input_level_mask); // 获取引脚 EXIO0 和 EXIO1 的电平状态,存放在 input_level_mask 中
|
||||
|
||||
// ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO2 和 EXIO3 模式为输出
|
||||
// ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, 1); // 将引脚电平设置为 1
|
||||
// ret = esp_io_expander_print_state(io_expander); // 打印引脚状态
|
||||
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输出
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
|
||||
const spi_bus_config_t bus_config = TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
|
||||
QSPI_PIN_NUM_LCD_DATA0,
|
||||
QSPI_PIN_NUM_LCD_DATA1,
|
||||
QSPI_PIN_NUM_LCD_DATA2,
|
||||
QSPI_PIN_NUM_LCD_DATA3,
|
||||
QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void Initializest77916Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
|
||||
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(QSPI_PIN_NUM_LCD_CS, NULL, NULL);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)QSPI_LCD_HOST, &io_config, &panel_io));
|
||||
|
||||
ESP_LOGI(TAG, "Install ST77916 panel driver");
|
||||
|
||||
st77916_vendor_config_t vendor_config = {
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = QSPI_PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||
.bits_per_pixel = QSPI_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(panel_io, &panel_config, &panel));
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_disp_on_off(panel, true);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
|
||||
display_ = new LcdDisplay(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = font_emoji_64_init(),
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
i2c_dev_tca9554_init();
|
||||
InitializeSpi();
|
||||
Initializest77916Display();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, I2S_STD_SLOT_LEFT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN, I2S_STD_SLOT_RIGHT); // I2S_STD_SLOT_LEFT / I2S_STD_SLOT_RIGHT / I2S_STD_SLOT_BOTH
|
||||
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
9
main/boards/esp32s3-korvo2-v3/config.json
Normal file
9
main/boards/esp32s3-korvo2-v3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32s3-korvo2-v3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,13 +125,20 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new BoxAudioCodec(i2c_bus_, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
}
|
||||
return audio_codec;
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display *GetDisplay() override
|
||||
|
||||
9
main/boards/kevin-box-1/config.json
Normal file
9
main/boards/kevin-box-1/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "kevin-box-1",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
9
main/boards/kevin-box-2/config.json
Normal file
9
main/boards/kevin-box-2/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "kevin-box-2",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "led/single_led.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_spiffs.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_timer.h>
|
||||
@@ -64,17 +63,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void MountStorage() {
|
||||
// Mount the storage partition
|
||||
esp_vfs_spiffs_conf_t conf = {
|
||||
.base_path = "/storage",
|
||||
.partition_label = "storage",
|
||||
.max_files = 5,
|
||||
.format_if_mount_failed = true,
|
||||
};
|
||||
esp_vfs_spiffs_register(&conf);
|
||||
}
|
||||
|
||||
void Enable4GModule() {
|
||||
// Make GPIO HIGH to enable the 4G module
|
||||
gpio_config_t ml307_enable_config = {
|
||||
@@ -175,7 +163,6 @@ public:
|
||||
InitializeCodecI2c();
|
||||
axp2101_ = new Axp2101(codec_i2c_bus_, AXP2101_I2C_ADDR);
|
||||
|
||||
MountStorage();
|
||||
Enable4GModule();
|
||||
|
||||
InitializeButtons();
|
||||
|
||||
9
main/boards/kevin-c3/config.json
Normal file
9
main/boards/kevin-c3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32c3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "kevin-c3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
45
main/boards/kevin-sp-v3-dev/config.h
Normal file
45
main/boards/kevin-sp-v3-dev/config.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_DEFAULT_OUTPUT_VOLUME 90
|
||||
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_42
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_41
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_2
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_3
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_46
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_1
|
||||
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_38
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define RESET_NVS_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define RESET_FACTORY_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 280
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define BACKLIGHT_INVERT false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 20
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_48
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#define ML307_RX_PIN GPIO_NUM_12
|
||||
#define ML307_TX_PIN GPIO_NUM_13
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
132
main/boards/kevin-sp-v3-dev/kevin-sp-v3_board.cc
Normal file
132
main/boards/kevin-sp-v3-dev/kevin-sp-v3_board.cc
Normal file
@@ -0,0 +1,132 @@
|
||||
#include "wifi_board.h"
|
||||
#include "ml307_board.h"
|
||||
|
||||
#include "audio_codecs/no_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "led/single_led.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <wifi_station.h>
|
||||
|
||||
#define TAG "kevin-sp-v3"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_20_4);
|
||||
LV_FONT_DECLARE(font_awesome_20_4);
|
||||
|
||||
|
||||
// class KEVIN_SP_V3Board : public Ml307Board {
|
||||
class KEVIN_SP_V3Board : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t display_i2c_bus_;
|
||||
Button boot_button_;
|
||||
LcdDisplay* display_;
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = GPIO_NUM_47;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = GPIO_NUM_21;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
});
|
||||
boot_button_.OnPressDown([this]() {
|
||||
Application::GetInstance().StartListening();
|
||||
});
|
||||
boot_button_.OnPressUp([this]() {
|
||||
Application::GetInstance().StopListening();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeSt7789Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = GPIO_NUM_14;
|
||||
io_config.dc_gpio_num = GPIO_NUM_45;
|
||||
io_config.spi_mode = 3;
|
||||
io_config.pclk_hz = 80 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, true));
|
||||
|
||||
display_ = new LcdDisplay(panel_io, panel, DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_20_4,
|
||||
.icon_font = &font_awesome_20_4,
|
||||
.emoji_font = font_emoji_64_init(),
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
KEVIN_SP_V3Board() :
|
||||
// Ml307Board(ML307_TX_PIN, ML307_RX_PIN, 4096),
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
ESP_LOGI(TAG, "Initializing KEVIN_SP_V3 Board");
|
||||
|
||||
InitializeSpi();
|
||||
InitializeButtons();
|
||||
InitializeSt7789Display();
|
||||
InitializeIot();
|
||||
}
|
||||
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
static SingleLed led(BUILTIN_LED_GPIO);
|
||||
return &led;
|
||||
}
|
||||
|
||||
virtual AudioCodec *GetAudioCodec() override {
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
|
||||
virtual Display *GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(KEVIN_SP_V3Board);
|
||||
12
main/boards/lichuang-c3-dev/config.json
Normal file
12
main/boards/lichuang-c3-dev/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"target": "esp32c3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "lichuang-c3-dev",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions_8M.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -104,6 +104,7 @@ private:
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -116,13 +117,19 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new Es8311AudioCodec(codec_i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR);
|
||||
}
|
||||
return audio_codec;
|
||||
static Es8311AudioCodec audio_codec(
|
||||
codec_i2c_bus_,
|
||||
I2C_NUM_0,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_PA_PIN,
|
||||
AUDIO_CODEC_ES8311_ADDR);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
|
||||
9
main/boards/lichuang-dev/config.json
Normal file
9
main/boards/lichuang-dev/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "lichuang-dev",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -130,6 +130,7 @@ private:
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -142,13 +143,20 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
audio_codec = new BoxAudioCodec(i2c_bus_, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
GPIO_NUM_NC, AUDIO_CODEC_ES8311_ADDR, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
}
|
||||
return audio_codec;
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
GPIO_NUM_NC,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
|
||||
9
main/boards/lilygo-t-circle-s3/config.json
Normal file
9
main/boards/lilygo-t-circle-s3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "lilygo-t-circle-s3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -219,14 +219,17 @@ public:
|
||||
}
|
||||
|
||||
virtual AudioCodec *GetAudioCodec() override {
|
||||
static Tcircles3AudioCodec *audio_codec = nullptr;
|
||||
if (audio_codec == nullptr){
|
||||
audio_codec = new Tcircles3AudioCodec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_MIC_I2S_GPIO_BCLK, AUDIO_MIC_I2S_GPIO_WS, AUDIO_MIC_I2S_GPIO_DATA,
|
||||
AUDIO_SPKR_I2S_GPIO_BCLK, AUDIO_SPKR_I2S_GPIO_LRCLK, AUDIO_SPKR_I2S_GPIO_DATA,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
}
|
||||
return audio_codec;
|
||||
static Tcircles3AudioCodec audio_codec(
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_MIC_I2S_GPIO_BCLK,
|
||||
AUDIO_MIC_I2S_GPIO_WS,
|
||||
AUDIO_MIC_I2S_GPIO_DATA,
|
||||
AUDIO_SPKR_I2S_GPIO_BCLK,
|
||||
AUDIO_SPKR_I2S_GPIO_LRCLK,
|
||||
AUDIO_SPKR_I2S_GPIO_DATA,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display *GetDisplay() override{
|
||||
|
||||
11
main/boards/m5stack-core-s3/config.json
Normal file
11
main/boards/m5stack-core-s3/config.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "m5stack-core-s3",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MODE_QUAD=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "audio_codecs/cores3_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "iot/thing_manager.h"
|
||||
@@ -12,7 +11,8 @@
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#include <esp_lcd_ili9341.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#define TAG "M5StackCoreS3Board"
|
||||
|
||||
@@ -119,7 +119,7 @@ private:
|
||||
Aw9523* aw9523_;
|
||||
Ft6336* ft6336_;
|
||||
LcdDisplay* display_;
|
||||
Button boot_button_;
|
||||
esp_timer_handle_t touchpad_timer_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
@@ -170,37 +170,53 @@ private:
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
static void touchpad_daemon(void* param) {
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
static void touchpad_timer_callback(void* arg) {
|
||||
auto& board = (M5StackCoreS3Board&)Board::GetInstance();
|
||||
auto touchpad = board.GetTouchpad();
|
||||
bool was_touched = false;
|
||||
while (1) {
|
||||
touchpad->UpdateTouchPoint();
|
||||
if (touchpad->GetTouchPoint().num > 0) {
|
||||
// On press
|
||||
if (!was_touched) {
|
||||
was_touched = true;
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
board.ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
static bool was_touched = false;
|
||||
static int64_t touch_start_time = 0;
|
||||
const int64_t TOUCH_THRESHOLD_MS = 500; // 触摸时长阈值,超过500ms视为长按
|
||||
|
||||
touchpad->UpdateTouchPoint();
|
||||
auto touch_point = touchpad->GetTouchPoint();
|
||||
|
||||
// 检测触摸开始
|
||||
if (touch_point.num > 0 && !was_touched) {
|
||||
was_touched = true;
|
||||
touch_start_time = esp_timer_get_time() / 1000; // 转换为毫秒
|
||||
}
|
||||
// 检测触摸释放
|
||||
else if (touch_point.num == 0 && was_touched) {
|
||||
was_touched = false;
|
||||
int64_t touch_duration = (esp_timer_get_time() / 1000) - touch_start_time;
|
||||
|
||||
// 只有短触才触发
|
||||
if (touch_duration < TOUCH_THRESHOLD_MS) {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting &&
|
||||
!WifiStation::GetInstance().IsConnected()) {
|
||||
board.ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
}
|
||||
// On release
|
||||
else if (was_touched) {
|
||||
was_touched = false;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void InitializeFt6336TouchPad() {
|
||||
ESP_LOGI(TAG, "Init FT6336");
|
||||
ft6336_ = new Ft6336(i2c_bus_, 0x38);
|
||||
xTaskCreate(touchpad_daemon, "tp", 2048, NULL, 5, NULL);
|
||||
|
||||
// 创建定时器,10ms 间隔
|
||||
esp_timer_create_args_t timer_args = {
|
||||
.callback = touchpad_timer_callback,
|
||||
.arg = NULL,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "touchpad_timer",
|
||||
.skip_unhandled_events = true,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &touchpad_timer_));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(touchpad_timer_, 10 * 1000)); // 10ms = 10000us
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
@@ -255,16 +271,6 @@ private:
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
@@ -272,27 +278,30 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
M5StackCoreS3Board() : boot_button_(GPIO_NUM_1) {
|
||||
M5StackCoreS3Board() {
|
||||
InitializeI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeAw9523();
|
||||
InitializeFt6336TouchPad();
|
||||
I2cDetect();
|
||||
InitializeSpi();
|
||||
InitializeIli9342Display();
|
||||
InitializeButtons();
|
||||
InitializeIot();
|
||||
InitializeFt6336TouchPad();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static CoreS3AudioCodec* audio_codec = nullptr;
|
||||
if (audio_codec == nullptr) {
|
||||
aw9523_->ResetAw88298();
|
||||
audio_codec = new CoreS3AudioCodec(i2c_bus_, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_AW88298_ADDR, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
}
|
||||
return audio_codec;
|
||||
static CoreS3AudioCodec audio_codec(i2c_bus_,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_AW88298_ADDR,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
|
||||
9
main/boards/magiclick-2p4/config.json
Normal file
9
main/boards/magiclick-2p4/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "magiclick-2p4",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -150,6 +150,7 @@ private:
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
9
main/boards/magiclick-c3/config.json
Normal file
9
main/boards/magiclick-c3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32c3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "magiclick-c3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -143,6 +143,7 @@ private:
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_4
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_15
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_21
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 240
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
|
||||
9
main/boards/movecall-moji-esp32s3/config.json
Normal file
9
main/boards/movecall-moji-esp32s3/config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "movecall-moji-esp32s3",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -131,7 +131,8 @@ private:
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeIot() {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||
thing_manager.AddThing(iot::CreateThing("Backlight"));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user