#!/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 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 --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()