新增文档和更新TCP服务器代码,增加命令帧处理功能及相关数据结构定义

This commit is contained in:
qiuxin 2025-05-08 19:59:16 +08:00
parent ccb1ef039f
commit 49ab0b8447
3 changed files with 224 additions and 40 deletions

Binary file not shown.

Binary file not shown.

View File

@ -39,6 +39,152 @@ extern uint8_t uart_echo_flags_hart2;
extern uint8_t uart_echo_flags_ble1; extern uint8_t uart_echo_flags_ble1;
extern uint8_t uart_echo_flags_ble2; extern uint8_t uart_echo_flags_ble2;
#define head_00 0xD5 // 帧头1
#define head_01 0xC8 // 帧头2
uint16_t data_len = 0; // 帧体长度
#define source_addr_h 0x01 // 源地址高
#define source_addr_l 0x02 // 源地址低
#define target_addr_h 0x0A // 目标地址高
#define target_addr_l 0x0B // 目标地址低
uint16_t reply_type = 0x00;// 报文类型_应答
// 校验和函数
uint8_t calc_checksum(const uint8_t *data, uint8_t start, uint8_t end) {
uint8_t checksum = 0;
for (uint8_t i = start; i <= end; i++) {
checksum += data[i];
}
return checksum;
}
// body: 报文体指针, body_len: 报文体长度, tx: 返回帧缓冲区, 返回帧总长度
uint16_t handle_type_80(const uint8_t *body, uint16_t body_len, uint8_t *tx)
{
uint16_t total_len = 2 + 2 + 2 + 2 + 1 + body_len + 2; // 帧头+帧长+源+目标+类型+体+校验
// 帧头
tx[0] = head_00;
tx[1] = head_01;
// 帧长度(大端)
tx[2] = (total_len >> 8) & 0xFF;
tx[3] = total_len & 0xFF;
// 源地址
tx[4] = source_addr_h;
tx[5] = source_addr_l;
// 目标地址
tx[6] = target_addr_h;
tx[7] = target_addr_l;
// 报文类型
tx[8] = reply_type;
// 报文体
tx[9] = 0x01;//执行成功
//memcpy(&tx[9], body, body_len);
// 校验和(累加源地址到报文体)
uint16_t checksum = 0;
for (int i = 4; i < 9 + body_len; ++i)
{
checksum += tx[i];
}
// 校验和2字节大端
tx[total_len - 2] = 0x00;//校验和只取低八位
tx[total_len - 1] = checksum & 0xFF;
return total_len;
}
uint16_t handle_type_81(const uint8_t *body, uint16_t body_len, uint8_t *tx)
{
uint16_t total_len = 2 + 2 + 2 + 2 + 1 + body_len + 2; // 帧头+帧长+源+目标+类型+体+校验
// 帧头
tx[0] = head_00;
tx[1] = head_01;
// 帧长度(大端)
tx[2] = (total_len >> 8) & 0xFF;
tx[3] = total_len & 0xFF;
// 源地址
tx[4] = source_addr_h;
tx[5] = source_addr_l;
// 目标地址
tx[6] = target_addr_h;
tx[7] = target_addr_l;
// 报文类型
tx[8] = reply_type;
// 报文体
tx[9] = 0x01;//主版本号1.0
tx[10] = 0x00;//次版本号0.0
//memcpy(&tx[9], body, body_len);
// 校验和(累加源地址到报文体)
uint16_t checksum = 0;
for (int i = 4; i < 9 + body_len; ++i)
{
checksum += tx[i];
}
// 校验和2字节大端
tx[total_len - 2] = 0x00;//校验和只取低八位
tx[total_len - 1] = checksum & 0xFF;
return total_len;
}
uint16_t handle_type_82(const uint8_t *body, uint16_t body_len, uint8_t *tx)
{
uint16_t total_len = 2 + 2 + 2 + 2 + 1 + body_len + 2; // 帧头+帧长+源+目标+类型+体+校验
// 帧头
tx[0] = head_00;
tx[1] = head_01;
// 帧长度(大端)
tx[2] = (total_len >> 8) & 0xFF;
tx[3] = total_len & 0xFF;
// 源地址
tx[4] = source_addr_h;
tx[5] = source_addr_l;
// 目标地址
tx[6] = target_addr_h;
tx[7] = target_addr_l;
// 报文类型
tx[8] = reply_type;
// 报文体
tx[9] = 0xBC;//心跳回复
// 校验和(累加源地址到报文体)
uint16_t checksum = 0;
for (int i = 4; i < 9 + body_len; ++i)
{
checksum += tx[i];
}
// 校验和2字节大端
//tx[total_len - 2] = (checksum >> 8) & 0xFF;
tx[total_len - 2] =0x00;//校验和只取低八位
tx[total_len - 1] = checksum & 0xFF;
return total_len;
}
uint16_t handle_type_83(const uint8_t *body, uint16_t body_len, uint8_t *tx)
{
uint16_t total_len = 2 + 2 + 2 + 2 + 1 + body_len + 2; // 帧头+帧长+源+目标+类型+体+校验
// 帧头
tx[0] = head_00;
tx[1] = head_01;
// 帧长度(大端)
tx[2] = (total_len >> 8) & 0xFF;
tx[3] = total_len & 0xFF;
// 源地址
tx[4] = source_addr_h;
tx[5] = source_addr_l;
// 目标地址
tx[6] = target_addr_h;
tx[7] = target_addr_l;
// 报文类型
tx[8] = reply_type;
// 报文体
tx[9] = 0x00;//7个字节表示的使能状态
// 校验和(累加源地址到报文体)
uint16_t checksum = 0;
for (int i = 4; i < 9 + body_len; ++i)
{
checksum += tx[i];
}
// 校验和2字节大端
//tx[total_len - 2] = (checksum >> 8) & 0xFF;
tx[total_len - 2] =0x00;//校验和只取低八位
tx[total_len - 1] = checksum & 0xFF;
return total_len;
}
/*接收回调函数*/ /*接收回调函数*/
static err_t tcpecho_recv_hart1(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) static err_t tcpecho_recv_hart1(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{ // 对应接收数据连接的控制块 接收到的数据 { // 对应接收数据连接的控制块 接收到的数据
@ -142,8 +288,8 @@ static err_t tcpecho_recv_ble2(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,
static err_t tcpecho_recv_control(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) static err_t tcpecho_recv_control(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{ {
uint8_t tcp_rx_data[128] = {0}; // 接收数据缓存区 uint8_t tcp_rx_data[128] = {0};
uint8_t tcp_tx_data[128] = {0}; // 发送数据缓存区 uint8_t tcp_tx_data[128] = {0};
uint8_t rx_data_len = 0; uint8_t rx_data_len = 0;
uint8_t tx_data_len = 0; uint8_t tx_data_len = 0;
@ -155,46 +301,84 @@ static err_t tcpecho_recv_control(void *arg, struct tcp_pcb *tpcb, struct pbuf *
memcpy(tcp_rx_data, (uint8_t *)p->payload, p->tot_len); memcpy(tcp_rx_data, (uint8_t *)p->payload, p->tot_len);
rx_data_len = p->tot_len; rx_data_len = p->tot_len;
// 判断是否为指定格式的命令帧 // 基本帧头校验,帧长和固定帧头
if (rx_data_len == 10 && if (rx_data_len == tcp_rx_data[3] && tcp_rx_data[0] == 0xD5 && tcp_rx_data[1] == 0xC8)
tcp_rx_data[0] == 0xD5 &&
tcp_rx_data[1] == 0xC8 &&
tcp_rx_data[2] == 0x0A &&
tcp_rx_data[3] == 0x01 &&
tcp_rx_data[4] == 0x01 &&
tcp_rx_data[5] == 0x0A &&
tcp_rx_data[6] == 0x0A &&
tcp_rx_data[7] == 0x00 &&
tcp_rx_data[8] == 0x00 &&
tcp_rx_data[9] == 0x17)
{ {
// 构造返回帧 uint8_t calc_sum = 0; // 改用uint8_t自动取低8位
tcp_tx_data[0] = 0xD5; // 帧头1 for (int i = 4; i < rx_data_len - 1; i++)
tcp_tx_data[1] = 0xC8; // 帧头2 {
tcp_tx_data[2] = 0x0A; // 帧长度 calc_sum += tcp_rx_data[i];
tcp_tx_data[3] = 0x01; // 源地址
tcp_tx_data[4] = 0x01;
tcp_tx_data[5] = 0x0A; // 目标地址
tcp_tx_data[6] = 0x0A;
tcp_tx_data[7] = 0x01; // 报文类型改为01
tcp_tx_data[8] = 0x00; // 报文体
// 计算校验和(从目标地址到报文体的累加和)
uint8_t checksum = 0;
for (int i = 5; i <= 8; i++) {
checksum += tcp_tx_data[i];
} }
tcp_tx_data[9] = checksum; uint8_t recv_sum = tcp_rx_data[rx_data_len - 1]; // 只取最后一个字节作为校验和
tx_data_len = 10; if (calc_sum != recv_sum)
{
pbuf_free(p);
return ERR_OK;
}
// 根据报文类型分发
switch (tcp_rx_data[8])
{
case 0x80: //复位
{
uint16_t body_len = rx_data_len - 11; //报文体长度 = 总长度 - 2(帧头) - 2(帧长) - 2(源) - 2(目标) - 1(类型) - 2(校验)
reply_type = tcp_rx_data[8];
tx_data_len = handle_type_80(tcp_rx_data + 9, body_len, tcp_tx_data);
break;
}
case 0x81://查询版本号
{
uint16_t body_len = 2; //报文体有主次2个字节
reply_type = tcp_rx_data[8];
tx_data_len = handle_type_81(tcp_rx_data + 9, body_len, tcp_tx_data);
break;
}
case 0x82://心跳请求
{
uint16_t body_len = 1; //心跳报文体有1个字节
reply_type = tcp_rx_data[8];
tx_data_len = handle_type_82(tcp_rx_data + 9, body_len, tcp_tx_data);
break;
}
case 0x83://读取模块使能状态
{
}
break;
case 0x84://设置模块是能状态
break;
case 0x85://读取读取配置参数
break;
case 0x86://设置配置参数
break;
case 0x87://读取测试数据
break;
case 0x88://透传数据
break;
default:
pbuf_free(p);
return ERR_OK;
}
// 发送返回帧 // 发送返回帧
if(tcp_write(tpcb, tcp_tx_data, tx_data_len, 1) != ERR_OK) { if (tx_data_len > 0)
// 发送失败处理 {
return ERR_MEM; if (tcp_write(tpcb, tcp_tx_data, tx_data_len, 1) != ERR_OK)
{
pbuf_free(p);
return ERR_MEM;
}
tcp_output(tpcb);
} }
tcp_output(tpcb); // 确保数据立即发送 pbuf_free(p);
} }
pbuf_free(p);
} }
else if (err == ERR_OK) else if (err == ERR_OK)
{ {