From 9d31bb5002abc1685a288fc81629cd507ba649d9 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Wed, 29 Apr 2020 20:52:09 +0200 Subject: [PATCH] Add support for RevPi Compact, better calculation of A1, A2, A3 on core object --- revpimodio2/__init__.py | 6 +- revpimodio2/device.py | 214 +++++++++++++++++++++++++++++++--------- revpimodio2/helper.py | 4 +- revpimodio2/modio.py | 9 +- revpimodio2/netio.py | 4 +- setup.py | 2 +- 6 files changed, 184 insertions(+), 55 deletions(-) diff --git a/revpimodio2/__init__.py b/revpimodio2/__init__.py index 74d9c21..5b1089d 100644 --- a/revpimodio2/__init__.py +++ b/revpimodio2/__init__.py @@ -15,13 +15,13 @@ fuehrt das Modul bei Datenaenderung aus. __all__ = [ "RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected", "RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected", - "Cycletools", + "Cycletools", "EventCallback" ] __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" __name__ = "revpimodio2" -__version__ = "2.4.5" +__version__ = "2.4.5c" # Global package values OFF = 0 @@ -94,6 +94,6 @@ def consttostr(value) -> str: # Benötigte Klassen importieren -from .helper import Cycletools +from .helper import Cycletools, EventCallback from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected diff --git a/revpimodio2/device.py b/revpimodio2/device.py index 8013abf..80730d1 100644 --- a/revpimodio2/device.py +++ b/revpimodio2/device.py @@ -647,12 +647,8 @@ class Core(Base): :return: 0=aus, 1=gruen, 2=rot """ - int_led = int.from_bytes( - self._ba_devdata[self._slc_led], byteorder="little" - ) - led = int_led & 1 - led += int_led & 2 - return led + # 0b00000011 = 3 + return self._ba_devdata[self._slc_led.start] & 3 def _get_leda2(self) -> int: """ @@ -660,37 +656,8 @@ class Core(Base): :return: 0=aus, 1=gruen, 2=rot """ - int_led = int.from_bytes( - self._ba_devdata[self._slc_led], byteorder="little" - ) >> 2 - led = int_led & 1 - led += int_led & 2 - return led - - def _set_calculatedled(self, addresslist: list, shifted_value: int) -> None: - """ - Berechnet und setzt neuen Bytewert fuer LED byte. - - :param addresslist: Liste der Vergleicher - :param shifted_value: Bits vergleichen - """ - # Byte als int holen - int_led = int.from_bytes( - self._ba_devdata[self._slc_led], byteorder="little" - ) - - for int_bit in addresslist: - value = bool(shifted_value & int_bit) - if bool(int_led & int_bit) != value: - # Berechnen, wenn verändert - if value: - int_led += int_bit - else: - int_led -= int_bit - - # Zurückschreiben wenn verändert - self._ba_devdata[self._slc_led] = \ - int_led.to_bytes(length=1, byteorder="little") + # 0b00001100 = 12 + return (self._ba_devdata[self._slc_led.start] & 12) >> 2 def _set_leda1(self, value: int) -> None: """ @@ -699,7 +666,13 @@ class Core(Base): :param value: 0=aus, 1=gruen, 2=rot """ if 0 <= value <= 3: - self._set_calculatedled([1, 2], value) + proc_value = self._ba_devdata[self._slc_led.start] + proc_value_calc = proc_value & 3 + if proc_value_calc == value: + return + # Set new value + self._ba_devdata[self._slc_led.start] = \ + proc_value - proc_value_calc + value else: raise ValueError("led status must be between 0 and 3") @@ -710,7 +683,14 @@ class Core(Base): :param value: 0=aus, 1=gruen, 2=rot """ if 0 <= value <= 3: - self._set_calculatedled([4, 8], value << 2) + value <<= 2 + proc_value = self._ba_devdata[self._slc_led.start] + proc_value_calc = proc_value & 12 + if proc_value_calc == value: + return + # Set new value + self._ba_devdata[self._slc_led.start] = \ + proc_value - proc_value_calc + value else: raise ValueError("led status must be between 0 and 3") @@ -960,12 +940,8 @@ class Connect(Core): :return: 0=aus, 1=gruen, 2=rot """ - int_led = int.from_bytes( - self._ba_devdata[self._slc_led], byteorder="little" - ) >> 4 - led = int_led & 1 - led += int_led & 2 - return led + # 0b00110000 = 48 + return (self._ba_devdata[self._slc_led.start] & 48) >> 4 def _get_wdtoggle(self) -> bool: """ @@ -982,7 +958,14 @@ class Connect(Core): :param: value 0=aus, 1=gruen, 2=rot """ if 0 <= value <= 3: - self._set_calculatedled([16, 32], value << 4) + value <<= 4 + proc_value = self._ba_devdata[self._slc_led.start] + proc_value_calc = proc_value & 48 + if proc_value_calc == value: + return + # Set new value + self._ba_devdata[self._slc_led.start] = \ + proc_value - proc_value_calc + value else: raise ValueError("led status must be between 0 and 3") @@ -1023,6 +1006,145 @@ class Connect(Core): wdautotoggle = property(_get_wdtoggle, _set_wdtoggle) +class Compact(Base): + """ + Klasse fuer den RevPi Connect. + + Stellt Funktionen fuer die LEDs zur Verfuegung. Auf IOs wird ueber das .io + Objekt zugegriffen. + """ + + __slots__ = "_slc_temperature", "_slc_frequency", "_slc_led", \ + "a1green", "a1red", "a2green", "a2red" + + def __setattr__(self, key, value): + """Verhindert Ueberschreibung der LEDs.""" + if hasattr(self, key) and key in ( + "a1green", "a1red", "a2green", "a2red"): + raise AttributeError( + "direct assignment is not supported - use .value Attribute" + ) + else: + object.__setattr__(self, key, value) + + def _devconfigure(self) -> None: + """Core-Klasse vorbereiten.""" + + # Statische IO Verknüpfungen des Compacts + self._slc_led = slice(23, 24) + self._slc_temperature = slice(0, 1) + self._slc_frequency = slice(1, 2) + + # Exportflags prüfen (Byte oder Bit) + lst_led = self._modio.io[self._slc_devoff][self._slc_led.start] + if len(lst_led) == 8: + exp_a1green = lst_led[0].export + exp_a1red = lst_led[1].export + exp_a2green = lst_led[2].export + exp_a2red = lst_led[3].export + else: + exp_a1green = lst_led[0].export + exp_a1red = exp_a1green + exp_a2green = exp_a1green + exp_a2red = exp_a1green + + # Echte IOs erzeugen + self.a1green = IOBase(self, [ + "core.a1green", 0, 1, self._slc_led.start, + exp_a1green, None, "LED_A1_GREEN", "0" + ], OUT, "little", False) + self.a1red = IOBase(self, [ + "core.a1red", 0, 1, self._slc_led.start, + exp_a1red, None, "LED_A1_RED", "1" + ], OUT, "little", False) + self.a2green = IOBase(self, [ + "core.a2green", 0, 1, self._slc_led.start, + exp_a2green, None, "LED_A2_GREEN", "2" + ], OUT, "little", False) + self.a2red = IOBase(self, [ + "core.a2red", 0, 1, self._slc_led.start, + exp_a2red, None, "LED_A2_RED", "3" + ], OUT, "little", False) + + def _get_leda1(self) -> int: + """ + Gibt den Zustand der LED A1 vom Compact zurueck. + + :return: 0=aus, 1=gruen, 2=rot + """ + # 0b00000011 = 3 + return self._ba_devdata[self._slc_led.start] & 3 + + def _get_leda2(self) -> int: + """ + Gibt den Zustand der LED A2 vom Compact zurueck. + + :return: 0=aus, 1=gruen, 2=rot + """ + # 0b00001100 = 12 + return (self._ba_devdata[self._slc_led.start] & 12) >> 2 + + def _set_leda1(self, value: int) -> None: + """ + Setzt den Zustand der LED A1 vom Compact. + + :param value: 0=aus, 1=gruen, 2=rot + """ + if 0 <= value <= 3: + proc_value = self._ba_devdata[self._slc_led.start] + proc_value_calc = proc_value & 3 + if proc_value_calc == value: + return + # Set new value + self._ba_devdata[self._slc_led.start] = \ + proc_value - proc_value_calc + value + else: + raise ValueError("led status must be between 0 and 3") + + def _set_leda2(self, value: int) -> None: + """ + Setzt den Zustand der LED A2 vom Compact. + + :param value: 0=aus, 1=gruen, 2=rot + """ + if 0 <= value <= 3: + value <<= 2 + proc_value = self._ba_devdata[self._slc_led.start] + proc_value_calc = proc_value & 12 + if proc_value_calc == value: + return + # Set new value + self._ba_devdata[self._slc_led.start] = \ + proc_value - proc_value_calc + value + else: + raise ValueError("led status must be between 0 and 3") + + A1 = property(_get_leda1, _set_leda1) + A2 = property(_get_leda2, _set_leda2) + + @property + def temperature(self) -> int: + """ + Gibt CPU-Temperatur zurueck. + + :return: CPU-Temperatur in Celsius (-273 wenn nich verfuegbar) + """ + return -273 if self._slc_temperature is None else int.from_bytes( + self._ba_devdata[self._slc_temperature], byteorder="little" + ) + + @property + def frequency(self) -> int: + """ + Gibt CPU Taktfrequenz zurueck. + + :return: CPU Taktfrequenz in MHz (-1 wenn nicht verfuegbar) + """ + return -1 if self._slc_frequency is None else int.from_bytes( + self._ba_devdata[self._slc_frequency], byteorder="little" + ) * 10 + + class DioModule(Device): """Stellt ein DIO / DI / DO Modul dar.""" diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py index a0a643d..44439b6 100644 --- a/revpimodio2/helper.py +++ b/revpimodio2/helper.py @@ -339,9 +339,9 @@ class ProcimgWriter(Thread): if io_event._bitshift: 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 + & io_event._bitshift if boolor == boolcp: continue diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 9c246e1..79a67a8 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -248,6 +248,12 @@ class RevPiModIO(object): self, device, simulator=self._simulator ) self.core = dev_new + elif pt == 104: + # RevPi Compact + dev_new = devicemodule.Compact( + self, device, simulator=self._simulator + ) + self.core = dev_new else: # Base immer als Fallback verwenden dev_new = devicemodule.Base( @@ -324,7 +330,8 @@ class RevPiModIO(object): self.syncoutputs() # Für RS485 errors am core defaults laden sollte procimg NULL sein - if not (self.core is None or self._monitoring or self._simulator): + if isinstance(self.core, devicemodule.Core) and \ + not (self._monitoring or self._simulator): if self.core._slc_errorlimit1 is not None: io = self.io[ self.core.offset + self.core._slc_errorlimit1.start diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index a43ade4..c982544 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -714,8 +714,8 @@ class NetFH(Thread): # Datenblöcke mit Group Seperator in Puffer ablegen self.__by_buff += self.__position.to_bytes(length=2, byteorder="little") + \ - len(bytebuff).to_bytes(length=2, byteorder="little") + \ - bytebuff + len(bytebuff).to_bytes(length=2, byteorder="little") + \ + bytebuff # TODO: Bufferlänge und dann flushen? diff --git a/setup.py b/setup.py index 54bcc7c..8c44350 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( license="LGPLv3", name="revpimodio2", - version="2.4.5", + version="2.4.5c", packages=["revpimodio2"], python_requires="~=3.2",