feat(vd960DBN): 实现 DLD960Loop 串口通信协议 (0x7F)

新增:
- docs/DLD960Loop_串口通信协议.md — 协议文档 V1.02
- loop_uart_proto.h/c — 协议实现: checksum/组包/解析/帧状态机/命令状态机

修改:
- usart_biz.c: 使用 lup_feed_byte() 帧解析器替代 timeout heuristic; 波特率修正为 115200
- tcp_json_srv.c/h: loop_param_set/query 真实实现(0x63/0x64), 0xC0 传感器推流, 延迟响应机制
- peripheral_main.c: 添加 tcp_json_push_sensor() 调用, 帧解析器超时保护

校验验证: 5个协议例程 XOR+SUM 全部通过
This commit is contained in:
wangfq
2026-07-02 09:26:34 +08:00
parent 4e75312a0f
commit 4fbda96078
7 changed files with 1522 additions and 64 deletions

View File

@@ -3,10 +3,12 @@
*
* Created on: 2026-02-26
* Author: wangfq
* Updated: 2026-07-02 — 使用 loop_uart_proto 帧解析器替代 timeout heuristic
*/
#include "config.h"
#include "cmcng.h"
#include "loop_uart_proto.h"
#include <string.h>
#include "dbn_ble_srv.h"
@@ -34,7 +36,7 @@ void uart_init(void){
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // Rx
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 192000;//115200;
USART_InitStructure.USART_BaudRate = 115200; // 115200 (协议规定)
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
@@ -42,7 +44,7 @@ void uart_init(void){
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART2, &USART_InitStructure);
// USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 配合DMA但测试不能接收原因未知。
// USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
@@ -55,11 +57,13 @@ void uart_init(void){
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO_Mode_IPU; // Key
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// 初始化帧解析器
lup_frame_reset();
}
@@ -76,11 +80,11 @@ void USART1_IRQHandler(void)
}
/*********************************************************************
* @fn USART2_IRQHandler
*
* @brief This function handles USART2 global interrupt request.
* @brief USART2 RX — 使用 lup_feed_byte() 帧解析器
* 当解析出完整帧时,复制到 g_pkg_uart_2.pkg 并设置 flag
*
* @return none
*/
@@ -88,25 +92,24 @@ void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
uint8_t _dat = USART_ReceiveData(USART2);
if(g_pkg_uart_2.offset == 0){
if(_dat != 0){
g_pkg_uart_2.pkg[g_pkg_uart_2.offset++] = _dat;
}
}
else{
if(g_pkg_uart_2.offset < BUFF_STACK_SIZE){
g_pkg_uart_2.pkg[g_pkg_uart_2.offset++] = _dat;
}
else{
g_pkg_uart_2.flag = 1;
}
}
if(g_pkg_uart_2.offset){
g_pkg_uart_2.tick = 0;
}
uint8_t _dat = USART_ReceiveData(USART2);
// 喂给帧解析器
if (lup_feed_byte(_dat)) {
// 帧接收完成,复制到 g_pkg_uart_2
const uint8_t *frame = lup_frame_data();
uint16_t frame_len = lup_frame_len();
if (frame_len <= BUFF_STACK_SIZE) {
memcpy(g_pkg_uart_2.pkg, frame, frame_len);
g_pkg_uart_2.offset = frame_len;
g_pkg_uart_2.flag = 1;
g_pkg_uart_2.tick = 0;
}
lup_frame_reset();
} else if (g_lup_parser.state != LUP_FRAME_STATE_IDLE) {
// 正在接收帧中tick 归零
g_pkg_uart_2.tick = 0;
}
}
}
@@ -133,46 +136,67 @@ void UART1_SendString(uint8_t *buf, uint16_t len)
}
/*
* uart_srv — 主循环中调用,处理已接收完整的 UART2 帧
*
* 处理流程:
* 1. 0x7F + 0xC0/0x0C → 传感器数据上报
* - 若无 BLE 连接 → 标记 `_report_flag`,在 TCP JSON 中处理
* - 若有 BLE 连接且 acs_enable → 转 0x8F 前缀发给 BLE
* 2. 0x7F + 其他 CMD → 响应帧,交给 lup_process_frame() 匹配挂起命令
* 3. 非 0x7F → 调试打印(可能是字符串等)
*/
void uart_srv(void)
{
uint8_t i;
uint8_t _report_flag = 0;
// 检查命令超时
lup_cmd_check_timeout();
if(g_pkg_uart_2.flag){
if(g_flag_counter_ota.flag == 0){
if(g_pkg_uart_2.pkg[0] == 0x7F){
if(g_pkg_uart_2.pkg[3] == 0xC0 && g_pkg_uart_2.pkg[4] == 0x0C)
uint8_t cmd = g_pkg_uart_2.pkg[3];
// --- 传感器上报 (0xC0) ---
if(cmd == 0xC0 && g_pkg_uart_2.pkg[4] == 0x0C)
{
if(g_dbn_ble_state_acs_enable.flag == 0){
// 无 BLE ACS 连接 → 标记为 TCP JSON 上报
_report_flag = 1;
}
else{
// BLE ACS 已连接 → 改 Magic 为 0x8F 发给 BLE
g_pkg_uart_2.pkg[0] = 0x8F;
}
}
else {
// --- 命令响应 → 交给协议处理器 ---
lup_process_frame(g_pkg_uart_2.pkg, g_pkg_uart_2.offset);
}
// 调试打印
for(i = 0; i < g_pkg_uart_2.offset; i++){
PRINT(" %02X", g_pkg_uart_2.pkg[i]);
}
PRINT("\n");
if(_report_flag){
InitPkgUart(&g_pkg_uart_2);
// 传感器帧保留在 pkg 中供上层 (tcp_json_srv) 处理
// 不 InitPkgUart — 由上层消费后再 InitPkgUart
}
}
else {
// 非 0x7F 魔法字节
PRINT("Rcv_len:%d,dat: %s\n", g_pkg_uart_2.offset, g_pkg_uart_2.pkg);
}
}
else{
// PRINT("From_Loop: ");
// for(i = 0; i < g_pkg_uart_2.offset; i++){
// PRINT(" %02X", g_pkg_uart_2.pkg[i]);
// }
// PRINT("\n");
// OTA 模式 — 忽略 Loop MCU 数据
}
if(g_flag_bt_state){
g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp);
@@ -180,7 +204,11 @@ void uart_srv(void)
else{
g_dbn_ble_state_acs_enable.flag = 0;
}
InitPkgUart(&g_pkg_uart_2);
// 只有非 _report_flag 时才立即清空
// _report_flag 的帧由 tcp_json 消费后清理
if (!_report_flag) {
InitPkgUart(&g_pkg_uart_2);
}
}
}