Files
DCU_ECAT_Master/_repro_hang.py
T
cbb d594b8fd94 init: DCU LAN9252 EtherCAT 主站工具集
现有工具纳入版本管理:
- ecat_tool.py: 一体化命令行主站(status/flash/eeprom/sdo/send)
- ecat_server.py + ecat.html/css: 网页/桌面控制台(端口 8090)
- ecat_scan.py / ecat_esc_regs.py / ecat_sniff.py: bring-up 扫描、
  网络侧 ESC 寄存器诊断、裸帧抓包对照
- ecat_flash_eeprom.py: 经网线烧写 SII 镜像 + 逐字校验
- *.bat / *.vbs 启动入口

新增 .gitignore(排除 venv/ 与 __pycache__)、.gitattributes(不改写换行符)、
requirements.txt(锁定 pysoem 1.1.13 等依赖)、README.md。
2026-09-03 01:56:29 +08:00

79 lines
2.4 KiB
Python

"""_repro_hang.py — 复现 2026-09-03 01:40 "op/start 卡住→闪退"。
复刻 ecat.html 的 UI 操作序列(100ms 周期 + 2s pollSync + 手动 stop/start 节奏):
open → 循环 N 轮{ op/start → 立即 cycle+sync_diag → cycle@100ms → ~2s 后 op/stop } → close
faulthandler 45s 看门狗: 卡住时自动转储所有线程栈(op/start 有界 ~26s, 超过 45s = 真卡死)。
退出码非 0xC0000005 之外的异常退出也会打印。
"""
import faulthandler
import sys
import time
faulthandler.enable() # 捕获原生访问违例(SEH)并打印 Python 栈 = 闪退根因现场
faulthandler.dump_traceback_later(45, exit=False)
import ecat_server as es
def t():
return time.strftime("%H:%M:%S")
def show(res):
for line in res.get("log", []):
print(f" [{t()}] {line}", flush=True)
def main():
rounds = int(sys.argv[1]) if len(sys.argv) > 1 else 30
r = es.api_open({"substr": "I226"})
show(r)
if not r.get("ok"):
print("open 失败, 退出", flush=True)
return 1
for i in range(rounds):
print(f"=== round {i} op/start ===", flush=True)
r = es.api_op_start({"dc_cycle_us": 0})
show(r)
if not r.get("ok"):
print(f" [{t()}] op/start 失败, 继续下一轮", flush=True)
time.sleep(1.0)
continue
# 复刻 doCycle() 立即一次 + pollSync() 立即一次
r = es.api_op_cycle({"outputs": ""})
if not r.get("ok"):
show(r)
r = es.api_sync_diag({})
if not r.get("ok"):
show(r)
# 100ms 周期跑 ~2s, 中途 2s 处再 pollSync 一次
end = time.time() + 2.0
synced = False
while time.time() < end:
r = es.api_op_cycle({"outputs": ""})
if not r.get("ok"):
show(r)
break
if not synced and time.time() > end - 1.0:
synced = True
r = es.api_sync_diag({})
if not r.get("ok"):
show(r)
time.sleep(0.1)
print(f" [{t()}] op/stop", flush=True)
r = es.api_op_stop({})
show(r)
time.sleep(1.0) # 用户点击间隔
es.api_close({})
print(f"[{t()}] 全部 {rounds} 轮完成, 无卡死", flush=True)
faulthandler.cancel_dump_traceback_later()
return 0
if __name__ == "__main__":
rc = main()
print(f"EXIT rc={rc}", flush=True)
sys.exit(rc)