/* * 模块名称:主机侧单测桩 - main.h(sb_link 模块专用) * 模块功能:给 Drivers/BSP/ScreenLink/sb_link.c 提供"可脚本控制"的 HAL 面: * ① 假 USART 寄存器:SR / DR 的**读取顺序与次数**可记账,ORE 锁存可注入; * ② 假 ReceiveToIdle_IT:记录挂接收的缓冲/长度,返回值可脚本指定(OK/BUSY/TIMEOUT/ERROR)。 * ⚠ 仅供 test/host/sb_link/ 使用,不参与 MCU 构建(MCU 走真实 main.h -> stm32f4xx_hal.h)。 * * 为什么必须桩:真实链 main.h -> stm32f4xx_hal.h -> stm32f4xx.h -> core_cm4.h 里是 * __IO 寄存器绝对地址与 ARMCC 内联汇编,宿主 MSVC 既编不动也访问不了。 * * ★ 本桩唯一的技巧点:`->SR` / `->DR` 的读没法用普通结构体成员钩住(成员访问不能替换)。 * 于是把 USART_TypeDef 的两个成员做成**函数指针**,再用宏把成员名改写成「成员名()」: * 生产代码 p_huart->Instance->SR * 预处理后 p_huart->Instance->sr_cell() * 即一次真实的函数调用 —— 测试因此能记账"读了什么、什么顺序",并让 ORE 的清除 * 严格按 RM0090 §30.6.1 的序列生效(**先读 SR 再读 DR 才清得掉**,顺序反了清不掉)。 * 改成员名之前先确认生产代码只用 `->SR` / `->DR` 这一种写法(sb_link.c 里就两处)。 * * 创建日期:2026-10-29 */ #ifndef MAIN_H #define MAIN_H #include #include /* ===== 与真实头同值的枚举(stm32f4xx_hal_def.h / stm32f4xx_hal_uart.h) ===== */ typedef enum { HAL_OK = 0x00U, HAL_ERROR = 0x01U, HAL_BUSY = 0x02U, HAL_TIMEOUT = 0x03U } HAL_StatusTypeDef; /* RxState 的两个取值:错误回调里"要不要重挂"就靠它判(见 sb_link.c 的 on_error 说明) */ #define HAL_UART_STATE_READY (0x20U) #define HAL_UART_STATE_BUSY_RX (0x22U) /* HAL 的错误位(ErrorCode):ORE 是阻塞型,NE/FE/PE 是非阻塞型 */ #define HAL_UART_ERROR_PE (0x01U) #define HAL_UART_ERROR_NE (0x02U) #define HAL_UART_ERROR_FE (0x04U) #define HAL_UART_ERROR_ORE (0x08U) /* ===== ① 假 USART 寄存器(读法见文件头的★) ===== */ typedef struct { uint32_t (*sr_cell)(void); uint32_t (*dr_cell)(void); } USART_TypeDef; #define SR sr_cell() #define DR dr_cell() #define SB_FAKE_SR_ORE (0x0008U) /* USART_SR_ORE,bit3 */ #define SB_FAKE_SR_CLEAN (0x00C0U) /* TXE|TC 置位,无错误位 */ #define SB_FAKE_DR_VALUE (0x00A5U) #define SB_FAKE_TRACE_MAX (8U) static uint32_t sb_reg_trace[SB_FAKE_TRACE_MAX]; /* 'S' = 读了 SR,'D' = 读了 DR */ static uint32_t sb_reg_n; static uint32_t sb_ore_latched; /* 1 = ORE 处于锁存态 */ static uint32_t sb_sr_seen; /* 1 = 刚读过 SR(DR 才清得掉 ORE) */ static uint32_t sb_sr_cell(void) { if (sb_reg_n < SB_FAKE_TRACE_MAX) { sb_reg_trace[sb_reg_n] = (uint32_t)'S'; } sb_reg_n++; sb_sr_seen = 1U; return (sb_ore_latched != 0U) ? SB_FAKE_SR_ORE : SB_FAKE_SR_CLEAN; } static uint32_t sb_dr_cell(void) { if (sb_reg_n < SB_FAKE_TRACE_MAX) { sb_reg_trace[sb_reg_n] = (uint32_t)'D'; } sb_reg_n++; /* RM0090 §30.6.1:读 SR 之后再读 DR 才清 ORE;顺序反了清不掉(真机也这样) */ if (sb_sr_seen != 0U) { sb_ore_latched = 0U; } sb_sr_seen = 0U; return SB_FAKE_DR_VALUE; } static USART_TypeDef g_sb_uart = { sb_sr_cell, sb_dr_cell }; /* ===== ② 假 UART 句柄 ===== */ typedef struct { uint32_t BaudRate; uint32_t WordLength; uint32_t StopBits; uint32_t Parity; uint32_t Mode; uint32_t HwFlowCtl; uint32_t OverSampling; } UART_InitTypeDef; typedef struct { USART_TypeDef *Instance; UART_InitTypeDef Init; volatile uint32_t gState; volatile uint32_t RxState; volatile uint32_t ErrorCode; } UART_HandleTypeDef; /* ===== ③ 假 ReceiveToIdle_IT ===== */ #define SB_FAKE_ARM_OK (0U) #define SB_FAKE_ARM_BUSY (1U) #define SB_FAKE_ARM_TIMEOUT (2U) #define SB_FAKE_ARM_ERROR (3U) static uint32_t sb_arm_calls; static uint32_t sb_arm_force; /* SB_FAKE_ARM_* */ static uint8_t *sb_arm_buf; static uint16_t sb_arm_size; static HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *p_huart, uint8_t *p_buf, uint16_t size) { sb_arm_calls++; sb_arm_buf = p_buf; sb_arm_size = size; if (sb_arm_force == SB_FAKE_ARM_BUSY) { return HAL_BUSY; } if (sb_arm_force == SB_FAKE_ARM_TIMEOUT) { return HAL_TIMEOUT; } if (sb_arm_force == SB_FAKE_ARM_ERROR) { return HAL_ERROR; } /* ORE 锁存时真机是收不了的(RXNE 不再置位)——桩照这个语义走, * 于是"ORE 没清干净"必然表现为挂接收失败,用例能抓住 */ if (sb_ore_latched != 0U) { return HAL_ERROR; } /* 挂上了:RxState 进 BUSY_RX。错误回调据此判断"接收是不是还在跑" * (真机也是这样:非阻塞型错误不动 RxState,阻塞型错误会把它打回 READY) */ p_huart->RxState = HAL_UART_STATE_BUSY_RX; return HAL_OK; } /* ===== ④ 测试用的复位/查询把手 ===== */ static void sb_fake_reset(void) { uint32_t i; for (i = 0U; i < SB_FAKE_TRACE_MAX; i++) { sb_reg_trace[i] = 0U; } sb_reg_n = 0U; sb_ore_latched = 0U; sb_sr_seen = 0U; sb_arm_calls = 0U; sb_arm_force = SB_FAKE_ARM_OK; sb_arm_buf = NULL; sb_arm_size = 0U; } /* 寄存器读序列是否为期望的字符串(如 "SD"):长度不等或内容不符都返回 0 */ static int sb_fake_trace_is(const char *p_expect) { uint32_t i; uint32_t len = (uint32_t)0U; while (p_expect[len] != '\0') { len++; } if (sb_reg_n != len) { return 0; } for (i = 0U; i < len; i++) { if (sb_reg_trace[i] != (uint32_t)(unsigned char)p_expect[i]) { return 0; } } return 1; } #endif /* MAIN_H */