refactor: 入口提到根目录, 代码收进 src/

上一版把入口塞进 launch/、代码摊在根目录, 正好反了: 双击入口该第一眼看到,
实现细节该收起来。现在:
  根目录  5 个 .bat/.vbs 入口 + README + requirements
  src/    ecat_server / ecat_tool / ecat_flash_eeprom / test_motor_backend
  src/web    前端资源      src/diag   独立诊断脚本

启动器改为 cd 进 %~dp0src 再跑(vbs 用 CurrentDirectory = base & "\src"),
工作目录落在 src 才能让 tool→flash_eeprom、test→server 的 import 解析到。
ecat_server.py 的 BASE_DIR 取自 __file__, 与 src/web 仍是同层父子关系,
_STATIC_MAP 和窗口模式的子进程 spawn 都无需改动。

.gitignore 补 sii.json / *.sii / eeprom_*.bin —— eeprom read --out 的导出
产物, 属运行结果不该入库。

验证: 7 个 py 全编译通过; test_motor_backend 8 项全通过; ecat.bat 与
run_scan.bat 实跑列出适配器; 服务起后 4 条静态路由 200 且 MIME 正确;
Edge headless 渲染主页与 motor 页, CSS 294 规则、9 节点样式生效, 零加载
失败零 JS 异常; bat 的 %~dp0 与 vbs 的 GetParentFolderName 实测均落在
项目根, src/ 下五个目标文件全部命中。
This commit is contained in:
cbb
2026-09-03 22:27:23 +08:00
parent beb33ffe50
commit 979da72181
19 changed files with 61 additions and 54 deletions
+5
View File
@@ -15,6 +15,11 @@ env/
*.pcapng
sniff_*.txt
# EEPROM/SII 导出产物(eeprom read --out 生成, 属运行结果不是源码)
sii.json
*.sii
eeprom_*.bin
# 一次性日志分析脚本(硬编码临时路径, 无留存价值)
_analyze_log.py
+34 -26
View File
@@ -18,45 +18,53 @@ venv\Scripts\python.exe -m pip install -r requirements.txt
## 目录结构
入口在最外层,双击即用;代码全部收进 `src/`。
```
ecat/
├─ ecat_server.py 网页控制台后端(REST API + 静态文件), 默认端口 8090
├─ ecat_tool.py 一体化命令行主站
├─ ecat_flash_eeprom.py 经网线烧写 SII 镜像(被 ecat_tool flash 复用)
├─ test_motor_backend.py 电机后端自测(不接硬件)
├─ web/ 前端资源(URL 路径不变, 仍是 / 与 /motor.html)
├─ diag/ 独立诊断脚本(互不依赖, 直接单跑)
├─ launch/ 双击入口(.bat/.vbs)
├─ ecat_app.vbs ← 桌面窗口(推荐)
├─ ecat_web.vbs ← 浏览器标签
├─ ecat_web.bat ← 控制台模式(看日志)
├─ ecat.bat ← 命令行工具
├─ run_scan.bat ← bring-up 扫描
├─ README.md / requirements.txt
├─ src/
│ ├─ ecat_server.py 网页控制台后端(REST API + 静态文件), 默认端口 8090
│ ├─ ecat_tool.py 一体化命令行主站
│ ├─ ecat_flash_eeprom.py 经网线烧写 SII 镜像(被 ecat_tool flash 复用)
│ ├─ test_motor_backend.py 电机后端自测(不接硬件)
│ ├─ web/ 前端资源(URL 路径不变, 仍是 / 与 /motor.html)
│ └─ diag/ 独立诊断脚本(互不依赖, 直接单跑)
└─ venv/ 本地虚拟环境(不入库)
```
根目录只放主程序:`ecat_tool.py` import `ecat_flash_eeprom`、
`test_motor_backend.py` import `ecat_server`,这几个互相 import 的必须同层,
挪进子目录就得改 import 或加包,不值得。
`src/` 根下那四个 .py 平放是有原因的:`ecat_tool.py` import `ecat_flash_eeprom`、
`test_motor_backend.py` import `ecat_server`,互相 import 的必须同层,再往下分
就得改 import 或做成包,不值得。
| 文件 | 说明 |
|------|------|
| `ecat_tool.py` | 一体化命令行主站:`adapters` / `status` / `flash` / `eeprom` / `sdo` / `send` 等子命令 |
| `ecat_server.py` | 网页控制台后端(REST API + 静态文件),默认端口 **8090**(8080 已被 ESP32 tools 占用) |
| `ecat_flash_eeprom.py` | 通过网线烧写 `gen_eeprom.py` 生成的 SII 镜像,逐字回读校验(烧完需断电重启让 ESC 重新加载) |
| `test_motor_backend.py` | 电机后端自测,**不接硬件**(假从站模拟 GD32 buildInput/processOutput)。跑法:`venv\Scripts\python.exe test_motor_backend.py` |
| `web/ecat.html` + `web/ecat.css` | 网页控制台前端 |
| `web/motor.html` + `web/motor.js` | 电机控制台:N1–N9 九节点,走 EtherCAT 过程数据(不经 WiFi/HTTP)。节点总览、8 种 Control_Mode、STATUS 实时解码、示波器曲线 |
| `diag/ecat_scan.py` | 最小化 bring-up 扫描:从站身份 + SII dump,`--op` 追加 PDO 测试 |
| `diag/ecat_esc_regs.py` | 从**网络侧**直读 LAN9252 ESC 寄存器,绕开 GD32/PDI,用于判断 EEPROM 加载是否真的失败;支持 `--reload` |
| `diag/ecat_sniff.py` | 旁路抓包,hexdump SOEM 自己发出的帧,用于对照裸帧格式 |
| `src/ecat_tool.py` | 一体化命令行主站:`adapters` / `status` / `flash` / `eeprom` / `sdo` / `send` 等子命令 |
| `src/ecat_server.py` | 网页控制台后端(REST API + 静态文件),默认端口 **8090**(8080 已被 ESP32 tools 占用) |
| `src/ecat_flash_eeprom.py` | 通过网线烧写 `gen_eeprom.py` 生成的 SII 镜像,逐字回读校验(烧完需断电重启让 ESC 重新加载) |
| `src/test_motor_backend.py` | 电机后端自测,**不接硬件**(假从站模拟 GD32 buildInput/processOutput)。跑法:在 `src/` 下 `..\venv\Scripts\python.exe test_motor_backend.py` |
| `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 自己发出的帧,用于对照裸帧格式 |
## 启动方式
双击 `launch/` 里的入口即可(脚本自己会定位到项目根,不必在特定目录下运行):
双击根目录下的入口即可(脚本自己定位路径,不必在特定目录下运行):
| 入口 | 效果 |
|------|------|
| `launch/ecat_app.vbs` | pywebview 桌面窗口,无控制台无浏览器标签(已针对部分 GPU 驱动白屏加 `--disable-gpu-compositing`) |
| `launch/ecat_web.vbs` | 后台起服务并打开浏览器标签,无控制台窗口 |
| `launch/ecat_web.bat` | 控制台模式,可见日志,调试用 |
| `launch/ecat.bat` | 命令行工具入口,如 `ecat.bat status`、`ecat.bat flash` |
| `launch/run_scan.bat` | 直接跑 bring-up 扫描,无参数则列出 Npcap 适配器 |
| `ecat_app.vbs` | pywebview 桌面窗口,无控制台无浏览器标签(已针对部分 GPU 驱动白屏加 `--disable-gpu-compositing`) |
| `ecat_web.vbs` | 后台起服务并打开浏览器标签,无控制台窗口 |
| `ecat_web.bat` | 控制台模式,可见日志,调试用 |
| `ecat.bat` | 命令行工具入口,如 `ecat.bat status`、`ecat.bat flash` |
| `run_scan.bat` | 直接跑 bring-up 扫描,无参数则列出 Npcap 适配器 |
电机控制台在服务起来后从主页右上「电机控制台」进入,或直接访问 `/motor.html`。
它只读写 EtherCAT 过程数据,需先在主页点「连接」并让从站进入 OP。
@@ -70,5 +78,5 @@ ecat/
断电才清零。固件 <1.5.52 无自愈需断电重启,1.5.52+ 有守护自动写回。
`config_map` 失败时后端会自动转储 4 个 SM 现场,可直接对照。
- 前端 CSS/JS 改动后记得 bump `?v=` 缓存版本,否则浏览器会加载旧代码。
`web/ecat.css` 被 `web/ecat.html` 与 `web/motor.html` 共用,两处版本号要一起改。
`src/web/ecat.css` 被 `ecat.html` 与 `motor.html` 共用,两处版本号要一起改。
- EEPROM 烧写后必须断电冷启动,ESC 才会重新加载配置。
+3 -4
View File
@@ -1,10 +1,9 @@
@echo off
rem EtherCAT master tool for DCU LAN9252 (scan/flash/send/monitor)
rem Examples: ecat.bat status | ecat.bat flash | ecat.bat send --u64 0x1,0x2,0x3,0x4 --duration 5
rem 本文件在 launch\ 下, %~dp0 指向 launch\, 故 ROOT 取其上一层。
rem 入口在项目根, 代码在 src\; cd 进 src 是为了让 py 之间的 import 正常解析。
chcp 65001 >nul
set PYTHONUTF8=1
set "ROOT=%~dp0.."
cd /d "%ROOT%"
"%ROOT%\venv\Scripts\python.exe" ecat_tool.py %*
cd /d "%~dp0src"
"%~dp0venv\Scripts\python.exe" ecat_tool.py %*
pause
+4 -5
View File
@@ -1,14 +1,13 @@
' DCU EtherCAT desktop window (pywebview/WebView2). No console, no browser tab.
' Browser-tab launcher: ecat_web.vbs Console-mode debug launcher: ecat_web.bat
' 本文件在 launch\ 下: 先取自身所在目录, 再上一层拿到项目根。
' 入口在项目根, 代码在 src\; 工作目录设为 src 以便 py 之间 import 正常解析。
Set sh = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
here = fso.GetParentFolderName(WScript.ScriptFullName)
base = fso.GetParentFolderName(here)
sh.CurrentDirectory = base
base = fso.GetParentFolderName(WScript.ScriptFullName)
sh.CurrentDirectory = base & "\src"
sh.Environment("PROCESS")("PYTHONUTF8") = "1"
' WebView2: keep GPU rasterization but disable GPU compositing.
' Full hardware acceleration white-screens this window on some GPU drivers;
' --disable-gpu-compositing fixes it while still using the GPU for raster.
sh.Environment("PROCESS")("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS") = "--disable-gpu-compositing"
sh.Run """" & base & "\venv\Scripts\pythonw.exe"" """ & base & "\ecat_server.py"" --window", 0, False
sh.Run """" & base & "\venv\Scripts\pythonw.exe"" """ & base & "\src\ecat_server.py"" --window", 0, False
+8
View File
@@ -0,0 +1,8 @@
@echo off
rem DCU EtherCAT master web console (serves src\web\ecat.html + pysoem API)
rem 入口在项目根, 代码在 src\; cd 进 src 是为了让 py 之间的 import 正常解析。
chcp 65001 >nul
set PYTHONUTF8=1
cd /d "%~dp0src"
"%~dp0venv\Scripts\python.exe" ecat_server.py
pause
+4 -5
View File
@@ -1,10 +1,9 @@
' DCU EtherCAT web console - hidden launcher (no console window).
' Double-click me. Console-mode debug launcher (visible logs): ecat_web.bat
' 本文件在 launch\ 下: 先取自身所在目录, 再上一层拿到项目根。
' 入口在项目根, 代码在 src\; 工作目录设为 src 以便 py 之间 import 正常解析。
Set sh = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
here = fso.GetParentFolderName(WScript.ScriptFullName)
base = fso.GetParentFolderName(here)
sh.CurrentDirectory = base
base = fso.GetParentFolderName(WScript.ScriptFullName)
sh.CurrentDirectory = base & "\src"
sh.Environment("PROCESS")("PYTHONUTF8") = "1"
sh.Run """" & base & "\venv\Scripts\python.exe"" """ & base & "\ecat_server.py""", 0, False
sh.Run """" & base & "\venv\Scripts\python.exe"" """ & base & "\src\ecat_server.py""", 0, False
-9
View File
@@ -1,9 +0,0 @@
@echo off
rem DCU EtherCAT master web console (serves web\ecat.html + pysoem API)
rem 本文件在 launch\ 下, %~dp0 指向 launch\, 故 ROOT 取其上一层。
chcp 65001 >nul
set PYTHONUTF8=1
set "ROOT=%~dp0.."
cd /d "%ROOT%"
"%ROOT%\venv\Scripts\python.exe" ecat_server.py
pause
+3 -5
View File
@@ -2,11 +2,9 @@
rem EtherCAT master bring-up scan (LAN9252)
rem Usage: run_scan.bat -> list Npcap adapters
rem run_scan.bat I226 -> scan EtherCAT slaves (add --op for PDO test)
rem 本文件在 launch\ 下, %~dp0 指向 launch\, 故 ROOT 取其上一层;
rem 扫描脚本已挪进 diag\。
rem 入口在项目根, 扫描脚本在 src\diag\。
chcp 65001 >nul
set PYTHONUTF8=1
set "ROOT=%~dp0.."
cd /d "%ROOT%"
"%ROOT%\venv\Scripts\python.exe" diag\ecat_scan.py %*
cd /d "%~dp0src"
"%~dp0venv\Scripts\python.exe" diag\ecat_scan.py %*
pause
View File
View File
View File
View File