From cd57956805493234cd64b377b49f825bd092fef5 Mon Sep 17 00:00:00 2001
From: Martin Teichmann <martin.teichmann@xfel.eu>
Date: Fri, 5 Feb 2021 17:34:13 +0000
Subject: [PATCH] support an analog output

---
 devices.py    | 14 ++++++++++++++
 ebpfcat.py    | 18 +++++++++++++-----
 terminals.py  |  7 +++++++
 testsystem.py | 18 +++++++++++-------
 4 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/devices.py b/devices.py
index 07f8734..529676b 100644
--- a/devices.py
+++ b/devices.py
@@ -13,3 +13,17 @@ class AnalogInput(Device):
 
     def update(self):
         self.value = self.data
+
+
+class AnalogOutput(Device):
+    value = DeviceVar()
+    data = TerminalVar()
+
+    def __init__(self, data):
+        self.data = data
+
+    def program(self):
+        self.data = self.value
+
+    def update(self):
+        self.data = self.value
diff --git a/ebpfcat.py b/ebpfcat.py
index 096f0d9..195331b 100644
--- a/ebpfcat.py
+++ b/ebpfcat.py
@@ -1,5 +1,5 @@
 from asyncio import ensure_future, gather, sleep
-from struct import pack, unpack, calcsize
+from struct import pack, unpack, calcsize, pack_into, unpack_from
 from time import time
 from .arraymap import ArrayMap, ArrayGlobalVarDesc
 from .ethercat import ECCmd, EtherCat, Packet, Terminal
@@ -38,8 +38,14 @@ class TerminalVar(MemoryDesc):
             self.terminal = value.terminal
             self.position = value.desc.position
             instance.__dict__[self.name] = value
-        else:
+        elif instance.sync_group.current_data is None:
             super().__set__(instance.sync_group, value)
+        else:
+            pv = instance.__dict__.get(self.name)
+            data = instance.sync_group.current_data
+            start = self.terminal.bases[self.position[0]] + self.position[1]
+            fmt = "<" + pv.desc.size
+            pack_into(fmt, data, start, value)
 
     def __get__(self, instance, owner):
         if instance is None:
@@ -53,7 +59,7 @@ class TerminalVar(MemoryDesc):
             data = instance.sync_group.current_data
             start = self.terminal.bases[self.position[0]] + self.position[1]
             fmt = "<" + pv.desc.size
-            return unpack(fmt, data[start:start+calcsize(fmt)])[0]
+            return unpack_from(fmt, data, start)[0]
 
     def __set_name__(self, name, owner):
         self.name = name
@@ -203,9 +209,11 @@ class SyncGroup:
 
     async def run(self):
         await gather(*[t.to_operational() for t in self.terminals])
+        self.current_data = self.asm_packet
         while True:
-            self.ec.send_packet(self.asm_packet)
-            self.current_data = await self.ec.receive_index(self.packet_index)
+            self.ec.send_packet(self.current_data)
+            data = await self.ec.receive_index(self.packet_index)
+            self.current_data = bytearray(data)
             for dev in self.devices:
                 dev.update()
 
diff --git a/terminals.py b/terminals.py
index 4ed4df3..467d3cb 100644
--- a/terminals.py
+++ b/terminals.py
@@ -5,6 +5,13 @@ class Generic(EBPFTerminal):
     pass
 
 
+class EL4104(EBPFTerminal):
+    ch1_value = PacketDesc((1, 0), 'H')
+    ch2_value = PacketDesc((1, 2), 'H')
+    ch3_value = PacketDesc((1, 4), 'H')
+    ch4_value = PacketDesc((1, 6), 'H')
+
+
 class EL3164(EBPFTerminal):
     ch1_attrs = PacketDesc((0, 0), 'H')
     ch2_attrs = PacketDesc((0, 4), 'H')
diff --git a/testsystem.py b/testsystem.py
index 9772f02..58ca91d 100644
--- a/testsystem.py
+++ b/testsystem.py
@@ -1,10 +1,10 @@
 from asyncio import gather, sleep, ensure_future
-from .terminals import EL3164, Generic
-from .devices import AnalogInput
+from .terminals import EL3164, EL4104, Generic
+from .devices import AnalogInput, AnalogOutput
 from .ebpfcat import FastEtherCat, FastSyncGroup, SyncGroup
 
 tdigi = Generic()
-tout = Generic()
+tout = EL4104()
 tin = EL3164()
 
 ec = FastEtherCat("eth0", [tdigi, tin, tout])
@@ -22,15 +22,19 @@ async def main():
     #ensure_future(monitor(ec))
 
     ai = AnalogInput(tin.ch1_value)
-    fsg = FastSyncGroup(ec, [ai])
-    #fsg = SyncGroup(ec, [ai])
+    ao = AnalogOutput(tout.ch1_value)
+    #fsg = FastSyncGroup(ec, [ai])
+    fsg = SyncGroup(ec, [ai, ao])
+
+    ao.value = 0
 
     fsg.start()
 
     for i in range(10):
         await sleep(0.1)
-        fsg.properties.read()
-        print(i, ai.value, ec.ebpf.count, ec.ebpf.allcount)
+        #fsg.properties.read()
+        ao.value = 3000 * i
+        print(i, ai.value, ao.data, await tout.get_state())
 
 if __name__ == "__main__":
     from asyncio import get_event_loop
-- 
GitLab