#ifndef VTK_FRAME_H #define VTK_FRAME_H #include "publicdata/public_define.h" #if (POS_VTK_EN) #ifdef __cplusplus extern "C" { #endif #include "main.h" /* VTK 基础协议号(串口模式) */ #define VTK_PD_VMC_TO_POS ((U16_T)0x96FB) /* CCU(VMC) → POS */ #define VTK_PD_POS_TO_VMC ((U16_T)0x97FB) /* POS → CCU(VMC) */ /* 串口帧相关常量 */ #define VTK_FRAME_START_BYTE ((U8_T)0x1F) #define VTK_MAX_APP_LEN ((U16_T)512) #define VTK_MAX_FRAME_LEN ((U16_T)(1 + 2 + 2 + VTK_MAX_APP_LEN + 2)) /* Start + Len + PD + App + CRC */ typedef struct { U16_T protoDisc; /* 协议号:VTK_PD_VMC_TO_POS / VTK_PD_POS_TO_VMC */ const U8_T *pApp; /* 指向应用层 TLV 数据起始地址 */ U16_T appLen; /* 应用层 TLV 数据长度 */ } VTK_FRAME_INFO_T; /* 串口帧打包:把 TLV 应用数据封装为完整 VTK 串口帧 * @param[in] pApp 应用层 TLV 数据指针 * @param[in] appLen 应用层 TLV 数据长度 * @param[in] protoDisc 协议号(通常为 VTK_PD_VMC_TO_POS) * @param[out] pOut 输出缓冲区 * @param[in] outMax 输出缓冲区大小 * @return U16_T 串口帧总长度;0 表示失败(缓冲区不足等) */ U16_T vtk_build_frame(const U8_T *pApp, U16_T appLen, U16_T protoDisc, U8_T *pOut, U16_T outMax); /* 串口帧解析:对一整帧(含 0x1F 起始和 CRC)做合法性校验,并给出应用层 TLV 区段 * @param[in] pFrame 输入帧缓冲区 * @param[in] frameLen 输入帧长度 * @param[out] pInfo 输出解析结果(协议号、应用层指针与长度) * @return U8_T 1=解析成功且 CRC 正确,0=失败 */ U8_T vtk_parse_frame(const U8_T *pFrame, U16_T frameLen, VTK_FRAME_INFO_T *pInfo); /* 流式解析器:用于从串口逐字节接收数据并拼出完整 VTK 帧 */ typedef enum { VTK_PARSE_WAIT_START = 0, VTK_PARSE_LEN_H, VTK_PARSE_LEN_L, VTK_PARSE_BODY, VTK_PARSE_CRC_H, VTK_PARSE_CRC_L } VTK_PARSE_STATE_E; typedef struct { VTK_PARSE_STATE_E state; U16_T lengthField; /* Length 字段值(Protocol Disc + App 长度) */ U16_T index; /* 当前已接收字节数 */ U16_T totalLen; /* 预期整帧长度(含起始和 CRC) */ U8_T buf[VTK_MAX_FRAME_LEN]; /* 内部缓冲区 */ } VTK_FRAME_PARSER_T; /* 初始化帧解析器 */ void vtk_frame_parser_init(VTK_FRAME_PARSER_T *parser); /* 向帧解析器输入 1 字节 * @param[in,out] parser 解析器状态 * @param[in] byte 串口接收到的 1 字节 * @param[out] ppFrame 当返回 1 时,指向完整帧起始地址(内部缓冲区) * @param[out] pLen 当返回 1 时,给出完整帧长度 * @return U8_T 1=拼出完整合法帧;0=尚未完成或校验失败 */ U8_T vtk_frame_parser_input(VTK_FRAME_PARSER_T *parser, U8_T byte, const U8_T **ppFrame, U16_T *pLen); /* 使用示例(发送 + 接收): * * // 发送侧:构造一帧带 TLV 的 VTK 串口报文并通过 UART 发送 * U8_T tlvBuf[VTK_MAX_APP_LEN]; * U16_T tlvLen = 0; * U8_T frameBuf[VTK_MAX_FRAME_LEN]; * U16_T frameLen; * * // 追加 TLV 参数,例如 MessageName(Tag=0x01)="CDP" * vtk_tlv_append_ascii(0x01, "CDP", tlvBuf, sizeof(tlvBuf), &tlvLen); * // 追加 OperationNo(Tag=0x03)="12345" * vtk_tlv_append_ascii_uint(0x03, 12345, 1, tlvBuf, sizeof(tlvBuf), &tlvLen); * // 追加 Amount(Tag=0x04)="5000" * vtk_tlv_append_ascii_uint(0x04, 5000, 1, tlvBuf, sizeof(tlvBuf), &tlvLen); * * // 封装为串口帧并发送 * frameLen = vtk_build_frame(tlvBuf, tlvLen, VTK_PD_VMC_TO_POS, * frameBuf, sizeof(frameBuf)); * if (frameLen > 0U) * { * POS_VTK_UART_SEND(frameBuf, frameLen); // 由上层实现的串口发送函数 * } * * // 接收侧:在 UART 接收中断/任务中逐字节喂入解析器 * static VTK_FRAME_PARSER_T s_parser; * static U8_T parserInited = 0; * * if (!parserInited) * { * vtk_frame_parser_init(&s_parser); * parserInited = 1; * } * * void UART_Rx_Handler_Byte(U8_T rxByte) * { * const U8_T *pFrame; * U16_T frameLen; * * if (vtk_frame_parser_input(&s_parser, rxByte, &pFrame, &frameLen)) * { * // 这里获得了一整帧 VTK 报文,可继续调用 vtk_parse_frame / vtk_parse_payment_response 解析 * } * } */ #ifdef __cplusplus } #endif #endif /* POS_VTK_EN */ #endif /* VTK_FRAME_H */