From 2b501347f62e5a7e59bb22d1e7f70128c1dffdbb Mon Sep 17 00:00:00 2001 From: Martin Teichmann <martin.teichmann@gmail.com> Date: Wed, 1 Feb 2023 09:42:02 +0000 Subject: [PATCH] improve addressing random terminals if the status of the bus is unknown, we need to assure not to address two terminals at the same time --- ebpfcat/ethercat.py | 18 ++++++++++++++++-- ebpfcat/scripts.py | 20 ++++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/ebpfcat/ethercat.py b/ebpfcat/ethercat.py index 4354262..2214772 100644 --- a/ebpfcat/ethercat.py +++ b/ebpfcat/ethercat.py @@ -28,6 +28,7 @@ this modules contains the code to actually talk to EtherCAT terminals. """ from asyncio import ensure_future, Event, Future, gather, get_event_loop, Protocol, Queue, Lock from enum import Enum +from itertools import count from random import randint from socket import socket, AF_PACKET, SOCK_DGRAM from struct import pack, unpack, unpack_from, calcsize @@ -281,7 +282,12 @@ class EtherCat(Protocol): if packet.full() or self.send_queue.empty(): data = await self.roundtrip_packet(packet) for start, stop, future in dgrams: - future.set_result(data[start:stop]) + wkc, = unpack("<H", data[stop:stop+2]) + if wkc == 0: + future.set_exception( + RuntimeError("datagram was not processed")) + else: + future.set_result(data[start:stop]) dgrams = [] packet = Packet() @@ -355,6 +361,15 @@ class EtherCat(Protocol): no, = unpack("<h", ret[16:18]) # number of terminals return no + async def find_free_address(self): + """Find an absolute address currently not in use""" + no = await self.count() + for i in count(no): + try: + await self.roundtrip(ECCmd.FPRD, i, 0x10, "H", 0) + except RuntimeError: + return i # this address is not in use + def connection_made(self, transport): """start the send loop once the connection is made""" transport.get_extra_info("socket").bind(self.addr) @@ -456,7 +471,6 @@ class Terminal: async def parse(func): bitpos = 0 async for idx, subidx, sm, bits in func: - #print("k", idx, subidx, sm, bits) if idx == 0: pass elif bits < 8: diff --git a/ebpfcat/scripts.py b/ebpfcat/scripts.py index 4a2ecd0..689b428 100644 --- a/ebpfcat/scripts.py +++ b/ebpfcat/scripts.py @@ -43,17 +43,17 @@ async def info(): if args.terminal is None: terminals = range(await ec.count()) + terms = [Terminal() for t in terminals] + for t in terms: + t.ec = ec + await asyncio.gather(*(t.initialize(-i, i + 7) + for i, t in zip(terminals, terms))) else: - # former terminal: don't listen! - # this does not work with all terminals, dunno why - await ec.roundtrip(ECCmd.FPRW, 7, 0x10, "H", 0) - terminals = [args.terminal] - - terms = [Terminal() for t in terminals] - for t in terms: - t.ec = ec - await asyncio.gather(*(t.initialize(-i, i + 7) - for i, t in zip(terminals, terms))) + free = await ec.find_free_address() + term = Terminal() + term.ec = ec + await term.initialize(-args.terminal, free) + terms = [term] for i, t in enumerate(terms): print(f"terminal no {i}") -- GitLab