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

support SDOs in terminals

parent 656fbb95
No related branches found
No related tags found
No related merge requests found
...@@ -28,7 +28,7 @@ from time import time ...@@ -28,7 +28,7 @@ from time import time
from .arraymap import ArrayMap, ArrayGlobalVarDesc from .arraymap import ArrayMap, ArrayGlobalVarDesc
from .ethercat import ( from .ethercat import (
ECCmd, EtherCat, MachineState, Packet, Terminal, EtherCatError, ECCmd, EtherCat, MachineState, Packet, Terminal, EtherCatError,
SyncManager) Struct, SyncManager)
from .ebpf import FuncId, MemoryDesc, SubProgram, prandom from .ebpf import FuncId, MemoryDesc, SubProgram, prandom
from .xdp import XDP, XDPExitCode, PacketVar as XDPPacketVar from .xdp import XDP, XDPExitCode, PacketVar as XDPPacketVar
from .bpf import ( from .bpf import (
...@@ -146,38 +146,6 @@ class PacketVar(MemoryDesc): ...@@ -146,38 +146,6 @@ class PacketVar(MemoryDesc):
self._start(device) + Packet.ETHERNET_HEADER) self._start(device) + Packet.ETHERNET_HEADER)
class Struct:
"""Define repetitive structures in a PDO
Some terminals, especially multi-channel terminals,
have repetitive structures in their PDO. Inherit from this
class to create a structure for them. Each instance
will then define one channel. It takes one parameter, which
is the offset in the CoE address space from the template
structure to the one of the channel.
"""
device = None
def __new__(cls, *args):
return StructDesc(cls, *args)
class StructDesc:
def __init__(self, struct, sm3=0, sm2=None):
self.struct = struct
if sm2 is None:
sm2 = sm3
self.position_offset = {SyncManager.OUT: sm2, SyncManager.IN: sm3}
def __get__(self, instance, owner):
if instance is None:
return self
ret = object.__new__(self.struct)
ret.position_offset = self.position_offset
ret.terminal = instance
return ret
class TerminalVar: class TerminalVar:
def __set__(self, instance, value): def __set__(self, instance, value):
if isinstance(value, PacketVar): if isinstance(value, PacketVar):
......
...@@ -477,6 +477,50 @@ class EtherCat(Protocol): ...@@ -477,6 +477,50 @@ class EtherCat(Protocol):
self.wait_futures[index].set_result(data) self.wait_futures[index].set_result(data)
class ServiceDesc:
def __init__(self, index, subidx):
self.index = index
self.subidx = subidx
class Struct:
"""Define repetitive structures in CoE objects
Some terminals, especially multi-channel terminals,
have repetitive structures in their CoE. Inherit from this
class to create a structure for them. Each instance
will then define one channel. It takes one parameter, which
is the offset in the CoE address space from the template
structure to the one of the channel.
"""
device = None
def __new__(cls, *args):
return StructDesc(cls, *args)
class StructDesc:
def __init__(self, struct, sm3=0, sm2=None):
self.struct = struct
if sm2 is None:
sm2 = sm3
self.position_offset = {SyncManager.OUT: sm2, SyncManager.IN: sm3}
def __get__(self, instance, owner):
if instance is None:
return self
if (ret := instance.__dict__.get(self.name)) is not None:
return ret
ret = object.__new__(self.struct)
ret.position_offset = self.position_offset
ret.terminal = instance
instance.__dict__[self.name] = ret
return ret
def __set_name__(self, owner, name):
self.name = name
class Terminal: class Terminal:
"""Represent one terminal (*SubDevice* or *slave*) in the loop""" """Represent one terminal (*SubDevice* or *slave*) in the loop"""
def __init__(self, ethercat): def __init__(self, ethercat):
...@@ -625,6 +669,22 @@ class Terminal: ...@@ -625,6 +669,22 @@ class Terminal:
await parse(parse_eeprom(self.eeprom[50]), SyncManager.IN) await parse(parse_eeprom(self.eeprom[50]), SyncManager.IN)
if 50 in self.eeprom else 0) if 50 in self.eeprom else 0)
async def parse_sdos(self):
sdos = {}
for cls in self.__class__.__mro__:
for k, v in cls.__dict__.items():
if isinstance(v, ServiceDesc):
setattr(self, k,
await self.read_object_entry(v.index, v.subidx))
elif isinstance(v, StructDesc):
struct = getattr(self, k)
offset = struct.position_offset[SyncManager.IN]
for kk, vv in struct.__class__.__dict__.items():
if isinstance(vv, ServiceDesc):
setattr(struct, kk,
await self.read_object_entry(
vv.index + offset, vv.subidx))
async def set_state(self, state): async def set_state(self, state):
"""try to set the state, and return the new state""" """try to set the state, and return the new state"""
await self.ec.roundtrip(ECCmd.FPWR, self.position, 0x0120, "H", state) await self.ec.roundtrip(ECCmd.FPWR, self.position, 0x0120, "H", state)
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from .ebpfcat import EBPFTerminal, PacketDesc, ProcessDesc, Struct from .ethercat import ServiceDesc, Struct
from .ebpfcat import EBPFTerminal, PacketDesc, ProcessDesc
class Generic(EBPFTerminal): class Generic(EBPFTerminal):
...@@ -136,10 +137,16 @@ class EL5042(EBPFTerminal): ...@@ -136,10 +137,16 @@ class EL5042(EBPFTerminal):
status = ProcessDesc(0x6000, 1, "H") status = ProcessDesc(0x6000, 1, "H")
invalid = ProcessDesc(0x6000, 0xE) invalid = ProcessDesc(0x6000, 0xE)
statusbits = ServiceDesc(0x8008, 2)
crc_invert = ServiceDesc(0x8008, 3)
multiturn = ServiceDesc(0x8008, 0x15)
singleturn = ServiceDesc(0x8008, 0x16)
frequency = ServiceDesc(0x8008, 0x13)
polynomial = ServiceDesc(0x8008, 0x11)
channel1 = Channel(0) channel1 = Channel(0)
channel2 = Channel(0x10) channel2 = Channel(0x10)
class EL6022(EBPFTerminal): class EL6022(EBPFTerminal):
class Channel(Struct): class Channel(Struct):
transmit_accept = PacketDesc(3, 0, 0) transmit_accept = PacketDesc(3, 0, 0)
...@@ -172,6 +179,13 @@ class EL7041(EBPFTerminal): ...@@ -172,6 +179,13 @@ class EL7041(EBPFTerminal):
low_switch = ProcessDesc(0x6010, 0xd) low_switch = ProcessDesc(0x6010, 0xd)
stepcounter = ProcessDesc(0x6010, 0x14) stepcounter = ProcessDesc(0x6010, 0x14)
max_current = ServiceDesc(0x8010, 1)
max_voltage = ServiceDesc(0x8010, 3)
coil_resistance = ServiceDesc(0x8010, 4)
motor_emf = ServiceDesc(0x8010, 5)
invLogicLim1 = ServiceDesc(0x8012, 0x30)
invLogicLim2 = ServiceDesc(0x8012, 0x31)
class EL7332(EBPFTerminal): class EL7332(EBPFTerminal):
compatibility = {(2, 0x1CA43052)} compatibility = {(2, 0x1CA43052)}
......
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