Files
wandering1 8744c833e5 docs(屏板链路): 规划文档收编为设计说明事实源,全仓引用与端口口径同步
- 重写 docs/子系统设计/屏板链路设计说明.md:链路角色、串口与端口配置、
  物理接线、协议实现口径、键值与状态灯映射、资源与耗时、对外接口、
  已验证/未闭环、坑账本——只写现状事实,演进过程查 git 历史
- 删除 docs/任务规划/屏板链路.md(内容已全部沉淀进上述设计说明,
  登记簿「完成即销项」;docs/任务规划/README.md 相应两行一并移除)
- 代码与主机侧测试的文档指针改指设计说明对应章节:
  sb_link.h/.c、sb_proto.h/.c、sb_led_map.h、console_log.c、ui_task.c、
  test/host 的 sb_link/sb_proto/sb_led_map 三套与两个台架脚本
- docs/README.md:设计文档索引行与设计说明描述更新,任务规划目录 7→6 文件
- docs/产品需求/产品需求设计文档.md:串口通道现状口径同步——第 11/12/13 条
  已交付(4208 B 应答/状态灯掩码/键上行/双出口并发)、LOGO 下发出局不实现、
  帧长实测固化、调试日志口 UART5/RS232#1(§4.2/§5.16/§6.6/§9.12/§9.13)
- docs/子系统设计/控制台单写者日志设计说明.md v1.8:全文端口口径由
  USART1 同步为 UART5/RS232#1(CON_UART* 单点宏),ORE 机理标注跨端口
  同因,时间线补端口迁移行;头部修订指针改为实际章节名

说明:本任务经用户显式授权在任务树内编辑 docs/任务规划/ 与产品需求基线
(铁律「单写者」豁免一次);主树合并后统一跑全量 check_doc_links --all。
2026-10-30 09:22:44 +08:00

167 lines
10 KiB
C
Raw Permalink 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.
/*
* 模块名称:屏板链路协议层(帧 A 解析 / 帧 B 组帧 / CRC-16)
* 模块功能:把「主机与屏板之间那两种帧」的编解码收成一处纯逻辑:
* - CRC-16/MODBUS(表与屏板固件逐字节一致,见 Drivers/BSP/ScreenLink/sb_proto.c)
* - 帧 A(屏板 → 主机,固定 6 B)解析:校验后吐出「命令类型 + 按键值」
* - 帧 B(主机 → 屏板,固定 4208 B)组帧:普通图(LED 掩码)/ LOGO(宽高 + 魔数)
* - 帧 B 自校验(组完立刻能验,供组帧路径自查)
* 本模块**不碰寄存器、不碰 DMA、不碰任务**:串口怎么配、谁来发、什么时候发都不归它管
* (那是 sb_link 与传输层的事)。
* 适用平台:STM32F4 系列(ARMCC v5);不依赖 HAL,主机侧可直接编译(故可主机单测)。
* 作者:王建锋
* 创建日期:2026-10-29
* 修改记录:
* 2026-10-29 王建锋 创建:按屏板固件 D:\Code\DTU Code\DTU-LCD 的 CRC16.c / MODBUS.c 逐字节对齐
*
* 协议事实源:屏板固件工程(不在本仓库)
* Middlewares/Modbus/CRC16.c —— 两张 256 字节查表 + Calculate_CRC() / Check_CRC()
* Middlewares/Modbus/MODBUS.c —— RS485_RefreshScreenCMD()(帧 A 组帧,6 B)
* RS485_Process()(帧 B 解析:3200 点阵 + 8 字节 info + CRC 在帧尾)
* Drivers/BSP/RS485/rs485.h —— UART_RX_LEN = 4208(帧 B 的线上长度,注释写 3208 是错的)
* 需求侧口径见 docs/产品需求/产品需求设计文档.md §5.16.2(帧结构)与 §5.16.3(按键枚举)。
*
* ⚠ 两个长度别混:屏板 `BMP_LEN` 的 3208 是**写 Flash 的记录长度**(点阵 3200 + 宽 4 + 高 4),
* 不是帧长;帧长以 `Check_CRC(..., UART_RX_LEN)` 的 **4208** 为准。本模块只认 4208。
*/
#ifndef SB_PROTO_H
#define SB_PROTO_H
#include <stdint.h>
#include "bsp_err.h" /* bsp_err_t / BSP_OK / BSP_ERR_*:本模块只报统一错误码 */
#ifdef __cplusplus
extern "C" {
#endif
/* ============================================================================
* 一、帧长与字段偏移(单一出处,别在调用方另抄一份)
* ==========================================================================*/
/* 帧 A:屏板 → 主机,固定 6 B。CRC 只覆盖前 4 B,高字节在前。 */
#define SB_FRAME_A_LEN (6U)
#define SB_FRAME_A_CRC_OFF (4U)
/* 帧 B:主机 → 屏板,固定 4208 B。CRC 覆盖 [0, 4205],高字节在前。 */
#define SB_FRAME_B_LEN (4208U)
#define SB_FRAME_B_BMP_LEN (3200U) /* 点阵:160 行 x 20 B/行,1 bpp,MSB 在前 */
#define SB_FRAME_B_INFO_LEN (8U) /* info[0..7] */
#define SB_FRAME_B_INFO_OFF (3200U)
#define SB_FRAME_B_PAD_OFF (3208U) /* 保留填充起点 */
#define SB_FRAME_B_PAD_LEN (998U) /* [3208, 4205]:屏板不读,但参与 CRC,须固定填 0 */
#define SB_FRAME_B_CRC_OFF (4206U)
/* 帧 A 的固定字段值 */
#define SB_ADDR (0x01U) /* 从站地址:**主机的地址**,不是屏板的 */
#define SB_FUNC_READ_HOLDING (0x03U) /* 功能码:读保持寄存器 */
#define SB_CMD_KEY (0x00U) /* 命令类型:按键事件(立即召唤) */
#define SB_CMD_RT (0x01U) /* 命令类型:周期刷新 */
/* 帧 B 的 LOGO 魔数(info[4] / info[5])
* ⚠ 待删除(用户裁定 2026-10-29):LOGO 功能出局,不下发、不接线;本组
* LOGO 常量与 sb_frame_b_build_logo() 保留仅为协议层完整性,**勿新增调用**。 */
#define SB_LOGO_MAGIC_HI (0x89U)
#define SB_LOGO_MAGIC_LO (0x45U)
/* 屏幕几何:LOGO 的宽高要在这一片点阵装得下 */
#define SB_SCREEN_W (160U)
#define SB_SCREEN_H (160U)
/* ============================================================================
* 二、帧 A 的解析结果
* ==========================================================================*/
/* 解析成功后的有效字段。addr / func 恒为 SB_ADDR / SB_FUNC_READ_HOLDING,
* 不再回吐(校验不过直接报错,能走到这里就一定是这两个值)。 */
typedef struct
{
uint8_t cmd; /* SB_CMD_KEY / SB_CMD_RT */
uint8_t key; /* cmd == SB_CMD_KEY 时有效;cmd == SB_CMD_RT 时恒为 0(见 sb_frame_a_parse 说明) */
} sb_frame_a_t;
/* ============================================================================
* 三、公开接口
* ==========================================================================*/
/*
* 函数功能:计算 CRC-16/MODBUS(多项式 0xA001 反转式、初值 0xFFFF、查表法)
* 入口参数:p_data - 待校验数据首地址
* len - 参与校验的字节数(不含 CRC 本身)
* 返回值:16 位**标准 CRC-16/MODBUS 值**(教科书校验值:数据 "123456789" → 0x4B37)
* 限定条件:p_data 必须非空且 len >= 1;本函数是纯算术,不做空指针检查(与相量系纯算法函数同口径)。
* 写进帧里一律**低字节在前**——屏板固件那个同名函数返回的是高低互换后的「线上字」,
* 两处命名都是反的,但线上字节是对的。陷阱与实测向量见 sb_proto.c 文件头,改前务必看。
* 函数说明:查表法而非逐位法。帧 B 一次要算 4206 B:逐位法约 13 万拍(毫秒量级),
* 查表法约 2.5 万拍(0.15 ms 量级,168 MHz 估算),后者才留得住 2-1 的 0.3 ms
* 组帧预算——而那份预算还要分给 3200 B 的点阵拷贝,2-1 实测时两者要一起算。
*/
uint16_t sb_crc16(const uint8_t *p_data, uint16_t len);
/*
* 函数功能:解析一帧帧 A(屏板发来的 6 B 召唤 / 按键帧)
* 入口参数:p_buf - 收到的字节首地址
* len - 收到的字节数(空闲中断断出来的实际长度)
* p_out - 解析结果输出(成功时写 cmd / key,失败时不改)
* 返回值:BSP_OK 解析成功,*p_out 有效
* BSP_ERR_CRC CRC 不符:帧被破坏,应计数后静默丢弃(不要回任何东西)
* BSP_ERR_PARAM 不是一个合法的召唤帧:指针空 / len != 6 / 地址不是 0x01 /
* 功能码不是 0x03 / 命令类型不是 0 或 1 —— 丢弃即可,不必计数
* 限定条件:只认固定 6 B 的帧 A;屏板的帧 B 应答方向相反,不经过本函数。
* 函数说明:
* 1. **先校 CRC 再看字段**:CRC 不过说明字节已经乱了,再去解释地址/功能码没有意义。
* 2. 地址与功能码不符也报 BSP_ERR_PARAM 而不是新造错误码——bsp_err.h 的码是跨模块的
* 「能不能重试」语义,不是协议细节;对调用方而言这几种都等于「这不是给本机的合法召唤帧」。
* 要区分细节就比对原始字节(屏板这两个字段是写死的,出现不符说明已经错位)。
* 3. cmd == SB_CMD_RT 时若 key 非 0 **不报错**,按 0 忽略:屏板的周期召唤本应带 0,
* 但为这一项丢一帧就等于丢一次刷新(280 ms 的画面不动),代价不对等。
*/
bsp_err_t sb_frame_a_parse(const uint8_t *p_buf, uint16_t len, sb_frame_a_t *p_out);
/*
* 函数功能:组一帧帧 B「普通图」(点阵 + 32 位 LED 掩码)
* 入口参数:p_frame - 输出缓冲,长度必须 >= SB_FRAME_B_LEN
* p_bmp - 点阵源,长度必须 >= SB_FRAME_B_BMP_LEN(160x160 @1bpp)
* led_mask - 状态灯位掩码,小端填进 info[0..3](info[0] = bit0..7)
* 返回值:BSP_OK 组帧完成,整帧(含 CRC)已就绪
* BSP_ERR_PARAM 指针为空
* 限定条件:p_frame 会被**整帧重写**(含 998 B 填充与 CRC),调用方不必预先清零;
* 组好的帧在下次调用前有效,本模块不持有任何缓冲。
* 函数说明:填充段固定填 0x00(屏板不读,但参与 CRC)。掩码的位语义不归本模块管
* (bit0 恒 0 / bit20~31 恒 0 这类业务约束属状态灯映射表,见任务规划批 3)。
*/
bsp_err_t sb_frame_b_build_image(uint8_t *p_frame, const uint8_t *p_bmp, uint32_t led_mask);
/*
* 函数功能:组一帧帧 B「LOGO」(点阵 + 宽高 + 魔数 0x89 0x45)
* 入口参数:p_frame - 输出缓冲,长度必须 >= SB_FRAME_B_LEN
* p_bmp - 点阵源,长度必须 >= SB_FRAME_B_BMP_LEN
* width - 图片宽度(像素),大端填进 info[0..1]
* height - 图片高度(像素),大端填进 info[2..3]
* 返回值:BSP_OK 组帧完成
* BSP_ERR_PARAM 指针为空 / 宽高为 0 / 超出 160x160 点阵容量
* 限定条件:宽高必须满足 ((width + 7) / 8) * height <= 3200 —— 屏板拿这两个数直接显示,
* 装不下的宽高会让它读越 3200 B 的点阵缓冲,故本函数按字节数而非像素数判容量。
* 函数说明:LOGO 帧会把屏板 Flash 0x0803F000(扇区 126)整块覆盖,且屏板不校验是否同一张图;
* 本模块只负责把帧组对,**什么时候发、能不能重复发由调用方决定**。
*/
bsp_err_t sb_frame_b_build_logo(uint8_t *p_frame, const uint8_t *p_bmp, uint16_t width, uint16_t height);
/*
* 函数功能:自校验一帧帧 B(重算 CRC 并与帧尾比对)
* 入口参数:p_frame - 待校验帧首地址
* len - 帧长度,必须等于 SB_FRAME_B_LEN
* 返回值:BSP_OK CRC 与帧尾一致
* BSP_ERR_CRC 不一致(帧被改写 / 组帧时漏算)
* BSP_ERR_PARAM 指针空或 len 不是 4208
* 限定条件:只验 CRC,不检查填充段是否全 0、也不检查掩码位语义。
* 函数说明:给组帧路径自查用(2-4 的「组帧自校验 100%」直接接这里)。
*/
bsp_err_t sb_frame_b_verify(const uint8_t *p_frame, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif /* SB_PROTO_H */