EMS 知识库
首页 / knowledge/代码解析/midware/meter

bb_update.h

源文件路径:midware/meter/bb_update.h 所属模块:midware/meter(电表/备用箱中间件) 代码行数:78

1. 文件职责

这是 BackupBox(BB,备用箱)内置 MCU 串口固件升级模块的对外头文件。它集中声明了升级流程用到的三类信息:协议常量(接收帧类型判别值、单帧最大负载长度)、升级状态机与帧类型的枚举(BB_STATE / BB_INSTRUCTIONS),以及升级上下文结构体(BB_UPDATE_CONTENT)和Flash 校验累加结构体(BB_CHECK)。

在数据流中它处在 midware/meter 中间件层与 net/(服务器固件下发)之间的接口位置:net/ 层把 BB 固件下载进 SDRAM,bb_update.c 用这里定义的结构体做升级上下文,midware/meter/meter.c 的 task_meter() 调用 bb_update() 推进升级。

本文件不包含任何实现,只做类型与接口声明;它被 bb_update.c、meter.c、net/ems.c include。

2. 关键数据结构与宏

名称类型说明
__BB_UPDATE_H__宏头文件防重复包含保护
DEBUG_BB宏0,调试开关;本文件中未被任何代码使用(bb_update.c 用的是 USART1_DEBUG)
RECV_SEQUENCE_FRAME宏0x06,接收侧"序列帧"类型判别值;bb_update.c 未直接引用,实际判定用的是硬编码字节
RECV_COMMAND_DATA_FRAME宏0x01,接收侧"指令与数据帧"类型判别值;同上未直接引用
MAX_PRG_LENGTH宏112*2 = 224,单次写 Flash 帧的最大负载字节数(112 个 16bit 字);bb_update.c:185 用它与拼包长度比较
BB_INSTRUCTIONS枚举帧类型分类:REPLY_FRAME(回复帧)、SEQUENCE_FRAME(序列帧)、COMMAND_DATA_FRAME(指令与数据帧);仅有语义说明作用,代码中未实例化使用
BB_STATE枚举升级状态机全部状态,见下节;bb_update.c 以整数值存入 BB_UPDATE_CONTENT.u8_insteructions_state
struct BB_UPDATE_CONTENT结构体(#pragma pack(1))升级主上下文,见下节字段表
struct BB_CHECK结构体(#pragma pack(1))Flash 校验累加器,见下节字段表

BB_STATE 枚举成员

成员隐含值说明
RESET_INSTRUCTIONS0发复位指令(上电初值即此状态)
BOOT_INSTRUCTIONS1发 "PSLAVER\r" 让 BB 进入 Bootloader
ADJUST_RATE2发 0x41 触发波特率自适应
ERASE_FLASH3擦除 BB 应用区
WRITE_FLASH4分块写 Flash(主体状态)
CHECK_FLASH5分段校验 Flash
SEND_KEY_WORD6写升级关键字 0x6D83
UPGRADE_END7发结束指令
UPGRADE_INIT8清理并重新开始
RECV_DATA9未被使用,遗留成员

struct BB_UPDATE_CONTENT 字段(#pragma pack(1),无填充)

字段类型说明
s32_len_buffu32本行 HEX 的数据字节数(命名前缀为 s32_ 但实际是 u32)
s32_lengthu32当前拼包缓冲中已累积的负载字节数,0 表示无待发数据
s32_addr_flashu32本次要写入 BB Flash 的绝对地址 = `(base<<16) \offset`
u32_old_flash_addru32上一次发送的绝对地址,用于判断是否需要对本次数据做校验累加
s32_old_addr_offsetu32上一行 HEX 的地址偏移,用于判断行间是否连续
s32_addr_flash_offsetu32本行 HEX 的地址偏移(hex_file_data.u16_addr)
s32_addr_flash_baseu32HEX 扩展线性地址(高 16 位基址)
u8_buffer[256]u8[256]拼包缓冲;首次拼包时整体预填 0xFF(模拟 Flash 擦除态),再按大端写入各行数据
u8_loop_addru8通信序列号,每发一帧递增,UPGRADE_INIT 时清零
u16_check_codeu16校验码字段;在 bb_update.c 中从未被读写,遗留字段
u8_insteructions_stateu8升级状态,取 BB_STATE 值(注意拼写为 insteructions,为源码原有拼写错误)
u32_amount_sequence_frameu32本次序列帧要声明的负载字节数(= s32_length)

struct BB_CHECK 字段

字段类型说明
u8_timeu8校验轮次计数;bb_update.c:197 只自增、从不读取,属死代码
u16_check_length[10]u16[10]每个校验区已累加的 16bit 字数;实际只用下标 0(前半区)、1(后半区)
u16_check_code[10]u16[10]每个校验区的 16bit 累加和;实际只用下标 0/1/2(下标 2 为关键字区相关校验)

3. 函数清单

本文件为纯头文件,不包含任何函数定义,仅在文件末尾(:73-75)声明了 3 个由 bb_update.c 实现的导出函数:

函数名作用域说明
void bb_update(void)全局(外部实现)BB 升级主状态机入口,每次调用推进一个状态
u8 GetPercentUpgradeBB(void)全局(外部实现)返回 BB 升级百分比(0-100)
u32 GetUpgradeFileOffsetBB(void)全局(外部实现)返回 BB 已传输的固件文本字节数

4. 核心逻辑解析

本文件无运行逻辑,此处说明其定义的类型在实现文件中的使用方式,以及由这些类型约定出的状态迁移。

4.1 状态机契约(BB_STATE)

实现文件 bb_update.c:317 用 switch(g_bb_update.u8_insteructions_state) 驱动,迁移关系为:

RESET_INSTRUCTIONS → BOOT_INSTRUCTIONS → ADJUST_RATE → ERASE_FLASH → WRITE_FLASH
        ▲                                                                │
        │                                                   解析到关键字地址
        │                                                                ▼
   UPGRADE_INIT ◄── UPGRADE_END ◄── CHECK_FLASH(轮次≥10) ◄── CHECK_FLASH
                                          │ (轮次==2)
                                          ▼
                                     SEND_KEY_WORD ──► CHECK_FLASH

4.2 数据布局约定(#pragma pack(1))

两个结构体都用 #pragma pack(1) 收紧,随后 #pragma pack() 恢复默认。这表示:

4.3 通信协议帧格式

本文件用宏 RECV_SEQUENCE_FRAME=0x06 与 RECV_COMMAND_DATA_FRAME=0x01 描述了接收侧两类帧的识别值,但实现文件(bb_update.c:274-291)并未使用这两个宏,而是硬编码了 14 个字节的常量特征做匹配。因此:

4.4 与 uCOS-II 的配合

头文件不涉及任务/信号量/邮箱;所有同步由实现文件中的 OSTimeGet() + OSTimeDlyHMSM() 完成。BB_UPDATE_CONTENT 只是被 task_meter() 单线程访问的普通全局数据,没有互斥保护——GetPercentUpgradeBB() / GetUpgradeFileOffsetBB() 被 net/ 层(可能运行在另一个任务)读取,与升级流程写入构成无锁跨任务共享。

4.5 关键全局变量

5. 对外接口

导出(供外部调用)

名称说明
void bb_update(void)由 midware/meter/meter.c:5738 调用
u8 GetPercentUpgradeBB(void)由 midware/meter/meter.c:6844、:6857 调用
u32 GetUpgradeFileOffsetBB(void)由 net/ems.c:6706 调用
MAX_PRG_LENGTH宏,bb_update.c:185 使用
struct BB_UPDATE_CONTENT / struct BB_CHECK类型,bb_update.c 用于定义全局实例

使用的外部符号(本文件自身依赖)

名称来源
includes.hmidware/meter/bb_update.h:13 include;提供 u8/u16/u32/s32 等基础类型与全局公共头

6. 依赖关系

7. 备注与风险点

  1. 命名前缀与实际类型不符:BB_UPDATE_CONTENT 中 s32_len_buff、s32_length、s32_addr_flash、s32_old_addr_offset、s32_addr_flash_offset、s32_addr_flash_base 全部声明为 u32,前缀却是 s32_(有符号 32 位)。容易误读为有符号量,而 bb_update.c:154 的 (s32_addr_flash_offset - s32_old_addr_offset) > 0x10 正是依赖无符号回绕的比较,前缀误导性明显。只有 u32_old_flash_addr 用了正确的 u32_ 前缀,同一结构体内风格不统一。
  2. 拼写错误固化进接口:u8_insteructions_state(应为 instructions)在头文件和实现文件中多处引用,属于无法在不破坏兼容的前提下修改的历史遗留。
  3. u16_check_code 为死字段:结构体里保留了一个从未被读写的 u16_check_code,容易被误认为有效校验字段。
  4. BB_INSTRUCTIONS 枚举与 RECV_SEQUENCE_FRAME/RECV_COMMAND_DATA_FRAME 宏均为"文档型死定义":实现文件全部使用硬编码字节做判定,宏改不动行为,反而给维护者"改这里就生效"的错觉。
  5. DEBUG_BB 宏无效::16 定义了 DEBUG_BB,但实现文件的调试开关是 USART1_DEBUG(来自 includes.h),DEBUG_BB 在任何 .c 中都未被引用。
  6. u8_buffer[256] 尺寸与使用方式不匹配:MAX_PRG_LENGTH 是 224,载荷实际只用 224 字节,但 bb_update.c:430 整块拷贝 256 字节到 g_u8_write_flash+20,造成 20 字节越界写。头文件这边的缓冲区声明应改为 [MAX_PRG_LENGTH] 或把拷贝长度改为 MAX_PRG_LENGTH。
  7. BB_CHECK 数组长度 10 与实际用 3 不匹配:u8_time 字段也是纯自增死代码,属未清理的预留设计。
  8. #pragma pack(1) 与 #pragma pack() 配对使用不带参数:#pragma pack() 恢复默认对齐是 Keil ARMCC 支持的写法,但跨编译器(如 GCC)行为不同;本工程固定用 Keil MDK,可接受。
  9. 无 extern 声明升级上下文:g_bb_update / g_check_code 在 bb_update.c 中是非 static 全局变量(外部链接),但头文件没有 extern 声明,形成"有外部链接但无对外声明"的状态,仅仅靠 3 个访问函数收口——从封装角度看是有意的,但 g_u8_bb_recv_buf 同样是外部链接却完全无出口,属于不一致。
  10. 异常路径未在接口约定:GetPercentUpgradeBB() 除零、bb_update() 被并发调用等异常在头文件中没有任何说明,调用方需自行保证时序。