当前位置: 首页 > news >正文

第九章:OTA 与 Flash 驱动 —— 如何用TDD验证固件升级逻辑的鲁棒性

这一章我们将切入一个非常关键且具有挑战性的场景:OTA(Over-the-Air)固件更新

OTA 逻辑最怕的是什么?是中途断电、Flash 写入失败、校验和不匹配。如果你在真机上测试这些异常,可能需要反复烧录、断开电源,甚至不小心把片子变“砖”。在 TDD 的世界里,我们可以优雅地模拟这些灾难。

9.1 OTA 测试的痛点

  1. 硬件寿命:频繁擦写内部 Flash 也是有寿命限制的。

  2. 场景模拟:你很难手动模拟“在写入第 1024 个字节时突然断电”。

  3. 复杂校验:CRC32、SHA256 的验证在 PC 上跑比在 MCU 上快得多。

9.2 接口抽象:Storage_Interface.h

为了让 OTA 逻辑可测,我们必须隔离 STM32 的HAL_FLASH_Program

// Storage_Interface.h
#ifndef STORAGE_INTERFACE_H
#define STORAGE_INTERFACE_H

#include <stdint.h>
#include <stdbool.h>

typedef enum { FLASH_OK, FLASH_ERROR, FLASH_BUSY } FlashStatus_t;

FlashStatus_t HW_Flash_ErasePage(uint32_t page_addr);
FlashStatus_t HW_Flash_Write(uint32_t addr, uint8_t* data, uint32_t len);
void HW_System_Reset(void);

#endif

9.3 实战:测试“断点续传”逻辑

我们要实现一个 OTA 接收器:它按包接收固件,记录已写入的偏移量,如果写入失败要能重试。

编写测试 (test_Ota_Service.c):我们要模拟一个非常极端的情况:第一次写入成功,第二次写入失败。

#include "unity.h"
#include "mock_Storage_Interface.h"
#include "Ota_Service.h"

void test_Ota_Should_HandleFlashWriteFailure(void) {
uint8_t dummy_data[128] = {0xA5};

// 1. 模拟第一包数据写入:返回成功
HW_Flash_Write_ExpectAndReturn(0x08010000, dummy_data, 128, FLASH_OK);
bool result = Ota_ProcessPacket(0, dummy_data, 128);
TEST_ASSERT_TRUE(result);

// 2. 模拟第二包数据写入:硬件突然报错(比如电压不稳或页损坏)
HW_Flash_Write_ExpectAndReturn(0x08010080, dummy_data, 128, FLASH_ERROR);

result = Ota_ProcessPacket(128, dummy_data, 128);

// 验证:逻辑层应该识别出失败,并返回 false,以便触发重传机制
TEST_ASSERT_FALSE(result);
}

9.4 进阶技巧:模拟“脏数据”与校验失败

在 OTA 中,校验和(Checksum)是最后一道防线。

void test_Ota_Should_RejectFirmware_WhenChecksumMismatch(void) {
// 模拟 Flash 读取出的数据
// 我们不需要真的读 Flash,直接 Mock 掉读取函数返回“坏数据”
HW_Flash_Read_StubWithCallback(my_Fake_Flash_Read_Bad_Data);

// 执行校验逻辑
bool is_valid = Ota_VerifyChecksum();

// 验证:校验不通过,且绝不调用系统重启去运行坏固件
TEST_ASSERT_FALSE(is_valid);
// 确保没有误触发系统重启(这也是一种验证)
HW_System_Reset_Expect(); // 如果你预期它报错后重启到 Bootloader
}

9.5 本章核心:防御式编程:

  1. 状态机保护:OTA 过程中如果收到无关的串口命令,状态机是否会崩溃?

  2. 原子操作模拟:模拟擦除了一半突然断电,Bootloader 能否识别出固件不完整?

  3. 边界检查:Mock 掉 Flash 大小接口,验证如果固件包超过 Flash 容量,代码是否会越界写入。

本章小结

这一章证明了 TDD 不仅能测“好用”的情况,更能测“坏掉”的情况。对于 OTA 这种高风险模块,这种“离线异常注入”是保证产品不批量变砖的唯一手段。

http://www.gsyq.cn/news/1437799.html

相关文章:

  • 2026年稻城亚丁四姑娘山旅游品牌TOP5客观盘点 - 优质品牌商家
  • 华为RH2288HV3服务器BIOS与iBMC固件升级专用HPM包(含操作指引)
  • CRMEB多商户商城v2.3.2源码包:支持人人分销开通、批量秒杀配置、商品定时上下架及同城配送全流程
  • 告别拍脑袋估算!用RUSLE模型5步搞定土壤侵蚀强度计算(附数据获取渠道)
  • 别再只用NTP了!手把手教你用LinuxPTP(ptp4l)实现微秒级时间同步
  • 保姆级教程:用UE5的Niagara系统,从零手搓一个会动的火焰特效(附材质球避坑点)
  • 成都墙绘单价全维度解析:3d墙绘/四川墙体彩绘公司/四川墙绘公司/地面墙绘/从品类到场景的成本逻辑 - 优质品牌商家
  • 保姆级教程:用davfs2在Ubuntu 22.04上挂载WebDAV网盘(含常见错误排查)
  • UE5 GAS实战:别再直接扣血了!用Meta Attributes和Set by Caller重构你的RPG伤害系统
  • 从机器翻译到智驾:规则派的黄昏与数据革命的终局(五)
  • RoboSeek框架:交互式机器人操作与强化学习实践
  • 别再被多重共线性坑了!用Python的sklearn手把手教你调岭回归(Ridge Regression)的alpha参数
  • 别再死记硬背了!用Python+OpenCV手把手带你理解相机内参矩阵K
  • 保姆级教程:在UE5里为技能配置动态伤害表(曲线表格+Set by Caller)
  • 看完这10个AI图片工具,我默默把手机里的修图App删了大半
  • 转炉炼钢终点碳温联合预测MATLAB一键运行包(含异常数据自动过滤与模型快速部署)
  • RISC‑V 架构的结构化分析:一种编程新范式的视角
  • 在Ubuntu 22.04上从零搭建TrinityCore 3.3.5服务器:一份保姆级避坑指南
  • 2026最火AI热点——基于MCP协议构建企业级AI Agent平台(Golang实战)
  • 从沙子到车辙(4.3):板级通信——CAN / CAN-FD
  • yolov26改进 | 添加注意力机制篇 | 添加TripletAttention三重注意力机制(附代码+机制原理+添加教程+网络结构图)
  • 开源本地AI笔记工具
  • delphi xe10.4 TTASKDIALOG帮助介绍-非官方
  • 应用通过cmd启动失败时报错,如何取消开机启动
  • Cadence AMS数模混合仿真保姆级教程:从Virtuoso Testbench到多线程加速全流程
  • 别再死记公式了!用Python手撸一个LDA分类器,从鸢尾花数据集开始
  • Argo浮标数据怎么用?手把手教你用Python替代Matlab计算海洋热容与盐容贡献
  • 昆山名酒回收电话评测:上海附近上门回收名酒/昆山五粮液回收/昆山八大回收/从核心维度选靠谱服务商 - 优质品牌商家
  • 保姆级教程:在Ubuntu 22.04上,用RTX 40系显卡从零搞定DeepStream 6.4(含CUDA 12.2和TensorRT 8.6.1.6)
  • SEED数据集实战:用Python+MNE批量读取脑电数据,附完整代码与通道映射表