# 协议架构说明 ## 1. 总体边界 小程序按“链路、协议、领域模型、功能服务、页面”分层。页面只做展示和事件转发;协议层只处理帧格式和响应解析;功能服务负责把协议动作组合成业务流程;领域模型负责参数组、结构体、数值编解码等纯数据逻辑。 ```text BLE 透传链路 transport/ble-core.js transport/ble-utils.js transport/ble-logs.js transport/ble-device-registry.js transport/protocol-helper-registry.js 协议层 protocols/modbus-rtu/index.js protocols/storage-access/index.js protocols/bootloader/index.js protocols/transport-helpers.js 领域模型 domain/parameter-groups/ domain/storage-access/code-info-parser.js 功能服务 features/communication/ features/modbus-rtu/service.js features/storage-access/ features/parameter-groups/ features/bootloader/ features/tools/ features/settings/ features/home/service.js 页面 pages/home/ pages/communication/ pages/params/ pages/settings/ ``` 维护原则: 1. 一个协议只保留一个协议入口文件,不再拆 `frame.js`、`request.js`、`response.js` 这类细粒度文件。 2. 功能服务按页面或业务域聚合,只有 UI 状态、协议传输、数据同步边界清晰时才拆分模块。 3. 领域模型可以按“值类型、编解码、结构体解析、参数组规范化”拆分,因为这些逻辑可测试且复用度高。 4. 页面不直接拼协议帧,不直接读写本地存储格式。 5. 设置页的协议模式只保留当前字段 `protocolMode`,不维护历史字段迁移逻辑。 ## 2. 协议模式 协议模式常量由 `domain/protocol-mode.js` 统一定义,当前设置值由 `store/settings-store.js` 持久化维护: | key | 页面名称 | 通讯页显示 | 参数页数据 | |---|---|---|---| | `none` | 无协议 | 串口发送卡片 + 日志 | 不显示协议参数组 | | `storage-access` | 存储访问 | 同步、CodeInfo、特殊指令、读写卡片 + 日志 | 存储访问结构体组/单变量组 | | `modbus-rtu` | 标准 Modbus | 标准 Modbus 指令卡片 + 日志 | Modbus 寄存器组 | 参数组按协议分别存储,切换协议时 `features/parameter-groups/store.js` 会切换当前参数组集合。自动读取/轮询运行时如果检测到协议切换,会停止当前协议的循环,避免用错误协议继续读写。 ## 3. 传输层 目录:`transport/` 职责: - `ble-core.js`:蓝牙扫描、连接、通知订阅、发送队列、响应等待、收发日志、页面订阅。 - `ble-utils.js`:BLE 设备识别、UUID 判断、包长推断、HEX/ArrayBuffer 转换、错误文案。 - `ble-logs.js`:收发日志构造、裁剪和清空。 - `ble-device-registry.js`:扫描设备合并、排序、连接标记和 RSSI 文案。 - `protocol-helper-registry.js`:协议 helper 的懒加载和响应读取函数归一化。 传输层不知道业务含义,只通过 `protocols/transport-helpers.js` 调用当前协议的响应解析能力。 ## 4. 协议层 ### 4.1 标准 Modbus RTU 入口:`protocols/modbus-rtu/index.js` 职责: - 生成标准 Modbus RTU 请求帧。 - 校验 Modbus CRC。 - 解析标准 Modbus 响应和异常响应。 - 计算单帧包长限制下的读取分片。 - 支持功能码 `0x01`、`0x02`、`0x03`、`0x04`、`0x05`、`0x06`、`0x10`。 - 地址和数量按标准 Modbus 寄存器/线圈语义处理。 - 不直接读取设置页从机地址,不直接调用 BLE 发送。 标准 Modbus 不解析 CodeInfo TLV 信息块,也不使用存储访问协议的 `CMD/AREA`。 ### 4.2 存储访问协议 入口:`protocols/storage-access/index.js` 职责: - 普通内存读写使用 `CMD + ADDR + LEN + DATA + CRC16-CCITT-FALSE`。 - `LEN` 固定 16 位,单位始终为字节。 - `CMD bit0~bit2` 区分普通区域:`0x00` 为 CODEINFO 描述符,`0x01..0x04` 为 DATA/IDATA/XDATA/CODE 的 16 位地址,`0x07` 为 32 位地址,`0x05..0x06` 保留。 - `CMD bit3` 为普通读写位,`bit4/bit5` 保留,`bit6` 为特殊指令位,`bit7` 为回帧故障标志。 - 普通区域包括 `CODEINFO`、`DATA`、`IDATA`、`XDATA`、`CODE`、`ADDR32`,其中 `CODEINFO` 和 `CODE` 只读。 - 特殊指令使用 `CMD=0x40 | special_code`,当前仅定义 `special_code=0x01` 复位。 - CodeInfo 同步先发送 `00 + CRC` 读取 `area=0x00 CODEINFO`,获取 `TLV_ADDR32 + TLV_LEN16 + ADDR_WIDTH8 + MAX_PACKET16`,再按 `ADDR_WIDTH` 用 CODE 或 ADDR32 读取完整信息块。 - 协议控制字段始终固定大端;结构体字段和单独变量等目标内存值当前默认按大端编解码。 - 不直接调用 BLE 发送,不负责弹窗;普通内存协议 IO 由 `features/storage-access/protocol-io.js` 编排。 完整帧格式和从机实现参考见 `存储访问协议.md`。 ### 4.3 Bootloader 协议入口:`protocols/bootloader/index.js` 功能服务:`features/bootloader/` 职责: - 保持独立升级协议,不依赖标准 Modbus 或存储访问协议。 - `protocols/bootloader/index.js` 负责 Bootloader 帧构建、CRC、ACK/NAK 和响应解析。 - `features/bootloader/service.js` 负责设置页升级状态、固件加载、握手、擦除、编程、校验流程。 - `features/bootloader/firmware.js` 负责芯片型号识别、Flash 容量推断、固件大小校验和升级地址布局。 - `features/bootloader/transport.js` 负责 Bootloader 原始帧发送、响应等待、断连中止和超时处理。 ## 5. 领域模型 ### 5.1 参数组模型 目录:`domain/parameter-groups/` 职责: - 定义参数组、寄存器、结构体字段、单变量的标准数据结构。 - 规范化地址、数量、读写状态、显示值和来源元数据。 - 支持标准 Modbus 寄存器/线圈组。 - 支持存储访问字节地址组、结构体字段、单变量、数组、bit field。 - 支持原始值到实际值的转换公式。 当前模块: | 文件 | 职责 | |---|---| | `constants.js` | 寄存器类型、数据类型、布局类型、地址上限和导入导出字段白名单 | | `model.js` | 参数组/寄存器规范化、地址布局、显示文案、导入克隆和领域 API | | `register-io.js` | 读缓存解码、写入编码、组级字节/字编码和分片辅助 | | `value-types.js` | 数据类型元数据、字节/字长度、bit field 长度、类型分类 | | `value-number.js` | 整数、HEX、float 的解析、范围校验和格式化 | | `value-text.js` | ASCII/UTF-8 文本字段的编码和解码 | | `value-codec.js` | 寄存器值编解码、显示值和输入校验 | | `value-formula.js` | 读回标幺值到实际值的转换公式求值 | | `struct-parser.js` | C 结构体与 enum 定义解析入口 | | `struct-c-syntax.js` | C 注释剥离、typedef、struct、enum 和 declarator 解析 | | `struct-layout.js` | 结构体字段布局、数组展开、ASCII 字段、enum 映射和 bit field 展开 | ### 5.2 CodeInfo 解析 入口:`domain/storage-access/code-info-parser.js` 职责: - 解析 CodeInfo 纯 TLV 信息块,未知 TLV 类型跳过。 - 使用 CODEINFO 描述符返回的 `TLV_LEN` 决定 CodeInfo 总长度,并使用 `ADDR_WIDTH/MAX_PACKET` 作为同步上下文;内存入口地址宽度和区域由 TLV `TYPE` 自描述。 - 解析 UTF-8/ASCII 电机型号、芯片型号和转换相关可选 TLV 参数。 - 固定 TLV `0x01~0x08` 映射真实存储区域、地址宽度和结构体/变量类型,并按结构体、单独变量成对排列;VALUE 为 `addr(2/4) + byte_len16 + name_len8 + name`。 - `0x20~0x3F` 为自定义 TLV,板卡参数从 `0x40` 开始递增。 - 生成参数组初始结构,结构体未导入定义时按字节占位,单独变量按 TLV `byte_len` 显示为未配置原始字节,后续由 UI 或 enum 导入确定同长度的解释类型。 ## 6. 功能服务 ### 6.1 通讯页服务 目录:`features/communication/` 当前模块: | 文件 | 职责 | |---|---| | `index.js` | 通讯页功能聚合入口,显式导出页面需要的 API | | `manual-rtu.js` | 标准 Modbus 指令表单、写多个寄存器输入、帧生成、发送和响应文案 | | `service.js` | 串口原始发送、存储访问普通读写、特殊指令下发 | | `view-model.js` | 日志展示、串口/存储访问表单状态、协议模式展示状态 | 无协议模式只显示串口发送和日志;标准 Modbus 模式只显示 Modbus 指令;存储访问模式只显示存储访问卡片。 ### 6.2 存储访问服务 目录:`features/storage-access/` 当前模块: | 文件 | 职责 | |---|---| | `protocol-io.js` | 普通内存读写、特殊指令发送、协议分包和设备协议包长 | | `manual-command.js` | 通讯页手动读写表单状态、校验、预览和执行;不暴露 CODEINFO 描述符读取 | | `code-info-sync.js` | 同步按钮触发的 CodeInfo 描述符读取、TLV 信息块读取、解析和参数组导入模型生成 | CodeInfo 读取只从同步流程进入:先读取 `area=0x00 CODEINFO` 描述符,再按 `ADDR_WIDTH` 用 `area=0x04 CODE` 或 `area=0x07 ADDR32` 完整读取信息块。通讯页手动读写只面向 `ADDR32/DATA/IDATA/XDATA/CODE` 普通内存区域。 ### 6.3 标准 Modbus 服务 入口:`features/modbus-rtu/service.js` 职责: - 包装 `protocols/modbus-rtu/index.js` 的帧生成、响应期望和分片能力。 - 读取设置页从机地址,并把地址错误统一转成浮层警告。 - 通过 BLE 发送标准 Modbus 读写命令。 - 聚合分片读取结果,供参数组读取、写入和自动读取复用。 ### 6.4 参数组服务 目录:`features/parameter-groups/` 当前模块: | 文件 | 职责 | |---|---| | `index.js` | 参数页功能聚合入口,显式导出页面需要的 API | | `service.js` | 参数组页面主 API、导入导出、结构体补全、读写调度 | | `store.js` | 参数组状态容器、协议切换、本地持久化、CodeInfo 卡片状态 | | `persistence.js` | 参数组 JSON 导入、导出和按协议本地存储 | | `imports.js` | 导入合并、重复项识别、结构体/enum 定义补全和已有结构保留 | | `io.js` | 标准 Modbus 和存储访问协议的参数组读写实现 | | `poller.js` | 按设置自动读取当前协议的可读参数组 | | `view-model.js` | 参数页展示态和弹窗状态 | | `drag-view-model.js` | 参数页寄存器拖拽排序状态计算 | | `dialog-handlers.js` | 新建/编辑参数组、寄存器信息弹窗、结构体解析交互 | ### 6.5 设置与工具服务 目录:`features/settings/`、`features/tools/` 职责: - 设置页协议模式、主题、蓝牙状态、Bootloader 状态和工具页面状态聚合。 - `protocol-implementation.js` 提供存储访问协议实现说明卡片和文件占位;从机源码暂未提供。 - `features/tools/index.js` 聚合工具入口、工具导航、CRC/哈希、滤波、阻抗、贴片码、制冷、三相功率等工具状态和事件处理器。 - 工具内部按工具域拆分,避免设置页脚本膨胀。 ## 7. 页面职责 ### 7.1 首页 目录:`pages/home/` 职责:蓝牙扫描、连接、断开、设备列表展示。 ### 7.2 通讯页 目录:`pages/communication/` 职责:根据协议模式显示对应通讯卡片和收发日志。 ### 7.3 参数页 目录:`pages/params/` 职责:展示参数组、读取、写入、导入导出、结构体补全、自动读取和拖拽排序。 ### 7.4 设置页 目录:`pages/settings/` 职责:协议模式、从机地址、自动读取间隔、最大包长、协议实现说明、Bootloader 和工具入口。 ## 8. 数据流 ### 8.1 存储访问同步 ```text 用户点击同步 -> pages/communication/communication.js -> features/parameter-groups/service.syncFromStorageAccessCodeInfo -> features/storage-access/code-info-sync.syncCodeInfo -> features/storage-access/code-info-sync.readCodeInfoBlock -> features/storage-access/protocol-io.readMemory -> protocols/storage-access/index.js 构建普通读帧 -> 发送 00 + CRC 读取 area=0x00 CODEINFO 描述符,获得 TLV_ADDR32 + TLV_LEN16 + ADDR_WIDTH8 + MAX_PACKET16 -> 按描述符和设置页最大包长分片读取 CodeInfo TLV 信息块 -> domain/storage-access/code-info-parser.parseCodeInfo -> domain/storage-access/code-info-parser.createGroupsFromCodeInfo -> features/parameter-groups/imports.mergeImportedGroups -> features/parameter-groups/store.setGroups ``` ### 8.2 参数组读取 ```text 手动读取或自动读取 -> pages/params/params.js -> features/parameter-groups/service.readGroup -> features/parameter-groups/io.readGroup -> 标准 Modbus: protocols/modbus-rtu/index.js -> 存储访问: features/storage-access/protocol-io.readMemory -> 读缓存映射回参数组显示态 ``` ### 8.3 参数组写入 ```text 输入完成或点击写入 -> pages/params/params.js -> features/parameter-groups/service.writeRegister/writeGroup -> features/parameter-groups/io.writeRegister/writeGroup -> 标准 Modbus: 单寄存器/多寄存器写入 -> 存储访问: 字节地址写入,bit field 使用读改写 -> 写入快照映射回参数组显示态 ``` ## 9. 维护约束 1. 不再按单个按钮、单个协议动作、单个导入步骤拆零碎模块,优先收敛到当前 feature service 和领域模型文件。 2. 新增协议能力优先放入对应 `protocols/*/index.js` 和对应 feature service,不直接写进页面。 3. 新增参数值类型时,同时更新 `constants.js`、`value-types.js`、`value-codec.js` 和必要的导入导出字段。 4. 新增 CodeInfo 字段时,同时更新 `domain/storage-access/code-info-parser.js` 和 `存储访问协议.md`。 5. 页面只通过 feature 入口或明确 service/view-model 文件调用业务逻辑。