Skip to content
Snippets Groups Projects
Commit 656fbb95 authored by Martin Teichmann's avatar Martin Teichmann
Browse files

improve address management on ethercat bus

now terminals can be initialized with either absolute or relative only,
the other one being chosen sensibly. Also remove race condition when
searching for free addresses.
parent d74a2f29
No related branches found
No related tags found
No related merge requests found
......@@ -302,6 +302,7 @@ class EtherCat(Protocol):
"""
self.addr = (network, 0x88A4, 0, 0, b"\xff\xff\xff\xff\xff\xff")
self.wait_futures = {}
self.used_addresses = set()
async def connect(self):
"""connect to the EtherCAT loop"""
......@@ -429,14 +430,29 @@ class EtherCat(Protocol):
return no
async def find_free_address(self):
"""Find an absolute address currently not in use"""
"""Find an absolute address not in use
an address once returned by this method is assumed to be used in the
future and will never be handed out again"""
while True:
i = randint(1000, 30000)
if i in self.used_addresses:
continue
self.used_addresses.add(i)
try:
await self.roundtrip(ECCmd.FPRD, i, 0x10, "H", 0)
except EtherCatError:
return i # this address is not in use
async def assigned_address(self, position):
"""return the set adress of terminal at position, if none set one"""
ret, = await self.roundtrip(ECCmd.APRD, position, 0x10, "H", 0)
if ret != 0:
return ret
ret = await self.find_free_address()
await self.roundtrip(ECCmd.APWR, position, 0x10, "H", ret)
return ret
async def eeprom_read(self, position, start):
"""read 4 bytes from the eeprom of terminal `position` at `start`"""
while (await self.roundtrip(ECCmd.APRD, position,
......@@ -466,18 +482,28 @@ class Terminal:
def __init__(self, ethercat):
self.ec = ethercat
async def initialize(self, relative, absolute):
async def initialize(self, relative=None, absolute=None):
"""Initialize the terminal
this sets up the connection to the terminal we represent.
:param relative: the position of the terminal in the loop,
a negative number counted down from 0 for the first terminal
If None, we assume the address is already initialized
:param absolute: the number used to identify the terminal henceforth
If None take a free one
If only one parameter is given, it is taken to be an absolute
position, the terminal address is supposed to be already initialized.
This also reads the EEPROM and sets up the sync manager as defined
therein. It still leaves the terminal in the init state. """
await self.ec.roundtrip(ECCmd.APWR, relative, 0x10, "H", absolute)
therein. It still leaves the terminal in the init state.
"""
assert relative is not None or absolute is not None
if absolute is None:
absolute = await self.ec.find_free_address()
if relative is not None:
await self.ec.roundtrip(ECCmd.APWR, relative, 0x10, "H", absolute)
self.position = absolute
await self.set_state(0x11)
......
......@@ -48,12 +48,11 @@ async def info():
terms = [Terminal(ec) for t in terminals]
for t in terms:
t.ec = ec
await asyncio.gather(*(t.initialize(-i, i + 7)
await asyncio.gather(*(t.initialize(-i)
for i, t in zip(terminals, terms)))
else:
free = await ec.find_free_address()
term = Terminal(ec)
await term.initialize(-args.terminal, free)
await term.initialize(-args.terminal)
terms = [term]
for i, t in enumerate(terms, args.terminal if args.terminal else 0):
......@@ -120,20 +119,9 @@ async def eeprom():
if args.terminal is None:
return
terminals = range(await ec.count())
else:
# former terminal: don't listen!
# this does not work with all terminals, dunno why
try:
await ec.roundtrip(ECCmd.FPRW, 7, 0x10, "H", 0)
except EtherCatError:
print('fine: no not used yet')
else:
print('had to silence former listener')
terminals = [args.terminal]
t = Terminal(ec)
await t.initialize(-args.terminal, 7)
await t.initialize(-args.terminal)
if args.read or args.check is not None:
r, = unpack("<4xI", await t._eeprom_read_one(0xc))
......@@ -165,7 +153,7 @@ async def create_test():
for i in range(no):
t = Terminal()
t.ec = ec
await t.initialize(-i, await ec.find_free_address())
await t.initialize(-i)
sdo = {}
if t.has_mailbox():
await t.to_operational(MachineState.PRE_OPERATIONAL)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment