Files
CCU621M/app/tcp_ser/tcp_server.c
T

1541 lines
48 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @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:单包 1024BJSON 约 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 */