在S3芯片上使用更多的PSRAM,解决立创开发板拍照时可能出现内存不足的问题

This commit is contained in:
Terrence
2025-06-24 04:59:00 +08:00
parent 2b0362a812
commit b3ab3d0920
5 changed files with 50 additions and 54 deletions

View File

@@ -100,7 +100,7 @@ Application::~Application() {
vEventGroupDelete(event_group_); vEventGroupDelete(event_group_);
} }
void Application::CheckNewVersion() { void Application::CheckNewVersion(Ota& ota) {
const int MAX_RETRY = 10; const int MAX_RETRY = 10;
int retry_count = 0; int retry_count = 0;
int retry_delay = 10; // 初始重试延迟为10秒 int retry_delay = 10; // 初始重试延迟为10秒
@@ -110,7 +110,7 @@ void Application::CheckNewVersion() {
auto display = Board::GetInstance().GetDisplay(); auto display = Board::GetInstance().GetDisplay();
display->SetStatus(Lang::Strings::CHECKING_NEW_VERSION); display->SetStatus(Lang::Strings::CHECKING_NEW_VERSION);
if (!ota_.CheckVersion()) { if (!ota.CheckVersion()) {
retry_count++; retry_count++;
if (retry_count >= MAX_RETRY) { if (retry_count >= MAX_RETRY) {
ESP_LOGE(TAG, "Too many retries, exit version check"); ESP_LOGE(TAG, "Too many retries, exit version check");
@@ -118,7 +118,7 @@ void Application::CheckNewVersion() {
} }
char buffer[128]; char buffer[128];
snprintf(buffer, sizeof(buffer), Lang::Strings::CHECK_NEW_VERSION_FAILED, retry_delay, ota_.GetCheckVersionUrl().c_str()); snprintf(buffer, sizeof(buffer), Lang::Strings::CHECK_NEW_VERSION_FAILED, retry_delay, ota.GetCheckVersionUrl().c_str());
Alert(Lang::Strings::ERROR, buffer, "sad", Lang::Sounds::P3_EXCLAMATION); Alert(Lang::Strings::ERROR, buffer, "sad", Lang::Sounds::P3_EXCLAMATION);
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", retry_delay, retry_count, MAX_RETRY); ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", retry_delay, retry_count, MAX_RETRY);
@@ -134,7 +134,7 @@ void Application::CheckNewVersion() {
retry_count = 0; retry_count = 0;
retry_delay = 10; // 重置重试延迟时间 retry_delay = 10; // 重置重试延迟时间
if (ota_.HasNewVersion()) { if (ota.HasNewVersion()) {
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE); Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE);
vTaskDelay(pdMS_TO_TICKS(3000)); vTaskDelay(pdMS_TO_TICKS(3000));
@@ -142,7 +142,7 @@ void Application::CheckNewVersion() {
SetDeviceState(kDeviceStateUpgrading); SetDeviceState(kDeviceStateUpgrading);
display->SetIcon(FONT_AWESOME_DOWNLOAD); display->SetIcon(FONT_AWESOME_DOWNLOAD);
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota_.GetFirmwareVersion(); std::string message = std::string(Lang::Strings::NEW_VERSION) + ota.GetFirmwareVersion();
display->SetChatMessage("system", message.c_str()); display->SetChatMessage("system", message.c_str());
auto& board = Board::GetInstance(); auto& board = Board::GetInstance();
@@ -161,7 +161,7 @@ void Application::CheckNewVersion() {
background_task_ = nullptr; background_task_ = nullptr;
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
ota_.StartUpgrade([display](int progress, size_t speed) { ota.StartUpgrade([display](int progress, size_t speed) {
char buffer[64]; char buffer[64];
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024); snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
display->SetChatMessage("system", buffer); display->SetChatMessage("system", buffer);
@@ -176,8 +176,8 @@ void Application::CheckNewVersion() {
} }
// No new version, mark the current version as valid // No new version, mark the current version as valid
ota_.MarkCurrentVersionValid(); ota.MarkCurrentVersionValid();
if (!ota_.HasActivationCode() && !ota_.HasActivationChallenge()) { if (!ota.HasActivationCode() && !ota.HasActivationChallenge()) {
xEventGroupSetBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT); xEventGroupSetBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT);
// Exit the loop if done checking new version // Exit the loop if done checking new version
break; break;
@@ -185,14 +185,14 @@ void Application::CheckNewVersion() {
display->SetStatus(Lang::Strings::ACTIVATION); display->SetStatus(Lang::Strings::ACTIVATION);
// Activation code is shown to the user and waiting for the user to input // Activation code is shown to the user and waiting for the user to input
if (ota_.HasActivationCode()) { if (ota.HasActivationCode()) {
ShowActivationCode(); ShowActivationCode(ota.GetActivationCode(), ota.GetActivationMessage());
} }
// This will block the loop until the activation is done or timeout // This will block the loop until the activation is done or timeout
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
ESP_LOGI(TAG, "Activating... %d/%d", i + 1, 10); ESP_LOGI(TAG, "Activating... %d/%d", i + 1, 10);
esp_err_t err = ota_.Activate(); esp_err_t err = ota.Activate();
if (err == ESP_OK) { if (err == ESP_OK) {
xEventGroupSetBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT); xEventGroupSetBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT);
break; break;
@@ -208,10 +208,7 @@ void Application::CheckNewVersion() {
} }
} }
void Application::ShowActivationCode() { void Application::ShowActivationCode(const std::string& code, const std::string& message) {
auto& message = ota_.GetActivationMessage();
auto& code = ota_.GetActivationCode();
struct digit_sound { struct digit_sound {
char digit; char digit;
const std::string_view& sound; const std::string_view& sound;
@@ -454,7 +451,8 @@ void Application::Start() {
display->UpdateStatusBar(true); display->UpdateStatusBar(true);
// Check for new firmware version or get the MQTT broker address // Check for new firmware version or get the MQTT broker address
CheckNewVersion(); Ota ota;
CheckNewVersion(ota);
// Initialize the protocol // Initialize the protocol
display->SetStatus(Lang::Strings::LOADING_PROTOCOL); display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
@@ -464,9 +462,9 @@ void Application::Start() {
McpServer::GetInstance().AddCommonTools(); McpServer::GetInstance().AddCommonTools();
#endif #endif
if (ota_.HasMqttConfig()) { if (ota.HasMqttConfig()) {
protocol_ = std::make_unique<MqttProtocol>(); protocol_ = std::make_unique<MqttProtocol>();
} else if (ota_.HasWebsocketConfig()) { } else if (ota.HasWebsocketConfig()) {
protocol_ = std::make_unique<WebsocketProtocol>(); protocol_ = std::make_unique<WebsocketProtocol>();
} else { } else {
ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT"); ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT");
@@ -702,8 +700,9 @@ void Application::Start() {
xEventGroupWaitBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY); xEventGroupWaitBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);
SetDeviceState(kDeviceStateIdle); SetDeviceState(kDeviceStateIdle);
has_server_time_ = ota.HasServerTime();
if (protocol_started) { if (protocol_started) {
std::string message = std::string(Lang::Strings::VERSION) + ota_.GetCurrentVersion(); std::string message = std::string(Lang::Strings::VERSION) + ota.GetCurrentVersion();
display->ShowNotification(message.c_str()); display->ShowNotification(message.c_str());
display->SetChatMessage("system", ""); display->SetChatMessage("system", "");
// Play the success sound to indicate the device is ready // Play the success sound to indicate the device is ready
@@ -731,7 +730,7 @@ void Application::OnClockTimer() {
SystemInfo::PrintHeapStats(); SystemInfo::PrintHeapStats();
// If we have synchronized server time, set the status to clock "HH:MM" if the device is idle // If we have synchronized server time, set the status to clock "HH:MM" if the device is idle
if (ota_.HasServerTime()) { if (has_server_time_) {
if (device_state_ == kDeviceStateIdle) { if (device_state_ == kDeviceStateIdle) {
Schedule([this]() { Schedule([this]() {
// Set status to clock "HH:MM" // Set status to clock "HH:MM"

View File

@@ -90,7 +90,6 @@ private:
std::unique_ptr<WakeWord> wake_word_; std::unique_ptr<WakeWord> wake_word_;
std::unique_ptr<AudioProcessor> audio_processor_; std::unique_ptr<AudioProcessor> audio_processor_;
std::unique_ptr<AudioDebugger> audio_debugger_; std::unique_ptr<AudioDebugger> audio_debugger_;
Ota ota_;
std::mutex mutex_; std::mutex mutex_;
std::list<std::function<void()>> main_tasks_; std::list<std::function<void()>> main_tasks_;
std::unique_ptr<Protocol> protocol_; std::unique_ptr<Protocol> protocol_;
@@ -100,6 +99,7 @@ private:
ListeningMode listening_mode_ = kListeningModeAutoStop; ListeningMode listening_mode_ = kListeningModeAutoStop;
AecMode aec_mode_ = kAecOff; AecMode aec_mode_ = kAecOff;
bool has_server_time_ = false;
bool aborted_ = false; bool aborted_ = false;
bool voice_detected_ = false; bool voice_detected_ = false;
bool busy_decoding_audio_ = false; bool busy_decoding_audio_ = false;
@@ -132,8 +132,8 @@ private:
bool ReadAudio(std::vector<int16_t>& data, int sample_rate, int samples); bool ReadAudio(std::vector<int16_t>& data, int sample_rate, int samples);
void ResetDecoder(); void ResetDecoder();
void SetDecodeSampleRate(int sample_rate, int frame_duration); void SetDecodeSampleRate(int sample_rate, int frame_duration);
void CheckNewVersion(); void CheckNewVersion(Ota& ota);
void ShowActivationCode(); void ShowActivationCode(const std::string& code, const std::string& message);
void OnClockTimer(); void OnClockTimer();
void SetListeningMode(ListeningMode mode); void SetListeningMode(ListeningMode mode);
void AudioLoop(); void AudioLoop();

View File

@@ -212,24 +212,6 @@ std::string Esp32Camera::Explain(const std::string& question) {
auto http = Board::GetInstance().CreateHttp(); auto http = Board::GetInstance().CreateHttp();
// 构造multipart/form-data请求体 // 构造multipart/form-data请求体
std::string boundary = "----ESP32_CAMERA_BOUNDARY"; std::string boundary = "----ESP32_CAMERA_BOUNDARY";
// 构造question字段
std::string question_field;
question_field += "--" + boundary + "\r\n";
question_field += "Content-Disposition: form-data; name=\"question\"\r\n";
question_field += "\r\n";
question_field += question + "\r\n";
// 构造文件字段头部
std::string file_header;
file_header += "--" + boundary + "\r\n";
file_header += "Content-Disposition: form-data; name=\"file\"; filename=\"camera.jpg\"\r\n";
file_header += "Content-Type: image/jpeg\r\n";
file_header += "\r\n";
// 构造尾部
std::string multipart_footer;
multipart_footer += "\r\n--" + boundary + "--\r\n";
// 配置HTTP客户端使用分块传输编码 // 配置HTTP客户端使用分块传输编码
http->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str()); http->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
@@ -255,12 +237,25 @@ std::string Esp32Camera::Explain(const std::string& question) {
return "{\"success\": false, \"message\": \"Failed to connect to explain URL\"}"; return "{\"success\": false, \"message\": \"Failed to connect to explain URL\"}";
} }
// 第一块question字段 {
http->Write(question_field.c_str(), question_field.size()); // 第一块question字段
std::string question_field;
// 第二块:文件字段头部 question_field += "--" + boundary + "\r\n";
http->Write(file_header.c_str(), file_header.size()); question_field += "Content-Disposition: form-data; name=\"question\"\r\n";
question_field += "\r\n";
question_field += question + "\r\n";
http->Write(question_field.c_str(), question_field.size());
}
{
// 第二块:文件字段头部
std::string file_header;
file_header += "--" + boundary + "\r\n";
file_header += "Content-Disposition: form-data; name=\"file\"; filename=\"camera.jpg\"\r\n";
file_header += "Content-Type: image/jpeg\r\n";
file_header += "\r\n";
http->Write(file_header.c_str(), file_header.size());
}
// 第三块JPEG数据 // 第三块JPEG数据
size_t total_sent = 0; size_t total_sent = 0;
while (true) { while (true) {
@@ -281,9 +276,12 @@ std::string Esp32Camera::Explain(const std::string& question) {
// 清理队列 // 清理队列
vQueueDelete(jpeg_queue); vQueueDelete(jpeg_queue);
// 第四块multipart尾部 {
http->Write(multipart_footer.c_str(), multipart_footer.size()); // 第四块multipart尾部
std::string multipart_footer;
multipart_footer += "\r\n--" + boundary + "--\r\n";
http->Write(multipart_footer.c_str(), multipart_footer.size());
}
// 结束块 // 结束块
http->Write("", 0); http->Write("", 0);

View File

@@ -4,8 +4,7 @@
{ {
"name": "lichuang-dev", "name": "lichuang-dev",
"sdkconfig_append": [ "sdkconfig_append": [
"CONFIG_USE_DEVICE_AEC=y", "CONFIG_USE_DEVICE_AEC=y"
"CONFIG_SR_NSN_NSNET2=y"
] ]
} }
] ]

View File

@@ -7,8 +7,8 @@ CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_SPIRAM=y CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096 CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=512
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=49152 CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65536
CONFIG_SPIRAM_MEMTEST=n CONFIG_SPIRAM_MEMTEST=n
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y