Files
DCU_ECAT_Master/diag/ecat_sniff.py
T
cbb beb33ffe50 refactor: 按角色分 web/ diag/ launch/ 三层, 根目录只留主程序
18 个文件平铺根目录太乱, 按角色归拢:
  web/     ecat.html/css + motor.html/js —— 前端资源
  diag/    ecat_scan / ecat_sniff / ecat_esc_regs —— 独立诊断脚本, 互不依赖
  launch/  5 个 .bat/.vbs 双击入口
根目录只留 ecat_server / ecat_tool / ecat_flash_eeprom / test_motor_backend:
这几个互相 import(tool→flash_eeprom, test→server), 挪进子目录就得改 import
或加包, 收益不抵成本。

配套改动:
  _STATIC_MAP 的值加 web/ 前缀 —— URL 路径刻意保持不变(/、/ecat.css、
  /motor.html), 页面内相对引用、书签、外部链接一律不用改。
  launch/ 里 %~dp0 现在指向 launch\, 五个启动器统一改为先取上一层作 ROOT
  (bat 用 %~dp0.., vbs 用两次 GetParentFolderName), run_scan 顺带指向
  diag\ecat_scan.py。

验证: 7 个 py 全编译通过; test_motor_backend 8 项全通过; 服务实起后 6 条
静态路由全 200 且 MIME 正确(js 是 application/javascript)、404 兜底正常;
Edge headless 渲染主页与 motor 页, CSS 294 规则加载、9 个节点样式生效、
零加载失败零 JS 异常; bat/vbs 的 ROOT 解析实测指到项目根, 五个目标文件
全部命中; ecat_tool adapters 与 diag/ecat_scan.py 实跑正常。
2026-09-03 22:08:38 +08:00

93 lines
3.4 KiB
Python
Raw 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.
#!/usr/bin/env python3
"""抓 SOEM 自己发的 EtherCAT 帧,对照裸帧格式。
另开 pcap 句柄抓包,同时在同进程里跑 pysoem eeprom_read,hexdump 收发帧。
用法:ecat_sniff.py [adapter-substr]"""
import ctypes
import struct
import sys
import threading
import time
import pysoem
ECAT = b"\x88\xa4"
class PcapPktHdr(ctypes.Structure):
_fields_ = [("tv_sec", ctypes.c_long), ("tv_usec", ctypes.c_long),
("caplen", ctypes.c_uint32), ("len", ctypes.c_uint32)]
def main():
substr = sys.argv[1] if len(sys.argv) > 1 else "I226"
adapter = None
for a in pysoem.find_adapters():
desc = a.desc.decode() if isinstance(a.desc, bytes) else a.desc
if substr.lower() in desc.lower():
adapter = a
break
if adapter is None:
raise SystemExit("适配器未找到")
name = adapter.name.decode() if isinstance(adapter.name, bytes) else adapter.name
wpcap = ctypes.WinDLL("wpcap.dll")
wpcap.pcap_open_live.restype = ctypes.c_void_p
wpcap.pcap_open_live.argtypes = [ctypes.c_char_p] + [ctypes.c_int] * 3 + [ctypes.c_char_p]
wpcap.pcap_next_ex.restype = ctypes.c_int
wpcap.pcap_next_ex.argtypes = [ctypes.c_void_p,
ctypes.POINTER(ctypes.POINTER(PcapPktHdr)),
ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte))]
wpcap.pcap_close.restype = None
wpcap.pcap_close.argtypes = [ctypes.c_void_p]
errbuf = ctypes.create_string_buffer(256)
handle = wpcap.pcap_open_live(name.encode(), 65535, 1, 50, errbuf)
if not handle:
raise SystemExit(f"pcap_open_live 失败: {errbuf.value.decode(errors='replace')}")
def soem_work():
try:
master = pysoem.Master()
master.open(adapter.name)
master.config_init()
slave = master.slaves[0]
slave.eeprom_read(0)
master.close()
except Exception as e:
print(f"soem_work: {type(e).__name__}: {e}")
t = threading.Thread(target=soem_work, daemon=True)
t.start()
frames = []
deadline = time.time() + 4.0
ph = ctypes.POINTER(PcapPktHdr)()
pd = ctypes.POINTER(ctypes.c_ubyte)()
while time.time() < deadline and len(frames) < 8:
r = wpcap.pcap_next_ex(handle, ctypes.byref(ph), ctypes.byref(pd))
if r != 1:
continue
data = bytes(bytearray(pd[:ph.contents.caplen]))
if len(data) >= 14 and data[12:14] == ECAT:
frames.append(data)
wpcap.pcap_close(handle)
print(f"抓到 {len(frames)} 个 EtherCAT 帧")
for i, f in enumerate(frames):
src = ":".join(f"{b:02X}" for b in f[6:12])
print(f"\n[{i}] len={len(f)} src={src}")
for off in range(14, min(len(f), 14 + 48), 16):
chunk = f[off:off + 16]
print(f" +{off - 14:02d}: " + " ".join(f"{b:02X}" for b in chunk))
# 解析前两个 datagram 头字段,确定头部布局
elen = struct.unpack_from("<H", f, 14)[0] & 0x7FF
print(f" ecat_hdr.len={elen} type={struct.unpack_from('<H', f, 14)[0] >> 12}")
d = f[16:]
if len(d) >= 12:
cmd, idx, adp, ado, ln = struct.unpack_from("<BBHHH", d, 0)
print(f" dgram: cmd=0x{cmd:02X} idx={idx} adp=0x{adp:04X} "
f"ado=0x{ado:04X} len_field={ln} (len={ln & 0x7FF})")
if __name__ == "__main__":
main()