新增 Python 串口助手 serial_tool(常驻 daemon+全量日志文件即接口)取代 serial-mcp-server:@test 采集链改写 + 全库文档迁移

This commit is contained in:
2026-09-15 03:00:41 +08:00
parent 9eb1bd63b4
commit 4b5ce72e11
16 changed files with 1463 additions and 406 deletions
@@ -1,106 +0,0 @@
# 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 "test\run_boot_test.ps1" `
-Port COM6 -BaudRate 115200 -DurationMs 30000 -InitialTimeoutMs 90000 `
-IdleTimeoutMs 8000 -MaxBytes 65536 `
-FlashCmd "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,266 @@
# Python 串口助手(serial_tool)设计说明
> **版本**:v1.1(需求 + 设计 + 实施记录)
> **日期**:2026-09-15
> **状态**:**已实施**(S1–S6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
> **关联文档**:`自动化测试流程.md` · `AGENTS.md`(串口调试/自动化测试节) · `.opencode/serial_config.json`(端口单一配置源,沿用)
> **取代**:`serial-mcp-server_串口调试.md`(实施时删除,工具历史并入本文 §12)
## 1. 背景与目标
### 1.1 为什么重写
现串口调试 = Adancurusul/serial-mcp-server(Rust 二进制,手编译置于用户档案)+ MCP/CLI 双形态。两个致命缺陷(2026-09-15 本机实测):
| # | 缺陷 | 影响 |
|---|---|---|
| F1 | 二进制绑定**用户档案**:`opencode.json` 的 `mcp.serial` 指向 `C:\Users\16241\AppData\Local\serial-mcp-server\*.exe`,本机实际用户为 **Administrator**(该档案不存在,二进制缺失) | serial MCP 工具不可用、@test 采集步骤断裂;换机器/换用户无法复现 |
| F2 | **无历史缓冲**:`read` 只能读调用**之后**到达的字节 | 抓开机日志被迫走"采集窗口 + first-byte 触发 + EOF 重试"仪式(6 个参数 + JSON 解析 + CH340 释放后重开陷阱特判) |
Python 重写一并解决:依赖收敛到仓库 `.venv + pyserial`(任意机器/用户可复现);常驻 daemon 把**全量** RX/TX 持续写入日志文件,历史 = 日志文件本身,采集窗口仪式整体消失。
### 1.2 目标
| # | 目标 |
|---|---|
| G1 | Agent 可枚举 COM 口、连接;失败 ≤1s 快速返回,绝不阻塞 |
| G2 | RX/TX 全量写入纯文本日志文件,Agent 直接读文件即得完整历史 |
| G3 | Agent 一切操作 = 带硬超时(5s)的短命令;串口所有权归常驻 daemon |
| G4 | 一条 `status` 命令看全状态(daemon/端口/计数/最后 RX/日志文件/错误) |
| G5 | 随时清空日志(原子 + 代际号,新旧内容可区分) |
| G6 | @test 一键流程切换新工具:open → clear → 烧录 → 读文件 → verify,无采集窗口 |
| G7 | 全流程**不关端口**(ST-Link 烧录不占 COM),从根上规避 CH340 释放/重开陷阱 |
## 2. 需求清单
| # | 需求 | 优先级 | 来源 |
|---|---|---|---|
| R1 | `ports`:枚举 COM 口(名称/友好名/厂商,标注配置目标口) | P0 | 用户 #1 |
| R2 | `open`:连接端口;不存在/被占用 ≤1s 返回明确错误;参数 port/baud/DTR/RTS | P0 | 用户 #1 |
| R3 | RX/TX 全量时间戳日志(单文件,纯文本,行格式见 §5) | P0 | 用户 #2 |
| R4 | 全部命令硬超时 5s + 失败返回 JSON(exit code 区分),CLI 永不挂起 | P0 | 用户 #3 |
| R5 | `status`:单条 JSON 全状态 | P0 | 用户 #4 |
| R6 | `clear`:原子清空 + 代际递增 + 文件内标记行 | P0 | 用户 #5 |
| R7 | 常驻 daemon + 单实例 + CLI 自动拉起(Agent 无需记生命周期) | P0 | 补充 |
| R8 | 日志 20MB 上限,超限**原地截头**保留尾部 10MB(不重开端口/不 rename) | P0 | 补充(用户确认) |
| R9 | 开端口不翻转 DTR/RTS(防 STM32 自动复位电路误复位),可配置 | P0 | 补充 |
| R10 | 串口读错/拔线 → daemon 存活,state=error,可重开;daemon 被杀可自恢复 | P0 | 补充 |
| R11 | @test 集成:`run_boot_test.ps1` 采集步改写 + `verify_log.ps1` 兼容 + 旧文档/配置迁移 | P0 | 用户场景 |
| R12 | `send`(TX 进日志)、`log --tail/--grep`、`start/stop/restart`、`selftest` 无头自检 | P1 | 补充 |
## 3. 总体方案
### 3.1 形态:常驻 daemon + 薄 CLI + "日志文件即接口"
```mermaid
flowchart LR
A["Agent(opencode bash 工具)"] -->|"短命令(硬超时 5s)"| C["serial_tool.py CLI"]
C -->|"HTTP 127.0.0.1:18765(JSON)"| D["daemon 进程(detached 单实例)"]
D --> S["串口读线程(pyserial,后台)"]
S --> W["行拆分/解码/flush"]
W --> F[("state/serial.log<br/>纯文本,Agent 直接读")]
D --> M[("state/meta.json<br/>pid/gen/版本")]
D --> L[("state/daemon.log<br/>daemon 自身 stderr")]
```
- **单文件实现**:`tools/serial_tool/serial_tool.py`(stdlib + pyserial,约 1000 行);解释器统一 `.venv\Scripts\python.exe`
- **Agent 调用式**:`& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' <命令> [参数]`(任意 cwd;state 目录按脚本位置解析,与 cwd 无关)
- **历史 = 日志文件**:Agent 用 Read/Grep 直接看历史,无需专门 API(`log` 命令只是便捷封装)
- **配置沿用** `.opencode/serial_config.json`(`portName`/`baudRate` 为默认值;新增可选字段 `httpPort`,默认 18765)
### 3.2 "不卡死"的归属(对用户 #3 的重新表述)
串口读是长时操作,归 daemon 后台线程;**Agent 侧只存在短命令**。"不卡死" = 命令层契约:每条 CLI 命令有 5s 硬截止(`--timeout` 可覆盖),到期即返回超时 JSON 与 exit 2,不做任何无限等待。
## 4. 命令契约
### 4.1 子命令一览
| 命令 | 用途 | 关键参数 | 返回(stdout,恒 JSON) |
|---|---|---|---|
| `ports` | 枚举 COM 口 | — | `{"ok":true,"ports":[{"name":"COM6","description":"USB 串行设备 (CH340)"},…],"configured":"COM6"}` |
| `open` | 开端口(**幂等**:同端口已开 = 直接成功,不重开) | `--port` `--baud` `--dtr 0/1` `--rts 0/1`(默认取配置文件;DTR/RTS 默认 0) | `{"ok":true,"port":"COM6","baud":115200,"gen":7,"since":"…ISO…"}` |
| `close` | 关端口(flush 后释放) | — | `{"ok":true}` |
| `send` | 发 TX 字节(进日志);默认**精确字节**不加换行 | 位置参数文本(UTF-8)或 `--hex 0D0A`;`--nl` 追加 CRLF | `{"ok":true,"bytes":12}` |
| `status` | 全状态(见 §4.2) | — | 见 §4.2 |
| `log` | 读日志(文件尾) | `--tail N`(默认 50;`0` = 全部)`--grep P` | `{"ok":true,"gen":8,"lines":["…"]}` |
| `clear` | 清空日志:原地截断 + 写 `[SYS] log cleared (gen=N+1)` | — | `{"ok":true,"gen":8}` |
| `start` / `stop` / `restart` | daemon 生命周期 | — | `{"ok":true,"pid":…}` / stop 后 `{"ok":true,"stopped":true}` |
| `selftest` | 无头自检(行拆分器/解码回退/截头算法 单测回环,无需硬件) | — | 0=PASS |
### 4.2 `status` 返回示例
```json
{
"ok": true,
"daemon": {"pid": 1234, "version": "1.0.0", "uptime_s": 61},
"port": {"ready": true, "name": "COM6", "baud": 115200, "dtr": false, "rts": false,
"since": "2026-09-15T10:29:58.112+08:00"},
"counters": {"rx_bytes": 1834, "tx_bytes": 12, "rx_lines": 57, "errors": 0},
"last_rx": {"ts": "2026-09-15T10:31:02.441+08:00", "line": "UI menu init: OK", "age_ms": 320},
"log": {"path": "D:\\…\\tools\\serial_tool\\state\\serial.log", "size": 4523, "gen": 7},
"state": "active",
"error": null
}
```
`state ∈ {stopped, active, error}`;`port.ready = 已开 && state≠error`。Agent 轮询等待只用本命令。
### 4.3 CLI 退出码契约
| exit | 含义 |
|---|---|
| 0 | 命令成功(`ok:true`) |
| 1 | 领域错误(`ok:false` + `error`:端口不存在/被占用/参数错…)——**快速失败,≤1s** |
| 2 | daemon 不可达或命令超时(5s 硬截止) |
| 3 | 参数/用法错误 |
### 4.4 自动拉起
任何命令(除 `start` 本身)发现 daemon 未运行 → CLI 以 `sys.executable`(同一 .venv 解释器)detached 拉起 daemon(`CREATE_NO_WINDOW`,stderr → `state/daemon.log`),轮询 HTTP 就绪(≤5s)后**重试原命令一次**;仍失败按 exit 2 返回。Agent 无需任何显式 start 步骤。
## 5. 日志文件规范
### 5.1 位置与配套文件(目录整体 gitignore)
| 文件 | 用途 |
|---|---|
| `tools/serial_tool/state/serial.log` | RX/TX/SYS 全量日志(Agent 直接读) |
| `tools/serial_tool/state/meta.json` | daemon 元数据(pid / 版本 / 当前 gen) |
| `tools/serial_tool/state/daemon.log` | daemon 自身 stderr(排障用) |
### 5.2 行格式
```
[SYS] 2026-09-15T10:29:58.112+08:00 port opened COM6 115200 (gen=7)
[SYS] 2026-09-15T10:29:58.301+08:00 log cleared (gen=8)
[RX] 2026-09-15T10:30:03.445+08:00 App init OK
[RX] 2026-09-15T10:30:07.912+08:00 UI menu init: OK
[TX] 2026-09-15T10:30:09.872+08:00 AT+PING
[SYS] 2026-09-15T10:31:00.000+08:00 log truncated to 10MB (cap=20MB)
```
| 规则 | 规定 |
|---|---|
| 方向标记 | `[RX]` 串口入 / `[TX]` Agent 发出 / `[SYS]` 工具事件(open/close/error/cleared/truncated) |
| 时间戳 | 本地 ISO8601 含毫秒与偏移(`2026-09-15T10:30:03.445+08:00`);**行时间戳 = 该行首字节到达时刻** |
| **完整行不变量** | 文件**只含完整行**:残行留 daemon 内存,`200ms` 无后续数据即冲刷成行(或 clear/close 时强制冲刷)→ Agent 读文件永不见半行 |
| 分行 | 按 `\n` 分(`\r` 剥除);纯二进制流(无换行)按 200ms 窗口成行 |
| 解码回退 | UTF-8 → GBK → 仍失败则该行文本域写 `HEX:<原始字节 hex>`(MCU 流 = ASCII 为主 + UTF-8 中文,前两级足够) |
| flush | 每行即 flush(串口速率低,无缓冲压力)→ 文件随时可读、内容即时可见 |
### 5.3 清空与代际
- `clear` = 写句柄上**原地截断**(`seek(0)+truncate`)+ 写 `[SYS] log cleared (gen=N+1)` 标记行;对写线程原子(单写者,截断与写入同一线程串行)
- 代际 `gen` 持久化于 `meta.json`(daemon 重启不丢);Agent 以"最后一个 cleared/opened 标记行"或 `status.log.gen` 区分新旧内容
### 5.4 体积上限(20MB,用户确认)
- 每次写后检查:`size > 20MB` → **原地截头**:在同一写句柄上**读尾部 10MB → 截空 → 写回**(Windows 无"丢弃头部"单系统调用,`ftruncate` 只能截尾;单写者线程内执行,无并发风险)
- **禁止** rename 轮转(Windows 下写句柄跟随被 rename 的文件)与重开文件/端口(CH340 释放后立即重开 → 读 0 字节 EOF 陷阱)
- 截头后写 `[SYS] … log truncated to 10MB (cap=20MB)`;文件头内容可能随时消失 → **Agent 读日志应看尾部**(`log --tail` 或直接读文件末段)
## 6. daemon 行为规范
| 项 | 规定 |
|---|---|
| 单实例 | HTTP 端口(默认 18765,`serial_config.json` 的 `httpPort` 可改)绑定即锁;端口被占 = 已有实例 |
| 拉起方式 | CLI detached 子进程(`CREATE_NO_WINDOW`),解释器 = `sys.executable`(保证同一 .venv) |
| `open` 语义 | 幂等(同端口已开 = 成功返回,**不重开**);端口不存在 → ≤1s 报错并附可用端口列表;被占用 → ≤1s 报错(Windows 共享冲突即时返回)并提示持有者 |
| DTR/RTS | 默认**不翻转**(`dtr=False, rts=False`,防 STM32 自动复位电路误复位目标板);`--dtr/--rts` 可显式置位 |
| 读线程容错 | 串口读异常/设备拔出 → 记 `[SYS] … serial error: …`,`state=error`(`status.error` 非空),**daemon 不退出**;重插后 `open` 重开恢复 |
| 重开退避 | 错误恢复路径重开端口前 ≥1.5s 退避(CH340 特性);正常流程不重开 |
| `stop` | 关端口(flush 尾行)→ 写 `[SYS] port closed` → 退出 |
| 进程被强杀 | Windows 进程退出自动释放 COM 端口;下次命令自动拉起新实例(`open` 幂等路径) |
## 7. 集成与迁移(@test 切换)
### 7.1 新 @test 流程(`run_boot_test.ps1` 采集步改写,退出码约定不变:0/1/2/3)
```mermaid
flowchart LR
A["open(自动拉起 daemon;幂等)"] --> B["clear → gen=N"]
B --> C["MDK-ARM\download.bat(ST-Link 烧录+复位,端口全程打开)"]
C --> D["wait-idle:rx 静默 8s(-SettleMs)或超时 30s(-MaxWaitMs)"]
D --> E["提取本代际 [RX] 行,剥 [RX] 时间戳前缀 → boot txt"]
E --> F["verify_log.ps1(标记匹配,脚本不动)"]
```
- 对比旧流程:6 个采集窗口参数 + JSON 解析 + EOF 重试 **全部删除**;采集 = 端口常开 + 读文件
- `verify_log.ps1` 无需修改(剥前缀后与现有纯文本契约一致)
- 参数保留:`-Port` `-BaudRate` `-FlashCmd` `-Required` `-Forbidden` `-OutDir`;删除 `-DurationMs` 等窗口参数,新增 `-SettleMs`(静默判据,**默认 8000**——boot 任务间有 3~4s 自然静默间隙,2000 会截断)`-MaxWaitMs`(默认 30000)
### 7.2 配套变更清单
| 对象 | 变更 |
|---|---|
| `requirements.txt` | 增 `pyserial`(**保持纯 ASCII** 注释) |
| `.gitignore` | 增 `tools/serial_tool/state/` |
| `opencode.json`(仓库根) | **删除 `mcp.serial` 段**(指向缺失二进制,已失效) |
| `docs/测试说明/serial-mcp-server_串口调试.md` | **删除**(内容精华并入本文;工具历史见 §12) |
| `AGENTS.md` | "串口调试"节改写为 serial_tool(配置源仍 `serial_config.json`);"自动化测试"节同步新流程 |
| `.opencode/command/test.md` | Step 0/2/Notes 改写(前置检查 = serial_tool 可用性 + `ports`;流程 = §7.1) |
| `docs/测试说明/自动化测试流程.md` | 采集机制描述同步(去 serial-mcp-server 表述) |
| `.opencode/serial_config.json` | 结构不变(可选增 `httpPort`);`note` 更新 |
## 8. 非目标与 v2 候选
**v1 明确不做**:多端口并发、MCP 封装、协议级 HEX 分析、硬件流控(RTS/CTS)、波特率自适应、GUI。
**v2 候选**:多端口(每口一 daemon 实例或子会话)、MCP wrapper(如需工具面板呈现)、按 tag 过滤的日志订阅(WebSocket/SSE)。
## 9. 测试与验收
### 9.1 无头自检(`selftest`,0=PASS)
行拆分器(CRLF/残行冲刷/纯二进制窗口)、解码回退链(UTF-8/GBK/HEX)、截头算法(合成大文件 → ftruncate 语义)——纯进程内,无需硬件。
### 9.2 端到端验收(逐项过)
| # | 用例 | 判据 |
|---|---|---|
| A1 | `ports` | 列表含 CH340 端口,`configured` 标注正确 |
| A2 | 端口被占用(另一进程先开 COM6)→ `open` | ≤1s 返回 `ok:false`(占用),无挂起 |
| A3 | `open→status→send→log→clear→close` 全走一遍 | 全 `ok:true`;日志含 TX 行与 cleared 标记;gen 递增 |
| A4 | `stop` 后强杀 daemon(taskkill)→ 再发任意命令 | 自动拉起成功,`open` 幂等路径无 CH340 EOF 错误 |
| A5 | 日志灌至 >20MB | 自动截头至 ~10MB,写入连续、无重开端口,`[SYS] truncated` 行存在 |
| A6 | 运行中拔 CH340 → `status` | daemon 存活,`state=error`;重插 + `open` 恢复 |
| A7 | **@test E2E ×3**(含一轮"上轮端口未关"场景) | 三轮全 PASS(Required 标记齐、无 Forbidden),boot 日志完整 |
| A8 | `selftest` | 0=PASS |
## 10. 实施步骤(按序执行)
| # | 步骤 | 产物 | 验证 |
|---|---|---|---|
| S1 | `requirements.txt` 增 pyserial + `.venv` 安装 | requirements.txt | `pip show pyserial` 有版本 ✅ |
| S2 | daemon 核心:HTTP 服务 + 串口读线程 + 行日志写(含 clear/截头/DTR 策略) | `tools/serial_tool/serial_tool.py`(daemon 部分) | `start→status→send→stop` 手动走通 ✅ |
| S3 | CLI 全子命令 + 自动拉起 + 超时契约 + `selftest` | serial_tool.py(CLI 部分) | `selftest` 0=PASS + 命令走查 ✅ |
| S4 | 验收 A1–A6、A8 | 测试通过记录 | A1–A5/A8 PASS ✅(本机无 CH340,A6 待硬件) |
| S5 | @test 集成:`run_boot_test.ps1` 采集步改写 + 参数收敛 | run_boot_test.ps1 | 负路径(端口缺失→exit 2)+ 假烧录全链路 + verify 正/负判定 ✅;**A7 正路径待 CH340 接入** |
| S6 | 文档/配置迁移(§7.2 全清单) | docs + 配置 | 全库 grep 无 serial-mcp-server 残留引用(本文 §12 工具历史除外) ✅ |
提交:全部完成后单提交(pre-commit 门禁;纯宿主侧 Python,不涉及 Keil 构建)。
## 11. 风险与开放问题
| # | 项 | 策略 |
|---|---|---|
| O1 | 换机器缺 CH340 驱动 → `ports` 无目标口 | `ports` 返回带提示("未找到 CH340,请装驱动");文档列驱动要求 |
| O2 | 截头瞬间 Agent 恰在读文件 → 视图错位 | 已知可接受:Agent 读**尾部**;`log` 命令经 daemon 读更稳 |
| O3 | daemon 强杀瞬间丢 ≤1 行(内存残行) | 可接受(debug 日志场景);`close` 路径保证冲刷 |
| O4 | HTTP 端口 18765 与其他服务冲突 | `serial_config.json` `httpPort` 可改 |
| O5 | TX 用途(本工程 USART1 单向输出) | 保留能力,面向未来交互/RS485 调试;v1 仅保证进日志 |
| O6 | daemon 常驻内存(Python 进程 ~20MB) | 可接受;`stop` 即释放 |
## 12. 工具历史
| 代 | 方案 | 结局 |
|---|---|---|
| 1 | Serial Studio MCP(GUI 依赖、导出文件定位问题) | 已清理(2026-09 前) |
| 2 | Adancurusul/serial-mcp-server(Rust,MCP+CLI) | **被本工具取代**:二进制绑定用户档案(本机缺失)+ 无历史缓冲(采集窗口仪式) |
| 3 | **serial_tool(本文,Python 仓库内)** | 当前方案 |
## 13. 变更记录
| 日期 | 变更 |
|---|---|
| 2026-09-15 | v1.1 实施完成(S1–S6)。实施中实测发现并修复 4 个设计文档未覆盖的 Windows 实现级缺陷:① `SO_REUSEADDR` 在 Windows 允许多个活跃 socket 绑同端口 → HTTP 服务改**独占绑定**(`SO_EXCLUSIVEADDRPLACE`,发行版未导出时用数值 0x40 兜底)+ restart 强制确认旧实例死亡,防"already_running"假成功留下旧代码;② 写句柄 `"ab"` 追加模式在 Windows **禁读** → 溢出截头的"读尾部"必崩,改 `"a+b"`(自测用独立句柄故未暴露,真实 daemon 溢出路径已 E2E 验证);③ Windows 对**不存在**的 COM 口常报 Access Denied → 误报"port busy",改以 `list_ports` 枚举结果为"不存在/占用"判定准绳;④ 静默判据默认 2s 会截断 boot(任务间 3~4s 自然静默间隙),`-SettleMs` 默认改 8000ms。验收状态:A1–A5/A8 PASS(本机无 CH340,用 COM1 替代口验证;A5 溢出用进程内驱动真实 writer_loop 验证);A6/A7 正路径待硬件接入补验 |
@@ -9,7 +9,7 @@
|---|---|
| `docs/测试说明/自动化测试流程.md` | @test 闭环细节(命令 / 标记 / 失败模式) |
| `docs/测试说明/测试文档模板规范.md` | 测试文档模板、命名规则(TM / TC / DP) |
| `docs/测试说明/serial-mcp-server_串口调试.md` | 串口调试 / 采集工具与陷阱 |
| `docs/测试说明/串口助手设计说明.md` | 串口调试 / 采集工具与陷阱(Python 串口助手) |
| `docs/UI 设计/UI_自动化测试流程.md` | UI 模拟器回归(ui-verify)细节 |
| `docs/代码规范/pre-commit使用说明.md` | pre-commit 门禁配置与范围 |
| `docs/项目部署环境要求.md` | 构建 / 测试工具链环境 |
@@ -187,8 +187,7 @@ static void phaseN_run(void) {
| 工具 | 位置 | 作用 |
|---|---|---|
| serial-mcp-server v0.3.0 | `%LOCALAPPDATA%\serial-mcp-server\serial-mcp-server.exe` | 串口 CLI / MCP:列端口、采集、读写 |
| `test/serial_capture.ps1` | `test/` | 底层采集编排(稳定启动 → 烧录 → 收集;内置 EOF 自动重试) |
| Python 串口助手(serial_tool) | `tools/serial_tool/serial_tool.py`(.venv + pyserial) | 常驻 daemon + 薄 CLI:列端口 / 开关 / 收发 / 全量日志 / wait-idle |
| `test/run_boot_test.ps1` | `test/` | 一键闭环:采集 → 烧录 → 提取日志 → 校验 |
| `test/verify_log.ps1` | `test/` | 日志标记校验(Required / Forbidden → PASS / FAIL) |
| `.opencode/serial_config.json` | 仓库 | **串口端口单一配置源**(当前 COM6 / 115200);换端口只改这个文件 |
@@ -267,9 +266,9 @@ flowchart TD
### 6.3 三条铁律
1. **采集必须先于烧录武装** —— serial-mcp-server 无历史缓冲(只能读调用后字节);开机日志必须"先采集、后烧录"(`run_boot_test.ps1` 已保证顺序);
1. **采集必须先于烧录武装** —— 开串口 + clear 在烧录前完成(daemon 常驻全量日志兜底,不会漏字节;`run_boot_test.ps1` 已保证顺序);
2. **端口以 `.opencode/serial_config.json` 为准** —— 每次连接前先读它;
3. **参数覆盖时间窗** —— `InitialTimeoutMs=90000`(覆盖编译 + 烧录)、`IdleTimeoutMs=8000`(覆盖 boot ~3-4s 自然静默间隙);`UnexpectedEof` 陷阱由 `serial_capture.ps1` 内置自动重试,勿裸跑 CLI。
3. **静默判据覆盖时间窗** —— `-SettleMs=8000`(覆盖 boot ~3-4s 自然静默间隙)、`-MaxWaitMs=30000`(整体超时兜底);
---
@@ -337,7 +336,7 @@ flowchart LR
| `storage_test.h` / `storage_test_task.c` | STORAGE 套件:FTL + FatFS 集成(TC-STO-01~04)+ 恢复测试 |
| `gd5f_test.h` / `gd5f_test_task.c` | GD5F 套件:NAND 驱动 10 阶段 |
| `sd2506_test.h` / `sd2506_test_task.c` | RTC 套件:SD2506 RTC 2 阶段组 |
| `run_boot_test.ps1` / `serial_capture.ps1` / `verify_log.ps1` | 自动化闭环三件套(纯 ASCII) |
| `run_boot_test.ps1` / `verify_log.ps1` + `serial_tool` | 自动化闭环三件套(ps1 纯 ASCII / Python 仓库内置) |
| `ftp_test.py` / `ftp_capture.py` / `ftp_up_dl_test.py` / `ftp_speed_test.py` | FTP PC 端测试工具 |
| `ch395f_socket_test.py` | CH395F PC 端 socket 回显 / 大文件传输工具 |
| `time_sync_server.py` | 对时推送 PC 端服务器 |
@@ -350,7 +349,7 @@ flowchart LR
| `docs/测试说明/GD5F2GQ5UE_Test_Guide.md` | GD5F + 存储集成(TC-GD5F / TC-STO) |
| `docs/测试说明/SD2506_Test_Guide.md` | RTC(TC-RTC-xxx) |
| `docs/测试说明/FTP_Test_Guide.md` | FTP 服务(手动 + 阶段 8 自动化) |
| `docs/测试说明/serial-mcp-server_串口调试.md` | 串口调试工具 |
| `docs/测试说明/串口助手设计说明.md` | 串口调试工具(Python 串口助手) |
| `docs/测试说明/自动化测试流程.md` | @test 闭环细节 |
| `docs/测试说明/测试文档模板规范.md` | 测试文档模板与命名 |
+12 -12
View File
@@ -7,10 +7,10 @@
```
@test 命令触发
│
├─ Step 0 预检 serial-mcp-server 二进制 + list-ports 确认 COM
├─ Step 0 预检 .venv + serial_tool(selftest/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 2 烧录 + 采集(一条命令编排:开串口 + 清日志 → 烧录 → wait-idle → 提取)
│ test/run_boot_test.ps1 (内置 serial_tool + download.bat + verify_log.ps1)
├─ Step 3 判定:
│ PASS → 报告,结束
│ FAIL → 依据 [MISS]/[HIT] + 日志尾部,修改代码后回到 Step 1
@@ -23,10 +23,9 @@
| `@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/run_boot_test.ps1` | `test/run_boot_test.ps1` | **一键闭环**:open + clear → 烧录 → wait-idle(静默 8s/超时 30s)→ 提取 `[RX]` → verify,退出码 0=PASS/1=FAIL/2=采集或烧录错误/3=用法错误 |
| `tools/serial_tool/serial_tool.py` | `tools/serial_tool/` | Python 串口助手(常驻 daemon + 薄 CLI):ports/open/send/status/log/clear/wait-idle/selftest;全量日志 `state/serial.log`(20MB 自动截头) |
| `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) |
## 判定标准
@@ -52,11 +51,11 @@
| 现象 | 处理 |
|---|---|
| `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 |
| `selftest` FAIL / `ModuleNotFoundError: pyserial` | venv 未建或依赖缺失:按 AGENTS.md「Python 环境」重建 `.venv` + `pip install -r requirements.txt` |
| daemon 无响应 / 自动拉起失败 | 查 `tools/serial_tool/state/daemon.log`;`serial_tool.py restart` 重建 daemon;检查 COM 是否被其他程序占用 |
| 抓到日志缺 `Network Init` | `-SettleMs` 太小(boot 任务间有 ~3-4s 自然静默间隙),用默认 8000ms |
| 烧录后无数据(`no_data`) | 开串口 + clear 必须在烧录**前**完成(`run_boot_test.ps1` 已保证);核对 COM 号、板子供电,看 `state/serial.log` 有无 SYS 异常行 |
| 端口被占用(`port busy`) | 先 `serial_tool.py close` 或 `restart`;检查其他程序占用;Keil ST-Link 不占 COM |
| 日志中无 UI 相关输出 | 见下节「UI 自动化」 |
## UI 屏幕自动化
@@ -72,10 +71,11 @@
`-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 模式)。
- **长时间采集**:daemon 全量持续写入 `state/serial.log`(20MB 上限自动截头保尾 10MB),直接读文件即可;或用 `log --tail 0 --grep <标记>` 过滤。
## 变更记录
| 日期 | 变更 |
|---|---|
| 2026-09-13 | 「UI 屏幕自动化(当前缺口)」更新:UI 初始化 DBG 打印已实现(`ui_task.c`),屏幕内容已纳入模拟器像素回归;测试分层与门禁见 `测试开发标准流程.md` |
| 2026-09-15 | 采集机制整体切换:serial-mcp-server(采集窗口/first-byte/EOF 重试)→ 仓库内置 Python 串口助手(daemon 常驻全量日志 + `wait-idle` 静默判据 `-SettleMs`/`-MaxWaitMs`);`serial_capture.ps1` 删除,流程/脚本清单/失败模式表同步 |
+17 -20
View File
@@ -21,7 +21,7 @@ flowchart LR
X[STM32CubeMX 6.17.0<br/>外设配置/代码再生成]
S[CMake + VS2019<br/>LVGL PC 模拟器]
P[Python .venv<br/>字体/回归脚本]
T[serial-mcp-server<br/>串口调试/自动测试]
T[Python 串口助手 serial_tool<br/>串口调试/自动测试]
end
subgraph TGT["② 目标板(DTU 硬件)"]
M[STM32F407ZGTx @168MHz<br/>1MB Flash / 192KB SRAM]
@@ -116,7 +116,7 @@ cmake --build build --config Debug # 日常增量
|---|---|---|
| 统一入口 | **仓库 `.venv\Scripts\python.exe`** | 一切依赖第三方库的脚本(字体生成、截图转 PNG、RemoDispBus 回归)都用它 |
| 解释器版本 | Python ≥ 3.10(任意发行版) | 种子解释器仅用于建 venv 一次;本机为 3.12.4 |
| 依赖 | `fonttools==4.51.0`、`pillow==10.3.0` | 清单 = 仓库根 `requirements.txt`(**必须保持纯 ASCII**:Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError) |
| 依赖 | `fonttools==4.51.0`、`pillow==10.3.0`、`pyserial==3.5` | 清单 = 仓库根 `requirements.txt`(**必须保持纯 ASCII**:Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError) |
| 入库情况 | `.venv/` 已 gitignore | **换机/首次必须重建** |
```powershell
@@ -146,12 +146,12 @@ python tools/font_gen/extract_cn.py # 任意 python3:
| 项 | 要求 | 说明 |
|---|---|---|
| serial-mcp-server | v0.3.0(Rust,自源码 `cargo build --release`) | 安装于 `%LOCALAPPDATA%\serial-mcp-server\`;MCP(AI 交互)与 CLI(脚本采集)两用 |
| Python 串口助手 | `tools/serial_tool/serial_tool.py`(仓库内置,.venv + pyserial) | 常驻 daemon + 薄 CLI + 全量日志文件;无需单独安装,`pip install -r requirements.txt` 即就绪 |
| 调试串口 | USART1(PA9 TX / PA10 RX),115200 8N1 | **端口单一配置源 `.opencode/serial_config.json`**(本机 COM6);换端口只改这个文件 |
| 一键测试 | `test\run_boot_test.ps1`(即 `@test`) | 采集窗口武装 → 烧录 → 日志标记校验;默认 COM6 / 115200,退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 |
| 一键测试 | `test\run_boot_test.ps1`(即 `@test`) | 开串口 + 清日志 → 烧录 → wait-idle(静默 8s/超时 30s)→ 提取 → 标记校验;默认端口取 `serial_config.json` / 115200,退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法错误 |
> 关键顺序:**串口采集必须先于烧录复位武装**(`-FlashCmd` 分支已保证)。
> 参数经验值与陷阱见 `docs/测试说明/serial-mcp-server_串口调试.md`、`docs/测试说明/自动化测试流程.md`。
> 采集 = 端口常开 + daemon 全量日志(`tools/serial_tool/state/serial.log`),无采集窗口/first-byte/EOF 重试仪式。
> 命令契约与陷阱见 `docs/测试说明/串口助手设计说明.md`、`docs/测试说明/自动化测试流程.md`。
### 2.7 代码审查钩子(pre-commit)
@@ -230,18 +230,15 @@ pre-commit run --all-files # 首次全库基线扫描
> 手动下载:uv → https://astral.sh/uv/ (一行安装 `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"`)· pre-commit → https://pre-commit.com/ · cppcheck 2.21.0 → https://github.com/CppQA/cppcheck/releases (2.21.0 tag 的 Windows x64 zip,解压至 `C:\Program Files\Cppcheck` 并加入 PATH)
**第 7 步:serial-mcp-server**(串口调试 / 自动测试,Rust 源码编译)
**第 7 步:Python 串口助手**(串口调试 / 自动测试,仓库内置)
无需单独安装:`tools/serial_tool/` 随仓库提供,依赖 `pyserial`(已入 `requirements.txt`,第 4 步建 `.venv` 时一并安装)。建成后验证:
```powershell
winget install Rustlang.Rustup
git clone https://github.com/Adancurusul/serial-mcp-server
cd serial-mcp-server; cargo build --release
New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\serial-mcp-server" | Out-Null
Copy-Item target\release\serial-mcp-server.exe "$env:LOCALAPPDATA\serial-mcp-server\"
& '.venv\Scripts\python.exe' tools\serial_tool\serial_tool.py selftest # → SELFTEST PASS
& '.venv\Scripts\python.exe' tools\serial_tool\serial_tool.py ports # 枚举 COM 口
```
> 手动下载:Rust → https://www.rust-lang.org/tools/install (运行 `rustup-init.exe`)· serial-mcp-server 源码 → https://github.com/Adancurusul/serial-mcp-server
**第 8 步:下载器驱动**(ST-Link)
- ST 官网下载 **STM32CubeProgrammer** 运行一次(自动安装 ST-Link USB 驱动):https://www.st.com/en/development-tools/stm32cubeprog.html
@@ -251,7 +248,7 @@ Copy-Item target\release\serial-mcp-server.exe "$env:LOCALAPPDATA\serial-mcp-ser
**第 9 步:串口配置**
```powershell
& "$env:LOCALAPPDATA\serial-mcp-server\serial-mcp-server.exe" serial_list_ports # 查 COM 号
& '.venv\Scripts\python.exe' tools\serial_tool\serial_tool.py ports # 查 COM 号
```
把查到的端口写入 `.opencode\serial_config.json` 的 `portName`(唯一配置源,换口只改这里)。
@@ -267,6 +264,7 @@ cmake --build build --config Debug # 0 警告
& '.venv\Scripts\python.exe' simulator\tests\check_menu_rows.py # PASS
& '.venv\Scripts\python.exe' simulator\tests\check_content_pages.py --update # 首次生成参考图
& '.venv\Scripts\python.exe' simulator\tests\check_content_pages.py # 再跑 → PASS
& '.venv\Scripts\python.exe' tools\serial_tool\serial_tool.py selftest # → SELFTEST PASS
pre-commit run --all-files
```
@@ -279,7 +277,7 @@ pre-commit run --all-files
- [ ] `git clone` 仓库 → `pre-commit install`;cppcheck 入 PATH
- [ ] 建 `.venv` 并 `pip install -r requirements.txt`
- [ ] `npm i -g lv_font_conv`
- [ ] serial-mcp-server 编译放置,写好 `.opencode/serial_config.json`(本机 COM 口)
- [ ] 写好 `.opencode/serial_config.json`(本机 COM 口),`serial_tool selftest` PASS
- [ ] 下载器(ST-Link 等)USB 驱动已装,Keil `Options for Target → Debug` 驱动一致
- [ ] 第 10 步冒烟验证全部通过
@@ -302,8 +300,6 @@ pre-commit run --all-files
| uv | https://astral.sh/uv/ | `powershell -c "irm https://astral.sh/uv/install.ps1 \| iex"` |
| pre-commit | https://pre-commit.com/ | 一般 `uv tool install pre-commit` |
| cppcheck | https://github.com/CppQA/cppcheck/releases | 2.21.0 的 Windows x64 zip(`cppcheck-2.21.0-windows-x64.zip` 形式),解压入 PATH |
| Rust(rustup) | https://www.rust-lang.org/tools/install | 运行 `rustup-init.exe` |
| serial-mcp-server | https://github.com/Adancurusul/serial-mcp-server | 源码 `cargo build --release`(v0.3.0) |
| STM32CubeProgrammer | https://www.st.com/en/development-tools/stm32cubeprog.html | 含 ST-Link USB 驱动 |
| ST-Link V2 驱动 | https://www.st.com/en/development-tools/stm321025.html | `ST-LinkV2-USB-Driver` 包 |
| SDL2(仅仓库预编译库缺失时) | https://github.com/libsdl-org/SDL/releases | 2.32.10,一般不需要 |
@@ -453,7 +449,7 @@ pre-commit run --all-files
| pip 装依赖报 UnicodeDecodeError | `requirements.txt` 含中文注释 | 保持该文件**纯 ASCII**(pip 按 GBK 代码页解码) |
| 字体生成 / 转 PNG 报缺模块 | 误用 PATH 里的 msys64 python | 一律用 `.venv\Scripts\python.exe` |
| 内容页回归 exit 2(参考缺失) | `tests/ref/` 是本地生成物、不入库 | 先 `check_content_pages.py --update` 生成参考,再跑回归 |
| 串口采集不到 / 端口占用 | COM 号变化 / 上一进程未释放 | 改 `.opencode/serial_config.json`;`serial_capture.ps1` 已带 EOF 自动重试 |
| 串口采集不到 / 端口占用 | COM 号变化 / 上一进程未释放 | 改 `.opencode/serial_config.json`;`serial_tool.py ports` 查实际端口,`open` 占用 ≤1s 报 `port busy` |
| 烧录失败 | 下载器未选 / USB 驱动缺失 | Keil `Options for Target → Debug` 选对驱动;安装下载器 USB 驱动 |
| 下载报 Flash 算法 / FLM 文件找不到 | 未安装 `Keil::STM32F4xx_DFP` pack(FLM 来自 pack 目录,不在仓库) | Pack Installer 安装该 pack 后重新下载 |
| UV4 启动弹 license 窗口 / 无法编译 | 90 天评估 license 过期或未激活 | `Options for Target → License` 查看/输入;长期使用购买正式 license |
@@ -472,7 +468,7 @@ pre-commit run --all-files
| 网口配置 / 生效链路 | `docs/网络配置说明.md` |
| 远程显示协议 | `docs/UI 设计/RemoDispBus协议与接收设计说明.md` |
| LVGL 模拟器部署 | `docs/UI 设计/LVGL模拟器部署与使用说明.md`、`simulator/README.md` |
| 串口调试 / 自动化测试 | `docs/测试说明/serial-mcp-server_串口调试.md`、`docs/测试说明/自动化测试流程.md` |
| 串口调试 / 自动化测试 | `docs/测试说明/串口助手设计说明.md`、`docs/测试说明/自动化测试流程.md` |
| pre-commit / cppcheck | `docs/代码规范/pre-commit使用说明.md`、`docs/代码规范/cppcheck使用说明.md` |
| 各模块测试指南 | `docs/测试说明/CH395F_Test_Guide.md`、`GD5F2GQ5UE_Test_Guide.md`、`SD2506_Test_Guide.md`、`FTP_Test_Guide.md` |
| 已知硬件陷阱 | `docs/问题记录/CH395F_Trap_Records.md` 等 |
@@ -485,6 +481,7 @@ pre-commit run --all-files
|---|---|
| 2026-09-13 | 初版:汇总开发机(Keil / VS2019+SDL2 / Python venv / 字体 / 串口工具 / pre-commit)、目标板(引脚 / 资源预算 / 下载 / 功能开关)、网络现场部署(默认参数 / 端口 / 验收清单)、远端客户端四类环境要求,附一次性搭建清单(含分步安装命令与冒烟验证)与常见环境问题速查 |
| 2026-09-13 | §2.8 各组件补手动下载网址;新增 §2.9 手动下载来源速查表 |
| 2026-09-15 | 串口调试/自动测试工具由 serial-mcp-server 切换为仓库内置 Python 串口助手(serial_tool,.venv + pyserial,免安装):§2.4 依赖清单、§2.6、§2.8 第 7/9/10 步、搭建清单、§2.9 下载表(去 Rust/serial-mcp-server)、速查表、相关文档同步 |
| 2026-09-13 | 补 STM32CubeMX 6.17.0 + STM32Cube FW_F4 V1.28.3(与 .ioc 一致):拓扑图 / §2.2 / 第 2 步 / §2.9 / 搭建清单,常见问题速查增加再生成版本不匹配条目 |
| 2026-09-13 | 新增"Keil 初始化配置(机器侧项,非项目自带)":license / Device Pack(含 FLM 来源解析路径)/ 下载器驱动,并列出项目自带免配置项;§六 速查补 FLM 缺失、license 过期两条 |
| 2026-09-13 | 补 RAM/Flash 链接布局说明:手动 scatter 文件 `STM32F407-Demo.sct`(在仓库)为链接依据(128KB = SRAM1+SRAM2,SRAM3/CCM 未映射),新机器无需重设、勿改 GUI Target 页 |