Files
Bionic_sphere/Bionic_Core/OTAClass/OTAClass.cpp
T
Misaki 4cc761aab3 1. 完成了语音识别的C++业务层封装,测试通过
2. 试着测试了一下LVGL_GIF渲染+音乐播放+语音识别的组合简单优化后,
          发现lvgl渲染略显卡顿,语音识别有缓冲区空警告,不过无伤大雅,还需要进一步深度优化。
2025-09-16 01:29:17 +08:00

273 lines
9.2 KiB
C++

//
// Created by misaki on 2025/9/2.
//
#include "OTAClass.h"
#include "esp_log.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <memory>
#include <sstream>
#include <pthread.h>
#include <esp_pthread.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
using namespace std::chrono;
const auto sleep_time = seconds{
5
};
#include "ThreadManager.h"
#include "WifiConnectors.h"
#include <string>
#include "LVGLRender.h"
#include "SDFileManager.h"
#include "AudioOutput.h"
#include "CommClass.h"
// JSON数据回调函数
void onJsonData(cJSON* json) {
// 打印接收到的JSON数据
char* jsonStr = cJSON_Print(json);
ESP_LOGI("JSON_CALLBACK", "收到JSON数据: %s", jsonStr);
free(jsonStr);
// 解析消息类型并处理
cJSON* type = cJSON_GetObjectItem(json, "type");
if (type && cJSON_IsString(type)) {
if (strcmp(type->valuestring, "greeting") == 0) {
ESP_LOGI("JSON_CALLBACK", "收到服务器问候消息");
} else if (strcmp(type->valuestring, "heartbeat") == 0) {
ESP_LOGI("JSON_CALLBACK", "收到心跳响应");
} else if (strcmp(type->valuestring, "response") == 0) {
ESP_LOGI("JSON_CALLBACK", "收到服务器响应");
} else if (strcmp(type->valuestring, "echo") == 0) {
ESP_LOGI("JSON_CALLBACK", "收到回显消息");
} else if (strcmp(type->valuestring, "broadcast") == 0) {
ESP_LOGI("JSON_CALLBACK", "收到广播消息");
}
}
// 记得删除cJSON对象
cJSON_Delete(json);
}
// WebSocket事件回调函数
void onWebSocketEvent(WebSocketEvent event, const std::string& message) {
switch (event) {
case WebSocketEvent::CONNECTED:
ESP_LOGI("EVENT_CALLBACK", "WebSocket已连接: %s", message.c_str());
break;
case WebSocketEvent::DISCONNECTED:
ESP_LOGI("EVENT_CALLBACK", "WebSocket已断开: %s", message.c_str());
break;
case WebSocketEvent::DATA_RECEIVED:
ESP_LOGI("EVENT_CALLBACK", "收到原始数据: %s", message.c_str());
break;
case WebSocketEvent::ERROR:
ESP_LOGE("EVENT_CALLBACK", "WebSocket错误: %s", message.c_str());
break;
}
}
// 发送状态信息函数
void sendStatus() {
cJSON* status = cJSON_CreateObject();
cJSON_AddStringToObject(status, "type", "status");
cJSON* data = cJSON_CreateObject();
cJSON_AddNumberToObject(data, "free_heap", esp_get_free_heap_size());
cJSON_AddNumberToObject(data, "uptime", xTaskGetTickCount() * portTICK_PERIOD_MS / 1000);
cJSON_AddItemToObject(status, "data", data);
if (WebSocketManager::getInstance()->sendJson(status)) {
ESP_LOGI("SEND", "已发送状态信息");
} else {
ESP_LOGE("SEND", "发送状态信息失败");
}
}
// 发送问候消息函数
void sendGreeting() {
cJSON* greeting = cJSON_CreateObject();
cJSON_AddStringToObject(greeting, "type", "greeting");
cJSON_AddStringToObject(greeting, "message", "Hello from ESP32-S3");
cJSON_AddNumberToObject(greeting, "timestamp", xTaskGetTickCount() * portTICK_PERIOD_MS / 1000);
if (WebSocketManager::getInstance()->sendJson(greeting)) {
ESP_LOGI("SEND", "已发送问候消息");
} else {
ESP_LOGE("SEND", "发送问候消息失败");
}
}
void websocket_task() {
TickType_t lastStatusTime = 0;
TickType_t lastHeartbeatTime = 0;
TickType_t lastGreetingTime = 0;
while (true) {
TickType_t currentTime = xTaskGetTickCount();
// 检查连接状态
if (!WebSocketManager::getInstance()->isConnected()) {
ESP_LOGI("APP_TASK", "WebSocket未连接,尝试重新连接...");
// 确保WiFi已连接
if (!WifiConnectors::getInstance()->isWifiConnect()) {
ESP_LOGI("APP_TASK", "WiFi未连接,等待WiFi连接...");
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
if (WebSocketManager::getInstance()->connect()) {
ESP_LOGI("APP_TASK", "重新连接成功");
} else {
ESP_LOGI("APP_TASK", "重新连接失败");
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
// 每10秒发送状态信息
if (currentTime - lastStatusTime > (10000 / portTICK_PERIOD_MS)) {
sendStatus();
lastStatusTime = currentTime;
}
// 每60秒发送问候
if (currentTime - lastGreetingTime > (60000 / portTICK_PERIOD_MS)) {
sendGreeting();
lastGreetingTime = currentTime;
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
void OTAClass::Init() {
ESP_LOGI("OTA", "Init");
ESP_LOGI("OTAClass::Init", "当前固件版本 1.0.1");
// 列出当前目录内容
std::string listing = SDFileManager::getInstance()->lsCommand(".", false, true);
ESP_LOGI("SD", "%s", listing.c_str());
// 切换到music目录
SDFileManager::getInstance()->cdCommand("music");
std::string pwdPath = SDFileManager::getInstance()->pwdCommand();
ESP_LOGI("SD", "%s", pwdPath.c_str());
// 列出当前目录内容
listing = SDFileManager::getInstance()->lsCommand(".", false, true);
ESP_LOGI("SD", "%s", listing.c_str());
LVGLRender::getInstance()->RenderGif("sequence01m.gif");
// 设置音量
AudioOutput::getInstance()->setVolume(5);
// 同步播放
AudioOutput::getInstance()->playSync("/sdcard/music", "kokoronashi.mp3");
// // 配置Wifi连接线程参数
// ThreadConfig wifi_config;
// wifi_config.name = "WifiConnector"; // 线程名称
// wifi_config.core_id = 1; // 绑定到核心1(避免与主线程冲突)
// wifi_config.stack_size = 4096; // 设置稍大的栈空间(Wifi连接可能需要)
// wifi_config.priority = 6; // 设置较高优先级(确保连接及时)
// // 使用单例方式创建线程,调用connectWifi成员函数
// std::thread wifi_thread = ThreadManager::createSingletonThread<WifiConnectors>(
// wifi_config,
// &WifiConnectors::connectWifi,
// "Misaki-2.4G", // SSID
// "88888888", // 密码
// 5 // 最大重试次数
// );
// wifi_thread.detach();
WifiConnectors::getInstance()->connectWifi("Misaki-2.4G", "88888888", 5);
// 等待WiFi连接成功后再连接WebSocket
ESP_LOGI("APP_TASK", "等待WiFi连接...");
while (!WifiConnectors::getInstance()->isWifiConnect()) {
ESP_LOGI("APP_TASK", "WiFi未连接,等待中...");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
// 配置WebSocket
WebSocketConfig config;
config.uri = "ws://" + std::string("192.168.1.11") + ":" + std::to_string(8080) + "/ws";
config.auto_reconnect = true; // 自动重连
config.reconnect_interval = 5000; // 重连间隔(毫秒)
config.heartbeat_interval = 30000; // 心跳间隔(毫秒)
config.max_reconnect_attempts = 10; // 最大重连尝试次数
// TODO: 此处通信类存在线程重复创建bug,似乎是来自esp-idf的bug,待查证
// 初始化WebSocket管理器
// if (!WebSocketManager::getInstance()->initialize(config)) {
// ESP_LOGE("APP_TASK", "WebSocket管理器初始化失败");
// vTaskDelete(NULL);
// return;
// }
// 设置回调函数
// WebSocketManager::getInstance()->setJsonCallback(onJsonData);
// WebSocketManager::getInstance()->setEventCallback(onWebSocketEvent);
// 连接WebSocket服务器
// ESP_LOGI("APP_TASK", "正在连接WebSocket服务器: %s", config.uri.c_str());
// if (!WebSocketManager::getInstance()->connect()) {
// ESP_LOGE("APP_TASK", "WebSocket连接失败");
// }
// 创建WebSocket任务
// ThreadConfig websocket_config;
// websocket_config.core_id = 0;
// websocket_config.inherit_cfg = true;
// websocket_config.name = "websocket_task";
// websocket_config.priority = 5;
// websocket_config.stack_size = 4096;
// std::thread websocket_thread = ThreadManager::createThread(websocket_config, websocket_task);
// websocket_thread.detach();
// ThreadConfig ota_config;
// ota_config.name = "OTA";
// ota_config.stack_size = 4096;
// ota_config.priority = 6;
// ota_config.core_id = 0;
// std::thread ota_thread = ThreadManager::createMemberThread<OTAClass>(
// ota_config,
// this,
// &OTAClass::Update
// );
while (true) { // 主线程线程循环
ThreadManager::print_sys_memory(); // 打印系统内存使用情况
ThreadManager::stats_task(); // 打印任务统计信息
std::this_thread::sleep_for(sleep_time); // 休眠5秒
}
}
#include "ota_ws.h"
// 启动OTA更新线程,前提是已经连接WiFi
void OTAClass::Update() {
// 测试OTA服务器192.168.1.11
while (true) {
if (WifiConnectors::getInstance()->isWifiConnect()) { // 如果Wifi已连接
ota_ws_start("192.168.1.11", 8080);
// 启动完就退出,删除自身
break;
}else {
std::this_thread::sleep_for(sleep_time);
}
}
vTaskDelete(nullptr);
}