1. 完成了对音频播放类的完整C++封装,测试通过
2. 修复了LVGL渲染类当中的一些小bug 3. 增加了一些CPU资源占用的日志打印函数,运行在主线程当中 4. 完善了底层通信类的封装,基于websocket,尚未测试
This commit is contained in:
@@ -1,4 +1,386 @@
|
||||
//
|
||||
// Created by misaki on 2025/9/2.
|
||||
//
|
||||
#include "CommClass.h"
|
||||
#include "CommClass.h"
|
||||
#include <cstring> // 引入字符串处理库头文件
|
||||
#include <chrono> // 时间库头文件
|
||||
#include <memory>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_netif_types.h>
|
||||
|
||||
// 静态成员初始化
|
||||
WebSocketManager* WebSocketManager::instance = nullptr;
|
||||
std::mutex WebSocketManager::instance_mutex;
|
||||
|
||||
// 标签用于日志
|
||||
static const char* TAG = "WebSocketManager";
|
||||
|
||||
|
||||
// 构造函数
|
||||
WebSocketManager::WebSocketManager()
|
||||
: client(nullptr), threads_running(false),
|
||||
connected(false), connecting(false), reconnect_attempts(0),
|
||||
stats{0, 0, 0, 0},
|
||||
wifi(WifiConnectors::getInstance())
|
||||
|
||||
{
|
||||
|
||||
// 初始化统计信息
|
||||
stats = {0, 0, 0, 0};
|
||||
}
|
||||
|
||||
|
||||
// 析构函数
|
||||
WebSocketManager::~WebSocketManager() {
|
||||
disconnect();
|
||||
|
||||
// 停止线程
|
||||
threads_running = false;
|
||||
queue_cv.notify_all();
|
||||
|
||||
if (reconnect_thread.joinable()) {
|
||||
reconnect_thread.join();
|
||||
}
|
||||
|
||||
if (heartbeat_thread.joinable()) {
|
||||
heartbeat_thread.join();
|
||||
}
|
||||
|
||||
if (send_thread.joinable()) {
|
||||
send_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketManager* WebSocketManager::getInstance() {
|
||||
std::lock_guard<std::mutex> lock(instance_mutex);
|
||||
if (instance == nullptr) {
|
||||
instance = new WebSocketManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool WebSocketManager::initialize(const WebSocketConfig& config) {
|
||||
this->config = config;
|
||||
|
||||
// 注册WiFi事件处理
|
||||
esp_event_handler_instance_t instance;
|
||||
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||
&WebSocketManager::wifiEventHandler,
|
||||
this, &instance);
|
||||
|
||||
// 启动发送线程
|
||||
threads_running = true;
|
||||
|
||||
ThreadConfig thread_config;
|
||||
thread_config.name = "WS_Send";
|
||||
thread_config.stack_size = 4096;
|
||||
|
||||
send_thread = ThreadManager::createMemberThread(thread_config, this,
|
||||
&WebSocketManager::sendThread);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSocketManager::connect() {
|
||||
if (connecting || connected) {
|
||||
ESP_LOGI(TAG, "Already connected or connecting");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查WiFi连接
|
||||
if (!wifi->isWifiConnect()) {
|
||||
ESP_LOGE(TAG, "WiFi not connected, cannot establish WebSocket connection");
|
||||
if (event_callback) {
|
||||
event_callback(WebSocketEvent::ERROR, "WiFi not connected");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
connecting = true;
|
||||
stats.connection_attempts++;
|
||||
|
||||
// 创建WebSocket客户端
|
||||
if (!createWebSocketClient()) {
|
||||
connecting = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 启动WebSocket客户端
|
||||
esp_err_t err = esp_websocket_client_start(client);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start WebSocket client: %d", err);
|
||||
destroyWebSocketClient();
|
||||
connecting = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 启动重连和心跳线程
|
||||
ThreadConfig thread_config;
|
||||
thread_config.name = "WS_Reconnect";
|
||||
thread_config.stack_size = 3072;
|
||||
|
||||
reconnect_thread = ThreadManager::createMemberThread(thread_config, this,
|
||||
&WebSocketManager::reconnectThread);
|
||||
|
||||
thread_config.name = "WS_Heartbeat";
|
||||
heartbeat_thread = ThreadManager::createMemberThread(thread_config, this,
|
||||
&WebSocketManager::heartbeatThread);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketManager::disconnect() {
|
||||
if (client) {
|
||||
esp_websocket_client_stop(client);
|
||||
destroyWebSocketClient();
|
||||
}
|
||||
|
||||
connected = false;
|
||||
connecting = false;
|
||||
|
||||
// 通知事件回调
|
||||
if (event_callback) {
|
||||
event_callback(WebSocketEvent::DISCONNECTED, "Disconnected by user");
|
||||
}
|
||||
}
|
||||
|
||||
bool WebSocketManager::sendJson(cJSON* json) {
|
||||
if (!connected) { // 检查连接状态
|
||||
ESP_LOGE(TAG, "Not connected, cannot send data");
|
||||
cJSON_Delete(json);
|
||||
return false;
|
||||
}
|
||||
|
||||
char* json_str = cJSON_PrintUnformatted(json); // 将JSON对象转换为字符串
|
||||
cJSON_Delete(json); // 释放JSON对象
|
||||
|
||||
if (!json_str) { // 检查转换结果
|
||||
ESP_LOGE(TAG, "Failed to stringify JSON");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(queue_mutex); // 锁定队列
|
||||
send_queue.push(json_str); // 添加到队列
|
||||
free(json_str); // 释放内存
|
||||
|
||||
queue_cv.notify_one(); // 通知发送线程
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSocketManager::sendRaw(const std::string& data) {
|
||||
if (!connected) { // 检查连接状态
|
||||
ESP_LOGE(TAG, "Not connected, cannot send data");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(queue_mutex); // 锁定队列
|
||||
send_queue.push(data); // 添加到队列
|
||||
queue_cv.notify_one(); // 通知发送线程
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketManager::setJsonCallback(JsonDataCallback callback) {
|
||||
json_callback = callback;
|
||||
}
|
||||
|
||||
void WebSocketManager::setEventCallback(EventCallback callback) {
|
||||
event_callback = callback;
|
||||
}
|
||||
|
||||
bool WebSocketManager::isConnected() const {
|
||||
return connected;
|
||||
}
|
||||
|
||||
WebSocketConfig WebSocketManager::getConfig() const {
|
||||
return config;
|
||||
}
|
||||
|
||||
void WebSocketManager::updateConfig(const WebSocketConfig& config) {
|
||||
this->config = config;
|
||||
}
|
||||
|
||||
WebSocketManager::Stats WebSocketManager::getStats() const {
|
||||
return stats;
|
||||
}
|
||||
|
||||
void WebSocketManager::websocketEventHandler(void* handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void* event_data) {
|
||||
WebSocketManager* instance = static_cast<WebSocketManager*>(handler_args);
|
||||
esp_websocket_event_data_t* data = (esp_websocket_event_data_t*)event_data;
|
||||
|
||||
switch(event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
instance->connected = true;
|
||||
instance->connecting = false;
|
||||
instance->reconnect_attempts = 0;
|
||||
instance->stats.successful_connections++;
|
||||
|
||||
ESP_LOGI(TAG, "WebSocket connected");
|
||||
if (instance->event_callback) {
|
||||
instance->event_callback(WebSocketEvent::CONNECTED, "Connected successfully");
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
instance->connected = false;
|
||||
instance->connecting = false;
|
||||
|
||||
ESP_LOGI(TAG, "WebSocket disconnected");
|
||||
if (instance->event_callback) {
|
||||
instance->event_callback(WebSocketEvent::DISCONNECTED, "Disconnected");
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
if (data->data_len > 0) {
|
||||
instance->stats.messages_received++;
|
||||
instance->handleReceivedData((const char*)data->data_ptr, data->data_len);
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
instance->connected = false;
|
||||
instance->connecting = false;
|
||||
|
||||
ESP_LOGE(TAG, "WebSocket error");
|
||||
if (instance->event_callback) {
|
||||
instance->event_callback(WebSocketEvent::ERROR, "WebSocket error occurred");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketManager::handleReceivedData(const char* data, int len) {
|
||||
// 尝试解析JSON
|
||||
cJSON* json = cJSON_ParseWithLength(data, len);
|
||||
if (json) {
|
||||
// 成功解析为JSON
|
||||
if (json_callback) {
|
||||
json_callback(json);
|
||||
} else {
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
} else {
|
||||
// 不是JSON格式,作为原始数据处理
|
||||
std::string message(data, len);
|
||||
if (event_callback) {
|
||||
event_callback(WebSocketEvent::DATA_RECEIVED, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketManager::reconnectThread() {
|
||||
while (threads_running) {
|
||||
if (!connected && config.auto_reconnect &&
|
||||
(config.max_reconnect_attempts == 0 ||
|
||||
reconnect_attempts < config.max_reconnect_attempts)) {
|
||||
|
||||
// 检查WiFi连接
|
||||
if (!wifi->isWifiConnect()) {
|
||||
ESP_LOGI(TAG, "WiFi not connected, waiting before WebSocket reconnect");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(config.reconnect_interval));
|
||||
continue;
|
||||
}
|
||||
|
||||
reconnect_attempts++;
|
||||
ESP_LOGI(TAG, "Attempting to reconnect (%ld/%d)",
|
||||
reconnect_attempts, config.max_reconnect_attempts);
|
||||
|
||||
if (connect()) {
|
||||
ESP_LOGI(TAG, "Reconnection attempt initiated");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Reconnection attempt failed");
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(config.reconnect_interval));
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketManager::heartbeatThread() {
|
||||
while (threads_running) {
|
||||
if (connected && config.heartbeat_interval > 0) {
|
||||
// 发送心跳消息
|
||||
cJSON* heartbeat = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(heartbeat, "type", "heartbeat");
|
||||
cJSON_AddNumberToObject(heartbeat, "timestamp", esp_log_timestamp());
|
||||
|
||||
sendJson(heartbeat);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(config.heartbeat_interval));
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketManager::sendThread() {
|
||||
while (threads_running) {
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
queue_cv.wait(lock, [this]() {
|
||||
return !send_queue.empty() || !threads_running;
|
||||
});
|
||||
|
||||
if (!threads_running) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!send_queue.empty() && connected) {
|
||||
std::string data = std::move(send_queue.front());
|
||||
send_queue.pop();
|
||||
lock.unlock();
|
||||
|
||||
// 发送数据
|
||||
int sent = esp_websocket_client_send_text(client, data.c_str(), static_cast<int>(data.length()), portMAX_DELAY);
|
||||
if (sent >= 0) {
|
||||
stats.messages_sent++;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to send data");
|
||||
// 将数据重新放回队列
|
||||
lock.lock();
|
||||
send_queue.push(std::move(data));
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WebSocketManager::createWebSocketClient() {
|
||||
esp_websocket_client_config_t ws_config = {};
|
||||
ws_config.uri = config.uri.c_str();
|
||||
ws_config.user_context = this;
|
||||
|
||||
client = esp_websocket_client_init(&ws_config);
|
||||
if (!client) {
|
||||
ESP_LOGE(TAG, "Failed to initialize WebSocket client");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 注册事件处理
|
||||
esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY,
|
||||
&WebSocketManager::websocketEventHandler, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketManager::destroyWebSocketClient() {
|
||||
if (client) {
|
||||
esp_websocket_client_stop(client);
|
||||
esp_websocket_client_destroy(client);
|
||||
client = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketManager::wifiEventHandler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data) {
|
||||
WebSocketManager* instance = static_cast<WebSocketManager*>(arg);
|
||||
|
||||
if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
// WiFi已连接,尝试重新连接WebSocket
|
||||
if (instance->config.auto_reconnect && !instance->connected) {
|
||||
ESP_LOGI(TAG, "WiFi connected, attempting to reconnect WebSocket");
|
||||
instance->connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,197 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <condition_variable>
|
||||
#include "esp_websocket_client.h"
|
||||
#include "cJSON.h"
|
||||
#include "ThreadManager.h"
|
||||
#include "WifiConnectors.h"
|
||||
|
||||
// WebSocket事件类型
|
||||
enum class WebSocketEvent {
|
||||
CONNECTED,
|
||||
DISCONNECTED,
|
||||
DATA_RECEIVED,
|
||||
ERROR
|
||||
};
|
||||
|
||||
// WebSocket配置
|
||||
struct WebSocketConfig {
|
||||
std::string uri; // WebSocket服务器URI
|
||||
int reconnect_interval = 5000; // 重连间隔(ms)
|
||||
int heartbeat_interval = 30000; // 心跳间隔(ms)
|
||||
int max_reconnect_attempts = 10; // 最大重连次数
|
||||
bool auto_reconnect = true; // 是否自动重连
|
||||
};
|
||||
|
||||
// JSON数据回调
|
||||
using JsonDataCallback = std::function<void(cJSON* json)>;
|
||||
// 事件回调
|
||||
using EventCallback = std::function<void(WebSocketEvent event, const std::string& message)>;
|
||||
|
||||
/* 回调函数示例:
|
||||
// JSON数据回调示例
|
||||
void onJsonData(cJSON* json) {
|
||||
// 处理接收到的JSON数据
|
||||
cJSON* type = cJSON_GetObjectItem(json, "type");
|
||||
if (type && cJSON_IsString(type)) {
|
||||
ESP_LOGI("App", "Received message type: %s", type->valuestring);
|
||||
|
||||
if (strcmp(type->valuestring, "sensor_data") == 0) {
|
||||
cJSON* value = cJSON_GetObjectItem(json, "value");
|
||||
if (value && cJSON_IsNumber(value)) {
|
||||
ESP_LOGI("App", "Sensor value: %.2f", value->valuedouble);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
// 事件回调示例
|
||||
void onWebSocketEvent(WebSocketEvent event, const std::string& message) {
|
||||
switch (event) {
|
||||
case WebSocketEvent::CONNECTED:
|
||||
ESP_LOGI("App", "WebSocket connected: %s", message.c_str());
|
||||
break;
|
||||
case WebSocketEvent::DISCONNECTED:
|
||||
ESP_LOGI("App", "WebSocket disconnected: %s", message.c_str());
|
||||
break;
|
||||
case WebSocketEvent::DATA_RECEIVED:
|
||||
ESP_LOGI("App", "Received raw data: %s", message.c_str());
|
||||
break;
|
||||
case WebSocketEvent::ERROR:
|
||||
ESP_LOGE("App", "WebSocket error: %s", message.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
class WebSocketManager {
|
||||
public:
|
||||
// 获取单例实例
|
||||
static WebSocketManager* getInstance();
|
||||
|
||||
// 删除拷贝构造函数和赋值运算符
|
||||
WebSocketManager(const WebSocketManager&) = delete;
|
||||
WebSocketManager& operator=(const WebSocketManager&) = delete;
|
||||
|
||||
// 初始化WebSocket管理器
|
||||
bool initialize(const WebSocketConfig& config);
|
||||
|
||||
// 连接到WebSocket服务器
|
||||
bool connect();
|
||||
|
||||
// 断开连接
|
||||
void disconnect();
|
||||
|
||||
// 发送JSON数据
|
||||
bool sendJson(cJSON* json);
|
||||
|
||||
// 发送原始字符串数据
|
||||
bool sendRaw(const std::string& data);
|
||||
|
||||
// 设置JSON数据回调
|
||||
void setJsonCallback(JsonDataCallback callback);
|
||||
|
||||
// 设置事件回调
|
||||
void setEventCallback(EventCallback callback);
|
||||
|
||||
// 获取连接状态
|
||||
bool isConnected() const;
|
||||
|
||||
// 获取配置信息
|
||||
WebSocketConfig getConfig() const;
|
||||
|
||||
// 更新配置
|
||||
void updateConfig(const WebSocketConfig& config);
|
||||
|
||||
// 获取统计信息
|
||||
struct Stats {
|
||||
uint32_t messages_sent; /// 发送消息数
|
||||
uint32_t messages_received; /// 接收到的消息数
|
||||
uint32_t connection_attempts; /// 连接尝试次数
|
||||
uint32_t successful_connections; /// 成功连接次数
|
||||
};
|
||||
Stats getStats() const;
|
||||
|
||||
private:
|
||||
WebSocketManager(); // 私有构造函数
|
||||
~WebSocketManager(); // 私有析构函数
|
||||
|
||||
/**
|
||||
* WebSocket事件处理函数
|
||||
* @param handler_args 处理参数
|
||||
* @param base 事件基础
|
||||
* @param event_id 事件ID
|
||||
* @param event_data 事件数据
|
||||
*/
|
||||
static void websocketEventHandler(void* handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void* event_data);
|
||||
|
||||
/**
|
||||
* 处理接收到的数据
|
||||
* @param data 数据
|
||||
* @param len 数据长度
|
||||
*/
|
||||
void handleReceivedData(const char* data, int len);
|
||||
|
||||
// 重连线程函数
|
||||
void reconnectThread();
|
||||
|
||||
// 心跳线程函数
|
||||
void heartbeatThread();
|
||||
|
||||
// 发送线程函数
|
||||
void sendThread();
|
||||
|
||||
// 创建WebSocket客户端
|
||||
bool createWebSocketClient();
|
||||
|
||||
// 销毁WebSocket客户端
|
||||
void destroyWebSocketClient();
|
||||
|
||||
// 处理WiFi事件
|
||||
static void wifiEventHandler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data);
|
||||
|
||||
private:
|
||||
static WebSocketManager* instance;
|
||||
static std::mutex instance_mutex;
|
||||
|
||||
esp_websocket_client_handle_t client;
|
||||
WebSocketConfig config;
|
||||
|
||||
// 线程相关
|
||||
std::thread reconnect_thread; /// 重连线程
|
||||
std::thread heartbeat_thread; /// 心跳线程
|
||||
std::thread send_thread; /// 发送线程
|
||||
bool threads_running; /// 线程运行标志
|
||||
|
||||
// 回调函数
|
||||
JsonDataCallback json_callback; /// JSON数据回调
|
||||
EventCallback event_callback; /// 事件回调
|
||||
|
||||
// 状态变量
|
||||
bool connected;
|
||||
bool connecting;
|
||||
uint32_t reconnect_attempts;
|
||||
|
||||
// 统计信息
|
||||
Stats stats;
|
||||
|
||||
// 发送队列
|
||||
std::queue<std::string> send_queue;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable queue_cv;
|
||||
|
||||
// WiFi实例
|
||||
WifiConnectors* wifi;
|
||||
};
|
||||
Reference in New Issue
Block a user