add config files for known boards
This commit is contained in:
@ -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());
|
||||
|
||||
Reference in New Issue
Block a user