test(日志): 主机单测桩跟到 UART5

生产源 f5161e15 已把控制台端口收口到 CON_UART(=huart5),桩若还停在
huart1 / MX_USART1_UART_Init,主机单测会因符号缺失编不过;更要紧的是
huart1.Instance = 0 那几组用例会失去"串口未初始化"的原意——改成填一个
生产代码根本不碰的句柄,短路照样命中,但测的已经不是真实那条路径。

- stub/usart.h:暴露 huart5 + MX_UART5_Init,并按真实 Inc/usart.h 校正
  "真实那份还声明哪些"的描述(huart1~4、MX_USART1~3_UART_Init、
  MX_UART4_Init)。
- stub/stm32f4_fake.h:USART1_IRQn -> UART5_IRQn,
  __HAL_RCC_USART1_CLK_DISABLE/ENABLE -> __HAL_RCC_UART5_*;假外设块的
  标题与位注释去掉具体实例号(它本来就是通用模型,不是某个实例)。
- console_log_test.c:huart1 -> huart5(19 处)、
  MX_USART1_UART_Init -> MX_UART5_Init,含一条用例的打印文案。

纯桩与测试改动,不碰生产源;153/153 PASSED。
This commit is contained in:
2026-10-29 18:56:55 +08:00
parent 7dbc8f8676
commit 8a0cb464c0
4 changed files with 37 additions and 35 deletions
+21 -21
View File
@@ -6,7 +6,7 @@
* 起是**整行独占**,不再是"无锁":M 族 TC-CONLOG-170 至 TC-CONLOG-179 钉"别的写者插不进
* 一行、让路行逐字节等同直发、让位不丢、真溢出才 [ERR]")、缓冲满有界等待与
* 丢弃可观测、TX 僵尸通道软复位自愈 + 300ms 冷却、DWT 与指令计数两种硬上界、
* huart1.Instance 未初始化的 NULL 短路、fputc 重定向、drain 250ms 预算、
* huart5.Instance 未初始化的 NULL 短路、fputc 重定向、drain 250ms 预算、
* 整行所有权(行级单一所有者,道G task-23)。
*
* 为什么要主机侧单测(而不是只用台架):
@@ -19,7 +19,7 @@
*
* 桩的边界(细节见 stub/stm32f4_fake.h 头注释):
* console_log.h / sys_events.h(含真实 SYS_EVT_CONSOLE_TX 位)用**真实头**;
* usart.h 用桩,但只暴露本模块访问的 huart1 + MX_USART1_UART_Init,寄存器位号 /
* usart.h 用桩,但只暴露本模块访问的 huart5 + MX_UART5_Init,寄存器位号 /
* 枚举值照抄真实头;USART SR 的 TXE/TC、DWT CYCCNT、HAL_GetTick、临界区、
* __get_IPSR、vTaskDelay、osEventFlagsSet 做成可控 + 可观测的量。
* ⚠ 本文件**刻意不定义**任何 syslog_* / DBG_* 符号:console_log.c 哪天把"TX 故障
@@ -38,7 +38,7 @@
* 读后清、300ms 冷却两端、tick==0 也进冷却(哨兵撞值修好后为正向断言)、
* 半块 / 已上线仍判失败
* 090..106 DWT 惰性使能三处寄存器写、使能失败退回 20000 次指令计数、超时判据不读
* HAL_GetTick(第 8b 轮台架动机)、huart1.Instance == NULL 短路两路 +
* HAL_GetTick(第 8b 轮台架动机)、huart5.Instance == NULL 短路两路 +
* "未初始化绝不 reinit"(误自愈修好后为正向断言)+ 证据不蒸发
* 110..117 fputc 重定向(未注册直发 / 注册逐字节入环 / ISR 上下文裸发 / 环满时 ISR
* 仍不等待)
@@ -112,7 +112,7 @@ uint32_t SystemCoreClock = 168000000U; /* 与 MCU 端一致(168 MHz) */
USART_TypeDef g_con_uart;
CoreDebug_Type g_con_core_debug;
DWT_Type g_con_dwt;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart5;
uint32_t con_uart_tx_n;
uint8_t con_uart_tx[CON_UART_TX_MAX];
@@ -282,12 +282,12 @@ osStatus_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
}
/* 真实版是 CubeMX 生成的 HAL_UART_Init 封装;桩按脚本决定"软复位到底治没治好" */
void MX_USART1_UART_Init(void)
void MX_UART5_Init(void)
{
s_mx_init_calls++;
huart1.Instance = &g_con_uart;
huart1.gState = HAL_UART_STATE_READY;
huart1.ErrorCode = HAL_UART_ERROR_NONE;
huart5.Instance = &g_con_uart;
huart5.gState = HAL_UART_STATE_READY;
huart5.ErrorCode = HAL_UART_ERROR_NONE;
if (s_mx_repair != 0) {
con_uart_txe_stuck = 0;
con_uart_txe_after = 0;
@@ -413,10 +413,10 @@ static void reset_all(void)
s_mx_init_calls = 0U;
s_mx_repair = 0;
huart1.Instance = &g_con_uart;
huart1.gState = HAL_UART_STATE_READY;
huart1.RxState = HAL_UART_STATE_READY;
huart1.ErrorCode = HAL_UART_ERROR_NONE;
huart5.Instance = &g_con_uart;
huart5.gState = HAL_UART_STATE_READY;
huart5.RxState = HAL_UART_STATE_READY;
huart5.ErrorCode = HAL_UART_ERROR_NONE;
}
/* ===================== 观察辅助 ===================== */
@@ -983,12 +983,12 @@ static void tc_dwt(void)
"TC-CONLOG-099 the DWT branch declares timeout on the first spin (the ceiling really works, never burns 20000)");
}
/* ============ TC-CONLOG-100..106 huart1.Instance == NULL 短路 + 未初始化分诊 ============ */
/* ============ TC-CONLOG-100..106 huart5.Instance == NULL 短路 + 未初始化分诊 ============ */
static void tc_null_uart(void)
{
printf("-- TC-CONLOG-100..106 USART1 not initialised: yield, never reinit, keep proof --\n");
printf("-- TC-CONLOG-100..106 UART5 not initialised: yield, never reinit, keep proof --\n");
reset_all();
huart1.Instance = 0;
huart5.Instance = 0;
dbg_console_write_raw("boom", 5U);
CHECK(con_uart_tx_n == 0U && con_uart_txe_reads == 0U,
"TC-CONLOG-100 with Instance==NULL not one register is touched (no dereference of address 0)");
@@ -996,7 +996,7 @@ static void tc_null_uart(void)
"TC-CONLOG-101 DWT is still lazily enabled before the short circuit (ensure stays ahead of the NULL check)");
reset_all();
huart1.Instance = 0;
huart5.Instance = 0;
CHECK(dbg_console_write_line("early", 5U) == 5,
"TC-CONLOG-102 the unattached path (pre-kernel) survives a missing UART and still returns the line length");
@@ -1004,7 +1004,7 @@ static void tc_null_uart(void)
reset_all();
attach_writer();
(void)dbg_console_write_line("abc", 3U);
huart1.Instance = 0; /* 写者起来了但串口还没初始化 */
huart5.Instance = 0; /* 写者起来了但串口还没初始化 */
s_mx_repair = 1;
writer_drain();
CHECK(s_mx_init_calls == 0U && con_rcc_disables == 0U && con_nvic_clears == 0U,
@@ -1014,7 +1014,7 @@ static void tc_null_uart(void)
CHECK(dbg_console_dropped() == 1U && used_now() == 0U,
"TC-CONLOG-105 the block that left the ring but never hit the wire counts as dropped");
huart1.Instance = &g_con_uart; /* 串口随后初始化好 */
huart5.Instance = &g_con_uart; /* 串口随后初始化好 */
con_uart_tx_n = 0U;
writer_drain();
CHECK(tx_contains("[ERR] CONSOLE dropped 1 lines") && dbg_console_dropped() == 0U,
@@ -1159,7 +1159,7 @@ static void tc_three_ledgers(void)
reset_all();
attach_writer();
(void)dbg_console_write_line("xyz", 3U);
huart1.Instance = 0;
huart5.Instance = 0;
writer_drain();
CHECK(dbg_console_dropped() == 1U && dbg_console_tx_timeout() == 0U
&& dbg_console_tx_fault() == 0U,
@@ -1193,11 +1193,11 @@ static void tc_three_ledgers(void)
con_dwt_step = SystemCoreClock / 4U;
(void)dbg_console_write_line("0123456789ABCDEFGHIJ", 20U); /* 缓冲满丢 1 行 */
con_dwt_step = 0U;
huart1.Instance = 0; /* 告警那一发也发不出去 */
huart5.Instance = 0; /* 告警那一发也发不出去 */
writer_drain();
CHECK(dbg_console_dropped() >= 1U,
"TC-CONLOG-148 drop count survives while the channel is unavailable (evidence no longer washed away)");
huart1.Instance = &g_con_uart;
huart5.Instance = &g_con_uart;
con_uart_tx_n = 0U;
writer_drain();
CHECK(tx_contains("[ERR] CONSOLE dropped") && dbg_console_dropped() == 0U,
+2 -2
View File
@@ -10,7 +10,7 @@
缓冲满两条上界
(DWT 周期 / 200 tick)与丢弃计数、[ERR] 告警行不经环(不递归)、TX 僵尸通道软复位
自愈 + 故障即止 + 300ms 冷却(含无符号回绕)、DWT 使能失败退回 20000 次指令计数、
huart1.Instance==NULL 短路、fputc 重定向、drain 250ms 预算、行级单一所有者。
huart5.Instance==NULL 短路、fputc 重定向、drain 250ms 预算、行级单一所有者。
工具链与判定委托 test/host/common/unit_test_harness.py。
为什么要主机侧单测(而不是只用台架):
@@ -26,7 +26,7 @@
docs/子系统设计/控制台单写者日志设计说明.md(G1~G5 / K1~K5 / §12 ORE 僵尸通道)。
桩的边界:console_log.h 与 sys_events.h 用真实头(SYS_EVT_CONSOLE_TX 位定义一改即
编译期报错);usart.h 是桩但只暴露本模块访问的 huart1 + MX_USART1_UART_Init,
编译期报错);usart.h 是桩但只暴露本模块访问的 huart5 + MX_UART5_Init,
USART SR 位号、DWT/CoreDebug 位掩码、HAL_StatusTypeDef 枚举值均照抄真实头,
宿主编不动的那条 main.h -> stm32f4xx_hal.h -> core_cm4.h 链由 stub/stm32f4_fake.h
以普通结构体替代(理由写在该文件头注释里)。
+8 -8
View File
@@ -2,7 +2,7 @@
* 模块名称:主机侧单测桩 - 假 HAL/CMSIS 寄存器面 + 内核入口(console_log 模块专用)
* 模块功能:让 App/log/console_log.c 在 PC 上编起来,并把它依赖的硬件/内核面做成
* **可脚本控制**的模型:
* ① USART1:TXE/TC 可注入「就绪 / 永远不就绪(僵尸通道)/ 前 N 次不就绪」;
* ① 假串口外设:TXE/TC 可注入「就绪 / 永远不就绪(僵尸通道)/ 前 N 次不就绪」;
* 写进 DR 的字节被收进一条上线字节日志,并按「一次 TC 就绪 = 一块」记块长。
* ② DWT CYCCNT:每次访问推进 con_dwt_step 个周期(= 给时间定价),
* CTRL 的 CYCCNTENA 可脚本成「写不进去」以走 con_tx_counted 支路。
@@ -19,7 +19,7 @@
* DWT_Type.CTRL/CYCCNT + DWT_CTRL_CYCCNTENA_Msk=bit0、CoreDebug_Type.DEMCR +
* CoreDebug_DEMCR_TRCENA_Msk=bit24(core_cm4.h)
* HAL_StatusTypeDef{OK=0,ERROR=1,BUSY=2,TIMEOUT=3}(stm32f4xx_hal_def.h)
* HAL_UART_STATE_RESET=0x00、HAL_UART_ERROR_NONE=0x00、USART1_IRQn=7
* HAL_UART_STATE_RESET=0x00、HAL_UART_ERROR_NONE=0x00、UART5_IRQn=7
* UART_HandleTypeDef 只搬本模块访问的 4 个字段(Instance/gState/RxState/ErrorCode),
* 余下(Init/Lock/...)刻意不搬:抄半份 HAL 结构只会更快与真实头漂移。
*
@@ -52,11 +52,11 @@
#include <stdlib.h>
/* ===== 与真实头同值的位 / 枚举(来源见文件头) ===== */
#define USART_SR_TXE_Msk (0x0080U) /* USART1->SR bit7 发送寄存器空 */
#define USART_SR_TC_Msk (0x0040U) /* USART1->SR bit6 发送完成 */
#define USART_SR_TXE_Msk (0x0080U) /* SR bit7 发送寄存器空 */
#define USART_SR_TC_Msk (0x0040U) /* SR bit6 发送完成 */
#define DWT_CTRL_CYCCNTENA_Msk (0x00000001U)
#define CoreDebug_DEMCR_TRCENA_Msk (0x01000000U)
#define USART1_IRQn 7
#define UART5_IRQn 7
#define HAL_UART_STATE_RESET 0x00U
#define HAL_UART_STATE_READY 0x20U
@@ -75,7 +75,7 @@ typedef enum {
extern uint32_t SystemCoreClock;
/* ------------------------------------------------------------------ */
/* ① 假 USART1 */
/* ① 假串口外设 */
/* ------------------------------------------------------------------ */
typedef struct {
volatile uint32_t SR;
@@ -368,7 +368,7 @@ extern uint32_t con_nvic_clears;
extern uint32_t con_rcc_disables;
extern uint32_t con_rcc_enables;
#define __NVIC_ClearPendingIRQ(irqn) do { (void)(irqn); con_nvic_clears++; } while (0)
#define __HAL_RCC_USART1_CLK_DISABLE() do { con_rcc_disables++; } while (0)
#define __HAL_RCC_USART1_CLK_ENABLE() do { con_rcc_enables++; } while (0)
#define __HAL_RCC_UART5_CLK_DISABLE() do { con_rcc_disables++; } while (0)
#define __HAL_RCC_UART5_CLK_ENABLE() do { con_rcc_enables++; } while (0)
#endif /* STM32F4_FAKE_H */
+6 -4
View File
@@ -1,8 +1,10 @@
/*
* 模块名称:主机侧单测桩 - usart.h(console_log 模块专用)
* 模块功能:与真实 Inc/usart.h 对本模块可见的部分逐字一致:extern UART_HandleTypeDef
* huart1; + void MX_USART1_UART_Init(void);(真实那份还声明 huart2~5 与
* MX_USART2~5_UART_Init,本模块只碰 USART1,搬多出来的声明没有意义)。
* huart5; + void MX_UART5_Init(void);(真实那份还声明 huart1~4 与
* MX_USART1~3_UART_Init / MX_UART4_Init,本模块只碰 UART5,搬多出来的声明
* 没有意义)。
* 2026-10-29 批 0:控制台从 USART1 迁到 RS232#1/UART5,本桩随之改。
* ⚠ 仅供 test/host/console_log/ 使用,不参与 MCU 构建。
* 真实 Inc/usart.h 的 include 链(main.h -> stm32f4xx_hal.h -> stm32f4xx.h ->
* core_cm4.h)在宿主上编不动,寄存器面由 stm32f4_fake.h 提供(理由见该文件头)。
@@ -14,7 +16,7 @@
#include <stdint.h>
#include "stm32f4_fake.h"
extern UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void);
extern UART_HandleTypeDef huart5;
void MX_UART5_Init(void);
#endif /* USART_H */