Add support for RevPi Compact, better calculation of A1, A2, A3 on core object

This commit is contained in:
2020-04-29 20:52:09 +02:00
parent 421cc17dbd
commit 9d31bb5002
6 changed files with 184 additions and 55 deletions

View File

@@ -15,13 +15,13 @@ fuehrt das Modul bei Datenaenderung aus.
__all__ = [ __all__ = [
"RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected", "RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected",
"RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected", "RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected",
"Cycletools", "Cycletools", "EventCallback"
] ]
__author__ = "Sven Sager <akira@revpimodio.org>" __author__ = "Sven Sager <akira@revpimodio.org>"
__copyright__ = "Copyright (C) 2018 Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "LGPLv3" __license__ = "LGPLv3"
__name__ = "revpimodio2" __name__ = "revpimodio2"
__version__ = "2.4.5" __version__ = "2.4.5c"
# Global package values # Global package values
OFF = 0 OFF = 0
@@ -94,6 +94,6 @@ def consttostr(value) -> str:
# Benötigte Klassen importieren # Benötigte Klassen importieren
from .helper import Cycletools from .helper import Cycletools, EventCallback
from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected
from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected

View File

@@ -647,12 +647,8 @@ class Core(Base):
:return: 0=aus, 1=gruen, 2=rot :return: 0=aus, 1=gruen, 2=rot
""" """
int_led = int.from_bytes( # 0b00000011 = 3
self._ba_devdata[self._slc_led], byteorder="little" return self._ba_devdata[self._slc_led.start] & 3
)
led = int_led & 1
led += int_led & 2
return led
def _get_leda2(self) -> int: def _get_leda2(self) -> int:
""" """
@@ -660,37 +656,8 @@ class Core(Base):
:return: 0=aus, 1=gruen, 2=rot :return: 0=aus, 1=gruen, 2=rot
""" """
int_led = int.from_bytes( # 0b00001100 = 12
self._ba_devdata[self._slc_led], byteorder="little" return (self._ba_devdata[self._slc_led.start] & 12) >> 2
) >> 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")
def _set_leda1(self, value: int) -> None: def _set_leda1(self, value: int) -> None:
""" """
@@ -699,7 +666,13 @@ class Core(Base):
:param value: 0=aus, 1=gruen, 2=rot :param value: 0=aus, 1=gruen, 2=rot
""" """
if 0 <= value <= 3: 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: else:
raise ValueError("led status must be between 0 and 3") 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 :param value: 0=aus, 1=gruen, 2=rot
""" """
if 0 <= value <= 3: 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: else:
raise ValueError("led status must be between 0 and 3") raise ValueError("led status must be between 0 and 3")
@@ -960,12 +940,8 @@ class Connect(Core):
:return: 0=aus, 1=gruen, 2=rot :return: 0=aus, 1=gruen, 2=rot
""" """
int_led = int.from_bytes( # 0b00110000 = 48
self._ba_devdata[self._slc_led], byteorder="little" return (self._ba_devdata[self._slc_led.start] & 48) >> 4
) >> 4
led = int_led & 1
led += int_led & 2
return led
def _get_wdtoggle(self) -> bool: def _get_wdtoggle(self) -> bool:
""" """
@@ -982,7 +958,14 @@ class Connect(Core):
:param: value 0=aus, 1=gruen, 2=rot :param: value 0=aus, 1=gruen, 2=rot
""" """
if 0 <= value <= 3: 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: else:
raise ValueError("led status must be between 0 and 3") raise ValueError("led status must be between 0 and 3")
@@ -1023,6 +1006,145 @@ class Connect(Core):
wdautotoggle = property(_get_wdtoggle, _set_wdtoggle) 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): class DioModule(Device):
"""Stellt ein DIO / DI / DO Modul dar.""" """Stellt ein DIO / DI / DO Modul dar."""

View File

@@ -339,9 +339,9 @@ class ProcimgWriter(Thread):
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] \ boolor = dev._ba_devdata[io_event._slc_address.start] \
& io_event._bitshift & io_event._bitshift
if boolor == boolcp: if boolor == boolcp:
continue continue

View File

@@ -248,6 +248,12 @@ class RevPiModIO(object):
self, device, simulator=self._simulator self, device, simulator=self._simulator
) )
self.core = dev_new self.core = dev_new
elif pt == 104:
# RevPi Compact
dev_new = devicemodule.Compact(
self, device, simulator=self._simulator
)
self.core = dev_new
else: else:
# Base immer als Fallback verwenden # Base immer als Fallback verwenden
dev_new = devicemodule.Base( dev_new = devicemodule.Base(
@@ -324,7 +330,8 @@ 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 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: if self.core._slc_errorlimit1 is not None:
io = self.io[ io = self.io[
self.core.offset + self.core._slc_errorlimit1.start self.core.offset + self.core._slc_errorlimit1.start

View File

@@ -714,8 +714,8 @@ class NetFH(Thread):
# Datenblöcke mit Group Seperator in Puffer ablegen # Datenblöcke mit Group Seperator in Puffer ablegen
self.__by_buff += self.__position.to_bytes(length=2, byteorder="little") + \ self.__by_buff += 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?

View File

@@ -17,7 +17,7 @@ setup(
license="LGPLv3", license="LGPLv3",
name="revpimodio2", name="revpimodio2",
version="2.4.5", version="2.4.5c",
packages=["revpimodio2"], packages=["revpimodio2"],
python_requires="~=3.2", python_requires="~=3.2",