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

@@ -0,0 +1,239 @@
/**
******************************************************************************
* @file loop_uart_proto.h
* @author wangfq
* @version V1.0
* @date 2026-07-02
* @brief DLD960Loop 串口通信协议 (7F) — CH32V208 ↔ DLD960Loop MCU
*
* 帧格式: 7F | Addr | LEN | CMD | Data... | XOR | SUM
* UART: USART2, 115200bps, PA2(Tx)/PA3(Rx)
*
* 该协议是通信MCU(CH32V208)与地感MCU(DLD960Loop/AT32F421)之间的接口。
* 网络接口(TCP JSON/5960)通过本模块向地感MCU下发命令并获取数据。
******************************************************************************
*/
#ifndef __LOOP_UART_PROTO_H__
#define __LOOP_UART_PROTO_H__
#include <stdint.h>
/*===========================================================================
* Protocol Constants
*===========================================================================*/
#define LUP_MAGIC 0x7F // 配置/查询协议
#define LUP_MAGIC_OTA 0x9F // OTA
#define LUP_ADDR_DEFAULT 0x00 // 默认地址
#define LUP_MAX_VALUE_LEN 64 // Value 字段最大长度
#define LUP_MAX_PKG_LEN (1 + 3 + LUP_MAX_VALUE_LEN + 2) // 70 bytes 最大帧
/*===========================================================================
* Command Bytes (CMD)
*===========================================================================*/
#define LUP_CMD_GET_VERSION 0x4A // 获取设备版本号
#define LUP_CMD_RESET 0x6D // 设备复位(无回复)
#define LUP_CMD_FACTORY_INIT 0x92 // 出厂初始化
#define LUP_CMD_SENSITIVITY 0x8A // 读写线圈灵敏度列表
#define LUP_CMD_SET_PARAM 0x63 // 设置多路参数
#define LUP_CMD_GET_PARAM 0x64 // 读取多路参数
#define LUP_CMD_SENSOR_REPORT 0xC0 // 设备主动上报传感信息
/*===========================================================================
* Sensor Types (0xC0 SensType)
*===========================================================================*/
#define LUP_SENS_TYPE_MULTI_COIL 0x0C // 多路线圈传感信息(四路)
/*===========================================================================
* R/W byte for sensitivity (0x8A)
*===========================================================================*/
#define LUP_SENS_RW_READ 0x00
#define LUP_SENS_RW_WRITE 0x01
/*===========================================================================
* 线圈数
*===========================================================================*/
#define LUP_COIL_COUNT 4
/*===========================================================================
* Data Structures
*===========================================================================*/
/* 线圈配置 (0x63 Set / 0x64 Get 中使用) */
typedef struct {
uint8_t sensitivity; // 低4位灵敏度(0~9), 高4位频率等级[4]=高频,[5]=低频
uint8_t loop_delay; // 延时时间 0~200, 0.1s/级
uint8_t output_mode; // 低3位: 0=存在,1=进入脉冲,2=离开脉冲,3=方向
// 高5位: SafeMode 分钟数(0=关闭)
uint8_t exist_mode; // 低4位: 0=永久, 非0=有限分钟
uint8_t direction_mode; // 低3位: 0=触发, 1~6=方向模式
// 高4位: Function_Mode
} LUP_CoilParam;
/* 多路参数设置 (0x63) */
typedef struct {
uint8_t auto_mode; // 0=不启用自动调频, 默认0
uint8_t amount; // 线圈数量
LUP_CoilParam params[LUP_COIL_COUNT];
} LUP_ParamSet;
/* 多路参数读取返回 (0x64 Response) */
typedef struct {
uint8_t auto_mode;
uint8_t amount;
LUP_CoilParam params[LUP_COIL_COUNT];
uint32_t freq[LUP_COIL_COUNT][3]; // [ch][0]=freq1, [1]=freq2, [2]=freq3
} LUP_ParamGet;
/* 单路线圈传感数据单元 (0xC0/0x0C 中的每一路线圈) */
typedef struct {
uint8_t freq_level : 2; // 00=高频33nF, 01=中高43nF, 10=中低66nF, 11=低频76nF
uint8_t direction : 1; // 0=触发, 1=方向判别
uint8_t freq_type : 1; // 0=初始频率, 1=实时频率
uint8_t sensitivity : 4; // 灵敏度等级
// 线圈评估条件
uint8_t condition : 4; // 环境状态评估值(0=正常, 值越大干扰越大)
uint8_t loop_state : 1; // 0=正常, 1=断开
uint8_t car_state : 1; // 0=无车, 1=有车
uint8_t misc_type : 2; // 0=时间量, 1=断开次数, 2=车流量
uint32_t freq; // 频率 (3 bytes, little-endian)
uint16_t variation; // 变化量 (2 bytes, little-endian)
union {
uint32_t passtime_ms5; // 通过时间/车间距, 5ms单位 (misc_type=0)
uint32_t cut_amount; // 线圈断开次数 (misc_type=1)
uint32_t flow_amount; // 车流量数 (misc_type=2)
} misc;
} LUP_CoilSensor;
/* 主动上报传感信息 (0xC0/0x0C) */
typedef struct {
uint8_t sens_type; // 0x0C
uint8_t sub_amount; // 分包数量(高4位), 0=无分包
uint8_t sub_sequence; // 当前分包序号(低4位), 1-based
uint8_t coil_count; // 线圈数 (解析出的)
LUP_CoilSensor coils[LUP_COIL_COUNT];
} LUP_SensorReport;
/* 灵敏度读写 (0x8A) */
typedef struct {
uint8_t rw; // 0=Read, 1=Write
uint8_t amount; // 灵敏度值数量
uint16_t sens_in[LUP_COIL_COUNT]; // 触发灵敏度
uint16_t sens_out[LUP_COIL_COUNT]; // 释放灵敏度
} LUP_Sensitivity;
/* 版本信息 (0x4A Response) */
typedef struct {
uint8_t status; // Status byte
uint8_t hard_main;
uint8_t hard_sub;
uint8_t hard_ssub;
uint8_t soft_main;
uint8_t soft_sub;
uint8_t soft_ssub;
char version_str[32]; // 格式化字符串
} LUP_VersionInfo;
/* 命令状态机 */
typedef enum {
LUP_STATE_IDLE = 0, // 空闲
LUP_STATE_WAIT_RESPONSE, // 等待响应
LUP_STATE_RESPONSE_READY, // 响应已就绪
LUP_STATE_TIMEOUT // 超时
} LUP_CmdState;
/* 挂起的命令跟踪 */
typedef struct {
uint8_t pending_cmd; // 当前等待响应的命令字节
uint32_t send_tick; // 发送时刻 (ms)
uint32_t timeout_ms; // 超时时间
LUP_CmdState state;
// 响应数据缓冲区
uint8_t resp_buf[LUP_MAX_PKG_LEN];
uint16_t resp_len;
} LUP_CmdTracker;
/*===========================================================================
* Global State
*===========================================================================*/
extern LUP_CmdTracker g_lup_cmd;
/*===========================================================================
* Public API
*===========================================================================*/
/* --- Checksum --- */
uint8_t lup_calc_xor(const uint8_t *data, uint16_t len);
uint8_t lup_calc_sum(const uint8_t *data, uint16_t len);
int lup_verify_checksum(const uint8_t *pkg, uint16_t len);
void lup_append_checksum(uint8_t *pkg);
/* --- Packet Builders (returns total packet length) --- */
uint16_t lup_build_get_version(uint8_t *buf);
uint16_t lup_build_reset(uint8_t *buf);
uint16_t lup_build_factory_init(uint8_t *buf);
uint16_t lup_build_sensitivity_read(uint8_t *buf);
uint16_t lup_build_sensitivity_write(uint8_t *buf, const LUP_Sensitivity *sens);
uint16_t lup_build_set_param(uint8_t *buf, const LUP_ParamSet *ps);
uint16_t lup_build_get_param(uint8_t *buf);
/* --- Packet Parsers (returns 0=success, <0=error) --- */
int lup_parse_version(const uint8_t *pkg, uint16_t len, LUP_VersionInfo *info);
int lup_parse_factory_init_resp(const uint8_t *pkg, uint16_t len, uint8_t *success);
int lup_parse_sensitivity_resp(const uint8_t *pkg, uint16_t len, LUP_Sensitivity *sens);
int lup_parse_param_get(const uint8_t *pkg, uint16_t len, LUP_ParamGet *pg);
int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *report);
int lup_parse_set_param_resp(const uint8_t *pkg, uint16_t len, uint8_t *success);
/* --- Command State Machine --- */
void lup_cmd_begin(uint8_t cmd, uint32_t timeout_ms);
void lup_cmd_done(void);
int lup_cmd_check_timeout(void);
void lup_cmd_on_response(const uint8_t *pkg, uint16_t len);
/* --- High-level Commands (send + wait handled by state machine) --- */
void lup_send_get_version(void);
void lup_send_reset(void);
void lup_send_factory_init(void);
void lup_send_sensitivity_read(void);
void lup_send_set_param(const LUP_ParamSet *ps);
void lup_send_get_param(void);
/* --- Mid-packet ACK for 0xC0 multi-packet --- */
uint16_t lup_build_sensor_ack(uint8_t *buf, uint8_t sens_type,
uint8_t seq, uint8_t sub_amount);
/* --- UART Frame Parser (called from USART2 ISR context) --- */
typedef enum {
LUP_FRAME_STATE_IDLE = 0, // 等待 0x7F
LUP_FRAME_STATE_HEADER, // 接收 Header (Addr, LEN, CMD)
LUP_FRAME_STATE_VALUE, // 接收 Value
LUP_FRAME_STATE_CHECK, // 接收 Checksum
LUP_FRAME_STATE_COMPLETE // 帧完成
} LUP_FrameState;
typedef struct {
LUP_FrameState state;
uint8_t buf[LUP_MAX_PKG_LEN];
uint16_t idx; // 当前写入位置
uint16_t value_len; // 期望的 Value 长度 (从 LEN 字段解析)
uint16_t value_idx; // 当前已接收的 Value 字节数
} LUP_FrameParser;
extern LUP_FrameParser g_lup_parser;
/* 喂一个字节给帧解析器,返回 1 表示帧接收完成 */
int lup_feed_byte(uint8_t byte);
/* 取完整帧的指针和数据长度 */
const uint8_t *lup_frame_data(void);
uint16_t lup_frame_len(void);
/* 重置帧解析器 */
void lup_frame_reset(void);
/* --- Process a complete frame (call from main loop context) --- */
void lup_process_frame(const uint8_t *pkg, uint16_t len);
#endif /* __LOOP_UART_PROTO_H__ */

View File

@@ -44,6 +44,17 @@ typedef enum {
#define JSON_CODE_DATA_TOO_LONG 6
#define JSON_CODE_NOT_AUTHED 7
/*===========================================================================
* Pending Loop MCU Command Response (deferred)
*===========================================================================*/
typedef struct {
uint8_t active; // 1 = pending response
uint8_t socket; // TCP socket to reply to
uint32_t msg_id; // Original msg_id
char cmd[32]; // Original command string
uint32_t deadline; // ms deadline for timeout
} TcpJsonPending;
/*===========================================================================
* Externs
*===========================================================================*/
@@ -51,6 +62,7 @@ extern uint8_t g_json_socket_listen; // TCP socket ID (listen + data)
extern TcpJsonAuthState g_json_auth_state;
extern uint32_t g_json_auth_timer; // ms timer for auth timeout
extern uint8_t g_json_pwd_retry; // password retry counter
extern TcpJsonPending g_json_pending; // Pending Loop MCU command state
/*===========================================================================
* API
@@ -58,5 +70,6 @@ extern uint8_t g_json_pwd_retry; // password retry counter
void tcp_json_srv_init(void); // Create listen socket on port 5960
void tcp_json_handle_sock_int(uint8_t socketid, uint8_t intstat); // Socket interrupt handler
void tcp_json_poll(void); // Periodic poll (auth timeout, etc.)
void tcp_json_push_sensor(void); // Push sensor data (0xC0) to TCP client
#endif /* __TCP_JSON_SRV_H__ */