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

support SDOs in terminals

parent 0dc3ce49
No related branches found
No related tags found
No related merge requests found
......@@ -28,7 +28,7 @@ from time import time
from .arraymap import ArrayMap, ArrayGlobalVarDesc
from .ethercat import (
ECCmd, EtherCat, MachineState, Packet, Terminal, EtherCatError,
SyncManager)
Struct, SyncManager)
from .ebpf import FuncId, MemoryDesc, SubProgram, prandom
from .xdp import XDP, XDPExitCode, PacketVar as XDPPacketVar
from .bpf import (
......@@ -146,38 +146,6 @@ class PacketVar(MemoryDesc):
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:
def __set__(self, instance, value):
if isinstance(value, PacketVar):
......
......@@ -477,6 +477,50 @@ class EtherCat(Protocol):
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:
"""Represent one terminal (*SubDevice* or *slave*) in the loop"""
def __init__(self, ethercat):
......@@ -625,6 +669,22 @@ class Terminal:
await parse(parse_eeprom(self.eeprom[50]), SyncManager.IN)
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):
"""try to set the state, and return the new state"""
await self.ec.roundtrip(ECCmd.FPWR, self.position, 0x0120, "H", state)
......
......@@ -15,7 +15,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 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):
......@@ -136,10 +137,16 @@ class EL5042(EBPFTerminal):
status = ProcessDesc(0x6000, 1, "H")
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)
channel2 = Channel(0x10)
class EL6022(EBPFTerminal):
class Channel(Struct):
transmit_accept = PacketDesc(3, 0, 0)
......@@ -172,6 +179,13 @@ class EL7041(EBPFTerminal):
low_switch = ProcessDesc(0x6010, 0xd)
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):
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