mirror of
https://github.com/naruxde/revpimodio2.git
synced 2025-11-08 22:03:53 +01:00
Starke Leistungsverbesserung bei device.get_*s()
auto_refresh in autorefresh überall umbenannt ioerror Zähler auch in RevPiModIO eingebaut _adjwait wird bei Umstellung gleich mit DIFF gesetzt _ba_devdata wird nach IOs vollständig erstellt StructIO Instantiierung vereinfacht / byteorder, signed automatisch
This commit is contained in:
@@ -25,8 +25,10 @@ class DeviceList(object):
|
||||
@return True, wenn Device vorhanden"""
|
||||
if type(key) == int:
|
||||
return key in self.__dict_position
|
||||
else:
|
||||
elif type(key) == str:
|
||||
return hasattr(self, key)
|
||||
else:
|
||||
return key in self.__dict_position.values()
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Gibt angegebenes Device zurueck.
|
||||
@@ -61,13 +63,11 @@ class DeviceList(object):
|
||||
|
||||
class Device(object):
|
||||
|
||||
"""Basisklasse fuer alle Device-Objekte der RevPiDevicelist()-Klasse.
|
||||
"""Basisklasse fuer alle Device-Objekte.
|
||||
|
||||
Die Basisfunktionalitaet generiert bei Instantiierung alle IOs und
|
||||
erweitert den Prozessabbildpuffer um die benoetigten Bytes. Ueber diese
|
||||
Klasse oder von dieser abgeleiteten Klassen, werden alle IOs angesprochen.
|
||||
Sie verwaltet ihren Prozessabbildpuffer und sorgt fuer die Aktualisierung
|
||||
der IO-Werte.
|
||||
erweitert den Prozessabbildpuffer um die benoetigten Bytes. Sie verwaltet
|
||||
ihren Prozessabbildpuffer und sorgt fuer die Aktualisierung der IO-Werte.
|
||||
|
||||
"""
|
||||
|
||||
@@ -78,7 +78,7 @@ class Device(object):
|
||||
@param dict_device dict() fuer dieses Device aus piCotry Konfiguration
|
||||
@param kwargs Weitere Parameter:
|
||||
- autoupdate: Wenn True fuehrt dieses Device Arbeiten am
|
||||
Prozessabbild bei Aufruf der RevPiDevicelist-Funktionen aus
|
||||
Prozessabbild bei Aufruf der read- writeprocimg Funktionen aus
|
||||
- simulator: Laed das Modul als Simulator und vertauscht IOs
|
||||
|
||||
"""
|
||||
@@ -87,7 +87,6 @@ class Device(object):
|
||||
self._dict_events = {}
|
||||
self._filelock = Lock()
|
||||
self._length = 0
|
||||
self._lst_io = []
|
||||
self._selfupdate = False
|
||||
|
||||
self.autoupdate = kwargs.get("autoupdate", True)
|
||||
@@ -98,11 +97,7 @@ class Device(object):
|
||||
self.position = int(dict_device.pop("position"))
|
||||
self.producttype = int(dict_device.pop("productType"))
|
||||
|
||||
# Neues bytearray und Kopie für mainloop anlegen
|
||||
self._ba_devdata = bytearray()
|
||||
self._ba_datacp = bytearray()
|
||||
|
||||
# Erst inp/out/mem poppen, dann in Klasse einfügen
|
||||
# IOM-Objekte erstellen und Adressen in SLCs speichern
|
||||
if kwargs.get("simulator", False):
|
||||
self.slc_inp = self._buildio(dict_device.pop("out"), IOType.INP)
|
||||
self.slc_out = self._buildio(dict_device.pop("inp"), IOType.OUT)
|
||||
@@ -123,6 +118,11 @@ class Device(object):
|
||||
self.slc_mem.start + self.offset, self.slc_mem.stop + self.offset
|
||||
)
|
||||
|
||||
# Neues bytearray und Kopie für mainloop anlegen
|
||||
# NOTE: Testen
|
||||
self._ba_devdata = bytearray(self._length)
|
||||
self._ba_datacp = bytearray()
|
||||
|
||||
# Alle restlichen attribute an Klasse anhängen
|
||||
self.__dict__.update(dict_device)
|
||||
|
||||
@@ -156,8 +156,8 @@ class Device(object):
|
||||
def __iter__(self):
|
||||
"""Gibt Iterator aller IOs zurueck.
|
||||
@return iter() aller IOs"""
|
||||
for i_byte in range(self.slc_devoff.start, self.slc_devoff.stop):
|
||||
for io in self._modio.io[i_byte]:
|
||||
for lst_io in self._modio.io[self.slc_devoff]:
|
||||
for io in lst_io:
|
||||
yield io
|
||||
|
||||
def __len__(self):
|
||||
@@ -178,52 +178,45 @@ class Device(object):
|
||||
@return slice()-Objekt mit Start und Stop Position dieser IOs
|
||||
|
||||
"""
|
||||
if len(dict_io) > 0:
|
||||
int_min, int_max = 4096, 0
|
||||
for key in sorted(dict_io, key=lambda x: int(x)):
|
||||
|
||||
# Neuen IO anlegen
|
||||
if bool(dict_io[key][7]) or self.producttype == 95:
|
||||
# Bei Bitwerten oder Core RevPiIOBase verwenden
|
||||
io_new = iomodule.IOBase(
|
||||
self,
|
||||
dict_io[key],
|
||||
iotype,
|
||||
byteorder="little"
|
||||
)
|
||||
else:
|
||||
io_new = iomodule.IntIO(
|
||||
self,
|
||||
dict_io[key],
|
||||
iotype,
|
||||
byteorder="little"
|
||||
)
|
||||
|
||||
# IO registrieren
|
||||
self._modio.io._register_new_io_object(io_new)
|
||||
|
||||
# Speicherbereich zuweisen
|
||||
self._ba_devdata.extend(bytes(io_new._length))
|
||||
|
||||
self._length += io_new._length
|
||||
|
||||
# Kleinste und größte Speicheradresse ermitteln
|
||||
if io_new.slc_address.start < int_min:
|
||||
int_min = io_new.slc_address.start
|
||||
if io_new.slc_address.stop > int_max:
|
||||
int_max = io_new.slc_address.stop
|
||||
|
||||
return slice(int_min, int_max)
|
||||
|
||||
else:
|
||||
if len(dict_io) <= 0:
|
||||
return slice(0, 0)
|
||||
|
||||
int_min, int_max = 4096, 0
|
||||
for key in sorted(dict_io, key=lambda x: int(x)):
|
||||
|
||||
# Neuen IO anlegen
|
||||
if bool(dict_io[key][7]) or self.producttype == 95:
|
||||
# Bei Bitwerten oder Core RevPiIOBase verwenden
|
||||
io_new = iomodule.IOBase(
|
||||
self, dict_io[key], iotype, "little", False
|
||||
)
|
||||
else:
|
||||
io_new = iomodule.IntIO(
|
||||
self, dict_io[key],
|
||||
iotype,
|
||||
"little",
|
||||
self.producttype == 103
|
||||
)
|
||||
|
||||
# IO registrieren
|
||||
self._modio.io._private_register_new_io_object(io_new)
|
||||
|
||||
self._length += io_new._length
|
||||
|
||||
# Kleinste und größte Speicheradresse ermitteln
|
||||
if io_new.slc_address.start < int_min:
|
||||
int_min = io_new.slc_address.start
|
||||
if io_new.slc_address.stop > int_max:
|
||||
int_max = io_new.slc_address.stop
|
||||
|
||||
return slice(int_min, int_max)
|
||||
|
||||
def _devconfigure(self):
|
||||
"""Funktion zum ueberschreiben von abgeleiteten Klassen."""
|
||||
pass
|
||||
|
||||
def auto_refresh(self, remove=False):
|
||||
"""Registriert ein Device fuer die automatische Synchronisierung.
|
||||
def autorefresh(self, remove=False):
|
||||
"""Registriert dieses Device fuer die automatische Synchronisierung.
|
||||
@param remove bool() True entfernt Device aus Synchronisierung"""
|
||||
if not remove and self not in self._modio._lst_refresh:
|
||||
|
||||
@@ -266,36 +259,37 @@ class Device(object):
|
||||
self._modio.writeprocimg(True, self)
|
||||
|
||||
def get_allios(self):
|
||||
"""Gibt eine Liste aller Inputs und Outputs zurueck.
|
||||
"""Gibt eine Liste aller Inputs und Outputs zurueck, keine MEMs.
|
||||
@return list() Input und Output, keine MEMs"""
|
||||
return [
|
||||
io for io in self._modio.io
|
||||
if io._parentdevice == self and io._iotype != IOType.MEM
|
||||
]
|
||||
lst_return = []
|
||||
for lst_io in self._modio.io[
|
||||
self.slc_inpoff.start:self.slc_outoff.stop]:
|
||||
lst_return += lst_io
|
||||
return lst_return
|
||||
|
||||
def get_inps(self):
|
||||
"""Gibt eine Liste aller Inputs zurueck.
|
||||
@return list() Inputs"""
|
||||
return [
|
||||
io for io in self._modio.io
|
||||
if io._parentdevice == self and io._iotype == IOType.INP
|
||||
]
|
||||
lst_return = []
|
||||
for lst_io in self._modio.io[self.slc_inpoff]:
|
||||
lst_return += lst_io
|
||||
return lst_return
|
||||
|
||||
def get_outs(self):
|
||||
"""Gibt eine Liste aller Outputs zurueck.
|
||||
@return list() Outputs"""
|
||||
return [
|
||||
io for io in self._modio.io
|
||||
if io._parentdevice == self and io._iotype == IOType.OUT
|
||||
]
|
||||
lst_return = []
|
||||
for lst_io in self._modio.io[self.slc_outoff]:
|
||||
lst_return += lst_io
|
||||
return lst_return
|
||||
|
||||
def get_mems(self):
|
||||
"""Gibt eine Liste aller mems zurueck.
|
||||
@return list() Mems"""
|
||||
return [
|
||||
io for io in self._modio.io
|
||||
if io._parentdevice == self and io._iotype == IOType.MEM
|
||||
]
|
||||
lst_return = []
|
||||
for lst_io in self._modio.io[self.slc_memoff]:
|
||||
lst_return += lst_io
|
||||
return lst_return
|
||||
|
||||
|
||||
class Core(Device):
|
||||
|
||||
@@ -228,22 +228,27 @@ class ProcimgWriter(Thread):
|
||||
super().__init__()
|
||||
self._adjwait = 0
|
||||
self._ioerror = 0
|
||||
self._maxioerrors = 0
|
||||
self._modio = parentmodio
|
||||
self._refresh = 0.05
|
||||
self._work = Event()
|
||||
|
||||
self.daemon = True
|
||||
self.lck_refresh = Lock()
|
||||
self.maxioerrors = 0
|
||||
self.newdata = Event()
|
||||
|
||||
def _get_ioerrors(self):
|
||||
"""Ruft aktuelle Anzahl der Fehler ab.
|
||||
@return Aktuelle Fehleranzahl"""
|
||||
return self._ioerror
|
||||
|
||||
def _gotioerror(self):
|
||||
"""IOError Verwaltung fuer auto_refresh."""
|
||||
"""IOError Verwaltung fuer autorefresh."""
|
||||
self._ioerror += 1
|
||||
if self.maxioerrors != 0 and self._ioerror >= self.maxioerrors:
|
||||
if self._maxioerrors != 0 and self._ioerror >= self._maxioerrors:
|
||||
raise RuntimeError(
|
||||
"reach max io error count {} on process image".format(
|
||||
self.maxioerrors
|
||||
self._maxioerrors
|
||||
)
|
||||
)
|
||||
warnings.warn(
|
||||
@@ -251,6 +256,11 @@ class ProcimgWriter(Thread):
|
||||
RuntimeWarning
|
||||
)
|
||||
|
||||
def get_maxioerrors(self):
|
||||
"""Gibt die Anzahl der maximal erlaubten Fehler zurueck.
|
||||
@return Anzahl erlaubte Fehler"""
|
||||
return self._maxioerrors
|
||||
|
||||
def get_refresh(self):
|
||||
"""Gibt Zykluszeit zurueck.
|
||||
@return int() Zykluszeit in Millisekunden"""
|
||||
@@ -342,15 +352,26 @@ class ProcimgWriter(Thread):
|
||||
"""Beendet die automatische Prozessabbildsynchronisierung."""
|
||||
self._work.set()
|
||||
|
||||
def set_maxioerrors(self, value):
|
||||
"""Setzt die Anzahl der maximal erlaubten Fehler.
|
||||
@param value Anzahl erlaubte Fehler"""
|
||||
if type(value) == int and value >= 0:
|
||||
self._maxioerrors = value
|
||||
else:
|
||||
raise ValueError("value must be 0 or a positive integer")
|
||||
|
||||
def set_refresh(self, value):
|
||||
"""Setzt die Zykluszeit in Millisekunden.
|
||||
@param value int() Millisekunden"""
|
||||
if value >= 10 and value < 2000:
|
||||
if type(value) == int and 10 <= value <= 2000:
|
||||
waitdiff = self._refresh - self._adjwait
|
||||
self._refresh = value / 1000
|
||||
self._adjwait = self._refresh
|
||||
self._adjwait = self._refresh - waitdiff
|
||||
else:
|
||||
raise ValueError(
|
||||
"refresh time must be 10 to 2000 milliseconds"
|
||||
)
|
||||
|
||||
ioerrors = property(_get_ioerrors)
|
||||
maxioerrors = property(get_maxioerrors, set_maxioerrors)
|
||||
refresh = property(get_refresh, set_refresh)
|
||||
|
||||
@@ -46,7 +46,7 @@ class IOList(object):
|
||||
object.__delattr__(self, key)
|
||||
|
||||
def __getattr__(self, key):
|
||||
"""Verwaltet geloeschte IOs.
|
||||
"""Verwaltet geloeschte IOs (Attribute, die nicht existieren).
|
||||
@param key Wert eines alten IOs
|
||||
@return Alten IO, wenn in Ref-Listen"""
|
||||
if key in self.__dict_iorefname:
|
||||
@@ -65,6 +65,11 @@ class IOList(object):
|
||||
return self.__dict_iobyte[key]
|
||||
else:
|
||||
raise KeyError("byte '{}' does not exist".format(key))
|
||||
elif type(key) == slice:
|
||||
return [
|
||||
self.__dict_iobyte[int_io]
|
||||
for int_io in range(key.start, key.stop)
|
||||
]
|
||||
else:
|
||||
return getattr(self, key)
|
||||
|
||||
@@ -105,12 +110,11 @@ class IOList(object):
|
||||
"_IOList__dict_iorefbyte"
|
||||
]:
|
||||
object.__setattr__(self, key, value)
|
||||
|
||||
else:
|
||||
# Setzt Wert bei Zuweisung
|
||||
getattr(self, key).value = value
|
||||
|
||||
def __replace_oldio_with_newio(self, io):
|
||||
def __private_replace_oldio_with_newio(self, io):
|
||||
"""Ersetzt bestehende IOs durch den neu Registrierten.
|
||||
@param io Neuer IO der eingefuegt werden soll"""
|
||||
for i in range(io.slc_address.start, io.slc_address.stop):
|
||||
@@ -125,7 +129,6 @@ class IOList(object):
|
||||
io._bitaddress, oldio._name
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
# Bereits überschriebene bytes() sind ungültig
|
||||
raise MemoryError(
|
||||
@@ -133,7 +136,6 @@ class IOList(object):
|
||||
io._name, oldio._name
|
||||
)
|
||||
)
|
||||
|
||||
elif oldio is not None:
|
||||
# IOs im Speicherbereich des neuen IO merken
|
||||
if io._bitaddress >= 0:
|
||||
@@ -144,7 +146,7 @@ class IOList(object):
|
||||
# ios aus listen entfernen
|
||||
delattr(self, oldio.name)
|
||||
|
||||
def _register_new_io_object(self, new_io):
|
||||
def _private_register_new_io_object(self, new_io):
|
||||
"""Registriert neues IO Objekt unabhaenging von __setattr__.
|
||||
@param new_io Neues IO Objekt"""
|
||||
if issubclass(type(new_io), IOBase):
|
||||
@@ -156,7 +158,7 @@ class IOList(object):
|
||||
)
|
||||
|
||||
if type(new_io) is StructIO:
|
||||
self.__replace_oldio_with_newio(new_io)
|
||||
self.__private_replace_oldio_with_newio(new_io)
|
||||
|
||||
object.__setattr__(self, new_io.name, new_io)
|
||||
|
||||
@@ -181,6 +183,10 @@ class IOList(object):
|
||||
print(self.__dict_iorefname)
|
||||
print(self.__dict_iorefbyte)
|
||||
|
||||
def _getdict(self):
|
||||
# NOTE: Nur Debugging
|
||||
return self.__dict_iobyte.copy()
|
||||
|
||||
|
||||
class IOBase(object):
|
||||
|
||||
@@ -196,13 +202,14 @@ class IOBase(object):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, parentdevice, valuelist, iotype, byteorder):
|
||||
def __init__(self, parentdevice, valuelist, iotype, byteorder, signed):
|
||||
"""Instantiierung der IOBase()-Klasse.
|
||||
|
||||
@param parentdevice Parentdevice auf dem der IO liegt
|
||||
@param valuelist Datenliste fuer Instantiierung
|
||||
@param iotype IOType() Wert
|
||||
@param byteorder Byteorder 'little' / 'big' fuer int() Berechnung
|
||||
@param sigend Intberechnung mit Vorzeichen durchfuehren
|
||||
|
||||
"""
|
||||
self._parentdevice = parentdevice
|
||||
@@ -217,7 +224,7 @@ class IOBase(object):
|
||||
self._byteorder = byteorder
|
||||
self._iotype = iotype
|
||||
self._name = valuelist[0]
|
||||
self._signed = False
|
||||
self._signed = signed
|
||||
self.bmk = valuelist[6]
|
||||
|
||||
int_startaddress = int(valuelist[3])
|
||||
@@ -274,22 +281,22 @@ class IOBase(object):
|
||||
@return Namen des IOs"""
|
||||
return self._name
|
||||
|
||||
def _get_address(self):
|
||||
"""Gibt die absolute Byteadresse im Prozessabbild zurueck.
|
||||
@return Absolute Byteadresse"""
|
||||
return self._parentdevice.offset + self.slc_address.start
|
||||
|
||||
def _get_byteorder(self):
|
||||
"""Gibt konfigurierte Byteorder zurueck.
|
||||
@return str() Byteorder"""
|
||||
return self._byteorder
|
||||
|
||||
def get_address(self):
|
||||
"""Gibt die absolute Byteadresse im Prozessabbild zurueck.
|
||||
@return Absolute Byteadresse"""
|
||||
return self._parentdevice.offset + self.slc_address.start
|
||||
|
||||
def get_length(self):
|
||||
def _get_length(self):
|
||||
"""Gibt die Bytelaenge des IO zurueck.
|
||||
@return Bytelaenge des IO"""
|
||||
return self._length
|
||||
|
||||
def get_name(self):
|
||||
def _get_name(self):
|
||||
"""Gibt den Namen des IOs zurueck.
|
||||
@return IO Name"""
|
||||
return self._name
|
||||
@@ -384,12 +391,10 @@ class IOBase(object):
|
||||
io_new = StructIO(
|
||||
self,
|
||||
name,
|
||||
self._iotype,
|
||||
kwargs.get("byteorder", "little"),
|
||||
frm,
|
||||
**kwargs
|
||||
)
|
||||
self._parentdevice._modio.io._register_new_io_object(io_new)
|
||||
self._parentdevice._modio.io._private_register_new_io_object(io_new)
|
||||
|
||||
# Optional Event eintragen
|
||||
reg_event = kwargs.get("event", None)
|
||||
@@ -473,7 +478,7 @@ class IOBase(object):
|
||||
"""Wartet auf Wertaenderung eines IOs.
|
||||
|
||||
Die Wertaenderung wird immer uerberprueft, wenn fuer Devices
|
||||
in Devicelist.auto_refresh() neue Daten gelesen wurden.
|
||||
mit aktiviertem autorefresh neue Daten gelesen wurden.
|
||||
|
||||
Bei Wertaenderung, wird das Warten mit 0 als Rueckgabewert beendet.
|
||||
|
||||
@@ -493,7 +498,7 @@ class IOBase(object):
|
||||
|
||||
Der Timeoutwert bricht beim Erreichen das Warten sofort mit
|
||||
Wert 2 Rueckgabewert ab. (Das Timeout wird ueber die Zykluszeit
|
||||
der auto_refresh Funktion berechnet, entspricht also nicht exact den
|
||||
der autorefresh Funktion berechnet, entspricht also nicht exact den
|
||||
angegeben Millisekunden! Es wird immer nach oben gerundet!)
|
||||
|
||||
@param edge Flanke RISING, FALLING, BOTH bei der mit True beendet wird
|
||||
@@ -510,10 +515,10 @@ class IOBase(object):
|
||||
Wert 100: Devicelist.exit() wurde aufgerufen
|
||||
|
||||
"""
|
||||
# Prüfen ob Device in auto_refresh ist
|
||||
# Prüfen ob Device in autorefresh ist
|
||||
if not self._parentdevice._selfupdate:
|
||||
raise RuntimeError(
|
||||
"auto_refresh is not activated for device '{}|{}' - there "
|
||||
"autorefresh is not activated for device '{}|{}' - there "
|
||||
"will never be new data".format(
|
||||
self._parentdevice.position, self._parentdevice.name
|
||||
)
|
||||
@@ -570,9 +575,10 @@ class IOBase(object):
|
||||
# Timeout abgelaufen
|
||||
return 2
|
||||
|
||||
address = property(get_address)
|
||||
length = property(get_length)
|
||||
name = property(get_name)
|
||||
address = property(_get_address)
|
||||
byteorder = property(_get_byteorder)
|
||||
length = property(_get_length)
|
||||
name = property(_get_name)
|
||||
value = property(get_value, set_value)
|
||||
|
||||
|
||||
@@ -651,29 +657,28 @@ class StructIO(IOBase):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, parentio, name, iotype, byteorder, frm, **kwargs):
|
||||
def __init__(self, parentio, name, frm, **kwargs):
|
||||
"""Erstellt einen IO mit struct-Formatierung.
|
||||
|
||||
@param parentio ParentIO Objekt, welches ersetzt wird
|
||||
@param name Name des neuen IO
|
||||
@param iotype IOType() Wert
|
||||
@param byteorder Byteorder 'little' / 'big' fuer int() Berechnung
|
||||
@param frm struct() formatierung (1 Zeichen)
|
||||
@param kwargs Weitere Parameter:
|
||||
- bmk: Bezeichnung fuer Output
|
||||
- bit: Registriert Outputs als bool() am angegebenen Bit im Byte
|
||||
- byteorder: Byteorder fuer den Input, Standardwert=little
|
||||
- defaultvalue: Standardwert fuer Output, Standard ist 0
|
||||
|
||||
"""
|
||||
if len(frm) == 1:
|
||||
# Byteorder prüfen und übernehmen
|
||||
byteorder = kwargs.get("byteorder", "little")
|
||||
if not (byteorder == "little" or byteorder == "big"):
|
||||
raise ValueError("byteorder must be 'little' or 'big'")
|
||||
bofrm = "<" if byteorder == "little" else ">"
|
||||
|
||||
bitaddress = "" if frm != "?" else str(kwargs.get("bit", 0))
|
||||
if bitaddress == "" or \
|
||||
(int(bitaddress) >= 0 and int(bitaddress) < 8):
|
||||
if bitaddress == "" or (0 <= int(bitaddress) < 8):
|
||||
|
||||
bitlength = "1" if bitaddress.isnumeric() else \
|
||||
struct.calcsize(bofrm + frm) * 8
|
||||
@@ -698,19 +703,31 @@ class StructIO(IOBase):
|
||||
raise AttributeError("parameter frm has to be a single sign")
|
||||
|
||||
# Basisklasse instantiieren
|
||||
super().__init__(parentio._parentdevice, valuelist, iotype, byteorder)
|
||||
# parentdevice, valuelist, iotype, byteorder, signed
|
||||
super().__init__(
|
||||
parentio._parentdevice,
|
||||
valuelist,
|
||||
parentio._iotype,
|
||||
byteorder,
|
||||
frm == frm.lower()
|
||||
)
|
||||
self.frm = frm
|
||||
|
||||
# Platz für neuen IO prüfen
|
||||
if not (self.slc_address.start >=
|
||||
parentio._parentdevice._dict_slc[iotype].start and
|
||||
parentio._parentdevice._dict_slc[parentio._iotype].start and
|
||||
self.slc_address.stop <=
|
||||
parentio._parentdevice._dict_slc[iotype].stop):
|
||||
parentio._parentdevice._dict_slc[parentio._iotype].stop):
|
||||
|
||||
raise BufferError(
|
||||
"registered value does not fit process image scope"
|
||||
)
|
||||
|
||||
def _get_signed(self):
|
||||
"""Ruft ab, ob der Wert Vorzeichenbehaftet behandelt werden soll.
|
||||
@return True, wenn Vorzeichenbehaftet"""
|
||||
return self._signed
|
||||
|
||||
def get_structvalue(self):
|
||||
"""Gibt den Wert mit struct Formatierung zurueck.
|
||||
@return Wert vom Typ der struct-Formatierung"""
|
||||
@@ -727,7 +744,7 @@ class StructIO(IOBase):
|
||||
else:
|
||||
self.set_value(struct.pack(self.frm, value))
|
||||
|
||||
byteorder = property(IOBase._get_byteorder)
|
||||
signed = property(_get_signed)
|
||||
value = property(get_structvalue, set_structvalue)
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class RevPiModIO(object):
|
||||
"""Instantiiert die Grundfunktionen.
|
||||
|
||||
@param kwargs Weitere Parameter:
|
||||
- auto_refresh: Wenn True, alle Devices zu auto_refresh hinzufuegen
|
||||
- autorefresh: Wenn True, alle Devices zu autorefresh hinzufuegen
|
||||
- configrsc: Pfad zur piCtory Konfigurationsdatei
|
||||
- procimg: Pfad zum Prozessabbild
|
||||
- monitoring: In- und Outputs werden gelesen, niemals geschrieben
|
||||
@@ -45,7 +45,7 @@ class RevPiModIO(object):
|
||||
- syncoutputs: Aktuell gesetzte Outputs vom Prozessabbild einlesen
|
||||
|
||||
"""
|
||||
self._auto_refresh = kwargs.get("auto_refresh", False)
|
||||
self._autorefresh = kwargs.get("autorefresh", False)
|
||||
self._configrsc = kwargs.get("configrsc", None)
|
||||
self._monitoring = kwargs.get("monitoring", False)
|
||||
self._procimg = kwargs.get("procimg", "/dev/piControl0")
|
||||
@@ -59,10 +59,12 @@ class RevPiModIO(object):
|
||||
self._buffedwrite = False
|
||||
self._exit = Event()
|
||||
self._imgwriter = None
|
||||
self._ioerror = 0
|
||||
self._length = 0
|
||||
self._looprunning = False
|
||||
self._lst_devselect = []
|
||||
self._lst_refresh = []
|
||||
self._maxioerrors = 0
|
||||
self._myfh = self._create_myfh()
|
||||
self._th_mainloop = None
|
||||
self._waitexit = Event()
|
||||
@@ -209,10 +211,9 @@ class RevPiModIO(object):
|
||||
if self._syncoutputs:
|
||||
self.syncoutputs(force=True)
|
||||
|
||||
# Optional ins auto_refresh aufnehmen
|
||||
if self._auto_refresh:
|
||||
for dev in self.device:
|
||||
dev.auto_refresh()
|
||||
# Optional ins autorefresh aufnehmen
|
||||
if self._autorefresh:
|
||||
self.autorefresh_all()
|
||||
|
||||
# Summary Klasse instantiieren
|
||||
self.summary = summarymodule.Summary(jconfigrsc["Summary"])
|
||||
@@ -233,11 +234,21 @@ class RevPiModIO(object):
|
||||
@return Millisekunden"""
|
||||
return self._imgwriter.refresh
|
||||
|
||||
def _get_ioerrors(self):
|
||||
"""Getter function.
|
||||
@return Aktuelle Anzahl gezaehlter Fehler"""
|
||||
return self._ioerror
|
||||
|
||||
def _get_length(self):
|
||||
"""Getter function.
|
||||
@return Laenge in Bytes der Devices"""
|
||||
return self._length
|
||||
|
||||
def _get_maxioerrors(self):
|
||||
"""Getter function.
|
||||
@return Anzahl erlaubte Fehler"""
|
||||
return self._maxioerrors
|
||||
|
||||
def _get_monitoring(self):
|
||||
"""Getter function.
|
||||
@return True, wenn als Monitoring gestartet"""
|
||||
@@ -253,26 +264,43 @@ class RevPiModIO(object):
|
||||
@return True, wenn als Simulator gestartet"""
|
||||
return self._simulator
|
||||
|
||||
def _gotioerror(self, action):
|
||||
"""IOError Verwaltung fuer Prozessabbildzugriff."""
|
||||
self._ioerror += 1
|
||||
if self._maxioerrors != 0 and self._ioerror >= self._maxioerrors:
|
||||
raise RuntimeError(
|
||||
"reach max io error count {} on process image".format(
|
||||
self._maxioerrors
|
||||
)
|
||||
)
|
||||
warnings.warn(
|
||||
"got io error during {} and count {} errors now".format(
|
||||
self._ioerror, self._ioerror
|
||||
),
|
||||
RuntimeWarning
|
||||
)
|
||||
|
||||
def _set_cycletime(self, milliseconds):
|
||||
"""Setzt Aktualisierungsrate der Prozessabbild-Synchronisierung.
|
||||
@param milliseconds int() in Millisekunden"""
|
||||
self._imgwriter.refresh = milliseconds
|
||||
|
||||
def auto_refresh_maxioerrors(self, value=None):
|
||||
"""Maximale IO Fehler fuer auto_refresh.
|
||||
@param value Setzt maximale Anzahl bis exception ausgeloest wird
|
||||
@return Maximale Anzahl bis exception ausgeloest wird"""
|
||||
if value is None:
|
||||
return self._imgwriter.maxioerrors
|
||||
elif type(value) == int and value >= 0:
|
||||
def _set_maxioerrors(self, value):
|
||||
"""Setzt Anzahl der maximal erlaubten Fehler bei Prozessabbildzugriff.
|
||||
@param value Anzahl erlaubte Fehler"""
|
||||
if type(value) == int and value >= 0:
|
||||
self._maxioerrors = value
|
||||
self._imgwriter.maxioerrors = value
|
||||
else:
|
||||
raise ValueError("value must be 0 or a positive integer")
|
||||
|
||||
def auto_refresh_resetioerrors(self):
|
||||
"""Setzt aktuellen IOError-Zaehler auf 0 zurueck."""
|
||||
self._imgwriter.maxioerrors = 0
|
||||
def autorefresh_all(self):
|
||||
"""Setzt alle Devices in autorefresh Funktion."""
|
||||
for dev in self.device:
|
||||
dev.autorefresh()
|
||||
|
||||
def cleanup(self):
|
||||
"""Beendet auto_refresh und alle Threads."""
|
||||
"""Beendet autorefresh und alle Threads."""
|
||||
self.exit(full=True)
|
||||
self._myfh.close()
|
||||
self.app = None
|
||||
@@ -297,15 +325,14 @@ class RevPiModIO(object):
|
||||
revpimodio.exit().
|
||||
|
||||
HINWEIS: Die Aktualisierungszeit und die Laufzeit der Funktion duerfen
|
||||
die eingestellte auto_refresh Zeit, bzw. uebergebene cycletime nicht
|
||||
die eingestellte autorefresh Zeit, bzw. uebergebene cycletime nicht
|
||||
ueberschreiten!
|
||||
|
||||
Ueber den Parameter cycletime kann die Aktualisierungsrate fuer das
|
||||
Prozessabbild gesetzt werden (selbe Funktion wie
|
||||
set_refreshtime(milliseconds)).
|
||||
Ueber das Attribut cycletime kann die Aktualisierungsrate fuer das
|
||||
Prozessabbild gesetzt werden.
|
||||
|
||||
@param func Funktion, die ausgefuehrt werden soll
|
||||
@param cycletime auto_refresh Wert in Millisekunden
|
||||
@param cycletime autorefresh Wert in Millisekunden
|
||||
@return None
|
||||
|
||||
"""
|
||||
@@ -315,9 +342,9 @@ class RevPiModIO(object):
|
||||
"can not start multiple loops mainloop/cycleloop"
|
||||
)
|
||||
|
||||
# Prüfen ob Devices in auto_refresh sind
|
||||
# Prüfen ob Devices in autorefresh sind
|
||||
if len(self._lst_refresh) == 0:
|
||||
raise RuntimeError("no device with auto_refresh activated")
|
||||
raise RuntimeError("no device with autorefresh activated")
|
||||
|
||||
# Prüfen ob Funktion callable ist
|
||||
if not callable(func):
|
||||
@@ -337,18 +364,18 @@ class RevPiModIO(object):
|
||||
# Auf neue Daten warten und nur ausführen wenn set()
|
||||
if not self._imgwriter.newdata.wait(2.5):
|
||||
if not self._exit.is_set() and not self._imgwriter.is_alive():
|
||||
raise RuntimeError("auto_refresh thread not running")
|
||||
raise RuntimeError("autorefresh thread not running")
|
||||
continue
|
||||
self._imgwriter.newdata.clear()
|
||||
|
||||
# Vor Aufruf der Funktion auto_refresh sperren
|
||||
# Vor Aufruf der Funktion autorefresh sperren
|
||||
self._imgwriter.lck_refresh.acquire()
|
||||
|
||||
# Funktion aufrufen und auswerten
|
||||
ec = func(cycleinfo)
|
||||
cycleinfo._docycle()
|
||||
|
||||
# auto_refresh freigeben
|
||||
# autorefresh freigeben
|
||||
self._imgwriter.lck_refresh.release()
|
||||
|
||||
# Cycleloop beenden
|
||||
@@ -357,16 +384,16 @@ class RevPiModIO(object):
|
||||
return ec
|
||||
|
||||
def exit(self, full=True):
|
||||
"""Beendet mainloop() und optional auto_refresh.
|
||||
"""Beendet mainloop() und optional autorefresh.
|
||||
|
||||
Wenn sich das Programm im mainloop() befindet, wird durch Aufruf
|
||||
von exit() die Kontrolle wieder an das Hauptprogramm zurueckgegeben.
|
||||
|
||||
Der Parameter full ist mit True vorbelegt und entfernt alle Devices aus
|
||||
dem auto_refresh. Der Thread fuer die Prozessabbildsynchronisierung
|
||||
dem autorefresh. Der Thread fuer die Prozessabbildsynchronisierung
|
||||
wird dann gestoppt und das Programm kann sauber beendet werden.
|
||||
|
||||
@param full Entfernt auch alle Devices aus auto_refresh"""
|
||||
@param full Entfernt auch alle Devices aus autorefresh"""
|
||||
self._exit.set()
|
||||
self._waitexit.set()
|
||||
if full:
|
||||
@@ -469,9 +496,9 @@ class RevPiModIO(object):
|
||||
"can not start multiple loops mainloop/cycleloop"
|
||||
)
|
||||
|
||||
# Prüfen ob Devices in auto_refresh sind
|
||||
# Prüfen ob Devices in autorefresh sind
|
||||
if len(self._lst_refresh) == 0:
|
||||
raise RuntimeError("no device with auto_refresh activated")
|
||||
raise RuntimeError("no device with autorefresh activated")
|
||||
|
||||
# Thread erstellen, wenn nicht blockieren soll
|
||||
if not blocking:
|
||||
@@ -498,7 +525,7 @@ class RevPiModIO(object):
|
||||
# Auf neue Daten warten und nur ausführen wenn set()
|
||||
if not self._imgwriter.newdata.wait(2.5):
|
||||
if not self._exit.is_set() and not self._imgwriter.is_alive():
|
||||
raise RuntimeError("auto_refresh thread not running")
|
||||
raise RuntimeError("autorefresh thread not running")
|
||||
continue
|
||||
|
||||
self._imgwriter.newdata.clear()
|
||||
@@ -593,7 +620,7 @@ class RevPiModIO(object):
|
||||
if dev._selfupdate:
|
||||
raise RuntimeError(
|
||||
"can not read process image, while device '{}|{}'"
|
||||
"is in auto_refresh mode".format(dev.position, dev.name)
|
||||
"is in autorefresh mode".format(dev.position, dev.name)
|
||||
)
|
||||
mylist = [dev]
|
||||
|
||||
@@ -602,10 +629,7 @@ class RevPiModIO(object):
|
||||
self._myfh.seek(0)
|
||||
bytesbuff = self._myfh.read(self._length)
|
||||
except IOError:
|
||||
warnings.warn(
|
||||
"read error on process image '{}'".format(self.myfh.name),
|
||||
RuntimeWarning
|
||||
)
|
||||
self._gotioerror("read")
|
||||
return False
|
||||
|
||||
for dev in mylist:
|
||||
@@ -628,6 +652,11 @@ class RevPiModIO(object):
|
||||
|
||||
return True
|
||||
|
||||
def resetioerrors(self):
|
||||
"""Setzt aktuellen IOError-Zaehler auf 0 zurueck."""
|
||||
self._ioerror = 0
|
||||
self._imgwriter._ioerror = 0
|
||||
|
||||
def setdefaultvalues(self, force=False, device=None):
|
||||
"""Alle Outputbuffer werden auf die piCtory default Werte gesetzt.
|
||||
@param force auch Devices mit autoupdate=False
|
||||
@@ -667,7 +696,7 @@ class RevPiModIO(object):
|
||||
if dev._selfupdate:
|
||||
raise RuntimeError(
|
||||
"can not sync process image, while device '{}|{}'"
|
||||
"is in auto_refresh mode".format(dev.position, dev.name)
|
||||
"is in autorefresh mode".format(dev.position, dev.name)
|
||||
)
|
||||
mylist = [dev]
|
||||
|
||||
@@ -675,10 +704,7 @@ class RevPiModIO(object):
|
||||
self._myfh.seek(0)
|
||||
bytesbuff = self._myfh.read(self._length)
|
||||
except IOError:
|
||||
warnings.warn(
|
||||
"read error on process image '{}'".format(self._myfh.name),
|
||||
RuntimeWarning
|
||||
)
|
||||
self._gotioerror("read")
|
||||
return False
|
||||
|
||||
for dev in mylist:
|
||||
@@ -731,11 +757,7 @@ class RevPiModIO(object):
|
||||
if self._buffedwrite:
|
||||
self._myfh.flush()
|
||||
except IOError:
|
||||
warnings.warn(
|
||||
"write error on process image '{}'"
|
||||
"".format(self._myfh.name),
|
||||
RuntimeWarning
|
||||
)
|
||||
self._gotioerror("write")
|
||||
workokay = False
|
||||
|
||||
dev._filelock.release()
|
||||
@@ -764,7 +786,7 @@ class RevPiModIO(object):
|
||||
if dev._selfupdate:
|
||||
raise RuntimeError(
|
||||
"can not write process image, while device '{}|{}'"
|
||||
"is in auto_refresh mode".format(dev.position, dev.name)
|
||||
"is in autorefresh mode".format(dev.position, dev.name)
|
||||
)
|
||||
mylist = [dev]
|
||||
|
||||
@@ -789,17 +811,15 @@ class RevPiModIO(object):
|
||||
workokay = False
|
||||
|
||||
if not workokay:
|
||||
warnings.warn(
|
||||
"write error on process image '{}'"
|
||||
"".format(self._myfh.name),
|
||||
RuntimeWarning
|
||||
)
|
||||
self._gotioerror("write")
|
||||
|
||||
return workokay
|
||||
|
||||
configrsc = property(_get_configrsc)
|
||||
cycletime = property(_get_cycletime, _set_cycletime)
|
||||
ioerrors = property(_get_ioerrors)
|
||||
length = property(_get_length)
|
||||
maxioerrors = property(_get_maxioerrors, _set_maxioerrors)
|
||||
monitoring = property(_get_monitoring)
|
||||
procimg = property(_get_procimg)
|
||||
simulator = property(_get_simulator)
|
||||
|
||||
Reference in New Issue
Block a user