第四章:手撕协议栈 —— 缓冲区与结构体数据的 Mock 技巧

这一章我们要攻克嵌入式开发中最常见的"重头戏":通信协议栈

不管是 UART、SPI 还是J1939/NMEA 2000等应用层协议,核心难点都在于:如何处理连续的数据流、缓冲区溢出以及复杂的结构体解析

4.1 协议栈 TDD 的难点

在测试串口(UART)时,我们不仅要 Mock 硬件发送函数,还要模拟"对方发过来的数据"。

  • 发送测试:验证逻辑是否将正确的字节序写入了驱动。

  • 接收测试:向缓冲区注入模拟数据,验证解析算法(如帧头、校验位、帧尾)是否正确。

4.2 接口抽象:面向报文的驱动

src/Driver_UART.h 中,我们不直接操作寄存器,而是定义发送字节的接口:

#ifndef DRIVER_UART_H

#define DRIVER_UART_H

#include <stdint.h>

// 发送一个字节

void UART_SendByte(uint8_t data);

// 检查是否有数据收到

bool UART_IsDataAvailable(void);

// 获取收到的字节

uint8_t UART_GetByte(void);

#endif

4.3 实战:测试一个简单的命令解析器

需求: 协议格式为 [0xAA, CMD, DATA, 0x55]。 我们要实现一个 Protocol_Parse() 函数,当收到 0xAA 0x01 0x01 0x55 时,触发"点灯"动作。

第一步:编写测试 (test_Protocol.c) 这里我们要用到 Expect 的连贯调用,模拟一串字节的到来。

#include "unity.h"

#include "mock_Driver_UART.h"

#include "mock_Hardware_Interface.h"

#include "Protocol_Service.h"

void test_Should_ExecuteCommand_WhenValidFrameReceived(void) {

// 模拟收到一帧完整数据包:0xAA, 0x01, 0x01, 0x55

// 第一次调用:帧头

UART_IsDataAvailable_ExpectAndReturn(true);

UART_GetByte_ExpectAndReturn(0xAA);

// 第二次调用:命令码 0x01

UART_IsDataAvailable_ExpectAndReturn(true);

UART_GetByte_ExpectAndReturn(0x01);

// 第三次调用:数据位 0x01

UART_IsDataAvailable_ExpectAndReturn(true);

UART_GetByte_ExpectAndReturn(0x01);

// 第四次调用:帧尾 0x55

UART_IsDataAvailable_ExpectAndReturn(true);

UART_GetByte_ExpectAndReturn(0x55);

// 关键:当解析到完整有效帧后,预期硬件接口会执行点灯

HW_GPIO_SetLed_Expect(true);

// 执行解析函数(模拟在 while(1) 或中断中调用多次)

for(int i=0; i<4; i++) {

Protocol_Parse();

}

}

4.4 进阶技巧:如何测试发送大块结构体?

如果你要发送一个复杂的 J1939 报文结构体,可以使用 CMock 的 ExpectWithArray 功能。

源码接口: void UART_WriteBuffer(uint8_t* data, uint16_t len);

测试代码:

void test_Should_SendCorrectPacket(void) {

uint8_t expected_data\[\] = {0x18, 0xFE, 0xF1, 0x00, 0xAA, 0xBB, 0xCC, 0xDD};

// 告诉 CMock:我预期 UART_WriteBuffer 被调用

// 并且第一个参数(指针)指向的内容应该匹配 expected_data

UART_WriteBuffer_ExpectWithArray(expected_data, 8, 8);

J1939_SendWheelSpeed(0xAABBCCDD);

}

4.5 本章核心心法:协议栈的"状态机测试"

在专栏中,你可以重点给读者分享以下观点:

  1. 分层治之:驱动层(UART_Send)用 Mock 模拟;解析层(CRC校验、状态机转换)在 PC 上纯逻辑测试。

  2. 错误注入 :在测试里故意返回一个错误的校验码 0x99,验证解析器是否能正确丢弃非法包并复位状态机。

  3. 压力测试:在测试里模拟缓冲区瞬间塞满 1024 字节,观察逻辑是否会死锁。

本章小结

这一章我们攻克了"流式数据"的 TDD 难关。你现在已经有能力在不连串口线的情况下,把 J1939、NMEA 2000 或者 Modbus 的协议逻辑写得天衣无缝了。

相关推荐
虎王物联7 小时前
STM32 HAL库串口DMA空闲中断:高效接收不定长Modbus数据帧
stm32·单片机·嵌入式硬件·dma·modbus
自小吃多7 小时前
DXF文件导入与PCB板框定义笔记
笔记·嵌入式硬件
SUNNYSPY0017 小时前
AO4402-ASEMI便携设备电源开关AO4402
单片机
STQY燊桐启元(深圳)电子科技8 小时前
医疗精密电源散热方案:相变陶瓷片保障医疗设备长效稳定低干扰
大数据·网络·人工智能
单片机仿真设计9 小时前
【proteus仿真】基于 STC89C52 单片机家用智能台灯设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
2601_950790689 小时前
深圳国产单片机厂商怎么选?技术能力与服务能力检查表
单片机·嵌入式硬件·国产mcu·芯片厂商·深圳单片机·单片机选型
CDN36010 小时前
节点智能调度实操:解决出海区域访问快慢不均、节点拥堵、跨洋延迟高,CDN 全网择优落地方案
运维·服务器·网络
roman_日积跬步-终至千里11 小时前
【数据治理(6)】DataOps 不是调度工具,而是让数据产品长期可信的运行机制
java·服务器·网络
xierui12312311 小时前
OpenAI 拟停止向 Cursor供模:如何设计不绑供应商的AIAgent架构
人工智能·系统架构·软件工程
hongmai66688811 小时前
MP2348GTL-Z:这颗24V/4A同步降压芯片,把性能和体积平衡得恰到好处
c语言·开发语言·arm开发·单片机·5g