8 Commits

Author SHA1 Message Date
YuanHongbin 8dfd6a6182 chore(version): 软件版本小版本迭代 V1.4 -> V1.5
ETH口升级兼容方案打通及升级链路收尾, 软件版本随本次功能迭代升级到V1.5
2026-10-12 10:44:57 +08:00
YuanHongbin 5db05d061b feat(ota): ETH口升级兼容方案与升级链路收尾, 软件版本V1.4
- ETH口参考Cat1接入0x7D升级: 下行IsHexText校验/NetUpgradeFeed第一优先/明文直通DebugAnalyze, 升级应答帧主循环最顶部直发
- 升级TX应答队列按通道绑定(TxChan/CurCh): Cat1/ETH各自取回本通道ACK, 双链路互不抢占
- ETH接收改为8KB单生产单消费环形缓冲: 修复IRQ与Rev线程单缓冲竞态丢包
- 升级会话期间ETH状态机旁路: 防RESET/OFF复位模组断链; 会话内纯hex流模式(奇数尾字符跨块拼接)
- Public: IsHexText公共化(Cat1/Eth共用), AsciiToHex内部计数器uint16修复(512字符块溢出丢帧)
- Cat1: 升级帧带CH_CAT1通道标签, 空闲5分钟保活重连只建链不上传
- 移除全部[ETHDBG]调试打印, 新增MAC不匹配提示日志
2026-10-12 10:24:44 +08:00
YuanHongbin 920bddf949 feat(cat1): 空闲保活重连/通道分流重构/远程调试命令链路, 注释编码统一UTF-8
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字符帧截断)
2026-10-10 14:14:16 +08:00
YuanHongbin 314ff67f26 chore(ide): 提交Keil调试器配置与Boot A/B分区升级方案文档 2026-09-23 11:22:02 +08:00
YuanHongbin 6d4aad164b chore(version): 软件版本小版本迭代 V1.3 -> V1.4 2026-09-23 11:22:02 +08:00
YuanHongbin b1cba74aa7 feat(app): 配合Boot A/B分区升级, 链接区限定A区232KB
bsp.h分区宏改A区29扇区+新增B区宏(FLASH_BINFO_BASE仍=0x7C000); GateWay_app.sct IROM 0x74000→0x3A000;
Update()增加AppSize<=FLASH_APPB_SIZE校验, 超限拒绝不置标志不复位
2026-09-23 11:16:55 +08:00
YuanHongbin 2cf17c4387 fix(stack): 增大Lora/LoraIRQ线程栈至2048并启用栈溢出检测
0x0020类型设备数据含float字段,DebugDisplaySensorData中%06f格式
触发ARMCC完整FP printf路径(vsprintf->_printf_fp_dec->btod),仅此调用链
需~1252B栈空间,而Lora线程栈仅1024B导致栈溢出踩踏堆中定时器链表节点,
rt_list_remove在_rt_timer_remove中崩溃.增大栈至2048并启用
RT_USING_OVERFLOW_CHECK提前检测溢出.
2026-09-18 17:39:04 +08:00
YuanHongbin e23a0d01ae feat(lora): 宽频信道表扩展为120信道(433.1MHz~492.6MHz)
- sx127x.h: 信道宏CH0~CH119, 基准433100000ul+500kHz步进(CH0=433.1MHz, CH119=492.6MHz)
- sx127x.h: SX1276_CHANNEL_MAX 46 -> 120, LoraSetChannel范围检查自动跟随
- sx127x.c: gdwSx1276ChannelTbl信道表扩为120项
- sx127x.c: LoraSetFreqCent频率校验范围改为433.1MHz~492.6MHz(原470.1下限会拒绝CH0~CH73)
- main.c: 频率校验失败回退默认值改为CH0(433.1MHz)
- 注意: 信道号与窄频版(develop)语义不同, 同编号对应不同频率, 两种固件设备互不相通
- 默认信道CH8在宽频下为437.1MHz
2026-09-08 10:21:32 +08:00
24 changed files with 1271 additions and 382 deletions
+112
View File
@@ -0,0 +1,112 @@
# Boot A/B 分区升级改造计划
## 背景
当前 Boot 升级流程:收到 0x81 升级请求后复位 → **先整片擦除 App 区(0x8000\~0x7C000, 58扇区)** → 逐包(200字节)边收边写 → 收完才做 CRC32 整包校验 → 失败/超时仅清标志,但 App 区已被擦除,**设备变砖只剩 Boot**。
改造目标:App 区分 A/B 两区。新固件先下载到 B 区暂存,**整包 CRC 校验成功后才搬运到 A 区**;任何失败(CRC 错/下载超时/断电)都能回到 A 区原有 App,彻底消除变砖风险。RS485 协议(0x81/0x82/0x01/0x02 帧)不变,主机升级工具无需修改。
## 新 Flash 分区(512KB = 64 扇区 × 8KB)
| 分区 | 地址范围 | 扇区数 | 说明 |
| ---------- | ---------------- | -------------- | --------------------------- |
| Boot | 0x00000\~0x07FFF | 4 (32KB) | 不变,MAC 常量 0x4000 不受影响 |
| **A区(运行)** | 0x08000\~0x41FFF | **29 (232KB)** | App 链接基址仍为 0x8000 |
| **B区(暂存)** | 0x42000\~0x7BFFF | **29 (232KB)** | 升级包下载区 |
| 参数区 | 0x7C000\~0x7DFFF | 1 | 不变,boot\_para\_t 结构**完全不变** |
| 备用 | 0x7E000\~0x7FFFF | 1 | 不变 |
App 当前实际 113KB,A/B 各 232KB 有约一倍余量。断电状态全部由 `UpdateFlag + AppSize + Crc32Check + B区CRC实测` 推导,**无需新增参数字段**。
## 新升级状态机
```
main() 决策(不变): AppFlag==START/BOOT_UPGRADE→跳A | UpdateFlag==UPDATE→BL_ERASE_FLASH | 其他→BL_IDLE
BL_ERASE_FLASH(改):
AppSize非法(==0 或 >232KB) → AppFlag=START_FLAG/UpdateFlag=0 → BL_RESET(回老App)
GetCrc32(B区, AppSize)==Crc32Check ? ──是(断电续传:已下载完/搬运中断电)──→ BL_COPY_TO_A
└─否→ 仅擦B区29扇区 → BL_GET_DATA(逐包写B区) → 收完 ↓
0x82 收完全部包(改):
CRC32(B区,AppSize)==Crc32Check ?
├─是→ UpDateFlag=false → BL_COPY_TO_A
└─否→ AppFlag=APP_START_FLAG / UpdateFlag=0 → 写参数 → BL_RESET (回老App, 原来是BL_IDLE变砖)
BL_COPY_TO_A(新增):
按 ceil(AppSize/8K) 扇区数逐扇区: FeedDog → 擦A扇区 → 从B读8KB到RAM缓冲 → FlashWrite写A
→ CRC32(A区,AppSize)==Crc32Check ?
├─是→ AppFlag=APP_BOOT_UPGRADE_FLAG / UpdateFlag=0 → 写参数 → BL_RESET → 跳A
└─否→ CopyRetryCnt<1 重试搬运; 仍失败→ AppFlag=0/UpdateFlag=0 → BL_IDLE
BL_GET_DATA_TIMEOUT(改): 重试3次耗尽 → AppFlag=APP_START_FLAG / UpdateFlag=0 → BL_RESET(回老App, 原来是BL_IDLE)
```
断电自愈覆盖:①下载中断电→重启 B 校验失败→重新下载;②搬运中断电→A 残缺但 B 仍有效→重启自动重搬;③擦 A 前提是 AppFlag=0 且 Boot 不会在 UpdateFlag 置位时跳转,无跳半擦区风险;④0x81 写参数中断电→参数区 0xFF→走 FirstRunFlag 分支跳 A,老 App 完好。
## Boot 工程改动(d:\keilProject\hc32f460\git\hc32f460bootloader)
**bsp.h**(分区宏,L194-206):
* `APP_A_ADDRESS = FLASH_BASE + BOOT_SIZE` (0x8000)、`APP_BANK_SECTORS 29u`、`APP_BANK_SIZE = 29*8K` (232KB)、`APP_B_ADDRESS = APP_A_ADDRESS + APP_BANK_SIZE` (0x42000)、`APP_ADDRESS` 保留别名指向 A 区、`BOOT_PARA_ADDRESS = APP_B_ADDRESS + APP_BANK_SIZE` (0x7C000 不变)
**main.h**:
* 枚举加 `BL_COPY_TO_A`;`BootLoader_t` 加 `uint32_t CopyRetryCnt`
**bsp.c**:
* `FlashWrite`/`FlashRead` 长度参数 `uint8_t` → `int`(8KB 整扇区 2048 字超出 uint8\_t,评审发现 P2)
* `FlashWrite` 尾部不足 4 字节时按 0xFF 补齐组字写入(防 AppSize 非 4 对齐时丢尾字节导致 CRC 永败)
* `EraseFlash()` 参数化为擦指定起始地址+扇区数(现仅用于擦 B 区 29 扇区,不再碰 A 区)
**main.c**:
* `GetCrc32(int dwLen)` → `GetCrc32(uint32_t BaseAddr, int dwLen)`(现有 L50 固定读 APP\_ADDRESS)
* `AppWriteFlash` 加基址参数,下载包写入 `APP_B_ADDRESS + offset`
* `AnalyzeData`:
* 0x81 分支:加 AppSize 合法性拒绝(>232KB 或 0 时忽略)
* 0x82 分支:加状态守卫 `Status 必须为 BL_GET_DATA/BL_WAIT_REV`(评审发现 P1:防迟到包破坏搬运期 B 区);收完 CRC 改算 B 区,成功→`BL_COPY_TO_A`,失败→恢复 START\_FLAG→BL\_RESET
* `BootLoaderLoopHandler`:`BL_ERASE_FLASH` 改为先校验 B 区(断电续传入口);新增 `BL_COPY_TO_A` case(调 CopyAppBtoA);`BL_GET_DATA_TIMEOUT` 耗尽改恢复 START\_FLAG+BL\_RESET
* 新增 `CopyAppBtoA()`:main.c 内实现,`static uint32_t s_CopyBuf[2048]`(8KB),逐扇区 EFM\_SectorErase(A)+读 B 缓冲+FlashWrite(A),每扇区 FeedDog,结尾 CRC32(A) 校验返回 bool
## App 工程改动(d:\keilProject\HC32F460\Git\GateWay)
**Project/GateWay/source/User/Inc/bsp.h**(L19-29,评审 P0 关键):
* `FLASH_APP_SIZE` 58→29 扇区后 `FLASH_BINFO_BASE` 会错算成 0x42000,**必须**改为:
`FLASH_APP_A_SIZE(29*8K)` + `FLASH_APPB_BASE = FLASH_APP_BASE + FLASH_APP_A_SIZE`(0x42000) + `FLASH_APPB_SIZE(29*8K)` + `FLASH_BINFO_BASE = FLASH_APPB_BASE + FLASH_APPB_SIZE`(**仍=0x7C000**)、FLASH\_CFG\_BASE 连带仍=0x7E000
**MDK/GateWay\_app.sct**:`LR_IROM1/ER_IROM1` 尺寸 `0x74000` → `0x3A000`(两个 target 共用此 sct,sct 优先于 uvprojx IROM)
**MDK/GateWay.uvprojx**:app\_boot target(L1168) IROM Size `0x6c000`→`0x3a000`(一致性,app\_dubeg 的 0x0/0x80000 本就与 sct 不一致,不动)
**source/User/Src/Update.c** `Update()`:加 `AppSize==0 || AppSize>FLASH_APPB_SIZE` 时报错返回,不置标志不复位
其余 App 代码(VTOR 动态基址、UpdateInit、升级异常检测、JumpToApp)均无需改动。
## 实施注意事项
1. **编码**:所有源文件含中文注释,一律 UTF-8。用 .NET 脚本(`UTF8Encoding(false)`)做替换修改(本会话已验证 Edit 工具会把 GBK 污染写入),改后校验 git diff 行数与编码
2. boot\_para\_t 结构、BOOT\_PARA\_ADDRESS、协议帧均不变 → 新旧 Boot/App 交叉兼容
3. 编译验证:Boot(Keil MDK)+ App(app\_boot target)分别编译通过,App 镜像 113KB < 232KB
## 验证清单
1. 正常升级全流程:新固件运行、外部参数分区按 APP\_BOOT\_UPGRADE\_FLAG 清理、传感器重新注册
2. 下载中断电 → 重启回老 App → 可再次升级
3. 下载超时(主机停发)→ 3 次重试后自动回老 App
4. CRC 注入失败 → 回老 App
5. 搬运中断电 → 重启自愈重搬 → 升级成功
6. B 区残留旧镜像 + 新 0x81(不同 AppSize/CRC)→ 不误判、重新下载
7. COPY 阶段发 0x81/0x82 → 均被拒绝,搬运不被干扰
8. AppSize=0 / >232KB → 拒绝
@@ -0,0 +1,85 @@
# 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 资费可忽略。
+4 -4
View File
@@ -432,18 +432,18 @@
<Bp>
<Number>0</Number>
<Type>0</Type>
<LineNumber>569</LineNumber>
<LineNumber>503</LineNumber>
<EnabledFlag>1</EnabledFlag>
<Address>0</Address>
<Address>54178</Address>
<ByteObject>0</ByteObject>
<HtxType>0</HtxType>
<ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<BreakIfRCount>1</BreakIfRCount>
<Filename>..\source\User\Src\CatOneTask.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
<Expression>\\GateWay\../source/User/Src/CatOneTask.c\503</Expression>
</Bp>
</Breakpoint>
<WatchWindow1>
+1 -1
View File
@@ -1165,7 +1165,7 @@
<OCR_RVCT4>
<Type>1</Type>
<StartAddress>0x8000</StartAddress>
<Size>0x6c000</Size>
<Size>0x3a000</Size>
</OCR_RVCT4>
<OCR_RVCT5>
<Type>1</Type>
+3 -3
View File
@@ -1,10 +1,10 @@
; *************************************************************
; *** Scatter-Loading Description File for GateWay APP ***
; *** Flash: APP区 0x8000起 (Boot 32KB), 到参数区0x7C000前 ***
; *** Flash: A区 0x8000~0x41FFF(232KB, 运行) + B区 0x42000~0x7BFFF(232KB, 升级暂存), 参数区0x7C000 ***
; *************************************************************
LR_IROM1 0x00008000 0x00074000 {
ER_IROM1 0x00008000 0x00074000 {
LR_IROM1 0x00008000 0x0003A000 {
ER_IROM1 0x00008000 0x0003A000 {
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
+7 -6
View File
@@ -13,6 +13,7 @@
#include "bsp.h"
#include "main.h"
#include "sx127x.h"
#include "CatOneTask.h"
extern GateWayPara_t GateWay;
@@ -76,9 +77,9 @@ void rt_hw_board_init(void)
static int uart_init(void)
{
//#error "TODO 2: Enable the hardware uart and config baudrate."
DbgOrCat1Uart_Config(500000);
// RS485Ch1_Config(500000);
/*USART1专用Cat1: 上电恒115200+CAT1方向*/
DbgOrCat1Uart_Config(115200);
CAT1_ON();
return 0;
}
INIT_BOARD_EXPORT(uart_init);
@@ -86,14 +87,14 @@ INIT_BOARD_EXPORT(uart_init);
void rt_hw_console_output(const char *str)
{
rt_enter_critical();
/*调试输出按duch配置分流; USART1固定Cat1, duch=cat1经透传缓冲上送TCP(不直写USART1防干扰AT通道)*/
switch(GateWay.ConfigPara.Duch) {
case CH_RS485_1: RS485Ch1UartSend((uint8_t *)str, strlen(str)); break;
case CH_RS485_2: RS485Ch2UartSend((uint8_t *)str, strlen(str)); break;
case CH_ETH: EthUartSend((uint8_t *)str, strlen(str)); break;
case CH_LORA: Sx1276LoRaSendBuffer((uint8_t *)str, strlen(str)); break;
case CH_CAT1: DebugOrCat1UartSend((uint8_t *)str, strlen(str)); break;
case CH_DBG: DebugOrCat1UartSend((uint8_t *)str, strlen(str)); break;
default: DebugOrCat1UartSend((uint8_t *)str, strlen(str)); break;
case CH_CAT1: RS485Ch1UartSend((uint8_t *)str, strlen(str)); break; /*系统级日志固定RS485 Ch1, 不进透传(防trace/AT应答自激灌环)*/
default: RS485Ch1UartSend((uint8_t *)str, strlen(str)); break; /*旧参数dbg/空值兜底RS485 Ch1*/
}
rt_exit_critical();
}
+1 -1
View File
@@ -41,7 +41,7 @@
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>
+2 -2
View File
@@ -2,8 +2,8 @@
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x00008000 0x0006C000 { ; load region size_region
ER_IROM1 0x00008000 0x0006C000 { ; load address = execution address
LR_IROM1 0x00008000 0x0003A000 { ; load region size_region
ER_IROM1 0x00008000 0x0003A000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
@@ -33,7 +33,6 @@ const DBGFunType DebugFun[DEBUG_CMD_CNT];
static GateWayPara GateWay;
static uint8_t DebugRxLen;
static uint8_t DebugRxBuff[DBG_RX_LEN_MAX];
static uint8_t DebugRxTimeOut1mSCnt;
static rt_sem_t DebugRev_Sem;
static char tempBuff[DEBUG_BUFF_MAX];
static bool ParaEchoCh1 = false;
@@ -43,10 +42,8 @@ void Debug_Printf(char *format, ...)
va_list args;
va_start(args, format);
vsprintf(&tempBuff[0], format, args);
if(GateWay && GateWay->ConfigPara.Duch == CH_CAT1
&& GateWay->ConfigPara.Much != CH_CAT1
&& GateWay->ConfigPara.Auch != CH_CAT1
&& !(GateWay->ConfigPara.CuchMask & CUCH_CAT1)) {
/*duch=cat1: 调试文本(命令回应)经Cat1 TCP透传(系统级rt_kprintf日志走console->RS485 Ch1, 不经此路径)*/
if(GateWay && GateWay->ConfigPara.Duch == CH_CAT1) { /*调试输出(命令回应)一律透传, 不限Much/Auch;*/
char *line = tempBuff;
while(line && *line) {
char *end = strstr(line, "\r\n");
@@ -58,9 +55,6 @@ void Debug_Printf(char *format, ...)
} else {
rt_kprintf(tempBuff);
}
if(ParaEchoCh1) {
RS485Ch1UartSend((uint8_t *)tempBuff, strlen(tempBuff));
}
va_end(args);
}
/*****************************************************************************************
@@ -84,7 +78,6 @@ void Debug_Thread_Entry(void *parameter)
result = rt_sem_take(DebugRev_Sem, RT_WAITING_FOREVER);
if(result == RT_EOK) {
DebugAnalyze(GateWay, DebugRxBuff, DebugRxLen);
DebugRxTimeOut1mSCnt = 0;
DebugRxLen = 0;
}
}
@@ -98,35 +91,15 @@ void Debug_Thread_Entry(void *parameter)
*****************************************************************************************/
void DbgOrCat1RxIrqCallback(uint8_t rData)
{
if(ChannelIsActive(GateWay->ConfigPara, CH_CAT1)) {
Cat1IrqCallback(rData);
return;
}
if(DebugRxTimeOut1mSCnt == 0)
DebugRxLen = 0;
DebugRxTimeOut1mSCnt = 3;
if(DebugRxLen < DBG_RX_LEN_MAX) {
DebugRxBuff[DebugRxLen++] = rData;
}
/*USART1专用Cat1: 接收数据无条件进Cat1处理(不再按配置分流)*/
Cat1IrqCallback(rData);
}
void DebugOrCat1RxOverhandler(void)
{
if(ChannelIsActive(GateWay->ConfigPara, CH_CAT1)) {
Cat1OverHandler();
return;
}
if(DebugRxTimeOut1mSCnt > 0)
DebugRxTimeOut1mSCnt--;
if(DebugRxLen > 2 && DebugRxTimeOut1mSCnt == 0) {
DebugRxTimeOut1mSCnt = 20;
rt_sem_release(DebugRev_Sem);
}
/*USART1固定接Cat1: 超时定时无条件服务Cat1接收链(URC分块超时/IRQ信号量释放)*/
Cat1OverHandler();
}
/*****************************************************************************************
@@ -168,7 +141,7 @@ void DebugAnalyze(GateWayPara GateWay, uint8_t *rData, uint16_t rLen)
for(int i = 0; i < DEBUG_CMD_CNT; i++) {
if(strcmp(argv[0], DebugFun[i].DBGCmd) == 0) {
DebugFun[i].DBGExec(argc, argv);
break; // 未匹配break跳出
/*USART1专用Cat1后, 调试输出统一走RS485 Ch1(经rt_kprintf→rt_hw_console_output)*/
}
}
}
@@ -203,7 +176,7 @@ void DebugCmdMainOnOff(int argc, char *argv[])
/*****************************************************************************************
* 函数名称: DebugCmdCat1OnOff
* 功能描述: CAT1通道消息控制
* 功能描述: Cat1调试信息开关(cat1dbg on/off)
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
@@ -251,10 +224,10 @@ void DebugCmdEthOnOff(int argc, char *argv[])
}
/*****************************************************************************************
* 函数名称: DebugCmdCat1OnOff
* 功能描述: CAT1通道消息控制
* 函数名称: DebugCmdRS485Ctrl
* 功能描述: RS485通道控制(通道使能/内置通讯单元使能/输出电压/波特率/升级标志)
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
*****************************************************************************************/
void DebugCmdRS485Ctrl(int argc, char *argv[])
@@ -699,14 +672,13 @@ void DebugCmdLsExclCommUnit(int argc, char *argv[])
}
/*****************************************************************************************
* 函数名称: ParseChannel
* 功能描述: 解析通道字符串
* 功能描述: 解析通道名称字符串为通道枚举值
* 参 数: str, 通道名称字符串
* 返 回 值: Channel_m通道枚举值
*****************************************************************************************/
static Channel_m ParseChannel(const char *str)
{
if(strcmp(str, "null") == 0) return CH_NULL;
if(strcmp(str, "dbg") == 0) return CH_DBG;
if(strcmp(str, "ch1") == 0) return CH_RS485_1;
if(strcmp(str, "ch2") == 0) return CH_RS485_2;
if(strcmp(str, "eth") == 0) return CH_ETH;
@@ -740,9 +712,7 @@ static void DebugCmdSetMuch(int argc, char *argv[])
DBG_LOG("Invalid channel.\r\n");
return;
}
if(ch != CH_NULL && (ChannelIsActive(GateWay->ConfigPara, ch)
|| (ch == CH_DBG && ChannelIsActive(GateWay->ConfigPara, CH_CAT1))
|| (ch == CH_CAT1 && ChannelIsActive(GateWay->ConfigPara, CH_DBG)))
if(ch != CH_NULL && ChannelIsActive(GateWay->ConfigPara, ch)
&& GateWay->ConfigPara.Much != ch) {
DBG_LOG("Channel %s is occupied.\r\n", ChannelName(ch));
return;
@@ -781,9 +751,7 @@ static void DebugCmdSetAuch(int argc, char *argv[])
DBG_LOG("Invalid channel.\r\n");
return;
}
if(ch != CH_NULL && (ChannelIsActive(GateWay->ConfigPara, ch)
|| (ch == CH_DBG && ChannelIsActive(GateWay->ConfigPara, CH_CAT1))
|| (ch == CH_CAT1 && ChannelIsActive(GateWay->ConfigPara, CH_DBG)))
if(ch != CH_NULL && ChannelIsActive(GateWay->ConfigPara, ch)
&& GateWay->ConfigPara.Auch != ch) {
DBG_LOG("Channel %s is occupied.\r\n", ChannelName(ch));
return;
@@ -845,9 +813,7 @@ static void DebugCmdSetCuch(int argc, char *argv[])
}
if(strcmp(argv[1], "add") == 0) {
if(GateWay->ConfigPara.Much == ch || GateWay->ConfigPara.Auch == ch || GateWay->ConfigPara.Duch == ch
|| (ch == CH_DBG && (GateWay->ConfigPara.Much == CH_CAT1 || GateWay->ConfigPara.Auch == CH_CAT1 || GateWay->ConfigPara.Duch == CH_CAT1))
|| (ch == CH_CAT1 && (GateWay->ConfigPara.Much == CH_DBG || GateWay->ConfigPara.Auch == CH_DBG || GateWay->ConfigPara.Duch == CH_DBG))) {
if(GateWay->ConfigPara.Much == ch || GateWay->ConfigPara.Auch == ch || GateWay->ConfigPara.Duch == ch) {
DBG_LOG("Channel %s occupied by Much/Auch/Duch.\r\n", ChannelName(ch));
return;
}
@@ -1030,8 +996,8 @@ void DebugCmdRestoreFactory(int argc, char *argv[])
DBG_LOG("Restore factory settings, GateWay Restart...\r\n");
/*仅擦除参数分区(扇区0~1),非全片擦除;擦除后参数区全0xFF,
重启后SavFlag无效自动加载Boot默认参数*/
for(uint32_t Sector = GATEWEY_PARA_SAV_SECTOR; Sector < LOG_INFO_START_SECTOR; Sector++) {
重启后SavFlag无效自动加载Boot默认参数*/
for(uint32_t Sector = GATEWEY_PARA_SAV_SECTOR; Sector < LOG_INFO_START_SECTOR; Sector++) {
SpiFlashEraseSector(Sector * SPIFLASH_SECTORSIZE);
} rt_thread_delay(1000);
NVIC_SystemReset();
@@ -1074,7 +1040,7 @@ static void DebugCmdUpload(int argc, char *argv[])
/*****************************************************************************************
* 函数名称: DebugCmdRegister
* 功能描述: 触发设备位置信息注册
* 功能描述: 触发重新向服务器注册(清注册标志并触发Cat1/ETH重连注册)
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
@@ -1109,10 +1075,10 @@ static void DebugCmdRegister(int argc, char *argv[])
}
/*****************************************************************************************
* 函数名称: DebugCmdRestoreFactory
* 功能描述: 恢复出厂设置
* 函数名称: DebugCmdReboot
* 功能描述: 重启网关(系统复位)
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
*****************************************************************************************/
void DebugCmdReboot(int argc, char *argv[])
@@ -1131,10 +1097,10 @@ void DebugCmdReboot(int argc, char *argv[])
}
/*****************************************************************************************
* 函数名称: DebugCmdSetSensorCollectTime
* 功能描述: 设置采集时间
* 函数名称: DebugCmdSetCollectTime
* 功能描述: 设置采集时间间隔(cu:通讯单元参数 / se:下发传感器)
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
*****************************************************************************************/
void DebugCmdSetCollectTime(int argc, char *argv[])
@@ -1198,7 +1164,7 @@ void DebugCmdSetCollectTime(int argc, char *argv[])
/*****************************************************************************************
* 函数名称: DebugCmdTimeSync
* 功能描述: 时间同步
* 功能描述: 系统时间同步(time命令设置系统时间)
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
@@ -1239,10 +1205,10 @@ void DebugCmdTimeSync(int argc, char *argv[])
}
/*****************************************************************************************
* 函数名称: DebugCmdTimeSync
* 功能描述: 查询各通讯单元的版本号
* 函数名称: DebugCmdQuerySensor
* 功能描述: 查询内置通讯单元的传感器列表
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
*****************************************************************************************/
extern SensorCommPara_t SComm1Para;
@@ -1289,8 +1255,7 @@ void DebugCmdSelDebugChannel(int argc, char *argv[])
if(strcmp(argv[1], "?") == 0) {
DBG_LOG("Debug Cmd: duch args\r\n");
DBG_LOG(" brief --> Debug information output channel selection.\r\n");
DBG_LOG(" args --> (dbg|ch1|ch2|eth|lora|cat1)\r\n");
DBG_LOG(" dbg: On board debugging serial port.\r\n");
DBG_LOG(" args --> (ch1|ch2|eth|lora|cat1)\r\n");
DBG_LOG(" ch1: RS485 channel 1 serial port.\r\n");
DBG_LOG(" ch2: RS485 channel 2 serial port.\r\n");
DBG_LOG(" eth: ETH serial port.\r\n");
@@ -1305,9 +1270,8 @@ void DebugCmdSelDebugChannel(int argc, char *argv[])
DBG_LOG("Invalid channel.\r\n");
return;
}
if((ch == CH_DBG && ChannelIsActive(GateWay->ConfigPara, CH_CAT1))
|| (ch == CH_CAT1 && ChannelIsActive(GateWay->ConfigPara, CH_DBG))) {
DBG_LOG("USART1 occupied by dbg/cat1 pair.\r\n");
if(ch == CH_DBG) {
DBG_LOG("DBG port removed: USART1 is dedicated to Cat1.\r\n");
return;
}
if(ChannelIsActive(GateWay->ConfigPara, ch)
@@ -1323,10 +1287,6 @@ void DebugCmdSelDebugChannel(int argc, char *argv[])
DbgOrCat1Uart_Config(115200);
CAT1_ON();
}
else if(ch == CH_DBG) {
DbgOrCat1Uart_Config(500000);
DBG_ON();
}
DBG_LOG("Set duch to %s.\r\n", ChannelName(ch));
WritePara((uint8_t *)&GateWay->ConfigPara, sizeof(GWConfigPara_t));
}
@@ -1616,7 +1576,7 @@ static void DebugCmdCali(int argc, char *argv[])
CommUnitCmd[sizeof(CommUnitFrameHeader_t)] = crc16 & 0x00ff;
CommUnitCmd[sizeof(CommUnitFrameHeader_t) + 1] = (crc16 >> 8) & 0x00ff;
if(mac[2] == 0x01) { //LORA通讯
if(mac[2] == 0x01) { //LORAͨѶ
if(GateWay->ConfigPara.CommUnitArray[ret].RegFlag == true) {
GateWay->ConfigPara.CommUnitArray[ret].CailFlag = true;
DBG_LOG("Wait for the device to respond. Mac:%02X-%02X-%02X-%02X-%02X-%02X\r\n",
@@ -1625,7 +1585,7 @@ static void DebugCmdCali(int argc, char *argv[])
TrySendFullPowerCmd(GateWay, ret);
}
}
else if(mac[2] == 0x02) { //RS485通讯
else if(mac[2] == 0x02) { //RS485ͨѶ
if(GateWay->ConfigPara.Rs485Ch1.Enable == true && !GateWay->ConfigPara.Rs485Ch1.CommUnitEnable) {
GateWay->ConfigPara.Rs485Ch1.RS485Send(Rs485Cmd, sizeof(CommUnitFrameHeader_t) + 2);
DBG_LOG("Calibrate CommUnit: %s!\r\n", argv[1]);
@@ -1735,7 +1695,7 @@ static void DebugLaserConfig(int argc, char *argv[])
CommUnitCmd[len++] = crc16 & 0x00ff;
CommUnitCmd[len++] = (crc16 >> 8) & 0x00ff;
if(mac[2] == 0x01) { //LORA通讯单元低功胀模式下直接下发
if(mac[2] == 0x01) { //LORA通讯单元低功耗模式下直接下发
if(GateWay->ConfigPara.CommUnitArray[ret].RegFlag == true)
{
if(onoff == true)
@@ -1750,11 +1710,11 @@ static void DebugLaserConfig(int argc, char *argv[])
{
GateWay->ConfigPara.CommUnitArray[ret].ContLaser = false;
GateWay->ConfigPara.CommUnitArray[ret].LaserOnOff = onoff;
Sx1276LoRaSendBuffer(CommUnitCmd, len);//直接发送
//直接发送
}
}
}
else if(mac[2] == 0x02) { //RS485通讯
else if(mac[2] == 0x02) { //RS485ͨѶ
if(GateWay->ConfigPara.Rs485Ch1.Enable == true && !GateWay->ConfigPara.Rs485Ch1.CommUnitEnable) {
GateWay->ConfigPara.Rs485Ch1.RS485Send(Rs485Cmd, len);
DBG_LOG("Control RS485 laser CommUnit: %s!\r\n", argv[1]);
@@ -1771,7 +1731,7 @@ static void DebugLaserConfig(int argc, char *argv[])
/*****************************************************************************************
* 函数名称: DebugCmdLPConfig
* 功能描述: 低功胀参数配置
* 功能描述: 低功耗参数配置
* 参 数: argc, 参数个数
argv, 参数列表
* 返 回 值: 无
@@ -1779,10 +1739,10 @@ static void DebugLaserConfig(int argc, char *argv[])
static void DebugCmdLPConfig(int argc, char *argv[])
{
DBG_LOG("\r\n");
uint16_t CollectInterval; //采集时间间隔
uint16_t ReportInterval; //上报时间间隔
uint8_t ERInterval; //紧急上报时间间隔
uint8_t ERTime; //紧急上报时间
uint16_t CollectInterval; //采集时间间隔
uint16_t ReportInterval; //上报时间间隔
uint8_t ERInterval; //紧急上报时间间隔
uint8_t ERTime; //紧急上报时间
uint8_t Mac[6];
bool ConfigAll = false;
+13 -6
View File
@@ -474,11 +474,18 @@ void Sx1276LoRaWakeup(void)
//配置本层参数的函数
//频道表
const uint32_t gdwSx1276ChannelTbl[SX1276_CHANNEL_MAX]={
CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8, CH9,
CH10, CH11, CH12, CH13, CH14, CH15, CH16, CH17, CH18, CH19,
CH20, CH21, CH22, CH23, CH24, CH25, CH26, CH27, CH28, CH29,
CH30, CH31, CH32, CH33, CH34, CH35, CH36, CH37, CH38, CH39,
CH40, CH41, CH42, CH43, CH44, CH45
CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8, CH9,
CH10, CH11, CH12, CH13, CH14, CH15, CH16, CH17, CH18, CH19,
CH20, CH21, CH22, CH23, CH24, CH25, CH26, CH27, CH28, CH29,
CH30, CH31, CH32, CH33, CH34, CH35, CH36, CH37, CH38, CH39,
CH40, CH41, CH42, CH43, CH44, CH45, CH46, CH47, CH48, CH49,
CH50, CH51, CH52, CH53, CH54, CH55, CH56, CH57, CH58, CH59,
CH60, CH61, CH62, CH63, CH64, CH65, CH66, CH67, CH68, CH69,
CH70, CH71, CH72, CH73, CH74, CH75, CH76, CH77, CH78, CH79,
CH80, CH81, CH82, CH83, CH84, CH85, CH86, CH87, CH88, CH89,
CH90, CH91, CH92, CH93, CH94, CH95, CH96, CH97, CH98, CH99,
CH100, CH101, CH102, CH103, CH104, CH105, CH106, CH107, CH108, CH109,
CH110, CH111, CH112, CH113, CH114, CH115, CH116, CH117, CH118, CH119
};
//LORAPT_CHANNEL
@@ -666,7 +673,7 @@ bool LoraSetRegPreamble(uint8_t RegPreamble)
}
bool LoraSetFreqCent(uint32_t FreqCent)
{
if(FreqCent < 470100000 || FreqCent > 492600000)
if(FreqCent < 433100000 || FreqCent > 492600000) //lora-wide: 433.1MHz~492.6MHz(与信道表匹配)
return false;
LoRaPara.dwFreqHz = FreqCent;
return true;
+122 -48
View File
@@ -660,7 +660,7 @@ typedef enum{
LORAPT_MAX
}Sx1276LoraParaType;
#define SX1276_CHANNEL_MAX 46
#define SX1276_CHANNEL_MAX 120
#define LORA_SPI_NSS_SET() SPI2_NSS_SET()
#define LORA_SPI_NSS_CLR() SPI2_NSS_CLR()
@@ -758,54 +758,128 @@ typedef struct {
#endif
/*
Lora频率:470100000ul + 500000*N, N=0~45, 共46个信道(470.1MHz~492.6MHz)
Lora频率:433100000ul + 500000*N, N=0~119, 共120个信道(433.1MHz~492.6MHz) [lora-wide宽频版]
*/
#define CH0 (470100000ul + 0) //470.1MHz
#define CH1 (470100000ul + 500000)
#define CH2 (470100000ul + 1000000)
#define CH3 (470100000ul + 1500000)
#define CH4 (470100000ul + 2000000)
#define CH5 (470100000ul + 2500000)
#define CH6 (470100000ul + 3000000)
#define CH7 (470100000ul + 3500000)
#define CH8 (470100000ul + 4000000)
#define CH9 (470100000ul + 4500000)
#define CH10 (470100000ul + 5000000)
#define CH11 (470100000ul + 5500000)
#define CH12 (470100000ul + 6000000)
#define CH13 (470100000ul + 6500000)
#define CH14 (470100000ul + 7000000)
#define CH15 (470100000ul + 7500000)
#define CH16 (470100000ul + 8000000)
#define CH17 (470100000ul + 8500000)
#define CH18 (470100000ul + 9000000)
#define CH19 (470100000ul + 9500000)
#define CH20 (470100000ul + 10000000)
#define CH21 (470100000ul + 10500000)
#define CH22 (470100000ul + 11000000)
#define CH23 (470100000ul + 11500000)
#define CH24 (470100000ul + 12000000)
#define CH25 (470100000ul + 12500000)
#define CH26 (470100000ul + 13000000)
#define CH27 (470100000ul + 13500000)
#define CH28 (470100000ul + 14000000)
#define CH29 (470100000ul + 14500000)
#define CH30 (470100000ul + 15000000)
#define CH31 (470100000ul + 15500000)
#define CH32 (470100000ul + 16000000)
#define CH33 (470100000ul + 16500000)
#define CH34 (470100000ul + 17000000)
#define CH35 (470100000ul + 17500000)
#define CH36 (470100000ul + 18000000)
#define CH37 (470100000ul + 18500000)
#define CH38 (470100000ul + 19000000)
#define CH39 (470100000ul + 19500000)
#define CH40 (470100000ul + 20000000)
#define CH41 (470100000ul + 20500000)
#define CH42 (470100000ul + 21000000)
#define CH43 (470100000ul + 21500000)
#define CH44 (470100000ul + 22000000)
#define CH45 (470100000ul + 22500000) //492.6MHz
#define CH0 (433100000ul + 0) //433.1MHz
#define CH1 (433100000ul + 500000)
#define CH2 (433100000ul + 1000000)
#define CH3 (433100000ul + 1500000)
#define CH4 (433100000ul + 2000000)
#define CH5 (433100000ul + 2500000)
#define CH6 (433100000ul + 3000000)
#define CH7 (433100000ul + 3500000)
#define CH8 (433100000ul + 4000000)
#define CH9 (433100000ul + 4500000)
#define CH10 (433100000ul + 5000000)
#define CH11 (433100000ul + 5500000)
#define CH12 (433100000ul + 6000000)
#define CH13 (433100000ul + 6500000)
#define CH14 (433100000ul + 7000000)
#define CH15 (433100000ul + 7500000)
#define CH16 (433100000ul + 8000000)
#define CH17 (433100000ul + 8500000)
#define CH18 (433100000ul + 9000000)
#define CH19 (433100000ul + 9500000)
#define CH20 (433100000ul + 10000000)
#define CH21 (433100000ul + 10500000)
#define CH22 (433100000ul + 11000000)
#define CH23 (433100000ul + 11500000)
#define CH24 (433100000ul + 12000000)
#define CH25 (433100000ul + 12500000)
#define CH26 (433100000ul + 13000000)
#define CH27 (433100000ul + 13500000)
#define CH28 (433100000ul + 14000000)
#define CH29 (433100000ul + 14500000)
#define CH30 (433100000ul + 15000000)
#define CH31 (433100000ul + 15500000)
#define CH32 (433100000ul + 16000000)
#define CH33 (433100000ul + 16500000)
#define CH34 (433100000ul + 17000000)
#define CH35 (433100000ul + 17500000)
#define CH36 (433100000ul + 18000000)
#define CH37 (433100000ul + 18500000)
#define CH38 (433100000ul + 19000000)
#define CH39 (433100000ul + 19500000)
#define CH40 (433100000ul + 20000000)
#define CH41 (433100000ul + 20500000)
#define CH42 (433100000ul + 21000000)
#define CH43 (433100000ul + 21500000)
#define CH44 (433100000ul + 22000000)
#define CH45 (433100000ul + 22500000)
#define CH46 (433100000ul + 23000000)
#define CH47 (433100000ul + 23500000)
#define CH48 (433100000ul + 24000000)
#define CH49 (433100000ul + 24500000)
#define CH50 (433100000ul + 25000000)
#define CH51 (433100000ul + 25500000)
#define CH52 (433100000ul + 26000000)
#define CH53 (433100000ul + 26500000)
#define CH54 (433100000ul + 27000000)
#define CH55 (433100000ul + 27500000)
#define CH56 (433100000ul + 28000000)
#define CH57 (433100000ul + 28500000)
#define CH58 (433100000ul + 29000000)
#define CH59 (433100000ul + 29500000)
#define CH60 (433100000ul + 30000000)
#define CH61 (433100000ul + 30500000)
#define CH62 (433100000ul + 31000000)
#define CH63 (433100000ul + 31500000)
#define CH64 (433100000ul + 32000000)
#define CH65 (433100000ul + 32500000)
#define CH66 (433100000ul + 33000000)
#define CH67 (433100000ul + 33500000)
#define CH68 (433100000ul + 34000000)
#define CH69 (433100000ul + 34500000)
#define CH70 (433100000ul + 35000000)
#define CH71 (433100000ul + 35500000)
#define CH72 (433100000ul + 36000000)
#define CH73 (433100000ul + 36500000)
#define CH74 (433100000ul + 37000000)
#define CH75 (433100000ul + 37500000)
#define CH76 (433100000ul + 38000000)
#define CH77 (433100000ul + 38500000)
#define CH78 (433100000ul + 39000000)
#define CH79 (433100000ul + 39500000)
#define CH80 (433100000ul + 40000000)
#define CH81 (433100000ul + 40500000)
#define CH82 (433100000ul + 41000000)
#define CH83 (433100000ul + 41500000)
#define CH84 (433100000ul + 42000000)
#define CH85 (433100000ul + 42500000)
#define CH86 (433100000ul + 43000000)
#define CH87 (433100000ul + 43500000)
#define CH88 (433100000ul + 44000000)
#define CH89 (433100000ul + 44500000)
#define CH90 (433100000ul + 45000000)
#define CH91 (433100000ul + 45500000)
#define CH92 (433100000ul + 46000000)
#define CH93 (433100000ul + 46500000)
#define CH94 (433100000ul + 47000000)
#define CH95 (433100000ul + 47500000)
#define CH96 (433100000ul + 48000000)
#define CH97 (433100000ul + 48500000)
#define CH98 (433100000ul + 49000000)
#define CH99 (433100000ul + 49500000)
#define CH100 (433100000ul + 50000000)
#define CH101 (433100000ul + 50500000)
#define CH102 (433100000ul + 51000000)
#define CH103 (433100000ul + 51500000)
#define CH104 (433100000ul + 52000000)
#define CH105 (433100000ul + 52500000)
#define CH106 (433100000ul + 53000000)
#define CH107 (433100000ul + 53500000)
#define CH108 (433100000ul + 54000000)
#define CH109 (433100000ul + 54500000)
#define CH110 (433100000ul + 55000000)
#define CH111 (433100000ul + 55500000)
#define CH112 (433100000ul + 56000000)
#define CH113 (433100000ul + 56500000)
#define CH114 (433100000ul + 57000000)
#define CH115 (433100000ul + 57500000)
#define CH116 (433100000ul + 58000000)
#define CH117 (433100000ul + 58500000)
#define CH118 (433100000ul + 59000000)
#define CH119 (433100000ul + 59500000) //492.6MHz
/*Lora中心频率默认值(编译期用于频道表等)
实际运行频率由Boot参数区(BootPara_t.LoraFreq)配置, APP启动时覆盖ConfigPara.Lora.FreqCent*/
+3 -3
View File
@@ -1,4 +1,4 @@
#ifndef __PUBLIC_H
#ifndef __PUBLIC_H
#define __PUBLIC_H
#include "bsp.h"
@@ -15,7 +15,6 @@
#define COMMUNIT_READ_SENSOR_INTERVAL_MAX (1 * 60)
#define LORA_ERR_RESET_DLY_MAX (10 * 60) //LORA通信异常复位延迟时间
#define CAT1_ERR_RESET_DLY_MAX (60 * 60) //CAT1通信异常复位延迟时间
typedef struct GateWay_t GateWayPara_t, *GateWayPara;
@@ -359,7 +358,8 @@ struct GateWay_t{
int MuchRevCallBack(GateWayPara GateWay, uint8_t *rData, uint16_t rLen);
int AuchRevCallBack(GateWayPara GateWay, uint8_t *rData, uint16_t rLen);
uint16_t CRC_Modbus(uint16_t wBase, __IO uint8_t *para, uint16_t length);
uint8_t AsciiToHex(char *ASCData, uint8_t *HexData, uint8_t sLen);
bool IsHexText(char *s, uint16_t len);
uint16_t AsciiToHex(char *ASCData, uint8_t *HexData, uint16_t sLen);
void HexToAscii(uint8_t *HexData, char *ASCData, uint8_t sLen);
int NetCommOrgData(GateWayPara GateWay, uint8_t *MegData, uint8_t *OutData);
int CommUnitAnalyze(GateWayPara GateWay, uint8_t *rData, uint16_t rLen, SendData Response);
+7
View File
@@ -32,5 +32,12 @@ typedef struct {
//输出接口
void Update(uint8_t *PayLoad);
void UpdateInit(void);
/*Cat1远程升级(0x7D帧)接口 - CatOneTask调用: 固件分包写外部SPI Flash暂存区, 收完置APP_UPDATE_SPI_FLAG复位*/
bool NetUpgradeFeed(uint8_t *data, uint16_t len, uint8_t ch); //喂入下行数据片段(带来源通道), 返回true=已被升级模块消费
bool NetUpgradePopTx(uint8_t *Out, uint16_t *OutLen, uint8_t ch); //取本通道待发应答帧(0x01/0x02, 0x7D原始帧)
bool NetUpgradeActive(void); //升级会话进行中
void NetUpgradeTick(void); //1ms轮询: 超时催发与会话放弃
void UpdateFromStash(uint32_t AppSize, uint32_t Crc32); //暂存区校验通过后置标志复位进Boot
#endif
+7 -4
View File
@@ -16,12 +16,14 @@
#define FLASH_BOOT_BASE (FLASH_BASE)
#define FLASH_BOOT_SIZE (4*FLASH_SECTOR_SIZE)
//app
//app A区(运行, 0x8000起, 232KB) + B区(升级暂存, 0x42000起, 232KB) - 与Boot A/B分区一致
#define FLASH_APP_BASE (FLASH_BOOT_BASE+ FLASH_BOOT_SIZE)
#define FLASH_APP_SIZE (58*FLASH_SECTOR_SIZE)
#define FLASH_APP_SIZE (29*FLASH_SECTOR_SIZE)
#define FLASH_APPB_BASE (FLASH_APP_BASE + FLASH_APP_SIZE)
#define FLASH_APPB_SIZE (29*FLASH_SECTOR_SIZE)
//boot info
#define FLASH_BINFO_BASE (FLASH_APP_BASE + FLASH_APP_SIZE)
//boot info (0x7C000, 位置不变)
#define FLASH_BINFO_BASE (FLASH_APPB_BASE + FLASH_APPB_SIZE)
#define FLASH_BINFO_SIZE (1*FLASH_SECTOR_SIZE)
//user config
@@ -33,6 +35,7 @@
#define APP_START_FLAG 0x55AA5A5A
#define APP_UPDATE_FLAG 0xA5A5AA55
#define APP_BOOT_UPGRADE_FLAG 0x5A5A55A5
#define APP_UPDATE_SPI_FLAG 0xA5A55A5A //Cat1远程升级: 固件已存外部SPI Flash暂存区, Boot据此搬运
#define WATCH_DOG 1
+1 -1
View File
@@ -4,7 +4,7 @@
#include "Public.h"
#include "DebugCmd.h"
#define SOFTWARE_VERSION 13
#define SOFTWARE_VERSION 15
#define HARDWARE_VERSION 12
extern bool MainDispEn;
@@ -40,6 +40,12 @@ uint32_t SpiFlashReadId(void);
#define LOG_INFO_START_SECTOR 0x02
#define LOG_SAV_START_SECTOR 0x03
/*固件升级暂存区(外部Flash尾部): 扇区4037=升级进度区, 扇区4038~4095=固件镜像(232KB,与Boot A/B分区一致)*/
#define FLASH_FW_STASH_PROG_SECTOR 4037
#define FLASH_FW_STASH_SECTOR 4038
#define FLASH_FW_STASH_SECTORS 58
#define LOG_SAV_END_ADDR (FLASH_FW_STASH_PROG_SECTOR * SPIFLASH_SECTORSIZE)
//#if (LORA_MODULE == WH_LR36_L)
//#define LOG_SAV_SIZE 78
//#define LOG_SAV_NUM_SECTOR 52 //每扇区存储数量
@@ -70,6 +76,12 @@ void AddLog(uint8_t *wData, uint32_t wLen);
int ReadLog(LogHeader Header, uint8_t **wData, uint32_t LogIdx);
int ReadPara(uint8_t *Para, uint32_t ParaLen);
int WritePara(uint8_t *Para, uint32_t ParaLen);
void FwStashEraseAll(void);
void FwStashProgRead(uint8_t *rData, uint16_t rLen);
void FwStashProgWrite(uint8_t *wData, uint16_t wLen);
void FwStashEraseSector(uint32_t SectorIdx);
int FwStashWrite(uint8_t *wData, uint32_t Offset, uint16_t wLen);
int FwStashRead(uint8_t *rData, uint32_t Offset, uint16_t rLen);
/* USER CODE END */
+209 -126
View File
@@ -1,16 +1,20 @@
#include "CatOneTask.h"
#include "Public.h"
#include "DebugCmd.h"
#include "Update.h"
static rt_sem_t CatOneRev_Sem = RT_NULL;
static rt_sem_t CatOneIRQ_Sem = RT_NULL;
static rt_thread_t Cat1Rev_Thread = RT_NULL;
static uint8_t CAT1DispEn = false;
static uint8_t CAT1DispEn = false; /*默认关闭: 正常工作不输出Cat1 AT流日志, cat1dbg命令动态开启*/
static CatOne_t CatOne;
static char CatOneRxBuff[CAT_ONE_REV_LEN_MAX];
#define CAT_ONE_URC_LEN_MAX 8192 //+LIPURC一批连发8包约3.6K, 预留8K
static char CatOneRxBuff[CAT_ONE_URC_LEN_MAX];
static uint16_t CatOneRxLen;
static volatile uint8_t Cat1RxSyncReq = 0; /*IRQ timeout-clear: Rev discards stale partial URC*/
static uint8_t CatOneTxBuff[CAT_ONE_REV_LEN_MAX];
static uint16_t CatOneTxLen;
@@ -20,8 +24,9 @@ static char CommUnitSendASCII[CAT_ONE_REV_LEN_MAX * 2];
static uint8_t Cat1RevTimeOutCnt;
static uint16_t CatSendErrCnt = 0;
static uint8_t Cat1RevErrCnt = 0; /*no-server-data watchdog: reset on any URC data*/
static uint8_t Cat1IdleReconnFlag = 0; /*空闲保活重连标志: 重连后只建链不上传(跳过注册帧)*/
bool Cat1DuchReady = false;
static char duchRing[8192];
static uint16_t duchWr, duchRd;
@@ -44,25 +49,26 @@ void Cat1DuchSend(const char *text, uint16_t len)
#define CATONE_RESET_DELAY_TIME_MAX (5 * 60 * 1000)
#define CAT1_TCP_REOPEN_RETRY_MAX 3
#define CAT1_TCP_REOPEN_RETRY_DLY 5000
#define CAT1_TCP_IDLE_RECONN_DLY_MAX (5 * 60) /*空闲无上传5分钟(秒计数): 断开重建TCP保活, exe端刷新客户端列表*/
const char *CatOneATCmdStr[16] = {
const char *CatOneATCmdStr[17] = {
"NULL",
"AT\r\n", //开机检测
"ATE0\r\n", //关回显
"AT+CPIN?\r\n", //识卡
"AT\r\n", //开机检测
"ATE0\r\n", //关回显
"AT+CPIN?\r\n", //识别卡
"AT+CGSN=1\r\n",
"AT+QCCID\r\n", //读卡号
"AT+CEREG?\r\n", //查询注册状态
"AT+QCCID\r\n", //读卡号
"AT+CEREG?\r\n", //查询注册状态
"AT+CGPADDR=1\r\n", //查询IP地址
"AT+CSQ\r\n", //查询信号强度
"AT+CSQ\r\n", //查询信号强度
"AT+LDNSGIP=gxjt.cui635.cn\r\n",
"AT+QLBS\r\n", //获取基站定位信息
"AT+QIOPEN=", //设置TCP服务器地址和端口
"AT+QLBS\r\n", //获取基站定位信息
"AT+QIOPEN=", //设置TCP服务器地址和端口号
"AT+QISEND=", //发送数据
"AT+QICLOSE=0\r\n", //断开连接
"AT+QLBSCFG=\"server\",http://locator-aep.xiot.senthink.com:80/locator/v0.1/locate\r\n",
"AT+CCLK?\r\n", //获取时间
"AT+QLBSCFG=\"token\",45B516D3078467E84DD2CFBF3532A4CB\r\n",
"AT+CCLK?\r\n", //获取时间
};
void Cat1DBGOnOff(bool OnOff)
@@ -298,41 +304,11 @@ void CatOneAtCmdAnalyze(char *RxBuff)
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
break;
case CAT_ONE_AT_NULL:
p = strstr(RxBuff, "+LIPURC");
if(p != NULL) {
char rData[120];
uint8_t hData[60];
int rLen, hLen, ret;
if(strstr(p, "+LIPURC: 0,0") != NULL) {
CAT1_DBG_LOG("TCP connection disconnected.\r\n\r\n");
CatOne.TcpConnFlag = false;
CatOne.Cat1Status = CAT_ONE_OFF;
return;
}
ret = sscanf(p, "+LIPURC: 0,1,%d,%119s\r\n", &rLen, rData);
if(ret == 2) {
if(rLen < 24)
return;
memset(hData, 0x00, 60);
hLen = AsciiToHex(rData, hData, rLen);
CatSendErrCnt = 0;
if(CatOne.GateWay->ConfigPara.Much == CH_CAT1)
CatOne.GateWay->MuchRevCallBack(CatOne.GateWay, hData, hLen);
else
CatOne.GateWay->AuchRevCallBack(CatOne.GateWay, hData, hLen);
}
else {
return;
}
rt_sem_release(CatOneRev_Sem);
return;
}
if(CatOne.TcpConnFlag && RxBuff[0] > ' ') {
DebugAnalyze(CatOne.GateWay, (uint8_t *)RxBuff, strlen(RxBuff));
return;
}
break;
default:
CatOne.ATCmdRet = CAT_ONE_RET_ERR;
@@ -371,6 +347,7 @@ void CatOneAtCmdSend(CatOneATCMD_m Cmd, uint32_t Dly, CatOneStatus_m NextStatus)
Cat1RevTimeOutCnt = 0;
DebugOrCat1UartSend((uint8_t *)CatOne.CatOneSendBuff, strlen(CatOne.CatOneSendBuff));
CatOne.CatOne1mSDelayCnt = Dly;
while(rt_sem_take(CatOneRev_Sem, 0) == RT_EOK); /*清空历史信号量: 防止URC释放的旧信号量令WAIT_REV立即误返回, 掩盖模组ERROR*/
CatOne.Cat1Status = CAT_ONE_WAIT_REV;
CatOne.NextStatus = NextStatus;
}
@@ -414,7 +391,17 @@ void CatOneLoopHandler(void)
{
static rt_err_t result;
uint16_t ret;
static uint8_t Cat1RevErrCnt = 0;
static uint8_t Cat1UpgTxFlag = 0; /*当前LIPSEND是否升级应答帧: 发完即回WAIT_SEND*/
NetUpgradeTick(); /*Cat1远程升级会话超时管理*/
{ /*state trace: cat1 status enum 0=IDEL 4=SEND 5=WAIT_SEND 6=REV 8=WAIT_REV 9=RESET 10=OFF*/
static signed char LastSt = -1;
if((signed char)CatOne.Cat1Status != LastSt) {
LastSt = (signed char)CatOne.Cat1Status;
CAT1_DBG_LOG("Cat1 state -> %d\r\n", LastSt);
}
}
switch(CatOne.Cat1Status){
case CAT_ONE_IDEL:
@@ -472,16 +459,23 @@ void CatOneLoopHandler(void)
case CAT_ONE_WAIT_CONN:
if(CatOne.TcpConnFlag) {
if(CatOne.GateWay->ConfigPara.Much == CH_CAT1) {
CatOne.Cat1Status = CAT_ONE_REG_SVR;
if(Cat1IdleReconnFlag) { /*空闲保活重连: 只建链不上传, 跳过注册帧*/
Cat1IdleReconnFlag = 0;
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
}
else if(CatOne.GateWay->ConfigPara.Auch == CH_CAT1 || (CatOne.GateWay->ConfigPara.CuchMask & CUCH_CAT1)) {
else if(CatOne.GateWay->ConfigPara.Much == CH_CAT1) {
CatOne.Cat1Status = CAT_ONE_REG_SVR; /*Cat1为主上传通道: 注册上送*/
}
else if(CatOne.GateWay->ConfigPara.Auch == CH_CAT1
|| (CatOne.GateWay->ConfigPara.CuchMask & CUCH_CAT1)) {
/*Cat1为辅助/掩码通道: 仅发注册帧维持在线*/
GateWayRegister(Payload);
CatOneTxLen = NetCommOrgData(CatOne.GateWay, Payload, CatOneTxBuff);
CatOne.Cat1Status = CAT_ONE_SEND_DATA;
}
else {
CatOne.Cat1Status = CAT_ONE_DUCH_MODE;
/*duch=cat1纯调试: 统一走WAIT_SEND状态机, duchRing轮询经LIPSEND hex透传, 升级不受分流限制*/
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
}
}
break;
@@ -493,6 +487,43 @@ void CatOneLoopHandler(void)
break;
case CAT_ONE_WAIT_SEND:
/*Cat1远程升级应答帧优先(0x7D原始帧直发, 绕过0x7A打包)*/
if(NetUpgradePopTx(CatOneTxBuff, &CatOneTxLen, CH_CAT1)) {
CatSendErrCnt = 0;
Cat1UpgTxFlag = 1; /*升级应答帧标记*/
CatOne.Cat1Status = CAT_ONE_SEND_DATA;
break;
}
/*duch=cat1调试文本透传: QISEND明文直发(网络调试助手可读), 升级会话期间暂停*/
if(duchRd != duchWr && !NetUpgradeActive()) {
uint16_t avail = (duchWr - duchRd) & 0x1FFF;
uint16_t n = (avail > 240) ? 240 : avail;
if(duchRd + n <= 8192) {
memcpy(Payload, &duchRing[duchRd], n);
} else {
uint16_t part = 8192 - duchRd;
memcpy(Payload, &duchRing[duchRd], part);
memcpy(Payload + part, duchRing, n - part);
}
duchRd = (duchRd + n) & 0x1FFF;
CatSendErrCnt = 0;
{ /*wait for modem URC silence: AT cmd colliding with URC burst gets swallowed*/
uint16_t waitMs = 0;
while(Cat1RevTimeOutCnt > 0 && waitMs < 50) {
rt_thread_delay(2);
waitMs += 2;
}
}
sprintf(CatOne.CatOneSendBuff, "AT+QISEND=0,%d\r\n", n);
DebugOrCat1UartSend((uint8_t *)CatOne.CatOneSendBuff, strlen(CatOne.CatOneSendBuff));
rt_thread_delay(200);
DebugOrCat1UartSend(Payload, n);
DebugOrCat1UartSend((uint8_t *)"\x1A", 1);
rt_thread_delay(500);
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
break;
}
result = rt_mq_recv(ChannelMQ(*CatOne.GateWay, CH_CAT1), Payload, CAT_ONE_REV_LEN_MAX, 1000);
if(result == RT_EOK) {
CatSendErrCnt = 0;
@@ -507,10 +538,13 @@ void CatOneLoopHandler(void)
}
else {
CatSendErrCnt++;
if(CatSendErrCnt > CAT1_ERR_RESET_DLY_MAX) {
CatOne.Cat1Status = CAT_ONE_RESET;
CAT1_DBG_LOG("Cat1 has no data for a long time, Reset!\r\n");
if(CatSendErrCnt > CAT1_TCP_IDLE_RECONN_DLY_MAX) {
/*空闲5分钟无上传: 断开重建TCP保活, exe端重新看到客户端(不发任何数据帧)*/
CatSendErrCnt = 0;
Cat1IdleReconnFlag = 1;
CatOne.NextStatus = CAT_ONE_TCP_CONN;
CatOne.Cat1Status = CAT_ONE_CLOSE_TCP;
CAT1_DBG_LOG("Cat1 idle 5min, reconnect TCP!\r\n");
break;
}
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
@@ -520,77 +554,50 @@ void CatOneLoopHandler(void)
case CAT_ONE_SEND_DATA:
CatOne.AtCmdResendCnt = 3;
Cat1RevErrCnt++;
Cat1RevErrCnt++;
if(Cat1RevErrCnt > 10) {
CatOne.Cat1Status = CAT_ONE_RESET;
CAT1_DBG_LOG("Cat1 has no receive data for a long time, Reset!\r\n");
Cat1RevErrCnt = 0;
break;
}
CatOneAtCmdSend(CAT_ONE_LIPSEND, 5000, CAT_ONE_REV_DATA);
if(Cat1UpgTxFlag) { /*升级应答帧: 发完即回WAIT_SEND取下一帧, 不等服务器响应*/
Cat1UpgTxFlag = 0;
{ /*wait for modem URC silence: LIPSEND colliding with URC burst gets swallowed, 3 failures trigger CLOSE_TCP*/
uint16_t waitMs = 0;
while(Cat1RevTimeOutCnt > 0 && waitMs < 50) {
rt_thread_delay(2);
waitMs += 2;
}
}
CatOneAtCmdSend(CAT_ONE_LIPSEND, 5000, CAT_ONE_WAIT_SEND);
}
else {
CatOneAtCmdSend(CAT_ONE_LIPSEND, 5000, CAT_ONE_REV_DATA);
}
break;
case CAT_ONE_REV_DATA:
if(CatOne.GateWay->ConfigPara.Much != CH_CAT1) {
rt_sem_take(CatOneRev_Sem, 0);
result = rt_sem_take(CatOneRev_Sem, CatOne.CatOne1mSDelayCnt);
if(result != RT_EOK) {
/*超时: 未注册成功视为服务器无响应重新注网; 已注册则仅本周期无数据*/
if(CatOne.GateWay->MuchRegFlag == false) {
/*未注册超时: 保持连接不重启(兼容网络调试助手等不回注册应答的对端);
连接自愈由LIPSEND失败与空闲5分钟重连兜底*/
CAT1_DBG_LOG("Cat1 reg timeout, keep link!\r\n");
}
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
break;
}
result = rt_sem_take(CatOneRev_Sem, CatOne.CatOne1mSDelayCnt);
if(result != RT_EOK) {
if(CatOne.TcpConnFlag == false) {
CAT1_DBG_LOG("Cat1 Rec Server Data Timeout!\r\n");
break;
}
}
else {
Cat1RevErrCnt = 0;
}
if(CatOne.GateWay->MuchRegFlag == false)
CatOne.Cat1Status = CAT_ONE_OFF;
else
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
/*信号量唤醒: 服务器有数据到达(注册应答/业务/升级会话), 直接进发送态取待发帧*/
Cat1RevErrCnt = 0;
CatOne.Cat1Status = CAT_ONE_WAIT_SEND;
break;
case CAT_ONE_CLOSE_TCP:
CatOne.AtCmdResendCnt = 3;
CatOneAtCmdSend(CAT_ONE_LTPCLOSE, 1000, CatOne.NextStatus);
break;
case CAT_ONE_DUCH_MODE:
Cat1DuchReady = true;
uint32_t runMs = 0;
while(ChannelIsActive(CatOne.GateWay->ConfigPara, CH_CAT1)) {
if(duchRd != duchWr) {
uint16_t avail = (duchWr - duchRd) & 0x1FFF;
uint16_t n = avail > 240 ? 240 : avail;
sprintf(CatOne.CatOneSendBuff, "AT+QISEND=0,%d\r\n", n);
DebugOrCat1UartSend((uint8_t *)CatOne.CatOneSendBuff, strlen(CatOne.CatOneSendBuff));
rt_thread_delay(200);
runMs += 200;
if(duchRd + n <= 8192) {
DebugOrCat1UartSend((uint8_t *)&duchRing[duchRd], n);
} else {
uint16_t part = 8192 - duchRd;
DebugOrCat1UartSend((uint8_t *)&duchRing[duchRd], part);
DebugOrCat1UartSend((uint8_t *)duchRing, n - part);
}
DebugOrCat1UartSend((uint8_t *)"\x1A", 1);
rt_thread_delay(500);
runMs += 500;
duchRd = (duchRd + n) & 0x1FFF;
} else {
rt_thread_delay(50);
runMs += 50;
}
if(runMs >= 1800000) {
CatOne.NextStatus = CAT_ONE_TCP_CONN;
CatOne.Cat1Status = CAT_ONE_CLOSE_TCP;
break;
}
}
Cat1DuchReady = false;
break;
case CAT_ONE_OFF:
CAT1_RESET_SET();
@@ -598,12 +605,12 @@ void CatOneLoopHandler(void)
rt_thread_delay(3000);
CAT1_PWR_KEY_SET();
CatSendErrCnt = 0;
Cat1IdleReconnFlag = 0; /*模组重启路径恢复完整注册流程*/
CatOne.RegisterDelayCnt = 0;
CAT1_DBG_LOG("Cat1 Power Off!\r\n");
CatOne.Cat1Status = CAT_ONE_IDEL;
CatOne.ResetDelayCnt = CATONE_RESET_DELAY_TIME_MAX;
DBG_ON();
break;
CatOne.ResetDelayCnt = CATONE_RESET_DELAY_TIME_MAX;
break;
case CAT_ONE_RESET:
CatSendErrCnt = 0;
@@ -644,10 +651,64 @@ static void CatOneInit(GateWayPara GateWay)
GateWay->MuchRevCallBack : GateWay->AuchRevCallBack;
}
/*+LIPURC异步事件统一分发: 与AT状态机无关, 任何状态下都能处理升级帧/业务数据*/
/*一批数据包的URC会连发, 多条可能挤进同一缓冲块: 必须循环解析每一条*/
static void CatOneUrcHandle(GateWayPara GateWay, char *RxBuff)
{
static char rData[3010]; /*static: 大缓冲+单线程访问*/
static uint8_t hData[1510];
char *p;
int rLen = 0, hLen;
if(strstr(RxBuff, "+LIPURC: 0,0") != NULL) {
CAT1_DBG_LOG("TCP connection disconnected.\r\n\r\n");
CatOne.TcpConnFlag = false;
CatOne.Cat1Status = CAT_ONE_OFF;
return;
}
p = strstr(RxBuff, "+LIPURC: 0,1,");
while(p != NULL) {
if(sscanf(p, "+LIPURC: 0,1,%d,%3000s", &rLen, rData) == 2) {
int sLen = (int)strlen(rData); /*data字段被命令内\r\n截断(%s遇空白停): 以实际可读长度为准, 兼容明文命令与hex帧*/
if(sLen > 0) {
memset(hData, 0x00, sizeof(hData)); /*ASCII hex转二进制(服务器下发为hex文本)*/
hLen = IsHexText(rData, sLen) ? AsciiToHex(rData, hData, sLen) : 0;
if(hLen == 0) {
/*非hex明文(如网络调试助手直发命令): 原样直通调试解析, 与ETH口明文直通一致*/
hLen = (sLen < (int)sizeof(hData)) ? sLen : (int)sizeof(hData) - 1;
memcpy(hData, rData, hLen);
CAT1_DBG_LOG("Cat1 rx plaintext %d bytes, to DebugAnalyze\r\n", hLen);
}
CatSendErrCnt = 0;
Cat1RevErrCnt = 0; /*server data arrived: reload watchdog*/
if(hLen > 0 && NetUpgradeFeed(hData, hLen, CH_CAT1)) {
/*0x7D frame consumed by NetUpgrade*/
}
else if(hLen > 0 && hData[0] == 0x7A) { /*0x7A业务帧: 按Much/Auch配置分流*/
if(CatOne.GateWay->ConfigPara.Much == CH_CAT1)
GateWay->MuchRevCallBack(GateWay, hData, hLen);
else
GateWay->AuchRevCallBack(GateWay, hData, hLen);
}
else if(hLen > 0) {
DebugAnalyze(GateWay, hData, hLen); /*明文调试命令: duch=cat1时服务端远程para等指令*/
}
}
}
else {
CAT1_DBG_LOG("LIPURC parse fail, drop!\r\n");
}
p = strstr(p + 13, "+LIPURC: 0,1,"); /*头部长13字节, 继续找下一条URC*/
}
rt_sem_release(CatOneRev_Sem); /*通知AT状态机: 已收到服务器数据(维持REV_DATA快速返回)*/
}
void CatOneRev_Thread_Entry(void *parameter)
{
rt_err_t result;
char RxBuffTemp[CAT_ONE_REV_LEN_MAX];
static char RxBuffTemp[CAT_ONE_URC_LEN_MAX]; /*static: 大缓冲避免拆分线程栈(单线程访问)*/
static uint16_t RxResidual = 0; /*残留半条URC长度(跨块拼接), 单线程访问*/
GateWayPara GateWay = (GateWayPara)parameter;
@@ -656,18 +717,40 @@ void CatOneRev_Thread_Entry(void *parameter)
while(1) {
result = rt_sem_take(CatOneIRQ_Sem, 500);
if(result == RT_EOK) {
memcpy(RxBuffTemp, CatOneRxBuff, CatOneRxLen);
RxBuffTemp[CatOneRxLen] = 0;
CatOneRxLen = 0;
char *urc = strstr(RxBuffTemp, "+LIPURC: 0,1,");
if(urc) {
char *data = strchr(strchr(strchr(urc, ',')+1, ',')+1, ',') + 1;
char *end = strchr(data, '\r');
if(end) *end = 0;
DebugAnalyze(GateWay, (uint8_t *)data, strlen(data));
if(Cat1RxSyncReq) { /*IRQ已超时清链: 陈旧残留作废重新同步*/
Cat1RxSyncReq = 0;
RxResidual = 0;
}
if(RxResidual + CatOneRxLen > CAT_ONE_URC_LEN_MAX - 1) {
RxResidual = 0; /*溢出保护: 丢弃残留重新同步*/
}
memcpy(RxBuffTemp + RxResidual, CatOneRxBuff, CatOneRxLen);
RxResidual += CatOneRxLen;
RxBuffTemp[RxResidual] = 0;
CatOneRxLen = 0;
if(strstr(RxBuffTemp, "+LIPURC") != NULL) {
/*按完整行切分: 最后一个\n之前逐条解析, 之后作残留等下一块拼接*/
char *lastNl = NULL;
char *scan = RxBuffTemp;
char *nl;
while((nl = strchr(scan, 0x0A)) != NULL) { lastNl = nl; scan = nl + 1; }
if(lastNl != NULL) {
int keep = (int)(RxResidual - (int)(lastNl + 1 - RxBuffTemp));
*(lastNl + 1) = 0; /*完整区以\n结尾截断*/
CatOneUrcHandle(GateWay, RxBuffTemp);
if(keep > 0) {
memmove(RxBuffTemp, lastNl + 1, keep);
RxResidual = (uint16_t)keep;
} else {
RxResidual = 0;
}
RxBuffTemp[RxResidual] = 0;
}
}
else {
CatOneAtCmdAnalyze(RxBuffTemp);
RxResidual = 0; /*AT应答整块消费*/
}
CatOneAtCmdAnalyze(RxBuffTemp);
memset(CatOneRxBuff, 0x00, CAT_ONE_REV_LEN_MAX);
}
}
}
@@ -699,20 +782,19 @@ void CatOne_Thread_Entry(void *parameter)
rt_kprintf("CatOne Thread is running!\r\n");
while(1) {
if(!ChannelIsActive(GateWay->ConfigPara, CH_CAT1)) {
rt_thread_delay(100);
continue;
}
/*USART1专用Cat1: 上电即持续注册连接, 不再依赖通道配置*/
CatOneLoopHandler();
}
}
void Cat1IrqCallback(uint8_t rData)
{
if(Cat1RevTimeOutCnt == 0)
if(Cat1RevTimeOutCnt == 0) {
CatOneRxLen = 0;
Cat1RxSyncReq = 1; /*stale partial URC: Rev side resyncs*/
}
if(CatOneRxLen < CAT_ONE_REV_LEN_MAX) {
if(CatOneRxLen < CAT_ONE_URC_LEN_MAX) {
CatOneRxBuff[CatOneRxLen++] = rData;
}
@@ -749,3 +831,4 @@ void CatOneTriggerRegister(void)
CAT1_ON();
CatOneReset();
}
+93 -27
View File
@@ -1,14 +1,30 @@
#include "EthTask.h"
#include "Public.h"
#include "DebugCmd.h"
#include "Update.h"
static rt_sem_t EthIRQ_Sem = RT_NULL;
static rt_thread_t EthRev_Thread = RT_NULL;
static EthTask_t Eth;
static char EthRxBuff[ETH_RX_LEN_MAX];
static uint16_t EthRxLen;
/*单生产(IRQ)单消费(Rev)环形缓冲: 无锁, 读写指针独立安全; 防Rev处理期间IRQ覆盖丢包*/
#define ETH_RING_SIZE 8192
static uint8_t EthRingBuf[ETH_RING_SIZE];
static volatile uint16_t EthRingW = 0, EthRingR = 0;
static uint16_t EthRingLen(void)
{
return (uint16_t)((EthRingW - EthRingR + ETH_RING_SIZE) % ETH_RING_SIZE);
}
static uint16_t EthRingGet(uint8_t *dst, uint16_t max)
{
uint16_t n = 0;
while(n < max && EthRingR != EthRingW) {
dst[n++] = EthRingBuf[EthRingR];
EthRingR = (uint16_t)((EthRingR + 1) % ETH_RING_SIZE);
}
return n;
}
static uint8_t EthRevTimeOutCnt;
static uint8_t Payload[ETH_RX_LEN_MAX];
@@ -79,7 +95,6 @@ static int GateWayRegister(uint8_t *TxBuff)
void EthLoopHandler(void)
{
rt_err_t result;
switch(Eth.Status) {
case ETH_IDEL:
rt_thread_delay(1);
@@ -156,6 +171,11 @@ void EthLoopHandler(void)
break;
case ETH_WAIT_SEND:
if(NetUpgradePopTx(Eth.TxBuff, &Eth.TxLen, CH_ETH)) { /*升级应答帧第一优先(仅取本通道帧)*/
Eth.Status = ETH_SEND_DATA;
break;
}
result = rt_mq_recv(ChannelMQ(*Eth.GateWay, CH_ETH), Payload, ETH_RX_LEN_MAX, 100);
if(result == RT_EOK) {
Eth.TxLen = NetCommOrgData(Eth.GateWay, Payload, Eth.TxBuff);
@@ -188,6 +208,7 @@ void EthLoopHandler(void)
}
HexToAscii(Eth.TxBuff, CommUnitSendASCII, Eth.TxLen);
EthRevTimeOutCnt = 0;
EthUartSend((uint8_t *)CommUnitSendASCII, Eth.TxLen * 2);
CommUnitSendASCII[Eth.TxLen * 2] = 0;
ETH_DBG_LOG("Eth Send: %s\r\n", CommUnitSendASCII);
@@ -259,13 +280,11 @@ static void EthInit(GateWayPara GateWay)
void EthIrqCallbackHandler(uint8_t rData)
{
if(EthRevTimeOutCnt == 0)
EthRxLen = 0;
if(EthRxLen < ETH_RX_LEN_MAX) {
EthRxBuff[EthRxLen++] = rData;
if((uint16_t)((EthRingW + 1) % ETH_RING_SIZE) != EthRingR) { /*未满才入, IRQ不阻塞*/
EthRingBuf[EthRingW] = rData;
EthRingW = (uint16_t)((EthRingW + 1) % ETH_RING_SIZE);
}
/*强制入环: 满时覆盖旧数据, IRQ永不阻塞*/
EthRevTimeOutCnt = 3;
}
@@ -274,7 +293,7 @@ void EthOverHandler(void)
if(EthRevTimeOutCnt > 0)
EthRevTimeOutCnt--;
if(EthRxLen > 0 && EthRevTimeOutCnt == 0) {
if(EthRingLen() > 0 && EthRevTimeOutCnt == 0) {
EthRevTimeOutCnt = 20;
rt_sem_release(EthIRQ_Sem);
}
@@ -292,24 +311,59 @@ static void EthRev_Thread_Entry(void *parameter)
while(1) {
result = rt_sem_take(EthIRQ_Sem, 500);
if(result == RT_EOK || EthRxLen > 1) {
if(EthRxLen == 0) continue;
memcpy(RxBuffTemp, EthRxBuff, EthRxLen);
RxBuffTemp[EthRxLen] = 0;
memset(HexData, 0x00, EthRxLen / 2);
uint8_t ret = AsciiToHex(RxBuffTemp, HexData, EthRxLen);
if(ret > 0 && HexData[0] == 0x7A) {
Eth.SendNoDataCnt = 0;
if(GateWay->ConfigPara.Much == CH_ETH)
GateWay->MuchRevCallBack(GateWay, HexData, ret);
else
GateWay->AuchRevCallBack(GateWay, HexData, ret);
uint16_t n = EthRingLen();
if(result == RT_EOK || n > 1) {
if(n == 0) continue;
n = EthRingGet((uint8_t *)RxBuffTemp, ETH_RX_LEN_MAX - 1);
RxBuffTemp[n] = 0;
uint16_t ret = 0;
if(NetUpgradeActive()) {
/*升级会话: 纯hex流模式, 奇数尾字符跨块拼接(模组512字节透传块会切在帧任意位置)*/
static char hexTail = 0;
static bool tailV = false;
if(tailV && n < ETH_RX_LEN_MAX) {
memmove(&RxBuffTemp[1], RxBuffTemp, n);
RxBuffTemp[0] = hexTail;
n++; tailV = false;
} else { tailV = false; }
if(n % 2 == 1) { hexTail = RxBuffTemp[n - 1]; tailV = true; n--; }
RxBuffTemp[n] = 0;
if(n > 0 && IsHexText(RxBuffTemp, n)) {
memset(HexData, 0x00, ETH_RX_LEN_MAX / 2);
ret = AsciiToHex(RxBuffTemp, HexData, n);
bool fed = (ret > 0) ? NetUpgradeFeed(HexData, ret, CH_ETH) : false;
/*注意: 会话内禁止全量hex打印, 串口打印阻塞EthRev线程导致USART RX缓冲溢出丢包*/
if(fed) Eth.SendNoDataCnt = 0; /*清看门狗防升级会话被复位*/
}
}
else if(EthRxLen > 1) {
DebugAnalyze(GateWay, (uint8_t *)RxBuffTemp, EthRxLen);
else {
/*非会话: hex业务帧/明文命令分流(0x81握手在此分支进入升级模块)*/
memset(HexData, 0x00, n / 2);
bool hexv = IsHexText(RxBuffTemp, n);
if(hexv) {
ret = AsciiToHex(RxBuffTemp, HexData, n);
}
bool fed = (ret > 0) ? NetUpgradeFeed(HexData, ret, CH_ETH) : false;
if(fed) {
Eth.SendNoDataCnt = 0;
}
else if(ret > 0 && HexData[0] == 0x7A) {
Eth.SendNoDataCnt = 0;
if(GateWay->ConfigPara.Much == CH_ETH)
GateWay->MuchRevCallBack(GateWay, HexData, ret);
else
GateWay->AuchRevCallBack(GateWay, HexData, ret);
}
else if(n > 1) {
DebugAnalyze(GateWay, (uint8_t *)RxBuffTemp, n);
}
}
memset(EthRxBuff, 0x00, ETH_RX_LEN_MAX);
EthRxLen = 0;
if(EthRingLen() > 0)
rt_sem_release(EthIRQ_Sem); /*缓冲仍有数据: 自释放信号量连续泵空*/
}
}
}
@@ -339,8 +393,20 @@ void Eth_Thread_Entry(void *parameter)
rt_kprintf("Eth Thread is running!\r\n");
while(1) {
/*升级会话应答帧: 最高优先直发, 不依赖通道配置/LINK状态/状态机(ACK原路CH_ETH返回)*/
if(NetUpgradeActive() && NetUpgradePopTx(Eth.TxBuff, &Eth.TxLen, CH_ETH)) {
HexToAscii(Eth.TxBuff, CommUnitSendASCII, Eth.TxLen);
CommUnitSendASCII[Eth.TxLen * 2] = 0;
EthUartSend((uint8_t *)CommUnitSendASCII, Eth.TxLen * 2);
}
if(!ChannelIsActive(GateWay->ConfigPara, CH_ETH)) {
rt_thread_delay(100);
rt_thread_delay(20);
continue;
}
if(NetUpgradeActive()) {
/*升级会话: 状态机旁路(防RESET/OFF复位模组断链), 应答走主循环直发+接收线程收包*/
rt_thread_delay(5);
continue;
}
EthLoopHandler();
+1 -1
View File
@@ -92,7 +92,7 @@ void Lora_Thread_Entry(void *parameter)
Debug_Printf("CatOneIRQ Sem Create Failed!\r\n");
}
LoraIRQ_Thread = rt_thread_create("LoraIRQ", LoraIRQ_Thread_Entry, NULL, 1024, 3, 20);
LoraIRQ_Thread = rt_thread_create("LoraIRQ", LoraIRQ_Thread_Entry, NULL, 2048, 3, 20);
if (LoraIRQ_Thread != RT_NULL)
rt_thread_startup(LoraIRQ_Thread);
+20 -2
View File
@@ -126,10 +126,28 @@ void HexToAscii(uint8_t *HexData, char *ASCData, uint8_t sLen)
sLen, 需要转的字符串长度
* 返 回 值: 无
*****************************************************************************************/
uint8_t AsciiToHex(char *ASCData, uint8_t *HexData, uint8_t sLen)
/*****************************************************************************************
* 函数名称: IsHexText
* 功能描述: 判断缓冲区内容是否为合法hex文本(AsciiToHex不校验字符合法性, 非hex明文须先识别)
* 参 数: s, 待判断字符串; len, 字符长度
* 返 回 值: true=合法hex文本(全字符∈[0-9a-fA-F]且偶数长度)
*****************************************************************************************/
bool IsHexText(char *s, uint16_t len)
{
if(len == 0 || len % 2 != 0)
return false;
for(uint16_t i = 0; i < len; i++) {
char c = s[i];
if(!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')))
return false;
}
return true;
}
uint16_t AsciiToHex(char *ASCData, uint8_t *HexData, uint16_t sLen)
{
char chr;
uint8_t HexLen = 0;
uint16_t HexLen = 0; /*uint16: 大块(512字符=256字节)时uint8溢出归0导致ret=0丢帧*/
if(sLen % 2 == 1)
return 0;
+456 -57
View File
@@ -1,61 +1,460 @@
#include "Update.h"
#include "DebugCmd.h"
#include "main.h"
#include "bsp.h"
#include "spiflash.h"
extern GateWayPara_t GateWay;
#include "Update.h"
#include "DebugCmd.h"
#include "main.h"
#include "bsp.h"
#include "spiflash.h"
#include <rthw.h> /*rt_hw_interrupt_disable/enable: TX queue critical section*/
extern GateWayPara_t GateWay;
static void NetUpgradeSavePkg(uint32_t PkgCnt); /*fwd decl: Update() calls it before its definition*/
/*****************************************************************************************
* 函数名称: Update
* 功能描述: 固件升级,此函数在解析到升级指令时调用
* 参 数: PayLoad 协议负载,需去除帧头等信息,只传负载数据
* 返 回 值: 无
*****************************************************************************************/
void Update(uint8_t *PayLoad)
{
UpDataRequset_t Req;
boot_para_t cfg = {0};
memcpy(&Req, PayLoad, sizeof(UpDataRequset_t));
/*固件大小校验: 为0或超出B区容量时拒绝升级, 不置标志不复位*/
if(Req.AppSize == 0 || Req.AppSize > FLASH_APPB_SIZE) {
U_DBG_LOG("AppSize invalid: %d (max %d)\r\n", (int)Req.AppSize, (int)FLASH_APPB_SIZE);
return;
}
/*读回现有boot参数,保留FirstRunFlag等字段*/
dev_boot_read_param(&cfg);
cfg.AppSize = Req.AppSize;
cfg.Crc32Check = Req.AppCrc32;
cfg.PackageCnt = Req.PackageNum;
cfg.AppFlag = 0;
cfg.UpdateFlag = APP_UPDATE_FLAG;
memcpy(cfg.GwMac, GateWay.ConfigPara.GwMac, 6);
U_DBG_LOG("Receive upgrade command:\r\n");
U_DBG_LOG("PackageNum: %d\r\n", cfg.PackageCnt);
U_DBG_LOG("AppSize: %d\r\n", cfg.AppSize);
U_DBG_LOG("AppCrc32: 0x%08x\r\n", cfg.Crc32Check);
U_DBG_LOG("System Reset!\r\n");
NetUpgradeSavePkg(0);
SAVE_BOOT_PARA(&cfg);
U_DELAY_MS(200);
U_SYSTEM_TESET();
}
/*****************************************************************************************
* 函数名称: UpdateInit
* 功能描述: 升级参数初始化,需要在程序启动,外设初始化完后调用
* 参 数: 无
* 返 回 值: 无
*****************************************************************************************/
void UpdateInit(void)
{
boot_para_t cfg;
READ_BOOT_PARA(&cfg);
/*参照hc32l170_app: 仅确保AppFlag=APP_START_FLAG, 使Boot下次直接跳转App
(网关MAC/服务器/Lora配置从BootPara_t获取, 由Boot配置)*/
if(cfg.AppFlag != APP_START_FLAG) {
cfg.AppFlag = APP_START_FLAG;
SAVE_BOOT_PARA(&cfg);
}
}
/*****************************************************************************************
* Cat1远程升级模块(0x7D帧, 与Boot RS485升级协议一致)
* 服务器(升级主机) --TCP--> Cat1模组 --USART1--> 本模块:
* 收0x81升级请求(校验/擦暂存区/断点续传判定) → 0x82分包顺序写入外部SPI Flash暂存区
* → 每收NUP_WINDOW包回0x02请求帧(服务端窗口流控) → 收完CRC32校验通过后置
* APP_UPDATE_SPI_FLAG复位, 由Boot完成"外部Flash→B区→A区"搬运
* 协议帧: 0x7D + DevMac(6) + Cmd + Len + Payload + CRC16(Modbus), 命令0x81/0x82/0x01/0x02
*****************************************************************************************/
#define NUP_PACKET_DATA 200 //每包数据长度(与服务端/Boot一致)
#define NUP_STASH_PROG_MAGIC 0xA5A5C35A //升级进度记录魔数
#define NUP_WINDOW 8 //每收W包回一次请求帧
#define NUP_TIMEOUT_MS 3000 //等包超时(Cat1延迟大)
#define NUP_TIMEOUT_MAX 5 //连续超时次数上限
#define NUP_IDLE_TIMEOUT_MS 1800000UL //整体无进展超时(30分钟)
#define NUP_FRAME_BUF_MAX 3072 //0x7D组帧缓冲上限(容纳URC单次喂入的多帧拼接)
#define NUP_APP_MAX (232 * 1024) //A区容量上限
/*升级进度记录(存外部Flash扇区4037): 断电/断连后据此判定断点续传*/
typedef struct {
uint32_t Magic; //NUP_STASH_PROG_MAGIC
uint32_t AppSize; //固件大小
uint32_t Crc32; //固件CRC32
uint32_t PkgCnt; //已连续收到的包数
}FwStashProg_t;
static struct {
bool Active; //升级会话进行中
uint16_t PkgCnt; //总包数
uint32_t AppSize; //固件大小
uint32_t Crc32; //固件CRC32
uint16_t ExpectIdx; //期望接收的包序号
uint16_t LastAckIdx; //最近一次0x02应答的包序号(窗口流控基准)
uint32_t LastTick; //最近收包时刻(rt_tick, 1ms)
uint32_t ErrCnt; //连续超时次数
uint8_t TxQ[4][40]; //应答帧队列(0x01/0x02连发互不挤占)
uint8_t TxQLen[4];
uint8_t TxHead;
uint8_t TxChan[4]; /*每帧来源通道: ACK从收到0x81的通道原路返回*/
uint8_t CurCh; /*当前会话通道: Feed进入时记录*/ //队首索引(出队)
uint8_t TxCnt; //队列帧数
}Nup;
static uint8_t NupFrameBuf[NUP_FRAME_BUF_MAX]; //0x7D组帧缓冲(TCP分片跨URC拼接)
static uint16_t NupFrameLen = 0;
static uint64_t NupErasedMap = 0; /*bit i: stash sector i erased this session (NOR writes only 1->0, erase-before-write required)*/
/*软件CRC32: 与Boot GetCrc32/服务端zlib.crc32同算法(0xEDB88320反射, 初末值0xFFFFFFFF)*/
static uint32_t NetUpgradeCrc32Stash(uint32_t Len)
{
uint32_t Crc = 0xFFFFFFFF;
uint32_t Done = 0;
uint8_t Buf[256];
while(Done < Len) {
uint16_t n = (Len - Done > sizeof(Buf)) ? sizeof(Buf) : (uint16_t)(Len - Done);
FwStashRead(Buf, Done, n);
for(uint16_t i = 0; i < n; i++) {
Crc ^= Buf[i];
for(int b = 0; b < 8; b++) {
Crc = (Crc & 1) ? (Crc >> 1) ^ 0xEDB88320 : (Crc >> 1);
}
}
Done += n;
}
return ~Crc;
}
/*进度记录持久化(扇区4037): PkgCnt=0表示清除*/
static void NetUpgradeSavePkg(uint32_t PkgCnt)
{
FwStashProg_t Prog;
Prog.Magic = (PkgCnt > 0) ? NUP_STASH_PROG_MAGIC : 0;
Prog.AppSize = Nup.AppSize;
Prog.Crc32 = Nup.Crc32;
Prog.PkgCnt = PkgCnt;
FwStashProgWrite((uint8_t *)&Prog, sizeof(Prog));
}
/*待发帧入队(0x7D原始帧, 由CatOne主循环经AT+LIPSEND直发, 绕过0x7A打包)*/
static void NetUpgradePushTx(uint8_t Cmd, uint8_t *Payload, uint8_t Len)
{
uint16_t crc;
rt_base_t level = rt_hw_interrupt_disable();
if(Nup.TxCnt >= 4) {
rt_hw_interrupt_enable(level);
return; /*queue full: drop*/
}
{
uint8_t Tail = (Nup.TxHead + Nup.TxCnt) % 4;
Nup.TxQ[Tail][0] = 0x7D;
memcpy(&Nup.TxQ[Tail][1], GateWay.ConfigPara.GwMac, 6);
Nup.TxQ[Tail][7] = Cmd;
Nup.TxQ[Tail][8] = Len;
memcpy(&Nup.TxQ[Tail][9], Payload, Len);
crc = CRC_Modbus(CRC16_BASE, Nup.TxQ[Tail], 9 + Len);
Nup.TxQ[Tail][9 + Len] = crc & 0xFF;
Nup.TxQ[Tail][10 + Len] = (crc >> 8) & 0xFF;
Nup.TxQLen[Tail] = 11 + Len;
Nup.TxChan[Tail] = Nup.CurCh; /*绑定来源通道*/
Nup.TxCnt++;
}
rt_hw_interrupt_enable(level);
U_DBG_LOG("NetUpgrade push: cmd=0x%02x cnt=%d\r\n", Cmd, Nup.TxCnt);
}
static void NetUpgradeSendAck(uint8_t Status, uint16_t Resumed)
{
uint8_t p[3];
p[0] = Status;
p[1] = Resumed & 0xFF;
p[2] = (Resumed >> 8) & 0xFF;
NetUpgradePushTx(0x01, p, 3); //0x20全新/0x21续传/0x32拒绝
}
static void NetUpgradeSendReq(uint16_t Idx)
{
uint8_t p[4];
p[0] = Idx & 0xFF;
p[1] = (Idx >> 8) & 0xFF;
p[2] = Nup.PkgCnt & 0xFF;
p[3] = (Nup.PkgCnt >> 8) & 0xFF;
NetUpgradePushTx(0x02, p, 4); //请求从Idx起的下一批(收满PkgCnt视为完成)
}
/*0x81升级请求: 合法性检查/回ACK并启动下载*/
static void NetUpgradeOnReq(uint8_t *Payload, uint8_t Len)
{
UpDataRequset_t Req;
if(Len < sizeof(Req)) {
return;
}
memcpy(&Req, Payload, sizeof(Req));
if(Req.AppSize == 0 || Req.AppSize > NUP_APP_MAX) {
NetUpgradeSendAck(0x32, 0);
U_DBG_LOG("NetUpgrade reject: AppSize=%d\r\n", Req.AppSize);
return;
}
/*断点续传已取消: 每次点击升级均从0%全新下载*/
NetUpgradeSavePkg(0);
NupErasedMap = 0;
Nup.Active = true;
Nup.PkgCnt = Req.PackageNum;
Nup.AppSize = Req.AppSize;
Nup.Crc32 = Req.AppCrc32;
Nup.ExpectIdx = 0;
Nup.ErrCnt = 0;
Nup.LastTick = rt_tick_get();
Nup.LastAckIdx = 0;
U_DBG_LOG("NetUpgrade req: Pkg=%d Size=%d Crc=0x%08x Resumed=0\r\n",
Nup.PkgCnt, Nup.AppSize, Nup.Crc32);
NetUpgradeSendAck(0x20, 0);
NetUpgradeSendReq(0); //请求首包, 服务端收到0x02才开始发包
}
/*0x82升级数据: 严格按期望包号顺序写暂存区, 收满窗口回请求帧, 收完CRC校验*/
static void NetUpgradeOnData(uint8_t *Payload, uint8_t Len)
{
uint16_t Idx, Total;
uint8_t DataLen;
uint32_t WriteLen;
if(!Nup.Active || Len < 5) {
return;
}
Idx = Payload[0] | (Payload[1] << 8);
Total = Payload[2] | (Payload[3] << 8);
DataLen = Payload[4];
if(Total != Nup.PkgCnt) {
return; //会话不匹配
}
if(Idx != Nup.ExpectIdx) {
return; //重复/乱序包: 丢弃(服务端按期望包号重发)
}
if(Idx == Nup.PkgCnt - 1) {
WriteLen = Nup.AppSize - (uint32_t)Idx * NUP_PACKET_DATA; //尾包实长
if(DataLen < WriteLen) {
return;
}
}
else {
if(DataLen < NUP_PACKET_DATA) {
return;
}
WriteLen = NUP_PACKET_DATA;
}
{
/*NOR only writes 1->0: erase touched stash sectors before write (one erase per sector per session), fixes stale-bit corruption on 2nd upgrade*/
uint32_t Sec0 = (uint32_t)Idx * NUP_PACKET_DATA / SPIFLASH_SECTORSIZE;
uint32_t Sec1 = ((uint32_t)Idx * NUP_PACKET_DATA + WriteLen - 1) / SPIFLASH_SECTORSIZE;
for(uint32_t s = Sec0; s <= Sec1; s++) {
if((NupErasedMap & ((uint64_t)1 << s)) == 0) {
FwStashEraseSector(s);
NupErasedMap |= (uint64_t)1 << s;
}
}
}
FwStashWrite(&Payload[5], (uint32_t)Idx * NUP_PACKET_DATA, WriteLen);
Nup.ExpectIdx++;
Nup.LastTick = rt_tick_get();
Nup.ErrCnt = 0;
if(Nup.ExpectIdx >= Nup.PkgCnt) {
if(NetUpgradeCrc32Stash(Nup.AppSize) == Nup.Crc32) {
U_DBG_LOG("NetUpgrade stash verified, reboot to bootloader\r\n");
UpdateFromStash(Nup.AppSize, Nup.Crc32); //置APP_UPDATE_SPI_FLAG并复位
}
U_DBG_LOG("NetUpgrade stash CRC failed, restart download\r\n");
//校验失败: 从0重下(写前按需擦除保证暂存区干净)
NetUpgradeSavePkg(0);
NupErasedMap = 0;
Nup.ExpectIdx = 0;
NetUpgradeSendReq(0);
return;
}
if(Nup.ExpectIdx - Nup.LastAckIdx >= NUP_WINDOW) {
NetUpgradeSendReq(Nup.ExpectIdx); //收满窗口, 请求下一批(与断点起点无关)
Nup.LastAckIdx = Nup.ExpectIdx;
}
if(Nup.ExpectIdx % (NUP_WINDOW * 4) == 0) {
NetUpgradeSavePkg(Nup.ExpectIdx); //定期持久化进度(32包一次)
}
}
static void NetUpgradeFrameHandler(uint8_t Cmd, uint8_t *Payload, uint8_t Len)
{
U_DBG_LOG("NetUpgrade frame: cmd=0x%02x len=%d\r\n", Cmd, Len);
switch(Cmd) {
case 0x81:
NetUpgradeOnReq(Payload, Len);
break;
case 0x82:
NetUpgradeOnData(Payload, Len);
break;
default:
break;
}
}
/*****************************************************************************************
* 函数名称: NetUpgradeFeed
* 功能描述: 喂入Cat1下行数据片段(+LIPURC二进制), 流式拼接提取完整0x7D升级帧
* 参 数: data/len, 二进制数据片段(TCP分片有序)
* 返 回 值: true=数据已被升级模块消费(帧头0x7D); false=非0x7D流, 调用方交还原0x7A路径
*****************************************************************************************/
bool NetUpgradeFeed(uint8_t *data, uint16_t len, uint8_t ch)
{
Nup.CurCh = ch; /*记录会话通道*/
if(NupFrameLen == 0) {
uint16_t skip = 0;
while(skip < len && data[skip] != 0x7D) {
skip++;
}
if(skip >= len) {
return false;
}
data += skip;
len -= skip;
}
if(NupFrameLen + len > NUP_FRAME_BUF_MAX) {
NupFrameLen = 0; //溢出保护, 重新同步
return true;
}
memcpy(&NupFrameBuf[NupFrameLen], data, len);
NupFrameLen += len;
while(NupFrameLen >= 11) {
if(NupFrameBuf[0] != 0x7D) {
uint16_t i;
for(i = 1; i < NupFrameLen; i++) {
if(NupFrameBuf[i] == 0x7D) break;
}
if(i >= NupFrameLen) {
NupFrameLen = 0;
break;
}
memmove(NupFrameBuf, &NupFrameBuf[i], NupFrameLen - i);
NupFrameLen -= i;
continue;
}
uint16_t total = 11 + NupFrameBuf[8];
if(NupFrameLen < total) {
break; //帧未收齐, 等下一分片
}
uint16_t calc = CRC_Modbus(CRC16_BASE, NupFrameBuf, total - 2);
uint16_t recv = NupFrameBuf[total - 2] | (NupFrameBuf[total - 1] << 8);
if(calc == recv) {
/*MAC filter: only the device whose own GwMac matches the 0x7D frame header handles the frame,
broadcast 0x81 is answered by the target device only, other devices drop it silently*/
if(memcmp(&NupFrameBuf[1], GateWay.ConfigPara.GwMac, 6) == 0) {
NetUpgradeFrameHandler(NupFrameBuf[7], &NupFrameBuf[9], NupFrameBuf[8]);
}
else {
U_DBG_LOG("NetUpgrade MAC mismatch, check upgrade dialog MAC\r\n");
}
memmove(NupFrameBuf, &NupFrameBuf[total], NupFrameLen - total);
NupFrameLen -= total;
}
else {
memmove(NupFrameBuf, &NupFrameBuf[1], NupFrameLen - 1);
NupFrameLen -= 1;
}
}
return true;
}
/*****************************************************************************************
* 函数名称: Update
* 功能描述: 固件升级,此函数在解析到升级指令时调用
* 参 数: PayLoad 协议负载,需去除帧头等信息,只传负载数据
* 返 回 值: 无
* 函 数 名: NetUpgradePopTx
* 功 能: 取出本通道应答帧(0x01 ACK/0x02请求), 供CatOne主循环/EthTask经AT+LIPSEND直发
*****************************************************************************************/
void Update(uint8_t *PayLoad)
bool NetUpgradePopTx(uint8_t *Out, uint16_t *OutLen, uint8_t ch)
{
UpDataRequset_t Req;
boot_para_t cfg = {0};
memcpy(&Req, PayLoad, sizeof(UpDataRequset_t));
/*读回现有boot参数,保留FirstRunFlag等字段*/
dev_boot_read_param(&cfg);
cfg.AppSize = Req.AppSize;
cfg.Crc32Check = Req.AppCrc32;
cfg.PackageCnt = Req.PackageNum;
cfg.AppFlag = 0;
cfg.UpdateFlag = APP_UPDATE_FLAG;
memcpy(cfg.GwMac, GateWay.ConfigPara.GwMac, 6);
U_DBG_LOG("Receive upgrade command:\r\n");
U_DBG_LOG("PackageNum: %d\r\n", cfg.PackageCnt);
U_DBG_LOG("AppSize: %d\r\n", cfg.AppSize);
U_DBG_LOG("AppCrc32: 0x%08x\r\n", cfg.Crc32Check);
U_DBG_LOG("System Reset!\r\n");
SAVE_BOOT_PARA(&cfg);
U_DELAY_MS(200);
U_SYSTEM_TESET();
}
/*****************************************************************************************
* 函数名称: UpdateInit
* 功能描述: 升级参数初始化,需要在程序启动,外设初始化完后调用
* 参 数: 无
* 返 回 值: 无
*****************************************************************************************/
void UpdateInit(void)
{
boot_para_t cfg;
READ_BOOT_PARA(&cfg);
/*参照hc32l170_app: 仅确保AppFlag=APP_START_FLAG, 使Boot下次直接跳转App
(网关MAC/服务器/Lora配置从BootPara_t获取, 由Boot配置)*/
if(cfg.AppFlag != APP_START_FLAG) {
cfg.AppFlag = APP_START_FLAG;
SAVE_BOOT_PARA(&cfg);
bool ret = false;
rt_base_t level = rt_hw_interrupt_disable();
for(uint8_t idx = 0; idx < Nup.TxCnt; idx++) {
uint8_t slot = (Nup.TxHead + idx) % 4;
if(Nup.TxChan[slot] != ch) continue; /*跳过其他通道的帧(Cat1/ETH各自取自己的ACK)*/
memcpy(Out, Nup.TxQ[slot], Nup.TxQLen[slot]);
*OutLen = Nup.TxQLen[slot];
uint8_t keep = Nup.TxCnt - idx - 1; /*slot之后的帧数: 依次前移紧凑*/
for(uint8_t m2 = 0; m2 < keep; m2++) {
uint8_t curSlot = (slot + m2) % 4;
uint8_t nxt = (slot + m2 + 1) % 4;
memcpy(Nup.TxQ[curSlot], Nup.TxQ[nxt], 40);
Nup.TxChan[curSlot] = Nup.TxChan[nxt];
Nup.TxQLen[curSlot] = Nup.TxQLen[nxt];
}
Nup.TxCnt--;
ret = true;
break;
}
}
rt_hw_interrupt_enable(level);
return ret;
}/*****************************************************************************************
* 函 数 名: NetUpgradeActive
* 功 能: 升级会话状态查询
*****************************************************************************************/
bool NetUpgradeActive(void)
{
return Nup.Active;
}
/*****************************************************************************************
* 函数名称: NetUpgradeTick
* 功能描述: 1ms轮询(CatOne主循环调用): 等包超时催发请求, 长期无进展放弃会话
*****************************************************************************************/
void NetUpgradeTick(void)
{
if(!Nup.Active) {
if(NupFrameLen > 0) {
NupFrameLen = 0; /*非会话期清理残片, 防止后续0x7A业务流被组帧器吞掉*/
}
return;
}
uint32_t Now = rt_tick_get();
if(Now - Nup.LastTick > NUP_IDLE_TIMEOUT_MS) {
Nup.Active = false;
NupFrameLen = 0;
U_DBG_LOG("NetUpgrade idle timeout(30min), abort session\r\n");
return;
}
if(Now - Nup.LastTick > NUP_TIMEOUT_MS) {
Nup.LastTick = Now;
NupFrameLen = 0; /*等包超时: 残片必为损坏流, 清掉重同步*/
Nup.ErrCnt++;
if(Nup.ErrCnt > NUP_TIMEOUT_MAX) {
Nup.Active = false; //放弃会话(不复位), 服务器可重新0x81发起
NupFrameLen = 0;
U_DBG_LOG("NetUpgrade timeout, abort session\r\n");
return;
}
NetUpgradeSendReq(Nup.ExpectIdx); //催发: 服务端重发当前批次
}
}
/*****************************************************************************************
* 函数名称: UpdateFromStash
* 功能描述: 暂存区校验通过后, 置APP_UPDATE_SPI_FLAG并复位, Boot从外部Flash搬运升级
*****************************************************************************************/
void UpdateFromStash(uint32_t AppSize, uint32_t Crc32)
{
boot_para_t cfg;
READ_BOOT_PARA(&cfg);
cfg.AppSize = AppSize;
cfg.Crc32Check = Crc32;
cfg.PackageCnt = (uint16_t)((AppSize + NUP_PACKET_DATA - 1) / NUP_PACKET_DATA);
cfg.AppFlag = 0;
cfg.UpdateFlag = APP_UPDATE_SPI_FLAG;
NetUpgradeSavePkg(0); /*清除进度记录:本次升级已完结,下次升级从0重新开始*/
U_DBG_LOG("Upgrade ready: Size=%d Crc=0x%08x, reboot\r\n", AppSize, Crc32);
SAVE_BOOT_PARA(&cfg);
U_DELAY_MS(200);
U_SYSTEM_TESET();
}
+7
View File
@@ -400,9 +400,14 @@ static void RS485Ch1UsartErrIrqCallback(void)
* 参 数: 无
* 返 回 值: 无
*****************************************************************************************/
static volatile bool RS485Ch1TxFlag = false; /*RS485Ch1发送期间置位: RX中断丢弃回环自收字节*/
static void RS485Ch1UsartRxIrqCallback(void)
{
uint8_t rData = RS485Ch1UartRec();
if(RS485Ch1TxFlag) {
return; /*发送回环自收字节丢弃*/
}
RS485Ch1RxIrqCallback(rData);
}
@@ -502,11 +507,13 @@ void RS485Ch1_Config(uint32_t BaudRate)
void RS485Ch1UartSend(uint8_t *sData, uint16_t sLen)
{
RS485_CH1_TX();
RS485Ch1TxFlag = true;
for(int i = 0; i < sLen; i++) {
USART_SendData(RS485_CH1_USART_CH, sData[i]);
while(USART_GetStatus(RS485_CH1_USART_CH, UsartTxComplete) == Reset);
}
RS485_CH1_RX();
RS485Ch1TxFlag = false;
}
/*****************************************************************************************
+5 -5
View File
@@ -235,7 +235,7 @@ void GateWayInit(void)
}
if(LoraSetFreqCent(GateWay.ConfigPara.Lora.FreqCent) == false)
{
GateWay.ConfigPara.Lora.FreqCent = 470100000;
GateWay.ConfigPara.Lora.FreqCent = 433100000; //lora-wide: 回退到CH0
LoraSetFreqCent(GateWay.ConfigPara.Lora.FreqCent);
}
if(LoraSetPower(GateWay.ConfigPara.Lora.ucPower) == false) {
@@ -285,10 +285,10 @@ void GateWayInit(void)
}
else
rt_kprintf("History Num: 0\r\n");
bool cat1Active = ChannelIsActive(GateWay.ConfigPara, CH_CAT1);
/*USART1专用Cat1: 上电恒115200+CAT1方向, 调试输出统一走RS485 Ch1(见rt_hw_console_output)*/
bool ethActive = ChannelIsActive(GateWay.ConfigPara, CH_ETH);
if(cat1Active) { DbgOrCat1Uart_Config(115200); CAT1_ON(); }
else { DBG_ON(); DbgOrCat1Uart_Config(500000); }
DbgOrCat1Uart_Config(115200);
CAT1_ON();
if(ethActive) { ETH_ON(); rt_thread_delay(1000); ETHReset(); }
}
@@ -397,7 +397,7 @@ int main(void)
else
return -1;
Lora_Thread = rt_thread_create("Lora", Lora_Thread_Entry, &GateWay, 1024, 3, 20);
Lora_Thread = rt_thread_create("Lora", Lora_Thread_Entry, &GateWay, 2048, 3, 20);
if (Lora_Thread != RT_NULL)
rt_thread_startup(Lora_Thread);
else
+59 -4
View File
@@ -323,7 +323,7 @@ void CheckDelSecter(uint32_t wAddr, uint16_t wLen)
uint32_t DelSectorNum = 0;
uint32_t SurplusSpace = SPIFLASH_SECTORSIZE - (wAddr % SPIFLASH_SECTORSIZE);
if((wAddr + wLen) > SPIFLASH_SIZE) {
if((wAddr + wLen) > LOG_SAV_END_ADDR) {
DelOffsetAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
SetLastLogEndAddr(DelOffsetAddr + wLen);
SetLoopSavFlag(1);
@@ -342,7 +342,7 @@ void CheckDelSecter(uint32_t wAddr, uint16_t wLen)
SpiFlashEraseSector(DelOffsetAddr);
DelOffsetAddr += SPIFLASH_SECTORSIZE;
}
if(DelOffsetAddr == SPIFLASH_SIZE) {
if(DelOffsetAddr == LOG_SAV_END_ADDR) {
DelOffsetAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
}
FindFirstLogAddr = DelOffsetAddr;
@@ -363,7 +363,7 @@ void CheckDelSecter(uint32_t wAddr, uint16_t wLen)
}
if(i == LOG_SAV_SIZE_MAX) {
ReadAddr += LOG_SAV_SIZE_MAX;
if(ReadAddr >= SPIFLASH_SIZE) { //找不到下一条数据,重置flash
if(ReadAddr >= LOG_SAV_END_ADDR) { //找不到下一条数据,重置flash
Debug_Printf("Add LOG Error, Next Data No Find!\r\n");
SetLogNum(0);
SetLoopSavFlag(0);
@@ -407,7 +407,7 @@ void AddLog(uint8_t *wData, uint32_t wLen)
//判断是否跨扇区,跨扇区需要先擦除下一扇区
CheckDelSecter(LLEndAddr, LogSize);
if(LogH->LogEndAddr > SPIFLASH_SIZE) {
if(LogH->LogEndAddr > LOG_SAV_END_ADDR) {
LLEndAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
LogH->LogEndAddr = ReadLastLogEndAddr();
}
@@ -419,6 +419,61 @@ void AddLog(uint8_t *wData, uint32_t wLen)
}
/*升级进度记录读写(扇区4037): 记录AppSize/Crc32/已收包数, 断电断连后支持断点续传*/
void FwStashProgRead(uint8_t *rData, uint16_t rLen)
{
FlashLock();
SpiFlashReadAnyLengthData(rData, FLASH_FW_STASH_PROG_SECTOR * SPIFLASH_SECTORSIZE, rLen);
FlashUnlock();
}
void FwStashProgWrite(uint8_t *wData, uint16_t wLen)
{
FlashLock();
SpiFlashEraseSector(FLASH_FW_STASH_PROG_SECTOR * SPIFLASH_SECTORSIZE);
SpiFlashWriteAnyLengthData(wData, FLASH_FW_STASH_PROG_SECTOR * SPIFLASH_SECTORSIZE, wLen);
FlashUnlock();
}
/*固件升级暂存区操作: 内部带互斥, 避免与AddLog/WritePara的SPI事务交错*/
void FwStashEraseAll(void)
{
FlashLock();
for(int i = 0; i < FLASH_FW_STASH_SECTORS; i++) {
SpiFlashEraseSector(FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + i * SPIFLASH_SECTORSIZE);
}
FlashUnlock();
}
void FwStashEraseSector(uint32_t SectorIdx)
{
FlashLock();
SpiFlashEraseSector(FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + SectorIdx * SPIFLASH_SECTORSIZE);
FlashUnlock();
}
int FwStashWrite(uint8_t *wData, uint32_t Offset, uint16_t wLen)
{
if(Offset + wLen > FLASH_FW_STASH_SECTORS * SPIFLASH_SECTORSIZE) {
return -1;
}
FlashLock();
SpiFlashWriteAnyLengthData(wData, FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + Offset, wLen);
FlashUnlock();
return 0;
}
int FwStashRead(uint8_t *rData, uint32_t Offset, uint16_t rLen)
{
if(Offset + rLen > FLASH_FW_STASH_SECTORS * SPIFLASH_SECTORSIZE) {
return -1;
}
FlashLock();
SpiFlashReadAnyLengthData(rData, FLASH_FW_STASH_SECTOR * SPIFLASH_SECTORSIZE + Offset, rLen);
FlashUnlock();
return 0;
}
/*****************************************************************************************
* 函数名称: ReadLog
* 功能描述: 读取日志