开启了192k 所有RAM

This commit is contained in:
2026-08-30 15:38:40 +08:00
parent 67370888a1
commit 71c41fabb9
23 changed files with 947 additions and 290 deletions
@@ -0,0 +1,106 @@
# serial-mcp-server 串口调试指南
通过 **Adancurusul/serial-mcp-server**(Rust,MIT)自主读取/控制 **USART1 串口**(PA9 TX / PA10 RX,115200bps)的打印流(MCU printf)。
## 项目与安装
- 仓库:https://github.com/Adancurusul/serial-mcp-server
- 本机安装:`%LOCALAPPDATA%\serial-mcp-server\serial-mcp-server.exe`(自源码 `cargo build --release` 编译,v0.3.0)
- 两种形态:
- **MCP stdio server**(`serve` 子命令)—— opencode.json 中 `mcp.serial`,工具带 `serial_` 前缀
- **CLI**(`list-ports` / `open` / `read` / `write` / `close` 等)—— 适合脚本化/一次性抓取
- **串口端口单一配置源:`.opencode/serial_config.json`**(当前本机 `COM6` / 115200)。端口变化只改这个文件
## 核心能力边界(重要)
**⚠️ 该项目没有"读取历史消息/历史缓冲"功能**(对比 qarnet/serial-mcp 有常驻环形缓冲):
- MCP `read` 只能读到**调用之后**到达的字节,之前的数据直接丢弃
- 连接打开期间**没有后台 ring buffer**(源码 `src/serial/connection.rs` 只持有流,无历史)
- 抓开机日志必须用 **采集窗口模式**(`duration_ms` + `start_trigger=first-byte`):**先启动采集等第一字节,再触发设备输出**,否则错过
## 采集窗口模式(capture)
这是该项目抓完整连续输出的唯一方式,等价于"有边界的持续读"。
### CLI 参数
```
serial-mcp-server read --port COM6 --baud 115200 \
--duration-ms 30000 \ # 采集窗口时长(从触发点起算)
--start-trigger first-byte \ # 触发方式:first-byte(默认)/ immediate
--initial-timeout-ms 90000 \ # first-byte 模式最多等多久来第一字节(超时空返回)
--idle-timeout-ms 8000 \ # 采集开始后连续静默多久提前结束
--max-bytes 65536 \ # 累计字节硬上限
--json
```
### 结束原因(completion_reason)
| 值 | 含义 |
|---|---|
| `initial_timeout` | 等 first-byte 超时,返回空(不算错误) |
| `duration_elapsed` | 从触发点采满 `duration-ms` |
| `idle_timeout` | 采集中途静默超过 `idle-timeout-ms` 提前收工 |
| `max_bytes` | 累计达 `max-bytes` |
### 返回结构
`read` 对象含:`data`(合并完整字节)、`bytes_read`、`status`(ok/timeout)、`completion_reason`、`waited_ms`(等到首字节耗时)、`elapsed_ms`(采集时长)、`chunks[]`(每块 offset/bytes_read/waited_ms/elapsed_ms)。
## 抓取 MCU 开机日志(@test 核心场景)
**顺序必须:先启动采集(打开 COM 等 first-byte)→ 再烧录触发复位 → 采集自动抓取。**
```powershell
# 一键:采集(含 EOF 重试)→ 烧录 → 提取日志 → verify 校验
powershell -ExecutionPolicy Bypass -File "D:\Code\DTU 程序\STM32F4-Base\test\run_boot_test.ps1" `
-Port COM6 -BaudRate 115200 -DurationMs 30000 -InitialTimeoutMs 90000 `
-IdleTimeoutMs 8000 -MaxBytes 65536 `
-FlashCmd "D:\Code\DTU 程序\STM32F4-Base\MDK-ARM\download.bat" `
-Required "App init OK;Network Init;net init: OK;PHY: 100M FULL" `
-Forbidden "FAIL;ERROR;HardFault"
```
退出码:0=PASS / 1=FAIL / 2=采集或烧录错误。
### 底层脚本(`test/serial_capture.ps1`)
- **`-FlashCmd` 分支**:一个调用内完成 稳定启动采集 → 烧录 → 等采集结束,避免工具调用间隔导致采集超时
- **EOF 自动重试**:COM 被上一个进程释放后立即重开会报
`UnexpectedEof: serial stream returned zero bytes during capture`(tokio-serial 读 0 字节,第三方项目 capture.rs 视为致命错误)。脚本检测到后退避 1.5s 重开,最多 3 次
- 采集稳定启动判据:进程存活超过 `-StabilityCheckMs`(默认 1.5s)
### 参数经验值(本机固件)
| 参数 | 值 | 理由 |
|---|---|---|
| `idle-timeout-ms` | 8000 | boot 阶段有自然静默间隙(defaultTask 与 netTask 之间约 3~4s),太小会在网络初始化前提前结束 |
| `initial-timeout-ms` | 90000 | 容错:烧录编译+下载耗时可能 40s+,采集必须等得住 |
| `duration-ms` | 30000 | 覆盖完整开机流程(boot ~5s + net init ~3s + FTP 延迟 7s) |
## 交互式调试(MCP)
用于主动下发命令、读取响应(非开机日志抓取):
1. `serial_list_ports` → 找 `COM6`(读 `.opencode/serial_config.json` 确认)
2. `serial_open`(port=COM6, baud_rate=115200)→ 返回 `connection_id`(UUID)
3. `serial_write`(connection_id, data, encoding=utf8/hex/base64)
4. `serial_read`(connection_id, timeout_ms=1000)→ 单次读,只能读到调用后的字节
5. `serial_close`
MCP `read` 也支持采集窗口字段:`duration_ms`、`start_trigger`、`initial_timeout_ms`、`idle_timeout_ms`(传 `duration_ms` 即进入 capture 模式)。
## 常见陷阱
| 现象 | 原因/处理 |
|---|---|
| `UnexpectedEof: serial stream returned zero bytes` | COM 刚被释放立即重开(tokio-serial 读 0 字节)。用 `serial_capture.ps1`(含重试)或间隔几秒再开 |
| 抓到日志缺少 `Network Init` | `idle-timeout-ms` 太小,在网络初始化前的静默间隙提前结束;调到 8000ms |
| 烧录后无数据 | 采集必须在烧录**前**启动;`initial-timeout-ms` 太短导致采集先超时 |
| `Error: Connection ID ... not found` | connection_id 是每次 open 生成的 UUID,读/写/关都要用它 |
| 端口被占用 | 先 `serial_close` 释放;Keil ST-Link 下载不占 COM,可并存 |
## 工具历史
本项目是 Serial Studio MCP 的替代方案(更轻量、无 GUI 依赖、无导出文件定位问题)。Serial Studio 相关配置、bridge 与文档已全部清理。
@@ -0,0 +1,79 @@
# 自动化测试流程(AI 迭代闭环)
> 目标:AI 改完代码后,可自动完成「构建 → 烧录 → 抓取串口调试信息 → 校验 → 迭代」,无需人工开终端/串口助手。
## 总体流程
```
@test 命令触发
│
├─ Step 0 预检 serial-mcp-server 二进制 + list-ports 确认 COM
├─ Step 1 构建验证 MDK-ARM/build.bat (0 错误 0 警告才继续)
├─ Step 2 烧录 + 采集(一条命令编排,先采集等 first-byte 再烧录)
│ test/run_boot_test.ps1 (内含 serial_capture.ps1 + download.bat + verify_log.ps1)
├─ Step 3 判定:
│ PASS → 报告,结束
│ FAIL → 依据 [MISS]/[HIT] + 日志尾部,修改代码后回到 Step 1
```
## 命令与脚本清单
| 名称 | 位置 | 作用 |
|---|---|---|
| `@build` | `.opencode/command/build.md` | 仅编译验证(0 错误 0 警告) |
| `@download` | `.opencode/command/download.md` | 编译并烧录(ST-Link) |
| `@test` | `.opencode/command/test.md` | 完整闭环:build → capture+download → verify → iterate |
| `test/run_boot_test.ps1` | `test/run_boot_test.ps1` | **一键闭环**:采集(含 EOF 重试)→ 烧录 → 提取日志 → verify,退出码 0=PASS/1=FAIL/2=错误 |
| `test/serial_capture.ps1` | `test/serial_capture.ps1` | 底层采集编排:稳定启动采集 → 烧录 → 等采集结束;内置 EOF 自动重试 |
| `test/verify_log.ps1` | `test/verify_log.ps1` | 对日志做标记校验,输出 PASS/FAIL 并返回退出码 |
| serial-mcp-server | `%LOCALAPPDATA%\serial-mcp-server\serial-mcp-server.exe` | CLI/MCP 串口工具(Adancurusul/serial-mcp-server) |
## 判定标准
- **构建**:`@build` 退出码 0(0 错误 0 警告),否则不进入硬件环节。
- **烧录**:`@download` 退出码 0(`run_boot_test.ps1` 内部调用)。
- **日志**:`verify_log.ps1` 退出码
- `0` = PASS:所有 `-Required` 标记均出现,且无 `-Forbidden` 模式命中
- `1` = FAIL:存在缺失标记(`[MISS]`)或违规模式(`[HIT]`)
- `2` = 日志文件不可读
### 默认开机标记(来自固件)
| 标记 | 来源 |
|---|---|
| `App init OK` | `App/app_main.c` |
| `RS485 init: OK` | `App/app_main.c` |
| `NAND init:` | `App/app_main.c` |
| `ADC init:` | `App/app_main.c` |
| `SD2506 ID:` / `time:` / `temp:` / `battery:` | `App/app_main.c` |
| `Network Init` / `net init: OK` / `MAC:` / `PHY:` | `App/task/net_task.c` |
### 失败模式应对
| 现象 | 处理 |
|---|---|
| `serial-mcp-server` 不存在 | 需先编译安装(见 `docs/测试说明/serial-mcp-server_串口调试.md`) |
| 采集报 `UnexpectedEof: zero bytes` | 已由 `serial_capture.ps1` 自动重试处理;若仍失败,检查 COM 是否被其他程序占用 |
| 抓到日志缺 `Network Init` | `IdleTimeoutMs` 太小(boot 阶段有 ~3-4s 静默间隙),调到 8000ms |
| 烧录后无数据 | 采集必须在烧录**前**启动(`run_boot_test.ps1` 已保证);`InitialTimeoutMs` 需覆盖编译+烧录耗时(90000) |
| 端口被占用 | 先 `serial_close` / 结束残留 `serial-mcp-server` 进程;Keil ST-Link 不占 COM |
| 日志中无 UI 相关输出 | 见下节「UI 自动化」 |
## UI 屏幕自动化(当前缺口)
`App/task/ui_task.c` 目前没有 DBG 打印,串口无法确认 UI 是否成功初始化。建议在固件中补充:
```c
if (ui_port_init() != 0) { DBG_ERROR("UI port init: FAIL"); } else { DBG_INFO("UI port init: OK"); }
if (ui_menu_init() != 0) { DBG_ERROR("UI menu init: FAIL"); } else { DBG_INFO("UI menu init: OK"); }
```
加完后把 `UI port init: OK` / `UI menu init: OK` 加入 `@test` 的 `-Required` 标记,即可自动回归 UI 初始化。屏幕上的**内容**仍需人工目检或后续接入截屏/控制类方案。
## 扩展用法
- **单模块回归**:`@test` 后接 `-Required` 定制,例如网络回归用
`-Required "App init OK;Network Init;net init: OK;PHY: 100M FULL"`。
- **测试套件构建**:`test/test_config.h` 开启某个 `TEST_SUITE_*` 后,把套件打印的
`=== ... Test:` 标题作为 Required 标记,配合 `test/` 下各用例输出判断。
- **长时间采集**:serial-mcp-server 支持 `--duration-ms` 长窗口采集(MCP `read` 传 `duration_ms` 即进入 capture 模式)。