Erste Debug-Version

This commit is contained in:
2017-08-14 16:12:44 +02:00
parent fa920b61ed
commit d733038563
17 changed files with 3230 additions and 243 deletions

View File

@@ -36,6 +36,7 @@ BOTH = 33
warnings.simplefilter(action="always")
class IOType(object):
"""IO Typen."""

View File

@@ -5,10 +5,8 @@
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
import struct
"""Modul fuer die Verwaltung der Devices."""
from threading import Lock
from . import io as iomodule
from .__init__ import IOType
from .helper import ProcimgWriter
@@ -42,7 +40,13 @@ class DeviceList(object):
def __iter__(self):
"""Gibt Iterator aller Devices zurueck.
@return iter() aller Devices"""
return iter(self.__dict_position.values())
for dev in sorted(self.__dict_position):
yield self.__dict_position[dev]
def __len__(self):
"""Gibt Anzahl der Devices zurueck.
return Anzahl der Devices"""
return len(self.__dict_position)
def __setattr__(self, key, value):
"""Setzt Attribute nur wenn Device.
@@ -107,9 +111,6 @@ class Device(object):
self.slc_out = self._buildio(dict_device.pop("out"), IOType.OUT)
self.slc_mem = self._buildio(dict_device.pop("mem"), IOType.MEM)
# Alle IOs nach Adresse sortieren
self._lst_io.sort(key=lambda x: x.slc_address.start)
# SLCs mit offset berechnen
self.slc_devoff = slice(self.offset, self.offset + self._length)
self.slc_inpoff = slice(
@@ -138,29 +139,14 @@ class Device(object):
@param key IO-Name str() / IO-Bytenummer int()
@return True, wenn device vorhanden"""
if type(key) == str:
return hasattr(self._modio.io, key)
if type(key) == int:
key += self.offset
return hasattr(self._modio.io, key) \
and getattr(self._modio.io, key)._parentdevice == self
elif type(key) == int:
return key in self._modio.io \
and len(self._modio.io[key]) > 0
and len(self._modio.io[key]) > 0 \
and self._modio.io[key][0]._parentdevice == self
else:
return key in self._lst_io
def __getitem__(self, key):
"""Gibt angegebenes IO-Objekt zurueck.
@param key Name order Byteadresse des IOs
@return IO-Objekt wenn Name, sonst list() mit IO-Objekt"""
if type(key) == int:
key += self.offset
if key in self._modio.io:
return self._modio.io[key]
else:
raise KeyError("byte '{}' does not exist".format(key))
else:
if hasattr(self._modio.io, key):
return getattr(self._modio.io, key)
else:
raise KeyError("'{}' does not exist".format(key))
return key._parentdevice == self
def __int__(self):
"""Gibt die Positon im RevPi Bus zurueck.
@@ -170,34 +156,20 @@ class Device(object):
def __iter__(self):
"""Gibt Iterator aller IOs zurueck.
@return iter() aller IOs"""
return iter(self._lst_io)
for i_byte in range(self.slc_devoff.start, self.slc_devoff.stop):
for io in self._modio.io[i_byte]:
yield io
def __len__(self):
"""Gibt Anzahl der Bytes zurueck, die dieses Device belegt.
@return int()"""
return self._length
def __str__(self):
"""Gibt den Namen des Devices zurueck.
@return Devicename"""
return self.name
def __setitem__(self, key, value):
"""Setzt den Wert des angegebenen Inputs.
@param key Name oder Byte des Inputs
@param value Wert der gesetzt werden soll"""
if type(key) == int:
key += self.offset
if key in self._modio.io:
if len(self._modio.io[key]) == 1:
self._modio.io[key][0].value = value
elif len(self._modio.io[key]) == 0:
raise KeyError("byte '{}' contains no input".format(key))
else:
raise KeyError(
"byte '{}' contains more than one bit-input"
"".format(key)
)
else:
raise KeyError("byte '{}' does not exist".format(key))
else:
getattr(self._modio.io, key).value = value
def _buildio(self, dict_io, iotype):
"""Erstellt aus der piCtory-Liste die IOs fuer dieses Device.
@@ -228,22 +200,12 @@ class Device(object):
)
# IO registrieren
if hasattr(self._modio.io, io_new.name):
raise NameError(
"name '{}' already exists on device '{}'".format(
io_new._name, self.name
)
)
else:
# Namesregister aufbauen
setattr(self._modio.io, io_new._name, io_new)
self._modio.io._register_new_io_object(io_new)
# Speicherbereich zuweisen
self._ba_devdata.extend(bytes(io_new._length))
# Speicherbereich zuweisen
self._ba_devdata.extend(bytes(io_new._length))
# IO eintragen
self._lst_io.append(io_new)
self._length += io_new._length
self._length += io_new._length
# Kleinste und größte Speicheradresse ermitteln
if io_new.slc_address.start < int_min:
@@ -303,45 +265,38 @@ class Device(object):
if not self._modio._monitoring:
self._modio.writeprocimg(True, self)
def get_allios(self):
"""Gibt eine Liste aller Inputs und Outputs zurueck.
@return list() Input und Output, keine MEMs"""
return [
io for io in self._modio.io
if io._parentdevice == self and io._iotype != IOType.MEM
]
def get_inps(self):
"""Gibt eine Liste aller Inputs zurueck.
@return list() Inputs"""
return [
io for io in self._lst_io if io._iotype == IOType.INP
io for io in self._modio.io
if io._parentdevice == self and io._iotype == IOType.INP
]
def get_outs(self):
"""Gibt eine Liste aller Outputs zurueck.
@return list() Outputs"""
return [
io for io in self._lst_io if io._iotype == IOType.OUT
io for io in self._modio.io
if io._parentdevice == self and io._iotype == IOType.OUT
]
def get_mems(self):
"""Gibt eine Liste aller mems zurueck.
@return list() Mems"""
return [
io for io in self._lst_io if io._iotype == IOType.MEM
io for io in self._modio.io
if io._parentdevice == self and io._iotype == IOType.MEM
]
def get_iobyabsaddress(self, address):
"""Gibt das IO-Objekt an angegebenen Byte im Prozessabbild zurueck.
@param address Byteadresse im Prozessabbild
@return list() mit IO-Objekt/en"""
return self[address - self.offset]
def get_iobyaddress(self, address):
"""Gibt das IO-Objekt an angegebenen Byte des Devices zurueck.
@param address Byteadresse im Deviceabbild
@return list() mit IO-Objekt/en"""
return self[address]
def get_iobyname(self, name):
"""Gibt das IO-Objekt mit angegebenen Namen zurueck.
@param name Name des IO-Objekts
@return IO-Objekt"""
return getattr(self._modio.io, name)
class Core(Device):
@@ -361,6 +316,9 @@ class Core(Device):
self._ioerrorlimit1 = None
self._ioerrorlimit2 = None
# Eigene IO-Liste aufbauen
self._lst_io = [x for x in self.__iter__()]
int_lenio = len(self._lst_io)
if int_lenio == 6:
# Core 1.1
@@ -584,38 +542,12 @@ class Gateway(Device):
@see #RevPiDevice.__init__ RevPiDevice.__init__(...)"""
super().__init__(parent, dict_device, **kwargs)
# TODO: evtl. an modio.io anhängen
self._dict_iorefbyte = {}
self._dict_iorefname = {}
self._dict_slc = {
IOType.INP: self.slc_inp,
IOType.OUT: self.slc_out,
IOType.MEM: self.slc_mem
}
def _getbytename(self, iobyte):
"""Ermittelt den Namen eines IOs auf der Byteadresse.
@param iobyte Bytenummer
@return IO-Namen"""
# Wenn IO schon ausgetauscht wurde
if iobyte in self._dict_iorefbyte:
return self._dict_iorefbyte[iobyte]
# Wenn IO jetzt ausgetauscht wird
if iobyte in self._modio.io:
intlen = len(self._modio.io[iobyte])
if intlen == 1:
return self._modio.io[iobyte][0].name
elif len == 0:
raise KeyError("byte '{}' contains no input".format(iobyte))
else:
raise KeyError(
"byte '{}' contains more than one bit-input".format(iobyte)
)
else:
raise KeyError("byte '{}' does not exist".format(iobyte))
def get_rawbytes(self):
"""Gibt die Bytes aus, die dieses Device verwendet.
@return bytes() des Devices"""
@@ -635,3 +567,7 @@ class Virtual(Gateway):
"""
pass
# Nachträglicher Import
from . import io as iomodule

View File

@@ -5,6 +5,7 @@
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
"""RevPiModIO Helperklassen und Tools."""
import warnings
from threading import Event, Lock, Thread
from timeit import default_timer

View File

@@ -5,10 +5,9 @@
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
"""RevPiModIO Modul fuer die Verwaltung der IOs."""
import struct
from threading import Event
from . import device as devicemodule
from .__init__ import RISING, FALLING, BOTH, IOType
@@ -17,13 +16,15 @@ class IOList(object):
"""Basisklasse fuer direkten Zugriff auf IO Objekte."""
def __init__(self):
"""Init IOList clacc."""
"""Init IOList class."""
self.__dict_iobyte = {k: [] for k in range(4096)}
self.__dict_iorefbyte = {}
self.__dict_iorefname = {}
def __contains__(self, key):
"""Prueft ob IO existiert.
@param key IO-Name str()
@return True, wenn IO vorhanden"""
@param key IO-Name str() oder Byte int()
@return True, wenn IO vorhanden / Byte belegt"""
if type(key) == int:
return key in self.__dict_iobyte \
and len(self.__dict_iobyte[key]) > 0
@@ -34,12 +35,27 @@ class IOList(object):
"""Entfernt angegebenen IO.
@param key IO zum entfernen"""
# TODO: Prüfen ob auch Bit sein kann
# FIXME: IO von DeviceIO Liste entfernen
# FIXME: IO aus Eventhandling entfernen
dev = getattr(self, key)
self.__dict_iobyte[dev.address].remove(dev)
io_del = getattr(self, key)
# Alte Events vom Device löschen
io_del.unreg_event()
# IO aus Byteliste und Attributen entfernen
self.__dict_iobyte[io_del.address].remove(io_del)
object.__delattr__(self, key)
def __getattr__(self, key):
"""Verwaltet geloeschte IOs.
@param key Wert eines alten IOs
@return Alten IO, wenn in Ref-Listen"""
if key in self.__dict_iorefname:
return self.__dict_iorefname[key]
elif key in self.__dict_iorefbyte:
return self.__dict_iorefbyte[key]
else:
raise AttributeError("can not find io '{}'".format(key))
def __getitem__(self, key):
"""Ruft angegebenen IO ab.
@param key IO Name oder Byte
@@ -83,42 +99,23 @@ class IOList(object):
"""Setzt IO Wert.
@param key IO Name oder Byte
@param value Wert, auf den der IO gesetzt wird"""
if issubclass(type(value), IOBase):
if hasattr(self, key):
raise AttributeError(
"attribute {} already exists - can not set io".format(key)
)
object.__setattr__(self, key, value)
# Bytedict erstellen für Adresszugriff
if value._bitaddress < 0:
self.__dict_iobyte[value.address].append(value)
else:
if len(self.__dict_iobyte[value.address]) != 8:
# "schnell" 8 Einträge erstellen da es BIT IOs sind
self.__dict_iobyte[value.address] += [
None, None, None, None, None, None, None, None
]
self.__dict_iobyte[value.address][value._bitaddress] = value
elif key == "_IOList__dict_iobyte":
if key in [
"_IOList__dict_iobyte",
"_IOList__dict_iorefname",
"_IOList__dict_iorefbyte"
]:
object.__setattr__(self, key, value)
else:
# Setzt Wert bei Zuweisung
getattr(self, key).value = value
def _replace_io(self, io):
def __replace_oldio_with_newio(self, io):
"""Ersetzt bestehende IOs durch den neu Registrierten.
@param io Neuer IO der eingefuegt werden soll"""
dict_oldio = {}
for oldio in self._lst_io:
# Alle IOs Prüfen ob sie im neuen Speicherbereich sind
errstart = oldio.slc_address.start >= io.slc_address.start \
and oldio.slc_address.start < io.slc_address.stop
errstop = oldio.slc_address.stop > io.slc_address.start \
and oldio.slc_address.stop <= io.slc_address.stop
for i in range(io.slc_address.start, io.slc_address.stop):
for oldio in self.__dict_iobyte[i + io._parentdevice.offset]:
if errstart or errstop:
if type(oldio) == StructIO:
# Hier gibt es schon einen neuen IO
if oldio._bitaddress >= 0:
@@ -137,39 +134,52 @@ class IOList(object):
)
)
else:
elif oldio is not None:
# IOs im Speicherbereich des neuen IO merken
dict_oldio[oldio.name] = oldio
for oldio in dict_oldio.values():
if io._bitaddress >= 0:
# ios für ref bei bitaddress speichern
self._dict_iorefbyte[oldio.slc_address.start] = oldio.name
self._dict_iorefname[oldio.name] = oldio.slc_address.start
# ios aus listen entfernen
delattr(self._modio.io, oldio.name)
self._lst_io.remove(oldio)
# Namensregister erweitern
setattr(self._modio.io, io.name, io)
# io einfügen (auch wenn nicht richtige stelle wegen BitOffset)
self._lst_io.insert(io.slc_address.start, io)
# Liste neu sortieren
self._lst_io.sort(key=lambda x: x.slc_address.start)
if io._bitaddress >= 0:
# ios für ref bei bitaddress speichern
self.__dict_iorefbyte[oldio.slc_address.start] = oldio
self.__dict_iorefname[oldio.name] = oldio
# ios aus listen entfernen
delattr(self, oldio.name)
def _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):
if hasattr(self, new_io.name):
raise AttributeError(
"attribute {} already exists - can not set io".format(
new_io.name
)
)
if type(new_io) is StructIO:
self.__replace_oldio_with_newio(new_io)
object.__setattr__(self, new_io.name, new_io)
# Bytedict erstellen für Adresszugriff
if new_io._bitaddress < 0:
self.__dict_iobyte[new_io.address].append(new_io)
else:
if len(self.__dict_iobyte[new_io.address]) != 8:
# "schnell" 8 Einträge erstellen da es BIT IOs sind
self.__dict_iobyte[new_io.address] += [
None, None, None, None, None, None, None, None
]
self.__dict_iobyte[new_io.address][new_io._bitaddress] = new_io
else:
raise AttributeError("io must be IOBase or sub class")
def _testme(self):
# NOTE: Nur Debugging
for x in self.__dict_iobyte:
if len(self.__dict_iobyte[x]) > 0:
print(x, self.__dict_iobyte[x])
print(self.__dict_iorefname)
print(self.__dict_iorefbyte)
class IOBase(object):
@@ -346,8 +356,8 @@ class IOBase(object):
)
break
def reg_inp(self, name, frm, **kwargs):
"""Registriert einen neuen Input an Adresse von Diesem.
def replace_io(self, name, frm, **kwargs):
"""Ersetzt bestehenden IO mit Neuem.
@param name Name des neuen Inputs
@param frm struct() formatierung (1 Zeichen)
@@ -364,7 +374,7 @@ class IOBase(object):
>Python3 struct()</a>
"""
if not issubclass(self._parentdevice, devicemodule.Gateway):
if not issubclass(type(self._parentdevice), Gateway):
raise RuntimeError(
"this function can be used for ios on gatway or virtual "
"devices only"
@@ -372,14 +382,14 @@ class IOBase(object):
# StructIO erzeugen und in IO-Liste einfügen
io_new = StructIO(
self._parentdevice,
self,
name,
IOType.INP,
self._iotype,
kwargs.get("byteorder", "little"),
frm,
**kwargs
)
setattr(self._parentdevice._modio.io, name, io_new)
self._parentdevice._modio.io._register_new_io_object(io_new)
# Optional Event eintragen
reg_event = kwargs.get("event", None)
@@ -388,48 +398,6 @@ class IOBase(object):
edge = kwargs.get("edge", None)
io_new.reg_event(reg_event, as_thread=as_thread, edge=edge)
def reg_out(self, name, frm, **kwargs):
"""Registriert einen neuen Output.
@param name Name des neuen Outputs
@param startout Outputname ab dem eingefuegt wird
@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 Output, Standardwert=little
- defaultvalue: Standardwert fuer Output, Standard ist 0
- event: Funktion fuer Eventhandling registrieren
- as_thread: Fuehrt die event-Funktion als RevPiCallback-Thread aus
- edge: event-Ausfuehren bei RISING, FALLING or BOTH Wertaenderung
@see <a target="_blank"
href="https://docs.python.org/3/library/struct.html#format-characters"
>Python3 struct()</a>
"""
if not issubclass(self._parentdevice, devicemodule.Gateway):
raise RuntimeError(
"this function can be used on gatway or virtual devices only"
)
# StructIO erzeugen und in IO-Liste einfügen
io_new = StructIO(
self._parentdevice,
name,
IOType.OUT,
kwargs.get("byteorder", "little"),
frm,
**kwargs
)
setattr(self._parentdevice._modio.io, name, io_new)
# Optional Event eintragen
reg_event = kwargs.get("event", None)
if reg_event is not None:
as_thread = kwargs.get("as_thread", False)
edge = kwargs.get("edge", None)
io_new.reg_event(name, reg_event, as_thread=as_thread, edge=edge)
def set_value(self, value):
"""Setzt den Wert des IOs mit bytes() oder bool().
@param value IO-Wert als bytes() oder bool()"""
@@ -715,9 +683,9 @@ class StructIO(IOBase):
name,
kwargs.get("defaultvalue", 0),
bitlength,
parentio.address,
parentio.slc_address.start,
False,
str(parentio.address).rjust(4, "0"),
str(parentio.slc_address.start).rjust(4, "0"),
kwargs.get("bmk", ""),
bitaddress
]
@@ -761,3 +729,7 @@ class StructIO(IOBase):
byteorder = property(IOBase._get_byteorder)
value = property(get_structvalue, set_structvalue)
# Nachträglicher Import
from .device import Gateway

View File

@@ -5,6 +5,7 @@
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
"""RevPiModIO Hauptklasse."""
import warnings
from json import load as jload
from os import access, F_OK, R_OK
@@ -56,7 +57,6 @@ class RevPiModIO(object):
# Private Variablen
self.__cleanupfunc = None
self._buffedwrite = False
self._device = []
self._exit = Event()
self._imgwriter = None
self._length = 0
@@ -73,7 +73,6 @@ class RevPiModIO(object):
# piCtory Klassen
self.app = None
self.device = None
self.devices = None
self.io = None
self.summary = None
@@ -129,7 +128,6 @@ class RevPiModIO(object):
# Device und IO Klassen anlegen
self.device = devicemodule.DeviceList()
#self.io = iomodule.IOList()
self.io = IOList()
# Devices initialisieren
@@ -181,8 +179,6 @@ class RevPiModIO(object):
dev_new = None
if dev_new is not None:
self._device.append(dev_new)
# Offset prüfen, muss mit Länge übereinstimmen
if self._length < dev_new.offset:
self._length = dev_new.offset
@@ -196,13 +192,13 @@ class RevPiModIO(object):
# DeviceList für direkten Zugriff aufbauen
setattr(self.device, dev_new.name, dev_new)
# dict_devname zerstören, wenn doppelte Namen vorhanden sind
# Namenszugriff zerstören, wenn doppelte Namen vorhanden sind
for errdev in err_names:
delattr(self.device, errdev)
warnings.warn(
"equal device name in pictory configuration. can not "
"build device to acces by name. you can access all devices "
"by position number pos_XX only!",
"by position number .device[nn] only!",
Warning
)
@@ -215,7 +211,7 @@ class RevPiModIO(object):
# Optional ins auto_refresh aufnehmen
if self._auto_refresh:
for dev in self._device:
for dev in self.device:
dev.auto_refresh()
# Summary Klasse instantiieren
@@ -277,12 +273,11 @@ class RevPiModIO(object):
def cleanup(self):
"""Beendet auto_refresh und alle Threads."""
# TODO: wirklich alles löschen
self.exit(full=True)
self._myfh.close()
self.app = None
self.core = None
self.device = None
self.devices = None
self.io = None
self.summary = None
@@ -589,9 +584,8 @@ class RevPiModIO(object):
"""
if device is None:
mylist = self._device
mylist = self.device
else:
# TODO: Devicesuchen ändern
dev = device if issubclass(type(device), devicemodule.Device) \
else self.device.__getitem__(device)
@@ -644,7 +638,7 @@ class RevPiModIO(object):
)
if device is None:
mylist = self._device
mylist = self.device
else:
dev = device if issubclass(type(device), devicemodule.Device) \
else self.__getitem__(device)
@@ -664,7 +658,7 @@ class RevPiModIO(object):
"""
if device is None:
mylist = self._device
mylist = self.device
else:
dev = device if issubclass(type(device), devicemodule.Device) \
else self.__getitem__(device)
@@ -761,7 +755,7 @@ class RevPiModIO(object):
)
if device is None:
mylist = self._device
mylist = self.device
else:
dev = device if issubclass(type(device), devicemodule.Device) \
else self.__getitem__(device)
@@ -850,7 +844,7 @@ class RevPiModIOSelected(RevPiModIO):
self._configure()
if len(self._device) == 0:
if len(self.device) == 0:
if type(self) == RevPiModIODriver:
raise RuntimeError(
"could not find any given VIRTUAL devices in config"
@@ -859,7 +853,7 @@ class RevPiModIOSelected(RevPiModIO):
raise RuntimeError(
"could not find any given devices in config"
)
elif len(self._device) != len(self._lst_devselect):
elif len(self.device) != len(self._lst_devselect):
if type(self) == RevPiModIODriver:
raise RuntimeError(
"could not find all given VIRTUAL devices in config"