Files
cbb a56b702d83 feat!: Python 后端整体切换为原生 C/SOEM 守护进程(ecat_native)
big-bang 迁移(硬约束: Npcap 网卡独占, 无法双主站并存), 四阶段真机验收的
完整契约与对拍记录见 MIGRATION.md —— Python 已删, 该文件是唯一行为基准。

- 新增 ecat_native.c: 与 Python 同构的全路由 native 守护 —— 总线生命周期
  open/close/status/op.start/op.stop, 电机 motor.start/stop/spin/state/
  send/rx/period/dbg, can/send|state, 配置维护 sdo/eeprom.read|write|
  verify/flash/sync_diag, 静态托管 src/web, shutdown/focus/--parent-pid
  看门狗/独立启动清场/端口漂移; 独占 8090 即生产链路。PDO 热循环天花板
  ~5kHz → ~7kHz。
- 删除 src/ecat_server.py(2826 行)、src/test_motor_backend.py(684 行)、
  ecat_app.vbs(桌面窗口随 pywebview 依赖一并移除): Python 后端不留副本。
- 编码回归改金标准: native_enc_diff.py 对照 native_enc_golden.json
  (阶段 2 与 Python _fill_can_out 逐字节对拍通过后固化, 不碰网卡),
  当场抓掉 json_tok 不跳闭合引号会静默丢 motor/send 参数的真 bug。
- build_native.bat: 编译前跑 gen_eeprom.py 生成 eeprom_image.h 供 native
  #include —— 同一生成器同一套断言, 断言失败构建中止; 改 SII 重跑即可。
- 修 flash 探针字历史隐患(本文件与 ecat_native.c 同步改): SCRATCH_WORD
  0x0200 实际落在 TxPDO 类别区内部(类别区已长到 0x0281), 单独跑 eeprom
  探针不烧录会把真数据擦成空洞; 移到 SII END 之后的 0x0400。
- 启动器 ecat_web.vbs/bat 改拉 build_native\ecat_native.exe
  (--substr I226 --web src\web)。
- 收录 soem-src wpcap 链接库(vendored, 构建必需)。

两轮回归修复(细节见 MIGRATION.md):
1) op/start 卡 AL 0x001B(SM 看门狗): 固件"自己写 1s 看门狗"的假设破产,
   do_op_start 第 5 步改为 ~5ms 节奏喂帧 ≥1s 再请求 OP, 24s 两次失败
   变 1.2s 进 OP。
2) OP 态数据冻结(从站 PDI_Isr SM2 分支被旗标挡住, 固件侧根因): 主站加
   楔死看门狗(输出窗口轮转 + 回显冻结 128 周期判死)与 /api/motor/state
   自动恢复(10s 冷却, 快照新增 wr 字段)。

已知差异: SDO 失败文本无 pysoem abort code 粒度; 250µs 亚毫秒周期从站
吃不下, 修复前勿用。build_native/ 构建产物入 .gitignore, 由脚本重建。
2026-09-05 16:01:15 +08:00

91 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# dcu-ecat-master
**DCU LAN9252 EtherCAT 主站工具集**(工作目录 `DCU/tools/ecat`)
**生产后端是原生 C/SOEM 守护进程** `build_native/ecat_native.exe`(`ecat_native.c` +
`build_native.bat` 编译,见 `MIGRATION.md` 的迁移记录):同一套 REST 契约、同一批
前端页面,PDO 热循环天花板从 Python 的 ~5kHz 提到 ~7kHz。Python 版后端已彻底删除
(2026-09-04,含备份);编码面回归改打金标准
`native_enc_golden.json`(`native_enc_diff.py`)。命令行工具 `ecat_tool.py`
仍是 Python + pysoem(低频诊断用,不与时序敏感的热循环抢网卡)。
在 Windows 上直接从网卡驱动 DCU 的 LAN9252 EtherCAT 从站:
扫描总线、读写 SII EEPROM、CoE SDO 读写、PDO 循环收发,以及一个本地网页/桌面控制台。
## 环境准备
- Python 3.12(venv 不入库;命令行工具与 legacy 后端用)
- [Npcap](https://npcap.com/):收发裸 EtherCAT 帧的前提(native 与 pysoem 共用)
- VS2022(Community 即可):编译 `build_native.bat` 产出原生守护进程
- 一块直连从站的物理网卡(示例中为 Intel I226)
```bat
py -3.12 -m venv venv
venv\Scripts\python.exe -m pip install -r requirements.txt
```
## 目录结构
入口在最外层,双击即用;代码全部收进 `src/`。
```
ecat/
├─ ecat_web.vbs ← 浏览器标签(启动 native 守护进程, 隐藏控制台)
├─ ecat_web.bat ← 控制台模式(看日志)
├─ ecat.bat ← 命令行工具
├─ run_scan.bat ← bring-up 扫描
├─ ecat_native.c ← 原生守护进程(生产后端, 全路由)
├─ build_native.bat ← 编译 native(先跑 gen_eeprom.py 生成 SII 默认镜像头)
├─ soem-src/ ← vendored SOEM(从 pysoem sdist 解出, 有一处补丁)
├─ MIGRATION.md ← Python→native 迁移记录(契约/验收/已知差异)
├─ native_enc_diff.py ← 编码回归: native enctest vs 金标准(不碰网卡)
├─ native_enc_golden.json ← 金标准(阶段 2 与 Python 逐字节对拍通过后固化)
├─ README.md / requirements.txt
├─ build_native/ ← ecat_native.exe + eeprom_image.h 等构建产物
├─ src/
│ ├─ ecat_tool.py 一体化命令行主站
│ ├─ ecat_flash_eeprom.py 经网线烧写 SII 镜像(被 ecat_tool flash 复用)
│ ├─ web/ 前端资源(URL 路径不变, 仍是 / 与 /motor.html; native 也托管这里)
│ └─ diag/ 独立诊断脚本(互不依赖, 直接单跑)
└─ venv/ 本地虚拟环境(不入库; CLI 与构建期 gen_eeprom 用)
```
| 文件 | 说明 |
|------|------|
| `src/ecat_tool.py` | 一体化命令行主站:`adapters` / `status` / `flash` / `eeprom` / `sdo` / `send` 等子命令 |
| `ecat_native.c` + `build_native.bat` | **生产后端**:原生 C/SOEM 守护进程(全路由 + 生命周期契约),默认端口 **8090**(8080 已被 ESP32 tools 占用)。迁移记录见 `MIGRATION.md` |
| `src/ecat_flash_eeprom.py` | 通过网线烧写 `gen_eeprom.py` 生成的 SII 镜像,逐字回读校验(烧完需断电重启让 ESC 重新加载)。被 `ecat_tool.py flash` 复用 |
| `native_enc_diff.py` + `native_enc_golden.json` | 编码回归:native `enctest` 路由输出 vs 金标准(阶段 2 与 Python `_fill_can_out` 逐字节对拍通过后固化)。改 `fill_can_out`/`pack_tx_batch` 后必跑 |
| ~~`legacy_py/`~~ | Python 后端已彻底删除(2026-09-04 切换收官,含备份 zip)。行为基准只存在于 `MIGRATION.md` 的逐字段对拍记录里;`ecat_app.vbs` 桌面窗口模式随之退役 |
| `src/web/ecat.html` + `ecat.css` | 网页控制台前端 |
| `src/web/motor.html` + `motor.js` | 电机控制台:N1–N9 九节点,走 EtherCAT 过程数据(不经 WiFi/HTTP)。节点总览、8 种 Control_Mode、STATUS 实时解码、示波器曲线 |
| `src/diag/ecat_scan.py` | 最小化 bring-up 扫描:从站身份 + SII dump,`--op` 追加 PDO 测试 |
| `src/diag/ecat_esc_regs.py` | 从**网络侧**直读 LAN9252 ESC 寄存器,绕开 GD32/PDI,用于判断 EEPROM 加载是否真的失败;支持 `--reload` |
| `src/diag/ecat_sniff.py` | 旁路抓包,hexdump SOEM 自己发出的帧,用于对照裸帧格式 |
## 启动方式
双击根目录下的入口即可(脚本自己定位路径,不必在特定目录下运行):
| 入口 | 效果 |
|------|------|
| `ecat_web.vbs` | 后台起 native 守护进程并打开浏览器标签,无控制台窗口 |
| `ecat_web.bat` | 控制台模式,可见日志,调试用 |
| `ecat.bat` | 命令行工具入口,如 `ecat.bat status`、`ecat.bat flash` |
| `run_scan.bat` | 直接跑 bring-up 扫描,无参数则列出 Npcap 适配器 |
电机控制台在服务起来后从主页右上「电机控制台」进入,或直接访问 `/motor.html`。
它只读写 EtherCAT 过程数据,需先在主页点「连接」并让从站进入 OP。
## 注意
- ESC 的 SyncManager 寄存器是 `0x0800 + 8n`:邮箱是 SM0=`0x0800`、SM1=`0x0808`,
`0x0810`/`0x0818` 是 SM2/SM3(过程数据)。写诊断代码时别混用,否则抓到的现场会误导判断。
- **邮箱楔死判据**:SM0/SM1 寄存器正常(start=0x1000/0x1200、act=01)但 SDO 持续失败,
就是 SSC 的 `u16EscAddrSendMbx` 错位——响应帧写到 SM1 start+4/+8 且逐会话累积,
断电才清零。固件 <1.5.52 无自愈需断电重启,1.5.52+ 有守护自动写回。
`config_map` 失败时后端会自动转储 4 个 SM 现场,可直接对照。
- 前端 CSS/JS 改动后记得 bump `?v=` 缓存版本,否则浏览器会加载旧代码。
`src/web/ecat.css` 被 `ecat.html` 与 `motor.html` 共用,两处版本号要一起改。
- EEPROM 烧写后必须断电冷启动,ESC 才会重新加载配置。