From 13a10cdf3369346f62c65be44e17d948591cc6c0 Mon Sep 17 00:00:00 2001 From: 11cookies11 Date: Sat, 7 Mar 2026 21:41:18 +0800 Subject: [PATCH 1/3] fix(dsl): register modbus protocol actions in runtime and qt runner English summary: - Register protocol actions in DSL runtime runner so modbus_read/modbus_write are available in non-v0.1 execution. - Register protocol actions in Qt script runner to keep desktop execution behavior consistent with runtime CLI. - Prevent real-device Modbus YAML scripts from failing with unknown action during action dispatch. ????? - ? DSL ??? runner ??????????? v0.1 ????? modbus_read/modbus_write? - ? Qt ?? runner ???????????????????? CLI ????? - ???? Modbus YAML ??????????????? --- dsl_runtime/engine/runner.py | 2 ++ ui/desktop/script_runner_qt.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dsl_runtime/engine/runner.py b/dsl_runtime/engine/runner.py index acc1d7d..8625e2a 100644 --- a/dsl_runtime/engine/runner.py +++ b/dsl_runtime/engine/runner.py @@ -6,6 +6,7 @@ from dsl_runtime.actions.dsl_chart_actions import register_chart_actions from dsl_runtime.actions.dsl_record_actions import register_record_actions from dsl_runtime.actions.dsl_data_actions import register_data_actions +from dsl_runtime.actions.dsl_protocol_actions import register_protocol_actions from dsl_runtime.lang.executor import StateMachineExecutor from dsl_runtime.lang.parser import parse_script from dsl_runtime.engine.channels import build_channels @@ -19,6 +20,7 @@ def _register_actions() -> None: register_chart_actions() register_record_actions() register_data_actions() + register_protocol_actions() def run_dsl(path: str, *, bus=None, external_events: list[str] | None = None) -> int: diff --git a/ui/desktop/script_runner_qt.py b/ui/desktop/script_runner_qt.py index 9f8d472..1da1b2e 100644 --- a/ui/desktop/script_runner_qt.py +++ b/ui/desktop/script_runner_qt.py @@ -11,6 +11,7 @@ from dsl_runtime.actions.dsl_builtin_actions import register_builtin_actions from dsl_runtime.actions.dsl_chart_actions import register_chart_actions from dsl_runtime.actions.dsl_data_actions import register_data_actions +from dsl_runtime.actions.dsl_protocol_actions import register_protocol_actions from dsl_runtime.actions.dsl_record_actions import register_record_actions from dsl_runtime.engine.channels import build_channels from dsl_runtime.engine.context import RuntimeContext @@ -123,6 +124,7 @@ def run(self) -> None: # pragma: no cover register_chart_actions() register_record_actions() register_data_actions() + register_protocol_actions() channels = {} ctx = None From 33389652d86efe8959912b3afbbdb7607e57b81d Mon Sep 17 00:00:00 2001 From: 11cookies11 Date: Sun, 8 Mar 2026 16:25:46 +0800 Subject: [PATCH 2/3] fix: avoid serial auto-reset by disabling DTR/RTS on open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit English summary: - Disable hardware flow-control toggles (rtscts/dsrdtr/xonxoff) for SerialChannel open. - Force DTR/RTS low after opening serial port to avoid auto-reset on ESP boards. - Keep behavior backward-compatible by guarding pin operations with try/except. 中文摘要: - SerialChannel 打开串口时关闭 rtscts/dsrdtr/xonxoff。 - 串口打开后将 DTR/RTS 置低,避免 ESP 板被自动复位。 - 通过 try/except 保持兼容,不影响不支持该操作的平台。 --- dsl_runtime/engine/channels.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dsl_runtime/engine/channels.py b/dsl_runtime/engine/channels.py index 75e7ab5..d91b849 100644 --- a/dsl_runtime/engine/channels.py +++ b/dsl_runtime/engine/channels.py @@ -63,7 +63,16 @@ def __init__(self, cfg: Dict[str, Any]) -> None: port=cfg["device"], baudrate=int(cfg.get("baudrate", 115200)), timeout=0, + rtscts=False, + dsrdtr=False, + xonxoff=False, ) + # Keep ESP boards from auto-resetting when the port is opened. + try: + self.ser.dtr = False + self.ser.rts = False + except Exception: + pass def write(self, data: bytes | str): payload = data.encode() if isinstance(data, str) else data From 83c1144222415b2b512bf65fadb045fa2a3c461b Mon Sep 17 00:00:00 2001 From: 11cookies11 Date: Sun, 8 Mar 2026 18:13:32 +0800 Subject: [PATCH 3/3] docs(docs): sync CN/EN user guides with current software behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [中文] - 变更内容: - 重写并同步中文/英文用户手册为教学型结构(安装启动、5 分钟上手、页面功能、DSL 入门、排障) - 校正文档中的功能状态与当前实现一致(协议包 UI 只读、Proxy Monitor 启用方式、推荐入口) - 更新 where 进度文件为本次手册同步任务完成状态 - 影响范围: - docs/USER_GUIDE.md - docs/USER_GUIDE_EN.md - .where-agent-progress.md - 兼容性/行为变化: - 仅文档更新,不修改运行时代码行为 - 依赖/环境: - 无新增依赖 [English] - Changes: - Rewrote and aligned CN/EN user guides into a learn-first structure (install, quick start, UI usage, DSL onboarding, troubleshooting). - Corrected documentation feature status to match current implementation (read-only protocol UI, proxy monitor enablement, recommended launch path). - Updated where progress file to reflect completion of this documentation sync task. - Impact: - docs/USER_GUIDE.md - docs/USER_GUIDE_EN.md - .where-agent-progress.md - Compatibility / Behavior Changes: - Documentation-only update; no runtime behavior changes. - Dependencies / Environment: - No new dependencies. --- .where-agent-progress.md | 31 +-- docs/USER_GUIDE.md | 516 +++++++++++++++-------------------- docs/USER_GUIDE_EN.md | 575 +++++++++++++++------------------------ 3 files changed, 435 insertions(+), 687 deletions(-) diff --git a/.where-agent-progress.md b/.where-agent-progress.md index daddc67..cf92b3a 100644 --- a/.where-agent-progress.md +++ b/.where-agent-progress.md @@ -1,26 +1,5 @@ -# Plan: YAML-DSL + 通讯包全量测试计划(全面覆盖) -- [x] 阶段 0:建立测试覆盖矩阵(DSL 功能点 × 协议包 × 场景类型 × 通过准则) -- [x] 阶段 0:统一测试目录与命名规范(cases/scenarios/reports) -- [x] 阶段 0:定义统一结果模型(PASS/FAIL、错误码、重试命中、耗时、日志链接) -- [x] 阶段 1:DSL 基础能力用例(session/send/expect/sleep/capture/assert)全覆盖 -- [x] 阶段 1:DSL 控制流用例(if/loop/retry/on_fail/switch_session)全覆盖 -- [x] 阶段 1:DSL 数据能力用例(parse json|kv|csv/path/measure/assert_range)全覆盖 -- [x] 阶段 1:DSL 安全能力用例(exec/file allowlist、拒绝路径、越权拦截)全覆盖 -- [x] 阶段 1:DSL 产物能力用例(raw_log/summary_json/report_csv)全覆盖 -- [x] 阶段 2:协议包 API 合规测试框架(send/recv/rpc 统一契约、入参校验、错误语义) -- [x] 阶段 2:AT 包测试(正常/ERROR/超时/多行回显/capture 兼容) -- [x] 阶段 2:SCPI 包测试(query/write/错误帧/csv 解析/超时) -- [x] 阶段 2:YMODEM 包测试(握手/分包/重传/EOT/失败中断) -- [x] 阶段 2:XMODEM 包测试(握手/块序/重传/结束) -- [x] 阶段 2:Modbus RTU 包测试(读写寄存器、异常码、CRC 错误) -- [x] 阶段 2:Modbus ASCII 包测试(LRC、帧边界、异常码) -- [x] 阶段 2:Modbus TCP 包测试(MBAP、并发请求、异常码) -- [x] 阶段 2:协议 vectors.yaml 全量回归(每包正常+异常+边界) -- [x] 阶段 3:靶机故障注入矩阵(超时/抖动/分片/丢包/断连/乱序)与 DSL 联动验证 -- [x] 阶段 3:多场景组合测试(升级 + 参数写入 + 版本校验 + 报告导出) -- [x] 阶段 3:长稳测试(循环运行、资源泄漏、错误恢复、重复执行一致性) -- [x] 阶段 3:性能基线(平均耗时、P95、重试成本、日志吞吐) -- [x] 阶段 4:一键总入口(full regression suite)整合 DSL + 协议包 + 靶机测试 -- [x] 阶段 4:CI 分层执行(PR 快速集、Nightly 全量集、周全稳集) -- [x] 阶段 4:发布门禁(全量通过率 100%、关键路径零回归、基线报告归档) -- [x] 阶段 4:测试文档冻结(测试矩阵、故障注入指南、排障手册、已知限制) +# Plan: ProtoFlow English User Guide Sync +- [x] Align structure with Chinese guide (learn-first flow) +- [x] Rewrite docs/USER_GUIDE_EN.md with current software behavior +- [x] Verify feature status/commands against implementation +- [x] Finalize delivery notes diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index bbe4919..fa62bec 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -1,322 +1,232 @@ -# ProtoFlow 用户使用说明书 +# ProtoFlow 用户手册(新版) + +本文档面向一线用户,目标是让你在最短时间内: +- 能启动 ProtoFlow 并完成基础通信调试 +- 能运行一份 DSL 自动化脚本 +- 能根据模板编写自己的脚本 +- 能定位常见错误 + +## 1. 软件定位 +ProtoFlow 是一个通信自动化工具,不只是“串口收发器”。 +它把通信流程拆成可执行步骤(DSL),用于: +- 串口 / TCP 调试 +- 协议包调用(AT / SCPI / YMODEM / Modbus 等) +- 自动化测试与产测流程 +- 过程日志与结果归档 + +## 2. 安装与启动 + +### 2.1 环境要求 +- Python 3.11+ +- Windows(当前仓库主要按 Windows 路径组织) +- 串口调试需要可用 COM 口 + +### 2.2 安装依赖 +```bash +pip install -r requirements.txt +``` -## 1. ProtoFlow 概述 -ProtoFlow 是面向嵌入式/工控/自动化测试的通信自动化运行时,采用 **YAML DSL + 状态机** 的声明式方式,将通信流程与协议动作解耦,帮助快速编排串口/TCP 交互、固件传输、Modbus 读写等任务。 -架构链路:`YAML DSL → 状态机 → 动作 (Actions) → 协议适配 → 通道 (UART/TCP)`。 +### 2.3 启动桌面版(推荐) +```bash +python main.py +``` -核心理念:流程(DSL)定义“做什么 & 顺序”,动作/协议适配层定义“怎么发/怎么收”,通道提供底层 IO。 +说明: +- `main.py` 会启动 Qt + Web 前端的完整 UI。 +- 运行日志默认写入 `%LOCALAPPDATA%/ProtoFlow/logs/`。 -## 2. 安装与运行 -- 依赖:`pip install pyyaml`,使用串口需 `pip install pyserial`。 -- 入口:`python app/dsl_main.py ` -- 输入:符合 DSL 规范的 YAML 脚本。 -- 输出:日志(INFO/DEBUG),状态机执行的事件流;动作可产生下行数据,通道可回传事件。 +## 3. 5 分钟上手(第一次使用) -## 3. YAML DSL 总览 -DSL 采用声明式状态机: -```yaml -version: 1 -vars: {...} # 初始变量 -channels: {...} # 通道定义 (uart/tcp) -state_machine: - initial: - states: - : - do: [...] # 动作列表 - on_event: {...} - timeout: - on_timeout: - when: - goto: - else_goto: -``` +1. 启动软件后进入 `Manual` 页面。 +2. 选择串口(Port)和波特率,点击连接。 +3. 在发送框输入 `AT`(文本模式,勾选 `+CR/+LF` 视设备要求),点击发送。 +4. 在右侧日志区确认收到 `OK` 或设备回包。 +5. 切到 `Scripts` 页面,加载示例脚本并运行。 -## 4. 通道(Channels)系统 -支持 UART 与 TCP。 -- UART 字段:`type: uart|serial`,`device: COMx 或 /dev/tty...`,`baudrate`(默认 115200) -- TCP 字段:`type: tcp`,`host`,`port`,`timeout`(秒,可选) +建议先用示例: +- `scripts/examples/at_command_flow_v01.yaml` +- `scripts/examples/scpi_flow_v01.yaml` -示例: -```yaml -channels: - boot: - type: uart - device: COM5 - baudrate: 115200 - plc: - type: tcp - host: 192.168.1.10 - port: 502 -``` +## 4. 界面功能说明 -## 5. 变量系统(vars) -- 定义:`vars:` 顶层对象,键值可为数字/字符串。 -- 作用域:全局,执行期可被 set 动作修改。 -- 访问:表达式中以 `$var` 或 `$obj.field` 引用。 -- 修改:`- set: { var_name: "" }`。 +### 4.1 Manual(手动调试) +适合联机调试和定位通信问题。 -## 6. 表达式系统(Expressions) -- 运算符:`+ - * / % **`,比较 `== != > >= < <=`,逻辑 `and/or/not`(也支持 `&& || !` 写法)。 -- 类型:数字、字符串、布尔、对象(属性/下标访问)。 -- 内置变量:`$now` 当前时间戳 ms,`$event` 最近事件,用户变量 `$block`、`$file.block_count` 等。 +主要能力: +- 串口连接 / 断开 +- 文本与 HEX 两种发送模式 +- 快捷指令管理(新增、编辑、删除、快速发送) +- IO 日志查看(ASCII/HEX 切换) +- 日志过滤、暂停、清空、导出 -示例: -```yaml -when: "$block <= file.block_count" -set: { retry: "$retry + 1" } -log: "progress=$block/$file.block_count at $now" -``` +常用操作建议: +- 命令行设备优先用文本模式 + `CR/LF`。 +- 二进制协议优先用 HEX 模式。 +- 先用 Manual 确认链路通,再跑 Scripts 自动化。 -## 7. 状态机 DSL(核心) -元素: -- `do`: 动作列表,按序执行。 -- `on_event`: 事件跳转映射。 -- `timeout` + `on_timeout`: 超时处理(ms)。 -- `when` + `goto` + `else_goto`: 条件跳转;若无 when 则直接 goto。 -- 状态结束到 `done` 视为流程完成。 - -执行流程:进入状态 → 执行 do → 条件/直接 goto → 等事件或等待超时 → 跳转 → 结束。 - -Mermaid 流程示例(XMODEM 核心流程): -```mermaid -stateDiagram-v2 - [*] --> wait_C - wait_C --> send_block: on C - wait_C --> fail: timeout - send_block --> next_block: on ACK - send_block --> send_block: on NAK - send_block --> fail: timeout - next_block --> send_block: when block<=file.block_count - next_block --> send_eot: else - send_eot --> done: on ACK - send_eot --> fail: timeout - fail --> done -``` +### 4.2 Scripts(脚本运行) +适合批量执行流程(发送、等待、断言、解析、记录)。 -## 8. 动作(Actions)系统 -- 调用:`- action: `,可带 `args: { ... }`。 -- 内置动作: - - `set`: 更新变量。 - - `log`: 输出日志。 - - `wait`: 毫秒休眠。 - - `wait_for_event`: 阻塞等待事件(可指定 `event`、`timeout`)。 - - `if`: 条件分支(`when`/`then`/`else` 内联动作块)。 - - `list_filter`: 列表过滤(`src`/`where`,可选 `dst`)。 - - `list_map`: 列表映射(`src`/`expr`,可选 `dst`,可选 `where`)。 -- 协议动作:XMODEM/Modbus 等(下文详述)。 -- 自定义动作:继承 `DslActionBase`,实现 `execute(ctx, args)` 并定义参数 `schema`,使用 `ActionRegistry.register("name", MyAction())` 注册。 - -## 9. XMODEM 动作 -- `send_xmodem_block`:发送指定块号(128B,自动 0x1A 填充),参数 `block: "$block"`。 -- `send_eot`:发送 EOT 结束。 -常见编排:等待 “C” → 发送块 → 等 ACK/NAK → 自增 block → 重复 → 发送 EOT。 - -## 10. YMODEM 动作 -当前示例主要提供 XMODEM;YMODEM 可类比扩展:发送 header、数据块、EOT(可参考 XMODEM 动作并新增 `send_ymodem_header` / `send_ymodem_block` / `send_ymodem_eot` 动作)。 - -## 11. Modbus(RTU/ASCII/TCP)动作 -- 预留动作:`modbus_read` / `modbus_write`(当前 DSL Runner 未实现,仅文档占位) - - 参数:`protocol: rtu|ascii|tcp`,`function`,`address`,`quantity`,`values`(写),`unit_id`。 -- 差异:RTU(CRC16,二进制);ASCII(LRC,文本帧);TCP(MBAP,无 CRC)。 -说明:仓库中已实现 Modbus 协议驱动(`infra/protocol/modbus_*.py`),可在 DSL 动作中调用(已注册 `modbus_read/modbus_write`)。 - -## 12. 事件系统(Events) -- 来源:通道 `read_event`(UART/TCP 读取到的字节,默认字符;无法解码则 HEX 字符串)。 -- 常见:XMODEM 场景 `"C"`、`"ACK"`、`"NAK"`(需设备回送对应字节)。 -- on_event:`on_event: { "C": send_block, ACK: next_block }`。 - -## 13. 完整示例 -### 13.1 XMODEM 升级 -```yaml -version: 1 -vars: - block: 1 - file_path: ./firmware.bin -channels: - boot: - type: uart - device: COM5 - baudrate: 115200 -state_machine: - initial: wait_C - states: - wait_C: - on_event: - "C": send_block - timeout: 5000 - on_timeout: fail - send_block: - do: - - action: send_xmodem_block - args: { block: "$block" } - on_event: - ACK: next_block - NAK: send_block - timeout: 2000 - on_timeout: fail - next_block: - do: - - set: { block: "$block + 1" } - when: "$block <= file.block_count" - goto: send_block - else_goto: send_eot - send_eot: - do: - - action: send_eot - on_event: - ACK: done - timeout: 2000 - on_timeout: fail - fail: - do: [ { log: "Failed" } ] - goto: done - done: - do: [ { log: "Completed" } ] -``` +主要能力: +- YAML 脚本加载/保存 +- 运行、停止 +- 运行日志查看 +- 变量快照查看 +- 执行进度显示 -### 13.2 YMODEM 示例(需自扩展动作) -```yaml -# 假设已注册 send_ymodem_header/send_ymodem_block/send_ymodem_eot -vars: { block: 1, file_path: ./file.bin } -state_machine: - initial: start - states: - start: - do: [ { action: send_ymodem_header } ] - on_event: { ACK: send_block } - send_block: - do: [ { action: send_ymodem_block, args: { block: "$block" } } ] - on_event: { ACK: inc_or_end, NAK: send_block } - inc_or_end: - do: [ { set: { block: "$block + 1" } } ] - when: "$block <= file.block_count" - goto: send_block - else_goto: send_eot - send_eot: - do: [ { action: send_ymodem_eot } ] - on_event: { ACK: done } - done: { do: [ { log: "OK" } ] } -``` +建议工作流: +1. 从 `scripts/examples/` 拷贝模板。 +2. 先改 `params`(端口、地址、文件路径)。 +3. 先跑通最小流程,再逐步加 `assert/parse/capture`。 -### 13.3 Modbus 轮询读写 -> 注:`modbus_read` / `modbus_write` 当前 DSL Runner 未实现,本段示例为文档预留模板。 -```yaml -vars: - retries: 0 -channels: - plc: - type: tcp - host: 192.168.1.10 - port: 502 -state_machine: - initial: read_regs - states: - read_regs: - do: - - action: modbus_read - args: - protocol: tcp - function: 3 - address: 4096 - quantity: 2 - unit_id: 1 - goto: write_regs - write_regs: - do: - - action: modbus_write - args: - protocol: tcp - function: 16 - address: 4098 - values: [1, 2] - unit_id: 1 - goto: done - done: - do: [ { log: "Modbus flow done" } ] -``` +### 4.3 Protocols(协议包) +用于查看当前可用的外置协议包(来自 `protocols/` 目录)。 + +当前行为: +- 可查看协议列表与元信息 +- UI 内协议包为只读(不能在 UI 内新增/编辑/删除) + +### 4.4 Proxy Monitor(透传监控,可选) +用于双串口透传与抓帧分析。 + +启用方式(二选一): +- 环境变量:`PROTOFLOW_ENABLE_PROXY_MONITOR=1` +- 配置文件:`config/app.yaml` 中 `app.proxy_monitor_enabled: true` + +未启用时,界面会隐藏/禁用相关能力。 + +### 4.5 Settings(设置) +可配置语言、主题、串口默认值、网络参数、工作目录等。 -### 13.4 组合示例(升级后写寄存器) -> 注:`modbus_read` / `modbus_write` 当前 DSL Runner 未实现,本段示例为文档预留模板。 +设置保存位置: +- `%LOCALAPPDATA%/ProtoFlow/config/ui_settings.json` + +## 5. DSL 脚本入门 + +## 5.1 推荐版本 +当前内置示例以 `version: "0.1"` 为主,建议新手优先使用 v0.1 示例模板快速上手。 + +## 5.2 最小可运行模板 ```yaml -vars: { block: 1, file_path: ./fw.bin } -channels: - boot: { type: uart, device: COM5, baudrate: 115200 } - plc: { type: tcp, host: 192.168.1.10, port: 502 } -state_machine: - initial: wait_C - states: - # 略,沿用 XMODEM 流程 - done: - do: - - action: modbus_write - args: { protocol: tcp, function: 6, address: 4100, values: [1], unit_id: 1 } - - log: "Upgrade + Modbus write finished" +version: "0.1" + +params: + port: "COM3" + baud: 115200 + +session: + transport: serial + port: "${port}" + baud: "${baud}" + data_bits: 8 + parity: none + stop_bits: 1 + encoding: ascii + eol: crlf + +defaults: + timeout_ms: 2000 + retry: + count: 1 + backoff_ms: 200 + strategy: fixed + +steps: + - id: ping + name: send + text: "AT" + + - id: wait_ok + name: expect + match: + type: contains + pattern: "OK" + + - id: done_assert + name: assert + expr: "${last_rx_text} != ''" + message: "no response" + +artifacts: + dir: "./runs/demo_${now}" + raw_log: true + summary_json: true + report_csv: false ``` -## 14. 错误处理与调试 -- 日志:INFO 记录状态进入/动作执行,DEBUG 记录事件。 -- 常见问题: - - YAML 结构错误:检查 `state_machine.initial` 是否存在于 `states`。 - - 表达式未定义变量:确保 `$var` 已在 vars 或 set 后存在。 - - 事件未匹配:确认设备回送字符与 on_event 匹配(大小写)。 -- 调试技巧: - - 提高日志等级为 DEBUG。 - - 在关键状态添加 `log` 输出变量/上下文。 - - 合理设置 `timeout`,避免过短导致误判。 - -## 15. 扩展指南 -- 添加新动作: - ```python - from dsl_runtime.actions.base import DslActionBase - from dsl_runtime.actions.registry import ActionRegistry - - class MyAction(DslActionBase): - def __init__(self) -> None: - super().__init__( - name="my_action", - schema={ - "required": ["foo"], - "optional": {"bar": 1}, - "types": {"foo": "string", "bar": "number"}, - "aliases": {"baz": "foo"}, - "allow_extra": False, - }, - ) - - def execute(self, ctx, args): - # ctx.channel_write / ctx.set_var / ctx.vars_snapshot() - ... - - ActionRegistry.register("my_action", MyAction()) - ``` -- 添加新协议动作:在 `dsl_runtime/actions/*.py` 中封装协议逻辑,调用协议封包构造器(如 XMODEM/Modbus)。 -- 添加新协议适配:实现协议封包/解析,供动作调用。 -- 扩展 DSL:修改 `dsl_runtime/lang/parser.py` / `dsl_runtime/lang/ast_nodes.py` / `dsl_runtime/lang/executor.py` 增加新语法字段,保持向后兼容。 -- 让 AI 编写 DSL:提供章节 7/8 模板,明确事件名、超时、变量命名,AI 可按样例生成 YAML。 - -## 16. 附录 -- 关键字:`version`, `vars`, `channels`, `state_machine`, `initial`, `states`, `do`, `on_event`, `timeout`, `on_timeout`, `when`, `goto`, `else_goto` -- 内置变量:`$now`,`$event`,用户变量(vars + set 生成);示例中 `file`、`file.block_count` 可由文件元信息动作填充。 -- 内置动作:`set`,`log`,`wait`,`wait_for_event`;曲线动作:`chart_add`,`chart_add3d`;schema 帧动作:`send_frame`,`expect_frame`;协议动作:`send_xmodem_block`,`send_eot`。 -- 说明:`meter_start/meter_add/meter_stop` 与 `modbus_read/modbus_write` 当前未在 DSL Runner 中实现(文档占位/预留字段)。 -- 表达式:算术/比较/逻辑,变量 `$var`/`$a.b`,内置 `$now/$event`。 -- 通道参数:UART `device`、`baudrate`;TCP `host`、`port`、`timeout`。 -- 简化 BNF(核心): -``` -script ::= "version"? "vars"? "channels" "state_machine" -state_machine ::= "initial" state_name "states" state_block+ -state_block ::= state_name ":" state_body -state_body ::= ("do": action_list)? ("on_event": event_map)? - ("timeout": int)? ("on_timeout": state_name)? - ("when": expr)? ("goto": state_name)? - ("else_goto": state_name)? -action_list ::= "-" action_entry+ -action_entry ::= {"action": name, "args": obj} | - {"set": obj} | {"log": str} | - {"wait": int|obj} | {"wait_for_event": obj} -expr ::= 参见表达式系统,支持 $var 引用 +## 5.3 常用 Step(按使用频率) +- `send`: 发送文本/HEX +- `expect`: 等待并匹配响应(contains/regex/startswith) +- `sleep`: 延时 +- `capture`: 正则提取到变量 +- `assert`: 条件断言 +- `if` / `loop`: 控制流 +- `parse` / `path`: 结构化解析与字段提取 +- `measure` / `assert_range`: 指标记录与范围校验 +- `protocol.rpc` / `protocol.send` / `protocol.recv`: 调用外置协议包 +- `switch_session`: 切换会话参数 +- `exec` / `file`: 受控执行(受 security 白名单限制) + +## 5.4 协议调用示例(AT) +```yaml +- id: at_ping + name: protocol.rpc + protocol: at_command + request: + cmd: "AT" + eol: "crlf" + expect: + status: "ok" + save_as: at_result + +- id: assert_at + name: assert + expr: "${at_result.ok}" + message: "AT command failed" ``` ---- - -本说明书面向嵌入式开发/工控通讯/自动化测试工程师及可编程 Agent,覆盖 DSL、状态机、动作系统、协议适配与扩展方法,可直接作为开源文档发布。*** +## 6. 产物与日志 +脚本运行后可输出到 `artifacts.dir`: +- `raw_log.jsonl`: 过程明细 +- `summary.json`: 结果汇总、错误码、变量快照 +- `report.csv`: 可选报表 + +桌面运行日志: +- `%LOCALAPPDATA%/ProtoFlow/logs/web_ui_*.log` + +## 7. 常见问题排查 + +### 7.1 连接失败 +- 检查端口是否被其他工具占用 +- 检查波特率/校验位/停止位是否与设备一致 +- 先在 Manual 页面验证收发,再执行脚本 + +### 7.2 expect 超时 +- 增大 `timeout_ms` +- 校验 `match.pattern` 是否正确 +- 检查设备是否需要 `CR/LF` + +### 7.3 变量为空导致断言失败 +- 确认 `capture` 的正则组号和文本来源 +- 先在日志中观察 `last_rx_text` + +### 7.4 exec/file 被拒绝 +- 在 `security` 中开启并配置白名单 +- 错误码常见为 `EXEC_NOT_ALLOWED` 或 `FILE_NOT_ALLOWED` + +### 7.5 代理监控不可见 +- 检查是否启用 `proxy_monitor_enabled` +- 重启应用后再查看 + +## 8. 用户最佳实践 +- 先手工、后自动:先在 Manual 确认设备链路,再迁移到 Scripts。 +- 小步迭代:每次只加 1~2 个 step,随时运行验证。 +- 先断言关键路径:对握手、关键响应、结果字段尽早 `assert`。 +- 固化模板:把稳定流程沉淀到 `scripts/examples/` 或团队模板库。 + +## 9. 相关文档 +- 项目概览:`README.md` +- 英文用户手册:`docs/USER_GUIDE_EN.md` +- v0.1 快速参考:`docs/YAML_DSL_V01_QUICKSTART.md` +- v0.2 规范与迁移:`docs/YAML_DSL_V02_SCHEMA_SPEC.md`、`docs/YAML_DSL_V02_MIGRATION_AND_BEST_PRACTICES.md` +- 协议包开发指南:`docs/PROTOCOL_PACKAGE_DEVELOPER_GUIDE.zh-CN.md` diff --git a/docs/USER_GUIDE_EN.md b/docs/USER_GUIDE_EN.md index f051e7d..dc8b8b2 100644 --- a/docs/USER_GUIDE_EN.md +++ b/docs/USER_GUIDE_EN.md @@ -1,375 +1,234 @@ -# ProtoFlow User Guide +# ProtoFlow User Guide (Updated) + +This guide is designed to help users quickly learn and use ProtoFlow in real work. +By the end, you should be able to: +- start ProtoFlow and complete basic communication debugging +- run a DSL automation script +- write your own script from templates +- troubleshoot common errors + +## 1. What ProtoFlow Is +ProtoFlow is a communication automation tool, not just a serial terminal. +It models communication as executable workflow steps (DSL), and is suitable for: +- serial / TCP debugging +- protocol-package calls (AT / SCPI / YMODEM / Modbus, etc.) +- automation and production test flows +- structured logging and run artifacts + +## 2. Install and Launch + +### 2.1 Requirements +- Python 3.11+ +- Windows (the current repository and scripts are primarily Windows-oriented) +- available COM ports if you use serial + +### 2.2 Install dependencies +```bash +pip install -r requirements.txt +``` -## 1. Overview -ProtoFlow is a communication automation runtime for embedded/industrial/automation testing. It uses a **YAML DSL + state machine** to define flows declaratively, decoupling communication steps from protocol actions so you can script UART/TCP exchanges, firmware transfers, Modbus operations, and custom protocols quickly. -Pipeline: `YAML DSL → state machine → actions → protocol adapter → channel (UART/TCP)`. +### 2.3 Launch desktop app (recommended) +```bash +python main.py +``` -## 2. Installation & Run -- Dependencies: `pip install pyyaml`; for serial use `pip install pyserial`. -- Entry point: `python app/dsl_main.py ` -- Input: YAML script that follows the DSL spec. -- Output: logs (INFO/DEBUG), state-machine event trace; actions can emit outbound data, channels can raise events. +Notes: +- `main.py` starts the full Qt + Web frontend desktop UI. +- Runtime logs are written to `%LOCALAPPDATA%/ProtoFlow/logs/`. -## 3. YAML DSL at a Glance -Declarative state machine: -```yaml -version: 1 -vars: {...} # initial variables -channels: {...} # channel definitions (uart/tcp) -state_machine: - initial: - states: - : - do: [...] # actions - on_event: {...} - timeout: - on_timeout: - when: - goto: - else_goto: -``` +## 3. 5-Minute Quick Start (First Run) -## 4. Channels (UART/TCP) -- UART fields: `type: uart|serial`, `device: COMx or /dev/tty...`, `baudrate` (default 115200) -- TCP fields: `type: tcp`, `host`, `port`, `timeout` (seconds, optional) -Example: -```yaml -channels: - boot: - type: uart - device: COM5 - baudrate: 115200 - plc: - type: tcp - host: 192.168.1.10 - port: 502 -``` +1. Launch the app and open the `Manual` page. +2. Select a serial port and baud rate, then connect. +3. Send `AT` (Text mode; enable `+CR/+LF` if required by your device). +4. Confirm you receive `OK` or device response in logs. +5. Switch to `Scripts`, load an example script, and run it. -## 5. Variable System (`vars`) -- Define: top-level `vars:` object; values can be numbers or strings. -- Scope: global; can be updated by `set` actions. -- Access: expressions use `$var` or `$obj.field`. -- Update: `- set: { var_name: "" }` - -## 6. Expression System -- Operators: `+ - * / % **`, comparisons `== != > >= < <=`, logic `and/or/not` (also `&& || !`). -- Types: number, string, boolean, object (field/index access). -- Built-ins: `$now` (ms), `$event` (last event), user vars (`$block`, `$file.block_count`, etc.). -Example: -```yaml -when: "$block <= file.block_count" -set: { retry: "$retry + 1" } -log: "progress=$block/$file.block_count at $now" -``` +Recommended examples: +- `scripts/examples/at_command_flow_v01.yaml` +- `scripts/examples/scpi_flow_v01.yaml` -## 7. State Machine (core) -Elements: -- `do`: action list executed sequentially. -- `on_event`: event→state mapping. -- `timeout` + `on_timeout`: timeout handling (ms). -- `when` + `goto` + `else_goto`: conditional transition; without `when` it jumps directly. -- Terminal: reaching state `done` is considered completion. -Execution: enter state → run `do` → conditional/direct goto → wait for event or timeout → transition → finish. -Mermaid example (XMODEM core): -```mermaid -stateDiagram-v2 - [*] --> wait_C - wait_C --> send_block: on C - wait_C --> fail: timeout - send_block --> next_block: on ACK - send_block --> send_block: on NAK - send_block --> fail: timeout - next_block --> send_block: when block<=file.block_count - next_block --> send_eot: else - send_eot --> done: on ACK - send_eot --> fail: timeout - fail --> done -``` +## 4. UI Usage Guide -## 8. Actions System -- Call: `- action: ` with optional `args: { ... }`. -- Built-ins: - - `set`: update variable. - - `log`: print log. - - `wait`: sleep in ms. - - `wait_for_event`: blocking wait (supports `event`, `timeout`). - - `if`: conditional inline action block (`when`, `then`, `else`). - - `list_filter`: filter a list into a new list (`src`, `where`, optional `dst`). - - `list_map`: map a list into a new list (`src`, `expr`, optional `dst`, optional `where`). -- Protocol actions: XMODEM/Modbus etc. (see below). -- Custom actions: subclass `DslActionBase`, implement `execute(ctx, args)` with a parameter `schema`, then register the instance via `ActionRegistry.register("name", MyAction())`. - -### 8.2 Data Processing (filter/transform) -`if` (recommended to reduce extra states when you only need to filter/branch inside `do`): -```yaml -do: - - if: - when: "$event_name == 'ui.param.apply' and $event_payload.enabled" - then: - - set: { threshold: "$event_payload.threshold" } - - log: "threshold applied: $threshold" - else: - - log: "ignored" -``` +### 4.1 Manual +Best for live communication debugging. -`list_filter` / `list_map` evaluate expressions per item. You can use `$item`, `$index`, and for dict items also `$item.` (identifier keys only). -```yaml -do: - - set: { samples: [1, 2, 3, 4, 5] } - - action: list_filter - args: { src: "$samples", where: "$item % 2 == 1", dst: odd } - - action: list_map - args: { src: "$odd", expr: "$item * 10", dst: scaled } - - log: "scaled=$scaled" -``` +Main capabilities: +- connect / disconnect serial +- send in Text or HEX mode +- quick command management (create/edit/delete/send) +- IO log view (ASCII/HEX) +- log filtering, pause, clear, export -### 8.1 Schema Frame Actions (custom frames + registered actions) -1) Define protocol frame schema (example): - ```yaml - frames: - req_read: - header: AA55 - tail: 0D0A - crc: crc16_modbus - fields: - - { name: addr, type: u16, endian: little } - - { name: length, type: u16, endian: little } - rsp_read: - header: AA55 - tail: 0D0A - crc: crc16_modbus - fields: - - { name: status, type: u8 } - - { name: data, type: bytes, length: 16 } - ``` -2) Use in DSL (actions are auto-registered at runner/UI startup): - ```yaml - - action: send_frame - args: - schema: ./proto_schema.yaml - frame: req_read - values: { addr: 0x1234, length: 16 } - - action: expect_frame - args: - schema: ./proto_schema.yaml - frame: rsp_read - timeout: 2 - save_as: rsp - ``` - - `send_frame`: builds packet per schema, writes to channel, stores `last_frame_tx` (hex + values). - - `expect_frame`: reads by tail or fixed length, parses, stores result in `save_as` (default `last_frame_rx`), raw hex in `last_frame_rx_raw`. -3) Register more custom actions (also applied at startup): - ```python - from dsl_runtime.actions.base import DslActionBase - from dsl_runtime.actions.registry import ActionRegistry - - class MyAction(DslActionBase): - def __init__(self) -> None: - super().__init__(name="my_action", schema={"allow_extra": False}) - - def execute(self, ctx, args): - # e.g., write custom bytes or combine multiple steps - ctx.channel_write(b"hello") - - ActionRegistry.register("my_action", MyAction()) - ``` - Then call in DSL: `- action: my_action`. - -## 9. XMODEM Actions -- `send_xmodem_block`: send specified block (128B, padded with 0x1A), arg `block: "$block"`. -- `send_eot`: send EOT to finish. -Typical flow: wait for "C" → send block → wait ACK/NAK → increment block → repeat → send EOT. - -## 10. YMODEM Actions -Currently examples are XMODEM-focused; YMODEM can be added similarly with actions like `send_ymodem_header` / `send_ymodem_block` / `send_ymodem_eot`. - -## 11. Modbus (RTU/ASCII/TCP) Actions -- Reserved actions: `modbus_read` / `modbus_write` (not implemented in current DSL runner; docs placeholder) - - Args: `protocol: rtu|ascii|tcp`, `function`, `address`, `quantity`, `values` (for write), `unit_id`. -- Differences: RTU (CRC16, binary); ASCII (LRC, text frame); TCP (MBAP, no CRC). -- Note: Modbus protocol drivers exist under `infra/protocol/modbus_*.py` and are available via DSL actions (`modbus_read/modbus_write`). - -## 12. Event System -- Sources: channel `read_event` (UART/TCP bytes; default decoded to text, fallback HEX string). -- Common: XMODEM events `"C"`, `"ACK"`, `"NAK"` (device must emit matching bytes). -- `on_event`: e.g. `on_event: { "C": send_block, ACK: next_block }`. - -## 13. Full Examples -### 13.1 XMODEM Upgrade -```yaml -version: 1 -vars: - block: 1 - file_path: ./firmware.bin -channels: - boot: - type: uart - device: COM5 - baudrate: 115200 -state_machine: - initial: wait_C - states: - wait_C: - on_event: - "C": send_block - timeout: 5000 - on_timeout: fail - send_block: - do: - - action: send_xmodem_block - args: { block: "$block" } - on_event: - ACK: next_block - NAK: send_block - timeout: 2000 - on_timeout: fail - next_block: - do: - - set: { block: "$block + 1" } - when: "$block <= file.block_count" - goto: send_block - else_goto: send_eot - send_eot: - do: - - action: send_eot - on_event: - ACK: done - timeout: 2000 - on_timeout: fail - fail: - do: [ { log: "Failed" } ] - goto: done - done: - do: [ { log: "Completed" } ] -``` +Practical tips: +- For command-based devices, start with Text mode + `CR/LF`. +- For binary protocols, use HEX mode. +- Always verify link and response in Manual before running automation scripts. -### 13.2 YMODEM (requires custom actions) -```yaml -# assume send_ymodem_header/send_ymodem_block/send_ymodem_eot are registered -vars: { block: 1, file_path: ./file.bin } -state_machine: - initial: start - states: - start: - do: [ { action: send_ymodem_header } ] - on_event: { ACK: send_block } - send_block: - do: [ { action: send_ymodem_block, args: { block: "$block" } } ] - on_event: { ACK: inc_or_end, NAK: send_block } - inc_or_end: - do: [ { set: { block: "$block + 1" } } ] - when: "$block <= file.block_count" - goto: send_block - else_goto: send_eot - send_eot: - do: [ { action: send_ymodem_eot } ] - on_event: { ACK: done } - done: { do: [ { log: "OK" } ] } -``` +### 4.2 Scripts +Best for repeatable automation flows (send, wait, assert, parse, record). -### 13.3 Modbus Poll & Write -> Note: `modbus_read` / `modbus_write` are not implemented in the current DSL runner; this is a placeholder example. -```yaml -vars: - retries: 0 -channels: - plc: - type: tcp - host: 192.168.1.10 - port: 502 -state_machine: - initial: read_regs - states: - read_regs: - do: - - action: modbus_read - args: - protocol: tcp - function: 3 - address: 4096 - quantity: 2 - unit_id: 1 - goto: write_regs - write_regs: - do: - - action: modbus_write - args: - protocol: tcp - function: 16 - address: 4098 - values: [1, 2] - unit_id: 1 - goto: done - done: - do: [ { log: "Modbus flow done" } ] -``` +Main capabilities: +- load/save YAML scripts +- run/stop +- runtime logs +- variable snapshot view +- execution progress + +Recommended workflow: +1. Copy a template from `scripts/examples/`. +2. Modify `params` first (port/address/file path). +3. Get a minimal flow running, then add `assert/parse/capture` step by step. + +### 4.3 Protocols +Shows available external protocol packages from the `protocols/` directory. + +Current behavior: +- list/view protocol package metadata +- UI protocol management is read-only (no create/edit/delete in UI) + +### 4.4 Proxy Monitor (Optional) +For dual-serial forwarding and frame capture analysis. + +Enable it by either: +- environment variable: `PROTOFLOW_ENABLE_PROXY_MONITOR=1` +- config: `config/app.yaml` with `app.proxy_monitor_enabled: true` -### 13.4 Combined (upgrade then write register) -> Note: `modbus_read` / `modbus_write` are not implemented in the current DSL runner; this is a placeholder example. +If not enabled, related UI features are hidden/disabled. + +### 4.5 Settings +Configure language, theme, serial defaults, network options, and workspace path. + +Settings file: +- `%LOCALAPPDATA%/ProtoFlow/config/ui_settings.json` + +## 5. DSL Getting Started + +## 5.1 Recommended version for new users +Most built-in runnable examples currently use `version: "0.1"`. +For onboarding, start from v0.1 templates first. + +## 5.2 Minimal runnable template ```yaml -vars: { block: 1, file_path: ./fw.bin } -channels: - boot: { type: uart, device: COM5, baudrate: 115200 } - plc: { type: tcp, host: 192.168.1.10, port: 502 } -state_machine: - initial: wait_C - states: - # reuse XMODEM flow (omitted for brevity) - done: - do: - - action: modbus_write - args: { protocol: tcp, function: 6, address: 4100, values: [1], unit_id: 1 } - - log: "Upgrade + Modbus write finished" +version: "0.1" + +params: + port: "COM3" + baud: 115200 + +session: + transport: serial + port: "${port}" + baud: "${baud}" + data_bits: 8 + parity: none + stop_bits: 1 + encoding: ascii + eol: crlf + +defaults: + timeout_ms: 2000 + retry: + count: 1 + backoff_ms: 200 + strategy: fixed + +steps: + - id: ping + name: send + text: "AT" + + - id: wait_ok + name: expect + match: + type: contains + pattern: "OK" + + - id: done_assert + name: assert + expr: "${last_rx_text} != ''" + message: "no response" + +artifacts: + dir: "./runs/demo_${now}" + raw_log: true + summary_json: true + report_csv: false ``` -## 14. Troubleshooting & Tuning -- Logs: INFO for state entry/action execution; DEBUG for events. -- Common issues: - - YAML structure: ensure `state_machine.initial` exists in `states`. - - Undefined variables: ensure `$var` exists in `vars` or set before use. - - Event mismatch: device must emit exact bytes that map to `on_event` keys (case-sensitive). -- Tips: - - Raise log level to DEBUG while debugging. - - Add `log` in key states to print variables/context. - - Set reasonable `timeout` values to avoid false timeouts. - -## 15. Extension Guide -- Add new action: - ```python - from dsl_runtime.actions.registry import ActionRegistry - def my_action(ctx, args): - # ctx.channel_write / ctx.set_var / ctx.vars_snapshot() - ... - ActionRegistry.register("my_action", MyAction()) - ``` -- Add new protocol actions: encapsulate protocol logic in `dsl_runtime/actions/*.py`, call protocol pack/unpack helpers (e.g., XMODEM/Modbus). -- Add new protocol adapter: implement packet build/parse for actions to call. -- Extend DSL: edit `dsl_runtime/lang/parser.py` / `dsl_runtime/lang/ast_nodes.py` / `dsl_runtime/lang/executor.py` to add syntax (keep backward compatibility). -- Let an AI draft DSL: provide templates from sections 7/8 with event names, timeouts, variable names; an AI can generate YAML by example. - -## 16. Appendix -- Keywords: `version`, `vars`, `channels`, `state_machine`, `initial`, `states`, `do`, `on_event`, `timeout`, `on_timeout`, `when`, `goto`, `else_goto` -- Built-in vars: `$now`, `$event`, user vars (vars + set); examples include `file`, `file.block_count`. -- Built-in actions: `set`, `log`, `wait`, `wait_for_event`; chart actions: `chart_add`, `chart_add3d`; schema actions: `send_frame`, `expect_frame`; protocol actions: `send_xmodem_block`, `send_eot`. -- Note: `meter_start/meter_add/meter_stop` and `modbus_read/modbus_write` are not implemented in the current DSL runner (docs placeholders). -- Expressions: arithmetic/comparison/logic; vars `$var`/`$a.b`; built-ins `$now/$event`. -- Channel params: UART `device`, `baudrate`; TCP `host`, `port`, `timeout`. -- Core BNF (simplified): -``` -script ::= "version"? "vars"? "channels" "state_machine" -state_machine ::= "initial" state_name "states" state_block+ -state_block ::= state_name ":" state_body -state_body ::= ("do": action_list)? ("on_event": event_map)? - ("timeout": int)? ("on_timeout": state_name)? - ("when": expr)? ("goto": state_name)? - ("else_goto": state_name)? -action_list ::= "-" action_entry+ -action_entry ::= {"action": name, "args": obj} | - {"set": obj} | {"log": str} | - {"wait": int|obj} | {"wait_for_event": obj} -expr ::= see expression system, supports $var references +## 5.3 Common steps (high-frequency) +- `send`: send text/hex payload +- `expect`: wait and match response (contains/regex/startswith) +- `sleep`: delay +- `capture`: regex extraction to variable +- `assert`: condition assertion +- `if` / `loop`: control flow +- `parse` / `path`: structured parsing and field extraction +- `measure` / `assert_range`: metric record and range check +- `protocol.rpc` / `protocol.send` / `protocol.recv`: call external protocol packages +- `switch_session`: switch runtime session settings +- `exec` / `file`: controlled execution (guarded by security allowlists) + +## 5.4 Protocol call example (AT) +```yaml +- id: at_ping + name: protocol.rpc + protocol: at_command + request: + cmd: "AT" + eol: "crlf" + expect: + status: "ok" + save_as: at_result + +- id: assert_at + name: assert + expr: "${at_result.ok}" + message: "AT command failed" ``` ---- - -This guide targets embedded/industrial communication & automation engineers (and programmable agents). It covers the DSL, state machine, action system, protocol adapters, and extension methods for rapid scripting and customization. +## 6. Artifacts and Logs +Script run artifacts under `artifacts.dir` may include: +- `raw_log.jsonl`: step-by-step runtime details +- `summary.json`: overall result, error code, variable snapshot +- `report.csv`: optional report export + +Desktop runtime logs: +- `%LOCALAPPDATA%/ProtoFlow/logs/web_ui_*.log` + +## 7. Troubleshooting + +### 7.1 Connection failed +- check if the serial port is already occupied +- verify baud/parity/stop bits +- validate IO in Manual first, then run scripts + +### 7.2 expect timeout +- increase `timeout_ms` +- verify `match.pattern` +- check if target requires `CR/LF` + +### 7.3 Empty variable causes assert failure +- verify `capture` regex and group index +- inspect `last_rx_text` in logs + +### 7.4 exec/file rejected +- enable and configure allowlists in `security` +- typical codes: `EXEC_NOT_ALLOWED`, `FILE_NOT_ALLOWED` + +### 7.5 Proxy Monitor not visible +- verify `proxy_monitor_enabled` is enabled +- restart the app + +## 8. Best Practices +- manual first, automation second: verify link in Manual before Scripts +- iterate in small steps: add 1-2 steps each change and run immediately +- assert critical path early: handshake, key responses, output fields +- solidify reusable templates under `scripts/examples/` or your team template repo + +## 9. Related Docs +- project overview: `README.md` +- Chinese user guide: `docs/USER_GUIDE.md` +- v0.1 quick reference: `docs/YAML_DSL_V01_QUICKSTART.md` +- v0.2 spec/migration: `docs/YAML_DSL_V02_SCHEMA_SPEC.md`, `docs/YAML_DSL_V02_MIGRATION_AND_BEST_PRACTICES.md` +- protocol package developer guide: `docs/PROTOCOL_PACKAGE_DEVELOPER_GUIDE.zh-CN.md`