add config files for known boards
This commit is contained in:
parent
fe05a039a2
commit
33518dca2b
@ -4,7 +4,7 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PROJECT_VER "0.4.1")
|
||||
set(PROJECT_VER "0.5.0")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(xiaozhi)
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#include <BuiltinLed.h>
|
||||
#include <TcpTransport.h>
|
||||
#include <TlsTransport.h>
|
||||
#include <Ml307SslTransport.h>
|
||||
#include <WifiConfigurationAp.h>
|
||||
#include <WifiStation.h>
|
||||
@ -10,6 +8,7 @@
|
||||
#include <esp_log.h>
|
||||
#include <cJSON.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
@ -17,29 +16,20 @@
|
||||
|
||||
|
||||
Application::Application()
|
||||
: boot_button_((gpio_num_t)CONFIG_BOOT_BUTTON_GPIO),
|
||||
volume_up_button_((gpio_num_t)CONFIG_VOLUME_UP_BUTTON_GPIO),
|
||||
volume_down_button_((gpio_num_t)CONFIG_VOLUME_DOWN_BUTTON_GPIO),
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
display_(CONFIG_DISPLAY_SDA_PIN, CONFIG_DISPLAY_SCL_PIN),
|
||||
#endif
|
||||
#ifdef CONFIG_USE_ML307
|
||||
ml307_at_modem_(CONFIG_ML307_TX_PIN, CONFIG_ML307_RX_PIN, 4096),
|
||||
http_(ml307_at_modem_),
|
||||
#else
|
||||
http_(),
|
||||
#endif
|
||||
firmware_upgrade_(http_)
|
||||
: boot_button_((gpio_num_t)BOOT_BUTTON_GPIO),
|
||||
volume_up_button_((gpio_num_t)VOLUME_UP_BUTTON_GPIO),
|
||||
volume_down_button_((gpio_num_t)VOLUME_DOWN_BUTTON_GPIO),
|
||||
display_(DISPLAY_SDA_PIN, DISPLAY_SCL_PIN)
|
||||
{
|
||||
event_group_ = xEventGroupCreate();
|
||||
|
||||
opus_encoder_.Configure(16000, 1);
|
||||
opus_decoder_ = opus_decoder_create(opus_decode_sample_rate_, 1, NULL);
|
||||
if (opus_decode_sample_rate_ != CONFIG_AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
output_resampler_.Configure(CONFIG_AUDIO_OUTPUT_SAMPLE_RATE, opus_decode_sample_rate_);
|
||||
if (opus_decode_sample_rate_ != AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
output_resampler_.Configure(AUDIO_OUTPUT_SAMPLE_RATE, opus_decode_sample_rate_);
|
||||
}
|
||||
if (16000 != CONFIG_AUDIO_INPUT_SAMPLE_RATE) {
|
||||
input_resampler_.Configure(CONFIG_AUDIO_INPUT_SAMPLE_RATE, 16000);
|
||||
if (16000 != AUDIO_INPUT_SAMPLE_RATE) {
|
||||
input_resampler_.Configure(AUDIO_INPUT_SAMPLE_RATE, 16000);
|
||||
}
|
||||
|
||||
firmware_upgrade_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
|
||||
@ -47,18 +37,29 @@ Application::Application()
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
if (update_display_timer_ != nullptr) {
|
||||
esp_timer_stop(update_display_timer_);
|
||||
esp_timer_delete(update_display_timer_);
|
||||
}
|
||||
if (ws_client_ != nullptr) {
|
||||
delete ws_client_;
|
||||
}
|
||||
if (opus_decoder_ != nullptr) {
|
||||
opus_decoder_destroy(opus_decoder_);
|
||||
}
|
||||
if (audio_encode_task_stack_ != nullptr) {
|
||||
free(audio_encode_task_stack_);
|
||||
}
|
||||
if (audio_device_ != nullptr) {
|
||||
delete audio_device_;
|
||||
}
|
||||
|
||||
vEventGroupDelete(event_group_);
|
||||
}
|
||||
|
||||
void Application::CheckNewVersion() {
|
||||
// Check if there is a new firmware version available
|
||||
firmware_upgrade_.SetBoardJson(Board::GetInstance().GetJson());
|
||||
firmware_upgrade_.CheckVersion();
|
||||
if (firmware_upgrade_.HasNewVersion()) {
|
||||
// Wait for the chat state to be idle
|
||||
@ -67,11 +68,9 @@ void Application::CheckNewVersion() {
|
||||
}
|
||||
SetChatState(kChatStateUpgrading);
|
||||
firmware_upgrade_.StartUpgrade([this](int progress, size_t speed) {
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "Upgrading...\n %d%% %zuKB/s", progress, speed / 1024);
|
||||
display_.SetText(buffer);
|
||||
#endif
|
||||
});
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||
@ -81,138 +80,19 @@ void Application::CheckNewVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
|
||||
#ifdef CONFIG_USE_ML307
|
||||
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";
|
||||
}
|
||||
#else
|
||||
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";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Application::UpdateDisplay() {
|
||||
while (true) {
|
||||
if (chat_state_ == kChatStateIdle) {
|
||||
#ifdef CONFIG_USE_ML307
|
||||
std::string network_name = ml307_at_modem_.GetCarrierName();
|
||||
int signal_quality = ml307_at_modem_.GetCsq();
|
||||
if (signal_quality == -1) {
|
||||
network_name = "No network";
|
||||
} else {
|
||||
ESP_LOGI(TAG, "%s CSQ: %d", network_name.c_str(), signal_quality);
|
||||
display_.SetText(network_name + "\n" + csq_to_string(signal_quality) + " (" + std::to_string(signal_quality) + ")");
|
||||
}
|
||||
#else
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
int8_t rssi = wifi_station.GetRssi();
|
||||
display_.SetText(wifi_station.GetSsid() + "\n" + rssi_to_string(rssi) + " (" + std::to_string(rssi) + ")");
|
||||
#endif
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10 * 1000));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Application::Start() {
|
||||
auto& builtin_led = BuiltinLed::GetInstance();
|
||||
#ifdef CONFIG_USE_ML307
|
||||
builtin_led.SetBlue();
|
||||
builtin_led.StartContinuousBlink(100);
|
||||
ml307_at_modem_.SetDebug(false);
|
||||
ml307_at_modem_.SetBaudRate(921600);
|
||||
// Print the ML307 modem information
|
||||
std::string module_name = ml307_at_modem_.GetModuleName();
|
||||
ESP_LOGI(TAG, "ML307 Module: %s", module_name.c_str());
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
display_.SetText(std::string("Wait for network\n") + module_name);
|
||||
#endif
|
||||
ml307_at_modem_.ResetConnections();
|
||||
ml307_at_modem_.WaitForNetworkReady();
|
||||
|
||||
std::string imei = ml307_at_modem_.GetImei();
|
||||
std::string iccid = ml307_at_modem_.GetIccid();
|
||||
ESP_LOGI(TAG, "ML307 IMEI: %s", imei.c_str());
|
||||
ESP_LOGI(TAG, "ML307 ICCID: %s", iccid.c_str());
|
||||
auto& board = Board::GetInstance();
|
||||
board.Initialize();
|
||||
|
||||
// If low power, the material ready event will be triggered by the modem because of a reset
|
||||
ml307_at_modem_.OnMaterialReady([this]() {
|
||||
ESP_LOGI(TAG, "ML307 material ready");
|
||||
Schedule([this]() {
|
||||
SetChatState(kChatStateIdle);
|
||||
});
|
||||
});
|
||||
|
||||
// Set the board type for OTA
|
||||
std::string carrier_name = ml307_at_modem_.GetCarrierName();
|
||||
int csq = ml307_at_modem_.GetCsq();
|
||||
std::string board_json = std::string("{\"type\":\"compact.4g\",");
|
||||
board_json += "\"revision\":\"" + module_name + "\",";
|
||||
board_json += "\"carrier\":\"" + carrier_name + "\",";
|
||||
board_json += "\"csq\":\"" + std::to_string(csq) + "\",";
|
||||
board_json += "\"imei\":\"" + imei + "\",";
|
||||
board_json += "\"iccid\":\"" + iccid + "\"}";
|
||||
firmware_upgrade_.SetBoardJson(board_json);
|
||||
#else
|
||||
// Try to connect to WiFi, if failed, launch the WiFi configuration AP
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
display_.SetText(std::string("Connect to WiFi\n") + wifi_station.GetSsid());
|
||||
#endif
|
||||
builtin_led.SetBlue();
|
||||
builtin_led.StartContinuousBlink(100);
|
||||
wifi_station.Start();
|
||||
if (!wifi_station.IsConnected()) {
|
||||
builtin_led.SetBlue();
|
||||
builtin_led.Blink(1000, 500);
|
||||
auto& wifi_ap = WifiConfigurationAp::GetInstance();
|
||||
wifi_ap.SetSsidPrefix("Xiaozhi");
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
display_.SetText(wifi_ap.GetSsid() + "\n" + wifi_ap.GetWebServerUrl());
|
||||
#endif
|
||||
wifi_ap.Start();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the board type for OTA
|
||||
std::string board_json = std::string("{\"type\":\"compact.wifi\",");
|
||||
board_json += "\"ssid\":\"" + wifi_station.GetSsid() + "\",";
|
||||
board_json += "\"rssi\":" + std::to_string(wifi_station.GetRssi()) + ",";
|
||||
board_json += "\"channel\":" + std::to_string(wifi_station.GetChannel()) + ",";
|
||||
board_json += "\"ip\":\"" + wifi_station.GetIpAddress() + "\",";
|
||||
board_json += "\"mac\":\"" + SystemInfo::GetMacAddress() + "\"}";
|
||||
firmware_upgrade_.SetBoardJson(board_json);
|
||||
#endif
|
||||
|
||||
audio_device_.Initialize();
|
||||
audio_device_.OnInputData([this](std::vector<int16_t>&& data) {
|
||||
if (16000 != CONFIG_AUDIO_INPUT_SAMPLE_RATE) {
|
||||
if (audio_device_.input_channels() == 2) {
|
||||
audio_device_ = board.CreateAudioDevice();
|
||||
audio_device_->Initialize();
|
||||
audio_device_->OnInputData([this](std::vector<int16_t>&& data) {
|
||||
if (16000 != AUDIO_INPUT_SAMPLE_RATE) {
|
||||
if (audio_device_->input_channels() == 2) {
|
||||
auto left_channel = std::vector<int16_t>(data.size() / 2);
|
||||
auto right_channel = std::vector<int16_t>(data.size() / 2);
|
||||
for (size_t i = 0, j = 0; i < left_channel.size(); ++i, j += 2) {
|
||||
@ -268,7 +148,7 @@ void Application::Start() {
|
||||
}, "play_audio", 4096 * 4, this, 4, NULL);
|
||||
|
||||
#ifdef CONFIG_USE_AFE_SR
|
||||
wake_word_detect_.Initialize(audio_device_.input_channels(), audio_device_.input_reference());
|
||||
wake_word_detect_.Initialize(audio_device_->input_channels(), audio_device_->input_reference());
|
||||
wake_word_detect_.OnVadStateChange([this](bool speaking) {
|
||||
Schedule([this, speaking]() {
|
||||
auto& builtin_led = BuiltinLed::GetInstance();
|
||||
@ -317,7 +197,7 @@ void Application::Start() {
|
||||
});
|
||||
wake_word_detect_.StartDetection();
|
||||
|
||||
audio_processor_.Initialize(audio_device_.input_channels(), audio_device_.input_reference());
|
||||
audio_processor_.Initialize(audio_device_->input_channels(), audio_device_->input_reference());
|
||||
audio_processor_.OnOutput([this](std::vector<int16_t>&& data) {
|
||||
Schedule([this, data = std::move(data)]() {
|
||||
if (chat_state_ == kChatStateListening) {
|
||||
@ -361,45 +241,37 @@ void Application::Start() {
|
||||
|
||||
volume_up_button_.OnClick([this]() {
|
||||
Schedule([this]() {
|
||||
auto volume = audio_device_.output_volume() + 10;
|
||||
auto volume = audio_device_->output_volume() + 10;
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
audio_device_.SetOutputVolume(volume);
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
audio_device_->SetOutputVolume(volume);
|
||||
display_.ShowNotification("Volume\n" + std::to_string(volume));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
Schedule([this]() {
|
||||
audio_device_.SetOutputVolume(100);
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
audio_device_->SetOutputVolume(100);
|
||||
display_.ShowNotification("Volume\n100");
|
||||
#endif
|
||||
});
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
Schedule([this]() {
|
||||
auto volume = audio_device_.output_volume() - 10;
|
||||
auto volume = audio_device_->output_volume() - 10;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
audio_device_.SetOutputVolume(volume);
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
audio_device_->SetOutputVolume(volume);
|
||||
display_.ShowNotification("Volume\n" + std::to_string(volume));
|
||||
#endif
|
||||
});
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
Schedule([this]() {
|
||||
audio_device_.SetOutputVolume(0);
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
audio_device_->SetOutputVolume(0);
|
||||
display_.ShowNotification("Volume\n0");
|
||||
#endif
|
||||
});
|
||||
});
|
||||
|
||||
@ -416,14 +288,8 @@ void Application::Start() {
|
||||
vTaskDelete(NULL);
|
||||
}, "check_new_version", 4096 * 2, this, 1, NULL);
|
||||
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
// Launch a task to update the display
|
||||
xTaskCreate([](void* arg) {
|
||||
Application* app = (Application*)arg;
|
||||
app->UpdateDisplay();
|
||||
vTaskDelete(NULL);
|
||||
}, "update_display", 4096, this, 1, NULL);
|
||||
#endif
|
||||
chat_state_ = kChatStateIdle;
|
||||
display_.UpdateDisplay();
|
||||
}
|
||||
|
||||
void Application::Schedule(std::function<void()> callback) {
|
||||
@ -450,6 +316,7 @@ void Application::MainLoop() {
|
||||
|
||||
void Application::SetChatState(ChatState state) {
|
||||
const char* state_str[] = {
|
||||
"unknown",
|
||||
"idle",
|
||||
"connecting",
|
||||
"listening",
|
||||
@ -457,13 +324,14 @@ void Application::SetChatState(ChatState state) {
|
||||
"wake_word_detected",
|
||||
"testing",
|
||||
"upgrading",
|
||||
"unknown"
|
||||
"invalid_state"
|
||||
};
|
||||
chat_state_ = state;
|
||||
ESP_LOGI(TAG, "STATE: %s", state_str[chat_state_]);
|
||||
|
||||
auto& builtin_led = BuiltinLed::GetInstance();
|
||||
switch (chat_state_) {
|
||||
case kChatStateUnknown:
|
||||
case kChatStateIdle:
|
||||
builtin_led.TurnOff();
|
||||
break;
|
||||
@ -557,7 +425,7 @@ void Application::AudioEncodeTask() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opus_decode_sample_rate_ != CONFIG_AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
if (opus_decode_sample_rate_ != AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
int target_size = output_resampler_.GetOutputSamples(frame_size);
|
||||
std::vector<int16_t> resampled(target_size);
|
||||
output_resampler_.Process(packet->pcm.data(), frame_size, resampled.data());
|
||||
@ -580,7 +448,7 @@ void Application::HandleAudioPacket(AudioPacket* packet) {
|
||||
}
|
||||
|
||||
// This will block until the audio device has finished playing the audio
|
||||
audio_device_.OutputData(packet->pcm);
|
||||
audio_device_->OutputData(packet->pcm);
|
||||
|
||||
if (break_speaking_) {
|
||||
skip_to_end_ = true;
|
||||
@ -589,7 +457,7 @@ void Application::HandleAudioPacket(AudioPacket* packet) {
|
||||
int frame_size = opus_decode_sample_rate_ / 1000 * opus_duration_ms_;
|
||||
std::vector<int16_t> silence(frame_size);
|
||||
bzero(silence.data(), silence.size() * sizeof(int16_t));
|
||||
audio_device_.OutputData(silence);
|
||||
audio_device_->OutputData(silence);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -643,9 +511,9 @@ void Application::SetDecodeSampleRate(int sample_rate) {
|
||||
opus_decoder_destroy(opus_decoder_);
|
||||
opus_decode_sample_rate_ = sample_rate;
|
||||
opus_decoder_ = opus_decoder_create(opus_decode_sample_rate_, 1, NULL);
|
||||
if (opus_decode_sample_rate_ != CONFIG_AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
ESP_LOGI(TAG, "Resampling audio from %d to %d", opus_decode_sample_rate_, CONFIG_AUDIO_OUTPUT_SAMPLE_RATE);
|
||||
output_resampler_.Configure(opus_decode_sample_rate_, CONFIG_AUDIO_OUTPUT_SAMPLE_RATE);
|
||||
if (opus_decode_sample_rate_ != AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
ESP_LOGI(TAG, "Resampling audio from %d to %d", opus_decode_sample_rate_, AUDIO_OUTPUT_SAMPLE_RATE);
|
||||
output_resampler_.Configure(opus_decode_sample_rate_, AUDIO_OUTPUT_SAMPLE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,15 +525,7 @@ void Application::StartWebSocketClient() {
|
||||
|
||||
std::string url = CONFIG_WEBSOCKET_URL;
|
||||
std::string token = "Bearer " + std::string(CONFIG_WEBSOCKET_ACCESS_TOKEN);
|
||||
#ifdef CONFIG_USE_ML307
|
||||
ws_client_ = new WebSocket(new Ml307SslTransport(ml307_at_modem_, 0));
|
||||
#else
|
||||
if (url.find("wss://") == 0) {
|
||||
ws_client_ = new WebSocket(new TlsTransport());
|
||||
} else {
|
||||
ws_client_ = new WebSocket(new TcpTransport());
|
||||
}
|
||||
#endif
|
||||
ws_client_ = Board::GetInstance().CreateWebSocket();
|
||||
ws_client_->SetHeader("Authorization", token.c_str());
|
||||
ws_client_->SetHeader("Protocol-Version", std::to_string(PROTOCOL_VERSION).c_str());
|
||||
ws_client_->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
||||
|
||||
@ -4,9 +4,6 @@
|
||||
#include <OpusEncoder.h>
|
||||
#include <OpusResampler.h>
|
||||
#include <WebSocket.h>
|
||||
#include <Ml307AtModem.h>
|
||||
#include <Ml307Http.h>
|
||||
#include <EspHttp.h>
|
||||
|
||||
#include <opus.h>
|
||||
#include <resampler_structs.h>
|
||||
@ -16,8 +13,9 @@
|
||||
#include <list>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "BoxAudioDevice.h"
|
||||
#include "AudioDevice.h"
|
||||
#include "Display.h"
|
||||
#include "Board.h"
|
||||
#include "FirmwareUpgrade.h"
|
||||
|
||||
#ifdef CONFIG_USE_AFE_SR
|
||||
@ -59,6 +57,7 @@ struct AudioPacket {
|
||||
|
||||
|
||||
enum ChatState {
|
||||
kChatStateUnknown,
|
||||
kChatStateIdle,
|
||||
kChatStateConnecting,
|
||||
kChatStateListening,
|
||||
@ -75,6 +74,10 @@ public:
|
||||
}
|
||||
|
||||
void Start();
|
||||
ChatState GetChatState() const { return chat_state_; }
|
||||
Display& GetDisplay() { return display_; }
|
||||
void Schedule(std::function<void()> callback);
|
||||
void SetChatState(ChatState state);
|
||||
|
||||
// 删除拷贝构造函数和赋值运算符
|
||||
Application(const Application&) = delete;
|
||||
@ -87,23 +90,11 @@ private:
|
||||
Button boot_button_;
|
||||
Button volume_up_button_;
|
||||
Button volume_down_button_;
|
||||
#ifdef CONFIG_AUDIO_CODEC_ES8311_ES7210
|
||||
BoxAudioDevice audio_device_;
|
||||
#else
|
||||
AudioDevice audio_device_;
|
||||
#endif
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
AudioDevice* audio_device_ = nullptr;
|
||||
Display display_;
|
||||
#endif
|
||||
#ifdef CONFIG_USE_AFE_SR
|
||||
WakeWordDetect wake_word_detect_;
|
||||
AudioProcessor audio_processor_;
|
||||
#endif
|
||||
#ifdef CONFIG_USE_ML307
|
||||
Ml307AtModem ml307_at_modem_;
|
||||
Ml307Http http_;
|
||||
#else
|
||||
EspHttp http_;
|
||||
#endif
|
||||
FirmwareUpgrade firmware_upgrade_;
|
||||
std::mutex mutex_;
|
||||
@ -111,9 +102,10 @@ private:
|
||||
std::list<std::function<void()>> main_tasks_;
|
||||
WebSocket* ws_client_ = nullptr;
|
||||
EventGroupHandle_t event_group_;
|
||||
volatile ChatState chat_state_ = kChatStateIdle;
|
||||
volatile ChatState chat_state_ = kChatStateUnknown;
|
||||
volatile bool break_speaking_ = false;
|
||||
bool skip_to_end_ = false;
|
||||
esp_timer_handle_t update_display_timer_ = nullptr;
|
||||
|
||||
// Audio encode / decode
|
||||
TaskHandle_t audio_encode_task_ = nullptr;
|
||||
@ -127,7 +119,7 @@ private:
|
||||
OpusDecoder* opus_decoder_ = nullptr;
|
||||
|
||||
int opus_duration_ms_ = 60;
|
||||
int opus_decode_sample_rate_ = CONFIG_AUDIO_OUTPUT_SAMPLE_RATE;
|
||||
int opus_decode_sample_rate_ = AUDIO_OUTPUT_SAMPLE_RATE;
|
||||
OpusResampler input_resampler_;
|
||||
OpusResampler output_resampler_;
|
||||
|
||||
@ -136,13 +128,10 @@ private:
|
||||
StackType_t* check_new_version_task_stack_ = nullptr;
|
||||
|
||||
void MainLoop();
|
||||
void Schedule(std::function<void()> callback);
|
||||
BinaryProtocol* AllocateBinaryProtocol(const uint8_t* payload, size_t payload_size);
|
||||
void SetDecodeSampleRate(int sample_rate);
|
||||
void SetChatState(ChatState state);
|
||||
void StartWebSocketClient();
|
||||
void CheckNewVersion();
|
||||
void UpdateDisplay();
|
||||
|
||||
void AudioEncodeTask();
|
||||
void AudioPlayTask();
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
#include "AudioDevice.h"
|
||||
#include "Board.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#define TAG "AudioDevice"
|
||||
|
||||
AudioDevice::AudioDevice()
|
||||
: input_sample_rate_(CONFIG_AUDIO_INPUT_SAMPLE_RATE),
|
||||
output_sample_rate_(CONFIG_AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
: input_sample_rate_(AUDIO_INPUT_SAMPLE_RATE),
|
||||
output_sample_rate_(AUDIO_OUTPUT_SAMPLE_RATE) {
|
||||
}
|
||||
|
||||
AudioDevice::~AudioDevice() {
|
||||
@ -22,7 +25,7 @@ AudioDevice::~AudioDevice() {
|
||||
}
|
||||
|
||||
void AudioDevice::Initialize() {
|
||||
#ifdef CONFIG_AUDIO_I2S_METHOD_SIMPLEX
|
||||
#ifdef AUDIO_I2S_METHOD_SIMPLEX
|
||||
CreateSimplexChannels();
|
||||
#else
|
||||
CreateDuplexChannels();
|
||||
@ -30,7 +33,7 @@ void AudioDevice::Initialize() {
|
||||
}
|
||||
|
||||
void AudioDevice::CreateDuplexChannels() {
|
||||
#ifdef CONFIG_AUDIO_I2S_METHOD_DUPLEX
|
||||
#ifndef AUDIO_I2S_METHOD_SIMPLEX
|
||||
duplex_ = true;
|
||||
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
@ -65,10 +68,10 @@ void AudioDevice::CreateDuplexChannels() {
|
||||
},
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_LRCK,
|
||||
.dout = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_DOUT,
|
||||
.din = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_DIN,
|
||||
.bclk = (gpio_num_t)AUDIO_I2S_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)AUDIO_I2S_GPIO_LRCK,
|
||||
.dout = (gpio_num_t)AUDIO_I2S_GPIO_DOUT,
|
||||
.din = (gpio_num_t)AUDIO_I2S_GPIO_DIN,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
@ -85,7 +88,7 @@ void AudioDevice::CreateDuplexChannels() {
|
||||
}
|
||||
|
||||
void AudioDevice::CreateSimplexChannels() {
|
||||
#ifdef CONFIG_AUDIO_I2S_METHOD_SIMPLEX
|
||||
#ifdef AUDIO_I2S_METHOD_SIMPLEX
|
||||
// Create a new channel for speaker
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
.id = I2S_NUM_0,
|
||||
@ -119,9 +122,9 @@ void AudioDevice::CreateSimplexChannels() {
|
||||
},
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_SPK_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_SPK_GPIO_LRCK,
|
||||
.dout = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_SPK_GPIO_DOUT,
|
||||
.bclk = (gpio_num_t)AUDIO_I2S_SPK_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)AUDIO_I2S_SPK_GPIO_LRCK,
|
||||
.dout = (gpio_num_t)AUDIO_I2S_SPK_GPIO_DOUT,
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
@ -136,10 +139,10 @@ void AudioDevice::CreateSimplexChannels() {
|
||||
chan_cfg.id = I2S_NUM_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.gpio_cfg.bclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_MIC_GPIO_SCK;
|
||||
std_cfg.gpio_cfg.ws = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_MIC_GPIO_WS;
|
||||
std_cfg.gpio_cfg.bclk = (gpio_num_t)AUDIO_I2S_MIC_GPIO_SCK;
|
||||
std_cfg.gpio_cfg.ws = (gpio_num_t)AUDIO_I2S_MIC_GPIO_WS;
|
||||
std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED;
|
||||
std_cfg.gpio_cfg.din = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_MIC_GPIO_DIN;
|
||||
std_cfg.gpio_cfg.din = (gpio_num_t)AUDIO_I2S_MIC_GPIO_DIN;
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
|
||||
|
||||
4
main/Board.cc
Normal file
4
main/Board.cc
Normal file
@ -0,0 +1,4 @@
|
||||
#include "Board.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
// static const char *TAG = "Board";
|
||||
43
main/Board.h
Normal file
43
main/Board.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
#include "config.h"
|
||||
#include <Http.h>
|
||||
#include <WebSocket.h>
|
||||
#include <AudioDevice.h>
|
||||
#include <string>
|
||||
|
||||
void* create_board();
|
||||
|
||||
class Board {
|
||||
public:
|
||||
static Board& GetInstance() {
|
||||
static Board* instance = nullptr;
|
||||
if (nullptr == instance) {
|
||||
instance = static_cast<Board*>(create_board());
|
||||
}
|
||||
return *instance;
|
||||
}
|
||||
|
||||
virtual void Initialize() = 0;
|
||||
virtual ~Board() = default;
|
||||
virtual AudioDevice* CreateAudioDevice() = 0;
|
||||
virtual Http* CreateHttp() = 0;
|
||||
virtual WebSocket* CreateWebSocket() = 0;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) = 0;
|
||||
virtual std::string GetJson() = 0;
|
||||
|
||||
protected:
|
||||
Board() = default;
|
||||
|
||||
private:
|
||||
Board(const Board&) = delete; // 禁用拷贝构造函数
|
||||
Board& operator=(const Board&) = delete; // 禁用赋值操作
|
||||
};
|
||||
|
||||
#define DECLARE_BOARD(BOARD_CLASS_NAME) \
|
||||
void* create_board() { \
|
||||
return new BOARD_CLASS_NAME(); \
|
||||
}
|
||||
|
||||
#endif // BOARD_H
|
||||
@ -1,4 +1,6 @@
|
||||
#include "BoxAudioDevice.h"
|
||||
#include "Board.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <cassert>
|
||||
|
||||
@ -25,14 +27,14 @@ BoxAudioDevice::~BoxAudioDevice() {
|
||||
|
||||
void BoxAudioDevice::Initialize() {
|
||||
duplex_ = true; // 是否双工
|
||||
input_reference_ = CONFIG_AUDIO_CODEC_INPUT_REFERENCE; // 是否使用参考输入,实现回声消除
|
||||
input_reference_ = AUDIO_INPUT_REFERENCE; // 是否使用参考输入,实现回声消除
|
||||
input_channels_ = input_reference_ ? 2 : 1; // 输入通道数
|
||||
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = (gpio_num_t)CONFIG_AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = (gpio_num_t)CONFIG_AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.sda_io_num = (gpio_num_t)AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = (gpio_num_t)AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
@ -70,7 +72,7 @@ void BoxAudioDevice::Initialize() {
|
||||
es8311_cfg.ctrl_if = out_ctrl_if_;
|
||||
es8311_cfg.gpio_if = gpio_if_;
|
||||
es8311_cfg.codec_mode = ESP_CODEC_DEV_WORK_MODE_DAC;
|
||||
es8311_cfg.pa_pin = CONFIG_AUDIO_CODEC_PA_PIN;
|
||||
es8311_cfg.pa_pin = AUDIO_CODEC_PA_PIN;
|
||||
es8311_cfg.use_mclk = true;
|
||||
es8311_cfg.hw_gain.pa_voltage = 5.0;
|
||||
es8311_cfg.hw_gain.codec_dac_voltage = 3.3;
|
||||
@ -160,10 +162,10 @@ void BoxAudioDevice::CreateDuplexChannels() {
|
||||
.bit_order_lsb = false
|
||||
},
|
||||
.gpio_cfg = {
|
||||
.mclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_MCLK,
|
||||
.bclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_LRCK,
|
||||
.dout = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_DOUT,
|
||||
.mclk = (gpio_num_t)AUDIO_I2S_GPIO_MCLK,
|
||||
.bclk = (gpio_num_t)AUDIO_I2S_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)AUDIO_I2S_GPIO_LRCK,
|
||||
.dout = (gpio_num_t)AUDIO_I2S_GPIO_DOUT,
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
@ -196,11 +198,11 @@ void BoxAudioDevice::CreateDuplexChannels() {
|
||||
.total_slot = I2S_TDM_AUTO_SLOT_NUM
|
||||
},
|
||||
.gpio_cfg = {
|
||||
.mclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_MCLK,
|
||||
.bclk = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_LRCK,
|
||||
.mclk = (gpio_num_t)AUDIO_I2S_GPIO_MCLK,
|
||||
.bclk = (gpio_num_t)AUDIO_I2S_GPIO_BCLK,
|
||||
.ws = (gpio_num_t)AUDIO_I2S_GPIO_LRCK,
|
||||
.dout = I2S_GPIO_UNUSED,
|
||||
.din = (gpio_num_t)CONFIG_AUDIO_DEVICE_I2S_GPIO_DIN,
|
||||
.din = (gpio_num_t)AUDIO_I2S_GPIO_DIN,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
|
||||
137
main/BuiltinLed.cc
Normal file
137
main/BuiltinLed.cc
Normal file
@ -0,0 +1,137 @@
|
||||
#include "BuiltinLed.h"
|
||||
#include "Board.h"
|
||||
#include <cstring>
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "builtin_led"
|
||||
|
||||
BuiltinLed::BuiltinLed() {
|
||||
mutex_ = xSemaphoreCreateMutex();
|
||||
blink_event_group_ = xEventGroupCreate();
|
||||
xEventGroupSetBits(blink_event_group_, BLINK_TASK_STOPPED_BIT);
|
||||
|
||||
if (BUILTIN_LED_GPIO == GPIO_NUM_NC) {
|
||||
ESP_LOGI(TAG, "Builtin LED not connected");
|
||||
return;
|
||||
}
|
||||
Initialize();
|
||||
SetGrey();
|
||||
}
|
||||
|
||||
BuiltinLed::~BuiltinLed() {
|
||||
StopBlinkInternal();
|
||||
if (led_strip_ != nullptr) {
|
||||
led_strip_del(led_strip_);
|
||||
}
|
||||
if (mutex_ != nullptr) {
|
||||
vSemaphoreDelete(mutex_);
|
||||
}
|
||||
if (blink_event_group_ != nullptr) {
|
||||
vEventGroupDelete(blink_event_group_);
|
||||
}
|
||||
}
|
||||
|
||||
BuiltinLed& BuiltinLed::GetInstance() {
|
||||
static BuiltinLed instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void BuiltinLed::Initialize() {
|
||||
led_strip_config_t strip_config = {};
|
||||
strip_config.strip_gpio_num = BUILTIN_LED_GPIO;
|
||||
strip_config.max_leds = 1;
|
||||
strip_config.led_pixel_format = LED_PIXEL_FORMAT_GRB;
|
||||
strip_config.led_model = LED_MODEL_WS2812;
|
||||
|
||||
led_strip_rmt_config_t rmt_config = {};
|
||||
rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz
|
||||
|
||||
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip_));
|
||||
led_strip_clear(led_strip_);
|
||||
}
|
||||
|
||||
void BuiltinLed::SetColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||
r_ = r;
|
||||
g_ = g;
|
||||
b_ = b;
|
||||
}
|
||||
|
||||
void BuiltinLed::TurnOn() {
|
||||
if (led_strip_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
StopBlinkInternal();
|
||||
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||
led_strip_set_pixel(led_strip_, 0, r_, g_, b_);
|
||||
led_strip_refresh(led_strip_);
|
||||
xSemaphoreGive(mutex_);
|
||||
}
|
||||
|
||||
void BuiltinLed::TurnOff() {
|
||||
if (led_strip_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
StopBlinkInternal();
|
||||
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||
led_strip_clear(led_strip_);
|
||||
xSemaphoreGive(mutex_);
|
||||
}
|
||||
|
||||
void BuiltinLed::BlinkOnce() {
|
||||
Blink(1, 100);
|
||||
}
|
||||
|
||||
void BuiltinLed::Blink(int times, int interval_ms) {
|
||||
StartBlinkTask(times, interval_ms);
|
||||
}
|
||||
|
||||
void BuiltinLed::StartContinuousBlink(int interval_ms) {
|
||||
StartBlinkTask(BLINK_INFINITE, interval_ms);
|
||||
}
|
||||
|
||||
void BuiltinLed::StartBlinkTask(int times, int interval_ms) {
|
||||
if (led_strip_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
StopBlinkInternal();
|
||||
xSemaphoreTake(mutex_, portMAX_DELAY);
|
||||
|
||||
blink_times_ = times;
|
||||
blink_interval_ms_ = interval_ms;
|
||||
should_blink_ = true;
|
||||
|
||||
xEventGroupClearBits(blink_event_group_, BLINK_TASK_STOPPED_BIT);
|
||||
xEventGroupSetBits(blink_event_group_, BLINK_TASK_RUNNING_BIT);
|
||||
|
||||
xTaskCreate([](void* obj) {
|
||||
auto this_ = static_cast<BuiltinLed*>(obj);
|
||||
int count = 0;
|
||||
while (this_->should_blink_ && (this_->blink_times_ == BLINK_INFINITE || count < this_->blink_times_)) {
|
||||
xSemaphoreTake(this_->mutex_, portMAX_DELAY);
|
||||
led_strip_set_pixel(this_->led_strip_, 0, this_->r_, this_->g_, this_->b_);
|
||||
led_strip_refresh(this_->led_strip_);
|
||||
xSemaphoreGive(this_->mutex_);
|
||||
|
||||
vTaskDelay(this_->blink_interval_ms_ / portTICK_PERIOD_MS);
|
||||
if (!this_->should_blink_) break;
|
||||
|
||||
xSemaphoreTake(this_->mutex_, portMAX_DELAY);
|
||||
led_strip_clear(this_->led_strip_);
|
||||
xSemaphoreGive(this_->mutex_);
|
||||
|
||||
vTaskDelay(this_->blink_interval_ms_ / portTICK_PERIOD_MS);
|
||||
if (this_->blink_times_ != BLINK_INFINITE) count++;
|
||||
}
|
||||
this_->blink_task_ = nullptr;
|
||||
xEventGroupClearBits(this_->blink_event_group_, BLINK_TASK_RUNNING_BIT);
|
||||
xEventGroupSetBits(this_->blink_event_group_, BLINK_TASK_STOPPED_BIT);
|
||||
vTaskDelete(NULL);
|
||||
}, "blink", 2048, this, tskIDLE_PRIORITY, &blink_task_);
|
||||
|
||||
xSemaphoreGive(mutex_);
|
||||
}
|
||||
|
||||
void BuiltinLed::StopBlinkInternal() {
|
||||
should_blink_ = false;
|
||||
xEventGroupWaitBits(blink_event_group_, BLINK_TASK_STOPPED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
||||
}
|
||||
52
main/BuiltinLed.h
Normal file
52
main/BuiltinLed.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef _BUILTIN_LED_H_
|
||||
#define _BUILTIN_LED_H_
|
||||
|
||||
#include <led_strip.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/event_groups.h>
|
||||
#include <atomic>
|
||||
|
||||
#define BLINK_INFINITE -1
|
||||
#define BLINK_TASK_STOPPED_BIT BIT0
|
||||
#define BLINK_TASK_RUNNING_BIT BIT1
|
||||
|
||||
#define DEFAULT_BRIGHTNESS 16
|
||||
|
||||
class BuiltinLed {
|
||||
public:
|
||||
static BuiltinLed& GetInstance();
|
||||
|
||||
void BlinkOnce();
|
||||
void Blink(int times, int interval_ms);
|
||||
void StartContinuousBlink(int interval_ms);
|
||||
void TurnOn();
|
||||
void TurnOff();
|
||||
void SetColor(uint8_t r, uint8_t g, uint8_t b);
|
||||
void SetWhite(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(brightness, brightness, brightness); }
|
||||
void SetGrey(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(brightness, brightness, brightness); }
|
||||
void SetRed(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(brightness, 0, 0); }
|
||||
void SetGreen(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(0, brightness, 0); }
|
||||
void SetBlue(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(0, 0, brightness); }
|
||||
|
||||
private:
|
||||
BuiltinLed();
|
||||
~BuiltinLed();
|
||||
BuiltinLed(const BuiltinLed&) = delete;
|
||||
BuiltinLed& operator=(const BuiltinLed&) = delete;
|
||||
|
||||
SemaphoreHandle_t mutex_;
|
||||
EventGroupHandle_t blink_event_group_;
|
||||
TaskHandle_t blink_task_ = nullptr;
|
||||
led_strip_handle_t led_strip_ = nullptr;
|
||||
uint8_t r_ = 0, g_ = 0, b_ = 0;
|
||||
int blink_times_ = 0;
|
||||
int blink_interval_ms_ = 0;
|
||||
std::atomic<bool> should_blink_{false};
|
||||
|
||||
void Initialize();
|
||||
void StartBlinkTask(int times, int interval_ms);
|
||||
void StopBlinkInternal();
|
||||
};
|
||||
|
||||
#endif // _BUILTIN_LED_H_
|
||||
@ -4,6 +4,9 @@
|
||||
static const char* TAG = "Button";
|
||||
|
||||
Button::Button(gpio_num_t gpio_num) : gpio_num_(gpio_num) {
|
||||
if (gpio_num == GPIO_NUM_NC) {
|
||||
return;
|
||||
}
|
||||
button_config_t button_config = {
|
||||
.type = BUTTON_TYPE_GPIO,
|
||||
.long_press_time = 1000,
|
||||
@ -27,6 +30,9 @@ Button::~Button() {
|
||||
}
|
||||
|
||||
void Button::OnPress(std::function<void()> callback) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_ = callback;
|
||||
iot_button_register_cb(button_handle_, BUTTON_PRESS_DOWN, [](void* handle, void* usr_data) {
|
||||
Button* button = static_cast<Button*>(usr_data);
|
||||
@ -37,6 +43,9 @@ void Button::OnPress(std::function<void()> callback) {
|
||||
}
|
||||
|
||||
void Button::OnLongPress(std::function<void()> callback) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_long_press_ = callback;
|
||||
iot_button_register_cb(button_handle_, BUTTON_LONG_PRESS_START, [](void* handle, void* usr_data) {
|
||||
Button* button = static_cast<Button*>(usr_data);
|
||||
@ -47,6 +56,9 @@ void Button::OnLongPress(std::function<void()> callback) {
|
||||
}
|
||||
|
||||
void Button::OnClick(std::function<void()> callback) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_click_ = callback;
|
||||
iot_button_register_cb(button_handle_, BUTTON_SINGLE_CLICK, [](void* handle, void* usr_data) {
|
||||
Button* button = static_cast<Button*>(usr_data);
|
||||
@ -57,6 +69,9 @@ void Button::OnClick(std::function<void()> callback) {
|
||||
}
|
||||
|
||||
void Button::OnDoubleClick(std::function<void()> callback) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_double_click_ = callback;
|
||||
iot_button_register_cb(button_handle_, BUTTON_DOUBLE_CLICK, [](void* handle, void* usr_data) {
|
||||
Button* button = static_cast<Button*>(usr_data);
|
||||
|
||||
@ -3,18 +3,50 @@ set(SOURCES "AudioDevice.cc"
|
||||
"SystemInfo.cc"
|
||||
"SystemReset.cc"
|
||||
"Application.cc"
|
||||
"Display.cc"
|
||||
"Button.cc"
|
||||
"BuiltinLed.cc"
|
||||
"Display.cc"
|
||||
"Board.cc"
|
||||
"main.cc"
|
||||
)
|
||||
set(INCLUDE_DIRS ".")
|
||||
|
||||
# 根据 BOARD_TYPE 配置添加对应的板级文件
|
||||
if(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI)
|
||||
# add all files from boards/bread-compact-wifi
|
||||
set(BOARD_TYPE "bread-compact-wifi")
|
||||
file(GLOB BOARD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc)
|
||||
list(APPEND SOURCES ${BOARD_SOURCES} "WifiBoard.cc")
|
||||
list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE})
|
||||
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ML307)
|
||||
# add all files from boards/bread-compact-ml307
|
||||
set(BOARD_TYPE "bread-compact-ml307")
|
||||
file(GLOB BOARD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc)
|
||||
list(APPEND SOURCES ${BOARD_SOURCES} "Ml307Board.cc")
|
||||
list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE})
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_BOX_3)
|
||||
# add all files from boards/esp-box-3
|
||||
set(BOARD_TYPE "esp-box-3")
|
||||
file(GLOB BOARD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc)
|
||||
list(APPEND SOURCES ${BOARD_SOURCES} "WifiBoard.cc")
|
||||
list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE})
|
||||
list(APPEND SOURCES "BoxAudioDevice.cc")
|
||||
elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_0)
|
||||
# add all files from boards/kevin-box-0
|
||||
set(BOARD_TYPE "kevin-box-0")
|
||||
file(GLOB BOARD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc)
|
||||
list(APPEND SOURCES ${BOARD_SOURCES} "Ml307Board.cc")
|
||||
list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE})
|
||||
list(APPEND SOURCES "BoxAudioDevice.cc")
|
||||
endif()
|
||||
|
||||
if(CONFIG_USE_AFE_SR)
|
||||
list(APPEND SOURCES "AudioProcessor.cc" "WakeWordDetect.cc")
|
||||
endif()
|
||||
if(CONFIG_AUDIO_CODEC_ES8311_ES7210)
|
||||
list(APPEND SOURCES "BoxAudioDevice.cc")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "."
|
||||
INCLUDE_DIRS ${INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
# 使用 target_compile_definitions 来定义 BOARD_TYPE
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\")
|
||||
105
main/Display.cc
105
main/Display.cc
@ -1,6 +1,3 @@
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
@ -9,11 +6,17 @@
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "Display.h"
|
||||
#include "Board.h"
|
||||
#include "Application.h"
|
||||
|
||||
#define TAG "Display"
|
||||
|
||||
#ifdef CONFIG_USE_DISPLAY
|
||||
|
||||
Display::Display(int sda_pin, int scl_pin) : sda_pin_(sda_pin), scl_pin_(scl_pin) {
|
||||
if (sda_pin_ == GPIO_NUM_NC || scl_pin_ == GPIO_NUM_NC) {
|
||||
ESP_LOGI(TAG, "Display not connected");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Display Pins: %d, %d", sda_pin_, scl_pin_);
|
||||
|
||||
i2c_master_bus_config_t bus_config = {
|
||||
@ -55,7 +58,7 @@ Display::Display(int sda_pin, int scl_pin) : sda_pin_(sda_pin), scl_pin_(scl_pin
|
||||
panel_config.bits_per_pixel = 1;
|
||||
|
||||
esp_lcd_panel_ssd1306_config_t ssd1306_config = {
|
||||
.height = CONFIG_DISPLAY_HEIGHT
|
||||
.height = DISPLAY_HEIGHT
|
||||
};
|
||||
panel_config.vendor_config = &ssd1306_config;
|
||||
|
||||
@ -68,50 +71,72 @@ Display::Display(int sda_pin, int scl_pin) : sda_pin_(sda_pin), scl_pin_(scl_pin
|
||||
ESP_LOGE(TAG, "Failed to initialize display");
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_, true, true));
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LVGL");
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
lvgl_port_init(&port_cfg);
|
||||
|
||||
const lvgl_port_display_cfg_t display_cfg = {
|
||||
.io_handle = panel_io_,
|
||||
.panel_handle = panel_,
|
||||
.buffer_size = 128 * CONFIG_DISPLAY_HEIGHT,
|
||||
.double_buffer = true,
|
||||
.hres = 128,
|
||||
.vres = CONFIG_DISPLAY_HEIGHT,
|
||||
.monochrome = true,
|
||||
.rotation = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
.flags = {
|
||||
.buff_dma = 0,
|
||||
.buff_spiram = 0,
|
||||
},
|
||||
};
|
||||
disp_ = lvgl_port_add_disp(&display_cfg);
|
||||
lv_disp_set_rotation(disp_, LV_DISP_ROT_180);
|
||||
|
||||
// Set the display to on
|
||||
ESP_LOGI(TAG, "Turning display on");
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));
|
||||
|
||||
ESP_LOGI(TAG, "Adding LCD screen");
|
||||
const lvgl_port_display_cfg_t display_cfg = {
|
||||
.io_handle = panel_io_,
|
||||
.panel_handle = panel_,
|
||||
.control_handle = nullptr,
|
||||
.buffer_size = DISPLAY_WIDTH * DISPLAY_HEIGHT,
|
||||
.double_buffer = false,
|
||||
.trans_size = 0,
|
||||
.hres = DISPLAY_WIDTH,
|
||||
.vres = DISPLAY_HEIGHT,
|
||||
.monochrome = true,
|
||||
.rotation = {
|
||||
.swap_xy = false,
|
||||
.mirror_x = true,
|
||||
.mirror_y = true,
|
||||
},
|
||||
.flags = {
|
||||
.buff_dma = 1,
|
||||
.buff_spiram = 0,
|
||||
.sw_rotate = 0,
|
||||
.full_refresh = 0,
|
||||
.direct_mode = 0,
|
||||
},
|
||||
};
|
||||
disp_ = lvgl_port_add_disp(&display_cfg);;
|
||||
|
||||
ESP_LOGI(TAG, "Display Loading...");
|
||||
if (lvgl_port_lock(0)) {
|
||||
label_ = lv_label_create(lv_disp_get_scr_act(disp_));
|
||||
// lv_obj_set_style_text_font(label_, font_, 0);
|
||||
lv_label_set_text(label_, "Initializing...");
|
||||
lv_obj_set_width(label_, disp_->driver->hor_res);
|
||||
lv_obj_set_height(label_, disp_->driver->ver_res);
|
||||
|
||||
notification_ = lv_label_create(lv_disp_get_scr_act(disp_));
|
||||
// lv_obj_set_style_text_font(notification_, font_, 0);
|
||||
lv_label_set_text(notification_, "Notification\nTest");
|
||||
lv_obj_set_width(notification_, disp_->driver->hor_res);
|
||||
lv_obj_set_height(notification_, disp_->driver->ver_res);
|
||||
lv_obj_set_style_opa(notification_, LV_OPA_MIN, 0);
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
// Create a timer to update the display every 10 seconds
|
||||
esp_timer_create_args_t update_display_timer_args = {
|
||||
.callback = [](void *arg) {
|
||||
Display* display = static_cast<Display*>(arg);
|
||||
display->UpdateDisplay();
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "UpdateDisplay",
|
||||
.skip_unhandled_events = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&update_display_timer_args, &update_display_timer_));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(update_display_timer_, 10 * 1000000));
|
||||
}
|
||||
|
||||
Display::~Display() {
|
||||
@ -119,6 +144,10 @@ Display::~Display() {
|
||||
esp_timer_stop(notification_timer_);
|
||||
esp_timer_delete(notification_timer_);
|
||||
}
|
||||
if (update_display_timer_ != nullptr) {
|
||||
esp_timer_stop(update_display_timer_);
|
||||
esp_timer_delete(update_display_timer_);
|
||||
}
|
||||
|
||||
lvgl_port_lock(0);
|
||||
if (label_ != nullptr) {
|
||||
@ -127,6 +156,10 @@ Display::~Display() {
|
||||
}
|
||||
lvgl_port_unlock();
|
||||
|
||||
if (font_ != nullptr) {
|
||||
lv_font_free(font_);
|
||||
}
|
||||
|
||||
if (disp_ != nullptr) {
|
||||
lvgl_port_deinit();
|
||||
esp_lcd_panel_del(panel_);
|
||||
@ -176,4 +209,20 @@ void Display::ShowNotification(const std::string &text) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
void Display::UpdateDisplay() {
|
||||
auto chat_state = Application::GetInstance().GetChatState();
|
||||
if (chat_state == kChatStateIdle || chat_state == kChatStateConnecting || chat_state == kChatStateListening) {
|
||||
std::string text;
|
||||
auto& board = Board::GetInstance();
|
||||
std::string network_name;
|
||||
int signal_quality;
|
||||
std::string signal_quality_text;
|
||||
if (!board.GetNetworkState(network_name, signal_quality, signal_quality_text)) {
|
||||
text = "No network";
|
||||
} else {
|
||||
ESP_LOGI(TAG, "%s CSQ: %d", network_name.c_str(), signal_quality);
|
||||
text = network_name + "\n" + signal_quality_text + " (" + std::to_string(signal_quality) + ")";
|
||||
}
|
||||
SetText(text);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@ public:
|
||||
void SetText(const std::string &text);
|
||||
void ShowNotification(const std::string &text);
|
||||
|
||||
void UpdateDisplay();
|
||||
|
||||
private:
|
||||
int sda_pin_;
|
||||
int scl_pin_;
|
||||
@ -26,9 +28,11 @@ private:
|
||||
esp_lcd_panel_io_handle_t panel_io_ = nullptr;
|
||||
esp_lcd_panel_handle_t panel_ = nullptr;
|
||||
lv_disp_t *disp_ = nullptr;
|
||||
lv_font_t *font_ = nullptr;
|
||||
lv_obj_t *label_ = nullptr;
|
||||
lv_obj_t *notification_ = nullptr;
|
||||
esp_timer_handle_t notification_timer_ = nullptr;
|
||||
esp_timer_handle_t update_display_timer_ = nullptr;
|
||||
|
||||
std::string text_;
|
||||
};
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "FirmwareUpgrade.h"
|
||||
#include "SystemInfo.h"
|
||||
#include "Board.h"
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_partition.h>
|
||||
@ -15,7 +17,7 @@
|
||||
#define TAG "FirmwareUpgrade"
|
||||
|
||||
|
||||
FirmwareUpgrade::FirmwareUpgrade(Http& http) : http_(http) {
|
||||
FirmwareUpgrade::FirmwareUpgrade() {
|
||||
}
|
||||
|
||||
FirmwareUpgrade::~FirmwareUpgrade() {
|
||||
@ -38,16 +40,18 @@ void FirmwareUpgrade::CheckVersion() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto http = Board::GetInstance().CreateHttp();
|
||||
for (const auto& header : headers_) {
|
||||
http_.SetHeader(header.first, header.second);
|
||||
http->SetHeader(header.first, header.second);
|
||||
}
|
||||
|
||||
http_.SetHeader("Content-Type", "application/json");
|
||||
http_.SetContent(GetPostData());
|
||||
http_.Open("POST", check_version_url_);
|
||||
http->SetHeader("Content-Type", "application/json");
|
||||
http->SetContent(GetPostData());
|
||||
http->Open("POST", check_version_url_);
|
||||
|
||||
auto response = http_.GetBody();
|
||||
http_.Close();
|
||||
auto response = http->GetBody();
|
||||
http->Close();
|
||||
delete http;
|
||||
|
||||
// Response: { "firmware": { "version": "1.0.0", "url": "http://" } }
|
||||
// Parse the JSON response and check if the version is newer
|
||||
@ -123,15 +127,17 @@ void FirmwareUpgrade::Upgrade(const std::string& firmware_url) {
|
||||
bool image_header_checked = false;
|
||||
std::string image_header;
|
||||
|
||||
if (!http_.Open("GET", firmware_url)) {
|
||||
auto http = Board::GetInstance().CreateHttp();
|
||||
if (!http->Open("GET", firmware_url)) {
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection");
|
||||
delete http;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t content_length = http_.GetBodyLength();
|
||||
size_t content_length = http->GetBodyLength();
|
||||
if (content_length == 0) {
|
||||
ESP_LOGE(TAG, "Failed to get content length");
|
||||
http_.Close();
|
||||
delete http;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -139,10 +145,10 @@ void FirmwareUpgrade::Upgrade(const std::string& firmware_url) {
|
||||
size_t total_read = 0, recent_read = 0;
|
||||
auto last_calc_time = esp_timer_get_time();
|
||||
while (true) {
|
||||
int ret = http_.Read(buffer, sizeof(buffer));
|
||||
int ret = http->Read(buffer, sizeof(buffer));
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Failed to read HTTP data: %s", esp_err_to_name(ret));
|
||||
http_.Close();
|
||||
delete http;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -174,13 +180,13 @@ void FirmwareUpgrade::Upgrade(const std::string& firmware_url) {
|
||||
auto current_version = esp_app_get_description()->version;
|
||||
if (memcmp(new_app_info.version, current_version, sizeof(new_app_info.version)) == 0) {
|
||||
ESP_LOGE(TAG, "Firmware version is the same, skipping upgrade");
|
||||
http_.Close();
|
||||
delete http;
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle)) {
|
||||
esp_ota_abort(update_handle);
|
||||
http_.Close();
|
||||
delete http;
|
||||
ESP_LOGE(TAG, "Failed to begin OTA");
|
||||
return;
|
||||
}
|
||||
@ -192,11 +198,11 @@ void FirmwareUpgrade::Upgrade(const std::string& firmware_url) {
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write OTA data: %s", esp_err_to_name(err));
|
||||
esp_ota_abort(update_handle);
|
||||
http_.Close();
|
||||
delete http;
|
||||
return;
|
||||
}
|
||||
}
|
||||
http_.Close();
|
||||
delete http;
|
||||
|
||||
esp_err_t err = esp_ota_end(update_handle);
|
||||
if (err != ESP_OK) {
|
||||
|
||||
@ -5,11 +5,9 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <Http.h>
|
||||
|
||||
class FirmwareUpgrade {
|
||||
public:
|
||||
FirmwareUpgrade(Http& http);
|
||||
FirmwareUpgrade();
|
||||
~FirmwareUpgrade();
|
||||
|
||||
void SetBoardJson(const std::string& board_json);
|
||||
@ -21,7 +19,6 @@ public:
|
||||
void MarkCurrentVersionValid();
|
||||
|
||||
private:
|
||||
Http& http_;
|
||||
std::string check_version_url_;
|
||||
bool has_new_version_ = false;
|
||||
std::string firmware_version_;
|
||||
|
||||
@ -18,218 +18,25 @@ config WEBSOCKET_ACCESS_TOKEN
|
||||
help
|
||||
Access token for websocket communication.
|
||||
|
||||
config AUDIO_INPUT_SAMPLE_RATE
|
||||
int "Audio Input Sample Rate"
|
||||
default 16000
|
||||
choice BOARD_TYPE
|
||||
prompt "Board Type"
|
||||
default BOARD_TYPE_BREAD_COMPACT_WIFI
|
||||
help
|
||||
Audio input sample rate.
|
||||
|
||||
config AUDIO_OUTPUT_SAMPLE_RATE
|
||||
int "Audio Output Sample Rate"
|
||||
default 24000
|
||||
help
|
||||
Audio output sample rate.
|
||||
|
||||
choice AUDIO_CODEC
|
||||
prompt "Audio Codec"
|
||||
default AUDIO_CODEC_NONE
|
||||
help
|
||||
Audio codec.
|
||||
config AUDIO_CODEC_ES8311_ES7210
|
||||
bool "Box: ES8311 + ES7210"
|
||||
config AUDIO_CODEC_NONE
|
||||
bool "None"
|
||||
Board type. 开发板类型
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI
|
||||
bool "面包板新版接线(WiFi)"
|
||||
config BOARD_TYPE_BREAD_COMPACT_ML307
|
||||
bool "面包板新版接线(ML307 AT)"
|
||||
config BOARD_TYPE_ESP_BOX_3
|
||||
bool "ESP BOX 3"
|
||||
config BOARD_TYPE_KEVIN_BOX_0
|
||||
bool "Kevin Box 0"
|
||||
endchoice
|
||||
|
||||
menu "Box Audio Codec I2C and PA Control"
|
||||
depends on AUDIO_CODEC_ES8311_ES7210
|
||||
|
||||
config AUDIO_CODEC_I2C_SDA_PIN
|
||||
int "Audio Codec I2C SDA Pin"
|
||||
default 39
|
||||
help
|
||||
Audio codec I2C SDA pin.
|
||||
|
||||
config AUDIO_CODEC_I2C_SCL_PIN
|
||||
int "Audio Codec I2C SCL Pin"
|
||||
default 38
|
||||
help
|
||||
Audio codec I2C SCL pin.
|
||||
|
||||
config AUDIO_CODEC_PA_PIN
|
||||
int "Audio Codec PA Pin"
|
||||
default 40
|
||||
help
|
||||
Audio codec PA pin.
|
||||
|
||||
config AUDIO_CODEC_INPUT_REFERENCE
|
||||
bool "Audio Codec Input Reference"
|
||||
default y
|
||||
help
|
||||
Audio codec input reference.
|
||||
endmenu
|
||||
|
||||
choice AUDIO_I2S_METHOD
|
||||
prompt "Audio I2S Method"
|
||||
default AUDIO_I2S_METHOD_SIMPLEX if AUDIO_CODEC_NONE
|
||||
default AUDIO_I2S_METHOD_DUPLEX if AUDIO_CODEC_ES8311_ES7210
|
||||
help
|
||||
Audio I2S method.
|
||||
config AUDIO_I2S_METHOD_SIMPLEX
|
||||
bool "Simplex"
|
||||
help
|
||||
Use I2S 0 as the audio input and I2S 1 as the audio output.
|
||||
config AUDIO_I2S_METHOD_DUPLEX
|
||||
bool "Duplex"
|
||||
help
|
||||
Use I2S 0 as the audio input and audio output.
|
||||
endchoice
|
||||
|
||||
menu "Audio I2S Simplex"
|
||||
depends on AUDIO_I2S_METHOD_SIMPLEX
|
||||
|
||||
config AUDIO_DEVICE_I2S_MIC_GPIO_WS
|
||||
int "I2S MIC GPIO WS"
|
||||
default 4
|
||||
help
|
||||
GPIO number of the I2S MIC WS.
|
||||
|
||||
config AUDIO_DEVICE_I2S_MIC_GPIO_SCK
|
||||
int "I2S MIC GPIO BCLK"
|
||||
default 5
|
||||
help
|
||||
GPIO number of the I2S MIC SCK.
|
||||
|
||||
config AUDIO_DEVICE_I2S_MIC_GPIO_DIN
|
||||
int "I2S MIC GPIO DIN"
|
||||
default 6
|
||||
help
|
||||
GPIO number of the I2S MIC DIN.
|
||||
|
||||
config AUDIO_DEVICE_I2S_SPK_GPIO_DOUT
|
||||
int "I2S SPK GPIO DOUT"
|
||||
default 7
|
||||
help
|
||||
GPIO number of the I2S SPK DOUT.
|
||||
|
||||
config AUDIO_DEVICE_I2S_SPK_GPIO_BCLK
|
||||
int "I2S SPK GPIO BCLK"
|
||||
default 15
|
||||
help
|
||||
GPIO number of the I2S SPK BCLK.
|
||||
|
||||
config AUDIO_DEVICE_I2S_SPK_GPIO_LRCK
|
||||
int "I2S SPK GPIO WS"
|
||||
default 16
|
||||
help
|
||||
GPIO number of the I2S SPK LRCK.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Audio I2S Duplex"
|
||||
depends on AUDIO_I2S_METHOD_DUPLEX
|
||||
|
||||
config AUDIO_DEVICE_I2S_GPIO_MCLK
|
||||
int "I2S GPIO MCLK"
|
||||
default -1
|
||||
help
|
||||
GPIO number of the I2S WS.
|
||||
|
||||
config AUDIO_DEVICE_I2S_GPIO_LRCK
|
||||
int "I2S GPIO LRCK"
|
||||
default 4
|
||||
help
|
||||
GPIO number of the I2S LRCK.
|
||||
|
||||
config AUDIO_DEVICE_I2S_GPIO_BCLK
|
||||
int "I2S GPIO BCLK / SCLK"
|
||||
default 5
|
||||
help
|
||||
GPIO number of the I2S BCLK.
|
||||
|
||||
config AUDIO_DEVICE_I2S_GPIO_DIN
|
||||
int "I2S GPIO DIN"
|
||||
default 6
|
||||
help
|
||||
GPIO number of the I2S DIN.
|
||||
|
||||
config AUDIO_DEVICE_I2S_GPIO_DOUT
|
||||
int "I2S GPIO DOUT"
|
||||
default 7
|
||||
help
|
||||
GPIO number of the I2S DOUT.
|
||||
|
||||
endmenu
|
||||
|
||||
config BOOT_BUTTON_GPIO
|
||||
int "Boot Button GPIO"
|
||||
default 0
|
||||
help
|
||||
GPIO number of the boot button.
|
||||
|
||||
config VOLUME_UP_BUTTON_GPIO
|
||||
int "Volume Up Button GPIO"
|
||||
default 40
|
||||
help
|
||||
GPIO number of the volume up button.
|
||||
|
||||
config VOLUME_DOWN_BUTTON_GPIO
|
||||
int "Volume Down Button GPIO"
|
||||
default 39
|
||||
help
|
||||
GPIO number of the volume down button.
|
||||
|
||||
config USE_AFE_SR
|
||||
bool "Use Espressif AFE SR"
|
||||
default y
|
||||
help
|
||||
Use AFE SR for wake word detection.
|
||||
|
||||
config USE_ML307
|
||||
bool "Use ML307"
|
||||
default n
|
||||
help
|
||||
Use ML307 as the modem.
|
||||
|
||||
config ML307_RX_PIN
|
||||
int "ML307 RX Pin"
|
||||
default 11
|
||||
depends on USE_ML307
|
||||
help
|
||||
GPIO number of the ML307 RX.
|
||||
|
||||
config ML307_TX_PIN
|
||||
int "ML307 TX Pin"
|
||||
default 12
|
||||
depends on USE_ML307
|
||||
help
|
||||
GPIO number of the ML307 TX.
|
||||
|
||||
config USE_DISPLAY
|
||||
bool "Use Display"
|
||||
default n
|
||||
help
|
||||
Use Display.
|
||||
|
||||
config DISPLAY_HEIGHT
|
||||
int "Display Height"
|
||||
default 32
|
||||
depends on USE_DISPLAY
|
||||
help
|
||||
Display height in pixels.
|
||||
|
||||
config DISPLAY_SDA_PIN
|
||||
int "Display SDA Pin"
|
||||
default 41
|
||||
depends on USE_DISPLAY
|
||||
help
|
||||
GPIO number of the Display SDA.
|
||||
|
||||
config DISPLAY_SCL_PIN
|
||||
int "Display SCL Pin"
|
||||
default 42
|
||||
depends on USE_DISPLAY
|
||||
help
|
||||
GPIO number of the Display SCL.
|
||||
|
||||
endmenu
|
||||
|
||||
98
main/Ml307Board.cc
Normal file
98
main/Ml307Board.cc
Normal file
@ -0,0 +1,98 @@
|
||||
#include "Ml307Board.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <Ml307Http.h>
|
||||
#include <Ml307SslTransport.h>
|
||||
#include <WebSocket.h>
|
||||
#include <esp_timer.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() : modem_(ML307_TX_PIN, ML307_RX_PIN, 4096) {
|
||||
}
|
||||
|
||||
void Ml307Board::StartModem() {
|
||||
auto& application = Application::GetInstance();
|
||||
auto& display = application.GetDisplay();
|
||||
modem_.SetDebug(false);
|
||||
modem_.SetBaudRate(921600);
|
||||
// Print the ML307 modem information
|
||||
std::string module_name = modem_.GetModuleName();
|
||||
ESP_LOGI(TAG, "ML307 Module: %s", module_name.c_str());
|
||||
display.SetText(std::string("Wait for network\n") + module_name);
|
||||
modem_.ResetConnections();
|
||||
modem_.WaitForNetworkReady();
|
||||
|
||||
std::string imei = modem_.GetImei();
|
||||
std::string iccid = modem_.GetIccid();
|
||||
ESP_LOGI(TAG, "ML307 IMEI: %s", imei.c_str());
|
||||
ESP_LOGI(TAG, "ML307 ICCID: %s", iccid.c_str());
|
||||
|
||||
// If low power, the material ready event will be triggered by the modem because of a reset
|
||||
modem_.OnMaterialReady([&application]() {
|
||||
ESP_LOGI(TAG, "ML307 material ready");
|
||||
application.Schedule([&application]() {
|
||||
application.SetChatState(kChatStateIdle);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Ml307Board::Initialize() {
|
||||
ESP_LOGI(TAG, "Initializing Ml307Board");
|
||||
StartModem();
|
||||
}
|
||||
|
||||
AudioDevice* Ml307Board::CreateAudioDevice() {
|
||||
return new AudioDevice();
|
||||
}
|
||||
|
||||
Http* Ml307Board::CreateHttp() {
|
||||
return new Ml307Http(modem_);
|
||||
}
|
||||
|
||||
WebSocket* Ml307Board::CreateWebSocket() {
|
||||
return new WebSocket(new Ml307SslTransport(modem_, 0));
|
||||
}
|
||||
|
||||
bool Ml307Board::GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) {
|
||||
network_name = modem_.GetCarrierName();
|
||||
signal_quality = modem_.GetCsq();
|
||||
signal_quality_text = csq_to_string(signal_quality);
|
||||
return signal_quality != -1;
|
||||
}
|
||||
|
||||
std::string Ml307Board::GetJson() {
|
||||
// Set the board type for OTA
|
||||
std::string board_type = BOARD_TYPE;
|
||||
std::string module_name = modem_.GetModuleName();
|
||||
std::string carrier_name = modem_.GetCarrierName();
|
||||
std::string imei = modem_.GetImei();
|
||||
std::string iccid = modem_.GetIccid();
|
||||
int csq = modem_.GetCsq();
|
||||
std::string board_json = std::string("{\"type\":\"" + board_type + "\",");
|
||||
board_json += "\"revision\":\"" + module_name + "\",";
|
||||
board_json += "\"carrier\":\"" + carrier_name + "\",";
|
||||
board_json += "\"csq\":\"" + std::to_string(csq) + "\",";
|
||||
board_json += "\"imei\":\"" + imei + "\",";
|
||||
board_json += "\"iccid\":\"" + iccid + "\"}";
|
||||
return board_json;
|
||||
}
|
||||
23
main/Ml307Board.h
Normal file
23
main/Ml307Board.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef ML307_BOARD_H
|
||||
#define ML307_BOARD_H
|
||||
|
||||
#include "Board.h"
|
||||
#include <Ml307AtModem.h>
|
||||
|
||||
class Ml307Board : public Board {
|
||||
protected:
|
||||
Ml307AtModem modem_;
|
||||
|
||||
void StartModem();
|
||||
|
||||
public:
|
||||
Ml307Board();
|
||||
virtual void Initialize() override;
|
||||
virtual AudioDevice* CreateAudioDevice() override;
|
||||
virtual Http* CreateHttp() override;
|
||||
virtual WebSocket* CreateWebSocket() override;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
|
||||
virtual std::string GetJson() override;
|
||||
};
|
||||
|
||||
#endif // ML307_BOARD_H
|
||||
@ -3,11 +3,18 @@
|
||||
|
||||
class SystemReset {
|
||||
public:
|
||||
SystemReset();
|
||||
static SystemReset& GetInstance() {
|
||||
static SystemReset instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void CheckButtons();
|
||||
|
||||
private:
|
||||
SystemReset(); // 构造函数私有化
|
||||
SystemReset(const SystemReset&) = delete; // 禁用拷贝构造
|
||||
SystemReset& operator=(const SystemReset&) = delete; // 禁用赋值操作
|
||||
|
||||
void ResetNvsFlash();
|
||||
void ResetToFactory();
|
||||
void RestartInSeconds(int seconds);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include <esp_log.h>
|
||||
#include <model_path.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "WakeWordDetect.h"
|
||||
#include "Application.h"
|
||||
|
||||
95
main/WifiBoard.cc
Normal file
95
main/WifiBoard.cc
Normal file
@ -0,0 +1,95 @@
|
||||
#include "WifiBoard.h"
|
||||
#include "Application.h"
|
||||
#include "WifiStation.h"
|
||||
#include "WifiConfigurationAp.h"
|
||||
#include "SystemInfo.h"
|
||||
#include "BuiltinLed.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <EspHttp.h>
|
||||
#include <TcpTransport.h>
|
||||
#include <TlsTransport.h>
|
||||
#include <WebSocket.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
void WifiBoard::StartWifi() {
|
||||
auto& application = Application::GetInstance();
|
||||
auto& display = application.GetDisplay();
|
||||
auto& builtin_led = BuiltinLed::GetInstance();
|
||||
|
||||
// Try to connect to WiFi, if failed, launch the WiFi configuration AP
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
display.SetText(std::string("Connect to WiFi\n") + wifi_station.GetSsid());
|
||||
wifi_station.Start();
|
||||
if (!wifi_station.IsConnected()) {
|
||||
builtin_led.SetBlue();
|
||||
builtin_led.Blink(1000, 500);
|
||||
auto& wifi_ap = WifiConfigurationAp::GetInstance();
|
||||
wifi_ap.SetSsidPrefix("Xiaozhi");
|
||||
display.SetText(wifi_ap.GetSsid() + "\n" + wifi_ap.GetWebServerUrl());
|
||||
wifi_ap.Start();
|
||||
// Wait until the WiFi configuration is finished
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WifiBoard::Initialize() {
|
||||
ESP_LOGI(TAG, "Initializing WifiBoard");
|
||||
StartWifi();
|
||||
}
|
||||
|
||||
Http* WifiBoard::CreateHttp() {
|
||||
return new EspHttp();
|
||||
}
|
||||
|
||||
WebSocket* WifiBoard::CreateWebSocket() {
|
||||
std::string url = CONFIG_WEBSOCKET_URL;
|
||||
if (url.find("wss://") == 0) {
|
||||
return new WebSocket(new TlsTransport());
|
||||
} else {
|
||||
return new WebSocket(new TcpTransport());
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiBoard::GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) {
|
||||
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;
|
||||
}
|
||||
|
||||
std::string WifiBoard::GetJson() {
|
||||
// Set the board type for OTA
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
std::string board_type = BOARD_TYPE;
|
||||
std::string board_json = std::string("{\"type\":\"" + board_type + "\",");
|
||||
board_json += "\"ssid\":\"" + wifi_station.GetSsid() + "\",";
|
||||
board_json += "\"rssi\":" + std::to_string(wifi_station.GetRssi()) + ",";
|
||||
board_json += "\"channel\":" + std::to_string(wifi_station.GetChannel()) + ",";
|
||||
board_json += "\"ip\":\"" + wifi_station.GetIpAddress() + "\",";
|
||||
board_json += "\"mac\":\"" + SystemInfo::GetMacAddress() + "\"}";
|
||||
return board_json;
|
||||
}
|
||||
18
main/WifiBoard.h
Normal file
18
main/WifiBoard.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef WIFI_BOARD_H
|
||||
#define WIFI_BOARD_H
|
||||
|
||||
#include "Board.h"
|
||||
|
||||
class WifiBoard : public Board {
|
||||
protected:
|
||||
virtual void StartWifi();
|
||||
|
||||
public:
|
||||
virtual void Initialize() override;
|
||||
virtual Http* CreateHttp() override;
|
||||
virtual WebSocket* CreateWebSocket() override;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
|
||||
virtual std::string GetJson() override;
|
||||
};
|
||||
|
||||
#endif // WIFI_BOARD_H
|
||||
18
main/boards/bread-compact-ml307/CompactMl307Board.cc
Normal file
18
main/boards/bread-compact-ml307/CompactMl307Board.cc
Normal file
@ -0,0 +1,18 @@
|
||||
#include "Ml307Board.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "CompactMl307Board"
|
||||
|
||||
class CompactMl307Board : public Ml307Board {
|
||||
public:
|
||||
virtual void Initialize() override {
|
||||
ESP_LOGI(TAG, "Initializing CompactMl307Board");
|
||||
Ml307Board::Initialize();
|
||||
}
|
||||
|
||||
virtual AudioDevice* CreateAudioDevice() override {
|
||||
return new AudioDevice();
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CompactMl307Board);
|
||||
45
main/boards/bread-compact-ml307/config.h
Normal file
45
main/boards/bread-compact-ml307/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_I2S_METHOD_SIMPLEX
|
||||
|
||||
#ifdef AUDIO_I2S_METHOD_SIMPLEX
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_5
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_7
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_16
|
||||
|
||||
#else
|
||||
|
||||
#define AUDIO_I2S_GPIO_LRCK GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
#endif
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_48
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_40
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_39
|
||||
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 32
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_41
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_42
|
||||
|
||||
|
||||
#define ML307_RX_PIN GPIO_NUM_11
|
||||
#define ML307_TX_PIN GPIO_NUM_12
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
19
main/boards/bread-compact-wifi/CompactWifiBoard.cc
Normal file
19
main/boards/bread-compact-wifi/CompactWifiBoard.cc
Normal file
@ -0,0 +1,19 @@
|
||||
#include "WifiBoard.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "CompactWifiBoard"
|
||||
|
||||
class CompactWifiBoard : public WifiBoard {
|
||||
public:
|
||||
virtual void Initialize() override {
|
||||
ESP_LOGI(TAG, "Initializing CompactWifiBoard");
|
||||
WifiBoard::Initialize();
|
||||
}
|
||||
|
||||
virtual AudioDevice* CreateAudioDevice() override {
|
||||
return new AudioDevice();
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CompactWifiBoard);
|
||||
40
main/boards/bread-compact-wifi/config.h
Normal file
40
main/boards/bread-compact-wifi/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_METHOD_SIMPLEX
|
||||
|
||||
#ifdef AUDIO_I2S_METHOD_SIMPLEX
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_5
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_7
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_16
|
||||
|
||||
#else
|
||||
|
||||
#define AUDIO_I2S_GPIO_LRCK GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_48
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_40
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_39
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 32
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_41
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_42
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
20
main/boards/esp-box-3/EspBox3Board.cc
Normal file
20
main/boards/esp-box-3/EspBox3Board.cc
Normal file
@ -0,0 +1,20 @@
|
||||
#include "WifiBoard.h"
|
||||
#include "BoxAudioDevice.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "EspBox3Board"
|
||||
|
||||
class EspBox3Board : public WifiBoard {
|
||||
public:
|
||||
virtual void Initialize() override {
|
||||
ESP_LOGI(TAG, "Initializing EspBox3Board");
|
||||
WifiBoard::Initialize();
|
||||
}
|
||||
|
||||
virtual AudioDevice* CreateAudioDevice() override {
|
||||
return new BoxAudioDevice();
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(EspBox3Board);
|
||||
32
main/boards/esp-box-3/config.h
Normal file
32
main/boards/esp-box-3/config.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 16000
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_2
|
||||
#define AUDIO_I2S_GPIO_LRCK GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_17
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_15
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_46
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_18
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_NC
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_NC
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
48
main/boards/kevin-box-0/KevinBoxBoard.cc
Normal file
48
main/boards/kevin-box-0/KevinBoxBoard.cc
Normal file
@ -0,0 +1,48 @@
|
||||
#include "Ml307Board.h"
|
||||
#include "BoxAudioDevice.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_spiffs.h>
|
||||
#include <driver/gpio.h>
|
||||
|
||||
static const char *TAG = "KevinBoxBoard";
|
||||
|
||||
class KevinBoxBoard : public Ml307Board {
|
||||
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 GPIO15 HIGH to enable the 4G module
|
||||
gpio_config_t ml307_enable_config = {
|
||||
.pin_bit_mask = (1ULL << 15),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&ml307_enable_config);
|
||||
gpio_set_level(GPIO_NUM_15, 1);
|
||||
}
|
||||
public:
|
||||
virtual void Initialize() override {
|
||||
ESP_LOGI(TAG, "Initializing KevinBoxBoard");
|
||||
MountStorage();
|
||||
Enable4GModule();
|
||||
Ml307Board::Initialize();
|
||||
}
|
||||
|
||||
virtual AudioDevice* CreateAudioDevice() override {
|
||||
return new BoxAudioDevice();
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(KevinBoxBoard);
|
||||
35
main/boards/kevin-box-0/config.h
Normal file
35
main/boards/kevin-box-0/config.h
Normal file
@ -0,0 +1,35 @@
|
||||
#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_INPUT_REFERENCE true
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_0
|
||||
#define AUDIO_I2S_GPIO_LRCK GPIO_NUM_47
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_48
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_45
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_21
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_40
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_39
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_38
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_8
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_6
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_7
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_4
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_5
|
||||
|
||||
#define ML307_RX_PIN GPIO_NUM_17
|
||||
#define ML307_TX_PIN GPIO_NUM_16
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@ -1,14 +1,14 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
78/esp-builtin-led: "^1.0.2"
|
||||
78/esp-wifi-connect: "^1.2.0"
|
||||
78/esp-opus-encoder: "^1.0.2"
|
||||
78/esp-ml307: "^1.2.1"
|
||||
espressif/led_strip: "^2.4.1"
|
||||
espressif/esp_codec_dev: "^1.3.1"
|
||||
espressif/esp-sr: "^1.9.0"
|
||||
espressif/button: "^3.3.1"
|
||||
lvgl/lvgl: "^8.4.0"
|
||||
esp_lvgl_port: "^1.4.0"
|
||||
esp_lvgl_port: "^2.4.1"
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: ">=5.3"
|
||||
|
||||
16
main/main.cc
16
main/main.cc
@ -13,22 +13,8 @@
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
#ifdef CONFIG_AUDIO_CODEC_ES8311_ES7210
|
||||
// Make GPIO15 HIGH to enable the 4G module
|
||||
gpio_config_t ml307_enable_config = {
|
||||
.pin_bit_mask = (1ULL << 15),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&ml307_enable_config);
|
||||
gpio_set_level(GPIO_NUM_15, 1);
|
||||
#endif
|
||||
|
||||
// Check if the reset button is pressed
|
||||
SystemReset system_reset;
|
||||
system_reset.CheckButtons();
|
||||
SystemReset::GetInstance().CheckButtons();
|
||||
|
||||
// Initialize the default event loop
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
@ -4,6 +4,7 @@ nvs, data, nvs, 0x9000, 0x4000,
|
||||
otadata, data, ota, 0xd000, 0x2000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
model, data, spiffs, 0x10000, 0xF0000,
|
||||
storage, data, spiffs, 0x100000, 1M,
|
||||
factory, app, factory, 0x200000, 4M,
|
||||
ota_0, app, ota_0, 0x600000, 4M,
|
||||
ota_1, app, ota_1, 0xA00000, 4M,
|
||||
|
||||
|
2667
sdkconfig.box
2667
sdkconfig.box
File diff suppressed because it is too large
Load Diff
@ -57,7 +57,7 @@ def get_board_name(folder):
|
||||
basename = os.path.basename(folder)
|
||||
if basename.startswith("v0.2"):
|
||||
return "simple"
|
||||
if basename.startswith("v0.3") or basename.startswith("v0.4"):
|
||||
if basename.startswith("v0.3") or basename.startswith("v0.4") or basename.startswith("v0.5"):
|
||||
if "ML307" in basename:
|
||||
return "compact.4g"
|
||||
else:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user