From 9b012c2091ab5f4c6b33cb5b0546b6fa8a6fc0e5 Mon Sep 17 00:00:00 2001
From: Martin Teichmann <martin.teichmann@xfel.eu>
Date: Wed, 2 Dec 2020 19:13:36 +0000
Subject: [PATCH] we get the terminals operational!

---
 ethercat.py | 148 +++++++++++++++++-----------------------------------
 1 file changed, 47 insertions(+), 101 deletions(-)

diff --git a/ethercat.py b/ethercat.py
index 9ee5a54..8fcf9c0 100644
--- a/ethercat.py
+++ b/ethercat.py
@@ -2,100 +2,6 @@ from asyncio import ensure_future, Event, Future, gather, get_event_loop, Protoc
 from socket import socket, AF_PACKET, SOCK_DGRAM
 from struct import pack, unpack, calcsize
 
-def create_frame(datagrams):
-    ret = [None]
-
-    for i, (cmd, idx, pos, offset, data) in enumerate(datagrams):
-        if isinstance(data, int):
-            data = b"\0" * data
-        ret.append(pack("<BBhHHH", cmd, idx, pos, offset,
-                        len(data) | ((i != len(datagrams) - 1) << 15), 0))
-        ret.append(data)
-        ret.append(b"\0\0")
-    size = sum(len(r) for r in ret[1:])
-    ret[0] = pack("<H", size | 0x1000)
-    return b"".join(ret)
-
-def print_frame(frame):
-    i = 2
-    while True:
-        cmd, idx, pos, offset, size, irq = unpack("<BBhHHH", frame[i : i+10])
-        i += 10
-        print(f"cmd {cmd} idx {idx} {pos:04x}:{offset:04x} irq {irq}")
-        nxt = size & 0x8000 != 0
-        size &= 0x7ff
-        print("data", size, frame[i : i+size], " ".join(f"{f:02x}" for f in frame[i : i+size]),
-              " ".join(f"{f:08b}" for f in frame[i : i+size]))
-        i += size
-        wkc, = unpack("<H", frame[i : i+2])
-        i += 2
-        print("wkc", wkc)
-        if not nxt:
-            break
-
-class Frame:
-    def __init__(self, datagrams):
-        ret = [None]
-        self.blocks = []
-        self.formats = []
-
-        j = 12
-
-        for i, (cmd, idx, pos, offset, data) in enumerate(datagrams):
-            data = "<" + data
-            size = calcsize(data)
-            ret.append(pack("<BBhHHH", cmd, idx, pos, offset,
-                            size | ((i != len(datagrams) - 1) << 15), 0))
-            ret.append(b"\0" * size)
-            self.blocks.append(j)
-            self.formats.append(data)
-            ret.append(b"\0\0")
-            j += size + 12
-        size = sum(len(r) for r in ret[1:])
-        ret[0] = pack("<H", size | 0x1000)
-        self.data = bytearray(b"".join(ret))
-
-    def roundtrip(self, sock, addr):
-        sock.sendto(self.data, addr)
-        ret = sock.recv_into(self.data)
-        if ret < len(self.data):
-            raise RuntimeError("not enough data")
-
-    def __getitem__(self, no):
-        pos = self.blocks[no]
-        d = self.data[pos : pos + calcsize(self.formats[no])]
-        return unpack(self.formats[no], d)
-
-    def __setitem__(self, no, data):
-        if not isinstance(data, tuple):
-            data = data,
-        pos = self.blocks[no]
-        self.data[pos : pos + calcsize(self.formats[no])
-                  ] = pack(self.formats[no], *data)
-
-    def __str__(self):
-        return "".join(self._str())
-
-    def _str(self):
-        i = 2
-        while True:
-            cmd, idx, pos, offset, size, irq = unpack("<BBhHHH",
-                                                      self.data[i : i+10])
-            i += 10
-            yield f"[{cmd} {idx} {pos:04x}:{offset:04x} {irq} ("
-            nxt = size & 0x8000 != 0
-            size &= 0x7ff
-            yield " ".join(f"{f:02x}" for f in self.data[i : i+size])
-            yield "   "
-            yield " ".join(f"{f:08b}" for f in self.data[i : i+size])
-            i += size
-            wkc, = unpack("<H", self.data[i : i+2])
-            i += 2
-            yield f") {wkc}]"
-            if nxt:
-                yield "\n"
-            else:
-                return
 
 class AsyncBase:
     async def __new__(cls, *args, **kwargs):
@@ -103,6 +9,7 @@ class AsyncBase:
         await ret.__init__(*args, **kwargs)
         return ret
 
+
 class EtherCat(Protocol, AsyncBase):
     async def __init__(self, network):
         self.addr = (network, 0x88A4, 0, 0, b"\xff\xff\xff\xff\xff\xff")
@@ -139,6 +46,8 @@ class EtherCat(Protocol, AsyncBase):
             data = pack("<" + fmt, *args)
         elif isinstance(fmt, str):
             data = b"\0" * calcsize(fmt)
+        elif isinstance(fmt, int):
+            data = b"\0" * fmt
         else:
             data = fmt
         self.send_queue.put_nowait((cmd, index, pos, offset, data, future))
@@ -190,15 +99,52 @@ class EtherCat(Protocol, AsyncBase):
                 return eeprom
             eeprom[hd] = await get_data(ws * 2)
 
+
+class Terminal:
+    def __init__(self, ethercat):
+        self.ec = ethercat
+
+    async def initialize(self, relative, absolute):
+        await self.ec.roundtrip(2, relative, 0x10, "H", absolute)
+        self.position = absolute
+        self.eeprom = await self.ec.read_eeprom(absolute)
+        await self.ec.roundtrip(5, absolute, 0x800, 0x80)
+        await self.ec.roundtrip(5, absolute, 0x800, self.eeprom[41])
+
+    async def set_state(self, state):
+        await self.ec.roundtrip(5, self.position, 0x0120, "H", state)
+        ret, = await self.ec.roundtrip(4, self.position, 0x0130, "H")
+        return ret
+
+    async def to_operational(self):
+        """try to bring the terminal to operational state"""
+        order = [0x11, 1, 2, 4, 8]
+        ret, = await self.ec.roundtrip(4, self.position, 0x0130, "H")
+        pos = order.index(ret)
+        s = 0x11 
+        for state in order[pos:]:
+            await self.ec.roundtrip(5, self.position, 0x0120, "H", state)
+            while s != state:
+                s, error = await self.ec.roundtrip(4, self.position,
+                                                   0x0130, "H2xH")
+                if error != 0:
+                    raise RuntimeError(f"AL register {error}")
+    
+    async def get_error(self):
+        return (await self.ec.roundtrip(4, self.position, 0x0134, "H"))[0]
+
+
 async def main():
     ec = await EtherCat("eth0")
-    await gather(
-        ec.roundtrip(2, 0, 0x10, "H", 8),
-        ec.roundtrip(2, -1, 0x10, "H", 3),
-        ec.roundtrip(2, -2, 0x10, "H", 21),
-        )
-
-    print(await gather(ec.read_eeprom(21), ec.read_eeprom(3), ec.read_eeprom(8)))
+    tin = Terminal(ec)
+    tout = Terminal(ec)
+    tdigi = Terminal(ec)
+    await tin.initialize(-1, 5)
+    await tout.initialize(-2, 6)
+    await tdigi.initialize(0, 22)
+    await tin.to_operational()
+    await tout.to_operational()
+    await tdigi.to_operational()
 
 if __name__ == "__main__":
     loop = get_event_loop()
-- 
GitLab