9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
3052 lines
109 KiB
C
3052 lines
109 KiB
C
/**
|
||
******************************************************************************
|
||
* @file tcp_protocol.c
|
||
* @brief TCP通信协议解析实现
|
||
******************************************************************************
|
||
*/
|
||
|
||
#include "tcp_protocol.h"
|
||
#include "tcp_server.h"
|
||
#include "cJSON.h"
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include "publicdata/publicdata.h"
|
||
#include "publicdata/type.h"
|
||
#include "fault_cheak/fault_interface.h"
|
||
|
||
#if BLE_DEBUG_EN
|
||
#include "debug_link.h"
|
||
#endif
|
||
|
||
#if TCP_DEBUG_EN
|
||
|
||
#include "system_data.h"
|
||
#include "debug_files.h"
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
|
||
/* 兼容历史代码中涉及的数据结构声明(当前实际读取逻辑已迁移到 system_data.c) */
|
||
#include "flash_file_mgr/fault_flash_impl.h"
|
||
#include "flash_file_mgr/meter_calculate_flash_impl.h"
|
||
#include "app_fatfs/fatfs_card.h"
|
||
|
||
/* 内部函数声明 */
|
||
static void tcp_fill_default_timestamp(char *buffer, uint32_t size);
|
||
int tcp_process_file_operation(const tcp_file_operation_data_t *fileOperation);
|
||
/* GetCurrentTime函数声明(在项目中已定义) */
|
||
extern void GetCurrentTime(Comm_Time *time);
|
||
/* v_rtc_set_time函数声明(在BSP/app_rtc/app_rtc.c中定义) */
|
||
extern void v_rtc_set_time(Comm_Time *time);
|
||
|
||
/**
|
||
* @brief 生成当前时间戳字符串
|
||
* @param buffer 缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_generate_timestamp(char *buffer, uint32_t size)
|
||
{
|
||
Comm_Time curTime;
|
||
|
||
if (buffer == NULL || size < 24) {
|
||
return -1;
|
||
}
|
||
|
||
/* 获取当前系统时间 */
|
||
GetCurrentTime(&curTime);
|
||
|
||
/* 格式化为字符串:YYYY-MM-DD HH:MM:SS.000 */
|
||
snprintf(buffer, size, "%04d-%02d-%02d %02d:%02d:%02d.000",
|
||
curTime.iYear, curTime.ucMonth, curTime.ucDay,
|
||
curTime.ucHour, curTime.ucMin, curTime.ucSec);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 填充默认时间戳(用于测试)
|
||
*/
|
||
static void tcp_fill_default_timestamp(char *buffer, uint32_t size)
|
||
{
|
||
/* 保留此函数作为备用,但主函数已使用真实时间 */
|
||
Comm_Time curTime;
|
||
GetCurrentTime(&curTime);
|
||
|
||
snprintf(buffer, size, "%04d-%02d-%02d %02d:%02d:%02d.000",
|
||
curTime.iYear, curTime.ucMonth, curTime.ucDay,
|
||
curTime.ucHour, curTime.ucMin, curTime.ucSec);
|
||
}
|
||
|
||
/**
|
||
* @brief 生成心跳消息JSON
|
||
* @param sequence 序列号
|
||
* @param source 来源字符串
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_heartbeat_json(uint32_t sequence, const char *source, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_HEARTBEAT);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddNumberToObject(data, "sequence", sequence);
|
||
cJSON_AddStringToObject(data, "source", source);
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成系统信息消息JSON
|
||
* @param systemInfo 系统信息结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_system_info_json(const tcp_system_info_data_t *systemInfo, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || systemInfo == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_SYSTEM_INFO);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "systemModel", systemInfo->systemModel);
|
||
cJSON_AddNumberToObject(data, "gunCount", systemInfo->gunCount);
|
||
cJSON_AddNumberToObject(data, "devicePower", systemInfo->devicePower);
|
||
cJSON_AddNumberToObject(data, "networkStatus", systemInfo->networkStatus);
|
||
cJSON_AddNumberToObject(data, "faultCount", systemInfo->faultCount);
|
||
cJSON_AddStringToObject(data, "version", systemInfo->version);
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成充电枪数据消息JSON
|
||
* @param gunData 充电枪数据结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_gun_data_json(const tcp_gun_data_t *gunData, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || gunData == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_GUN_INFO);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddNumberToObject(data, "gunNumber", gunData->gunNumber);
|
||
cJSON_AddNumberToObject(data, "chargingStatus", gunData->chargingStatus);
|
||
cJSON_AddNumberToObject(data, "gunConnectionStatus", gunData->gunConnectionStatus);
|
||
cJSON_AddNumberToObject(data, "chargingTime", gunData->charge_time);
|
||
cJSON_AddNumberToObject(data, "demandVoltage", gunData->demandVoltage);
|
||
cJSON_AddNumberToObject(data, "demandCurrent", gunData->demandCurrent);
|
||
cJSON_AddNumberToObject(data, "actualVoltage", gunData->actualVoltage);
|
||
cJSON_AddNumberToObject(data, "actualCurrent", gunData->actualCurrent);
|
||
cJSON_AddNumberToObject(data, "energy", gunData->energy);
|
||
cJSON_AddNumberToObject(data, "cost", gunData->cost);
|
||
cJSON_AddNumberToObject(data, "batterySOC", gunData->batterySOC);
|
||
cJSON_AddStringToObject(data, "userId", gunData->userId);
|
||
cJSON_AddStringToObject(data, "orderNumber", gunData->orderNumber);
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 解析接收到的JSON消息
|
||
* @param json JSON字符串
|
||
* @param message 输出消息结构体
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_parse_json_message(const char *json, tcp_message_t *message)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *item = NULL;
|
||
cJSON *data = NULL;
|
||
|
||
if (json == NULL || message == NULL) {
|
||
TCP_PRINT("tcp_parse_json_message: NULL parameters\r\n");
|
||
return -1;
|
||
}
|
||
|
||
|
||
/* 解析JSON */
|
||
root = cJSON_Parse(json);
|
||
if (root == NULL) {
|
||
TCP_PRINT("tcp_parse_json_message: cJSON_Parse failed\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 清空消息结构体 */
|
||
memset(message, 0, sizeof(tcp_message_t));
|
||
|
||
/* 解析version */
|
||
item = cJSON_GetObjectItem(root, "version");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->version, item->valuestring, sizeof(message->version) - 1);
|
||
}
|
||
|
||
/* 解析timestamp */
|
||
item = cJSON_GetObjectItem(root, "timestamp");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->timestamp, item->valuestring, sizeof(message->timestamp) - 1);
|
||
}
|
||
|
||
/* 解析command */
|
||
item = cJSON_GetObjectItem(root, "command");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->command, item->valuestring, sizeof(message->command) - 1);
|
||
} else {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 解析data */
|
||
data = cJSON_GetObjectItem(root, "data");
|
||
if (data == NULL || !cJSON_IsObject(data)) {
|
||
TCP_PRINT("tcp_parse_json_message: missing or invalid data object\r\n");
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
|
||
/* 根据command类型解析data */
|
||
if (strcmp(message->command, CMD_HEARTBEAT) == 0) {
|
||
/* 解析心跳数据 */
|
||
item = cJSON_GetObjectItem(data, "sequence");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.heartbeat.sequence = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "source");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.heartbeat.source, item->valuestring,
|
||
sizeof(message->data.heartbeat.source) - 1);
|
||
}
|
||
} else if (strcmp(message->command, CMD_CHARGE_CONTROL) == 0) {
|
||
/* 解析充电启停控制数据 */
|
||
item = cJSON_GetObjectItem(data, "gunNumber");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.chargeControl.gunNumber = (uint8_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "action");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.chargeControl.action = (uint8_t)item->valueint;
|
||
}
|
||
} else if (strcmp(message->command, CMD_PARAM_QUERY) == 0) {
|
||
/* 解析参数查询数据 */
|
||
item = cJSON_GetObjectItem(data, "type");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.paramQuery.type, item->valuestring,
|
||
sizeof(message->data.paramQuery.type) - 1);
|
||
} else {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
} else if (strcmp(message->command, CMD_PARAM_MODIFY) == 0) {
|
||
/* 解析参数修改数据 */
|
||
item = cJSON_GetObjectItem(data, "type");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.paramModify.type, item->valuestring,
|
||
sizeof(message->data.paramModify.type) - 1);
|
||
} else {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 解析参数数组 */
|
||
cJSON *params_array = cJSON_GetObjectItem(data, "params");
|
||
if (params_array != NULL && cJSON_IsArray(params_array)) {
|
||
int array_size = cJSON_GetArraySize(params_array);
|
||
if (array_size > 0) {
|
||
/* 分配内存存储参数 */
|
||
message->data.paramModify.count = array_size;
|
||
message->data.paramModify.params = (tcp_param_item_t *)pvPortMalloc(
|
||
array_size * sizeof(tcp_param_item_t));
|
||
if (message->data.paramModify.params == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 清空参数数组 */
|
||
memset(message->data.paramModify.params, 0, array_size * sizeof(tcp_param_item_t));
|
||
|
||
/* 解析每个参数项 */
|
||
for (int i = 0; i < array_size; i++) {
|
||
cJSON *param_item = cJSON_GetArrayItem(params_array, i);
|
||
if (param_item != NULL && cJSON_IsObject(param_item)) {
|
||
/* 解析参数名称 */
|
||
cJSON *name_item = cJSON_GetObjectItem(param_item, "name");
|
||
if (name_item != NULL && cJSON_IsString(name_item)) {
|
||
strncpy(message->data.paramModify.params[i].name, name_item->valuestring,
|
||
sizeof(message->data.paramModify.params[i].name) - 1);
|
||
}
|
||
|
||
/* 解析参数值 */
|
||
cJSON *value_item = cJSON_GetObjectItem(param_item, "value");
|
||
if (value_item != NULL && cJSON_IsString(value_item)) {
|
||
strncpy(message->data.paramModify.params[i].value, value_item->valuestring,
|
||
sizeof(message->data.paramModify.params[i].value) - 1);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
message->data.paramModify.count = 0;
|
||
message->data.paramModify.params = NULL;
|
||
}
|
||
} else {
|
||
message->data.paramModify.count = 0;
|
||
message->data.paramModify.params = NULL;
|
||
}
|
||
} else if (strcmp(message->command, CMD_FIRMWARE_UPGRADE) == 0) {
|
||
/* 解析固件升级数据 */
|
||
item = cJSON_GetObjectItem(data, "subCommand");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.firmwareUpgrade.subCommand, item->valuestring,
|
||
sizeof(message->data.firmwareUpgrade.subCommand) - 1);
|
||
} else {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 根据子命令解析不同的字段 */
|
||
if (strcmp(message->data.firmwareUpgrade.subCommand, FIRMWARE_SUBCMD_START) == 0) {
|
||
/* 解析Start子命令 */
|
||
item = cJSON_GetObjectItem(data, "fileSize");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.start.fileSize = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "totalPackets");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.start.totalPackets = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "packetSize");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.start.packetSize = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "firmwareVersion");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.firmwareUpgrade.u.start.firmwareVersion, item->valuestring,
|
||
sizeof(message->data.firmwareUpgrade.u.start.firmwareVersion) - 1);
|
||
}
|
||
} else if (strcmp(message->data.firmwareUpgrade.subCommand, FIRMWARE_SUBCMD_DATA) == 0) {
|
||
/* 解析Data子命令 */
|
||
item = cJSON_GetObjectItem(data, "packetIndex");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.data.packetIndex = (uint32_t)item->valueint;
|
||
} else {
|
||
/* 如果packetIndex字段不存在或不是数字,使用默认值0 */
|
||
message->data.firmwareUpgrade.u.data.packetIndex = 0;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "totalPackets");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.data.totalPackets = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "data");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
/* 动态分配内存存储数据 */
|
||
const char *data_str = item->valuestring;
|
||
size_t data_len = strlen(data_str);
|
||
message->data.firmwareUpgrade.u.data.data = (char *)pvPortMalloc(data_len + 1);
|
||
if (message->data.firmwareUpgrade.u.data.data != NULL) {
|
||
strncpy(message->data.firmwareUpgrade.u.data.data, data_str, data_len);
|
||
message->data.firmwareUpgrade.u.data.data[data_len] = '\0';
|
||
message->data.firmwareUpgrade.u.data.data_len = data_len;
|
||
} else {
|
||
TCP_PRINT("Failed to allocate memory for firmware data\r\n");
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
} else {
|
||
message->data.firmwareUpgrade.u.data.data = NULL;
|
||
message->data.firmwareUpgrade.u.data.data_len = 0;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "crc");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.data.crc = (uint32_t)item->valueint;
|
||
}
|
||
} else if (strcmp(message->data.firmwareUpgrade.subCommand, FIRMWARE_SUBCMD_END) == 0) {
|
||
/* 解析End子命令 */
|
||
item = cJSON_GetObjectItem(data, "status");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.end.status = (uint8_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "errorMessage");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.firmwareUpgrade.u.end.errorMessage, item->valuestring,
|
||
sizeof(message->data.firmwareUpgrade.u.end.errorMessage) - 1);
|
||
}
|
||
} else if (strcmp(message->data.firmwareUpgrade.subCommand, FIRMWARE_SUBCMD_RESPONSE) == 0) {
|
||
/* 解析Response子命令 */
|
||
item = cJSON_GetObjectItem(data, "response");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.response.response = (uint8_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "packetIndex");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.firmwareUpgrade.u.response.packetIndex = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "message");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.firmwareUpgrade.u.response.message, item->valuestring,
|
||
sizeof(message->data.firmwareUpgrade.u.response.message) - 1);
|
||
}
|
||
} else {
|
||
/* 未知子命令 */
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
} else if (strcmp(message->command, CMD_FILE_OPERATIONS) == 0) {
|
||
/* 解析文件操作数据 */
|
||
item = cJSON_GetObjectItem(data, "subCommand");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.fileOperation.subCommand, item->valuestring,
|
||
sizeof(message->data.fileOperation.subCommand) - 1);
|
||
} else {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 根据子命令解析不同的字段 */
|
||
if (strcmp(message->data.fileOperation.subCommand, FILE_OP_SUBCMD_QUERY) == 0) {
|
||
/* 解析查询子命令 - 支持两种格式:
|
||
1. 直接格式:data中包含path字段
|
||
2. 嵌套格式:data中包含request对象,request对象中包含path和recursive字段
|
||
*/
|
||
cJSON *request_obj = cJSON_GetObjectItem(data, "request");
|
||
if (request_obj != NULL && cJSON_IsObject(request_obj)) {
|
||
/* 嵌套格式:从request对象中获取path */
|
||
item = cJSON_GetObjectItem(request_obj, "path");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.fileOperation.request.query.path, item->valuestring,
|
||
sizeof(message->data.fileOperation.request.query.path) - 1);
|
||
}
|
||
/* 解析recursive字段(可选) */
|
||
item = cJSON_GetObjectItem(request_obj, "recursive");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.fileOperation.request.query.recursive = (uint8_t)item->valueint;
|
||
}
|
||
} else {
|
||
/* 直接格式:从data对象中直接获取path */
|
||
item = cJSON_GetObjectItem(data, "path");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.fileOperation.request.query.path, item->valuestring,
|
||
sizeof(message->data.fileOperation.request.query.path) - 1);
|
||
}
|
||
}
|
||
} else if (strcmp(message->data.fileOperation.subCommand, FILE_OP_SUBCMD_DELETE) == 0) {
|
||
/* 解析删除子命令 - 支持两种格式:
|
||
1. 直接格式:data中包含path字段(完整路径)
|
||
2. 新格式:data中包含fileName和path字段,需要组合成完整路径
|
||
*/
|
||
cJSON *fileName_item = cJSON_GetObjectItem(data, "fileName");
|
||
cJSON *path_item = cJSON_GetObjectItem(data, "path");
|
||
|
||
if (fileName_item != NULL && cJSON_IsString(fileName_item) &&
|
||
path_item != NULL && cJSON_IsString(path_item)) {
|
||
/* 新格式:组合路径和文件名 */
|
||
char full_path[256];
|
||
const char *path_str = path_item->valuestring;
|
||
const char *file_name = fileName_item->valuestring;
|
||
|
||
/* 构建完整路径:path + "/" + fileName */
|
||
if (path_str[0] == '\0') {
|
||
/* 如果路径为空,直接使用文件名 */
|
||
snprintf(full_path, sizeof(full_path), "/%s", file_name);
|
||
} else if (path_str[strlen(path_str) - 1] == '/') {
|
||
/* 如果路径以斜杠结尾,直接拼接 */
|
||
snprintf(full_path, sizeof(full_path), "%s%s", path_str, file_name);
|
||
} else {
|
||
/* 否则添加斜杠分隔符 */
|
||
snprintf(full_path, sizeof(full_path), "%s/%s", path_str, file_name);
|
||
}
|
||
|
||
strncpy(message->data.fileOperation.request.delete.path, full_path,
|
||
sizeof(message->data.fileOperation.request.delete.path) - 1);
|
||
message->data.fileOperation.request.delete.path[sizeof(message->data.fileOperation.request.delete.path) - 1] = '\0';
|
||
|
||
TCP_PRINT("Delete request with fileName and path: path=%s, fileName=%s, fullPath=%s\r\n",
|
||
path_str, file_name, message->data.fileOperation.request.delete.path);
|
||
} else if (path_item != NULL && cJSON_IsString(path_item)) {
|
||
/* 直接格式:使用完整的path字段 */
|
||
strncpy(message->data.fileOperation.request.delete.path, path_item->valuestring,
|
||
sizeof(message->data.fileOperation.request.delete.path) - 1);
|
||
message->data.fileOperation.request.delete.path[sizeof(message->data.fileOperation.request.delete.path) - 1] = '\0';
|
||
|
||
TCP_PRINT("Delete request with full path: %s\r\n", message->data.fileOperation.request.delete.path);
|
||
} else {
|
||
/* 两种格式都不满足,返回错误 */
|
||
TCP_PRINT("Delete request missing required fields (need either path or both fileName and path)\r\n");
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 解析force字段(可选) */
|
||
item = cJSON_GetObjectItem(data, "force");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.fileOperation.request.delete.force = (uint8_t)item->valueint;
|
||
} else {
|
||
message->data.fileOperation.request.delete.force = 0; /* 默认不强制删除 */
|
||
}
|
||
} else if (strcmp(message->data.fileOperation.subCommand, FILE_OP_SUBCMD_DOWNLOAD) == 0) {
|
||
/* 解析下载子命令 - 支持两种格式:
|
||
1. 直接格式:data中包含path字段(完整路径)
|
||
2. 新格式:data中包含fileName和path字段,需要组合成完整路径
|
||
*/
|
||
cJSON *fileName_item = cJSON_GetObjectItem(data, "fileName");
|
||
cJSON *path_item = cJSON_GetObjectItem(data, "path");
|
||
|
||
if (fileName_item != NULL && cJSON_IsString(fileName_item) &&
|
||
path_item != NULL && cJSON_IsString(path_item)) {
|
||
/* 新格式:组合路径和文件名 */
|
||
char full_path[64];
|
||
const char *path_str = path_item->valuestring;
|
||
const char *file_name = fileName_item->valuestring;
|
||
|
||
/* 构建完整路径:path + "/" + fileName */
|
||
if (path_str[0] == '\0') {
|
||
/* 如果路径为空,直接使用文件名 */
|
||
snprintf(full_path, sizeof(full_path), "/%s", file_name);
|
||
} else if (path_str[strlen(path_str) - 1] == '/') {
|
||
/* 如果路径以斜杠结尾,直接拼接 */
|
||
snprintf(full_path, sizeof(full_path), "%s%s", path_str, file_name);
|
||
} else {
|
||
/* 否则添加斜杠分隔符 */
|
||
snprintf(full_path, sizeof(full_path), "%s/%s", path_str, file_name);
|
||
}
|
||
|
||
strncpy(message->data.fileOperation.request.download.path, full_path,
|
||
sizeof(message->data.fileOperation.request.download.path) - 1);
|
||
message->data.fileOperation.request.download.path[sizeof(message->data.fileOperation.request.download.path) - 1] = '\0';
|
||
|
||
TCP_PRINT("Download request with fileName and path: path=%s, fileName=%s, fullPath=%s\r\n",
|
||
path_str, file_name, message->data.fileOperation.request.download.path);
|
||
} else if (path_item != NULL && cJSON_IsString(path_item)) {
|
||
/* 直接格式:使用完整的path字段 */
|
||
strncpy(message->data.fileOperation.request.download.path, path_item->valuestring,
|
||
sizeof(message->data.fileOperation.request.download.path) - 1);
|
||
message->data.fileOperation.request.download.path[sizeof(message->data.fileOperation.request.download.path) - 1] = '\0';
|
||
|
||
TCP_PRINT("Download request with full path: %s\r\n", message->data.fileOperation.request.download.path);
|
||
} else {
|
||
/* 两种格式都不满足,返回错误 */
|
||
TCP_PRINT("Download request missing required fields (need either path or both fileName and path)\r\n");
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "offset");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.fileOperation.request.download.offset = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "chunkSize");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.fileOperation.request.download.chunk_size = (uint32_t)item->valueint;
|
||
}
|
||
} else if (strcmp(message->data.fileOperation.subCommand, FILE_OP_SUBCMD_UPLOAD) == 0) {
|
||
/* 解析上传子命令 */
|
||
item = cJSON_GetObjectItem(data, "path");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.fileOperation.request.upload.path, item->valuestring,
|
||
sizeof(message->data.fileOperation.request.upload.path) - 1);
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "data");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
/* 注意:data字段是uint8_t*,但我们需要将其作为char*处理 */
|
||
strncpy((char *)message->data.fileOperation.request.upload.data, item->valuestring,
|
||
sizeof(message->data.fileOperation.request.upload.data) - 1);
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "offset");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.fileOperation.request.upload.offset = (uint32_t)item->valueint;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "fileSize");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.fileOperation.request.upload.file_size = (uint32_t)item->valueint;
|
||
}
|
||
} else {
|
||
/* 未知子命令 */
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
} else if (strcmp(message->command, CMD_HISTORY_OPERATIONS) == 0) {
|
||
/* 解析历史记录查询/清除请求 */
|
||
item = cJSON_GetObjectItem(data, "subCommand");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.historyOperations.subCommand, item->valuestring,
|
||
sizeof(message->data.historyOperations.subCommand) - 1);
|
||
} else {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "historyType");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.historyOperations.historyType, item->valuestring,
|
||
sizeof(message->data.historyOperations.historyType) - 1);
|
||
} else {
|
||
message->data.historyOperations.historyType[0] = '\0';
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "queryId");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.historyOperations.queryId = (uint32_t)item->valueint;
|
||
} else {
|
||
message->data.historyOperations.queryId = 0;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "startIndex");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.historyOperations.startIndex = (uint16_t)item->valueint;
|
||
} else {
|
||
message->data.historyOperations.startIndex = 0;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "fetchCount");
|
||
if (item != NULL && cJSON_IsNumber(item)) {
|
||
message->data.historyOperations.fetchCount = (uint16_t)item->valueint;
|
||
} else {
|
||
message->data.historyOperations.fetchCount = 0;
|
||
}
|
||
} else if (strcmp(message->command, CMD_FAULT_INFO) == 0) {
|
||
/* 解析故障信息请求 */
|
||
item = cJSON_GetObjectItem(data, "faultCode");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.faultInfo.faultCode, item->valuestring,
|
||
sizeof(message->data.faultInfo.faultCode) - 1);
|
||
} else {
|
||
/* 故障代码是可选的,如果为空表示查询所有故障 */
|
||
message->data.faultInfo.faultCode[0] = '\0';
|
||
}
|
||
} else if (strcmp(message->command, CMD_CUSTOM_DATA) == 0) {
|
||
/* 解析自定义数据请求 */
|
||
item = cJSON_GetObjectItem(data, "functionContent");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.customData.functionContent, item->valuestring,
|
||
sizeof(message->data.customData.functionContent) - 1);
|
||
} else {
|
||
/* 如果字段不存在,设置为空字符串 */
|
||
message->data.customData.functionContent[0] = '\0';
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "functionField");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.customData.functionField, item->valuestring,
|
||
sizeof(message->data.customData.functionField) - 1);
|
||
} else {
|
||
/* 如果字段不存在,设置为空字符串 */
|
||
message->data.customData.functionField[0] = '\0';
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(data, "functionParams");
|
||
if (item != NULL && cJSON_IsString(item)) {
|
||
strncpy(message->data.customData.functionParams, item->valuestring,
|
||
sizeof(message->data.customData.functionParams) - 1);
|
||
} else {
|
||
/* 如果字段不存在,设置为空字符串 */
|
||
message->data.customData.functionParams[0] = '\0';
|
||
}
|
||
} else {
|
||
/* 未知命令 */
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_Delete(root);
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 解析时间字符串到Comm_Time结构体
|
||
* @param time_str 时间字符串,格式为"YYYY-MM-DD HH:MM:SS.xxx"
|
||
* @param time 输出时间结构体
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_parse_timestamp_string(const char *time_str, Comm_Time *time)
|
||
{
|
||
int year, month, day, hour, minute, second, millisecond;
|
||
|
||
if (time_str == NULL || time == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 解析时间字符串格式:YYYY-MM-DD HH:MM:SS.xxx */
|
||
if (sscanf(time_str, "%d-%d-%d %d:%d:%d.%d",
|
||
&year, &month, &day, &hour, &minute, &second, &millisecond) != 7) {
|
||
/* 尝试不带毫秒的格式 */
|
||
if (sscanf(time_str, "%d-%d-%d %d:%d:%d",
|
||
&year, &month, &day, &hour, &minute, &second) != 6) {
|
||
return -1;
|
||
}
|
||
millisecond = 0;
|
||
}
|
||
|
||
/* 验证时间范围 */
|
||
if (year < 2000 || year > 2100 ||
|
||
month < 1 || month > 12 ||
|
||
day < 1 || day > 31 ||
|
||
hour < 0 || hour > 23 ||
|
||
minute < 0 || minute > 59 ||
|
||
second < 0 || second > 59) {
|
||
return -1;
|
||
}
|
||
|
||
/* 填充时间结构体 */
|
||
time->iYear = (U16_T)year;
|
||
time->ucMonth = (U8_T)month;
|
||
time->ucDay = (U8_T)day;
|
||
time->ucHour = (U8_T)hour;
|
||
time->ucMin = (U8_T)minute;
|
||
time->ucSec = (U8_T)second;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 计算两个时间之间的分钟差
|
||
* @param time1 时间1
|
||
* @param time2 时间2
|
||
* @retval 分钟差(绝对值)
|
||
*/
|
||
static int tcp_calculate_time_diff_minutes(const Comm_Time *time1, const Comm_Time *time2)
|
||
{
|
||
/* 简单计算:假设每个月30天,每年365天 */
|
||
long total_minutes1 = (long)time1->iYear * 365 * 24 * 60 +
|
||
(long)time1->ucMonth * 30 * 24 * 60 +
|
||
(long)time1->ucDay * 24 * 60 +
|
||
(long)time1->ucHour * 60 +
|
||
(long)time1->ucMin;
|
||
|
||
long total_minutes2 = (long)time2->iYear * 365 * 24 * 60 +
|
||
(long)time2->ucMonth * 30 * 24 * 60 +
|
||
(long)time2->ucDay * 24 * 60 +
|
||
(long)time2->ucHour * 60 +
|
||
(long)time2->ucMin;
|
||
|
||
long diff = total_minutes1 - total_minutes2;
|
||
if (diff < 0) {
|
||
diff = -diff;
|
||
}
|
||
|
||
return (int)diff;
|
||
}
|
||
|
||
/* 子函数声明 */
|
||
static int tcp_process_heartbeat_message(const tcp_message_t *message);
|
||
static int tcp_process_charge_control_message(const tcp_message_t *message);
|
||
static int tcp_process_param_query_message(const tcp_message_t *message);
|
||
static int tcp_process_param_modify_message(const tcp_message_t *message);
|
||
static int tcp_process_firmware_upgrade_message(const tcp_message_t *message);
|
||
static int tcp_process_file_operation_message(const tcp_message_t *message);
|
||
static int tcp_process_fault_info_message(const tcp_message_t *message);
|
||
static int tcp_process_history_operations_message(const tcp_message_t *message);
|
||
static int tcp_process_custom_data_message(const tcp_message_t *message);
|
||
static int tcp_generate_fault_info_json(const tcp_fault_info_response_t *response, char *buffer, uint32_t size);
|
||
|
||
/* 子函数实现 */
|
||
|
||
/**
|
||
* @brief 处理心跳消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_heartbeat_message(const tcp_message_t *message)
|
||
{
|
||
Comm_Time curTime;
|
||
Comm_Time receivedTime;
|
||
int time_diff_minutes = 0;
|
||
|
||
TCP_PRINT("Received heartbeat: sequence=%u, source=%s\r\r\n",
|
||
message->data.heartbeat.sequence,
|
||
message->data.heartbeat.source);
|
||
|
||
/* 解析消息中的时间戳并进行校时检查 */
|
||
if (message->timestamp[0] != '\0') {
|
||
/* 解析接收到的消息时间戳 */
|
||
if (tcp_parse_timestamp_string(message->timestamp, &receivedTime) == 0) {
|
||
/* 获取当前系统时间 */
|
||
GetCurrentTime(&curTime);
|
||
|
||
/* 计算时间差(分钟) */
|
||
time_diff_minutes = tcp_calculate_time_diff_minutes(&receivedTime, &curTime);
|
||
|
||
TCP_PRINT("Time check: received=%04d-%02d-%02d %02d:%02d:%02d, current=%04d-%02d-%02d %02d:%02d:%02d, diff=%d minutes\r\r\n",
|
||
receivedTime.iYear, receivedTime.ucMonth, receivedTime.ucDay,
|
||
receivedTime.ucHour, receivedTime.ucMin, receivedTime.ucSec,
|
||
curTime.iYear, curTime.ucMonth, curTime.ucDay,
|
||
curTime.ucHour, curTime.ucMin, curTime.ucSec,
|
||
time_diff_minutes);
|
||
|
||
/* 如果时间差大于5分钟,进行校时 */
|
||
if (time_diff_minutes > 5) {
|
||
TCP_PRINT("Time difference too large (%d minutes), adjusting system time...\r\r\n", time_diff_minutes);
|
||
|
||
/* 调用RTC校时函数 */
|
||
v_rtc_set_time(&receivedTime);
|
||
|
||
TCP_PRINT("System time adjusted to: %04d-%02d-%02d %02d:%02d:%02d\r\r\n",
|
||
receivedTime.iYear, receivedTime.ucMonth, receivedTime.ucDay,
|
||
receivedTime.ucHour, receivedTime.ucMin, receivedTime.ucSec);
|
||
} else {
|
||
TCP_PRINT("Time difference within acceptable range (%d minutes), no adjustment needed\r\r\n", time_diff_minutes);
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to parse timestamp: %s\r\r\n", message->timestamp);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理充电控制消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_charge_control_message(const tcp_message_t *message)
|
||
{
|
||
char msg[64];
|
||
|
||
TCP_PRINT("Received charge control: gun=%u, action=%u\r\r\n",
|
||
message->data.chargeControl.gunNumber,
|
||
message->data.chargeControl.action);
|
||
|
||
/* 调用system_data模块处理充电控制 */
|
||
if (message->data.chargeControl.action == CHARGE_ACTION_STOP) {
|
||
/* 停止充电 */
|
||
if (system_data_stop_charge(message->data.chargeControl.gunNumber, msg) != 0) {
|
||
TCP_PRINT("Failed to stop charge: %s\r\r\n", msg);
|
||
return -1;
|
||
}
|
||
TCP_PRINT("Charge stopped: %s\r\r\n", msg);
|
||
} else if (message->data.chargeControl.action == CHARGE_ACTION_START) {
|
||
/* 启动充电 */
|
||
if (system_data_start_charge(message->data.chargeControl.gunNumber,
|
||
"", "", msg) != 0) {
|
||
TCP_PRINT("Failed to start charge: %s\r\r\n", msg);
|
||
return -1;
|
||
}
|
||
TCP_PRINT("Charge started: %s\r\r\n", msg);
|
||
} else {
|
||
TCP_PRINT("Unknown charge action: %u\r\r\n", message->data.chargeControl.action);
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理参数查询消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_param_query_message(const tcp_message_t *message)
|
||
{
|
||
tcp_param_query_response_t response;
|
||
char *response_json = NULL;
|
||
int json_len = 0;
|
||
int result = 0;
|
||
/* 参数查询:按固定大小缓冲 + 分包发送 */
|
||
#define TCP_PARAM_QUERY_JSON_BUF_SIZE (2048)
|
||
#define TCP_PARAM_QUERY_MAX_PARAMS_PER_PACKET (20)
|
||
|
||
TCP_PRINT("Received param query: type=%s\r\r\n",
|
||
message->data.paramQuery.type);
|
||
|
||
/* 处理参数查询请求 */
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
if (tcp_process_param_query(&message->data.paramQuery, &response) != 0) {
|
||
TCP_PRINT("Failed to process param query\r\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 动态分配响应JSON缓冲区(固定 2048) */
|
||
response_json = (char *)pvPortMalloc(TCP_PARAM_QUERY_JSON_BUF_SIZE);
|
||
if (response_json == NULL) {
|
||
TCP_PRINT("Failed to allocate memory for response JSON\r\r\n");
|
||
result = -1;
|
||
goto cleanup;
|
||
}
|
||
|
||
/* 按“每包最多 20 个参数”分包应答 */
|
||
{
|
||
uint16_t total = response.count;
|
||
uint16_t offset = 0;
|
||
uint16_t pkt_index = 0;
|
||
uint16_t total_pkts = (total + TCP_PARAM_QUERY_MAX_PARAMS_PER_PACKET - 1) / TCP_PARAM_QUERY_MAX_PARAMS_PER_PACKET;
|
||
|
||
while (offset < total) {
|
||
uint16_t chunk = total - offset;
|
||
if (chunk > TCP_PARAM_QUERY_MAX_PARAMS_PER_PACKET) {
|
||
chunk = TCP_PARAM_QUERY_MAX_PARAMS_PER_PACKET;
|
||
}
|
||
|
||
tcp_param_query_response_t chunk_resp;
|
||
memset(&chunk_resp, 0, sizeof(chunk_resp));
|
||
strncpy(chunk_resp.type, response.type, sizeof(chunk_resp.type) - 1);
|
||
chunk_resp.count = chunk;
|
||
chunk_resp.params = &response.params[offset];
|
||
|
||
json_len = tcp_generate_param_query_response(&chunk_resp, response_json, TCP_PARAM_QUERY_JSON_BUF_SIZE);
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, (uint16_t)json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("Param query response sent pkt %u/%u, params %u~%u, json %d bytes\r\r\n",
|
||
(unsigned)(pkt_index + 1), (unsigned)total_pkts,
|
||
(unsigned)offset, (unsigned)(offset + chunk - 1),
|
||
json_len);
|
||
} else {
|
||
TCP_PRINT("Failed to send param query response pkt %u/%u: %d\r\r\n",
|
||
(unsigned)(pkt_index + 1), (unsigned)total_pkts, send_err);
|
||
result = -1;
|
||
break;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate param query response pkt %u/%u (offset=%u, chunk=%u)\r\r\n",
|
||
(unsigned)(pkt_index + 1), (unsigned)total_pkts,
|
||
(unsigned)offset, (unsigned)chunk);
|
||
result = -1;
|
||
break;
|
||
}
|
||
|
||
offset = (uint16_t)(offset + chunk);
|
||
pkt_index++;
|
||
}
|
||
}
|
||
|
||
cleanup:
|
||
/* 释放动态分配的内存 */
|
||
if (response.params != NULL) {
|
||
vPortFree(response.params);
|
||
}
|
||
if (response_json != NULL) {
|
||
vPortFree(response_json);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理参数修改消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_param_modify_message(const tcp_message_t *message)
|
||
{
|
||
tcp_param_modify_response_t response;
|
||
char *response_json = NULL;
|
||
int json_len = 0;
|
||
int result = 0;
|
||
|
||
TCP_PRINT("Received param modify: type=%s, count=%u\r\r\n",
|
||
message->data.paramModify.type,
|
||
message->data.paramModify.count);
|
||
|
||
/* 处理参数修改请求 */
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
if (tcp_process_param_modify(&message->data.paramModify, &response) != 0) {
|
||
TCP_PRINT("Failed to process param modify\r\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 动态分配响应JSON缓冲区 */
|
||
response_json = (char *)pvPortMalloc(2048);
|
||
if (response_json == NULL) {
|
||
TCP_PRINT("Failed to allocate memory for response JSON\r\r\n");
|
||
result = -1;
|
||
goto cleanup;
|
||
}
|
||
|
||
/* 生成响应JSON */
|
||
json_len = tcp_generate_param_modify_response(&response, response_json, 2048);
|
||
if (json_len > 0) {
|
||
TCP_PRINT("Param modify response generated (%d bytes)\r\r\n", json_len);
|
||
|
||
/* 发送响应到客户端 */
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("Param modify response sent successfully\r\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send param modify response: %d\r\r\n", send_err);
|
||
result = -1;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate param modify response\r\r\n");
|
||
result = -1;
|
||
}
|
||
|
||
cleanup:
|
||
/* 注意:message->data.paramModify.params 的内存由 tcp_free_message 函数释放
|
||
这里不释放,因为 message 是 const 指针,不能修改 */
|
||
if (response_json != NULL) {
|
||
vPortFree(response_json);
|
||
response_json = NULL;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理固件升级消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_firmware_upgrade_message(const tcp_message_t *message)
|
||
{
|
||
TCP_PRINT("Received firmware upgrade: subCommand=%s\r\r\n",
|
||
message->data.firmwareUpgrade.subCommand);
|
||
|
||
/* 处理固件升级请求 */
|
||
if (tcp_process_firmware_upgrade(&message->data.firmwareUpgrade) != 0) {
|
||
TCP_PRINT("Failed to process firmware upgrade\r\r\n");
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理文件操作消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_file_operation_message(const tcp_message_t *message)
|
||
{
|
||
TCP_PRINT("Received file operation: subCommand=%s\r\r\n",
|
||
message->data.fileOperation.subCommand);
|
||
|
||
/* 处理文件操作请求 */
|
||
if (tcp_process_file_operation(&message->data.fileOperation) != 0) {
|
||
TCP_PRINT("Failed to process file operation\r\r\n");
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理接收到的消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_process_received_message(const tcp_message_t *message)
|
||
{
|
||
if (message == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 根据命令类型调用相应的处理函数 */
|
||
if (strcmp(message->command, CMD_HEARTBEAT) == 0) {
|
||
return tcp_process_heartbeat_message(message);
|
||
} else if (strcmp(message->command, CMD_CHARGE_CONTROL) == 0) {
|
||
return tcp_process_charge_control_message(message);
|
||
} else if (strcmp(message->command, CMD_PARAM_QUERY) == 0) {
|
||
return tcp_process_param_query_message(message);
|
||
} else if (strcmp(message->command, CMD_PARAM_MODIFY) == 0) {
|
||
return tcp_process_param_modify_message(message);
|
||
} else if (strcmp(message->command, CMD_FIRMWARE_UPGRADE) == 0) {
|
||
return tcp_process_firmware_upgrade_message(message);
|
||
} else if (strcmp(message->command, CMD_FILE_OPERATIONS) == 0) {
|
||
return tcp_process_file_operation_message(message);
|
||
} else if (strcmp(message->command, CMD_FAULT_INFO) == 0) {
|
||
return tcp_process_fault_info_message(message);
|
||
} else if (strcmp(message->command, CMD_HISTORY_OPERATIONS) == 0) {
|
||
return tcp_process_history_operations_message(message);
|
||
} else if (strcmp(message->command, CMD_CUSTOM_DATA) == 0) {
|
||
return tcp_process_custom_data_message(message);
|
||
} else {
|
||
TCP_PRINT("Received unknown command: %s\r\r\n", message->command);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 填充参数项(辅助函数)
|
||
* @param item 参数项指针
|
||
* @param name 参数名称
|
||
* @param type 参数类型
|
||
* @param value 参数值(字符串格式)
|
||
* @retval 无
|
||
*/
|
||
static void tcp_fill_param_item(tcp_param_item_t *item, const char *name, const char *type, const char *value)
|
||
{
|
||
if (item == NULL || name == NULL || type == NULL || value == NULL) {
|
||
return;
|
||
}
|
||
|
||
strncpy(item->name, name, sizeof(item->name) - 1);
|
||
strncpy(item->type, type, sizeof(item->type) - 1);
|
||
strncpy(item->value, value, sizeof(item->value) - 1);
|
||
}
|
||
|
||
/**
|
||
* @brief 处理参数查询请求(使用参数映射表)
|
||
* @param request 参数查询请求
|
||
* @param response 参数查询响应
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_process_param_query(const tcp_param_query_request_t *request, tcp_param_query_response_t *response)
|
||
{
|
||
const param_map_item_t *param_map = NULL;
|
||
uint16_t param_count = 0;
|
||
uint16_t i;
|
||
char value_buffer[128];
|
||
|
||
if (request == NULL || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 复制参数类型 */
|
||
strncpy(response->type, request->type, sizeof(response->type) - 1);
|
||
|
||
/* 根据参数类型获取对应的映射表 */
|
||
if (strcmp(request->type, PARAM_TYPE_BASIC) == 0) {
|
||
param_map = param_get_basic_map();
|
||
param_count = param_get_basic_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_NETWORK) == 0) {
|
||
param_map = param_get_network_map();
|
||
param_count = param_get_network_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_METER) == 0) {
|
||
param_map = param_get_meter_map();
|
||
param_count = param_get_meter_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_ENABLE) == 0) {
|
||
param_map = param_get_enable_map();
|
||
param_count = param_get_enable_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_FEE) == 0) {
|
||
param_map = param_get_fee_map();
|
||
param_count = param_get_fee_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_SDK) == 0) {
|
||
param_map = param_get_sdk_map();
|
||
param_count = param_get_sdk_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_QRCODE) == 0) {
|
||
param_map = param_get_qrcode_map();
|
||
param_count = param_get_qrcode_map_size();
|
||
} else {
|
||
/* 其他参数类型暂不支持 */
|
||
response->count = 0;
|
||
response->params = NULL;
|
||
TCP_PRINT("Unsupported param type: %s\r\r\n", request->type);
|
||
return -1;
|
||
}
|
||
|
||
if (param_map == NULL || param_count == 0) {
|
||
response->count = 0;
|
||
response->params = NULL;
|
||
TCP_PRINT("No parameter map found for type: %s\r\r\n", request->type);
|
||
return -1;
|
||
}
|
||
|
||
/* 分配参数数组内存 */
|
||
response->count = param_count;
|
||
response->params = (tcp_param_item_t *)pvPortMalloc(response->count * sizeof(tcp_param_item_t));
|
||
if (response->params == NULL) {
|
||
response->count = 0;
|
||
return -1;
|
||
}
|
||
|
||
/* 填充基本参数 */
|
||
memset(response->params, 0, response->count * sizeof(tcp_param_item_t));
|
||
|
||
/* 使用参数映射表填充参数 */
|
||
for (i = 0; i < param_count; i++) {
|
||
const param_map_item_t *map_item = ¶m_map[i];
|
||
|
||
/* 获取参数值字符串 */
|
||
if (param_get_value_as_string(map_item, value_buffer, sizeof(value_buffer)) != 0) {
|
||
snprintf(value_buffer, sizeof(value_buffer), "error");
|
||
}
|
||
|
||
/* 填充参数项 */
|
||
strncpy(response->params[i].name, map_item->param_name, sizeof(response->params[i].name) - 1);
|
||
strncpy(response->params[i].type, param_type_to_string(map_item->data_type),
|
||
sizeof(response->params[i].type) - 1);
|
||
strncpy(response->params[i].value, value_buffer, sizeof(response->params[i].value) - 1);
|
||
|
||
/* 填充描述字段(如果存在) */
|
||
if (map_item->decs != NULL) {
|
||
strncpy(response->params[i].decs, map_item->decs, sizeof(response->params[i].decs) - 1);
|
||
} else {
|
||
response->params[i].decs[0] = '\0'; /* 设置为空字符串 */
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成参数查询响应JSON
|
||
* @param response 参数查询响应
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_param_query_response(const tcp_param_query_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
cJSON *params_array = NULL;
|
||
cJSON *param_item = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
int i;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_PARAM_QUERY);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "type", response->type);
|
||
cJSON_AddNumberToObject(data, "count", response->count);
|
||
|
||
/* 创建参数数组 */
|
||
params_array = cJSON_CreateArray();
|
||
if (params_array == NULL) {
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 添加参数项到数组 */
|
||
for (i = 0; i < response->count; i++) {
|
||
param_item = cJSON_CreateObject();
|
||
if (param_item == NULL) {
|
||
cJSON_Delete(params_array);
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(param_item, "name", response->params[i].name);
|
||
cJSON_AddStringToObject(param_item, "type", response->params[i].type);
|
||
cJSON_AddStringToObject(param_item, "value", response->params[i].value);
|
||
cJSON_AddStringToObject(param_item, "decs", response->params[i].decs);
|
||
|
||
cJSON_AddItemToArray(params_array, param_item);
|
||
}
|
||
|
||
cJSON_AddItemToObject(data, "params", params_array);
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理参数修改请求
|
||
* @param request 参数修改请求
|
||
* @param response 参数修改响应
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_process_param_modify(const tcp_param_modify_request_t *request, tcp_param_modify_response_t *response)
|
||
{
|
||
const param_map_item_t *param_map = NULL;
|
||
uint16_t param_count = 0;
|
||
uint16_t i;
|
||
|
||
if (request == NULL || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 初始化响应 */
|
||
memset(response, 0, sizeof(tcp_param_modify_response_t));
|
||
strncpy(response->type, request->type, sizeof(response->type) - 1);
|
||
response->received = request->count;
|
||
|
||
/* 根据参数类型获取对应的映射表 */
|
||
if (strcmp(request->type, PARAM_TYPE_BASIC) == 0) {
|
||
param_map = param_get_basic_map();
|
||
param_count = param_get_basic_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_NETWORK) == 0) {
|
||
param_map = param_get_network_map();
|
||
param_count = param_get_network_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_METER) == 0) {
|
||
param_map = param_get_meter_map();
|
||
param_count = param_get_meter_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_ENABLE) == 0) {
|
||
param_map = param_get_enable_map();
|
||
param_count = param_get_enable_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_FEE) == 0) {
|
||
param_map = param_get_fee_map();
|
||
param_count = param_get_fee_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_SDK) == 0) {
|
||
param_map = param_get_sdk_map();
|
||
param_count = param_get_sdk_map_size();
|
||
} else if (strcmp(request->type, PARAM_TYPE_QRCODE) == 0) {
|
||
param_map = param_get_qrcode_map();
|
||
param_count = param_get_qrcode_map_size();
|
||
} else {
|
||
/* 其他参数类型暂不支持 */
|
||
TCP_PRINT("Unsupported param type for modify: %s\r\r\n", request->type);
|
||
return -1;
|
||
}
|
||
|
||
if (param_map == NULL || param_count == 0) {
|
||
TCP_PRINT("No parameter map found for type: %s\r\r\n", request->type);
|
||
return -1;
|
||
}
|
||
|
||
/* 处理每个参数 */
|
||
for (i = 0; i < request->count; i++) {
|
||
const tcp_param_item_t *req_item = &request->params[i];
|
||
const param_map_item_t *map_item = NULL;
|
||
uint16_t j;
|
||
|
||
/* 在映射表中查找参数 */
|
||
for (j = 0; j < param_count; j++) {
|
||
if (strcmp(param_map[j].param_name, req_item->name) == 0) {
|
||
map_item = ¶m_map[j];
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (map_item == NULL) {
|
||
/* 未找到参数 */
|
||
TCP_PRINT("Parameter not found: %s\r\r\n", req_item->name);
|
||
response->failed++;
|
||
continue;
|
||
}
|
||
|
||
/* 尝试设置参数值 */
|
||
if (param_set_value_from_string(map_item, req_item->value) == 0) {
|
||
TCP_PRINT("Parameter set successfully: %s = %s\r\r\n", req_item->name, req_item->value);
|
||
response->success++;
|
||
} else {
|
||
TCP_PRINT("Failed to set parameter: %s = %s\r\r\n", req_item->name, req_item->value);
|
||
response->failed++;
|
||
}
|
||
response->processed++;
|
||
}
|
||
|
||
v_flash_save_cfg_data();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成参数修改响应JSON
|
||
* @param response 参数修改响应
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_param_modify_response(const tcp_param_modify_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_PARAM_MODIFY);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "type", response->type);
|
||
cJSON_AddNumberToObject(data, "received", response->received);
|
||
cJSON_AddNumberToObject(data, "processed", response->processed);
|
||
cJSON_AddNumberToObject(data, "success", response->success);
|
||
cJSON_AddNumberToObject(data, "failed", response->failed);
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成固件升级消息JSON
|
||
* @param firmwareUpgrade 固件升级数据结构体指针
|
||
* @param subCommand 子命令字符串
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_firmware_upgrade_json(const tcp_firmware_upgrade_data_t *firmwareUpgrade, const char *subCommand, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || firmwareUpgrade == NULL || subCommand == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_FIRMWARE_UPGRADE);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", subCommand);
|
||
|
||
/* 根据子命令添加不同的字段 */
|
||
if (strcmp(subCommand, FIRMWARE_SUBCMD_START) == 0) {
|
||
cJSON_AddNumberToObject(data, "fileSize", firmwareUpgrade->u.start.fileSize);
|
||
cJSON_AddNumberToObject(data, "totalPackets", firmwareUpgrade->u.start.totalPackets);
|
||
cJSON_AddNumberToObject(data, "packetSize", firmwareUpgrade->u.start.packetSize);
|
||
cJSON_AddStringToObject(data, "firmwareVersion", firmwareUpgrade->u.start.firmwareVersion);
|
||
} else if (strcmp(subCommand, FIRMWARE_SUBCMD_DATA) == 0) {
|
||
cJSON_AddNumberToObject(data, "packetIndex", firmwareUpgrade->u.data.packetIndex);
|
||
cJSON_AddNumberToObject(data, "totalPackets", firmwareUpgrade->u.data.totalPackets);
|
||
if (firmwareUpgrade->u.data.data != NULL && firmwareUpgrade->u.data.data_len > 0) {
|
||
cJSON_AddStringToObject(data, "data", firmwareUpgrade->u.data.data);
|
||
} else {
|
||
cJSON_AddStringToObject(data, "data", "");
|
||
}
|
||
cJSON_AddNumberToObject(data, "crc", firmwareUpgrade->u.data.crc);
|
||
} else if (strcmp(subCommand, FIRMWARE_SUBCMD_END) == 0) {
|
||
cJSON_AddNumberToObject(data, "status", firmwareUpgrade->u.end.status);
|
||
cJSON_AddStringToObject(data, "errorMessage", firmwareUpgrade->u.end.errorMessage);
|
||
} else if (strcmp(subCommand, FIRMWARE_SUBCMD_RESPONSE) == 0) {
|
||
cJSON_AddNumberToObject(data, "response", firmwareUpgrade->u.response.response);
|
||
cJSON_AddNumberToObject(data, "packetIndex", firmwareUpgrade->u.response.packetIndex);
|
||
cJSON_AddStringToObject(data, "message", firmwareUpgrade->u.response.message);
|
||
} else {
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/** 固件升级 Response:0=ACK,非0=NAK */
|
||
#define FIRMWARE_RESP_ACK 0U
|
||
#define FIRMWARE_RESP_NAK 1U
|
||
|
||
void tcp_firmware_upgrade_log_io(const char *dir, const char *data, uint32_t len)
|
||
{
|
||
uint32_t off = 0U;
|
||
enum { kChunk = 480U };
|
||
|
||
if ((dir == NULL) || (data == NULL) || (len == 0U)) {
|
||
return;
|
||
}
|
||
|
||
if (len <= kChunk) {
|
||
printf("[FW_UPGRADE] %s (%u): %.*s\r\n", dir, (unsigned)len, (int)len, data);
|
||
return;
|
||
}
|
||
|
||
printf("[FW_UPGRADE] %s (%u bytes):\r\n", dir, (unsigned)len);
|
||
while (off < len) {
|
||
uint32_t n = len - off;
|
||
|
||
if (n > kChunk) {
|
||
n = kChunk;
|
||
}
|
||
printf("[FW_UPGRADE] %s+%u: %.*s\r\n", dir, (unsigned)off, (int)n, data + off);
|
||
off += n;
|
||
}
|
||
}
|
||
|
||
void tcp_firmware_upgrade_log_buf(const char *dir, const uint8_t *data, uint32_t len)
|
||
{
|
||
uint32_t off = 0U;
|
||
uint32_t i;
|
||
enum { kHexShow = 48U, kChunk = 256U };
|
||
|
||
if ((dir == NULL) || (data == NULL) || (len == 0U)) {
|
||
return;
|
||
}
|
||
|
||
printf("[FW_UPGRADE] %s (%u) HEX:", dir, (unsigned)len);
|
||
for (i = 0U; i < len && i < kHexShow; i++) {
|
||
printf(" %02X", (unsigned)data[i]);
|
||
}
|
||
if (len > kHexShow) {
|
||
printf(" ...");
|
||
}
|
||
printf("\r\n");
|
||
|
||
if (len <= kChunk) {
|
||
printf("[FW_UPGRADE] %s TXT: %.*s\r\n", dir, (int)len, (const char *)data);
|
||
return;
|
||
}
|
||
|
||
while (off < len) {
|
||
uint32_t n = len - off;
|
||
|
||
if (n > kChunk) {
|
||
n = kChunk;
|
||
}
|
||
printf("[FW_UPGRADE] %s+%u TXT: %.*s\r\n", dir, (unsigned)off, (int)n,
|
||
(const char *)(data + off));
|
||
off += n;
|
||
}
|
||
}
|
||
|
||
void tcp_firmware_upgrade_log_meta(const char *tag, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
||
{
|
||
if (tag == NULL) {
|
||
return;
|
||
}
|
||
printf("[FW_UPGRADE] %s used=%u proc=%u cap=%u pending=%u\r\n",
|
||
tag, (unsigned)a, (unsigned)b, (unsigned)c, (unsigned)d);
|
||
}
|
||
|
||
static int tcp_send_firmware_upgrade_response(uint8_t response_code, int packet_index, const char *message)
|
||
{
|
||
tcp_firmware_upgrade_data_t response_data;
|
||
char response_json[512];
|
||
int json_len;
|
||
err_t send_err;
|
||
|
||
memset(&response_data, 0, sizeof(response_data));
|
||
strncpy(response_data.subCommand, FIRMWARE_SUBCMD_RESPONSE, sizeof(response_data.subCommand) - 1U);
|
||
response_data.u.response.response = response_code;
|
||
response_data.u.response.packetIndex = packet_index;
|
||
if (message != NULL) {
|
||
strncpy(response_data.u.response.message, message, sizeof(response_data.u.response.message) - 1U);
|
||
}
|
||
|
||
json_len = tcp_generate_firmware_upgrade_json(&response_data, FIRMWARE_SUBCMD_RESPONSE,
|
||
response_json, sizeof(response_json));
|
||
if (json_len <= 0) {
|
||
return -1;
|
||
}
|
||
|
||
tcp_firmware_upgrade_log_io("TX", response_json, (uint32_t)json_len);
|
||
send_err = tcp_server_send_json(response_json, (uint32_t)json_len);
|
||
return (send_err == ERR_OK) ? 0 : -1;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理固件升级请求
|
||
* @param firmwareUpgrade 固件升级数据结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_process_firmware_upgrade(const tcp_firmware_upgrade_data_t *firmwareUpgrade)
|
||
{
|
||
int ret;
|
||
|
||
if (firmwareUpgrade == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
TCP_PRINT("Processing firmware upgrade: subCommand=%s\r\n", firmwareUpgrade->subCommand);
|
||
|
||
if (strcmp(firmwareUpgrade->subCommand, FIRMWARE_SUBCMD_START) == 0) {
|
||
TCP_PRINT("Firmware upgrade start:\r\n");
|
||
TCP_PRINT(" File size: %u bytes\r\n", firmwareUpgrade->u.start.fileSize);
|
||
TCP_PRINT(" Total packets: %u\r\n", firmwareUpgrade->u.start.totalPackets);
|
||
TCP_PRINT(" Packet size: %u bytes\r\n", firmwareUpgrade->u.start.packetSize);
|
||
TCP_PRINT(" Firmware version: %s\r\n", firmwareUpgrade->u.start.firmwareVersion);
|
||
|
||
(void)tcp_server_rx_upgrade_begin();
|
||
|
||
if (system_filetransfer_start_firmware_upgrade(
|
||
firmwareUpgrade->u.start.fileSize,
|
||
firmwareUpgrade->u.start.totalPackets,
|
||
firmwareUpgrade->u.start.packetSize,
|
||
firmwareUpgrade->u.start.firmwareVersion) != 0) {
|
||
TCP_PRINT("Failed to start firmware upgrade\r\n");
|
||
tcp_server_rx_upgrade_end();
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, -1, "Start rejected");
|
||
return -1;
|
||
}
|
||
|
||
if (system_filetransfer_commit_firmware_start() != 0) {
|
||
TCP_PRINT("Failed to erase firmware area\r\n");
|
||
tcp_server_rx_upgrade_end();
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, -1, "Erase failed");
|
||
return -1;
|
||
}
|
||
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_ACK, -1, "Start accepted");
|
||
|
||
tcp_server_link_rx_drain();
|
||
|
||
} else if (strcmp(firmwareUpgrade->subCommand, FIRMWARE_SUBCMD_DATA) == 0) {
|
||
int pkt = (int)firmwareUpgrade->u.data.packetIndex;
|
||
|
||
TCP_PRINT("Firmware upgrade data packet:\r\n");
|
||
TCP_PRINT(" Packet index: %u/%u\r\n", firmwareUpgrade->u.data.packetIndex, firmwareUpgrade->u.data.totalPackets);
|
||
TCP_PRINT(" Data length: %u bytes (Base64)\r\n", firmwareUpgrade->u.data.data_len);
|
||
TCP_PRINT(" CRC: 0x%08X\r\n", firmwareUpgrade->u.data.crc);
|
||
|
||
if (system_filetransfer_receive_firmware_packet(
|
||
firmwareUpgrade->u.data.packetIndex,
|
||
(const uint8_t *)firmwareUpgrade->u.data.data,
|
||
firmwareUpgrade->u.data.data_len,
|
||
firmwareUpgrade->u.data.crc) != 0) {
|
||
TCP_PRINT("Failed to receive firmware packet\r\n");
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, pkt, "Packet rejected");
|
||
return -1;
|
||
}
|
||
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_ACK, pkt, "Packet received");
|
||
|
||
} else if (strcmp(firmwareUpgrade->subCommand, FIRMWARE_SUBCMD_END) == 0) {
|
||
firmware_upgrade_context_t fw_ctx;
|
||
|
||
TCP_PRINT("Firmware upgrade end:\r\n");
|
||
TCP_PRINT(" Status: %u\r\n", firmwareUpgrade->u.end.status);
|
||
TCP_PRINT(" Error message: %s\r\n", firmwareUpgrade->u.end.errorMessage);
|
||
|
||
memset(&fw_ctx, 0, sizeof(fw_ctx));
|
||
if (system_filetransfer_get_firmware_status(&fw_ctx) != 0 ||
|
||
fw_ctx.state == FILE_TRANSFER_IDLE) {
|
||
TCP_PRINT("No active firmware upgrade session\r\n");
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, 0, "No upgrade session");
|
||
return -1;
|
||
}
|
||
|
||
if ((firmwareUpgrade->u.end.status == FIRMWARE_STATUS_SUCCESS ||
|
||
firmwareUpgrade->u.end.status == FIRMWARE_STATUS_COMPLETED) &&
|
||
fw_ctx.received_packets == fw_ctx.total_packets &&
|
||
fw_ctx.received_bytes >= fw_ctx.file_size) {
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_ACK, 0, "Upgrade completed");
|
||
tcp_server_link_rx_drain();
|
||
vTaskDelay(pdMS_TO_TICKS(200));
|
||
(void)system_filetransfer_end_firmware_upgrade(
|
||
firmwareUpgrade->u.end.status,
|
||
firmwareUpgrade->u.end.errorMessage);
|
||
return 0;
|
||
}
|
||
|
||
ret = system_filetransfer_end_firmware_upgrade(
|
||
firmwareUpgrade->u.end.status,
|
||
firmwareUpgrade->u.end.errorMessage);
|
||
if (ret < 0) {
|
||
TCP_PRINT("No active firmware upgrade session\r\n");
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, 0, "No upgrade session");
|
||
return -1;
|
||
}
|
||
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, 0, "Upgrade failed");
|
||
return -1;
|
||
|
||
} else if (strcmp(firmwareUpgrade->subCommand, FIRMWARE_SUBCMD_RESPONSE) == 0) {
|
||
TCP_PRINT("Firmware upgrade response from client: code=%u index=%d msg=%s\r\n",
|
||
firmwareUpgrade->u.response.response,
|
||
firmwareUpgrade->u.response.packetIndex,
|
||
firmwareUpgrade->u.response.message);
|
||
|
||
} else {
|
||
TCP_PRINT("Unknown firmware upgrade subCommand: %s\r\n", firmwareUpgrade->subCommand);
|
||
tcp_send_firmware_upgrade_response(FIRMWARE_RESP_NAK, -1, "Unknown subCommand");
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成文件查询响应JSON
|
||
* @param response 文件查询响应结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_file_query_response(const tcp_file_query_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
cJSON *files_array = NULL;
|
||
cJSON *file_item = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
int i;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_FILE_OPERATIONS);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", FILE_OP_SUBCMD_QUERY);
|
||
cJSON_AddStringToObject(data, "path", response->path);
|
||
cJSON_AddNumberToObject(data, "fileCount", response->file_count);
|
||
cJSON_AddNumberToObject(data, "dirCount", response->dir_count);
|
||
cJSON_AddNumberToObject(data, "totalSize", response->total_size);
|
||
|
||
/* 创建文件数组 */
|
||
if (response->file_count > 0 && response->files != NULL) {
|
||
files_array = cJSON_CreateArray();
|
||
if (files_array == NULL) {
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 添加文件项到数组 */
|
||
for (i = 0; i < response->file_count; i++) {
|
||
file_item = cJSON_CreateObject();
|
||
if (file_item == NULL) {
|
||
cJSON_Delete(files_array);
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(file_item, "name", response->files[i].name);
|
||
cJSON_AddNumberToObject(file_item, "type", response->files[i].type);
|
||
cJSON_AddNumberToObject(file_item, "size", response->files[i].size);
|
||
cJSON_AddStringToObject(file_item, "modifiedTime", response->files[i].modified_time);
|
||
cJSON_AddStringToObject(file_item, "createdTime", response->files[i].created_time);
|
||
|
||
cJSON_AddItemToArray(files_array, file_item);
|
||
}
|
||
|
||
cJSON_AddItemToObject(data, "files", files_array);
|
||
}
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
TCP_PRINT("Generated file query response JSON (%d bytes)\r\n", json_len);
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成文件删除响应JSON
|
||
* @param response 文件删除响应结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_file_delete_response(const tcp_file_delete_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_FILE_OPERATIONS);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", FILE_OP_SUBCMD_DELETE);
|
||
cJSON_AddStringToObject(data, "path", response->path);
|
||
cJSON_AddNumberToObject(data, "status", response->status);
|
||
cJSON_AddStringToObject(data, "message", response->message);
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
TCP_PRINT("Generated file delete response JSON (%d bytes)\r\n", json_len);
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成文件下载响应JSON
|
||
* @param response 文件下载响应结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_file_download_response(const tcp_file_download_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_FILE_OPERATIONS);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", FILE_OP_SUBCMD_DOWNLOAD);
|
||
cJSON_AddStringToObject(data, "path", response->path);
|
||
cJSON_AddNumberToObject(data, "fileSize", response->file_size);
|
||
cJSON_AddNumberToObject(data, "offset", response->offset);
|
||
cJSON_AddNumberToObject(data, "chunkSize", response->chunk_size);
|
||
cJSON_AddNumberToObject(data, "dataLen", response->data_len);
|
||
cJSON_AddNumberToObject(data, "isLastChunk", response->is_last_chunk);
|
||
|
||
/* 添加数据字段:文件块经 Base64 编码后写入,避免日志中的控制字符/非 UTF-8 导致 JSON 非法 */
|
||
if (response->data != NULL && response->data_len > 0) {
|
||
uint32_t b64_size = ((response->data_len + 2) / 3) * 4 + 1;
|
||
char *b64_buf = (char *)pvPortMalloc(b64_size);
|
||
if (b64_buf != NULL) {
|
||
if (base64_encode(response->data, response->data_len, b64_buf, b64_size) > 0) {
|
||
cJSON_AddStringToObject(data, "data", b64_buf);
|
||
} else {
|
||
cJSON_AddStringToObject(data, "data", "");
|
||
}
|
||
vPortFree(b64_buf);
|
||
} else {
|
||
cJSON_AddStringToObject(data, "data", "");
|
||
}
|
||
} else {
|
||
cJSON_AddStringToObject(data, "data", "");
|
||
}
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
TCP_PRINT("Generated file download response JSON (%d bytes)\r\n", json_len);
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成文件上传响应JSON
|
||
* @param response 文件上传响应结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_file_upload_response(const tcp_file_upload_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_FILE_OPERATIONS);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", FILE_OP_SUBCMD_UPLOAD);
|
||
cJSON_AddStringToObject(data, "path", response->path);
|
||
cJSON_AddNumberToObject(data, "receivedSize", response->received_size);
|
||
cJSON_AddNumberToObject(data, "totalSize", response->total_size);
|
||
cJSON_AddNumberToObject(data, "status", response->status);
|
||
cJSON_AddStringToObject(data, "message", response->message);
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
TCP_PRINT("Generated file upload response JSON (%d bytes)\r\n", json_len);
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理文件操作请求
|
||
* @param fileOperation 文件操作数据结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
int tcp_process_file_operation(const tcp_file_operation_data_t *fileOperation)
|
||
{
|
||
if (fileOperation == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
TCP_PRINT("Processing file operation: subCommand=%s\r\n", fileOperation->subCommand);
|
||
|
||
/* 根据子命令处理 */
|
||
if (strcmp(fileOperation->subCommand, FILE_OP_SUBCMD_QUERY) == 0) {
|
||
TCP_PRINT("File query operation:\r\n");
|
||
TCP_PRINT(" Path: %s\r\n", fileOperation->request.query.path);
|
||
|
||
/* 调用system_filectrl模块处理文件查询 */
|
||
tcp_file_query_response_t response;
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
if (system_filectrl_process_query((const file_query_request_t *)&fileOperation->request.query,
|
||
(file_query_response_t *)&response) != 0) {
|
||
TCP_PRINT("Failed to query files\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 生成响应JSON并发送 */
|
||
char response_json[2048];
|
||
int json_len = tcp_generate_file_query_response(&response, response_json, sizeof(response_json));
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("File query response sent successfully\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send file query response: %d\r\n", send_err);
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate file query response JSON\r\n");
|
||
}
|
||
|
||
/* 释放动态分配的内存 - 使用专门的释放函数 */
|
||
system_filectrl_free_query_response((file_query_response_t *)&response);
|
||
|
||
} else if (strcmp(fileOperation->subCommand, FILE_OP_SUBCMD_DELETE) == 0) {
|
||
TCP_PRINT("File delete operation:\r\n");
|
||
TCP_PRINT(" Path: %s\r\n", fileOperation->request.delete.path);
|
||
|
||
/* 调用system_filectrl模块处理文件删除 */
|
||
tcp_file_delete_response_t response;
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
if (system_filectrl_process_delete((const file_delete_request_t *)&fileOperation->request.delete,
|
||
(file_delete_response_t *)&response) != 0) {
|
||
TCP_PRINT("Failed to delete file\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 生成响应JSON并发送 */
|
||
char response_json[512];
|
||
int json_len = tcp_generate_file_delete_response(&response, response_json, sizeof(response_json));
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("File delete response sent successfully\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send file delete response: %d\r\n", send_err);
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate file delete response JSON\r\n");
|
||
}
|
||
|
||
} else if (strcmp(fileOperation->subCommand, FILE_OP_SUBCMD_DOWNLOAD) == 0) {
|
||
TCP_PRINT("File download operation:\r\n");
|
||
TCP_PRINT(" Path: %s\r\n", fileOperation->request.download.path);
|
||
TCP_PRINT(" Offset: %u\r\n", fileOperation->request.download.offset);
|
||
TCP_PRINT(" Chunk size: %u\r\n", fileOperation->request.download.chunk_size);
|
||
|
||
/* 调用system_filectrl模块处理文件下载 */
|
||
tcp_file_download_response_t response;
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
if (system_filectrl_process_download((const file_download_request_t *)&fileOperation->request.download,
|
||
(file_download_response_t *)&response) != 0) {
|
||
TCP_PRINT("Failed to download file\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 生成响应JSON并发送 */
|
||
char response_json[2048]; /* 需要足够大以容纳Base64数据 */
|
||
int json_len = tcp_generate_file_download_response(&response, response_json, sizeof(response_json));
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("File download response sent successfully\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send file download response: %d\r\n", send_err);
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate file download response JSON\r\n");
|
||
}
|
||
|
||
/* 释放动态分配的内存 - 使用专门的释放函数 */
|
||
system_filectrl_free_download_response((file_download_response_t *)&response);
|
||
|
||
} else if (strcmp(fileOperation->subCommand, FILE_OP_SUBCMD_UPLOAD) == 0) {
|
||
TCP_PRINT("File upload operation:\r\n");
|
||
TCP_PRINT(" Path: %s\r\n", fileOperation->request.upload.path);
|
||
TCP_PRINT(" Offset: %u\r\n", fileOperation->request.upload.offset);
|
||
TCP_PRINT(" File size: %u\r\n", fileOperation->request.upload.file_size);
|
||
TCP_PRINT(" Data length: %u bytes (Base64)\r\n", (uint32_t)strlen((const char *)fileOperation->request.upload.data));
|
||
|
||
/* 调用system_filectrl模块处理文件上传 */
|
||
tcp_file_upload_response_t response;
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
if (system_filectrl_process_upload((const file_upload_request_t *)&fileOperation->request.upload,
|
||
(file_upload_response_t *)&response) != 0) {
|
||
TCP_PRINT("Failed to upload file\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 生成响应JSON并发送 */
|
||
char response_json[512];
|
||
int json_len = tcp_generate_file_upload_response(&response, response_json, sizeof(response_json));
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("File upload response sent successfully\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send file upload response: %d\r\n", send_err);
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate file upload response JSON\r\n");
|
||
}
|
||
|
||
} else {
|
||
TCP_PRINT("Unknown file operation subCommand: %s\r\n", fileOperation->subCommand);
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 释放消息结构体中分配的内存
|
||
* @param message 消息结构体指针
|
||
*/
|
||
void tcp_free_message(tcp_message_t *message)
|
||
{
|
||
if (message == NULL) {
|
||
return;
|
||
}
|
||
|
||
/* 根据命令类型释放不同的动态分配内存 */
|
||
if (strcmp(message->command, CMD_PARAM_MODIFY) == 0) {
|
||
/* 释放参数修改请求中的参数数组 */
|
||
if (message->data.paramModify.params != NULL) {
|
||
vPortFree(message->data.paramModify.params);
|
||
message->data.paramModify.params = NULL;
|
||
message->data.paramModify.count = 0;
|
||
}
|
||
} else if (strcmp(message->command, CMD_FIRMWARE_UPGRADE) == 0) {
|
||
/* 释放固件升级Data子命令中的数据 */
|
||
if (strcmp(message->data.firmwareUpgrade.subCommand, FIRMWARE_SUBCMD_DATA) == 0) {
|
||
if (message->data.firmwareUpgrade.u.data.data != NULL) {
|
||
vPortFree(message->data.firmwareUpgrade.u.data.data);
|
||
message->data.firmwareUpgrade.u.data.data = NULL;
|
||
message->data.firmwareUpgrade.u.data.data_len = 0;
|
||
}
|
||
}
|
||
}
|
||
/* 注意:文件操作中的内存由专门的释放函数处理,不需要在这里释放 */
|
||
}
|
||
|
||
/**
|
||
* @brief 处理故障信息消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_fault_info_message(const tcp_message_t *message)
|
||
{
|
||
tcp_fault_info_response_t response;
|
||
char *response_json = NULL;
|
||
int json_len = 0;
|
||
int result = 0;
|
||
|
||
TCP_PRINT("Received fault info request: faultCode=%s\r\r\n",
|
||
message->data.faultInfo.faultCode);
|
||
|
||
/* 处理故障信息请求 */
|
||
memset(&response, 0, sizeof(response));
|
||
|
||
/* 调用v_get_fault_data函数获取故障数据 */
|
||
tcp_get_system_fault_data(&response);
|
||
|
||
|
||
|
||
/* 动态分配响应JSON缓冲区 */
|
||
response_json = (char *)pvPortMalloc(2048);
|
||
if (response_json == NULL) {
|
||
TCP_PRINT("Failed to allocate memory for response JSON\r\r\n");
|
||
result = -1;
|
||
goto cleanup;
|
||
}
|
||
|
||
/* 生成响应JSON */
|
||
json_len = tcp_generate_fault_info_json(&response, response_json, 2048);
|
||
if (json_len > 0) {
|
||
TCP_PRINT("Fault info response generated (%d bytes)\r\r\n", json_len);
|
||
|
||
/* 发送响应到客户端 */
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("Fault info response sent successfully\r\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send fault info response: %d\r\r\n", send_err);
|
||
result = -1;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate fault info response\r\r\n");
|
||
result = -1;
|
||
}
|
||
|
||
cleanup:
|
||
/* 释放动态分配的内存 */
|
||
if (response.faults != NULL) {
|
||
vPortFree(response.faults);
|
||
}
|
||
if (response_json != NULL) {
|
||
vPortFree(response_json);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成故障信息响应JSON
|
||
* @param response 故障信息响应结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
static int tcp_generate_fault_info_json(const tcp_fault_info_response_t *response, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
cJSON *faults_array = NULL;
|
||
cJSON *fault_item = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
int i;
|
||
|
||
if (buffer == NULL || size == 0 || response == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_FAULT_INFO);
|
||
cJSON_AddNumberToObject(root, "status", 0); /* 成功状态 */
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddNumberToObject(data, "faultCount", response->faultCount);
|
||
|
||
/* 创建故障数组 */
|
||
if (response->faultCount > 0 && response->faults != NULL) {
|
||
faults_array = cJSON_CreateArray();
|
||
if (faults_array == NULL) {
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 添加故障项到数组 */
|
||
for (i = 0; i < response->faultCount; i++) {
|
||
fault_item = cJSON_CreateObject();
|
||
if (fault_item == NULL) {
|
||
cJSON_Delete(faults_array);
|
||
cJSON_Delete(data);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(fault_item, "location", response->faults[i].location);
|
||
cJSON_AddStringToObject(fault_item, "code", response->faults[i].code);
|
||
cJSON_AddStringToObject(fault_item, "time", response->faults[i].time);
|
||
cJSON_AddStringToObject(fault_item, "description", response->faults[i].description);
|
||
|
||
cJSON_AddItemToArray(faults_array, fault_item);
|
||
}
|
||
|
||
cJSON_AddItemToObject(data, "faults", faults_array);
|
||
}
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理历史记录查询/清除消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_history_operations_message(const tcp_message_t *message)
|
||
{
|
||
char *response_json = NULL;
|
||
int json_len = 0;
|
||
int result = 0;
|
||
|
||
uint16_t totalCount = 0;
|
||
uint16_t startIndex = 0;
|
||
uint16_t fetchCount = 0;
|
||
uint16_t wantedCount = 0;
|
||
uint16_t filledCount = 0;
|
||
uint16_t returnedCount = 0;
|
||
uint8_t isLastPacket = 1;
|
||
|
||
uint8_t include_time = 0;
|
||
|
||
const tcp_history_operations_data_t *req = NULL;
|
||
req = &message->data.historyOperations;
|
||
|
||
TCP_PRINT("Received history operations: subCommand=%s, historyType=%s, startIndex=%u, fetchCount=%u, queryId=%u\r\r\n",
|
||
req->subCommand, req->historyType, req->startIndex, req->fetchCount, (unsigned int)req->queryId);
|
||
|
||
/* 清除响应/查询响应最终都需要 JSON 缓冲区 */
|
||
response_json = (char *)pvPortMalloc(2048);
|
||
if (response_json == NULL) {
|
||
TCP_PRINT("Failed to allocate memory for history response JSON\r\r\n");
|
||
return -1;
|
||
}
|
||
|
||
memset(response_json, 0, 2048);
|
||
|
||
/* 子命令:Query */
|
||
if (strcmp(req->subCommand, HISTORY_OP_SUBCMD_QUERY) == 0) {
|
||
tcp_history_query_xfer_t *hx = NULL;
|
||
char (*time_buf)[HISTORY_TIME_STR_SIZE] = NULL;
|
||
char (*content_buf)[HISTORY_CONTENT_STR_SIZE] = NULL;
|
||
|
||
startIndex = req->startIndex;
|
||
fetchCount = req->fetchCount;
|
||
|
||
/* 约 13KB+ 传输缓冲放堆上,避免任务栈溢出导致死机 */
|
||
hx = (tcp_history_query_xfer_t *)pvPortMalloc(sizeof(tcp_history_query_xfer_t));
|
||
if (hx != NULL) {
|
||
memset(hx, 0, sizeof(*hx));
|
||
time_buf = hx->time_buf;
|
||
content_buf = hx->content_buf;
|
||
wantedCount = fetchCount;
|
||
if (wantedCount > HISTORY_QUERY_MAX_RECORDS) {
|
||
wantedCount = HISTORY_QUERY_MAX_RECORDS;
|
||
}
|
||
filledCount = tcp_history_build_records(req->historyType, startIndex, wantedCount,
|
||
time_buf, content_buf, &include_time, &totalCount);
|
||
} else {
|
||
TCP_PRINT("tcp_process_history_operations_message: hx malloc failed (history query)\r\r\n");
|
||
totalCount = tcp_history_get_total_count(req->historyType);
|
||
include_time = (strcmp(req->historyType, "fault") == 0 ||
|
||
strcmp(req->historyType, "charging") == 0) ? 1u : 0u;
|
||
filledCount = 0u;
|
||
}
|
||
|
||
/* 按1024字节JSON长度限制裁剪 returnedCount */
|
||
returnedCount = 0;
|
||
|
||
/* 逐步尝试:从filledCount开始往下裁剪 */
|
||
for (int tryCount = (int)filledCount; tryCount >= 0; --tryCount) {
|
||
uint16_t tmpReturned = (uint16_t)tryCount;
|
||
isLastPacket = ((uint16_t)(startIndex + tmpReturned) >= totalCount) ? 1u : 0u;
|
||
|
||
/* 生成 QueryResponse JSON */
|
||
cJSON *root = cJSON_CreateObject();
|
||
cJSON *data = NULL;
|
||
cJSON *records = NULL;
|
||
char timestamp[32] = {0};
|
||
char *json_str = NULL;
|
||
|
||
if (root == NULL) {
|
||
continue;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
cJSON_Delete(root);
|
||
continue;
|
||
}
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_HISTORY_OPERATIONS);
|
||
cJSON_AddNumberToObject(root, "status", 0);
|
||
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
continue;
|
||
}
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", "QueryResponse");
|
||
cJSON_AddStringToObject(data, "historyType", req->historyType);
|
||
cJSON_AddNumberToObject(data, "queryId", req->queryId);
|
||
cJSON_AddNumberToObject(data, "startIndex", startIndex);
|
||
cJSON_AddNumberToObject(data, "totalCount", totalCount);
|
||
cJSON_AddNumberToObject(data, "returnedCount", tmpReturned);
|
||
cJSON_AddNumberToObject(data, "isLastPacket", isLastPacket);
|
||
|
||
records = cJSON_CreateArray();
|
||
if (records == NULL) {
|
||
cJSON_Delete(root);
|
||
continue;
|
||
}
|
||
cJSON_AddItemToObject(data, "records", records);
|
||
|
||
for (uint16_t i = 0; i < tmpReturned; i++) {
|
||
cJSON *rec = cJSON_CreateObject();
|
||
if (rec == NULL) {
|
||
continue;
|
||
}
|
||
|
||
if (include_time != 0u && time_buf != NULL) {
|
||
cJSON_AddStringToObject(rec, "time", time_buf[i]);
|
||
}
|
||
cJSON_AddStringToObject(rec, "content",
|
||
(content_buf != NULL) ? content_buf[i] : "");
|
||
cJSON_AddItemToArray(records, rec);
|
||
}
|
||
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
continue;
|
||
}
|
||
|
||
json_len = (int)strlen(json_str);
|
||
cJSON_free(json_str);
|
||
|
||
/* 1024字节限制:符合才停止 */
|
||
if (json_len <= 1024) {
|
||
/* 重新生成一次,拷贝到 response_json */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str != NULL) {
|
||
json_len = (int)strlen(json_str);
|
||
if (json_len + 1 <= 2048) {
|
||
strncpy(response_json, json_str, 2047);
|
||
response_json[2047] = '\0';
|
||
returnedCount = tmpReturned;
|
||
}
|
||
cJSON_free(json_str);
|
||
}
|
||
cJSON_Delete(root);
|
||
break;
|
||
}
|
||
|
||
cJSON_Delete(root);
|
||
}
|
||
|
||
/* 若仍未生成合法返回,返回空records也要确保返回 */
|
||
if (returnedCount == 0) {
|
||
/* 生成一个最小 QueryResponse(0条记录) */
|
||
cJSON *root = cJSON_CreateObject();
|
||
cJSON *data = cJSON_CreateObject();
|
||
cJSON *records = cJSON_CreateArray();
|
||
char timestamp[32] = {0};
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) == 0) {
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
} else {
|
||
cJSON_AddStringToObject(root, "timestamp", "0");
|
||
}
|
||
cJSON_AddStringToObject(root, "command", CMD_HISTORY_OPERATIONS);
|
||
cJSON_AddNumberToObject(root, "status", 0);
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", "QueryResponse");
|
||
cJSON_AddStringToObject(data, "historyType", req->historyType);
|
||
cJSON_AddNumberToObject(data, "queryId", req->queryId);
|
||
cJSON_AddNumberToObject(data, "startIndex", startIndex);
|
||
cJSON_AddNumberToObject(data, "totalCount", totalCount);
|
||
cJSON_AddNumberToObject(data, "returnedCount", 0);
|
||
cJSON_AddNumberToObject(data, "isLastPacket", 1);
|
||
cJSON_AddItemToObject(data, "records", records);
|
||
|
||
char *json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str != NULL) {
|
||
json_len = (int)strlen(json_str);
|
||
if (json_len + 1 <= 2048) {
|
||
strncpy(response_json, json_str, 2047);
|
||
response_json[2047] = '\0';
|
||
}
|
||
cJSON_free(json_str);
|
||
}
|
||
|
||
cJSON_Delete(root);
|
||
}
|
||
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, (uint16_t)json_len);
|
||
if (send_err != ERR_OK) {
|
||
TCP_PRINT("Failed to send history query response: %d\r\r\n", send_err);
|
||
result = -1;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate history query response\r\r\n");
|
||
result = -1;
|
||
}
|
||
|
||
if (hx != NULL) {
|
||
vPortFree(hx);
|
||
hx = NULL;
|
||
}
|
||
} else if (strcmp(req->subCommand, HISTORY_OP_SUBCMD_CLEAR) == 0) {
|
||
/* 清除记录 */
|
||
uint32_t status = 0;
|
||
char message[128] = {0};
|
||
|
||
int clearRet = tcp_history_clear_records(req->historyType, message, (uint32_t)sizeof(message));
|
||
status = (clearRet == 0) ? 0u : 1u;
|
||
|
||
/* 生成 ClearResponse JSON */
|
||
cJSON *root = cJSON_CreateObject();
|
||
cJSON *data = NULL;
|
||
char timestamp[32] = {0};
|
||
if (root == NULL) {
|
||
vPortFree(response_json);
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) == 0) {
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
} else {
|
||
cJSON_AddStringToObject(root, "timestamp", "0");
|
||
}
|
||
cJSON_AddStringToObject(root, "command", CMD_HISTORY_OPERATIONS);
|
||
cJSON_AddNumberToObject(root, "status", status);
|
||
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
vPortFree(response_json);
|
||
return -1;
|
||
}
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
cJSON_AddStringToObject(data, "subCommand", "ClearResponse");
|
||
cJSON_AddStringToObject(data, "historyType", req->historyType);
|
||
cJSON_AddNumberToObject(data, "queryId", req->queryId);
|
||
cJSON_AddNumberToObject(data, "status", status);
|
||
cJSON_AddStringToObject(data, "message", message);
|
||
|
||
char *json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str != NULL) {
|
||
json_len = (int)strlen(json_str);
|
||
if (json_len + 1 <= 2048) {
|
||
strncpy(response_json, json_str, 2047);
|
||
response_json[2047] = '\0';
|
||
}
|
||
cJSON_free(json_str);
|
||
}
|
||
|
||
cJSON_Delete(root);
|
||
|
||
if (json_len > 0) {
|
||
err_t send_err = tcp_server_send_json(response_json, (uint16_t)json_len);
|
||
if (send_err != ERR_OK) {
|
||
TCP_PRINT("Failed to send history clear response: %d\r\r\n", send_err);
|
||
result = -1;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate history clear response\r\r\n");
|
||
result = -1;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Unknown history subCommand: %s\r\r\n", req->subCommand);
|
||
result = -1;
|
||
}
|
||
|
||
if (response_json != NULL) {
|
||
vPortFree(response_json);
|
||
response_json = NULL;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理自定义数据消息
|
||
* @param message 消息结构体指针
|
||
* @retval 0成功,-1失败
|
||
*/
|
||
static int tcp_process_custom_data_message(const tcp_message_t *message)
|
||
{
|
||
tcp_custom_data_t response_data;
|
||
char *response_json = NULL;
|
||
int json_len = 0;
|
||
int result = 0;
|
||
|
||
TCP_PRINT("Received custom data: functionContent=%s, functionField=%s, functionParams=%s\r\r\n",
|
||
message->data.customData.functionContent,
|
||
message->data.customData.functionField,
|
||
message->data.customData.functionParams);
|
||
|
||
/* 处理自定义数据请求 */
|
||
memset(&response_data, 0, sizeof(response_data));
|
||
|
||
/* 调用自定义数据处理函数 */
|
||
if (tcp_process_custom_data(&message->data.customData, &response_data) != 0) {
|
||
TCP_PRINT("Failed to process custom data\r\r\n");
|
||
return -1;
|
||
}
|
||
|
||
/* 动态分配响应JSON缓冲区 */
|
||
response_json = (char *)pvPortMalloc(1024);
|
||
if (response_json == NULL) {
|
||
TCP_PRINT("Failed to allocate memory for response JSON\r\r\n");
|
||
result = -1;
|
||
goto cleanup;
|
||
}
|
||
|
||
/* 生成响应JSON */
|
||
json_len = tcp_generate_custom_data_json(&response_data, response_json, 1024);
|
||
if (json_len > 0) {
|
||
TCP_PRINT("Custom data response generated (%d bytes)\r\r\n", json_len);
|
||
|
||
/* 发送响应到客户端 */
|
||
err_t send_err = tcp_server_send_json(response_json, json_len);
|
||
if (send_err == ERR_OK) {
|
||
TCP_PRINT("Custom data response sent successfully\r\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send custom data response: %d\r\r\n", send_err);
|
||
result = -1;
|
||
}
|
||
} else {
|
||
TCP_PRINT("Failed to generate custom data response\r\r\n");
|
||
result = -1;
|
||
}
|
||
|
||
cleanup:
|
||
/* 释放动态分配的内存 */
|
||
if (response_json != NULL) {
|
||
vPortFree(response_json);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @brief 生成自定义数据JSON
|
||
* @param customData 自定义数据结构体指针
|
||
* @param buffer 输出缓冲区
|
||
* @param size 缓冲区大小
|
||
* @retval JSON字符串长度,-1表示失败
|
||
*/
|
||
int tcp_generate_custom_data_json(const tcp_custom_data_t *customData, char *buffer, uint32_t size)
|
||
{
|
||
cJSON *root = NULL;
|
||
cJSON *data = NULL;
|
||
char timestamp[32];
|
||
char *json_str = NULL;
|
||
int json_len = 0;
|
||
|
||
if (buffer == NULL || size == 0 || customData == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
/* 生成时间戳 */
|
||
if (tcp_generate_timestamp(timestamp, sizeof(timestamp)) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 创建JSON对象 */
|
||
root = cJSON_CreateObject();
|
||
if (root == NULL) {
|
||
return -1;
|
||
}
|
||
|
||
cJSON_AddStringToObject(root, "version", "2.0");
|
||
cJSON_AddStringToObject(root, "timestamp", timestamp);
|
||
cJSON_AddStringToObject(root, "command", CMD_CUSTOM_DATA);
|
||
|
||
/* 创建data对象 */
|
||
data = cJSON_CreateObject();
|
||
if (data == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 添加自定义数据字段 */
|
||
cJSON_AddStringToObject(data, "functionContent", customData->functionContent);
|
||
cJSON_AddStringToObject(data, "functionField", customData->functionField);
|
||
cJSON_AddStringToObject(data, "functionParams", customData->functionParams);
|
||
|
||
cJSON_AddItemToObject(root, "data", data);
|
||
|
||
/* 生成JSON字符串 */
|
||
json_str = cJSON_PrintUnformatted(root);
|
||
if (json_str == NULL) {
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
json_len = strlen(json_str);
|
||
if (json_len + 1 > size) {
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
return -1;
|
||
}
|
||
|
||
/* 复制到输出缓冲区 */
|
||
strncpy(buffer, json_str, size);
|
||
buffer[size - 1] = '\0';
|
||
|
||
/* 释放内存 */
|
||
cJSON_free(json_str);
|
||
cJSON_Delete(root);
|
||
|
||
return json_len;
|
||
}
|
||
|
||
|
||
|
||
#endif
|