style: Format everything with black (100 characters per line)

Signed-off-by: Sven Sager <akira@narux.de>
This commit is contained in:
2023-10-27 14:44:44 +02:00
parent ba708fc145
commit ecf91f56db
8 changed files with 1164 additions and 984 deletions

View File

@@ -14,10 +14,25 @@ fuehrt das Modul bei Datenaenderung aus.
""" """
__all__ = [ __all__ = [
"IOEvent", "IOEvent",
"RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected", "run_plc", "RevPiModIO",
"RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected", "run_net_plc", "RevPiModIODriver",
"Cycletools", "EventCallback", "RevPiModIOSelected",
"ProductType", "DeviceType", "AIO", "COMPACT", "DI", "DO", "DIO", "FLAT", "MIO", "run_plc",
"RevPiNetIO",
"RevPiNetIODriver",
"RevPiNetIOSelected",
"run_net_plc",
"Cycletools",
"EventCallback",
"ProductType",
"DeviceType",
"AIO",
"COMPACT",
"DI",
"DO",
"DIO",
"FLAT",
"MIO",
] ]
__author__ = "Sven Sager <akira@revpimodio.org>" __author__ = "Sven Sager <akira@revpimodio.org>"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager"

View File

@@ -29,11 +29,11 @@ def acheck(check_type, **kwargs) -> None:
for var_name in kwargs: for var_name in kwargs:
none_okay = var_name.endswith("_noneok") none_okay = var_name.endswith("_noneok")
if not (isinstance(kwargs[var_name], check_type) or if not (isinstance(kwargs[var_name], check_type) or none_okay and kwargs[var_name] is None):
none_okay and kwargs[var_name] is None):
msg = "Argument '{0}' must be {1}{2}".format( msg = "Argument '{0}' must be {1}{2}".format(
var_name.rstrip("_noneok"), str(check_type), var_name.rstrip("_noneok"),
" or <class 'NoneType'>" if none_okay else "" str(check_type),
" or <class 'NoneType'>" if none_okay else "",
) )
raise TypeError(msg) raise TypeError(msg)

File diff suppressed because it is too large Load Diff

View File

@@ -87,12 +87,31 @@ class Cycletools:
Lampen synchron blinken zu lassen. Lampen synchron blinken zu lassen.
""" """
__slots__ = "__cycle", "__cycletime", "__ucycle", "__dict_ton", \ __slots__ = (
"__dict_tof", "__dict_tp", "__dict_change", \ "__cycle",
"_start_timer", "core", "device", \ "__cycletime",
"first", "io", "last", "var", \ "__ucycle",
"flag1c", "flag5c", "flag10c", "flag15c", "flag20c", \ "__dict_ton",
"flank5c", "flank10c", "flank15c", "flank20c" "__dict_tof",
"__dict_tp",
"__dict_change",
"_start_timer",
"core",
"device",
"first",
"io",
"last",
"var",
"flag1c",
"flag5c",
"flag10c",
"flag15c",
"flag20c",
"flank5c",
"flank10c",
"flank15c",
"flank20c",
)
def __init__(self, cycletime, revpi_object): def __init__(self, cycletime, revpi_object):
"""Init Cycletools class.""" """Init Cycletools class."""
@@ -208,16 +227,13 @@ class Cycletools:
else: else:
value = io.get_value() value = io.get_value()
return self.__dict_change[io] != value and ( return self.__dict_change[io] != value and (
value and edge == RISING or value and edge == RISING or not value and edge == FALLING
not value and edge == FALLING
) )
else: else:
if not isinstance(io, IOBase): if not isinstance(io, IOBase):
raise TypeError("parameter 'io' must be an io object") raise TypeError("parameter 'io' must be an io object")
if not (edge == BOTH or type(io.value) == bool): if not (edge == BOTH or type(io.value) == bool):
raise ValueError( raise ValueError("parameter 'edge' can be used with bit io objects only")
"parameter 'edge' can be used with bit io objects only"
)
self.__dict_change[io] = None self.__dict_change[io] = None
return False return False
@@ -283,8 +299,7 @@ class Cycletools:
:param milliseconds: Millisekunden, der Verzoegerung wenn neu gestartet :param milliseconds: Millisekunden, der Verzoegerung wenn neu gestartet
""" """
if self.__dict_ton.get(name, [-1])[0] == -1: if self.__dict_ton.get(name, [-1])[0] == -1:
self.__dict_ton[name] = \ self.__dict_ton[name] = [ceil(milliseconds / self.__cycletime), True]
[ceil(milliseconds / self.__cycletime), True]
else: else:
self.__dict_ton[name][1] = True self.__dict_ton[name][1] = True
@@ -326,8 +341,7 @@ class Cycletools:
:param milliseconds: Millisekunden, die der Impuls anstehen soll :param milliseconds: Millisekunden, die der Impuls anstehen soll
""" """
if self.__dict_tp.get(name, [-1])[0] == -1: if self.__dict_tp.get(name, [-1])[0] == -1:
self.__dict_tp[name] = \ self.__dict_tp[name] = [ceil(milliseconds / self.__cycletime), True]
[ceil(milliseconds / self.__cycletime), True]
else: else:
self.__dict_tp[name][1] = True self.__dict_tp[name][1] = True
@@ -364,9 +378,19 @@ class ProcimgWriter(Thread):
Event-Handling verwendet. Event-Handling verwendet.
""" """
__slots__ = "__dict_delay", "__eventth", "_eventqth", "__eventwork", \ __slots__ = (
"_eventq", "_modio", \ "__dict_delay",
"_refresh", "_work", "daemon", "lck_refresh", "newdata" "__eventth",
"_eventqth",
"__eventwork",
"_eventq",
"_modio",
"_refresh",
"_work",
"daemon",
"lck_refresh",
"newdata",
)
def __init__(self, parentmodio): def __init__(self, parentmodio):
"""Init ProcimgWriter class.""" """Init ProcimgWriter class."""
@@ -387,43 +411,38 @@ class ProcimgWriter(Thread):
def __check_change(self, dev) -> None: def __check_change(self, dev) -> None:
"""Findet Aenderungen fuer die Eventueberwachung.""" """Findet Aenderungen fuer die Eventueberwachung."""
for io_event in dev._dict_events: for io_event in dev._dict_events:
if dev._ba_datacp[io_event._slc_address] == dev._ba_devdata[io_event._slc_address]:
if dev._ba_datacp[io_event._slc_address] == \
dev._ba_devdata[io_event._slc_address]:
continue continue
if io_event._bitshift: if io_event._bitshift:
boolcp = dev._ba_datacp[io_event._slc_address.start] \ boolcp = dev._ba_datacp[io_event._slc_address.start] & io_event._bitshift
& io_event._bitshift boolor = dev._ba_devdata[io_event._slc_address.start] & io_event._bitshift
boolor = dev._ba_devdata[io_event._slc_address.start] \
& io_event._bitshift
if boolor == boolcp: if boolor == boolcp:
continue continue
for regfunc in dev._dict_events[io_event]: for regfunc in dev._dict_events[io_event]:
if regfunc.edge == BOTH \ if (
or regfunc.edge == RISING and boolor \ regfunc.edge == BOTH
or regfunc.edge == FALLING and not boolor: or regfunc.edge == RISING
and boolor
or regfunc.edge == FALLING
and not boolor
):
if regfunc.delay == 0: if regfunc.delay == 0:
if regfunc.as_thread: if regfunc.as_thread:
self._eventqth.put( self._eventqth.put((regfunc, io_event._name, io_event.value), False)
(regfunc, io_event._name, io_event.value),
False
)
else: else:
self._eventq.put( self._eventq.put((regfunc, io_event._name, io_event.value), False)
(regfunc, io_event._name, io_event.value),
False
)
else: else:
# Verzögertes Event in dict einfügen # Verzögertes Event in dict einfügen
tup_fire = ( tup_fire = (
regfunc, io_event._name, io_event.value, regfunc,
io_event._name,
io_event.value,
io_event, io_event,
) )
if regfunc.overwrite \ if regfunc.overwrite or tup_fire not in self.__dict_delay:
or tup_fire not in self.__dict_delay:
self.__dict_delay[tup_fire] = ceil( self.__dict_delay[tup_fire] = ceil(
regfunc.delay / 1000 / self._refresh regfunc.delay / 1000 / self._refresh
) )
@@ -431,26 +450,19 @@ class ProcimgWriter(Thread):
for regfunc in dev._dict_events[io_event]: for regfunc in dev._dict_events[io_event]:
if regfunc.delay == 0: if regfunc.delay == 0:
if regfunc.as_thread: if regfunc.as_thread:
self._eventqth.put( self._eventqth.put((regfunc, io_event._name, io_event.value), False)
(regfunc, io_event._name, io_event.value),
False
)
else: else:
self._eventq.put( self._eventq.put((regfunc, io_event._name, io_event.value), False)
(regfunc, io_event._name, io_event.value),
False
)
else: else:
# Verzögertes Event in dict einfügen # Verzögertes Event in dict einfügen
tup_fire = ( tup_fire = (
regfunc, io_event._name, io_event.value, regfunc,
io_event._name,
io_event.value,
io_event, io_event,
) )
if regfunc.overwrite \ if regfunc.overwrite or tup_fire not in self.__dict_delay:
or tup_fire not in self.__dict_delay: self.__dict_delay[tup_fire] = ceil(regfunc.delay / 1000 / self._refresh)
self.__dict_delay[tup_fire] = ceil(
regfunc.delay / 1000 / self._refresh
)
# Nach Verarbeitung aller IOs die Bytes kopieren (Lock ist noch drauf) # Nach Verarbeitung aller IOs die Bytes kopieren (Lock ist noch drauf)
dev._ba_datacp = dev._ba_devdata[:] dev._ba_datacp = dev._ba_devdata[:]
@@ -460,9 +472,7 @@ class ProcimgWriter(Thread):
while self.__eventwork: while self.__eventwork:
try: try:
tup_fireth = self._eventqth.get(timeout=1) tup_fireth = self._eventqth.get(timeout=1)
th = EventCallback( th = EventCallback(tup_fireth[0].func, tup_fireth[1], tup_fireth[2])
tup_fireth[0].func, tup_fireth[1], tup_fireth[2]
)
th.start() th.start()
self._eventqth.task_done() self._eventqth.task_done()
except queue.Empty: except queue.Empty:
@@ -524,7 +534,7 @@ class ProcimgWriter(Thread):
warnings.warn( warnings.warn(
"cycle time of {0} ms exceeded in your cycle function" "cycle time of {0} ms exceeded in your cycle function"
"".format(int(self._refresh * 1000)), "".format(int(self._refresh * 1000)),
RuntimeWarning RuntimeWarning,
) )
mrk_delay = self._refresh mrk_delay = self._refresh
# Nur durch cycleloop erreichbar - keine verzögerten Events # Nur durch cycleloop erreichbar - keine verzögerten Events
@@ -545,23 +555,25 @@ class ProcimgWriter(Thread):
# Read all device bytes, because it is shared # Read all device bytes, because it is shared
fh.seek(dev.offset) fh.seek(dev.offset)
bytesbuff[dev._slc_devoff] = \ bytesbuff[dev._slc_devoff] = fh.read(len(dev._ba_devdata))
fh.read(len(dev._ba_devdata))
if self._modio._monitoring or dev._shared_procimg: if self._modio._monitoring or dev._shared_procimg:
# Inputs und Outputs in Puffer # Inputs und Outputs in Puffer
dev._ba_devdata[:] = bytesbuff[dev._slc_devoff] dev._ba_devdata[:] = bytesbuff[dev._slc_devoff]
if self.__eventwork \ if (
and len(dev._dict_events) > 0 \ self.__eventwork
and dev._ba_datacp != dev._ba_devdata: and len(dev._dict_events) > 0
and dev._ba_datacp != dev._ba_devdata
):
self.__check_change(dev) self.__check_change(dev)
else: else:
# Inputs in Puffer, Outputs in Prozessabbild # Inputs in Puffer, Outputs in Prozessabbild
dev._ba_devdata[dev._slc_inp] = \ dev._ba_devdata[dev._slc_inp] = bytesbuff[dev._slc_inpoff]
bytesbuff[dev._slc_inpoff] if (
if self.__eventwork \ self.__eventwork
and len(dev._dict_events) > 0 \ and len(dev._dict_events) > 0
and dev._ba_datacp != dev._ba_devdata: and dev._ba_datacp != dev._ba_devdata
):
self.__check_change(dev) self.__check_change(dev)
fh.seek(dev._slc_outoff.start) fh.seek(dev._slc_outoff.start)
@@ -579,16 +591,13 @@ class ProcimgWriter(Thread):
else: else:
if not mrk_warn: if not mrk_warn:
if self._modio._debug == 0: if self._modio._debug == 0:
warnings.warn( warnings.warn("recover from io errors on process image", RuntimeWarning)
"recover from io errors on process image",
RuntimeWarning
)
else: else:
warnings.warn( warnings.warn(
"recover from io errors on process image - total " "recover from io errors on process image - total "
"count of {0} errors now" "count of {0} errors now"
"".format(self._modio._ioerror), "".format(self._modio._ioerror),
RuntimeWarning RuntimeWarning,
) )
mrk_warn = True mrk_warn = True
@@ -600,8 +609,7 @@ class ProcimgWriter(Thread):
# Verzögerte Events prüfen # Verzögerte Events prüfen
if self.__eventwork: if self.__eventwork:
for tup_fire in tuple(self.__dict_delay.keys()): for tup_fire in tuple(self.__dict_delay.keys()):
if tup_fire[0].overwrite and \ if tup_fire[0].overwrite and tup_fire[3].value != tup_fire[2]:
tup_fire[3].value != tup_fire[2]:
del self.__dict_delay[tup_fire] del self.__dict_delay[tup_fire]
else: else:
self.__dict_delay[tup_fire] -= 1 self.__dict_delay[tup_fire] -= 1
@@ -617,9 +625,8 @@ class ProcimgWriter(Thread):
# Second default_timer call include calculation time from above # Second default_timer call include calculation time from above
if default_timer() - ot > self._refresh: if default_timer() - ot > self._refresh:
warnings.warn( warnings.warn(
"io refresh time of {0} ms exceeded!" "io refresh time of {0} ms exceeded!".format(int(self._refresh * 1000)),
"".format(int(self._refresh * 1000)), RuntimeWarning,
RuntimeWarning
) )
mrk_delay = 0.0 mrk_delay = 0.0
else: else:
@@ -641,8 +648,6 @@ class ProcimgWriter(Thread):
if type(value) == int and 5 <= value <= 2000: if type(value) == int and 5 <= value <= 2000:
self._refresh = value / 1000 self._refresh = value / 1000
else: else:
raise ValueError( raise ValueError("refresh time must be 5 to 2000 milliseconds")
"refresh time must be 5 to 2000 milliseconds"
)
refresh = property(get_refresh, set_refresh) refresh = property(get_refresh, set_refresh)

View File

@@ -8,8 +8,7 @@ import struct
from re import match as rematch from re import match as rematch
from threading import Event from threading import Event
from ._internal import consttostr, RISING, FALLING, BOTH, INP, OUT, \ from ._internal import consttostr, RISING, FALLING, BOTH, INP, OUT, MEM, PROCESS_IMAGE_SIZE
MEM, PROCESS_IMAGE_SIZE
try: try:
# Funktioniert nur auf Unix # Funktioniert nur auf Unix
@@ -69,8 +68,16 @@ class IOList(object):
self.__dict_iobyte[io_del.address][io_del._bitaddress] = None self.__dict_iobyte[io_del.address][io_del._bitaddress] = None
# Do not use any() because we want to know None, not 0 # Do not use any() because we want to know None, not 0
if self.__dict_iobyte[io_del.address] == \ if self.__dict_iobyte[io_del.address] == [
[None, None, None, None, None, None, None, None]: None,
None,
None,
None,
None,
None,
None,
None,
]:
self.__dict_iobyte[io_del.address] = [] self.__dict_iobyte[io_del.address] = []
else: else:
self.__dict_iobyte[io_del.address].remove(io_del) self.__dict_iobyte[io_del.address].remove(io_del)
@@ -110,9 +117,7 @@ class IOList(object):
elif type(key) == slice: elif type(key) == slice:
return [ return [
self.__dict_iobyte[int_io] self.__dict_iobyte[int_io]
for int_io in range( for int_io in range(key.start, key.stop, 1 if key.step is None else key.step)
key.start, key.stop, 1 if key.step is None else key.step
)
] ]
else: else:
return getattr(self, key) return getattr(self, key)
@@ -143,15 +148,10 @@ class IOList(object):
def __setattr__(self, key, value): def __setattr__(self, key, value):
"""Verbietet aus Leistungsguenden das direkte Setzen von Attributen.""" """Verbietet aus Leistungsguenden das direkte Setzen von Attributen."""
if key in ( if key in ("_IOList__dict_iobyte", "_IOList__dict_iorefname"):
"_IOList__dict_iobyte",
"_IOList__dict_iorefname"
):
object.__setattr__(self, key, value) object.__setattr__(self, key, value)
else: else:
raise AttributeError( raise AttributeError("direct assignment is not supported - use .value Attribute")
"direct assignment is not supported - use .value Attribute"
)
def __private_replace_oldio_with_newio(self, io) -> None: def __private_replace_oldio_with_newio(self, io) -> None:
""" """
@@ -168,16 +168,17 @@ class IOList(object):
scan_stop = scan_start + (1 if io._length == 0 else io._length) scan_stop = scan_start + (1 if io._length == 0 else io._length)
# Defaultvalue über mehrere Bytes sammeln # Defaultvalue über mehrere Bytes sammeln
calc_defaultvalue = b'' calc_defaultvalue = b""
for i in range(scan_start, scan_stop): for i in range(scan_start, scan_stop):
for oldio in self.__dict_iobyte[i]: for oldio in self.__dict_iobyte[i]:
if type(oldio) == StructIO: if type(oldio) == StructIO:
# Hier gibt es schon einen neuen IO # Hier gibt es schon einen neuen IO
if oldio._bitshift: if oldio._bitshift:
if io._bitshift == oldio._bitshift \ if (
and io._slc_address == oldio._slc_address: io._bitshift == oldio._bitshift
and io._slc_address == oldio._slc_address
):
raise MemoryError( raise MemoryError(
"bit {0} already assigned to '{1}'".format( "bit {0} already assigned to '{1}'".format(
io._bitaddress, oldio._name io._bitaddress, oldio._name
@@ -186,9 +187,7 @@ class IOList(object):
else: else:
# Bereits überschriebene bytes sind ungültig # Bereits überschriebene bytes sind ungültig
raise MemoryError( raise MemoryError(
"new io '{0}' overlaps memory of '{1}'".format( "new io '{0}' overlaps memory of '{1}'".format(io._name, oldio._name)
io._name, oldio._name
)
) )
elif oldio is not None: elif oldio is not None:
# IOs im Speicherbereich des neuen IO merken # IOs im Speicherbereich des neuen IO merken
@@ -201,8 +200,7 @@ class IOList(object):
if io._byteorder == "little": if io._byteorder == "little":
calc_defaultvalue += oldio._defaultvalue calc_defaultvalue += oldio._defaultvalue
else: else:
calc_defaultvalue = \ calc_defaultvalue = oldio._defaultvalue + calc_defaultvalue
oldio._defaultvalue + calc_defaultvalue
# ios aus listen entfernen # ios aus listen entfernen
delattr(self, oldio._name) delattr(self, oldio._name)
@@ -211,9 +209,7 @@ class IOList(object):
# Nur bei StructIO und keiner gegebenen defaultvalue übernehmen # Nur bei StructIO und keiner gegebenen defaultvalue übernehmen
if io._bitshift: if io._bitshift:
io_byte_address = io._parentio_address - io.address io_byte_address = io._parentio_address - io.address
io._defaultvalue = bool( io._defaultvalue = bool(io._parentio_defaultvalue[io_byte_address] & io._bitshift)
io._parentio_defaultvalue[io_byte_address] & io._bitshift
)
else: else:
io._defaultvalue = calc_defaultvalue io._defaultvalue = calc_defaultvalue
@@ -226,8 +222,7 @@ class IOList(object):
if isinstance(new_io, IOBase): if isinstance(new_io, IOBase):
if hasattr(self, new_io._name): if hasattr(self, new_io._name):
raise AttributeError( raise AttributeError(
"attribute {0} already exists - can not set io" "attribute {0} already exists - can not set io".format(new_io._name)
"".format(new_io._name)
) )
if type(new_io) is StructIO: if type(new_io) is StructIO:
@@ -239,8 +234,16 @@ class IOList(object):
if new_io._bitshift: if new_io._bitshift:
if len(self.__dict_iobyte[new_io.address]) != 8: if len(self.__dict_iobyte[new_io.address]) != 8:
# "schnell" 8 Einträge erstellen da es BIT IOs sind # "schnell" 8 Einträge erstellen da es BIT IOs sind
self.__dict_iobyte[new_io.address] += \ self.__dict_iobyte[new_io.address] += [
[None, None, None, None, None, None, None, None] None,
None,
None,
None,
None,
None,
None,
None,
]
self.__dict_iobyte[new_io.address][new_io._bitaddress] = new_io self.__dict_iobyte[new_io.address][new_io._bitaddress] = new_io
else: else:
self.__dict_iobyte[new_io.address].append(new_io) self.__dict_iobyte[new_io.address].append(new_io)
@@ -289,13 +292,26 @@ class IOBase(object):
auch als <class 'int'> verwendet werden koennen. auch als <class 'int'> verwendet werden koennen.
""" """
__slots__ = "__bit_ioctl_off", "__bit_ioctl_on", "_bitaddress", \ __slots__ = (
"_bitshift", "_bitlength", "_byteorder", "_defaultvalue", \ "__bit_ioctl_off",
"_export", "_iotype", "_length", "_name", "_parentdevice", \ "__bit_ioctl_on",
"_read_only_io", "_signed", "_slc_address", "bmk" "_bitaddress",
"_bitshift",
"_bitlength",
"_byteorder",
"_defaultvalue",
"_export",
"_iotype",
"_length",
"_name",
"_parentdevice",
"_read_only_io",
"_signed",
"_slc_address",
"bmk",
)
def __init__(self, parentdevice, valuelist: list, iotype: int, def __init__(self, parentdevice, valuelist: list, iotype: int, byteorder: str, signed: bool):
byteorder: str, signed: bool):
""" """
Instantiierung der IOBase-Klasse. Instantiierung der IOBase-Klasse.
@@ -312,8 +328,7 @@ class IOBase(object):
# Bitadressen auf Bytes aufbrechen und umrechnen # Bitadressen auf Bytes aufbrechen und umrechnen
self._bitaddress = -1 if valuelist[7] == "" else int(valuelist[7]) % 8 self._bitaddress = -1 if valuelist[7] == "" else int(valuelist[7]) % 8
self._bitshift = None if self._bitaddress == -1 \ self._bitshift = None if self._bitaddress == -1 else 1 << self._bitaddress
else 1 << self._bitaddress
# Längenberechnung # Längenberechnung
self._bitlength = int(valuelist[2]) self._bitlength = int(valuelist[2])
@@ -333,9 +348,7 @@ class IOBase(object):
if self._bitshift: if self._bitshift:
# Höhere Bits als 7 auf nächste Bytes umbrechen # Höhere Bits als 7 auf nächste Bytes umbrechen
int_startaddress += int(int(valuelist[7]) / 8) int_startaddress += int(int(valuelist[7]) / 8)
self._slc_address = slice( self._slc_address = slice(int_startaddress, int_startaddress + 1)
int_startaddress, int_startaddress + 1
)
# Defaultvalue ermitteln, sonst False # Defaultvalue ermitteln, sonst False
if valuelist[1] is None and type(self) == StructIO: if valuelist[1] is None and type(self) == StructIO:
@@ -347,14 +360,10 @@ class IOBase(object):
self._defaultvalue = False self._defaultvalue = False
# Ioctl für Bitsetzung setzen # Ioctl für Bitsetzung setzen
self.__bit_ioctl_off = struct.pack( self.__bit_ioctl_off = struct.pack("<HB", self._get_address(), self._bitaddress)
"<HB", self._get_address(), self._bitaddress self.__bit_ioctl_on = self.__bit_ioctl_off + b"\x01"
)
self.__bit_ioctl_on = self.__bit_ioctl_off + b'\x01'
else: else:
self._slc_address = slice( self._slc_address = slice(int_startaddress, int_startaddress + self._length)
int_startaddress, int_startaddress + self._length
)
if str(valuelist[1]).isdigit(): if str(valuelist[1]).isdigit():
# Defaultvalue aus Zahl in Bytes umrechnen # Defaultvalue aus Zahl in Bytes umrechnen
self._defaultvalue = int(valuelist[1]).to_bytes( self._defaultvalue = int(valuelist[1]).to_bytes(
@@ -382,8 +391,7 @@ class IOBase(object):
try: try:
buff = valuelist[1].encode("ASCII") buff = valuelist[1].encode("ASCII")
if len(buff) <= self._length: if len(buff) <= self._length:
self._defaultvalue = \ self._defaultvalue = buff + bytes(self._length - len(buff))
buff + bytes(self._length - len(buff))
except Exception: except Exception:
pass pass
@@ -394,10 +402,7 @@ class IOBase(object):
:return: <class 'bool'> Nur False wenn False oder 0 sonst True :return: <class 'bool'> Nur False wenn False oder 0 sonst True
""" """
if self._bitshift: if self._bitshift:
return bool( return bool(self._parentdevice._ba_devdata[self._slc_address.start] & self._bitshift)
self._parentdevice._ba_devdata[self._slc_address.start]
& self._bitshift
)
else: else:
return any(self._parentdevice._ba_devdata[self._slc_address]) return any(self._parentdevice._ba_devdata[self._slc_address])
@@ -406,8 +411,7 @@ class IOBase(object):
# Inline get_value() # Inline get_value()
if self._bitshift: if self._bitshift:
return bool( return bool(
self._parentdevice._ba_devdata[self._slc_address.start] self._parentdevice._ba_devdata[self._slc_address.start] & self._bitshift
& self._bitshift
) )
else: else:
return bytes(self._parentdevice._ba_devdata[self._slc_address]) return bytes(self._parentdevice._ba_devdata[self._slc_address])
@@ -430,8 +434,9 @@ class IOBase(object):
""" """
return self._name return self._name
def __reg_xevent(self, func, delay: int, edge: int, as_thread: bool, def __reg_xevent(
overwrite: bool, prefire: bool) -> None: self, func, delay: int, edge: int, as_thread: bool, overwrite: bool, prefire: bool
) -> None:
""" """
Verwaltet reg_event und reg_timerevent. Verwaltet reg_event und reg_timerevent.
@@ -444,26 +449,19 @@ class IOBase(object):
""" """
# Prüfen ob Funktion callable ist # Prüfen ob Funktion callable ist
if not callable(func): if not callable(func):
raise ValueError( raise ValueError("registered function '{0}' is not callable".format(func))
"registered function '{0}' is not callable".format(func)
)
if type(delay) != int or delay < 0: if type(delay) != int or delay < 0:
raise ValueError( raise ValueError("'delay' must be <class 'int'> and greater or equal 0")
"'delay' must be <class 'int'> and greater or equal 0"
)
if edge != BOTH and not self._bitshift: if edge != BOTH and not self._bitshift:
raise ValueError( raise ValueError("parameter 'edge' can be used with bit io objects only")
"parameter 'edge' can be used with bit io objects only"
)
if prefire and self._parentdevice._modio._looprunning: if prefire and self._parentdevice._modio._looprunning:
raise RuntimeError( raise RuntimeError("prefire can not be used if mainloop is running")
"prefire can not be used if mainloop is running"
)
if self not in self._parentdevice._dict_events: if self not in self._parentdevice._dict_events:
with self._parentdevice._filelock: with self._parentdevice._filelock:
self._parentdevice._dict_events[self] = \ self._parentdevice._dict_events[self] = [
[IOEvent(func, edge, as_thread, delay, overwrite, prefire)] IOEvent(func, edge, as_thread, delay, overwrite, prefire)
]
else: else:
# Prüfen ob Funktion schon registriert ist # Prüfen ob Funktion schon registriert ist
for regfunc in self._parentdevice._dict_events[self]: for regfunc in self._parentdevice._dict_events[self]:
@@ -476,10 +474,7 @@ class IOBase(object):
raise RuntimeError( raise RuntimeError(
"io '{0}' with function '{1}' already in list " "io '{0}' with function '{1}' already in list "
"with edge '{2}' - edge '{3}' not allowed anymore" "with edge '{2}' - edge '{3}' not allowed anymore"
"".format( "".format(self._name, func, consttostr(regfunc.edge), consttostr(edge))
self._name, func,
consttostr(regfunc.edge), consttostr(edge)
)
) )
else: else:
raise RuntimeError( raise RuntimeError(
@@ -490,9 +485,7 @@ class IOBase(object):
elif regfunc.edge == edge: elif regfunc.edge == edge:
raise RuntimeError( raise RuntimeError(
"io '{0}' with function '{1}' for given edge '{2}' " "io '{0}' with function '{1}' for given edge '{2}' "
"already in list".format( "already in list".format(self._name, func, consttostr(edge))
self._name, func, consttostr(edge)
)
) )
# Eventfunktion einfügen # Eventfunktion einfügen
@@ -548,9 +541,7 @@ class IOBase(object):
if self._bitshift: if self._bitshift:
# Write single bit to process image # Write single bit to process image
value = \ value = self._parentdevice._ba_devdata[self._slc_address.start] & self._bitshift
self._parentdevice._ba_devdata[self._slc_address.start] & \
self._bitshift
if self._parentdevice._modio._run_on_pi: if self._parentdevice._modio._run_on_pi:
# IOCTL auf dem RevPi # IOCTL auf dem RevPi
with self._parentdevice._modio._myfh_lck: with self._parentdevice._modio._myfh_lck:
@@ -559,8 +550,7 @@ class IOBase(object):
ioctl( ioctl(
self._parentdevice._modio._myfh, self._parentdevice._modio._myfh,
19216, 19216,
self.__bit_ioctl_on if value self.__bit_ioctl_on if value else self.__bit_ioctl_off,
else self.__bit_ioctl_off
) )
except Exception as e: except Exception as e:
self._parentdevice._modio._gotioerror("ioset", e) self._parentdevice._modio._gotioerror("ioset", e)
@@ -572,12 +562,10 @@ class IOBase(object):
try: try:
self._parentdevice._modio._myfh.ioctl( self._parentdevice._modio._myfh.ioctl(
19216, 19216,
self.__bit_ioctl_on if value self.__bit_ioctl_on if value else self.__bit_ioctl_off,
else self.__bit_ioctl_off
) )
except Exception as e: except Exception as e:
self._parentdevice._modio._gotioerror( self._parentdevice._modio._gotioerror("net_ioset", e)
"net_ioset", e)
return False return False
else: else:
@@ -586,8 +574,7 @@ class IOBase(object):
# Set value durchführen (Funktion K+16) # Set value durchführen (Funktion K+16)
self._parentdevice._modio._simulate_ioctl( self._parentdevice._modio._simulate_ioctl(
19216, 19216,
self.__bit_ioctl_on if value self.__bit_ioctl_on if value else self.__bit_ioctl_off,
else self.__bit_ioctl_off
) )
except Exception as e: except Exception as e:
self._parentdevice._modio._gotioerror("file_ioset", e) self._parentdevice._modio._gotioerror("file_ioset", e)
@@ -598,9 +585,7 @@ class IOBase(object):
value = bytes(self._parentdevice._ba_devdata[self._slc_address]) value = bytes(self._parentdevice._ba_devdata[self._slc_address])
with self._parentdevice._modio._myfh_lck: with self._parentdevice._modio._myfh_lck:
try: try:
self._parentdevice._modio._myfh.seek( self._parentdevice._modio._myfh.seek(self._get_address())
self._get_address()
)
self._parentdevice._modio._myfh.write(value) self._parentdevice._modio._myfh.write(value)
if self._parentdevice._modio._buffedwrite: if self._parentdevice._modio._buffedwrite:
self._parentdevice._modio._myfh.flush() self._parentdevice._modio._myfh.flush()
@@ -625,15 +610,11 @@ class IOBase(object):
:return: IO-Wert als <class 'bytes'> oder <class 'bool'> :return: IO-Wert als <class 'bytes'> oder <class 'bool'>
""" """
if self._bitshift: if self._bitshift:
return bool( return bool(self._parentdevice._ba_devdata[self._slc_address.start] & self._bitshift)
self._parentdevice._ba_devdata[self._slc_address.start]
& self._bitshift
)
else: else:
return bytes(self._parentdevice._ba_devdata[self._slc_address]) return bytes(self._parentdevice._ba_devdata[self._slc_address])
def reg_event( def reg_event(self, func, delay=0, edge=BOTH, as_thread=False, prefire=False):
self, func, delay=0, edge=BOTH, as_thread=False, prefire=False):
""" """
Registriert fuer IO ein Event bei der Eventueberwachung. Registriert fuer IO ein Event bei der Eventueberwachung.
@@ -652,8 +633,7 @@ class IOBase(object):
""" """
self.__reg_xevent(func, delay, edge, as_thread, True, prefire) self.__reg_xevent(func, delay, edge, as_thread, True, prefire)
def reg_timerevent( def reg_timerevent(self, func, delay, edge=BOTH, as_thread=False, prefire=False):
self, func, delay, edge=BOTH, as_thread=False, prefire=False):
""" """
Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt. Registriert fuer IO einen Timer, welcher nach delay func ausfuehrt.
@@ -685,20 +665,13 @@ class IOBase(object):
if self._iotype == INP: if self._iotype == INP:
if self._parentdevice._modio._simulator: if self._parentdevice._modio._simulator:
raise RuntimeError( raise RuntimeError(
"can not write to output '{0}' in simulator mode" "can not write to output '{0}' in simulator mode".format(self._name)
"".format(self._name)
) )
else: else:
raise RuntimeError( raise RuntimeError("can not write to input '{0}'".format(self._name))
"can not write to input '{0}'".format(self._name)
)
elif self._iotype == MEM: elif self._iotype == MEM:
raise RuntimeError( raise RuntimeError("can not write to memory '{0}'".format(self._name))
"can not write to memory '{0}'".format(self._name) raise RuntimeError("the io object '{0}' is read only".format(self._name))
)
raise RuntimeError(
"the io object '{0}' is read only".format(self._name)
)
if self._bitshift: if self._bitshift:
# Versuchen egal welchen Typ in Bool zu konvertieren # Versuchen egal welchen Typ in Bool zu konvertieren
@@ -722,8 +695,7 @@ class IOBase(object):
int_byte -= self._bitshift int_byte -= self._bitshift
# Zurückschreiben wenn verändert # Zurückschreiben wenn verändert
self._parentdevice._ba_devdata[self._slc_address.start] = \ self._parentdevice._ba_devdata[self._slc_address.start] = int_byte
int_byte
self._parentdevice._filelock.release() self._parentdevice._filelock.release()
@@ -738,9 +710,7 @@ class IOBase(object):
if self._length != len(value): if self._length != len(value):
raise ValueError( raise ValueError(
"'{0}' requires a <class 'bytes'> object of " "'{0}' requires a <class 'bytes'> object of "
"length {1}, but {2} was given".format( "length {1}, but {2} was given".format(self._name, self._length, len(value))
self._name, self._length, len(value)
)
) )
if self._parentdevice._shared_procimg: if self._parentdevice._shared_procimg:
@@ -764,8 +734,7 @@ class IOBase(object):
else: else:
newlist = [] newlist = []
for regfunc in self._parentdevice._dict_events[self]: for regfunc in self._parentdevice._dict_events[self]:
if regfunc.func != func or edge is not None \ if regfunc.func != func or edge is not None and regfunc.edge != edge:
and regfunc.edge != edge:
newlist.append(regfunc) newlist.append(regfunc)
# Wenn Funktionen übrig bleiben, diese übernehmen # Wenn Funktionen übrig bleiben, diese übernehmen
@@ -832,17 +801,11 @@ class IOBase(object):
"revpimodio2.FALLING or revpimodio2.BOTH" "revpimodio2.FALLING or revpimodio2.BOTH"
) )
if not (exitevent is None or type(exitevent) == Event): if not (exitevent is None or type(exitevent) == Event):
raise TypeError( raise TypeError("parameter 'exitevent' must be <class 'threading.Event'>")
"parameter 'exitevent' must be <class 'threading.Event'>"
)
if type(timeout) != int or timeout < 0: if type(timeout) != int or timeout < 0:
raise ValueError( raise ValueError("parameter 'timeout' must be <class 'int'> and greater than 0")
"parameter 'timeout' must be <class 'int'> and greater than 0"
)
if edge != BOTH and not self._bitshift: if edge != BOTH and not self._bitshift:
raise ValueError( raise ValueError("parameter 'edge' can be used with bit Inputs only")
"parameter 'edge' can be used with bit Inputs only"
)
# Abbruchwert prüfen # Abbruchwert prüfen
if okvalue == self.value: if okvalue == self.value:
@@ -858,23 +821,27 @@ class IOBase(object):
exitevent = Event() exitevent = Event()
flt_timecount = 0 if bool_timecount else -1 flt_timecount = 0 if bool_timecount else -1
while not self._parentdevice._modio._waitexit.is_set() \ while (
and not exitevent.is_set() \ not self._parentdevice._modio._waitexit.is_set()
and flt_timecount < timeout: and not exitevent.is_set()
and flt_timecount < timeout
):
if self._parentdevice._modio._imgwriter.newdata.wait(2.5): if self._parentdevice._modio._imgwriter.newdata.wait(2.5):
self._parentdevice._modio._imgwriter.newdata.clear() self._parentdevice._modio._imgwriter.newdata.clear()
if val_start != self.value: if val_start != self.value:
if edge == BOTH \ if (
or edge == RISING and not val_start \ edge == BOTH
or edge == FALLING and val_start: or edge == RISING
and not val_start
or edge == FALLING
and val_start
):
return 0 return 0
else: else:
val_start = not val_start val_start = not val_start
if bool_timecount: if bool_timecount:
flt_timecount += \ flt_timecount += self._parentdevice._modio._imgwriter._refresh
self._parentdevice._modio._imgwriter._refresh
elif bool_timecount: elif bool_timecount:
flt_timecount += 2.5 flt_timecount += 2.5
@@ -922,7 +889,7 @@ class IntIO(IOBase):
return int.from_bytes( return int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed,
) )
def __call__(self, value=None): def __call__(self, value=None):
@@ -931,16 +898,18 @@ class IntIO(IOBase):
return int.from_bytes( return int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed,
) )
else: else:
# Inline from set_intvalue() # Inline from set_intvalue()
if type(value) == int: if type(value) == int:
self.set_value(value.to_bytes( self.set_value(
value.to_bytes(
self._length, self._length,
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed,
)) )
)
else: else:
raise TypeError( raise TypeError(
"'{0}' need a <class 'int'> value, but {1} was given" "'{0}' need a <class 'int'> value, but {1} was given"
@@ -983,9 +952,7 @@ class IntIO(IOBase):
:return: <class 'int'> Defaultvalue :return: <class 'int'> Defaultvalue
""" """
return int.from_bytes( return int.from_bytes(self._defaultvalue, byteorder=self._byteorder, signed=self._signed)
self._defaultvalue, byteorder=self._byteorder, signed=self._signed
)
def get_intvalue(self) -> int: def get_intvalue(self) -> int:
""" """
@@ -996,7 +963,7 @@ class IntIO(IOBase):
return int.from_bytes( return int.from_bytes(
self._parentdevice._ba_devdata[self._slc_address], self._parentdevice._ba_devdata[self._slc_address],
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed,
) )
def set_intvalue(self, value: int) -> None: def set_intvalue(self, value: int) -> None:
@@ -1006,11 +973,13 @@ class IntIO(IOBase):
:param value: <class 'int'> Wert :param value: <class 'int'> Wert
""" """
if type(value) == int: if type(value) == int:
self.set_value(value.to_bytes( self.set_value(
value.to_bytes(
self._length, self._length,
byteorder=self._byteorder, byteorder=self._byteorder,
signed=self._signed signed=self._signed,
)) )
)
else: else:
raise TypeError( raise TypeError(
"'{0}' need a <class 'int'> value, but {1} was given" "'{0}' need a <class 'int'> value, but {1} was given"
@@ -1028,9 +997,7 @@ class IntIOCounter(IntIO):
__slots__ = ("__ioctl_arg",) __slots__ = ("__ioctl_arg",)
def __init__( def __init__(self, counter_id, parentdevice, valuelist, iotype, byteorder, signed):
self, counter_id,
parentdevice, valuelist, iotype, byteorder, signed):
""" """
Instantiierung der IntIOCounter-Klasse. Instantiierung der IntIOCounter-Klasse.
@@ -1044,10 +1011,11 @@ class IntIOCounter(IntIO):
# Deviceposition + leer + Counter_ID # Deviceposition + leer + Counter_ID
# ID-Bits: 7|6|5|4|3|2|1|0|15|14|13|12|11|10|9|8 # ID-Bits: 7|6|5|4|3|2|1|0|15|14|13|12|11|10|9|8
self.__ioctl_arg = \ self.__ioctl_arg = (
parentdevice._position.to_bytes(1, "little") \ parentdevice._position.to_bytes(1, "little")
+ b'\x00' \ + b"\x00"
+ (1 << counter_id).to_bytes(2, "little") + (1 << counter_id).to_bytes(2, "little")
)
""" """
IOCTL fuellt dieses struct, welches durch padding im Speicher nach IOCTL fuellt dieses struct, welches durch padding im Speicher nach
@@ -1067,23 +1035,16 @@ class IntIOCounter(IntIO):
def reset(self) -> None: def reset(self) -> None:
"""Setzt den Counter des Inputs zurueck.""" """Setzt den Counter des Inputs zurueck."""
if self._parentdevice._modio._monitoring: if self._parentdevice._modio._monitoring:
raise RuntimeError( raise RuntimeError("can not reset counter, while system is in monitoring mode")
"can not reset counter, while system is in monitoring mode"
)
if self._parentdevice._modio._simulator: if self._parentdevice._modio._simulator:
raise RuntimeError( raise RuntimeError("can not reset counter, while system is in simulator mode")
"can not reset counter, while system is in simulator mode"
)
if self._parentdevice._modio._run_on_pi: if self._parentdevice._modio._run_on_pi:
# IOCTL auf dem RevPi # IOCTL auf dem RevPi
with self._parentdevice._modio._myfh_lck: with self._parentdevice._modio._myfh_lck:
try: try:
# Counter reset durchführen (Funktion K+20) # Counter reset durchführen (Funktion K+20)
ioctl( ioctl(self._parentdevice._modio._myfh, 19220, self.__ioctl_arg)
self._parentdevice._modio._myfh,
19220, self.__ioctl_arg
)
except Exception as e: except Exception as e:
self._parentdevice._modio._gotioerror("iorst", e) self._parentdevice._modio._gotioerror("iorst", e)
@@ -1091,9 +1052,7 @@ class IntIOCounter(IntIO):
# IOCTL über Netzwerk # IOCTL über Netzwerk
with self._parentdevice._modio._myfh_lck: with self._parentdevice._modio._myfh_lck:
try: try:
self._parentdevice._modio._myfh.ioctl( self._parentdevice._modio._myfh.ioctl(19220, self.__ioctl_arg)
19220, self.__ioctl_arg
)
except Exception as e: except Exception as e:
self._parentdevice._modio._gotioerror("net_iorst", e) self._parentdevice._modio._gotioerror("net_iorst", e)
@@ -1101,9 +1060,7 @@ class IntIOCounter(IntIO):
# IOCTL in Datei simulieren # IOCTL in Datei simulieren
try: try:
# Set value durchführen (Funktion K+20) # Set value durchführen (Funktion K+20)
self._parentdevice._modio._simulate_ioctl( self._parentdevice._modio._simulate_ioctl(19220, self.__ioctl_arg)
19220, self.__ioctl_arg
)
except Exception as e: except Exception as e:
self._parentdevice._modio._gotioerror("file_iorst", e) self._parentdevice._modio._gotioerror("file_iorst", e)
@@ -1153,12 +1110,7 @@ class IntIOReplaceable(IntIO):
`<https://docs.python.org/3/library/struct.html#format-characters>`_ `<https://docs.python.org/3/library/struct.html#format-characters>`_
""" """
# StructIO erzeugen # StructIO erzeugen
io_new = StructIO( io_new = StructIO(self, name, frm, **kwargs)
self,
name,
frm,
**kwargs
)
# StructIO in IO-Liste einfügen # StructIO in IO-Liste einfügen
self._parentdevice._modio.io._private_register_new_io_object(io_new) self._parentdevice._modio.io._private_register_new_io_object(io_new)
@@ -1170,7 +1122,7 @@ class IntIOReplaceable(IntIO):
reg_event, reg_event,
kwargs.get("delay", 0), kwargs.get("delay", 0),
kwargs.get("edge", BOTH), kwargs.get("edge", BOTH),
kwargs.get("as_thread", False) kwargs.get("as_thread", False),
) )
@@ -1182,8 +1134,14 @@ class StructIO(IOBase):
bereit. Der struct-Formatwert wird bei der Instantiierung festgelegt. bereit. Der struct-Formatwert wird bei der Instantiierung festgelegt.
""" """
__slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \ __slots__ = (
"_parentio_length", "_parentio_name", "_wordorder" "__frm",
"_parentio_address",
"_parentio_defaultvalue",
"_parentio_length",
"_parentio_name",
"_wordorder",
)
def __init__(self, parentio, name: str, frm: str, **kwargs): def __init__(self, parentio, name: str, frm: str, **kwargs):
""" """
@@ -1215,15 +1173,12 @@ class StructIO(IOBase):
if frm == "?": if frm == "?":
if self._wordorder: if self._wordorder:
raise ValueError( raise ValueError("you can not use wordorder for bit based ios")
"you can not use wordorder for bit based ios"
)
bitaddress = kwargs.get("bit", 0) bitaddress = kwargs.get("bit", 0)
max_bits = parentio._length * 8 max_bits = parentio._length * 8
if not (0 <= bitaddress < max_bits): if not (0 <= bitaddress < max_bits):
raise ValueError( raise ValueError(
"bitaddress must be a value between 0 and {0}" "bitaddress must be a value between 0 and {0}".format(max_bits - 1)
"".format(max_bits - 1)
) )
bitlength = 1 bitlength = 1
@@ -1246,8 +1201,7 @@ class StructIO(IOBase):
raise ValueError("wordorder must be 'little' or 'big'") raise ValueError("wordorder must be 'little' or 'big'")
if byte_length % 2 != 0: if byte_length % 2 != 0:
raise ValueError( raise ValueError(
"the byte length of new io must must be even to " "the byte length of new io must must be even to use wordorder"
"use wordorder"
) )
# [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress] # [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress]
@@ -1260,7 +1214,7 @@ class StructIO(IOBase):
False, False,
str(parentio._slc_address.start).rjust(4, "0"), str(parentio._slc_address.start).rjust(4, "0"),
kwargs.get("bmk", ""), kwargs.get("bmk", ""),
bitaddress bitaddress,
] ]
else: else:
raise ValueError( raise ValueError(
@@ -1270,11 +1224,7 @@ class StructIO(IOBase):
# Basisklasse instantiieren # Basisklasse instantiieren
super().__init__( super().__init__(
parentio._parentdevice, parentio._parentdevice, valuelist, parentio._iotype, byteorder, frm == frm.lower()
valuelist,
parentio._iotype,
byteorder,
frm == frm.lower()
) )
self.__frm = bofrm + frm self.__frm = bofrm + frm
if "export" in kwargs: if "export" in kwargs:
@@ -1286,13 +1236,11 @@ class StructIO(IOBase):
self._export = parentio._export self._export = parentio._export
# Platz für neuen IO prüfen # Platz für neuen IO prüfen
if not (self._slc_address.start >= if not (
parentio._parentdevice._dict_slc[parentio._iotype].start and self._slc_address.start >= parentio._parentdevice._dict_slc[parentio._iotype].start
self._slc_address.stop <= and self._slc_address.stop <= parentio._parentdevice._dict_slc[parentio._iotype].stop
parentio._parentdevice._dict_slc[parentio._iotype].stop): ):
raise BufferError( raise BufferError("registered value does not fit process image scope")
"registered value does not fit process image scope"
)
def __call__(self, value=None): def __call__(self, value=None):
if value is None: if value is None:
@@ -1310,9 +1258,7 @@ class StructIO(IOBase):
if self._bitshift: if self._bitshift:
self.set_value(value) self.set_value(value)
elif self._wordorder == "little" and self._length > 2: elif self._wordorder == "little" and self._length > 2:
self.set_value( self.set_value(self._swap_word_order(struct.pack(self.__frm, value)))
self._swap_word_order(struct.pack(self.__frm, value))
)
else: else:
self.set_value(struct.pack(self.__frm, value)) self.set_value(struct.pack(self.__frm, value))
@@ -1343,8 +1289,10 @@ class StructIO(IOBase):
array_length = len(bytes_to_swap) array_length = len(bytes_to_swap)
swap_array = bytearray(bytes_to_swap) swap_array = bytearray(bytes_to_swap)
for i in range(0, array_length // 2, 2): for i in range(0, array_length // 2, 2):
swap_array[-i - 2:array_length - i], swap_array[i:i + 2] = \ swap_array[-i - 2 : array_length - i], swap_array[i : i + 2] = (
swap_array[i:i + 2], swap_array[-i - 2:array_length - i] swap_array[i : i + 2],
swap_array[-i - 2 : array_length - i],
)
return bytes(swap_array) return bytes(swap_array)
def get_structdefaultvalue(self): def get_structdefaultvalue(self):
@@ -1394,9 +1342,7 @@ class StructIO(IOBase):
if self._bitshift: if self._bitshift:
self.set_value(value) self.set_value(value)
elif self._wordorder == "little" and self._length > 2: elif self._wordorder == "little" and self._length > 2:
self.set_value( self.set_value(self._swap_word_order(struct.pack(self.__frm, value)))
self._swap_word_order(struct.pack(self.__frm, value))
)
else: else:
self.set_value(struct.pack(self.__frm, value)) self.set_value(struct.pack(self.__frm, value))
@@ -1422,7 +1368,7 @@ class MemIO(IOBase):
if self._bitlength > 64: if self._bitlength > 64:
# STRING # STRING
try: try:
val = val.strip(b'\x00').decode() val = val.strip(b"\x00").decode()
except Exception: except Exception:
pass pass
return val return val

View File

@@ -65,20 +65,55 @@ class RevPiModIO(object):
Device Positionen oder Device Namen. Device Positionen oder Device Namen.
""" """
__slots__ = "__cleanupfunc", \ __slots__ = (
"_autorefresh", "_buffedwrite", "_configrsc", "_debug", "_devselect", \ "__cleanupfunc",
"_exit", "_exit_level", "_imgwriter", "_ioerror", \ "_autorefresh",
"_length", "_looprunning", "_lst_devselect", "_lst_refresh", \ "_buffedwrite",
"_maxioerrors", "_monitoring", "_myfh", "_myfh_lck", \ "_configrsc",
"_procimg", "_replace_io_file", "_run_on_pi", \ "_debug",
"_set_device_based_cycle_time", "_simulator", "_init_shared_procimg", \ "_devselect",
"_syncoutputs", "_th_mainloop", "_waitexit", \ "_exit",
"app", "core", "device", "exitsignal", "io", "summary" "_exit_level",
"_imgwriter",
"_ioerror",
"_length",
"_looprunning",
"_lst_devselect",
"_lst_refresh",
"_maxioerrors",
"_monitoring",
"_myfh",
"_myfh_lck",
"_procimg",
"_replace_io_file",
"_run_on_pi",
"_set_device_based_cycle_time",
"_simulator",
"_init_shared_procimg",
"_syncoutputs",
"_th_mainloop",
"_waitexit",
"app",
"core",
"device",
"exitsignal",
"io",
"summary",
)
def __init__( def __init__(
self, autorefresh=False, monitoring=False, syncoutputs=True, self,
procimg=None, configrsc=None, simulator=False, debug=True, autorefresh=False,
replace_io_file=None, shared_procimg=False, direct_output=False): monitoring=False,
syncoutputs=True,
procimg=None,
configrsc=None,
simulator=False,
debug=True,
replace_io_file=None,
shared_procimg=False,
direct_output=False,
):
""" """
Instantiiert die Grundfunktionen. Instantiiert die Grundfunktionen.
@@ -96,20 +131,27 @@ class RevPiModIO(object):
""" """
# Parameterprüfung # Parameterprüfung
acheck( acheck(
bool, autorefresh=autorefresh, monitoring=monitoring, bool,
syncoutputs=syncoutputs, simulator=simulator, debug=debug, autorefresh=autorefresh,
shared_procimg=shared_procimg, direct_output=direct_output monitoring=monitoring,
syncoutputs=syncoutputs,
simulator=simulator,
debug=debug,
shared_procimg=shared_procimg,
direct_output=direct_output,
) )
acheck( acheck(
str, procimg_noneok=procimg, configrsc_noneok=configrsc, str,
replace_io_file_noneok=replace_io_file procimg_noneok=procimg,
configrsc_noneok=configrsc,
replace_io_file_noneok=replace_io_file,
) )
# TODO: Remove in next release # TODO: Remove in next release
if direct_output: if direct_output:
warnings.warn(DeprecationWarning( warnings.warn(
"direct_output is deprecated - use shared_procimg instead!" DeprecationWarning("direct_output is deprecated - use shared_procimg instead!")
)) )
self._autorefresh = autorefresh self._autorefresh = autorefresh
self._configrsc = configrsc self._configrsc = configrsc
@@ -233,13 +275,11 @@ class RevPiModIO(object):
# Apply device filter # Apply device filter
if self._devselect.values: if self._devselect.values:
# Check for supported types in values # Check for supported types in values
for dev in self._devselect.values: for dev in self._devselect.values:
if type(dev) not in (int, str): if type(dev) not in (int, str):
raise ValueError( raise ValueError(
"need device position as <class 'int'> or " "need device position as <class 'int'> or device name as <class 'str'>"
"device name as <class 'str'>"
) )
lst_devices = [] lst_devices = []
@@ -253,8 +293,10 @@ class RevPiModIO(object):
continue continue
else: else:
# Auto search depending of value item type # Auto search depending of value item type
if not (dev["name"] in self._devselect.values if not (
or int(dev["position"]) in self._devselect.values): dev["name"] in self._devselect.values
or int(dev["position"]) in self._devselect.values
):
continue continue
lst_devices.append(dev) lst_devices.append(dev)
@@ -269,7 +311,6 @@ class RevPiModIO(object):
# Devices initialisieren # Devices initialisieren
err_names_check = {} err_names_check = {}
for device in sorted(lst_devices, key=lambda x: x["offset"]): for device in sorted(lst_devices, key=lambda x: x["offset"]):
# VDev alter piCtory Versionen auf KUNBUS-Standard ändern # VDev alter piCtory Versionen auf KUNBUS-Standard ändern
if device["position"] == "adap.": if device["position"] == "adap.":
device["position"] = 64 device["position"] = 64
@@ -281,64 +322,42 @@ class RevPiModIO(object):
pt = int(device["productType"]) pt = int(device["productType"])
if pt == ProductType.REVPI_CORE: if pt == ProductType.REVPI_CORE:
# RevPi Core # RevPi Core
dev_new = devicemodule.Core( dev_new = devicemodule.Core(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
self.core = dev_new self.core = dev_new
elif pt == ProductType.REVPI_CONNECT: elif pt == ProductType.REVPI_CONNECT:
# RevPi Connect # RevPi Connect
dev_new = devicemodule.Connect( dev_new = devicemodule.Connect(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
self.core = dev_new self.core = dev_new
elif pt == ProductType.REVPI_CONNECT_4: elif pt == ProductType.REVPI_CONNECT_4:
# RevPi Connect 4 # RevPi Connect 4
dev_new = devicemodule.Connect4( dev_new = devicemodule.Connect4(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
self.core = dev_new self.core = dev_new
elif pt == ProductType.REVPI_COMPACT: elif pt == ProductType.REVPI_COMPACT:
# RevPi Compact # RevPi Compact
dev_new = devicemodule.Compact( dev_new = devicemodule.Compact(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
self.core = dev_new self.core = dev_new
elif pt == ProductType.REVPI_FLAT: elif pt == ProductType.REVPI_FLAT:
# RevPi Flat # RevPi Flat
dev_new = devicemodule.Flat( dev_new = devicemodule.Flat(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
self.core = dev_new self.core = dev_new
else: else:
# Base immer als Fallback verwenden # Base immer als Fallback verwenden
dev_new = devicemodule.Base( dev_new = devicemodule.Base(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
elif device["type"] == DeviceType.LEFT_RIGHT: elif device["type"] == DeviceType.LEFT_RIGHT:
# IOs # IOs
pt = int(device["productType"]) pt = int(device["productType"])
if pt == ProductType.DIO \ if pt == ProductType.DIO or pt == ProductType.DI or pt == ProductType.DO:
or pt == ProductType.DI \
or pt == ProductType.DO:
# DIO / DI / DO # DIO / DI / DO
dev_new = devicemodule.DioModule( dev_new = devicemodule.DioModule(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
else: else:
# Alle anderen IO-Devices # Alle anderen IO-Devices
dev_new = devicemodule.Device( dev_new = devicemodule.Device(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
elif device["type"] == DeviceType.VIRTUAL: elif device["type"] == DeviceType.VIRTUAL:
# Virtuals # Virtuals
dev_new = devicemodule.Virtual( dev_new = devicemodule.Virtual(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
elif device["type"] == DeviceType.EDGE: elif device["type"] == DeviceType.EDGE:
# Gateways # Gateways
dev_new = devicemodule.Gateway( dev_new = devicemodule.Gateway(self, device, simulator=self._simulator)
self, device, simulator=self._simulator
)
elif device["type"] == DeviceType.RIGHT: elif device["type"] == DeviceType.RIGHT:
# Connectdevice # Connectdevice
dev_new = None dev_new = None
@@ -347,7 +366,7 @@ class RevPiModIO(object):
warnings.warn( warnings.warn(
"device type '{0}' on position {1} unknown" "device type '{0}' on position {1} unknown"
"".format(device["type"], device["position"]), "".format(device["type"], device["position"]),
Warning Warning,
) )
dev_new = None dev_new = None
@@ -378,7 +397,7 @@ class RevPiModIO(object):
"equal device name '{0}' in pictory configuration. you can " "equal device name '{0}' in pictory configuration. you can "
"access this devices by position number .device[{1}] only!" "access this devices by position number .device[{1}] only!"
"".format(check_dev, "|".join(err_names_check[check_dev])), "".format(check_dev, "|".join(err_names_check[check_dev])),
Warning Warning,
) )
# ImgWriter erstellen # ImgWriter erstellen
@@ -393,17 +412,12 @@ class RevPiModIO(object):
self.syncoutputs() self.syncoutputs()
# Für RS485 errors am core defaults laden sollte procimg NULL sein # Für RS485 errors am core defaults laden sollte procimg NULL sein
if isinstance(self.core, devicemodule.Core) and \ if isinstance(self.core, devicemodule.Core) and not (self._monitoring or self._simulator):
not (self._monitoring or self._simulator):
if self.core._slc_errorlimit1 is not None: if self.core._slc_errorlimit1 is not None:
io = self.io[ io = self.io[self.core.offset + self.core._slc_errorlimit1.start][0]
self.core.offset + self.core._slc_errorlimit1.start
][0]
io.set_value(io._defaultvalue) io.set_value(io._defaultvalue)
if self.core._slc_errorlimit2 is not None: if self.core._slc_errorlimit2 is not None:
io = self.io[ io = self.io[self.core.offset + self.core._slc_errorlimit2.start][0]
self.core.offset + self.core._slc_errorlimit2.start
][0]
io.set_value(io._defaultvalue) io.set_value(io._defaultvalue)
# RS485 errors schreiben # RS485 errors schreiben
@@ -471,8 +485,7 @@ class RevPiModIO(object):
if "defaultvalue" in creplaceio[io]: if "defaultvalue" in creplaceio[io]:
if dict_replace["frm"] == "?": if dict_replace["frm"] == "?":
try: try:
dict_replace["defaultvalue"] = \ dict_replace["defaultvalue"] = creplaceio[io].getboolean("defaultvalue")
creplaceio[io].getboolean("defaultvalue")
except Exception: except Exception:
raise ValueError( raise ValueError(
"replace_io_file: could not convert '{0}' " "replace_io_file: could not convert '{0}' "
@@ -494,8 +507,7 @@ class RevPiModIO(object):
) )
else: else:
try: try:
dict_replace["defaultvalue"] = \ dict_replace["defaultvalue"] = creplaceio[io].getint("defaultvalue")
creplaceio[io].getint("defaultvalue")
except Exception: except Exception:
raise ValueError( raise ValueError(
"replace_io_file: could not convert '{0}' " "replace_io_file: could not convert '{0}' "
@@ -634,23 +646,19 @@ class RevPiModIO(object):
self._ioerror += 1 self._ioerror += 1
if self._maxioerrors != 0 and self._ioerror >= self._maxioerrors: if self._maxioerrors != 0 and self._ioerror >= self._maxioerrors:
raise RuntimeError( raise RuntimeError(
"reach max io error count {0} on process image" "reach max io error count {0} on process image".format(self._maxioerrors)
"".format(self._maxioerrors)
) )
if not show_warn or self._debug == -1: if not show_warn or self._debug == -1:
return return
if self._debug == 0: if self._debug == 0:
warnings.warn( warnings.warn("got io error on process image", RuntimeWarning)
"got io error on process image",
RuntimeWarning
)
else: else:
warnings.warn( warnings.warn(
"got io error during '{0}' and count {1} errors now | {2}" "got io error during '{0}' and count {1} errors now | {2}"
"".format(action, self._ioerror, str(e)), "".format(action, self._ioerror, str(e)),
RuntimeWarning RuntimeWarning,
) )
def _set_cycletime(self, milliseconds: int) -> None: def _set_cycletime(self, milliseconds: int) -> None:
@@ -660,10 +668,7 @@ class RevPiModIO(object):
:param milliseconds: <class 'int'> in Millisekunden :param milliseconds: <class 'int'> in Millisekunden
""" """
if self._looprunning: if self._looprunning:
raise RuntimeError( raise RuntimeError("can not change cycletime when cycleloop or mainloop is running")
"can not change cycletime when cycleloop or mainloop is "
"running"
)
else: else:
self._imgwriter.refresh = milliseconds self._imgwriter.refresh = milliseconds
@@ -701,7 +706,7 @@ class RevPiModIO(object):
else: else:
raise ValueError("value must be 0 or a positive integer") raise ValueError("value must be 0 or a positive integer")
def _simulate_ioctl(self, request: int, arg=b'') -> None: def _simulate_ioctl(self, request: int, arg=b"") -> None:
""" """
Simuliert IOCTL Funktionen auf procimg Datei. Simuliert IOCTL Funktionen auf procimg Datei.
@@ -717,9 +722,7 @@ class RevPiModIO(object):
# Simulatonsmodus schreibt direkt in Datei # Simulatonsmodus schreibt direkt in Datei
with self._myfh_lck: with self._myfh_lck:
self._myfh.seek(byte_address) self._myfh.seek(byte_address)
int_byte = int.from_bytes( int_byte = int.from_bytes(self._myfh.read(1), byteorder="little")
self._myfh.read(1), byteorder="little"
)
int_bit = 1 << bit_address int_bit = 1 << bit_address
if not bool(int_byte & int_bit) == new_value: if not bool(int_byte & int_bit) == new_value:
@@ -741,8 +744,9 @@ class RevPiModIO(object):
for i in range(16): for i in range(16):
if bool(bit_field & 1 << i): if bool(bit_field & 1 << i):
io_byte = self.device[dev_position].offset \ io_byte = self.device[dev_position].offset + int(
+ int(self.device[dev_position]._lst_counter[i]) self.device[dev_position]._lst_counter[i]
)
break break
if io_byte == -1: if io_byte == -1:
@@ -750,7 +754,7 @@ class RevPiModIO(object):
with self._myfh_lck: with self._myfh_lck:
self._myfh.seek(io_byte) self._myfh.seek(io_byte)
self._myfh.write(b'\x00\x00\x00\x00') self._myfh.write(b"\x00\x00\x00\x00")
if self._buffedwrite: if self._buffedwrite:
self._myfh.flush() self._myfh.flush()
@@ -796,9 +800,7 @@ class RevPiModIO(object):
""" """
# Prüfen ob ein Loop bereits läuft # Prüfen ob ein Loop bereits läuft
if self._looprunning: if self._looprunning:
raise RuntimeError( raise RuntimeError("can not start multiple loops mainloop/cycleloop")
"can not start multiple loops mainloop/cycleloop"
)
# Prüfen ob Devices in autorefresh sind # Prüfen ob Devices in autorefresh sind
if len(self._lst_refresh) == 0: if len(self._lst_refresh) == 0:
@@ -809,16 +811,14 @@ class RevPiModIO(object):
# Prüfen ob Funktion callable ist # Prüfen ob Funktion callable ist
if not callable(func): if not callable(func):
raise RuntimeError( raise RuntimeError("registered function '{0}' ist not callable".format(func))
"registered function '{0}' ist not callable".format(func)
)
# Thread erstellen, wenn nicht blockieren soll # Thread erstellen, wenn nicht blockieren soll
if not blocking: if not blocking:
self._th_mainloop = Thread( self._th_mainloop = Thread(
target=self.cycleloop, target=self.cycleloop,
args=(func,), args=(func,),
kwargs={"cycletime": cycletime, "blocking": True} kwargs={"cycletime": cycletime, "blocking": True},
) )
self._th_mainloop.start() self._th_mainloop.start()
return return
@@ -851,9 +851,9 @@ class RevPiModIO(object):
break break
# Just warn, user has to use maxioerrors to kill program # Just warn, user has to use maxioerrors to kill program
warnings.warn(RuntimeWarning( warnings.warn(
"no new io data in cycle loop for 2500 milliseconds" RuntimeWarning("no new io data in cycle loop for 2500 milliseconds")
)) )
cycleinfo.last = self._exit.is_set() cycleinfo.last = self._exit.is_set()
continue continue
@@ -942,7 +942,6 @@ class RevPiModIO(object):
cp = ConfigParser() cp = ConfigParser()
for io in self.io: for io in self.io:
if isinstance(io, StructIO): if isinstance(io, StructIO):
# Required values # Required values
cp.add_section(io.name) cp.add_section(io.name)
cp[io.name]["replace"] = io._parentio_name cp[io.name]["replace"] = io._parentio_name
@@ -958,8 +957,7 @@ class RevPiModIO(object):
if type(io.defaultvalue) is bytes: if type(io.defaultvalue) is bytes:
if any(io.defaultvalue): if any(io.defaultvalue):
# Convert each byte to an integer # Convert each byte to an integer
cp[io.name]["defaultvalue"] = \ cp[io.name]["defaultvalue"] = " ".join(map(str, io.defaultvalue))
" ".join(map(str, io.defaultvalue))
elif io.defaultvalue != 0: elif io.defaultvalue != 0:
cp[io.name]["defaultvalue"] = str(io.defaultvalue) cp[io.name]["defaultvalue"] = str(io.defaultvalue)
if io.bmk != "": if io.bmk != "":
@@ -971,10 +969,7 @@ class RevPiModIO(object):
with open(filename, "w") as fh: with open(filename, "w") as fh:
cp.write(fh) cp.write(fh)
except Exception as e: except Exception as e:
raise RuntimeError( raise RuntimeError("could not write export file '{0}' | {1}".format(filename, e))
"could not write export file '{0}' | {1}"
"".format(filename, e)
)
def get_jconfigrsc(self) -> dict: def get_jconfigrsc(self) -> dict:
""" """
@@ -986,8 +981,8 @@ class RevPiModIO(object):
if self._configrsc is not None: if self._configrsc is not None:
if not access(self._configrsc, F_OK | R_OK): if not access(self._configrsc, F_OK | R_OK):
raise RuntimeError( raise RuntimeError(
"can not access pictory configuration at {0}".format( "can not access pictory configuration at {0}".format(self._configrsc)
self._configrsc)) )
else: else:
# piCtory Konfiguration an bekannten Stellen prüfen # piCtory Konfiguration an bekannten Stellen prüfen
lst_rsc = ["/etc/revpi/config.rsc", "/opt/KUNBUS/config.rsc"] lst_rsc = ["/etc/revpi/config.rsc", "/opt/KUNBUS/config.rsc"]
@@ -1035,10 +1030,7 @@ class RevPiModIO(object):
""" """
# Prüfen ob Funktion callable ist # Prüfen ob Funktion callable ist
if not (cleanupfunc is None or callable(cleanupfunc)): if not (cleanupfunc is None or callable(cleanupfunc)):
raise RuntimeError( raise RuntimeError("registered function '{0}' ist not callable".format(cleanupfunc))
"registered function '{0}' ist not callable"
"".format(cleanupfunc)
)
self.__cleanupfunc = cleanupfunc self.__cleanupfunc = cleanupfunc
signal(SIGINT, self.__evt_exit) signal(SIGINT, self.__evt_exit)
signal(SIGTERM, self.__evt_exit) signal(SIGTERM, self.__evt_exit)
@@ -1063,9 +1055,7 @@ class RevPiModIO(object):
""" """
# Prüfen ob ein Loop bereits läuft # Prüfen ob ein Loop bereits läuft
if self._looprunning: if self._looprunning:
raise RuntimeError( raise RuntimeError("can not start multiple loops mainloop/cycleloop")
"can not start multiple loops mainloop/cycleloop"
)
# Prüfen ob Devices in autorefresh sind # Prüfen ob Devices in autorefresh sind
if len(self._lst_refresh) == 0: if len(self._lst_refresh) == 0:
@@ -1076,9 +1066,7 @@ class RevPiModIO(object):
# Thread erstellen, wenn nicht blockieren soll # Thread erstellen, wenn nicht blockieren soll
if not blocking: if not blocking:
self._th_mainloop = Thread( self._th_mainloop = Thread(target=self.mainloop, kwargs={"blocking": True})
target=self.mainloop, kwargs={"blocking": True}
)
self._th_mainloop.start() self._th_mainloop.start()
return return
@@ -1100,17 +1088,17 @@ class RevPiModIO(object):
if not regfunc.prefire: if not regfunc.prefire:
continue continue
if regfunc.edge == BOTH \ if (
or regfunc.edge == RISING and io.value \ regfunc.edge == BOTH
or regfunc.edge == FALLING and not io.value: or regfunc.edge == RISING
and io.value
or regfunc.edge == FALLING
and not io.value
):
if regfunc.as_thread: if regfunc.as_thread:
self._imgwriter._eventqth.put( self._imgwriter._eventqth.put((regfunc, io._name, io.value), False)
(regfunc, io._name, io.value), False
)
else: else:
self._imgwriter._eventq.put( self._imgwriter._eventq.put((regfunc, io._name, io.value), False)
(regfunc, io._name, io.value), False
)
# ImgWriter mit Eventüberwachung aktivieren # ImgWriter mit Eventüberwachung aktivieren
self._imgwriter._collect_events(True) self._imgwriter._collect_events(True)
@@ -1118,7 +1106,6 @@ class RevPiModIO(object):
runtime = -1 if self._debug == -1 else 0 runtime = -1 if self._debug == -1 else 0
while not self._exit.is_set(): while not self._exit.is_set():
# Laufzeit der Eventqueue auf 0 setzen # Laufzeit der Eventqueue auf 0 setzen
if self._imgwriter._eventq.qsize() == 0: if self._imgwriter._eventq.qsize() == 0:
runtime = -1 if self._debug == -1 else 0 runtime = -1 if self._debug == -1 else 0
@@ -1135,13 +1122,12 @@ class RevPiModIO(object):
self._imgwriter._eventq.task_done() self._imgwriter._eventq.task_done()
# Laufzeitprüfung # Laufzeitprüfung
if runtime != -1 and \ if runtime != -1 and default_timer() - runtime > self._imgwriter._refresh:
default_timer() - runtime > self._imgwriter._refresh:
runtime = -1 runtime = -1
warnings.warn( warnings.warn(
"can not execute all event functions in one cycle - " "can not execute all event functions in one cycle - "
"optimize your event functions or rise .cycletime", "optimize your event functions or rise .cycletime",
RuntimeWarning RuntimeWarning,
) )
except Empty: except Empty:
if not self._exit.is_set() and not self._imgwriter.is_alive(): if not self._exit.is_set() and not self._imgwriter.is_alive():
@@ -1177,8 +1163,11 @@ class RevPiModIO(object):
if device is None: if device is None:
mylist = self.device mylist = self.device
else: else:
dev = device if isinstance(device, devicemodule.Device) \ dev = (
device
if isinstance(device, devicemodule.Device)
else self.device.__getitem__(device) else self.device.__getitem__(device)
)
if dev._selfupdate: if dev._selfupdate:
raise RuntimeError( raise RuntimeError(
@@ -1200,7 +1189,6 @@ class RevPiModIO(object):
for dev in mylist: for dev in mylist:
if not dev._selfupdate: if not dev._selfupdate:
# FileHandler sperren # FileHandler sperren
dev._filelock.acquire() dev._filelock.acquire()
@@ -1226,16 +1214,16 @@ class RevPiModIO(object):
:param device: nur auf einzelnes Device anwenden :param device: nur auf einzelnes Device anwenden
""" """
if self._monitoring: if self._monitoring:
raise RuntimeError( raise RuntimeError("can not set default values, while system is in monitoring mode")
"can not set default values, while system is in monitoring "
"mode"
)
if device is None: if device is None:
mylist = self.device mylist = self.device
else: else:
dev = device if isinstance(device, devicemodule.Device) \ dev = (
device
if isinstance(device, devicemodule.Device)
else self.device.__getitem__(device) else self.device.__getitem__(device)
)
mylist = [dev] mylist = [dev]
for dev in mylist: for dev in mylist:
@@ -1254,8 +1242,11 @@ class RevPiModIO(object):
if device is None: if device is None:
mylist = self.device mylist = self.device
else: else:
dev = device if isinstance(device, devicemodule.Device) \ dev = (
device
if isinstance(device, devicemodule.Device)
else self.device.__getitem__(device) else self.device.__getitem__(device)
)
if dev._selfupdate: if dev._selfupdate:
raise RuntimeError( raise RuntimeError(
@@ -1292,16 +1283,16 @@ class RevPiModIO(object):
:return: True, wenn Arbeiten an allen Devices erfolgreich waren :return: True, wenn Arbeiten an allen Devices erfolgreich waren
""" """
if self._monitoring: if self._monitoring:
raise RuntimeError( raise RuntimeError("can not write process image, while system is in monitoring mode")
"can not write process image, while system is in monitoring "
"mode"
)
if device is None: if device is None:
mylist = self.device mylist = self.device
else: else:
dev = device if isinstance(device, devicemodule.Device) \ dev = (
device
if isinstance(device, devicemodule.Device)
else self.device.__getitem__(device) else self.device.__getitem__(device)
)
if dev._selfupdate: if dev._selfupdate:
raise RuntimeError( raise RuntimeError(
@@ -1321,9 +1312,7 @@ class RevPiModIO(object):
if dev._shared_procimg: if dev._shared_procimg:
for io in dev._shared_write: for io in dev._shared_write:
if not io._write_to_procimg(): if not io._write_to_procimg():
global_ex = IOError( global_ex = IOError("error on shared procimg while write")
"error on shared procimg while write"
)
dev._shared_write.clear() dev._shared_write.clear()
else: else:
# Outpus auf Bus schreiben # Outpus auf Bus schreiben
@@ -1375,10 +1364,19 @@ class RevPiModIOSelected(RevPiModIO):
__slots__ = () __slots__ = ()
def __init__( def __init__(
self, deviceselection, autorefresh=False, monitoring=False, self,
syncoutputs=True, procimg=None, configrsc=None, deviceselection,
simulator=False, debug=True, replace_io_file=None, autorefresh=False,
shared_procimg=False, direct_output=False): monitoring=False,
syncoutputs=True,
procimg=None,
configrsc=None,
simulator=False,
debug=True,
replace_io_file=None,
shared_procimg=False,
direct_output=False,
):
""" """
Instantiiert nur fuer angegebene Devices die Grundfunktionen. Instantiiert nur fuer angegebene Devices die Grundfunktionen.
@@ -1390,8 +1388,16 @@ class RevPiModIOSelected(RevPiModIO):
:ref: :func:`RevPiModIO.__init__(...)` :ref: :func:`RevPiModIO.__init__(...)`
""" """
super().__init__( super().__init__(
autorefresh, monitoring, syncoutputs, procimg, configrsc, autorefresh,
simulator, debug, replace_io_file, shared_procimg, direct_output monitoring,
syncoutputs,
procimg,
configrsc,
simulator,
debug,
replace_io_file,
shared_procimg,
direct_output,
) )
if type(deviceselection) is not DevSelect: if type(deviceselection) is not DevSelect:
@@ -1410,24 +1416,19 @@ class RevPiModIOSelected(RevPiModIO):
if len(self.device) == 0: if len(self.device) == 0:
if self._devselect.type: if self._devselect.type:
raise DeviceNotFoundError( raise DeviceNotFoundError(
"could not find ANY given {0} devices in config" "could not find ANY given {0} devices in config".format(self._devselect.type)
"".format(self._devselect.type)
) )
else: else:
raise DeviceNotFoundError( raise DeviceNotFoundError("could not find ANY given devices in config")
"could not find ANY given devices in config" elif not self._devselect.other_device_key and len(self.device) != len(
) self._devselect.values
elif not self._devselect.other_device_key \ ):
and len(self.device) != len(self._devselect.values):
if self._devselect.type: if self._devselect.type:
raise DeviceNotFoundError( raise DeviceNotFoundError(
"could not find ALL given {0} devices in config" "could not find ALL given {0} devices in config".format(self._devselect.type)
"".format(self._devselect.type)
) )
else: else:
raise DeviceNotFoundError( raise DeviceNotFoundError("could not find ALL given devices in config")
"could not find ALL given devices in config"
)
class RevPiModIODriver(RevPiModIOSelected): class RevPiModIODriver(RevPiModIOSelected):
@@ -1443,9 +1444,17 @@ class RevPiModIODriver(RevPiModIOSelected):
__slots__ = () __slots__ = ()
def __init__( def __init__(
self, virtdev, autorefresh=False, self,
syncoutputs=True, procimg=None, configrsc=None, debug=True, virtdev,
replace_io_file=None, shared_procimg=False, direct_output=False): autorefresh=False,
syncoutputs=True,
procimg=None,
configrsc=None,
debug=True,
replace_io_file=None,
shared_procimg=False,
direct_output=False,
):
""" """
Instantiiert die Grundfunktionen. Instantiiert die Grundfunktionen.
@@ -1460,14 +1469,21 @@ class RevPiModIODriver(RevPiModIOSelected):
virtdev = (virtdev,) virtdev = (virtdev,)
dev_select = DevSelect(DeviceType.VIRTUAL, "", virtdev) dev_select = DevSelect(DeviceType.VIRTUAL, "", virtdev)
super().__init__( super().__init__(
dev_select, autorefresh, False, syncoutputs, procimg, configrsc, dev_select,
True, debug, replace_io_file, shared_procimg, direct_output autorefresh,
False,
syncoutputs,
procimg,
configrsc,
True,
debug,
replace_io_file,
shared_procimg,
direct_output,
) )
def run_plc( def run_plc(func, cycletime=50, replace_io_file=None, debug=True, procimg=None, configrsc=None):
func, cycletime=50, replace_io_file=None, debug=True,
procimg=None, configrsc=None):
""" """
Run Revoluton Pi as real plc with cycle loop and exclusive IO access. Run Revoluton Pi as real plc with cycle loop and exclusive IO access.

View File

@@ -18,22 +18,22 @@ from .modio import DevSelect, RevPiModIO as _RevPiModIO
from .pictory import DeviceType from .pictory import DeviceType
# Synchronisierungsbefehl # Synchronisierungsbefehl
_syssync = b'\x01\x06\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _syssync = b"\x01\x06\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"
# Disconnectbefehl # Disconnectbefehl
_sysexit = b'\x01EX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysexit = b"\x01EX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"
# DirtyBytes von Server entfernen # DirtyBytes von Server entfernen
_sysdeldirty = b'\x01EY\x00\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x17' _sysdeldirty = b"\x01EY\x00\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x17"
# piCtory Konfiguration laden # piCtory Konfiguration laden
_syspictory = b'\x01PI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _syspictory = b"\x01PI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"
_syspictoryh = b'\x01PH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _syspictoryh = b"\x01PH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"
# ReplaceIO Konfiguration laden # ReplaceIO Konfiguration laden
_sysreplaceio = b'\x01RP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysreplaceio = b"\x01RP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"
_sysreplaceioh = b'\x01RH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysreplaceioh = b"\x01RH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"
# Hashvalues # Hashvalues
HASH_FAIL = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' HASH_FAIL = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
# Header start/stop # Header start/stop
HEADER_START = b'\x01' HEADER_START = b"\x01"
HEADER_STOP = b'\x17' HEADER_STOP = b"\x17"
class AclException(Exception): class AclException(Exception):
@@ -57,12 +57,28 @@ class NetFH(Thread):
so gesteuert werden. so gesteuert werden.
""" """
__slots__ = "__buff_size", "__buff_block", "__buff_recv", \ __slots__ = (
"__by_buff", "__check_replace_ios", "__config_changed", \ "__buff_size",
"__int_buff", "__dictdirty", "__flusherr", "__replace_ios_h", \ "__buff_block",
"__pictory_h", "__position", "__sockerr", "__sockend", \ "__buff_recv",
"__socklock", "__timeout", "__waitsync", "_address", \ "__by_buff",
"_serversock", "daemon" "__check_replace_ios",
"__config_changed",
"__int_buff",
"__dictdirty",
"__flusherr",
"__replace_ios_h",
"__pictory_h",
"__position",
"__sockerr",
"__sockend",
"__socklock",
"__timeout",
"__waitsync",
"_address",
"_serversock",
"daemon",
)
def __init__(self, address: tuple, check_replace_ios: bool, timeout=500): def __init__(self, address: tuple, check_replace_ios: bool, timeout=500):
""" """
@@ -83,8 +99,8 @@ class NetFH(Thread):
self.__config_changed = False self.__config_changed = False
self.__int_buff = 0 self.__int_buff = 0
self.__dictdirty = {} self.__dictdirty = {}
self.__replace_ios_h = b'' self.__replace_ios_h = b""
self.__pictory_h = b'' self.__pictory_h = b""
self.__sockerr = Event() self.__sockerr = Event()
self.__sockend = Event() self.__sockend = Event()
self.__socklock = Lock() self.__socklock = Lock()
@@ -95,9 +111,7 @@ class NetFH(Thread):
# Parameterprüfung # Parameterprüfung
if not isinstance(address, tuple): if not isinstance(address, tuple):
raise TypeError( raise TypeError("parameter address must be <class 'tuple'> ('IP', PORT)")
"parameter address must be <class 'tuple'> ('IP', PORT)"
)
if not isinstance(timeout, int): if not isinstance(timeout, int):
raise TypeError("parameter timeout must be <class 'int'>") raise TypeError("parameter timeout must be <class 'int'>")
@@ -125,7 +139,7 @@ class NetFH(Thread):
:param bytecode: Antwort, die geprueft werden solll :param bytecode: Antwort, die geprueft werden solll
""" """
if bytecode == b'\x18': if bytecode == b"\x18":
# Alles beenden, wenn nicht erlaubt # Alles beenden, wenn nicht erlaubt
self.__sockend.set() self.__sockend.set()
self.__sockerr.set() self.__sockerr.set()
@@ -174,7 +188,7 @@ class NetFH(Thread):
buff_recv = bytearray(recv_len) buff_recv = bytearray(recv_len)
while recv_len > 0: while recv_len > 0:
block = so.recv(recv_len) block = so.recv(recv_len)
if block == b'': if block == b"":
raise OSError("lost connection on hash receive") raise OSError("lost connection on hash receive")
buff_recv += block buff_recv += block
recv_len -= len(block) recv_len -= len(block)
@@ -183,18 +197,19 @@ class NetFH(Thread):
if self.__pictory_h and buff_recv[:16] != self.__pictory_h: if self.__pictory_h and buff_recv[:16] != self.__pictory_h:
self.__config_changed = True self.__config_changed = True
self.close() self.close()
raise ConfigChanged( raise ConfigChanged("configuration on revolution pi was changed")
"configuration on revolution pi was changed")
else: else:
self.__pictory_h = buff_recv[:16] self.__pictory_h = buff_recv[:16]
# Änderung an replace_ios prüfen # Änderung an replace_ios prüfen
if self.__check_replace_ios and self.__replace_ios_h \ if (
and buff_recv[16:] != self.__replace_ios_h: self.__check_replace_ios
and self.__replace_ios_h
and buff_recv[16:] != self.__replace_ios_h
):
self.__config_changed = True self.__config_changed = True
self.close() self.close()
raise ConfigChanged( raise ConfigChanged("configuration on revolution pi was changed")
"configuration on revolution pi was changed")
else: else:
self.__replace_ios_h = buff_recv[16:] self.__replace_ios_h = buff_recv[16:]
except ConfigChanged: except ConfigChanged:
@@ -295,11 +310,18 @@ class NetFH(Thread):
else: else:
# Nur bestimmte Dirtybytes löschen # Nur bestimmte Dirtybytes löschen
# b CM ii xx c0000000 b = 16 # b CM ii xx c0000000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(
pack(
"=c2sH2xc7xc", "=c2sH2xc7xc",
HEADER_START, b'EY', position, b'\xfe', HEADER_STOP HEADER_START,
), 1) b"EY",
if buff != b'\x1e': position,
b"\xfe",
HEADER_STOP,
),
1,
)
if buff != b"\x1e":
# ACL prüfen und ggf Fehler werfen # ACL prüfen und ggf Fehler werfen
self.__check_acl(buff) self.__check_acl(buff)
@@ -343,12 +365,18 @@ class NetFH(Thread):
try: try:
# b CM ii ii 00000000 b = 16 # b CM ii ii 00000000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(
pack(
"=c2sHH8xc", "=c2sHH8xc",
HEADER_START, HEADER_START,
b'FD', self.__int_buff, len(self.__by_buff), b"FD",
HEADER_STOP self.__int_buff,
) + self.__by_buff, 1) len(self.__by_buff),
HEADER_STOP,
)
+ self.__by_buff,
1,
)
except Exception: except Exception:
raise raise
finally: finally:
@@ -356,7 +384,7 @@ class NetFH(Thread):
self.__int_buff = 0 self.__int_buff = 0
self.__by_buff.clear() self.__by_buff.clear()
if buff != b'\x1e': if buff != b"\x1e":
# ACL prüfen und ggf Fehler werfen # ACL prüfen und ggf Fehler werfen
self.__check_acl(buff) self.__check_acl(buff)
@@ -403,7 +431,7 @@ class NetFH(Thread):
""" """
return int(self.__timeout * 1000) return int(self.__timeout * 1000)
def ioctl(self, request: int, arg=b'') -> None: def ioctl(self, request: int, arg=b"") -> None:
""" """
IOCTL Befehle ueber das Netzwerk senden. IOCTL Befehle ueber das Netzwerk senden.
@@ -419,11 +447,10 @@ class NetFH(Thread):
raise TypeError("arg must be <class 'bytes'>") raise TypeError("arg must be <class 'bytes'>")
# b CM xx ii iiii0000 b = 16 # b CM xx ii iiii0000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(
"=c2s2xHI4xc", pack("=c2s2xHI4xc", HEADER_START, b"IC", len(arg), request, HEADER_STOP) + arg, 1
HEADER_START, b'IC', len(arg), request, HEADER_STOP )
) + arg, 1) if buff != b"\x1e":
if buff != b'\x1e':
# ACL prüfen und ggf Fehler werfen # ACL prüfen und ggf Fehler werfen
self.__check_acl(buff) self.__check_acl(buff)
@@ -443,10 +470,9 @@ class NetFH(Thread):
raise ValueError("read of closed file") raise ValueError("read of closed file")
# b CM ii ii 00000000 b = 16 # b CM ii ii 00000000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(
"=c2sHH8xc", pack("=c2sHH8xc", HEADER_START, b"DA", self.__position, length, HEADER_STOP), length
HEADER_START, b'DA', self.__position, length, HEADER_STOP )
), length)
self.__position += length self.__position += length
return buff return buff
@@ -466,10 +492,9 @@ class NetFH(Thread):
length = len(buffer) length = len(buffer)
# b CM ii ii 00000000 b = 16 # b CM ii ii 00000000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(
"=c2sHH8xc", pack("=c2sHH8xc", HEADER_START, b"DA", self.__position, length, HEADER_STOP), length
HEADER_START, b'DA', self.__position, length, HEADER_STOP )
), length)
buffer[:] = buff buffer[:] = buff
return len(buffer) return len(buffer)
@@ -484,13 +509,11 @@ class NetFH(Thread):
raise ValueError("read of closed file") raise ValueError("read of closed file")
if self.__pictory_h == HASH_FAIL: if self.__pictory_h == HASH_FAIL:
raise RuntimeError( raise RuntimeError("could not read/parse piCtory configuration over network")
"could not read/parse piCtory configuration over network"
)
buff = self._direct_sr(_syspictory, 4) buff = self._direct_sr(_syspictory, 4)
recv_length, = unpack("=I", buff) (recv_length,) = unpack("=I", buff)
return self._direct_sr(b'', recv_length) return self._direct_sr(b"", recv_length)
def readreplaceio(self) -> bytes: def readreplaceio(self) -> bytes:
""" """
@@ -502,27 +525,21 @@ class NetFH(Thread):
raise ValueError("read of closed file") raise ValueError("read of closed file")
if self.__replace_ios_h == HASH_FAIL: if self.__replace_ios_h == HASH_FAIL:
raise RuntimeError( raise RuntimeError("replace_io_file: could not read/parse over network")
"replace_io_file: could not read/parse over network"
)
buff = self._direct_sr(_sysreplaceio, 4) buff = self._direct_sr(_sysreplaceio, 4)
recv_length, = unpack("=I", buff) (recv_length,) = unpack("=I", buff)
return self._direct_sr(b'', recv_length) return self._direct_sr(b"", recv_length)
def run(self) -> None: def run(self) -> None:
"""Handler fuer Synchronisierung.""" """Handler fuer Synchronisierung."""
state_reconnect = False state_reconnect = False
while not self.__sockend.is_set(): while not self.__sockend.is_set():
# Bei Fehlermeldung neu verbinden # Bei Fehlermeldung neu verbinden
if self.__sockerr.is_set(): if self.__sockerr.is_set():
if not state_reconnect: if not state_reconnect:
state_reconnect = True state_reconnect = True
warnings.warn( warnings.warn("got a network error and try to reconnect", RuntimeWarning)
"got a network error and try to reconnect",
RuntimeWarning
)
self._connect() self._connect()
if self.__sockerr.is_set(): if self.__sockerr.is_set():
# Verhindert beim Scheitern 100% CPU last # Verhindert beim Scheitern 100% CPU last
@@ -530,10 +547,7 @@ class NetFH(Thread):
continue continue
else: else:
state_reconnect = False state_reconnect = False
warnings.warn( warnings.warn("successfully reconnected after network error", RuntimeWarning)
"successfully reconnected after network error",
RuntimeWarning
)
# Kein Fehler aufgetreten, sync durchführen wenn socket frei # Kein Fehler aufgetreten, sync durchführen wenn socket frei
if self.__socklock.acquire(blocking=False): if self.__socklock.acquire(blocking=False):
@@ -543,9 +557,7 @@ class NetFH(Thread):
self.__buff_recv.clear() self.__buff_recv.clear()
recv_lenght = 2 recv_lenght = 2
while recv_lenght > 0: while recv_lenght > 0:
count = self._serversock.recv_into( count = self._serversock.recv_into(self.__buff_block, recv_lenght)
self.__buff_block, recv_lenght
)
if count == 0: if count == 0:
raise IOError("lost network connection on sync") raise IOError("lost network connection on sync")
self.__buff_recv += self.__buff_block[:count] self.__buff_recv += self.__buff_block[:count]
@@ -554,11 +566,8 @@ class NetFH(Thread):
except IOError: except IOError:
self.__sockerr.set() self.__sockerr.set()
else: else:
if self.__buff_recv != b'\x06\x16': if self.__buff_recv != b"\x06\x16":
warnings.warn( warnings.warn("data error on network sync", RuntimeWarning)
"data error on network sync",
RuntimeWarning
)
self.__sockerr.set() self.__sockerr.set()
continue continue
finally: finally:
@@ -596,12 +605,13 @@ class NetFH(Thread):
try: try:
# b CM ii ii 00000000 b = 16 # b CM ii ii 00000000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(
"=c2sHH8xc", pack("=c2sHH8xc", HEADER_START, b"EY", position, len(dirtybytes), HEADER_STOP)
HEADER_START, b'EY', position, len(dirtybytes), HEADER_STOP + dirtybytes,
) + dirtybytes, 1) 1,
)
if buff != b'\x1e': if buff != b"\x1e":
# ACL prüfen und ggf Fehler werfen # ACL prüfen und ggf Fehler werfen
self.__check_acl(buff) self.__check_acl(buff)
@@ -627,11 +637,8 @@ class NetFH(Thread):
try: try:
# b CM ii xx 00000000 b = 16 # b CM ii xx 00000000 b = 16
buff = self._direct_sr(pack( buff = self._direct_sr(pack("=c2sH10xc", HEADER_START, b"CF", value, HEADER_STOP), 1)
"=c2sH10xc", if buff != b"\x1e":
HEADER_START, b'CF', value, HEADER_STOP
), 1)
if buff != b'\x1e':
raise IOError("set timeout error on network") raise IOError("set timeout error on network")
except Exception: except Exception:
self.__sockerr.set() self.__sockerr.set()
@@ -666,10 +673,11 @@ class NetFH(Thread):
self.__int_buff += 1 self.__int_buff += 1
# Datenblock mit Position und Länge in Puffer ablegen # Datenblock mit Position und Länge in Puffer ablegen
self.__by_buff += \ self.__by_buff += (
self.__position.to_bytes(length=2, byteorder="little") \ self.__position.to_bytes(length=2, byteorder="little")
+ len(bytebuff).to_bytes(length=2, byteorder="little") \ + len(bytebuff).to_bytes(length=2, byteorder="little")
+ bytebuff + bytebuff
)
# TODO: Bufferlänge und dann flushen? # TODO: Bufferlänge und dann flushen?
@@ -697,9 +705,17 @@ class RevPiNetIO(_RevPiModIO):
__slots__ = "_address" __slots__ = "_address"
def __init__( def __init__(
self, address, autorefresh=False, monitoring=False, self,
syncoutputs=True, simulator=False, debug=True, address,
replace_io_file=None, shared_procimg=False, direct_output=False): autorefresh=False,
monitoring=False,
syncoutputs=True,
simulator=False,
debug=True,
replace_io_file=None,
shared_procimg=False,
direct_output=False,
):
""" """
Instantiiert die Grundfunktionen. Instantiiert die Grundfunktionen.
@@ -714,28 +730,20 @@ class RevPiNetIO(_RevPiModIO):
could be insecure for automation could be insecure for automation
:param direct_output: Deprecated, use shared_procimg :param direct_output: Deprecated, use shared_procimg
""" """
check_ip = compile( check_ip = compile(r"^(25[0-5]|(2[0-4]|[01]?\d|)\d)(\.(25[0-5]|(2[0-4]|[01]?\d|)\d)){3}$")
r"^(25[0-5]|(2[0-4]|[01]?\d|)\d)"
r"(\.(25[0-5]|(2[0-4]|[01]?\d|)\d)){3}$"
)
# Adresse verarbeiten # Adresse verarbeiten
if isinstance(address, str): if isinstance(address, str):
self._address = (address, 55234) self._address = (address, 55234)
elif isinstance(address, tuple): elif isinstance(address, tuple):
if len(address) == 2 \ if len(address) == 2 and isinstance(address[0], str) and isinstance(address[1], int):
and isinstance(address[0], str) \
and isinstance(address[1], int):
# Werte prüfen # Werte prüfen
if not 0 < address[1] <= 65535: if not 0 < address[1] <= 65535:
raise ValueError("port number out of range 1 - 65535") raise ValueError("port number out of range 1 - 65535")
self._address = address self._address = address
else: else:
raise TypeError( raise TypeError("address tuple must be (<class 'str'>, <class 'int'>)")
"address tuple must be (<class 'str'>, <class 'int'>)"
)
else: else:
raise TypeError( raise TypeError(
"parameter address must be <class 'str'> or <class 'tuple'> " "parameter address must be <class 'str'> or <class 'tuple'> "
@@ -749,8 +757,7 @@ class RevPiNetIO(_RevPiModIO):
self._address = (ipv4, self._address[1]) self._address = (ipv4, self._address[1])
except Exception: except Exception:
raise ValueError( raise ValueError(
"can not resolve ip address for hostname '{0}'" "can not resolve ip address for hostname '{0}'".format(self._address[0])
"".format(self._address[0])
) )
# Vererben # Vererben
@@ -801,10 +808,7 @@ class RevPiNetIO(_RevPiModIO):
try: try:
cp.read_string(byte_buff.decode("utf-8")) cp.read_string(byte_buff.decode("utf-8"))
except Exception as e: except Exception as e:
raise RuntimeError( raise RuntimeError("replace_io_file: could not read/parse network data | {0}".format(e))
"replace_io_file: could not read/parse network data | {0}"
"".format(e)
)
return cp return cp
def disconnect(self) -> None: def disconnect(self) -> None:
@@ -862,16 +866,12 @@ class RevPiNetIO(_RevPiModIO):
:param device: nur auf einzelnes Device anwenden, sonst auf Alle :param device: nur auf einzelnes Device anwenden, sonst auf Alle
""" """
if self.monitoring: if self.monitoring:
raise RuntimeError( raise RuntimeError("can not send default values, while system is in monitoring mode")
"can not send default values, while system is in "
"monitoring mode"
)
if device is None: if device is None:
self._myfh.clear_dirtybytes() self._myfh.clear_dirtybytes()
else: else:
dev = device if isinstance(device, Device) \ dev = device if isinstance(device, Device) else self.device.__getitem__(device)
else self.device.__getitem__(device)
mylist = [dev] mylist = [dev]
for dev in mylist: for dev in mylist:
@@ -887,16 +887,12 @@ class RevPiNetIO(_RevPiModIO):
:param device: nur auf einzelnes Device anwenden, sonst auf Alle :param device: nur auf einzelnes Device anwenden, sonst auf Alle
""" """
if self.monitoring: if self.monitoring:
raise RuntimeError( raise RuntimeError("can not send default values, while system is in monitoring mode")
"can not send default values, while system is in "
"monitoring mode"
)
if device is None: if device is None:
mylist = self.device mylist = self.device
else: else:
dev = device if isinstance(device, Device) \ dev = device if isinstance(device, Device) else self.device.__getitem__(device)
else self.device.__getitem__(device)
mylist = [dev] mylist = [dev]
for dev in mylist: for dev in mylist:
@@ -921,13 +917,10 @@ class RevPiNetIO(_RevPiModIO):
int_byte += 1 if bitio._defaultvalue else 0 int_byte += 1 if bitio._defaultvalue else 0
# Errechneten Int-Wert in ein Byte umwandeln # Errechneten Int-Wert in ein Byte umwandeln
dirtybytes += \ dirtybytes += int_byte.to_bytes(length=1, byteorder="little")
int_byte.to_bytes(length=1, byteorder="little")
# Dirtybytes an PLC Server senden # Dirtybytes an PLC Server senden
self._myfh.set_dirtybytes( self._myfh.set_dirtybytes(dev._offset + dev._slc_out.start, dirtybytes)
dev._offset + dev._slc_out.start, dirtybytes
)
config_changed = property(get_config_changed) config_changed = property(get_config_changed)
reconnecting = property(get_reconnecting) reconnecting = property(get_reconnecting)
@@ -946,9 +939,18 @@ class RevPiNetIOSelected(RevPiNetIO):
__slots__ = () __slots__ = ()
def __init__( def __init__(
self, address, deviceselection, autorefresh=False, self,
monitoring=False, syncoutputs=True, simulator=False, debug=True, address,
replace_io_file=None, shared_procimg=False, direct_output=False): deviceselection,
autorefresh=False,
monitoring=False,
syncoutputs=True,
simulator=False,
debug=True,
replace_io_file=None,
shared_procimg=False,
direct_output=False,
):
""" """
Instantiiert nur fuer angegebene Devices die Grundfunktionen. Instantiiert nur fuer angegebene Devices die Grundfunktionen.
@@ -961,8 +963,15 @@ class RevPiNetIOSelected(RevPiNetIO):
:ref: :func:`RevPiNetIO.__init__()` :ref: :func:`RevPiNetIO.__init__()`
""" """
super().__init__( super().__init__(
address, autorefresh, monitoring, syncoutputs, simulator, debug, address,
replace_io_file, shared_procimg, direct_output autorefresh,
monitoring,
syncoutputs,
simulator,
debug,
replace_io_file,
shared_procimg,
direct_output,
) )
if type(deviceselection) is not DevSelect: if type(deviceselection) is not DevSelect:
@@ -981,24 +990,19 @@ class RevPiNetIOSelected(RevPiNetIO):
if len(self.device) == 0: if len(self.device) == 0:
if self._devselect.type: if self._devselect.type:
raise DeviceNotFoundError( raise DeviceNotFoundError(
"could not find ANY given {0} devices in config" "could not find ANY given {0} devices in config".format(self._devselect.type)
"".format(self._devselect.type)
) )
else: else:
raise DeviceNotFoundError( raise DeviceNotFoundError("could not find ANY given devices in config")
"could not find ANY given devices in config" elif not self._devselect.other_device_key and len(self.device) != len(
) self._devselect.values
elif not self._devselect.other_device_key \ ):
and len(self.device) != len(self._devselect.values):
if self._devselect.type: if self._devselect.type:
raise DeviceNotFoundError( raise DeviceNotFoundError(
"could not find ALL given {0} devices in config" "could not find ALL given {0} devices in config".format(self._devselect.type)
"".format(self._devselect.type)
) )
else: else:
raise DeviceNotFoundError( raise DeviceNotFoundError("could not find ALL given devices in config")
"could not find ALL given devices in config"
)
class RevPiNetIODriver(RevPiNetIOSelected): class RevPiNetIODriver(RevPiNetIOSelected):
@@ -1014,9 +1018,16 @@ class RevPiNetIODriver(RevPiNetIOSelected):
__slots__ = () __slots__ = ()
def __init__( def __init__(
self, address, virtdev, autorefresh=False, self,
syncoutputs=True, debug=True, replace_io_file=None, address,
shared_procimg=False, direct_output=False): virtdev,
autorefresh=False,
syncoutputs=True,
debug=True,
replace_io_file=None,
shared_procimg=False,
direct_output=False,
):
""" """
Instantiiert die Grundfunktionen. Instantiiert die Grundfunktionen.
@@ -1032,13 +1043,20 @@ class RevPiNetIODriver(RevPiNetIOSelected):
virtdev = (virtdev,) virtdev = (virtdev,)
dev_select = DevSelect(DeviceType.VIRTUAL, "", virtdev) dev_select = DevSelect(DeviceType.VIRTUAL, "", virtdev)
super().__init__( super().__init__(
address, dev_select, autorefresh, False, syncoutputs, True, debug, address,
replace_io_file, shared_procimg, direct_output dev_select,
autorefresh,
False,
syncoutputs,
True,
debug,
replace_io_file,
shared_procimg,
direct_output,
) )
def run_net_plc( def run_net_plc(address, func, cycletime=50, replace_io_file=None, debug=True):
address, func, cycletime=50, replace_io_file=None, debug=True):
""" """
Run Revoluton Pi as real plc with cycle loop and exclusive IO access. Run Revoluton Pi as real plc with cycle loop and exclusive IO access.

View File

@@ -13,6 +13,7 @@ __license__ = "LGPLv2"
# - RevPiConCan_20180425_1_0.rap # - RevPiConCan_20180425_1_0.rap
# - RevPiGateCANopen_20161102_1_0.rap # - RevPiGateCANopen_20161102_1_0.rap
class ProductType: class ProductType:
CON_BT = 111 CON_BT = 111
CON_CAN = 109 CON_CAN = 109
@@ -65,6 +66,7 @@ class ProductType:
class DeviceType: class DeviceType:
"""Module key "type" in piCtory file.""" """Module key "type" in piCtory file."""
IGNORED = "" IGNORED = ""
BASE = "BASE" # Core devices BASE = "BASE" # Core devices
EDGE = "EDGE" # Gateways EDGE = "EDGE" # Gateways
@@ -75,6 +77,7 @@ class DeviceType:
class AIO: class AIO:
"""Memory value mappings for RevPi AIO 1.0 (RevPiAIO_20170301_1_0.rap).""" """Memory value mappings for RevPi AIO 1.0 (RevPiAIO_20170301_1_0.rap)."""
OUT_RANGE_OFF = 0 # Off OUT_RANGE_OFF = 0 # Off
OUT_RANGE_0_5V = 1 # 0 - 5V OUT_RANGE_0_5V = 1 # 0 - 5V
OUT_RANGE_0_10V = 2 # 0 - 10V OUT_RANGE_0_10V = 2 # 0 - 10V
@@ -148,6 +151,7 @@ class AIO:
class DI: class DI:
"""Memory value mappings for RevPi DI 1.0 (RevPiDI_20160818_1_0.rap).""" """Memory value mappings for RevPi DI 1.0 (RevPiDI_20160818_1_0.rap)."""
IN_MODE_DIRECT = 0 # Direct IN_MODE_DIRECT = 0 # Direct
IN_MODE_COUNT_RISING = 1 # Counter, rising edge IN_MODE_COUNT_RISING = 1 # Counter, rising edge
IN_MODE_COUNT_FALLING = 2 # Counter, falling edge IN_MODE_COUNT_FALLING = 2 # Counter, falling edge
@@ -161,6 +165,7 @@ class DI:
class DO: class DO:
"""Memory value mappings for RevPi DO 1.0 (RevPiDO_20160818_1_0.rap).""" """Memory value mappings for RevPi DO 1.0 (RevPiDO_20160818_1_0.rap)."""
OUT_PWM_FREQ_40HZ = 1 # 40Hz 1% OUT_PWM_FREQ_40HZ = 1 # 40Hz 1%
OUT_PWM_FREQ_80HZ = 2 # 80Hz 2% OUT_PWM_FREQ_80HZ = 2 # 80Hz 2%
OUT_PWM_FREQ_160HZ = 4 # 160Hz 4% OUT_PWM_FREQ_160HZ = 4 # 160Hz 4%
@@ -170,11 +175,13 @@ class DO:
class DIO(DI, DO): class DIO(DI, DO):
"""Memory value mappings for RevPi DIO 1.0 (RevPiDIO_20160818_1_0.rap).""" """Memory value mappings for RevPi DIO 1.0 (RevPiDIO_20160818_1_0.rap)."""
pass pass
class MIO: class MIO:
"""Memory value mappings for RevPi MIO 1.0 (RevPiMIO_20200901_1_0.rap).""" """Memory value mappings for RevPi MIO 1.0 (RevPiMIO_20200901_1_0.rap)."""
ENCODER_MODE_DISABLED = 0 ENCODER_MODE_DISABLED = 0
ENCODER_MODE_ENABLED = 1 ENCODER_MODE_ENABLED = 1
@@ -193,6 +200,7 @@ class MIO:
class COMPACT: class COMPACT:
"""Memory value mappings for RevPi Compact 1.0 (RevPiCompact_20171023_1_0.rap).""" """Memory value mappings for RevPi Compact 1.0 (RevPiCompact_20171023_1_0.rap)."""
DIN_DEBOUNCE_OFF = 0 # Off DIN_DEBOUNCE_OFF = 0 # Off
DIN_DEBOUNCE_25US = 1 # 25us DIN_DEBOUNCE_25US = 1 # 25us
DIN_DEBOUNCE_750US = 2 # 750us DIN_DEBOUNCE_750US = 2 # 750us
@@ -206,5 +214,6 @@ class COMPACT:
class FLAT: class FLAT:
"""Memory value mappings for RevPi Flat 1.0 (RevPiFlat_20200921_1_0.rap).""" """Memory value mappings for RevPi Flat 1.0 (RevPiFlat_20200921_1_0.rap)."""
IN_RANGE_0_10V = 0 IN_RANGE_0_10V = 0
IN_RANGE_4_20MA = 1 IN_RANGE_4_20MA = 1