920bddf949
Cat1通信稳定性: - 新增空闲5分钟无上传自动断开重建TCP保活(只建链不上传, exe端客户端列表自动刷新) - 注册超时不再重启模组(兼容网络调试助手等不回注册应答的对端), 连接自愈由LIPSEND失败与空闲重连兜底 - 日志流分离: 调试回应(Debug_Printf)经duchRing透传, 系统级rt_kprintf日志固定走RS485 Ch1, 消除trace/AT应答自激灌环 通道分流重构(USART1固定接Cat1): - much/auch/duch/cuch恢复按配置分流; dbg通道选项从全部配置命令删除(ParseChannel/帮助文本/CH_DBG互斥残留) - 下行分流规则: 0x7D升级帧第一优先(NetUpgradeFeed), 0x7A业务帧按Much/Auch回调, 其余明文直通DebugAnalyze - Cat1升级不受分流限制: 无论Cat1配置在哪个通道均可响应0x81握手与完整升级会话 - 删除DUCH_MODE独占透传状态(duch=cat1纯调试统一走WAIT_SEND), 删除CAT1_ERR_RESET_DLY_MAX(1小时空闲重启由5分钟TCP重连替代) 远程调试命令链路: - 服务端明文/hex命令经Cat1下行直通DebugAnalyze执行, 兼容带/不带\r\n(修复strlen<rLen误判截断URC丢弃) - LIPURC解析增加Cat1IsHexText合法性校验(修复AsciiToHex对非hex明文静默产出乱码绕过直通分支) - 命令回应经QISEND明文直发(网络调试助手可读, 发送前等URC流静默防吞), 升级应答帧保持LIPSEND hex(exe协议不变) 注释与编码治理: - 全工程C/H文件统一UTF-8: CatOneATCmdStr 10处历史乱码注释还原为正确中文 - DebugCmd.c 35处函数头乱码注释(U+FFFD固化)从git 314ff67历史按函数名恢复, 5个新增函数注释按实现补写 - 修正错位/错误描述: DebugCmdTimeSync(系统时间同步)/DebugCmdRegister(重新注册)/DebugCmdCat1OnOff(调试开关)/DebugCmdSetCollectTime等4处按实际功能重写, 低功耗错别字修正 - 修复CatOneATCmdStr[16]数组17元素越界且CAT_ONE_CCLK索引错位(时间同步从未生效), 扩容[17]并归位 升级模块(承接f206b8f联调结论): - TX队列rt_hw_interrupt_disable/enable关中断临界区(修并发越界HardFault) - 断点续传永久取消(每次点击升级从0全新下载); 升级启动/完结均清进度记录(扇区4037) - 暂存区按需擦除NupErasedMap(修二次升级NOR脏位损坏); 0x7D帧头MAC与本机不一致丢弃(防串台) - AsciiToHex长度参数uint8->uint16(修432字符帧截断)
86 lines
7.1 KiB
Markdown
86 lines
7.1 KiB
Markdown
# Cat1 远程升级方案设计(待评审)
|
||
|
||
## 总体架构
|
||
|
||
App 扮演"接收端"角色(与 Boot 在 RS485 升级中的角色相同),服务器扮演升级主机:
|
||
|
||
```
|
||
服务器(升级主机) --TCP--> 合宙Cat1模组 --USART1--> App(RT-Thread)
|
||
│ ├─ 收0x7D帧(0x81/0x82) → 固件分包写外部SPI Flash暂存区
|
||
│←────────── 0x01 ACK(带进度) ──────────────┤
|
||
│ └─ 收完→CRC32校验→置UpdateFlag=APP_UPDATE_SPI_FLAG→复位
|
||
复位
|
||
└→ Boot: 检测APP_UPDATE_SPI_FLAG
|
||
→ SPI Flash逐扇区读 → 写内部B区 → CRC32(B)
|
||
→ 搬运B→A → CRC32(A) → 擦SPI Flash暂存区 → 置完成标志 → 复位跳App
|
||
```
|
||
|
||
**升级协议完全复用 RS485 的 0x7D 帧**:帧头 0x7D + DevMac(6) + Cmd(1) + PayloadLen(1) + Payload + CRC16(Modbus),命令 0x81 升级请求{PackageNum, AppSize, AppCrc32} / 0x82 数据{PackageIndex, PackageNum, DataLen, Data[200]} / 0x01 ACK / 0x02 请求数据。服务器端协议不变。
|
||
|
||
## 关键决策与理由
|
||
|
||
1. **Boot 不驱动 Cat1**:AT 注网 30 秒起、Boot 仅 32KB 分区(当前 Code 16KB)、模组 TCP 连接态在 MCU 复位后不可控。收包/重试/续传等复杂逻辑全部放 App(RTOS 资源丰富),Boot 只做"从外部 Flash 搬运到 B 区"这一简单确定性动作。
|
||
2. **固件暂存外部 SPI Flash**:16MB 尾部划 58×4KB=232KB 暂存区(扇区 4038~4095),日志环形写入回绕点同步从 16MB 末尾前移到扇区 4038。
|
||
3. **复用 UpdateFlag 机制**:新增标志值 `APP_UPDATE_SPI_FLAG`(建议 0xA5A55A5A,与现有 START=0x55AA5A5A / UPDATE=0xA5A5AA55 / BOOT_UPGRADE=0x5A5A55A5 不冲突),`boot_para_t` 结构不变,RS485 本地升级路径完全不受影响。
|
||
4. **依赖 TCP 可靠有序**:应用层丢包仅发生在断连/模组重启,因此用"断点续传 + 超时重发请求"而非滑动窗选择重传,状态机与 Boot 版本同构,服务器实现简单。
|
||
|
||
## 升级流程(含 Cat1 特化处理)
|
||
|
||
1. 服务器 → `0x81{PackageNum, AppSize, AppCrc32}`
|
||
2. App 校验 DevMac/合法性(AppSize==0 或 >232KB 拒绝)→ 回 `0x01 ACK`:
|
||
- 载荷建议扩展为 `{Status, ResumedIdx}`:`0x20`=全新开始(App 擦暂存区)、`0x21`=断点续传(已收 ResumedIdx 包,服务器从该包续发)。**注意:原 0x01 载荷 1 字节(0x20),扩展为 3 字节需服务器端同步适配(新版本服务器)**
|
||
3. 服务器从 ResumedIdx 起发 `0x82{PackageIndex, ...}`:
|
||
- **流控(推荐窗口式)**:服务器连发 W 包(建议 W=8~16)→ App 校验 PackageIdx 顺序写入暂存区(乱序/重复包丢弃)→ App 主动发 `0x02{期望包号}` → 服务器继续。停等式(每包一问一答)在 Cat1 上太慢:1160 包 × RTT≈2~5 分钟+,窗口式约 30~60 秒
|
||
- TCP 保证有序,App 端只需顺序校验 + 期望包号判定
|
||
4. App 收完 → `CRC32(暂存区, AppSize)`:
|
||
- 通过 → 回 `0x01{0x30 完成}` → 写 boot_para_t{AppSize, Crc32Check, UpdateFlag=APP_UPDATE_SPI_FLAG} → 200ms → 复位
|
||
- 失败 → 回 `0x01{0x31 CRC错}` → 不复位,清暂存区等待服务器重发(可多次)
|
||
5. Boot 检测 `APP_UPDATE_SPI_FLAG` → 逐 8KB:读外部 2×4KB 扇区 → 擦写内部 B 区 1×8KB 扇区 → `CRC32(B)` → `CopyAppBtoA()`(现有)→ `CRC32(A)` → **擦外部暂存区(防残留误判,同 RS485 路径 B 区擦除教训)** → 置 `APP_BOOT_UPGRADE_FLAG` → 复位跳 App
|
||
6. App 启动(`APP_BOOT_UPGRADE_FLAG`)→ 擦外部参数分区 → 上线后服务器可查版本确认升级成功
|
||
|
||
### 超时与重试参数(Cat1 特化,均为 App 侧状态机)
|
||
|
||
| 参数 | Boot RS485 值 | Cat1 版建议 | 理由 |
|
||
|------|--------------|------------|------|
|
||
| 等包超时 | 500ms | **3 秒** | Cat1 RTT + 模组缓冲 |
|
||
| 重试次数 | 3 | **5** | 偶发断连需模组重连 |
|
||
| 断连恢复 | — | 模组重连(现有逻辑)后服务器重发 0x81,ACK 带进度续传 | TCP 断开后应用层无从补偿 |
|
||
| 整体超时 | — | 30 分钟无进展 → 放弃升级(清标志,不复位) | 防止无限等待 |
|
||
|
||
### 断电自愈矩阵(Cat1 路径)
|
||
|
||
| 断电/异常时机 | 恢复行为 |
|
||
|--------------|---------|
|
||
| App 收包中断连/断电 | 暂存区+进度保留 → 重连后 0x81 续传 |
|
||
| App 置标志后、复位前 | Boot 正常走 SPI Flash→B→A |
|
||
| Boot 搬运中(写B区)断电 | UpdateFlag 仍为 SPI_FLAG → B 区 CRC 有效则重搬;无效则清标志回老 App |
|
||
| 搬运完、擦暂存区中断电 | 参数未写 → B CRC 判定重搬(B 仍在);参数已写 → 跳新 App |
|
||
|
||
## 改动清单
|
||
|
||
### App(GateWay 工程)
|
||
| 文件 | 改动 |
|
||
|------|------|
|
||
| `spiflash.h/c` | 新增 `FLASH_FW_STASH_BASE`(扇区 4038 起)+ StashErase/StashWrite/StashRead;`AddLog` 回绕点 16MB→扇区 4038;新增 CRC32(与 Boot GetCrc32 同算法 0xEDB88320) |
|
||
| `CatOneTask.c`(或新文件) | Cat1 通道增加 0x7D 帧组帧解析(`+LIPURC` hex→二进制后按 0x7D 组帧,与现有 0x7A 链路并存,按帧头区分);升级接收状态机(移植 Boot AnalyzeData+BL 状态机,超时/重试参数按上表) |
|
||
| `Update.c` | 新增 `UpdateFromStash()`:写 boot_para_t(APP_UPDATE_SPI_FLAG + AppSize + Crc32Check)→ 复位 |
|
||
| `bsp.h`(App) | `APP_UPDATE_SPI_FLAG` 宏;`boot_para_t` 不动 |
|
||
| `main.h`(App) | 版本号随迭代递增 |
|
||
|
||
### Boot(HC32F460BootLoader 工程)
|
||
| 文件 | 改动 |
|
||
|------|------|
|
||
| `bsp.c/h` | SPI Flash 驱动:与 App 相同总线(需确认外部 Flash 挂载的 SPI 外设与引脚,Boot 复用),W25Q 写使能/扇区擦/页读命令;约 +2~3KB(Boot 当前 16KB,32KB 分区内余量足够) |
|
||
| `main.c/h` | `APP_UPDATE_SPI_FLAG` 宏 + main() 决策分支(SPI_FLAG → 新状态 `BL_STASH_TO_B`);`BL_STASH_TO_B`:逐 8KB 外部读→B 区写→CRC(B) 通过进 `BL_COPY_TO_A`(现有),失败清标志回老 App;`BL_COPY_TO_A` 成功分支追加"擦外部暂存区" |
|
||
|
||
### 服务器端(不在本仓库,需同步开发)
|
||
- 实现 0x81/0x82 升级主机逻辑:窗口流控(W 包一批)、解析 0x02 期望包号、断点续传(ACK 的 ResumedIdx)、完成/失败状态处理
|
||
|
||
## 风险与待确认项
|
||
|
||
1. **调试口与 Cat1 共用 USART1(PB08 方向切换)**:升级期间必须保证 UART 方向锁定在 Cat1 侧(`CAT1_ON()`),升级状态机运行期间禁止调试打印切向(`U_DBG_LOG` 若触发 `DBG_ON()` 会破坏 TCP 数据)。实施时需审查 DEBUG=1 下所有升级路径的打印。
|
||
2. **外部 Flash 挂载总线待确认**:读 spiflash.c 确认 SPI 外设号/引脚/QSPI 模式,Boot 驱动按此实现。
|
||
3. **日志区历史数据**:回绕点前移到扇区 4038(约 15.77MB),已存历史日志超出的部分会被覆盖——现网日志增长慢,实际影响小,但需知晓。
|
||
4. **0x01 ACK 载荷扩展**(1→3 字节)需服务器端配合,若服务器不改动则退化为停等式流控(慢但兼容)。
|
||
5. **升级流量**:232KB/次,Cat1 资费可忽略。
|