Files
DCU_ECAT_Master/ecat_scan.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

121 lines
3.7 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 python
"""EtherCAT master bring-up test for the DCU LAN9252 slave (pysoem >= 1.1 API).
Usage:
ecat_scan.py list all Npcap adapters and exit
ecat_scan.py <name-substr> open the first adapter whose description matches
the substring (e.g. "I226"), scan the bus and
print slave identity + SII EEPROM dump
ecat_scan.py <substr> --op additionally request OP and run PDO cycles for 2s
"""
import sys
import time
try:
import pysoem
except ImportError:
print("pysoem 无法加载:请先安装 Npcap(本目录下的 npcap-1.88.exe,"
"安装时保持勾选 'Install WinPcap API-compatible Mode')")
sys.exit(1)
AL_STATE = {1: "INIT", 2: "PREOP", 4: "SAFEOP", 8: "OP"}
def al_state_name(code):
return AL_STATE.get(code, f"0x{code:02x}")
def list_adapters():
for i, a in enumerate(pysoem.find_adapters()):
desc = a.desc.decode() if isinstance(a.desc, bytes) else a.desc
print(f"[{i}] {desc}\n {a.name}")
def find_adapter(substr):
for a in pysoem.find_adapters():
desc = a.desc.decode() if isinstance(a.desc, bytes) else a.desc
if substr.lower() in desc.lower():
return a
return None
def dump_eeprom(slave, count=0x10):
print(" SII EEPROM dump (每行 8 个 word 地址,原始 32bit 返回):")
for base in range(0, count, 8):
words = []
for w in range(base, base + 8):
try:
v = bytes(slave.eeprom_read(w))
words.append(v.hex().upper())
except Exception:
words.append("ERRRRRRRR")
print(f" 0x{base:02X}: {' '.join(words)}")
def main():
if len(sys.argv) < 2 or sys.argv[1] in ("-l", "--list"):
list_adapters()
return
substr = sys.argv[1]
want_op = "--op" in sys.argv[2:]
adapter = find_adapter(substr)
if adapter is None:
print(f"没有找到描述包含 {substr!r} 的适配器,当前列表:")
list_adapters()
sys.exit(1)
desc = adapter.desc.decode() if isinstance(adapter.desc, bytes) else adapter.desc
master = pysoem.Master()
master.open(adapter.name)
try:
n = master.config_init()
except Exception as e:
print(f"总线上没有发现从站({type(e).__name__}: {e}):"
"请检查 DCU 板子是否上电、网线是否接到 I226-V 网口")
sys.exit(2)
if not n:
print("总线上没有发现从站:请检查 DCU 板子是否上电、网线是否接到 I226-V 网口")
sys.exit(2)
print(f"\n适配器: {desc}")
print(f"发现 {n} 个从站:")
for i, s in enumerate(master.slaves):
print(f" [{i}] name={s.name!r}")
print(f" VendorID=0x{s.man:08X} ProductCode=0x{s.id:08X} Revision={s.rev}")
print(f" AL state={al_state_name(s.state)} AL status code=0x{s.al_status:04X}"
f" DC={s.dc_sync}")
dump_eeprom(master.slaves[0])
if not want_op:
return
master.config_map()
if master.state_check(pysoem.SAFEOP_STATE, 2000) != pysoem.SAFEOP_STATE:
print(f"进入 SAFEOP 失败, 当前 AL 状态: {al_state_name(master.state)}")
sys.exit(3)
t_end = time.time() + 2.0
frames = 0
while time.time() < t_end:
master.send_processdata()
master.receive_processdata(2000)
frames += 1
time.sleep(0.001)
master.state = pysoem.OP_STATE
master.write_state()
if master.state_check(pysoem.OP_STATE, 2000) == pysoem.OP_STATE:
print(f"已进入 OP, PDO 循环 {frames} 帧正常")
else:
print(f"进入 OP 失败, 当前 AL 状态: {al_state_name(master.state)}")
if __name__ == "__main__":
main()