9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
1541 lines
48 KiB
C
1541 lines
48 KiB
C
/**
|
||
******************************************************************************
|
||
* @file tcp_server.c
|
||
* @brief TCP调试服务器实现
|
||
******************************************************************************
|
||
*/
|
||
|
||
#include "tcp_server.h"
|
||
#include "debug_link.h"
|
||
#include "tcp_protocol.h"
|
||
#include "debug_files.h"
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include "publicdata/public_define.h"
|
||
#include "publicdata/publicdata.h"
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
#include "semphr.h"
|
||
#include "cJSON.h"
|
||
|
||
#if BLE_DEBUG_EN
|
||
#include "ble_link/fc41d_ble.h"
|
||
#endif
|
||
|
||
#if TCP_DEBUG_EN
|
||
|
||
/* TCP服务器配置 */
|
||
#define TCP_LOCAL_PORT TCP_DEBUG_PORT
|
||
#define MAX_CLIENTS TCP_DEBUG_MAX_CLIENTS
|
||
|
||
/* 接收数据缓冲区(用于处理多包/残包) */
|
||
#define TCP_RX_BUF_NORMAL 1024U /* 常态:心跳/参数查询等 */
|
||
#define TCP_RX_BUF_UPGRADE 8192U /* 以太网固件升级拼包 */
|
||
#define TCP_RX_BUF_UPGRADE_BLE 2048U /* BLE:单包 1024B,JSON 约 1.6KB */
|
||
|
||
typedef struct {
|
||
uint8_t *buffer;
|
||
uint32_t cap;
|
||
uint32_t used;
|
||
uint32_t processed;
|
||
} tcp_rx_buffer_t;
|
||
|
||
/* 服务器状态结构体实例 */
|
||
static tcp_server_state_t server_state = {
|
||
.server_pcb = NULL,
|
||
.client_pcb = NULL,
|
||
.is_client_connected = 0,
|
||
.heartbeat_sequence = 0,
|
||
.system_info_sent = 0,
|
||
.tick_counter = 0,
|
||
.heartbeat_last_tick = 0,
|
||
.system_info_last_tick = 0,
|
||
.gun_data_last_tick = 0,
|
||
.last_heartbeat_received_tick = 0
|
||
};
|
||
|
||
/* 接收数据缓冲区(用于多包处理) */
|
||
static tcp_rx_buffer_t rx_buffer;
|
||
static SemaphoreHandle_t tcp_server_mutex = NULL; /* 服务器状态互斥锁 */
|
||
static SemaphoreHandle_t rx_buffer_mutex = NULL; /* 接收缓冲区互斥锁 */
|
||
|
||
/* 消息发送间隔(秒) */
|
||
#define HEARTBEAT_INTERVAL_SEC 10 /* 设备主动心跳(已关闭,仅保留供兼容) */
|
||
#define PERIODIC_REPORT_INTERVAL_SEC 2U /* SystemInfo + 双枪 GunInfo 周期 */
|
||
#define HEARTBEAT_TIMEOUT_SEC 30 /* 客户端心跳超时 30 秒 */
|
||
|
||
#define TCP_MSG_JSON_BUF_SIZE 768U /* GunInfo JSON 较长,预留 768 字节 */
|
||
/** 固件升级时 tcp_server_process 内追加 RX/抽帧轮次 */
|
||
#define TCP_UPGRADE_RX_BURST_PASSES 96U
|
||
|
||
/* 定时判断函数 */
|
||
static uint8_t tcp_should_send_message(uint32_t last_send_tick, uint32_t interval_sec);
|
||
|
||
/* 接收数据缓冲区操作函数(用于多包处理) */
|
||
static void tcp_rx_buffer_init(void);
|
||
static int tcp_rx_buffer_append(const uint8_t *data, uint16_t len);
|
||
static int tcp_rx_buffer_extract_json(char *output, uint32_t output_size, int *out_json_start);
|
||
static void tcp_rx_buffer_rollback_to(uint32_t pos);
|
||
static int s_tcp_json_is_heartbeat(const char *json);
|
||
static int s_tcp_fw_data_b64_incomplete(const char *json, int json_len);
|
||
static void s_tcp_log_rx_cache(const char *when);
|
||
static int s_tcp_diag_rx_trace(void);
|
||
static void tcp_rx_buffer_consume(uint32_t len);
|
||
static void tcp_rx_buffer_reset(void);
|
||
|
||
static int tcp_rx_buffer_set_cap(uint32_t cap)
|
||
{
|
||
uint8_t *new_buf;
|
||
uint32_t keep_used;
|
||
uint32_t keep_processed;
|
||
|
||
if (cap == 0U) {
|
||
return -1;
|
||
}
|
||
if ((rx_buffer.buffer != NULL) && (rx_buffer.cap == cap)) {
|
||
return 0;
|
||
}
|
||
|
||
keep_used = rx_buffer.used;
|
||
keep_processed = rx_buffer.processed;
|
||
|
||
new_buf = (uint8_t *)pvPortMalloc(cap);
|
||
if (new_buf == NULL) {
|
||
TCP_PRINT("RX buffer alloc failed (%u bytes)\r\n", (unsigned)cap);
|
||
return -1;
|
||
}
|
||
|
||
if ((rx_buffer.buffer != NULL) && (keep_used > 0U)) {
|
||
uint32_t copy_len = keep_used;
|
||
if (copy_len > cap) {
|
||
copy_len = cap;
|
||
keep_processed = 0U;
|
||
}
|
||
memcpy(new_buf, rx_buffer.buffer, copy_len);
|
||
keep_used = copy_len;
|
||
}
|
||
|
||
if (rx_buffer.buffer != NULL) {
|
||
vPortFree(rx_buffer.buffer);
|
||
}
|
||
rx_buffer.buffer = new_buf;
|
||
rx_buffer.cap = cap;
|
||
rx_buffer.used = keep_used;
|
||
rx_buffer.processed = keep_processed;
|
||
TCP_PRINT("RX buffer cap=%u bytes (used=%u)\r\n", (unsigned)cap, (unsigned)keep_used);
|
||
return 0;
|
||
}
|
||
|
||
static void tcp_rx_buffer_free(void)
|
||
{
|
||
if (rx_buffer.buffer != NULL) {
|
||
vPortFree(rx_buffer.buffer);
|
||
rx_buffer.buffer = NULL;
|
||
}
|
||
rx_buffer.cap = 0U;
|
||
rx_buffer.used = 0U;
|
||
rx_buffer.processed = 0U;
|
||
}
|
||
|
||
int tcp_server_rx_upgrade_begin(void)
|
||
{
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
if (comm_link_ble_rx_upgrade_begin() != 0) {
|
||
return -1;
|
||
}
|
||
return tcp_rx_buffer_set_cap(TCP_RX_BUF_UPGRADE_BLE);
|
||
}
|
||
#endif
|
||
return tcp_rx_buffer_set_cap(TCP_RX_BUF_UPGRADE);
|
||
}
|
||
|
||
int tcp_server_rx_upgrade_end(void)
|
||
{
|
||
tcp_rx_buffer_reset();
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
(void)comm_link_ble_rx_upgrade_end();
|
||
}
|
||
#endif
|
||
return tcp_rx_buffer_set_cap(TCP_RX_BUF_NORMAL);
|
||
}
|
||
|
||
void tcp_server_rx_clear_pending(void)
|
||
{
|
||
tcp_rx_buffer_reset();
|
||
}
|
||
|
||
/* 丢弃 processed 之前无 '{' 的残留字节(BLE 分片/心跳尾包) */
|
||
static int s_tcp_rx_has_partial_json(void)
|
||
{
|
||
int brace_count = 0;
|
||
int in_string = 0;
|
||
int escape_next = 0;
|
||
int partial = 0;
|
||
|
||
if (rx_buffer.used <= rx_buffer.processed) {
|
||
return 0;
|
||
}
|
||
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
for (uint32_t i = rx_buffer.processed; i < rx_buffer.used; i++) {
|
||
char c = rx_buffer.buffer[i];
|
||
|
||
if (escape_next) {
|
||
escape_next = 0;
|
||
continue;
|
||
}
|
||
if (c == '"' && (i == rx_buffer.processed || rx_buffer.buffer[i - 1U] != '\\')) {
|
||
in_string = !in_string;
|
||
continue;
|
||
}
|
||
if (c == '\\' && in_string) {
|
||
escape_next = 1;
|
||
continue;
|
||
}
|
||
if (!in_string) {
|
||
if (c == '{') {
|
||
brace_count++;
|
||
} else if (c == '}') {
|
||
brace_count--;
|
||
}
|
||
}
|
||
}
|
||
|
||
partial = (brace_count > 0) ? 1 : 0;
|
||
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
|
||
return partial;
|
||
}
|
||
|
||
static int s_tcp_diag_rx_trace(void)
|
||
{
|
||
return (system_filetransfer_is_active() != 0) ? 1 : 0;
|
||
}
|
||
|
||
static void s_tcp_log_rx_cache_locked(const char *when)
|
||
{
|
||
uint32_t pending;
|
||
|
||
pending = (rx_buffer.used > rx_buffer.processed) ?
|
||
(rx_buffer.used - rx_buffer.processed) : 0U;
|
||
tcp_firmware_upgrade_log_meta(when,
|
||
rx_buffer.used,
|
||
rx_buffer.processed,
|
||
rx_buffer.cap,
|
||
pending);
|
||
if (pending > 0U) {
|
||
tcp_firmware_upgrade_log_buf("TCP-CACHE-DATA",
|
||
(const uint8_t *)(rx_buffer.buffer + rx_buffer.processed),
|
||
pending);
|
||
}
|
||
}
|
||
|
||
static void s_tcp_log_rx_cache(const char *when)
|
||
{
|
||
if (s_tcp_diag_rx_trace() == 0) {
|
||
return;
|
||
}
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
s_tcp_log_rx_cache_locked(when);
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
}
|
||
|
||
static void tcp_rx_buffer_skip_leading_garbage(void)
|
||
{
|
||
uint32_t i;
|
||
int first_brace = -1;
|
||
|
||
if (rx_buffer.used <= rx_buffer.processed) {
|
||
return;
|
||
}
|
||
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
for (i = rx_buffer.processed; i < rx_buffer.used; i++) {
|
||
if (rx_buffer.buffer[i] == '{') {
|
||
first_brace = (int)i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (first_brace > (int)rx_buffer.processed) {
|
||
TCP_PRINT("Skip %u bytes before JSON '{'\r\n",
|
||
(unsigned)((uint32_t)first_brace - rx_buffer.processed));
|
||
rx_buffer.processed = (uint32_t)first_brace;
|
||
}
|
||
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
}
|
||
|
||
/* 接收缓冲区处理函数 */
|
||
static void tcp_server_process_rx_buffer(void);
|
||
|
||
/* Socket API相关函数 */
|
||
static int tcp_server_socket_receive_data(void)
|
||
{
|
||
uint8_t temp_buffer[1024];
|
||
int received = 0;
|
||
int total = 0;
|
||
int link_error = 0;
|
||
|
||
for (;;) {
|
||
received = comm_link_receive_data(temp_buffer, sizeof(temp_buffer));
|
||
if (received < 0) {
|
||
link_error = received;
|
||
break;
|
||
}
|
||
if (received == 0) {
|
||
break;
|
||
}
|
||
|
||
if (tcp_rx_buffer_append(temp_buffer, (uint16_t)received) != 0) {
|
||
TCP_PRINT("Failed to append data to RX buffer from socket\r\n");
|
||
} else {
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
if (system_filetransfer_is_active() != 0) {
|
||
system_filetransfer_touch_activity_on_rx();
|
||
}
|
||
tcp_firmware_upgrade_log_io("RX-LINK", (const char *)temp_buffer, (uint32_t)received);
|
||
}
|
||
TCP_PRINT("Added %d bytes to RX buffer from socket\r\n", received);
|
||
}
|
||
total += received;
|
||
if (s_tcp_diag_rx_trace() == 0) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (link_error < 0) {
|
||
TCP_PRINT("Socket receive error or connection closed: %d\r\n", link_error);
|
||
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
server_state.is_client_connected = 0;
|
||
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
|
||
tcp_rx_buffer_reset();
|
||
return link_error;
|
||
}
|
||
|
||
return total;
|
||
}
|
||
|
||
void upgrade_erase_yield(void)
|
||
{
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
comm_link_ble_process();
|
||
}
|
||
#endif
|
||
if (server_state.is_client_connected) {
|
||
uint8_t pass;
|
||
|
||
for (pass = 0U; pass < 4U; pass++) {
|
||
if (tcp_server_socket_receive_data() <= 0) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void tcp_server_link_rx_drain(void)
|
||
{
|
||
uint8_t pass;
|
||
|
||
if (!server_state.is_client_connected) {
|
||
return;
|
||
}
|
||
|
||
for (pass = 0U; pass < 32U; pass++) {
|
||
int got = tcp_server_socket_receive_data();
|
||
if (got <= 0) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 发送数据到客户端(Socket API版本)
|
||
* @param data 要发送的数据
|
||
* @param len 数据长度
|
||
* @retval 发送的字节数,-1表示错误
|
||
*/
|
||
static int tcp_server_send_data_socket(const void *data, uint16_t len)
|
||
{
|
||
if (data == NULL || len == 0) {
|
||
return -1;
|
||
}
|
||
|
||
#if TCP_DEBUG_EN
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
tcp_firmware_upgrade_log_io("TX-LINK", (const char *)data, (uint32_t)len);
|
||
}
|
||
#endif
|
||
|
||
/* 打印原始发送数据 */
|
||
TCP_PRINT_RAW_SEND((const uint8_t *)data, len);
|
||
|
||
/* 使用Socket API发送数据 */
|
||
return comm_link_send_data((const uint8_t *)data, len);
|
||
}
|
||
|
||
/**
|
||
* @brief 判断是否应该发送消息(基于时间间隔)
|
||
* @param last_send_tick 上次发送时的tick
|
||
* @param interval_sec 发送间隔(秒)
|
||
* @retval 1应该发送,0不应该发送
|
||
*/
|
||
static uint8_t tcp_should_send_message(uint32_t last_send_tick, uint32_t interval_sec)
|
||
{
|
||
uint32_t elapsed = server_state.tick_counter - last_send_tick;
|
||
return (elapsed >= interval_sec) ? 1 : 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化接收数据缓冲区
|
||
*/
|
||
static void tcp_rx_buffer_init(void)
|
||
{
|
||
rx_buffer_mutex = xSemaphoreCreateMutex();
|
||
if (rx_buffer_mutex == NULL) {
|
||
TCP_PRINT("Failed to create RX buffer mutex\r\n");
|
||
return;
|
||
}
|
||
|
||
rx_buffer.buffer = NULL;
|
||
rx_buffer.cap = 0U;
|
||
rx_buffer.used = 0U;
|
||
rx_buffer.processed = 0U;
|
||
if (tcp_rx_buffer_set_cap(TCP_RX_BUF_NORMAL) != 0) {
|
||
TCP_PRINT("RX buffer normal alloc failed\r\n");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 重置接收数据缓冲区
|
||
*/
|
||
static void tcp_rx_buffer_reset(void)
|
||
{
|
||
/* 获取接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
rx_buffer.used = 0;
|
||
rx_buffer.processed = 0;
|
||
|
||
/* 释放接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 将数据追加到接收缓冲区
|
||
* @param data 数据指针
|
||
* @param len 数据长度
|
||
* @retval 0成功,-1失败(缓冲区满)
|
||
*/
|
||
static int tcp_rx_buffer_append(const uint8_t *data, uint16_t len)
|
||
{
|
||
int result = -1;
|
||
|
||
if (data == NULL || len == 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 获取接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
/* 检查缓冲区是否有足够空间 */
|
||
if (rx_buffer.buffer == NULL || rx_buffer.cap == 0U) {
|
||
result = -1;
|
||
} else if (rx_buffer.used + len > rx_buffer.cap) {
|
||
TCP_PRINT("RX buffer full! Used: %u, Adding: %u, Max: %u\r\n",
|
||
rx_buffer.used, len, rx_buffer.cap);
|
||
result = -1;
|
||
} else {
|
||
#if TCP_DEBUG_EN
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
if ((len >= 12U) && (data[0] == (uint8_t)'{')) {
|
||
uint16_t peek = (len > 128U) ? 128U : len;
|
||
char head[129];
|
||
|
||
memcpy(head, data, peek);
|
||
head[peek] = '\0';
|
||
if ((strstr(head, CMD_FIRMWARE_UPGRADE) != NULL) &&
|
||
(s_tcp_rx_has_partial_json() != 0)) {
|
||
TCP_PRINT("Upgrade host retry: drop partial JSON (%u bytes)\r\n",
|
||
(unsigned)(rx_buffer.used - rx_buffer.processed));
|
||
rx_buffer.used = rx_buffer.processed;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
/* 复制数据到缓冲区 */
|
||
memcpy(rx_buffer.buffer + rx_buffer.used, data, len);
|
||
rx_buffer.used += len;
|
||
|
||
TCP_PRINT("Added %u bytes to RX buffer, total: %u\r\n", len, rx_buffer.used);
|
||
result = 0;
|
||
#if TCP_DEBUG_EN
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
s_tcp_log_rx_cache_locked("TCP-after-append");
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/* 释放接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @brief 从缓冲区提取完整的JSON消息
|
||
* @param output 输出缓冲区
|
||
* @param output_size 输出缓冲区大小
|
||
* @param out_json_start 可选,返回本条 JSON 在缓冲中的起始下标(用于半包回退)
|
||
* @retval JSON消息长度,0表示没有完整消息,-1表示错误
|
||
*/
|
||
static int tcp_rx_buffer_extract_json(char *output, uint32_t output_size, int *out_json_start)
|
||
{
|
||
int brace_count = 0;
|
||
int json_start = -1;
|
||
int json_end = -1;
|
||
int in_string = 0;
|
||
int escape_next = 0;
|
||
int i;
|
||
int result = 0;
|
||
|
||
if (output == NULL || output_size == 0) {
|
||
return -1;
|
||
}
|
||
|
||
/* 获取接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
/* 查找完整的JSON消息(通过括号匹配,忽略字符串内的括号) */
|
||
for (i = rx_buffer.processed; i < rx_buffer.used; i++) {
|
||
char c = rx_buffer.buffer[i];
|
||
|
||
/* 处理转义字符 */
|
||
if (escape_next) {
|
||
escape_next = 0;
|
||
continue;
|
||
}
|
||
|
||
/* 处理字符串开始/结束 */
|
||
if (c == '"' && (i == rx_buffer.processed || rx_buffer.buffer[i-1] != '\\')) {
|
||
in_string = !in_string;
|
||
continue;
|
||
}
|
||
|
||
/* 处理转义字符标记 */
|
||
if (c == '\\' && in_string) {
|
||
escape_next = 1;
|
||
continue;
|
||
}
|
||
|
||
/* 只有在不在字符串内时才计数括号 */
|
||
if (!in_string) {
|
||
if (c == '{') {
|
||
if (brace_count == 0) {
|
||
json_start = i; /* 记录JSON开始位置 */
|
||
}
|
||
brace_count++;
|
||
} else if (c == '}') {
|
||
brace_count--;
|
||
|
||
if (brace_count == 0 && json_start != -1) {
|
||
json_end = i; /* 记录JSON结束位置 */
|
||
break;
|
||
} else if (brace_count < 0) {
|
||
/* 括号不匹配,重置状态 */
|
||
brace_count = 0;
|
||
json_start = -1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 检查是否找到完整的JSON消息 */
|
||
if (json_start != -1 && json_end != -1) {
|
||
int json_len = json_end - json_start + 1;
|
||
|
||
/* 检查输出缓冲区是否足够 */
|
||
if (json_len >= output_size) {
|
||
TCP_PRINT("JSON too large for output buffer: %d >= %u\r\n",
|
||
json_len, output_size);
|
||
result = -1;
|
||
} else {
|
||
/* 复制JSON消息到输出缓冲区 */
|
||
memcpy(output, rx_buffer.buffer + json_start, json_len);
|
||
output[json_len] = '\0';
|
||
|
||
if (out_json_start != NULL) {
|
||
*out_json_start = json_start;
|
||
}
|
||
|
||
/* 更新已处理位置 */
|
||
rx_buffer.processed = (uint32_t)(json_end + 1);
|
||
|
||
TCP_PRINT("Extracted JSON message (%d bytes)\r\n", json_len);
|
||
|
||
result = json_len;
|
||
}
|
||
} else {
|
||
/* 没有找到完整的JSON消息 */
|
||
if (rx_buffer.used - rx_buffer.processed > 0) {
|
||
TCP_PRINT("No complete JSON found. Buffer: remaining=%u bytes\r\n",
|
||
rx_buffer.used - rx_buffer.processed);
|
||
|
||
/* 调试:打印缓冲区的前200个字符 */
|
||
uint32_t remaining = rx_buffer.used - rx_buffer.processed;
|
||
if (remaining > 0) {
|
||
char debug_buf[256];
|
||
uint32_t copy_len = (remaining < 200) ? remaining : 200;
|
||
memcpy(debug_buf, rx_buffer.buffer + rx_buffer.processed, copy_len);
|
||
debug_buf[copy_len] = '\0';
|
||
TCP_PRINT("Buffer content (first %u bytes): %s\r\n", copy_len, debug_buf);
|
||
}
|
||
|
||
/* 检查是否有可能是JSON消息的一部分(但没有开头的'{') */
|
||
/* 这种情况可能发生在JSON消息被TCP分割时 */
|
||
if (json_start == -1 && json_end == -1) {
|
||
/* 检查缓冲区中是否有JSON格式的字符 */
|
||
int has_json_chars = 0;
|
||
for (uint32_t j = rx_buffer.processed; j < rx_buffer.used; j++) {
|
||
char c = rx_buffer.buffer[j];
|
||
if (c == '"' || c == ':' || c == ',' || c == '[' || c == ']' ||
|
||
(c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
|
||
(c >= 'A' && c <= 'Z') || c == '.' || c == '-' || c == '+' || c == '=') {
|
||
has_json_chars = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (has_json_chars) {
|
||
TCP_PRINT("Buffer contains JSON-like data but no complete JSON message found\r\n");
|
||
TCP_PRINT("This may be a partial JSON message (split by TCP)\r\n");
|
||
}
|
||
}
|
||
}
|
||
result = 0;
|
||
}
|
||
|
||
/* 释放接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
static void tcp_rx_buffer_rollback_to(uint32_t pos)
|
||
{
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
if (pos <= rx_buffer.used) {
|
||
rx_buffer.processed = pos;
|
||
}
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
}
|
||
|
||
static int s_tcp_json_is_heartbeat(const char *json)
|
||
{
|
||
if (json == NULL) {
|
||
return 0;
|
||
}
|
||
return (strstr(json, "\"command\":\"Heartbeat\"") != NULL) ? 1 : 0;
|
||
}
|
||
|
||
static int s_tcp_fw_data_b64_incomplete(const char *json, int json_len)
|
||
{
|
||
const char *subcmd;
|
||
const char *p;
|
||
const char *end;
|
||
const char *pi;
|
||
uint32_t b64_len;
|
||
uint32_t pkt = 0U;
|
||
uint32_t expect = 0U;
|
||
uint32_t min_b64;
|
||
const char *b64_field = NULL;
|
||
|
||
if ((json == NULL) || (json_len <= 0)) {
|
||
return 0;
|
||
}
|
||
if (strstr(json, CMD_FIRMWARE_UPGRADE) == NULL) {
|
||
return 0;
|
||
}
|
||
subcmd = strstr(json, "\"subCommand\":\"Data\"");
|
||
if (subcmd == NULL) {
|
||
subcmd = strstr(json, "\"subCommand\": \"Data\"");
|
||
}
|
||
if (subcmd == NULL) {
|
||
return 0;
|
||
}
|
||
|
||
/* 在 data 对象内查找值为字符串的 "data" 字段(Base64 载荷,非外层 "data":{) */
|
||
p = json;
|
||
while ((p = strstr(p, "\"data\"")) != NULL) {
|
||
const char *col;
|
||
p += 6;
|
||
col = strchr(p, ':');
|
||
if (col == NULL) {
|
||
break;
|
||
}
|
||
col++;
|
||
while ((col < json + json_len) && (*col == ' ' || *col == '\t')) {
|
||
col++;
|
||
}
|
||
if (*col == '"') {
|
||
b64_field = col + 1;
|
||
break;
|
||
}
|
||
}
|
||
if (b64_field == NULL) {
|
||
return 1;
|
||
}
|
||
|
||
p = b64_field;
|
||
end = p;
|
||
while (end < json + json_len) {
|
||
if (*end == '"') {
|
||
break;
|
||
}
|
||
if ((*end == '\\') && (end + 1 < json + json_len)) {
|
||
end += 2;
|
||
} else {
|
||
end++;
|
||
}
|
||
}
|
||
if (*end != '"') {
|
||
return 1;
|
||
}
|
||
b64_len = (uint32_t)(end - p);
|
||
|
||
pi = strstr(json, "\"packetIndex\"");
|
||
if (pi != NULL) {
|
||
(void)sscanf(pi, "\"packetIndex\":%u", &pkt);
|
||
}
|
||
if (system_filetransfer_get_expected_packet_bytes(pkt, &expect) != 0 || expect == 0U) {
|
||
return 0;
|
||
}
|
||
min_b64 = ((expect + 2U) / 3U) * 4U;
|
||
return (b64_len < min_b64) ? 1 : 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 消费已处理的数据(移动未处理数据到缓冲区开头)
|
||
* @param len 要消费的长度
|
||
*/
|
||
static void tcp_rx_buffer_consume(uint32_t len)
|
||
{
|
||
if (len == 0 || len > rx_buffer.processed) {
|
||
return;
|
||
}
|
||
|
||
/* 获取接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
/* 移动未处理数据到缓冲区开头 */
|
||
uint32_t remaining = rx_buffer.used - rx_buffer.processed;
|
||
if (remaining > 0) {
|
||
memmove(rx_buffer.buffer,
|
||
rx_buffer.buffer + rx_buffer.processed,
|
||
remaining);
|
||
}
|
||
|
||
/* 更新缓冲区状态 */
|
||
rx_buffer.used = remaining;
|
||
rx_buffer.processed = 0;
|
||
|
||
TCP_PRINT("Consumed %u bytes from RX buffer, remaining: %u\r\n",
|
||
len, rx_buffer.used);
|
||
|
||
/* 如果缓冲区为空,重置状态 */
|
||
if (rx_buffer.used == 0) {
|
||
TCP_PRINT("RX buffer is empty, ready for new data\r\n");
|
||
}
|
||
|
||
/* 释放接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 启动TCP服务器(Socket API版本)
|
||
* @retval err_t 错误码
|
||
*/
|
||
err_t tcp_server_start(void)
|
||
{
|
||
int result;
|
||
cJSON_Hooks hooks;
|
||
|
||
/* 初始化cJSON使用FreeRTOS内存分配器 */
|
||
hooks.malloc_fn = pvPortMalloc;
|
||
hooks.free_fn = vPortFree;
|
||
cJSON_InitHooks(&hooks);
|
||
|
||
/* 创建服务器状态互斥锁 */
|
||
tcp_server_mutex = xSemaphoreCreateMutex();
|
||
if (tcp_server_mutex == NULL) {
|
||
TCP_PRINT("Failed to create server mutex\r\n");
|
||
return ERR_MEM;
|
||
}
|
||
|
||
/* 初始化接收缓冲区(内部会创建接收缓冲区互斥锁) */
|
||
tcp_rx_buffer_init();
|
||
|
||
system_filetransfer_init();
|
||
|
||
/* 检查接收缓冲区互斥锁是否创建成功 */
|
||
if (rx_buffer_mutex == NULL) {
|
||
TCP_PRINT("Failed to create RX buffer mutex\r\n");
|
||
vSemaphoreDelete(tcp_server_mutex);
|
||
tcp_server_mutex = NULL;
|
||
return ERR_MEM;
|
||
}
|
||
|
||
/* 使用Socket API初始化TCP服务器 */
|
||
result = comm_link_start();
|
||
if (result != 0) {
|
||
TCP_PRINT("Failed to initialize socket server: %d\r\n", result);
|
||
vSemaphoreDelete(rx_buffer_mutex);
|
||
rx_buffer_mutex = NULL;
|
||
vSemaphoreDelete(tcp_server_mutex);
|
||
tcp_server_mutex = NULL;
|
||
return ERR_MEM;
|
||
}
|
||
|
||
/* 获取互斥锁保护状态变量 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
/* 重置服务器状态 */
|
||
server_state.system_info_sent = 0;
|
||
server_state.heartbeat_last_tick = 0;
|
||
server_state.system_info_last_tick = 0;
|
||
server_state.gun_data_last_tick = 0;
|
||
server_state.last_heartbeat_received_tick = 0;
|
||
server_state.heartbeat_sequence = 0;
|
||
server_state.is_client_connected = 0;
|
||
server_state.client_pcb = NULL;
|
||
server_state.server_pcb = NULL;
|
||
|
||
/* 释放互斥锁 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
|
||
if (comm_link_get_type() == COMM_LINK_TCP) {
|
||
TCP_PRINT("Debug server started, link=TCP port=%d\r\n", TCP_LOCAL_PORT);
|
||
} else {
|
||
TCP_PRINT("Debug server started, link=BLE (FC41D)\r\n");
|
||
}
|
||
return ERR_OK;
|
||
}
|
||
|
||
/**
|
||
* @brief 停止TCP服务器
|
||
*/
|
||
void tcp_server_stop(void)
|
||
{
|
||
/* 获取互斥锁保护状态变量 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
/* 关闭客户端连接(使用Socket API) */
|
||
comm_link_close_client();
|
||
comm_link_stop();
|
||
|
||
/* 重置协议相关状态 */
|
||
server_state.system_info_sent = 0;
|
||
server_state.heartbeat_last_tick = 0;
|
||
server_state.system_info_last_tick = 0;
|
||
server_state.gun_data_last_tick = 0;
|
||
server_state.last_heartbeat_received_tick = 0;
|
||
server_state.heartbeat_sequence = 0;
|
||
server_state.is_client_connected = 0;
|
||
server_state.client_pcb = NULL;
|
||
server_state.server_pcb = NULL;
|
||
|
||
/* 释放互斥锁 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
|
||
/* 删除服务器状态互斥锁 */
|
||
if (tcp_server_mutex != NULL) {
|
||
vSemaphoreDelete(tcp_server_mutex);
|
||
tcp_server_mutex = NULL;
|
||
}
|
||
|
||
/* 删除接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
vSemaphoreDelete(rx_buffer_mutex);
|
||
rx_buffer_mutex = NULL;
|
||
}
|
||
|
||
/* 重置接收缓冲区 */
|
||
tcp_rx_buffer_reset();
|
||
|
||
TCP_PRINT("Server stopped (Socket API)\r\n");
|
||
}
|
||
|
||
/**
|
||
* @brief 发送指定类型的消息给客户端(Socket API版本)
|
||
* @param msg_type 消息类型(TCP_MSG_HEARTBEAT或TCP_MSG_SYSTEM_INFO)
|
||
*/
|
||
void tcp_server_send_message(tcp_msg_type_t msg_type)
|
||
{
|
||
char json_buffer[TCP_MSG_JSON_BUF_SIZE];
|
||
int json_len;
|
||
int sent;
|
||
|
||
if (system_filetransfer_is_active() != 0) {
|
||
return;
|
||
}
|
||
|
||
/* 检查客户端是否连接(使用Socket API) */
|
||
if (!comm_link_is_client_connected()) {
|
||
return;
|
||
}
|
||
|
||
switch (msg_type) {
|
||
case TCP_MSG_HEARTBEAT: {
|
||
/* 生成心跳JSON */
|
||
json_len = tcp_generate_heartbeat_json(server_state.heartbeat_sequence, "device", json_buffer, sizeof(json_buffer));
|
||
if (json_len <= 0) {
|
||
TCP_PRINT("Failed to generate heartbeat JSON\r\n");
|
||
return;
|
||
}
|
||
|
||
/* 发送JSON数据(使用Socket API) */
|
||
sent = tcp_server_send_data_socket(json_buffer, json_len);
|
||
if (sent > 0) {
|
||
server_state.heartbeat_sequence++; /* 序列号递增 */
|
||
TCP_PRINT("Sent heartbeat (seq=%u)\r\n", server_state.heartbeat_sequence - 1);
|
||
} else {
|
||
TCP_PRINT("Failed to send heartbeat: %d\r\n", sent);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case TCP_MSG_SYSTEM_INFO: {
|
||
tcp_system_info_data_t system_info;
|
||
|
||
/* 获取默认系统信息 */
|
||
tcp_get_default_system_info(&system_info);
|
||
|
||
/* 生成系统信息JSON */
|
||
json_len = tcp_generate_system_info_json(&system_info, json_buffer, sizeof(json_buffer));
|
||
if (json_len <= 0) {
|
||
TCP_PRINT("Failed to generate system info JSON\r\n");
|
||
return;
|
||
}
|
||
|
||
/* 发送JSON数据(使用Socket API) */
|
||
sent = tcp_server_send_data_socket(json_buffer, json_len);
|
||
if (sent > 0) {
|
||
TCP_PRINT("Sent system info\r\n");
|
||
} else {
|
||
TCP_PRINT("Failed to send system info: %d\r\n", sent);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case TCP_MSG_GUN_DATA: {
|
||
/* 发送各枪实时数据 */
|
||
for (uint8_t gun_num = 1; gun_num <= (uint8_t)GUN_MAX_CNT; gun_num++) {
|
||
tcp_gun_data_t gun_data;
|
||
|
||
tcp_get_default_gun_data(&gun_data, gun_num);
|
||
|
||
json_len = tcp_generate_gun_data_json(&gun_data, json_buffer, sizeof(json_buffer));
|
||
if (json_len <= 0) {
|
||
TCP_PRINT("Failed to generate gun data JSON for gun %u\r\n", (unsigned)gun_num);
|
||
#if BLE_DEBUG_EN
|
||
BT_PRINT("GunInfo JSON fail gun=%u\r\n", (unsigned)gun_num);
|
||
#endif
|
||
continue;
|
||
}
|
||
|
||
sent = tcp_server_send_data_socket(json_buffer, (uint16_t)json_len);
|
||
if (sent > 0) {
|
||
TCP_PRINT("Sent gun data for gun %u\r\n", (unsigned)gun_num);
|
||
} else {
|
||
TCP_PRINT("Failed to send gun data for gun %u: %d\r\n", (unsigned)gun_num, sent);
|
||
#if BLE_DEBUG_EN
|
||
BT_PRINT("GunInfo send fail gun=%u ret=%d\r\n", (unsigned)gun_num, sent);
|
||
#endif
|
||
}
|
||
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
vTaskDelay(pdMS_TO_TICKS(80));
|
||
} else
|
||
#endif
|
||
{
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
default:
|
||
TCP_PRINT("Unknown message type: %d\r\n", msg_type);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 发送JSON数据给客户端(Socket API版本)
|
||
* @param json_data JSON字符串
|
||
* @param len 数据长度
|
||
* @retval err_t 错误码
|
||
*/
|
||
err_t tcp_server_send_json(const char *json_data, uint16_t len)
|
||
{
|
||
int sent;
|
||
|
||
if (json_data == NULL || len == 0) {
|
||
return ERR_ARG;
|
||
}
|
||
|
||
/* 检查客户端是否连接(使用Socket API) */
|
||
if (!comm_link_is_client_connected()) {
|
||
TCP_PRINT("Cannot send JSON: no client connected\r\n");
|
||
return ERR_CONN;
|
||
}
|
||
|
||
/* 发送JSON数据(使用Socket API) */
|
||
sent = tcp_server_send_data_socket(json_data, len);
|
||
if (sent > 0) {
|
||
#if BLE_DEBUG_EN
|
||
if (!COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
(void)tcp_server_send_data_socket("\r\n", 2);
|
||
TCP_PRINT("Sent JSON data (%u bytes) + CRLF\r\n", len);
|
||
} else {
|
||
TCP_PRINT("Sent JSON data (%u bytes)\r\n", len);
|
||
}
|
||
#else
|
||
(void)tcp_server_send_data_socket("\r\n", 2);
|
||
TCP_PRINT("Sent JSON data (%u bytes) + CRLF\r\n", len);
|
||
#endif
|
||
return ERR_OK;
|
||
} else {
|
||
TCP_PRINT("Failed to send JSON data: %d\r\n", sent);
|
||
return ERR_IF;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 处理接收缓冲区中的数据(提取并处理完整的JSON消息)
|
||
*/
|
||
static void tcp_server_process_rx_buffer(void)
|
||
{
|
||
char *json_buffer = NULL; /* 动态分配缓冲区以处理JSON消息 */
|
||
int json_len;
|
||
int processed_any = 0;
|
||
int has_partial_json = 0;
|
||
|
||
/* 动态分配JSON缓冲区 */
|
||
json_buffer = (char *)pvPortMalloc(rx_buffer.cap > 0U ? rx_buffer.cap : TCP_RX_BUF_NORMAL);
|
||
if (json_buffer == NULL) {
|
||
TCP_PRINT("Failed to allocate JSON buffer (%u bytes)\r\n",
|
||
(unsigned)(rx_buffer.cap > 0U ? rx_buffer.cap : TCP_RX_BUF_NORMAL));
|
||
return;
|
||
}
|
||
|
||
/* 检查是否有部分JSON消息(有'{'但没有匹配的'}',或者有'}'但没有匹配的'{') */
|
||
if (rx_buffer.used > rx_buffer.processed) {
|
||
int brace_count = 0;
|
||
int in_string = 0;
|
||
int escape_next = 0;
|
||
int has_open_brace = 0;
|
||
int has_close_brace = 0;
|
||
|
||
for (uint32_t i = rx_buffer.processed; i < rx_buffer.used; i++) {
|
||
char c = rx_buffer.buffer[i];
|
||
|
||
/* 处理转义字符 */
|
||
if (escape_next) {
|
||
escape_next = 0;
|
||
continue;
|
||
}
|
||
|
||
/* 处理字符串开始/结束 */
|
||
if (c == '"' && (i == rx_buffer.processed || rx_buffer.buffer[i-1] != '\\')) {
|
||
in_string = !in_string;
|
||
continue;
|
||
}
|
||
|
||
/* 处理转义字符标记 */
|
||
if (c == '\\' && in_string) {
|
||
escape_next = 1;
|
||
continue;
|
||
}
|
||
|
||
/* 只有在不在字符串内时才计数括号 */
|
||
if (!in_string) {
|
||
if (c == '{') {
|
||
brace_count++;
|
||
has_open_brace = 1;
|
||
} else if (c == '}') {
|
||
brace_count--;
|
||
has_close_brace = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 如果有未匹配的'{',说明有部分JSON消息(等待更多数据) */
|
||
if (brace_count > 0) {
|
||
has_partial_json = 1;
|
||
TCP_PRINT("Partial JSON detected in buffer (unmatched braces: %d)\r\n", brace_count);
|
||
}
|
||
/* 如果只有'}'没有'{',可能是JSON消息被分割,开头部分在之前的数据包中 */
|
||
else if (has_close_brace && !has_open_brace) {
|
||
has_partial_json = 1;
|
||
TCP_PRINT("Partial JSON detected (only close brace found, waiting for more data)\r\n");
|
||
}
|
||
/* 如果缓冲区中有数据但没有括号,可能是JSON消息的一部分(如字符串中间) */
|
||
else if (rx_buffer.used - rx_buffer.processed > 0 && !has_open_brace && !has_close_brace) {
|
||
/* 检查缓冲区中是否有JSON格式的字符(如引号、冒号等) */
|
||
int has_json_chars = 0;
|
||
for (uint32_t i = rx_buffer.processed; i < rx_buffer.used; i++) {
|
||
char c = rx_buffer.buffer[i];
|
||
if (c == '"' || c == ':' || c == ',' || c == '[' || c == ']') {
|
||
has_json_chars = 1;
|
||
break;
|
||
}
|
||
}
|
||
if (has_json_chars) {
|
||
has_partial_json = 1;
|
||
TCP_PRINT("Partial JSON detected (JSON characters found, waiting for more data)\r\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 循环提取并处理所有完整的JSON消息 */
|
||
while (1) {
|
||
int json_start_pos = -1;
|
||
|
||
json_len = tcp_rx_buffer_extract_json(json_buffer,
|
||
rx_buffer.cap > 0U ? rx_buffer.cap : TCP_RX_BUF_NORMAL,
|
||
&json_start_pos);
|
||
|
||
if (json_len > 0) {
|
||
if (system_filetransfer_is_active() != 0) {
|
||
if (s_tcp_json_is_heartbeat(json_buffer) != 0) {
|
||
processed_any = 1;
|
||
continue;
|
||
}
|
||
if (s_tcp_fw_data_b64_incomplete(json_buffer, json_len) != 0) {
|
||
TCP_PRINT("Upgrade JSON incomplete b64, rollback\r\n");
|
||
s_tcp_log_rx_cache("TCP-b64-incomplete");
|
||
if (json_start_pos >= 0) {
|
||
tcp_rx_buffer_rollback_to((uint32_t)json_start_pos);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
tcp_server_process_received_data(json_buffer, (uint16_t)json_len);
|
||
processed_any = 1;
|
||
#if TCP_DEBUG_EN
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
s_tcp_log_rx_cache("TCP-after-json-ok");
|
||
}
|
||
#endif
|
||
} else if (json_len == 0) {
|
||
/* 没有完整的JSON消息 */
|
||
#if TCP_DEBUG_EN
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
s_tcp_log_rx_cache("TCP-no-full-json");
|
||
}
|
||
#endif
|
||
break;
|
||
} else {
|
||
/* 错误 */
|
||
TCP_PRINT("Failed to extract JSON from RX buffer\r\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* 消费已处理的数据 */
|
||
if (rx_buffer.processed > 0) {
|
||
tcp_rx_buffer_consume(rx_buffer.processed);
|
||
#if TCP_DEBUG_EN
|
||
if (s_tcp_diag_rx_trace() != 0) {
|
||
s_tcp_log_rx_cache("TCP-after-consume");
|
||
}
|
||
#endif
|
||
} else if (rx_buffer.used > 0) {
|
||
/* 如果没有找到完整的JSON消息,但缓冲区中有数据 */
|
||
|
||
/* 检查缓冲区使用率是否过高 */
|
||
uint8_t buffer_usage_high = (rx_buffer.cap > 0U) &&
|
||
(rx_buffer.used > (rx_buffer.cap * 3U / 4U));
|
||
|
||
if (buffer_usage_high) {
|
||
/* 固件升级中保留半包 JSON,禁止丢弃(避免 Base64 被截断) */
|
||
if (system_filetransfer_is_active() != 0) {
|
||
TCP_PRINT("RX buffer high (%u/%u) during upgrade, keep partial JSON\r\n",
|
||
rx_buffer.used, rx_buffer.cap);
|
||
} else if (has_partial_json) {
|
||
/* 有部分JSON消息,但缓冲区快满了 */
|
||
/* 尝试查找缓冲区中是否有'{'字符,从那里开始保留数据 */
|
||
int first_brace_pos = -1;
|
||
|
||
/* 获取接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreTake(rx_buffer_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
/* 查找第一个'{'字符 */
|
||
for (uint32_t i = 0; i < rx_buffer.used; i++) {
|
||
if (rx_buffer.buffer[i] == '{') {
|
||
first_brace_pos = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (first_brace_pos > 0) {
|
||
/* 找到'{'字符,清理之前的数据 */
|
||
TCP_PRINT("RX buffer high (%u/%u) with partial JSON, cleaning %u bytes before first '{'\r\n",
|
||
rx_buffer.used, rx_buffer.cap, first_brace_pos);
|
||
tcp_rx_buffer_consume(first_brace_pos);
|
||
} else if (first_brace_pos == -1) {
|
||
/* 没有找到'{'字符,清理一半的数据 */
|
||
TCP_PRINT("RX buffer high (%u/%u) with partial JSON but no '{', cleaning half of data\r\n",
|
||
rx_buffer.used, rx_buffer.cap);
|
||
uint32_t clean_len = rx_buffer.used / 2;
|
||
if (clean_len > 0) {
|
||
tcp_rx_buffer_consume(clean_len);
|
||
}
|
||
}
|
||
|
||
/* 释放接收缓冲区互斥锁 */
|
||
if (rx_buffer_mutex != NULL) {
|
||
xSemaphoreGive(rx_buffer_mutex);
|
||
}
|
||
} else {
|
||
/* 没有部分JSON消息,清理一半的数据 */
|
||
TCP_PRINT("RX buffer usage high (%u/%u), no partial JSON, cleaning half of data\r\n",
|
||
rx_buffer.used, rx_buffer.cap);
|
||
uint32_t clean_len = rx_buffer.used / 2;
|
||
if (clean_len > 0) {
|
||
tcp_rx_buffer_consume(clean_len);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (json_buffer != NULL) {
|
||
vPortFree(json_buffer);
|
||
json_buffer = NULL;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 处理接收到的数据
|
||
*/
|
||
void tcp_server_process_received_data(const char *data, uint16_t len)
|
||
{
|
||
tcp_message_t message;
|
||
//printf("tcp_message_t size is %d\r\n",sizeof(tcp_message_t));
|
||
if (data == NULL || len == 0) {
|
||
return;
|
||
}
|
||
|
||
/* 尝试解析JSON消息 */
|
||
if (tcp_parse_json_message(data, &message) == 0) {
|
||
#if TCP_DEBUG_EN
|
||
if (strcmp(message.command, CMD_FIRMWARE_UPGRADE) == 0) {
|
||
tcp_firmware_upgrade_log_io("RX", (const char *)data, (uint32_t)len);
|
||
}
|
||
if (system_filetransfer_is_active() != 0) {
|
||
if (strcmp(message.command, CMD_HEARTBEAT) == 0) {
|
||
tcp_free_message(&message);
|
||
return;
|
||
}
|
||
if (strcmp(message.command, CMD_FIRMWARE_UPGRADE) != 0) {
|
||
TCP_PRINT("Drop command '%s' during firmware upgrade\r\n", message.command);
|
||
tcp_free_message(&message);
|
||
return;
|
||
}
|
||
}
|
||
#endif
|
||
/* 解析成功,处理消息 */
|
||
tcp_process_received_message(&message);
|
||
|
||
/* 释放消息中动态分配的内存 */
|
||
tcp_free_message(&message);
|
||
|
||
/* 如果是心跳消息,更新最后收到心跳的时间 */
|
||
if (strcmp(message.command, CMD_HEARTBEAT) == 0) {
|
||
/* 获取互斥锁保护状态变量 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
server_state.last_heartbeat_received_tick = server_state.tick_counter;
|
||
TCP_PRINT("Heartbeat received, updated last tick to %u\r\n", server_state.tick_counter);
|
||
|
||
/* 释放互斥锁 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
}
|
||
} else {
|
||
/* 如果不是有效的JSON,打印原始数据 */
|
||
TCP_PRINT("Received raw data (%d bytes): %s\r\n", len, data);
|
||
}
|
||
}
|
||
|
||
static void tcp_server_send_ctrl(void)
|
||
{
|
||
uint8_t due = 0U;
|
||
|
||
if (system_filetransfer_is_active() != 0) {
|
||
return;
|
||
}
|
||
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if (server_state.is_client_connected) {
|
||
if (server_state.system_info_sent == 0U) {
|
||
due = 1U;
|
||
} else if (tcp_should_send_message(server_state.system_info_last_tick,
|
||
PERIODIC_REPORT_INTERVAL_SEC)) {
|
||
due = 1U;
|
||
}
|
||
|
||
if (due != 0U) {
|
||
server_state.system_info_sent = 1U;
|
||
server_state.system_info_last_tick = server_state.tick_counter;
|
||
server_state.gun_data_last_tick = server_state.tick_counter;
|
||
}
|
||
}
|
||
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
|
||
if (due == 0U) {
|
||
return;
|
||
}
|
||
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
BT_PRINT("tcp_server: send SystemInfo+GunInfo\r\n");
|
||
}
|
||
#endif
|
||
|
||
tcp_server_send_message(TCP_MSG_SYSTEM_INFO);
|
||
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
vTaskDelay(pdMS_TO_TICKS(120));
|
||
} else
|
||
#endif
|
||
{
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
|
||
tcp_server_send_message(TCP_MSG_GUN_DATA);
|
||
}
|
||
/**
|
||
* @brief TCP服务器处理函数(周期性调用)- Socket API版本
|
||
*/
|
||
void tcp_server_process(void)
|
||
{
|
||
uint8_t should_check_heartbeat_timeout = 0;
|
||
static U32_T tick_counter = 0;
|
||
U32_T tick_counter_now = get_current_seconds();
|
||
|
||
comm_link_process();
|
||
|
||
/* 更新tick计数器 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if(tick_counter_now != tick_counter)
|
||
{
|
||
server_state.tick_counter++;
|
||
tick_counter = tick_counter_now;
|
||
}
|
||
|
||
/* 检查客户端连接状态(使用Socket API) */
|
||
int is_connected = comm_link_is_client_connected();
|
||
|
||
/* 更新服务器状态中的连接状态 */
|
||
if (server_state.is_client_connected != is_connected) {
|
||
server_state.is_client_connected = is_connected;
|
||
|
||
if (is_connected) {
|
||
/* 新客户端连接 */
|
||
server_state.system_info_sent = 0; /* 连接成功后需要第一时间发送系统信息 */
|
||
server_state.heartbeat_last_tick = 0;
|
||
server_state.system_info_last_tick = 0;
|
||
server_state.gun_data_last_tick = 0;
|
||
server_state.last_heartbeat_received_tick = 0;
|
||
TCP_PRINT("Client connected (Socket API)\r\n");
|
||
#if BLE_DEBUG_EN
|
||
if (COMM_LINK_IS_BLE(comm_link_get_type())) {
|
||
BT_PRINT("tcp_server: BLE client up, begin RX/TX\r\n");
|
||
}
|
||
#endif
|
||
} else {
|
||
/* 客户端断开连接 */
|
||
TCP_PRINT("Client disconnected (Socket API)\r\n");
|
||
/* 重置接收缓冲区 */
|
||
tcp_rx_buffer_reset();
|
||
}
|
||
}
|
||
|
||
/* 检查是否需要发送心跳 */
|
||
if (server_state.is_client_connected) {
|
||
/* 检查心跳超时(仅在收到过心跳后才检查) */
|
||
if (server_state.last_heartbeat_received_tick > 0) {
|
||
uint32_t heartbeat_timeout_elapsed = server_state.tick_counter - server_state.last_heartbeat_received_tick;
|
||
if (heartbeat_timeout_elapsed >= HEARTBEAT_TIMEOUT_SEC) {
|
||
should_check_heartbeat_timeout = 1;
|
||
TCP_PRINT("Heartbeat timeout detected! Elapsed: %u seconds\r\n", heartbeat_timeout_elapsed);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 释放互斥锁 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
|
||
/* Socket API处理逻辑 */
|
||
|
||
/* 1. 接受新的客户端连接 */
|
||
if (!server_state.is_client_connected) {
|
||
int accept_result = comm_link_accept_client();
|
||
if (accept_result > 0) {
|
||
/* 新客户端连接成功 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
server_state.is_client_connected = 1;
|
||
server_state.system_info_sent = 0;
|
||
server_state.heartbeat_last_tick = 0;
|
||
server_state.system_info_last_tick = 0;
|
||
server_state.gun_data_last_tick = 0;
|
||
server_state.last_heartbeat_received_tick = 0;
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 2. 接收数据(如果有客户端连接) */
|
||
if (server_state.is_client_connected) {
|
||
tcp_server_socket_receive_data();
|
||
}
|
||
|
||
/* 3. 处理接收缓冲区 */
|
||
if (system_filetransfer_is_active() != 0) {
|
||
tcp_rx_buffer_skip_leading_garbage();
|
||
}
|
||
tcp_server_process_rx_buffer();
|
||
if (system_filetransfer_is_active() != 0) {
|
||
uint8_t pass;
|
||
for (pass = 0U; pass < TCP_UPGRADE_RX_BURST_PASSES; pass++) {
|
||
comm_link_process();
|
||
(void)tcp_server_socket_receive_data();
|
||
tcp_server_process_rx_buffer();
|
||
}
|
||
}
|
||
|
||
/* 4. 处理心跳超时(固件升级期间不判心跳超时) */
|
||
system_filetransfer_poll_idle_timeout();
|
||
|
||
if (system_filetransfer_is_active() != 0) {
|
||
should_check_heartbeat_timeout = 0U;
|
||
}
|
||
|
||
if (should_check_heartbeat_timeout) {
|
||
TCP_PRINT("Disconnecting client due to heartbeat timeout\r\n");
|
||
|
||
/* 关闭客户端连接 */
|
||
comm_link_close_client();
|
||
|
||
/* 获取互斥锁保护状态变量 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreTake(tcp_server_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
server_state.is_client_connected = 0;
|
||
|
||
/* 释放互斥锁 */
|
||
if (tcp_server_mutex != NULL) {
|
||
xSemaphoreGive(tcp_server_mutex);
|
||
}
|
||
|
||
/* 重置接收缓冲区 */
|
||
tcp_rx_buffer_reset();
|
||
}
|
||
|
||
/* 5. 发送控制消息(心跳、系统信息等) */
|
||
tcp_server_send_ctrl();
|
||
}
|
||
|
||
|
||
|
||
#else /* TCP_DEBUG_EN */
|
||
|
||
/* 当TCP_DEBUG_EN未使能时,提供空实现以避免链接错误 */
|
||
err_t tcp_server_start(void) { return ERR_OK; }
|
||
void tcp_server_stop(void) { }
|
||
void tcp_server_process(void) { }
|
||
void tcp_server_send_heartbeat(void) { }
|
||
void tcp_server_send_system_info(void) { }
|
||
err_t tcp_server_send_json(const char *json_data, uint16_t len) { LWIP_UNUSED_ARG(json_data); LWIP_UNUSED_ARG(len); return ERR_OK; }
|
||
void tcp_server_process_received_data(const char *data, uint16_t len) { LWIP_UNUSED_ARG(data); LWIP_UNUSED_ARG(len); }
|
||
void tcp_server_task(void *arg) { LWIP_UNUSED_ARG(arg); }
|
||
|
||
void tcp_server_process(void) { /* CCU621_M compat stub */ }
|
||
#endif /* TCP_DEBUG_EN */ |