d1e6bb4ba7
N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
(user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13
N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
(芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
(不注册编译;实验分支 n30-chip-bench 保留)
N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言
验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
385 lines
22 KiB
Markdown
385 lines
22 KiB
Markdown
# Python 串口助手(serial_tool)使用指南
|
||
|
||
> **定位**:面向使用者的操作手册——命令怎么敲、输出怎么看、常见场景怎么组合、出问题怎么排查。
|
||
> **关联文档**:设计决策与实现细节见 `串口助手设计说明.md`;@test 自动化闭环见 `自动化测试流程.md`;`serial-assistant` skill 有一页速查(用到自动加载,AGENTS.md 不再重复收录)。
|
||
> **版本**:v1.1(与 `.dsh/skills/serial-assistant/scripts/serial_tool.py` 当前实现一致,2026-09-15)
|
||
|
||
## 1. 它是什么(60 秒版)
|
||
|
||
仓库内置的串口调试工具,三个组成部分:
|
||
|
||
| 组成 | 是什么 | 你要知道的 |
|
||
|---|---|---|
|
||
| **常驻 daemon** | 后台 Python 进程,**串口唯一持有者**,把 RX/TX 持续写进日志文件 | 不用管它——任何命令发现它没在跑会**自动拉起** |
|
||
| **薄 CLI** | `serial_tool.py <命令>`,每条命令都是带 5s 硬超时的短操作 | 你唯一直接打交道的界面 |
|
||
| **日志文件** | `.dsh/skills/serial-assistant/scripts/state/serial.log`,**全量历史就在这里** | 想回看任何时刻的数据 → 直接读这个文件 |
|
||
|
||
**统一入口**(仓库根目录执行,任意 cwd 均可):
|
||
|
||
```powershell
|
||
& '.venv\Scripts\python.exe' '.dsh/skills/serial-assistant/scripts/serial_tool.py' <命令> [参数]
|
||
```
|
||
|
||
两条心法:
|
||
1. **所有输出都是 JSON**(stdout),退出码 0=成功 / 1=领域错误 / 2=daemon 不可达 / 3=用法错误;
|
||
2. **历史不用"采集"**——daemon 一直在写日志文件,随时 Read/Grep 就是完整历史。
|
||
|
||
## 2. 快速上手
|
||
|
||
```powershell
|
||
# ① 看本机有哪些 COM 口(不依赖 daemon;configured = 配置目标口)
|
||
& '.venv\Scripts\python.exe' '.dsh/skills/serial-assistant/scripts/serial_tool.py' ports
|
||
|
||
# ② 开串口(自动拉起 daemon;端口取 .serialtest/config.json,也可显式指定)
|
||
& '.venv\Scripts\python.exe' '.dsh/skills/serial-assistant/scripts/serial_tool.py' open
|
||
|
||
# ③ 发一条数据(文本;--hex 发字节;--nl 末尾加 CRLF)
|
||
& '.venv\Scripts\python.exe' '.dsh/skills/serial-assistant/scripts/serial_tool.py' send "hello" --nl
|
||
|
||
# ④ 看最近 20 行日志(含刚发的 TX 和收到的 RX)
|
||
& '.venv\Scripts\python.exe' '.dsh/skills/serial-assistant/scripts/serial_tool.py' log --tail 20
|
||
|
||
# ⑤ 不用了:关串口(daemon 继续常驻;要彻底退出用 stop)
|
||
& '.venv\Scripts\python.exe' '.dsh/skills/serial-assistant/scripts/serial_tool.py' close
|
||
```
|
||
|
||
## 3. 命令速查
|
||
|
||
| 命令 | 作用 | 依赖 daemon |
|
||
|---|---|---|
|
||
| `ports` | 枚举 COM 口,标注配置目标口(`configured_present`;系统里只有**一个**候选时给 `hint`) | 否(本地执行) |
|
||
| `open` | 开串口(**幂等**:同口已开 = 直接成功;不带 `--dtr/--rts` = **保持现状**,显式给则现场应用并在 `note` 里回显) | 是(未运行自动拉起) |
|
||
| `close` | 关串口 | 是 |
|
||
| `send` | 发 TX 字节(进日志) | 是 |
|
||
| `status` | 全状态一条 JSON(含 `state`、`rx_age_ms` = 距最后一个 RX 字节的毫秒数,`null` = 这个 daemon 还没收过字节) | 是 |
|
||
| `log` | 读日志文件(`--tail N` / `--grep P`) | **否**(直接读文件,daemon 死了也能用) |
|
||
| `clear` | 清空日志 + 代际 +1 | 是 |
|
||
| `wait-idle` | 等 RX 静默(@test 的收尾判据) | 是 |
|
||
| `start` / `stop` / `restart` | daemon 生命周期 | — |
|
||
| `selftest` | 无头自检(行拆分/解码/截头算法,无需硬件) | 否 |
|
||
|
||
所有命令都支持 `--timeout <秒>`(默认 5)覆盖 CLI→daemon 硬超时。
|
||
|
||
### 3.1 `ports` — 枚举串口
|
||
|
||
```powershell
|
||
... serial_tool.py ports
|
||
```
|
||
|
||
```json
|
||
{"ok": true,
|
||
"ports": [{"name": "COM1", "description": "通信端口 (COM1)", "hwid": "ACPI\\PNP0501\\0"}, …],
|
||
"configured": "COM6"}
|
||
```
|
||
|
||
- `configured` 来自 `.serialtest/config.json` 的 `portName`;找不到它 = 板子没接/驱动没装/口号变了。
|
||
- CH340 的 `description` 通常含"USB 串行设备"字样。
|
||
|
||
### 3.2 `open` — 开串口
|
||
|
||
```powershell
|
||
... serial_tool.py open # 端口/波特率取配置文件
|
||
... serial_tool.py open --port COM6 --baud 115200
|
||
... serial_tool.py open --dtr 1 --rts 0 # 显式置位(默认都不翻转,见下)
|
||
```
|
||
|
||
- **幂等**:同端口同波特率已开 → 直接返回成功(`note: already open`),不会重开端口。
|
||
- **DTR/RTS 默认不翻转**——防 STM32 自动复位电路把目标板误复位;确需翻转才用 `--dtr 1` / `--rts 1`。
|
||
- 成功返回:`{"ok":true,"port":"COM6","baud":115200,"dtr":false,"rts":false,"gen":7,"since":"…ISO…"}`。
|
||
- 失败(**≤1s 快速返回**,exit 1):
|
||
|
||
| 错误 | 含义 |
|
||
|---|---|
|
||
| `port not found: COM6 (available: COM1, …)` | 该口不存在(Windows 对此常报 Access Denied,工具已按端口枚举结果纠正判定) |
|
||
| `port busy: COM1 (held by another process)` | 口被其他进程占用 |
|
||
|
||
- **重开退避**:距上次关口/daemon 启动 <1.5s 时,open 会先等待再开(CH340"释放后立即重开 → 读 0 字节"陷阱的规避)。
|
||
|
||
### 3.3 `close` — 关串口
|
||
|
||
```powershell
|
||
... serial_tool.py close # → {"ok":true}
|
||
```
|
||
|
||
未开时返回 `{"ok":true,"note":"port not open"}`(不算错误)。daemon 继续运行。
|
||
|
||
### 3.4 `send` — 发数据
|
||
|
||
```powershell
|
||
... serial_tool.py send "hello" # 文本(UTF-8 编码发出,精确字节,不加换行)
|
||
... serial_tool.py send "hello" --nl # 末尾追加 CRLF
|
||
... serial_tool.py send --hex 0D0A # 发字节 0x0D 0x0A(支持空格分隔:0D 0A 亦可)
|
||
... serial_tool.py send --hex 48454C4C4F # = "HELLO"
|
||
```
|
||
|
||
- 文本与 `--hex` **二选一**;都不给 = 用法错误(exit 3)。
|
||
- 成功返回:`{"ok":true,"bytes":7}`(实际发出字节数)。
|
||
- 端口未开 → `port not open (run 'open' first)`。
|
||
- 日志中的 TX 行会把控制字符转义成字面文本(`…hello\r\n`),保持日志行式完整。
|
||
|
||
### 3.5 `status` — 全状态
|
||
|
||
```powershell
|
||
... serial_tool.py status
|
||
```
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"daemon": {"pid": 16816, "version": "1.0.0", "uptime_s": 31},
|
||
"port": {"ready": true, "name": "COM1", "baud": 115200, "dtr": false, "rts": false,
|
||
"since": "2026-09-15T02:30:57.739+08:00"},
|
||
"counters": {"rx_bytes": 1834, "tx_bytes": 22, "rx_lines": 57, "tx_lines": 3, "errors": 0},
|
||
"last_rx": {"ts": "…", "line": "UI menu init: OK", "age_ms": 320},
|
||
"log": {"path": "…\\tools\\serial_tool\\state\\serial.log", "size": 4523, "gen": 7},
|
||
"state": "active",
|
||
"error": null
|
||
}
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| `state` | `active`(正常收数据)/ `stopped`(口未开)/ `error`(读错/拔线,`error` 字段有详情;重开 `open` 即恢复) |
|
||
| `port.ready` | 已开 && 非 error |
|
||
| `counters` | 本 daemon 生命周期累计(daemon 重启清零) |
|
||
| `last_rx.age_ms` | 距最后一行 RX 的毫秒数——判断"还在刷/已静默" |
|
||
| `log.gen` | 当前日志代际(`clear` 会 +1) |
|
||
|
||
### 3.6 `log` — 读日志
|
||
|
||
```powershell
|
||
... serial_tool.py log # 末 50 行
|
||
... serial_tool.py log --tail 200 # 末 200 行
|
||
... serial_tool.py log --tail 0 # 全部行
|
||
... serial_tool.py log --grep "App init OK" # 只留含子串的行(全文件搜,再截尾)
|
||
... serial_tool.py log --grep "init" --tail 100
|
||
... serial_tool.py log --grep "app init" -i # 忽略大小写
|
||
... serial_tool.py log --regex "\[STACK\]|Network Init" --tail 5 # 正则
|
||
```
|
||
|
||
- **直接读日志文件**实现——daemon 死机/被杀也不受影响;`gen` 取自 `meta.json`。
|
||
- **先过滤、后截尾**(2026-10-10 修):旧实现先 `--tail`(默认 50)后 grep,`log --grep "App init OK"` 只要开机后又刷了 50 行就必然查无此 marker——这就是旧文档"log --grep 实测不可信"的根因,现已修复,可直接作判定依据。
|
||
- 返回 `{"ok":true,"gen":N,"lines":[…],"scanned":总行数,"matched":命中行数}`;`--tail` 截掉了部分命中时另带 `note` 说明。`--regex` 写错 → `ok:false` + 错误文本(exit 3)。
|
||
- 等价的手动读法(Agent 用 Read/Grep 工具、人用 PowerShell 均可):
|
||
|
||
```powershell
|
||
Get-Content '.dsh\skills\serial-assistant\scripts\state\serial.log' -Tail 20
|
||
Select-String -Path '.dsh\skills\serial-assistant\scripts\state\serial.log' -Pattern 'App init OK'
|
||
```
|
||
|
||
### 3.7 `clear` — 清空日志(代际 +1)
|
||
|
||
```powershell
|
||
... serial_tool.py clear # → {"ok":true,"gen":8}
|
||
```
|
||
|
||
- 原地截断 + 写 `[SYS] … log cleared (gen=N+1)` 标记行;**不重开文件、不动串口**。
|
||
- 用途:每次烧录/实验前 clear 一下,之后日志里就只属于本轮,新旧内容按 `gen`/标记行区分。
|
||
|
||
### 3.8 `wait-idle` — 等 RX 静默
|
||
|
||
```powershell
|
||
... serial_tool.py wait-idle # 静默 8s 或超时 30s
|
||
... serial_tool.py wait-idle --settle-ms 5000 --max-ms 60000 # 自定义
|
||
... serial_tool.py wait-idle --first-timeout-ms 12000 # 首字节 12s 未到即判 no_data
|
||
```
|
||
|
||
```json
|
||
{"ok": true, "rx_bytes": 1834, "idle": true, "waited_ms": 8041, "reason": "idle"}
|
||
```
|
||
|
||
| `reason` | 含义 | `idle` |
|
||
|---|---|---|
|
||
| `idle` | 收到过数据,且已连续静默 ≥ `--settle-ms`(**正常收尾**) | true |
|
||
| `no_data` | **本次等待期间**一个字节都没收到(板子没输出/口不对/没烧进去) | false |
|
||
| `timeout` | `--max-ms` 到了仍在持续吐数据 | false |
|
||
|
||
- **`--settle-ms` 默认 8000 不是随便定的**:本工程 boot 任务间有 3~4s 自然静默间隙,判据小于它会把开机日志截断。
|
||
- **首字节门(2026-10-10 加)**:首字节到达**之前**不启动静默计时——旧实现从进入即计时,板子第一行比 `--settle-ms` 来得晚就提前收尾("开机日志缺尾巴"的另一半成因)。`--first-timeout-ms`(0 = 同 `--max-ms`)到点仍零字节 → `no_data` 快速失败。
|
||
- **`rx_bytes` 是本次增量**(旧实现回的是 daemon 累计值,常驻 daemon 下动辄百万,无判读价值)。
|
||
- **CLI 超时自动推导**:未显式带 `--timeout` 时按 `--max-ms/1000 + 5` 取值,不再需要手工加(旧版固定 5s 会在 daemon 还在等时掐断连接 → CLI exit 2 + daemon.log 刷 `ConnectionAbortedError`)。
|
||
- @test 流程(`run_boot_test.py`)用它作为"烧录后日志收齐"的判据(`--first-wait-ms` 默认 12000)。
|
||
|
||
### 3.9 `start` / `stop` / `restart` — daemon 生命周期
|
||
|
||
```powershell
|
||
... serial_tool.py start # 拉起(已在跑 → already_running:true,不做任何事)
|
||
... serial_tool.py stop # 优雅退出:关串口 → 冲刷尾行 → 退出
|
||
... serial_tool.py restart # 停旧 + 拉新,保证新进程加载的是当前代码
|
||
```
|
||
|
||
- 日常**不需要** start(任何命令都会自动拉起)。
|
||
- **改了 `serial_tool.py` 之后**要 `restart`,否则运行中的还是旧代码。
|
||
- `stop` 后 COM 端口立即释放,可交给其他程序;daemon 死掉/被杀同理(下次命令自动拉起,但**串口不会自动重开**——需要时再 `open`)。
|
||
|
||
### 3.10 `selftest` — 无头自检
|
||
|
||
```powershell
|
||
... serial_tool.py selftest # 10 项进程内回环测试,无需硬件
|
||
# [PASS] T1a CRLF 行 … SELFTEST PASS(exit 0)
|
||
```
|
||
|
||
新机器搭完环境先跑它:过了 = 解释器/pyserial/核心算法都正常。
|
||
|
||
## 4. 日志文件(全量历史)
|
||
|
||
### 4.1 三个文件
|
||
|
||
以下文件均在 `state/` 下,属**运行时产物,未创建于仓库**(首次运行工具后才生成):
|
||
|
||
| 文件 | 内容 | 谁读 |
|
||
|---|---|---|
|
||
| `.dsh/skills/serial-assistant/scripts/state/serial.log` | RX/TX/SYS 全量日志 | 你(Read/Grep/`log` 命令) |
|
||
| `.dsh/skills/serial-assistant/scripts/state/meta.json`(运行时未创建) | daemon pid / 版本 / 当前 gen / 口配置快照 | 工具内部 |
|
||
| `.dsh/skills/serial-assistant/scripts/state/daemon.log` | daemon 自身 stderr(启动行、异常) | 排障时看 |
|
||
|
||
整个 `state/` 目录已 gitignore——纯本机运行时产物。
|
||
|
||
### 4.2 行格式
|
||
|
||
```
|
||
[SYS] 2026-09-15T02:30:57.739+08:00 port opened COM1 115200 (gen=0)
|
||
[RX] 2026-09-15T02:31:23.101+08:00 App init OK
|
||
[TX] 2026-09-15T02:31:23.986+08:00 hello_from_tool\r\n
|
||
[SYS] 2026-09-15T02:31:24.245+08:00 log cleared (gen=1)
|
||
[SYS] 2026-09-15T02:39:54.598+08:00 log truncated to 10MB (cap=20MB)
|
||
```
|
||
|
||
| 规则 | 说明 |
|
||
|---|---|
|
||
| 方向标记 | `[RX]` 串口收到 / `[TX]` 你发出 / `[SYS]` 工具事件(open/close/error/cleared/truncated) |
|
||
| 时间戳 | 本地 ISO8601 含毫秒与偏移;= **该行首字节到达时刻** |
|
||
| **只含完整行** | 残行留 daemon 内存,200ms 无后续数据才冲刷成行 → 你**永远读不到半行** |
|
||
| 解码回退 | UTF-8 → GBK → 都不行则该文本域写 `HEX:ab12…`(纯二进制流时整行转 hex) |
|
||
| TX 转义 | 发出的控制字符写成字面 `\r` `\n`(日志按行存储,真换行会把一行劈成两行) |
|
||
| flush | 每行即 flush——文件随时可读、内容即时落盘 |
|
||
|
||
### 4.3 体积上限与截头
|
||
|
||
- 单文件上限 **20MB**;超过后 daemon **原地截头**保留**尾部 10MB** 并写 `[SYS] … log truncated` 标记行。
|
||
- 截头不重开文件、不重开端口、不影响正在收的数据——但**文件头部的老内容会消失**。
|
||
- 因此:查旧数据要看**文件尾部**(`log --tail N` / `Get-Content -Tail`),别从文件头读。
|
||
- 嫌它涨得快/想立刻清空 → `clear`(代际 +1,比截头干净)。
|
||
|
||
## 5. 典型工作流
|
||
|
||
### 5.1 交互式调试(发命令看响应)
|
||
|
||
```powershell
|
||
... serial_tool.py open
|
||
... serial_tool.py send "AT+STATUS" --nl
|
||
... serial_tool.py log --tail 10 # 看响应(或直接 Read 日志文件)
|
||
# … 反复 send / log …
|
||
... serial_tool.py close
|
||
```
|
||
|
||
### 5.2 抓一次开机日志(手动版 @test)
|
||
|
||
```powershell
|
||
... serial_tool.py open --port COM6
|
||
... serial_tool.py clear # 代际 +1:此后内容只属于本轮
|
||
# ……此刻去烧录/复位板子(ST-Link 烧录不占 COM,串口全程保持打开)……
|
||
... serial_tool.py wait-idle --settle-ms 8000 --max-ms 30000
|
||
... serial_tool.py log --tail 0 # 取本轮全量 → 人眼/脚本检查标记
|
||
```
|
||
|
||
自动化版本 = `.dsh/skills/serial-boot-test/scripts/run_boot_test.py`(同一序列 + 烧录 + 标记校验,见 `自动化测试流程.md`)。
|
||
|
||
### 5.3 长时运行监控
|
||
|
||
```powershell
|
||
... serial_tool.py log --grep "ERROR" --tail 50 # 随时捞特定内容
|
||
... serial_tool.py status # 看 counters.errors / last_rx.age_ms
|
||
```
|
||
|
||
daemon 常驻,日志持续累积(20MB 自动截头),几天不关也没压力。
|
||
|
||
### 5.4 排障三件套
|
||
|
||
```powershell
|
||
... serial_tool.py status # ① state/error/counters 一眼看全
|
||
Get-Content '.dsh\skills\serial-assistant\scripts\state\daemon.log' -Tail 30 # ② daemon 自身输出
|
||
... serial_tool.py restart # ③ 重建 daemon(顺带加载新代码)
|
||
```
|
||
|
||
## 6. 配置
|
||
|
||
唯一配置源:`.serialtest/config.json`
|
||
|
||
```json
|
||
{
|
||
"portName": "COM6",
|
||
"portHint": "USB 串行设备",
|
||
"baudRate": 115200,
|
||
"httpPort": 18765,
|
||
"note": "……"
|
||
}
|
||
```
|
||
|
||
| 字段 | 用途 | 缺省 |
|
||
|---|---|---|
|
||
| `portName` | `open` 的默认端口;`ports` 的 `configured` 标注 | 无(必须给) |
|
||
| `baudRate` | 默认波特率 | 115200 |
|
||
| `httpPort` | daemon HTTP 端口(一般不动) | 18765 |
|
||
|
||
**换端口只改这个文件**(`@test` 与手动调试都读它)。`httpPort` 冲突时才需要改。
|
||
|
||
## 7. 故障排查
|
||
|
||
| 现象 | 原因 | 处理 |
|
||
|---|---|---|
|
||
| `port not found: COMx (available: …)` | 板子没接 / CH340 驱动没装 / 口号变了 | 对照 `available` 列表;装 CH340 驱动;改 `.serialtest/config.json` 的 `portName` |
|
||
| `port busy: COMx (held by another process)` | 别的程序占着口 | `Get-Process` 找占用者关掉;或 `… serial_tool.py close` 释放本工具占的口 |
|
||
| `daemon start timeout` / `daemon unreachable` | daemon 起不来(端口冲突/解释器问题) | 看 `state/daemon.log`;`… serial_tool.py restart`;确认 18765 未被占(改 `httpPort`) |
|
||
| `daemon did not answer within Ns (busy? raise --timeout)` | 命令耗时超过 `--timeout`——daemon 活着、只是还在等(典型:显式给 `wait-idle` 带了小 `--timeout`) | 调大 `--timeout`,或不显式给(`wait-idle` 按 `--max-ms` 自动推导)。2026-10-10 起这种情况**不再**顺手拉起第二个 daemon |
|
||
| `wait-idle` 返回 `no_data` | 全程无 RX | 核对 COM 号与波特率;板子供电;烧录是否成功;`status` 看 `port.ready` |
|
||
| 日志里出现 `HEX:…` 行 | 该段字节不是 UTF-8/GBK 文本(二进制流/乱码) | 正常回退行为,按 hex 对照协议解析 |
|
||
| `state: error` + `error: read: …` | 读串口出错/拔线 | daemon 仍活着;重插后 `open` 即恢复(自动 1.5s 退避) |
|
||
| 改了 `serial_tool.py` 行为没变 | 运行中的 daemon 还是旧代码 | `… serial_tool.py restart` |
|
||
| 开机日志"缺尾巴"(如缺 `Network Init`) | ① `--settle-ms` 太小,在 boot 自然静默间隙就收尾;② 首字节晚于 `--settle-ms` 到达,静默计时提前触发 | 用默认 8000(`run_boot_test.py` 已内置);2026-10-10 起首字节到达前不启动静默计时,必要时调 `--first-timeout-ms` |
|
||
| `open` 报 `no port specified … [config: …]` | `.serialtest/config.json` 缺失 / JSON 语法错 / `baudRate`·`httpPort` 非整数(现按 `utf-8-sig` 读并**显式回显**错误,不再静默回退成"没配端口") | 按 `config_error` 文本修文件;`status` 与 `ports` 也回显 `config_error` |
|
||
| 旧日志"丢了" | 20MB 截头丢的是**文件头** | 查旧内容要看尾部;重要轮次开始前先 `clear` 分代 |
|
||
|
||
## 8. 常见问题
|
||
|
||
- **daemon 会一直占着内存吗?** 一个 Python 进程约 20MB;不需要时 `stop` 即释放。常驻与否都不影响正确性。
|
||
- **daemon 被强杀(taskkill)会怎样?** 端口由系统自动释放;下次任何命令自动拉起新 daemon。**串口不会自动重开**,需要时再 `open`(这是设计:避免在设备异常时盲目重连)。
|
||
- **能同时开两个串口吗?** v1 单口(一个 daemon 管一个口)。多口需求见 `docs/测试说明/串口助手设计说明.md` §8 v2 候选。
|
||
- **能直接删 `serial.log` 吗?** 可以,但代际 `gen` 不会变、写句柄不变——建议用 `clear`(原子 + 代际 +1 + 标记行)。
|
||
- **为什么 TX 日志里是字面 `\r\n` 而不是真换行?** 日志按行存储;真换行会把一条 TX 劈成两行,转义后一条 TX 恒一行。
|
||
- **ST-Link 烧录会抢串口吗?** 不会(烧录走 SWD,不走 COM)——这正是"串口全程保持打开、烧录前后不重开"的设计基础,也彻底绕开了 CH340 释放/重开陷阱。
|
||
- **别的程序/Agent 能绕过 CLI 直接用吗?** 能——daemon 暴露本机 HTTP JSON 接口(§9)。
|
||
|
||
## 9. 附录:HTTP 协议(绕过 CLI)
|
||
|
||
daemon 在 `127.0.0.1:<httpPort>`(默认 18765)提供 JSON API,与 CLI 一一对应:
|
||
|
||
| 方法 路径 | 请求体(JSON,可空) | 说明 |
|
||
|---|---|---|
|
||
| `GET /ping` | — | `{"ok":true,"version":"1.0.0","pid":…}` |
|
||
| `GET /status` | — | 同 `status` 命令 |
|
||
| `GET /ports` | — | 同 `ports` 命令 |
|
||
| `POST /open` | `{"port":"COM6","baud":115200,"dtr":0,"rts":0}`(均可省) | 同 `open` |
|
||
| `POST /close` | — | 同 `close` |
|
||
| `POST /send` | `{"text":"hi","nl":true}` 或 `{"hex":"0D0A"}` | 同 `send` |
|
||
| `POST /clear` | — | 同 `clear` |
|
||
| `POST /wait-idle` | `{"settle_ms":8000,"max_ms":30000,"first_timeout_ms":12000}`(均可省) | **同步阻塞**至静默/首字节超时/整体超时才返回 |
|
||
| `POST /stop` | — | 关口后 daemon 退出(响应先于退出发出) |
|
||
|
||
响应码:`200` 成功 / `400` 领域错误(`ok:false`+`error`)/ `504` daemon 忙(命令 20s 未完成)/ `404` 未知端点。
|
||
|
||
PowerShell 示例:
|
||
|
||
```powershell
|
||
Invoke-RestMethod http://127.0.0.1:18765/status
|
||
Invoke-RestMethod -Method Post http://127.0.0.1:18765/send -Body '{"text":"ping"}'
|
||
```
|
||
|
||
## 变更记录
|
||
|
||
| 日期 | 变更 |
|
||
|---|---|
|
||
| 2026-09-15 | 初版:命令全参考(含实测输出)、日志规范、典型工作流、故障排查、FAQ、HTTP 附录;与 v1.1 实现(含 4 项 Windows 缺陷修复)对齐 |
|
||
| 2026-10-10 | 第一批可靠性修复同步:① `wait-idle` `no_data` 改按**本次增量**判(旧实现常驻 daemon 下永不触发)、加**首字节门** `--first-timeout-ms`、`rx_bytes` 改回本次增量;② `log` 改**先过滤后截尾**并加 `-i`/`--regex` + `scanned`/`matched` 计数(旧顺序即"log --grep 不可信"根因);③ `wait-idle` CLI 超时按 `--max-ms` 自动推导(不再需手工 `--timeout`),且超时不再被误判成"daemon 不可达"——旧实现会顺手拉起一个绑不上 HTTP 口的 daemon(`daemon.log` 里成串的 `listening`/`HTTP port busy` 即由此而来),现改为快速失败并提示调大 `--timeout`;④ 配置读取改 `utf-8-sig` 并显式回显 `config_error`;⑤ `status.daemon.exclusive_bind` 可验 HTTP 口独占绑定是否真生效 |
|
||
| 2026-10-10 | 第三批同步:① `ports` 加 `configured_present` + `hint`(换 USB 口/换机后 COM 号变了,系统里只有一个候选时直接给出口名;`open` 的 `port not found` 报错里也带 `[hint: ...]`);② `status` 加 `rx_age_ms`(判"板子是不是根本没在说话"不必自己减时间戳);③ `open` 幂等分支不再吞 `--dtr/--rts`——不带这俩参数时**保持当前 DTR/RTS**(旧实现把"没给"当 False,重开即静默拉低),显式给则现场应用并在 `note` 回显 `applied dtr=1` |
|