diff --git a/ebpfcat/ebpfcat.py b/ebpfcat/ebpfcat.py
index c3b927474d67ad34fe674b87902270aa9ac2e87c..a8b1908c9392b485ab03f1489eeb7e3278feb037 100644
--- a/ebpfcat/ebpfcat.py
+++ b/ebpfcat/ebpfcat.py
@@ -231,8 +231,8 @@ class EBPFTerminal(Terminal):
     compatibility = None
     position_offset = {2: 0, 3: 0}
 
-    async def initialize(self, relative, absolute):
-        await super().initialize(relative, absolute)
+    async def apply_eeprom(self):
+        await super().apply_eeprom()
         if (self.compatibility is not None and
                 (self.vendorId, self.productCode) not in self.compatibility):
             raise RuntimeError(
diff --git a/ebpfcat/ethercat.py b/ebpfcat/ethercat.py
index 6a37e0c1f3e21f319d10ec40e8a49411c2807e9d..d626644fc3f7d8abeba4cc8a504fb47dfbe88f36 100644
--- a/ebpfcat/ethercat.py
+++ b/ebpfcat/ethercat.py
@@ -406,8 +406,14 @@ class Terminal:
         await self.set_state(0x11)
         await self.set_state(1)
 
+        self.mbx_cnt = 1
+        self.mbx_lock = Lock()
+
+        await self.apply_eeprom()
+
+    async def apply_eeprom(self):
         async def read_eeprom(no, fmt):
-            return unpack(fmt, await self.eeprom_read_one(no))
+            return unpack(fmt, await self._eeprom_read_one(no))
 
         self.vendorId, self.productCode = await read_eeprom(8, "<II")
         self.revisionNo, self.serialNo = await read_eeprom(0xc, "<II")
@@ -416,9 +422,6 @@ class Terminal:
         # self.mbx_in_off, self.mbx_in_sz, self.mbx_out_off, self.mbx_out_sz = \
         #     await read_eeprom(0x18, "<HHHH")
 
-        self.mbx_cnt = 1
-        self.mbx_lock = Lock()
-
         self.eeprom = await self.read_eeprom()
         if 41 not in self.eeprom:
             # no sync managers defined in eeprom
@@ -573,7 +576,7 @@ class Terminal:
         return (await self.ec.roundtrip(ECCmd.FPWR, self.position,
                                         start, *args, **kwargs))
 
-    async def eeprom_read_one(self, start):
+    async def _eeprom_read_one(self, start):
         """read 8 bytes from the eeprom at `start`"""
         while (await self.read(0x502, "H"))[0] & 0x8000:
             pass
@@ -602,7 +605,7 @@ class Terminal:
             nonlocal data, pos
 
             while len(data) < size:
-                data += await self.eeprom_read_one(pos)
+                data += await self._eeprom_read_one(pos)
                 pos += 4
             ret, data = data[:size], data[size:]
             return ret
diff --git a/ebpfcat/ethercat_test.py b/ebpfcat/ethercat_test.py
index f95f0c701ae51b3d64986a7ea01fc95bac6f1dfa..5c921c4fa139bc5ff2b4f4f8b2fb13d2e595168a 100644
--- a/ebpfcat/ethercat_test.py
+++ b/ebpfcat/ethercat_test.py
@@ -15,22 +15,33 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
+from ast import literal_eval
 from asyncio import CancelledError, Future, get_event_loop, sleep, gather
-from unittest import TestCase, main
+from functools import wraps
+from itertools import count
+from struct import pack
+from unittest import TestCase, main, skip
 
 from .devices import AnalogInput, AnalogOutput, Motor
 from .terminals import EL4104, EL3164, EK1814
-from .ethercat import ECCmd
+from .ethercat import ECCmd, Terminal
 from .ebpfcat import (
     FastSyncGroup, SyncGroup, TerminalVar, Device, EBPFTerminal, PacketDesc)
 from .ebpf import Instruction, Opcode as O
 
 
+H = bytes.fromhex
+
+
 class MockEtherCat:
     def __init__(self, test):
         self.test = test
+        with open(__file__.rsplit("/", 1)[0] + "/testdata.py", "r") as fin:
+            self.test_data = literal_eval(fin.read())
 
-    async def roundtrip(self, *args):
+    async def roundtrip(self, *args, data=None):
+        if data is not None:
+            args += data,
         self.test.assertEqual(args, self.expected.pop(0))
         return self.results.pop(0)
 
@@ -50,68 +61,121 @@ class MockEtherCat:
         return 0x33
 
 
+class MockTerminal(Terminal):
+    async def initialize(self, relative, absolute):
+        self.position = absolute
+        self.operational = False
+        data = self.ec.test_data[-relative]
+        self.test_eeprom = data["eeprom"]
+        self.test_sdo = data["sdo"]
+        await self.apply_eeprom()
+
+    async def to_operational(self):
+        self.operational = True
+
+    async def sdo_read(self, index, subindex=None):
+        assert self.operational
+        if subindex is None:
+            r = b''
+            for i in count(1):
+                a = self.test_sdo.get((index, i))
+                if a is None:
+                    break
+                r += a
+            return r
+        elif subindex == 0 and (index, 0) not in self.test_sdo:
+            for i in count(1):
+                a = self.test_sdo.get((index, i))
+                if a is None:
+                    return pack("B", i - 1)
+        return self.test_sdo[index, subindex]
+
+    async def _eeprom_read_one(self, pos):
+        if pos * 2 > len(self.test_eeprom):
+            return b"\xff" * 8
+        return self.test_eeprom[pos*2 : pos*2 + 8]
+
+
+def mockAsync(f):
+    @wraps(f)
+    def wrapper(self):
+        get_event_loop().run_until_complete(f(self))
+    return wrapper
+
+
+def mockTerminal(cls):
+    class Mocked(MockTerminal, cls):
+        pass
+    return Mocked()
+
+
 class Tests(TestCase):
-    def test_input(self):
-        ti = EL3164()
-        ti.pdo_in_sz = 4
-        ti.pdo_in_off = 0xABCD
-        ti.position = 0x77
-        ti.pdo_out_sz = 3
-        ti.pdo_out_off = 0x4321
+    @mockAsync
+    async def test_input(self):
+        ti = mockTerminal(EL3164)
         ec = MockEtherCat(self)
         ti.ec = ec
+        ec.expected = [
+            (ECCmd.FPWR, 4, 0x800, 0x80),
+            (ECCmd.FPWR, 4, 0x800, H('00108000260001018010800022000102'
+                                     '00110000040000038011100020000104')),
+        ]
+        ec.results = [None, None]
+        await ti.initialize(-1, 4)
         ai = AnalogInput(ti.channel1.value)
         SyncGroup.packet_index = 1000
         sg = SyncGroup(ec, [ai])
         self.task = sg.start()
         ec.expected = [
-            (ECCmd.FPRD, 0x77, 304, "H2xH"),  # get state
-            bytes.fromhex("2d10"  # EtherCAT Header, length & type
-                          "0000e8030000008000000000"  # ID datagram
-                          "04007700cdab04800000000000000000" # in datagram
-                          "050077002143030000000000000000"), # out datagram
+            H("2a10"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              # in datagram
+              "04000400801110000000000000000000000000000000000000000000"),
             1000, # == 0x3e8, see ID datagram
-            bytes.fromhex("2d10"  # EtherCAT Header, length & type
-                          "0000e8030000008000000000"  # ID datagram
-                          "04007700cdab04800000123456780000" # in datagram
-                          "050077002143030000000000000000"), # out datagram
+            H("2a10"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              # in datagram
+              "04000400801110000000123456780000000000000000000000000000"),
             1000,
             ]
         ec.results = [
-            (8, 0),  # return state 8, no error
-            bytes.fromhex("2d10"  # EtherCAT Header, length & type
-                          "0000e8030000008000000000"  # ID datagram
-                          "04007700cdab04800000123456780000" # in datagram
-                          "050077002143030000000000000000"), # out datagram
+            H("2a10"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              # in datagram
+              "04000400801110000000123456780000000000000000000000000000"),
+            H("2a10"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              # in datagram
+              "04000400801110000000123456780000000000000000000000000000"),
             ]
         self.future = Future()
         with self.assertRaises(CancelledError):
-            get_event_loop().run_until_complete(
-                    gather(self.future, self.task))
+            await gather(self.future, self.task)
         self.assertEqual(ai.value, 0x7856)
         self.task.cancel()
         with self.assertRaises(CancelledError):
-            get_event_loop().run_until_complete(self.task)
+            await self.task
 
-    def test_output(self):
-        ti = EL4104()
-        ti.pdo_in_sz = 4
-        ti.pdo_in_off = 0xABCD
-        ti.position = 0x77
-        ti.pdo_out_sz = 3
-        ti.pdo_out_off = 0x4321
+    @mockAsync
+    async def test_output(self):
+        ti = mockTerminal(EL4104)
         ec = MockEtherCat(self)
         ti.ec = ec
+        ec.expected = [
+            (ECCmd.FPWR, 7, 0x800, 0x80),
+            (ECCmd.FPWR, 7, 0x800, H('0010800026000101801080002200010'
+                                     '200110800240001038011000000000004')),
+        ]
+        ec.results = [None, None]
+        await ti.initialize(-2, 7)
         ao = AnalogOutput(ti.ch1_value)
         SyncGroup.packet_index = 1000
         sg = SyncGroup(ec, [ao])
         self.task = sg.start()
         ec.expected = [
-            (ECCmd.FPRD, 0x77, 304, "H2xH"),  # get state
-            bytes.fromhex("2d10"  # EtherCAT Header, length & type
-                          "0000e8030000008000000000"  # ID datagram
-                          "04007700cdab04800000000000000000" # in datagram
-                          "050077002143030000000000000000"), # out datagram
+            H("2210"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              "0500070000110800000000000000000000000000"), # out datagram
             1000, # == 0x3e8, see ID datagram
             ]
         ec.results = [
@@ -120,48 +184,30 @@ class Tests(TestCase):
         self.future = Future()
         ao.value = 0x9876
         with self.assertRaises(CancelledError):
-            get_event_loop().run_until_complete(
-                    gather(self.future, self.task))
+            await gather(self.future, self.task)
         ec.expected = [
-            bytes.fromhex("2d10"  # EtherCAT Header, length & type
-                          "0000e8030000008000000000"  # ID datagram
-                          "04007700cdab04800000123456780000" # in datagram
-                          "050077002143030000007698000000"), # out datagram
+            H("2210"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              "0500070000110800000076980000000000000000"), # out datagram
             1000,
             ]
         ec.results = [
-            bytes.fromhex("2d10"  # EtherCAT Header, length & type
-                          "0000e8030000008000000000"  # ID datagram
-                          "04007700cdab04800000123456780000" # in datagram
-                          "050077002143030000007698000000"), # out datagram
+            H("2210"  # EtherCAT Header, length & type
+              "0000e8030000008000000000"  # ID datagram
+              "0500070000110800000076980000000000000000"), # out datagram
             ]
         self.future = Future()
         with self.assertRaises(CancelledError):
-            get_event_loop().run_until_complete(
-                    gather(self.future, self.task))
+            await gather(self.future, self.task)
         self.task.cancel()
         with self.assertRaises(CancelledError):
-            get_event_loop().run_until_complete(self.task)
+            await self.task
 
+    @skip
     def test_ebpf(self):
-        ti = EL3164()
-        ti.pdo_in_sz = 4
-        ti.pdo_in_off = 0xABCD
-        ti.position = 0x77
-        ti.pdo_out_sz = None
-        ti.pdo_out_off = None
-        to = EL4104()
-        to.pdo_in_sz = None
-        to.pdo_in_off = None
-        to.position = 0x55
-        to.pdo_out_sz = 2
-        to.pdo_out_off = 0x5678
-        td = EK1814()
-        td.pdo_in_sz = 1
-        td.pdo_in_off = 0x7777
-        td.position = 0x44
-        td.pdo_out_sz = 1
-        td.pdo_out_off = 0x8888
+        ti = mockTerminal(EL3164)
+        to = mockTerminal(EL4104)
+        td = mockTerminal(EK1814)
 
         class D(Device):
             ai = TerminalVar()