Files
car_stm32f103vet6/Core/Bsp/protocol.c

126 lines
4.1 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 protocol.c
* @brief 协议处理函数实现
* @details 该文件包含了协议解析和处理的相关函数,主要用于处理从 ESP12F
* 模块接收到的数据。
* @author Beihong Wang
* @date 2026-04-01
*/
#include "protocol.h"
#include "bsp_uart.h"
#include "checksum.h"
#include "cmsis_os.h"
#include "elog.h"
#include <stdio.h>
#include <string.h>
/* 定义日志 TAG */
#define Protocol_TAG "Protocol"
/* 引用在 freertos.c 中定义的消息队列句柄 */
extern osMessageQueueId_t CmdQueueHandle;
/**
* @brief 协议处理函数
* @details 严格按照协议文档:校验范围 = 帧头 + 命令 + 数据
* 即从下标 0 开始,一直加到最后一个冒号之前
*/
void Protocol_HandleMessage(uint8_t *data, uint16_t len) {
if (data == NULL)
return;
// 1. 基础检查:长度必须足够,且必须以 '#' 结尾
if (len < 10 || data[len - 1] != '#') {
elog_w(Protocol_TAG, "协议错误:长度不足或帧尾错误 (len: %d)", len);
return;
}
// 2. 寻找校验位前的分隔符
// 协议格式LOGI:CMD:DATA:CS#
// 我们需要找到最后一个冒号 ':' 的位置,它前面是数据,后面是校验位
int last_colon_pos = -1;
for (int i = 0; i < len; i++) {
if (data[i] == ':') {
last_colon_pos = i;
}
}
// 如果找不到冒号,说明格式错误
if (last_colon_pos == -1 || last_colon_pos < 5) {
elog_w(Protocol_TAG, "协议错误:找不到分隔符 ':' 或位置非法");
return;
}
// 3. 提取接收到的校验位 (从 ASCII 转为 Hex 数值)
// 校验位紧跟在 last_colon_pos 之后,长度为 2 字节
char recv_cs_hex_str[3] = {0};
// 防止越界
if (last_colon_pos + 3 >= len) {
elog_w(Protocol_TAG, "协议错误:校验位数据越界");
return;
}
recv_cs_hex_str[0] = data[last_colon_pos + 1];
recv_cs_hex_str[1] = data[last_colon_pos + 2];
unsigned int received_checksum = 0;
sscanf(recv_cs_hex_str, "%02X", &received_checksum);
// 4. 计算本地校验和
// 【核心修改点】
// 严格按照协议文档:从下标 0 开始,长度为 last_colon_pos
// 也就是计算 "LOGI:SP:080" 的累加和
uint8_t calculated_checksum =
Calculate_CheckSum(data, 0, (uint16_t)last_colon_pos);
// 5. 对比校验和
if (calculated_checksum == (uint8_t)received_checksum) {
elog_i(Protocol_TAG, "✅ 校验通过!执行指令: %s", (char *)data);
/* 提取有效载荷发送到消息队列 */
char cmd_payload[16] = {0};
// 将 "LOGI:" 之后到最后一个冒号之前的内容作为指令
uint16_t payload_len = last_colon_pos - 5;
uint16_t copy_len = (payload_len > 15) ? 15 : payload_len;
if (copy_len > 0) {
memcpy(cmd_payload, &data[5], copy_len);
}
osStatus_t status = osMessageQueuePut(CmdQueueHandle, cmd_payload, 0, 0);
if (status != osOK) {
elog_e(Protocol_TAG, "Protocol: Queue put failed: %d", status);
}
} else {
elog_w(Protocol_TAG, "❌ 校验失败!计算值: 0x%02X, 接收值: 0x%02X",
calculated_checksum, (uint8_t)received_checksum);
// 辅助调试:打印实际参与计算的数据段
char debug_buf[32] = {0};
if (last_colon_pos < 32) {
memcpy(debug_buf, data, last_colon_pos);
elog_i(Protocol_TAG, " -> 单片机正在计算这段数据的校验和: [%s]",
debug_buf);
elog_i(Protocol_TAG, " -> 请检查上位机是否也是按照此范围计算累加和");
}
}
}
#define CarCtrlTask_TAG "CarCtrlTask"
void CarCtrl_Task(void *argument) {
/* USER CODE BEGIN CarCtrl_Task */
char cmd_payload[16];
/* Infinite loop */
for (;;) {
/* 从消息队列中获取数据,阻塞等待 */
if (osMessageQueueGet(CmdQueueHandle, cmd_payload, NULL, osWaitForever) ==
osOK) {
elog_i(CarCtrlTask_TAG, "CarCtrl: Received command (ASCII: %s) from queue",
cmd_payload);
/* 可以在这里添加根据 cmd_payload 控制小车的逻辑 */
}
// osDelay(1); // osMessageQueueGet 已经是阻塞的,不需要额外的 osDelay
}
/* USER CODE END CarCtrl_Task */
}