mirror of
https://github.com/naruxde/revpimodio2.git
synced 2025-11-08 22:03:53 +01:00
Merge branch 'develop'
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -3,7 +3,7 @@
|
|||||||
<component name="JavaScriptSettings">
|
<component name="JavaScriptSettings">
|
||||||
<option name="languageLevel" value="ES6" />
|
<option name="languageLevel" value="ES6" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" />
|
||||||
<component name="PythonCompatibilityInspectionAdvertiser">
|
<component name="PythonCompatibilityInspectionAdvertiser">
|
||||||
<option name="version" value="3" />
|
<option name="version" value="3" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
2
.idea/revpimodio2.iml
generated
2
.idea/revpimodio2.iml
generated
@@ -2,7 +2,7 @@
|
|||||||
<module type="PYTHON_MODULE" version="4">
|
<module type="PYTHON_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.8" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ __all__ = [
|
|||||||
"RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected", "run_plc",
|
"RevPiModIO", "RevPiModIODriver", "RevPiModIOSelected", "run_plc",
|
||||||
"RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected",
|
"RevPiNetIO", "RevPiNetIODriver", "RevPiNetIOSelected",
|
||||||
"Cycletools", "EventCallback",
|
"Cycletools", "EventCallback",
|
||||||
"AIO", "DI", "DO", "DIO",
|
"AIO", "COMPACT", "DI", "DO", "DIO",
|
||||||
]
|
]
|
||||||
__author__ = "Sven Sager <akira@revpimodio.org>"
|
__author__ = "Sven Sager <akira@revpimodio.org>"
|
||||||
__copyright__ = "Copyright (C) 2020 Sven Sager"
|
__copyright__ = "Copyright (C) 2020 Sven Sager"
|
||||||
__license__ = "LGPLv3"
|
__license__ = "LGPLv3"
|
||||||
__name__ = "revpimodio2"
|
__name__ = "revpimodio2"
|
||||||
__version__ = "2.5.3"
|
__version__ = "2.5.3d"
|
||||||
|
|
||||||
# Global package values
|
# Global package values
|
||||||
OFF = 0
|
OFF = 0
|
||||||
@@ -96,7 +96,7 @@ def consttostr(value) -> str:
|
|||||||
|
|
||||||
|
|
||||||
# Benötigte Klassen importieren
|
# Benötigte Klassen importieren
|
||||||
from .pictory import AIO, DI, DO, DIO
|
from .pictory import AIO, COMPACT, DI, DO, DIO
|
||||||
from .helper import Cycletools, EventCallback
|
from .helper import Cycletools, EventCallback
|
||||||
from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected, run_plc
|
from .modio import RevPiModIO, RevPiModIODriver, RevPiModIOSelected, run_plc
|
||||||
from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected
|
from .netio import RevPiNetIO, RevPiNetIODriver, RevPiNetIOSelected
|
||||||
|
|||||||
@@ -125,10 +125,11 @@ class Device(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = "__my_io_list", "_ba_devdata", "_ba_datacp", \
|
__slots__ = "__my_io_list", "_ba_devdata", "_ba_datacp", \
|
||||||
"_dict_events", "_filelock", "_length", "_modio", "_name", "_offset", \
|
"_dict_events", "_filelock", "_length", "_modio", "_name", \
|
||||||
"_position", "_producttype", "_selfupdate", "_slc_devoff", \
|
"_offset", "_position", "_producttype", "_selfupdate", \
|
||||||
"_slc_inp", "_slc_inpoff", "_slc_mem", "_slc_memoff", \
|
"_slc_devoff", "_slc_inp", "_slc_inpoff", "_slc_mem", \
|
||||||
"_slc_out", "_slc_outoff", "bmk", "catalognr", "comment", "extend", \
|
"_slc_memoff", "_slc_out", "_slc_outoff", "_shared_procimg", \
|
||||||
|
"bmk", "catalognr", "comment", "extend", \
|
||||||
"guid", "id", "inpvariant", "outvariant", "type"
|
"guid", "id", "inpvariant", "outvariant", "type"
|
||||||
|
|
||||||
def __init__(self, parentmodio, dict_device, simulator=False):
|
def __init__(self, parentmodio, dict_device, simulator=False):
|
||||||
@@ -146,6 +147,7 @@ class Device(object):
|
|||||||
self._length = 0
|
self._length = 0
|
||||||
self.__my_io_list = []
|
self.__my_io_list = []
|
||||||
self._selfupdate = False
|
self._selfupdate = False
|
||||||
|
self._shared_procimg = parentmodio._shared_procimg
|
||||||
|
|
||||||
# Wertzuweisung aus dict_device
|
# Wertzuweisung aus dict_device
|
||||||
self._name = dict_device.get("name")
|
self._name = dict_device.get("name")
|
||||||
@@ -500,6 +502,17 @@ class Device(object):
|
|||||||
"""
|
"""
|
||||||
self._modio.setdefaultvalues(self)
|
self._modio.setdefaultvalues(self)
|
||||||
|
|
||||||
|
def shared_procimg(self, activate: bool) -> None:
|
||||||
|
"""
|
||||||
|
Activate sharing of process image just for this device.
|
||||||
|
|
||||||
|
WARNING: All outputs will set immediately in process image on value
|
||||||
|
change. That is also inside the cycle loop!
|
||||||
|
|
||||||
|
:param activate: Set True to activate process image sharing
|
||||||
|
"""
|
||||||
|
self._shared_procimg = True if activate else False
|
||||||
|
|
||||||
def syncoutputs(self) -> bool:
|
def syncoutputs(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Lesen aller Outputs im Prozessabbild fuer dieses Device.
|
Lesen aller Outputs im Prozessabbild fuer dieses Device.
|
||||||
@@ -593,11 +606,13 @@ class Core(Base):
|
|||||||
exp_a1red = lst_led[1].export
|
exp_a1red = lst_led[1].export
|
||||||
exp_a2green = lst_led[2].export
|
exp_a2green = lst_led[2].export
|
||||||
exp_a2red = lst_led[3].export
|
exp_a2red = lst_led[3].export
|
||||||
|
# exp_wd = lst_led[7].export
|
||||||
else:
|
else:
|
||||||
exp_a1green = lst_led[0].export
|
exp_a1green = lst_led[0].export
|
||||||
exp_a1red = exp_a1green
|
exp_a1red = exp_a1green
|
||||||
exp_a2green = exp_a1green
|
exp_a2green = exp_a1green
|
||||||
exp_a2red = exp_a1green
|
exp_a2red = exp_a1green
|
||||||
|
# exp_wd = exp_a1green
|
||||||
|
|
||||||
# Echte IOs erzeugen
|
# Echte IOs erzeugen
|
||||||
self.a1green = IOBase(self, [
|
self.a1green = IOBase(self, [
|
||||||
@@ -673,13 +688,8 @@ 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:
|
||||||
proc_value = self._ba_devdata[self._slc_led.start]
|
self.a1green(bool(value & 1))
|
||||||
proc_value_calc = proc_value & 3
|
self.a1red(bool(value & 2))
|
||||||
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")
|
||||||
|
|
||||||
@@ -690,14 +700,8 @@ 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:
|
||||||
value <<= 2
|
self.a2green(bool(value & 1))
|
||||||
proc_value = self._ba_devdata[self._slc_led.start]
|
self.a2red(bool(value & 2))
|
||||||
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")
|
||||||
|
|
||||||
@@ -907,12 +911,10 @@ class Connect(Core):
|
|||||||
exp_a3green = lst_led[4].export
|
exp_a3green = lst_led[4].export
|
||||||
exp_a3red = lst_led[5].export
|
exp_a3red = lst_led[5].export
|
||||||
exp_x2out = lst_led[6].export
|
exp_x2out = lst_led[6].export
|
||||||
exp_wd = lst_led[7].export
|
|
||||||
else:
|
else:
|
||||||
exp_a3green = lst_led[0].export
|
exp_a3green = lst_led[0].export
|
||||||
exp_a3red = exp_a3green
|
exp_a3red = exp_a3green
|
||||||
exp_x2out = exp_a3green
|
exp_x2out = exp_a3green
|
||||||
exp_wd = exp_a3green
|
|
||||||
lst_status = lst_myios[self._slc_statusbyte.start]
|
lst_status = lst_myios[self._slc_statusbyte.start]
|
||||||
if len(lst_status) == 8:
|
if len(lst_status) == 8:
|
||||||
exp_x2in = lst_status[6].export
|
exp_x2in = lst_status[6].export
|
||||||
@@ -963,14 +965,8 @@ 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:
|
||||||
value <<= 4
|
self.a3green(bool(value & 1))
|
||||||
proc_value = self._ba_devdata[self._slc_led.start]
|
self.a3red(bool(value & 2))
|
||||||
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")
|
||||||
|
|
||||||
@@ -1013,7 +1009,7 @@ class Connect(Core):
|
|||||||
|
|
||||||
class Compact(Base):
|
class Compact(Base):
|
||||||
"""
|
"""
|
||||||
Klasse fuer den RevPi Connect.
|
Klasse fuer den RevPi Compact.
|
||||||
|
|
||||||
Stellt Funktionen fuer die LEDs zur Verfuegung. Auf IOs wird ueber das .io
|
Stellt Funktionen fuer die LEDs zur Verfuegung. Auf IOs wird ueber das .io
|
||||||
Objekt zugegriffen.
|
Objekt zugegriffen.
|
||||||
@@ -1025,7 +1021,7 @@ class Compact(Base):
|
|||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
"""Verhindert Ueberschreibung der LEDs."""
|
"""Verhindert Ueberschreibung der LEDs."""
|
||||||
if hasattr(self, key) and key in (
|
if hasattr(self, key) and key in (
|
||||||
"a1green", "a1red", "a2green", "a2red"):
|
"a1green", "a1red", "a2green", "a2red", "wd"):
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
"direct assignment is not supported - use .value Attribute"
|
"direct assignment is not supported - use .value Attribute"
|
||||||
)
|
)
|
||||||
@@ -1102,13 +1098,8 @@ class Compact(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:
|
||||||
proc_value = self._ba_devdata[self._slc_led.start]
|
self.a1green(bool(value & 1))
|
||||||
proc_value_calc = proc_value & 3
|
self.a1red(bool(value & 2))
|
||||||
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")
|
||||||
|
|
||||||
@@ -1119,14 +1110,8 @@ class Compact(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:
|
||||||
value <<= 2
|
self.a2green(bool(value & 1))
|
||||||
proc_value = self._ba_devdata[self._slc_led.start]
|
self.a2red(bool(value & 2))
|
||||||
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")
|
||||||
|
|
||||||
@@ -1160,6 +1145,250 @@ class Compact(Base):
|
|||||||
) * 10
|
) * 10
|
||||||
|
|
||||||
|
|
||||||
|
class Flat(Base):
|
||||||
|
"""
|
||||||
|
Klasse fuer den RevPi Flat.
|
||||||
|
|
||||||
|
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", \
|
||||||
|
"a3green", "a3red", "a4green", "a4red", \
|
||||||
|
"a5green", "a5red", "wd"
|
||||||
|
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
"""Verhindert Ueberschreibung der LEDs."""
|
||||||
|
if hasattr(self, key) and key in (
|
||||||
|
"a1green", "a1red", "a2green", "a2red",
|
||||||
|
"a3green", "a3red", "a4green", "a4red",
|
||||||
|
"a5green", "a5red", "wd"):
|
||||||
|
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(6, 8)
|
||||||
|
self._slc_temperature = slice(4, 5)
|
||||||
|
self._slc_frequency = slice(5, 6)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
exp_a3green = lst_led[4].export
|
||||||
|
exp_a3red = lst_led[5].export
|
||||||
|
exp_a4green = lst_led[6].export
|
||||||
|
exp_a4red = lst_led[7].export
|
||||||
|
|
||||||
|
# Next byte
|
||||||
|
lst_led = self._modio.io[self._slc_devoff][self._slc_led.start + 1]
|
||||||
|
exp_a5green = lst_led[0].export
|
||||||
|
exp_a5red = lst_led[1].export
|
||||||
|
else:
|
||||||
|
exp_a1green = lst_led[0].export
|
||||||
|
exp_a1red = exp_a1green
|
||||||
|
exp_a2green = exp_a1green
|
||||||
|
exp_a2red = exp_a1green
|
||||||
|
exp_a3green = exp_a1green
|
||||||
|
exp_a3red = exp_a1green
|
||||||
|
exp_a4green = exp_a1green
|
||||||
|
exp_a4red = exp_a1green
|
||||||
|
exp_a5green = exp_a1green
|
||||||
|
exp_a5red = 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)
|
||||||
|
self.a3green = IOBase(self, [
|
||||||
|
"core.a3green", 0, 1, self._slc_led.start,
|
||||||
|
exp_a3green, None, "LED_A3_GREEN", "4"
|
||||||
|
], OUT, "little", False)
|
||||||
|
self.a3red = IOBase(self, [
|
||||||
|
"core.a3red", 0, 1, self._slc_led.start,
|
||||||
|
exp_a3red, None, "LED_A3_RED", "5"
|
||||||
|
], OUT, "little", False)
|
||||||
|
self.a4green = IOBase(self, [
|
||||||
|
"core.a4green", 0, 1, self._slc_led.start,
|
||||||
|
exp_a4green, None, "LED_A4_GREEN", "6"
|
||||||
|
], OUT, "little", False)
|
||||||
|
self.a4red = IOBase(self, [
|
||||||
|
"core.a4red", 0, 1, self._slc_led.start,
|
||||||
|
exp_a4red, None, "LED_A4_RED", "7"
|
||||||
|
], OUT, "little", False)
|
||||||
|
self.a5green = IOBase(self, [
|
||||||
|
"core.a5green", 0, 1, self._slc_led.start,
|
||||||
|
exp_a5green, None, "LED_A5_GREEN", "8"
|
||||||
|
], OUT, "little", False)
|
||||||
|
self.a5red = IOBase(self, [
|
||||||
|
"core.a5red", 0, 1, self._slc_led.start,
|
||||||
|
exp_a5red, None, "LED_A5_RED", "9"
|
||||||
|
], OUT, "little", False)
|
||||||
|
|
||||||
|
# todo: Add internal switch and relay, like Connect
|
||||||
|
|
||||||
|
# Software watchdog einrichten
|
||||||
|
self.wd = IOBase(self, [
|
||||||
|
"core.wd", 0, 1, self._slc_led.start,
|
||||||
|
False, None, "WatchDog", "15"
|
||||||
|
], OUT, "little", False)
|
||||||
|
|
||||||
|
def _get_leda1(self) -> int:
|
||||||
|
"""
|
||||||
|
Get value of LED A1 from RevPi Flat device.
|
||||||
|
|
||||||
|
:return: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
return self._ba_devdata[self._slc_led.start] & 0b11
|
||||||
|
|
||||||
|
def _get_leda2(self) -> int:
|
||||||
|
"""
|
||||||
|
Get value of LED A2 from RevPi Flat device.
|
||||||
|
|
||||||
|
:return: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
return (self._ba_devdata[self._slc_led.start] & 0b1100) >> 2
|
||||||
|
|
||||||
|
def _get_leda3(self) -> int:
|
||||||
|
"""
|
||||||
|
Get value of LED A3 from RevPi Flat device.
|
||||||
|
|
||||||
|
:return: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
return (self._ba_devdata[self._slc_led.start] & 0b110000) >> 4
|
||||||
|
|
||||||
|
def _get_leda4(self) -> int:
|
||||||
|
"""
|
||||||
|
Get value of LED A4 from RevPi Flat device.
|
||||||
|
|
||||||
|
:return: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
return (self._ba_devdata[self._slc_led.start] & 0b11000000) >> 6
|
||||||
|
|
||||||
|
def _get_leda5(self) -> int:
|
||||||
|
"""
|
||||||
|
Get value of LED A5 from RevPi Flat device.
|
||||||
|
|
||||||
|
:return: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
return self._ba_devdata[self._slc_led.start + 1] & 0b11
|
||||||
|
|
||||||
|
def _set_leda1(self, value: int) -> None:
|
||||||
|
"""
|
||||||
|
Set LED A1 on RevPi Flat device.
|
||||||
|
|
||||||
|
:param value: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
if 0 <= value <= 3:
|
||||||
|
self.a1green(bool(value & 1))
|
||||||
|
self.a1red(bool(value & 2))
|
||||||
|
else:
|
||||||
|
raise ValueError("led status must be between 0 and 3")
|
||||||
|
|
||||||
|
def _set_leda2(self, value: int) -> None:
|
||||||
|
"""
|
||||||
|
Set LED A2 on RevPi Flat device.
|
||||||
|
|
||||||
|
:param value: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
if 0 <= value <= 3:
|
||||||
|
self.a2green(bool(value & 1))
|
||||||
|
self.a2red(bool(value & 2))
|
||||||
|
else:
|
||||||
|
raise ValueError("led status must be between 0 and 3")
|
||||||
|
|
||||||
|
def _set_leda3(self, value: int) -> None:
|
||||||
|
"""
|
||||||
|
Set LED A3 on RevPi Flat device.
|
||||||
|
|
||||||
|
:param value: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
if 0 <= value <= 3:
|
||||||
|
self.a3green(bool(value & 1))
|
||||||
|
self.a3red(bool(value & 2))
|
||||||
|
else:
|
||||||
|
raise ValueError("led status must be between 0 and 3")
|
||||||
|
|
||||||
|
def _set_leda4(self, value: int) -> None:
|
||||||
|
"""
|
||||||
|
Set LED A4 on RevPi Flat device.
|
||||||
|
|
||||||
|
:param value: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
if 0 <= value <= 3:
|
||||||
|
self.a4green(bool(value & 1))
|
||||||
|
self.a4red(bool(value & 2))
|
||||||
|
else:
|
||||||
|
raise ValueError("led status must be between 0 and 3")
|
||||||
|
|
||||||
|
def _set_leda5(self, value: int) -> None:
|
||||||
|
"""
|
||||||
|
Set LED A5 on RevPi Flat device.
|
||||||
|
|
||||||
|
:param value: 0=off, 1=green, 2=red
|
||||||
|
"""
|
||||||
|
if 0 <= value <= 3:
|
||||||
|
self.a5green(bool(value & 1))
|
||||||
|
self.a5red(bool(value & 2))
|
||||||
|
else:
|
||||||
|
raise ValueError("led status must be between 0 and 3")
|
||||||
|
|
||||||
|
def wd_toggle(self):
|
||||||
|
"""Toggle watchdog bit to prevent a timeout."""
|
||||||
|
self.wd.value = not self.wd.value
|
||||||
|
|
||||||
|
A1 = property(_get_leda1, _set_leda1)
|
||||||
|
A2 = property(_get_leda2, _set_leda2)
|
||||||
|
A3 = property(_get_leda3, _set_leda3)
|
||||||
|
A4 = property(_get_leda4, _set_leda4)
|
||||||
|
A5 = property(_get_leda5, _set_leda5)
|
||||||
|
|
||||||
|
@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."""
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import queue
|
|||||||
import warnings
|
import warnings
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from threading import Event, Lock, Thread
|
from threading import Event, Lock, Thread
|
||||||
|
from time import sleep
|
||||||
from timeit import default_timer
|
from timeit import default_timer
|
||||||
|
|
||||||
from revpimodio2 import BOTH, FALLING, RISING
|
from revpimodio2 import BOTH, FALLING, RISING
|
||||||
@@ -463,6 +464,7 @@ class ProcimgWriter(Thread):
|
|||||||
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()
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -532,20 +534,18 @@ class ProcimgWriter(Thread):
|
|||||||
fh.seek(0)
|
fh.seek(0)
|
||||||
fh.readinto(bytesbuff)
|
fh.readinto(bytesbuff)
|
||||||
|
|
||||||
if self._modio._monitoring or self._modio._direct_output:
|
for dev in self._modio._lst_refresh:
|
||||||
# Inputs und Outputs in Puffer
|
with dev._filelock:
|
||||||
for dev in self._modio._lst_refresh:
|
if self._modio._monitoring or dev._shared_procimg:
|
||||||
with dev._filelock:
|
# Inputs und Outputs in Puffer
|
||||||
dev._ba_devdata[:] = bytesbuff[dev._slc_devoff]
|
dev._ba_devdata[:] = bytesbuff[dev._slc_devoff]
|
||||||
if self.__eventwork \
|
if 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)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Inputs in Puffer, Outputs in Prozessabbild
|
# Inputs in Puffer, Outputs in Prozessabbild
|
||||||
for dev in self._modio._lst_refresh:
|
|
||||||
with dev._filelock:
|
|
||||||
dev._ba_devdata[dev._slc_inp] = \
|
dev._ba_devdata[dev._slc_inp] = \
|
||||||
bytesbuff[dev._slc_inpoff]
|
bytesbuff[dev._slc_inpoff]
|
||||||
if self.__eventwork \
|
if self.__eventwork \
|
||||||
@@ -556,8 +556,8 @@ class ProcimgWriter(Thread):
|
|||||||
fh.seek(dev._slc_outoff.start)
|
fh.seek(dev._slc_outoff.start)
|
||||||
fh.write(dev._ba_devdata[dev._slc_out])
|
fh.write(dev._ba_devdata[dev._slc_out])
|
||||||
|
|
||||||
if self._modio._buffedwrite:
|
if self._modio._buffedwrite:
|
||||||
fh.flush()
|
fh.flush()
|
||||||
|
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
self._modio._gotioerror("autorefresh", e, mrk_warn)
|
self._modio._gotioerror("autorefresh", e, mrk_warn)
|
||||||
@@ -602,8 +602,8 @@ class ProcimgWriter(Thread):
|
|||||||
self._eventq.put(tup_fire, False)
|
self._eventq.put(tup_fire, False)
|
||||||
del self.__dict_delay[tup_fire]
|
del self.__dict_delay[tup_fire]
|
||||||
|
|
||||||
# Refresh abwarten
|
# Sleep and not .wait (.wait uses system clock)
|
||||||
self._work.wait(self._adjwait)
|
sleep(self._adjwait)
|
||||||
|
|
||||||
# Wartezeit anpassen um echte self._refresh zu erreichen
|
# Wartezeit anpassen um echte self._refresh zu erreichen
|
||||||
mrk_dt = default_timer()
|
mrk_dt = default_timer()
|
||||||
|
|||||||
@@ -624,7 +624,7 @@ class IOBase(object):
|
|||||||
# Versuchen egal welchen Typ in Bool zu konvertieren
|
# Versuchen egal welchen Typ in Bool zu konvertieren
|
||||||
value = bool(value)
|
value = bool(value)
|
||||||
|
|
||||||
if self._parentdevice._modio._direct_output:
|
if self._parentdevice._shared_procimg:
|
||||||
# Direktes Schreiben der Outputs
|
# Direktes Schreiben der Outputs
|
||||||
|
|
||||||
if self._parentdevice._modio._run_on_pi:
|
if self._parentdevice._modio._run_on_pi:
|
||||||
@@ -640,6 +640,7 @@ class IOBase(object):
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._parentdevice._modio._gotioerror("ioset", e)
|
self._parentdevice._modio._gotioerror("ioset", e)
|
||||||
|
return
|
||||||
|
|
||||||
elif hasattr(self._parentdevice._modio._myfh, "ioctl"):
|
elif hasattr(self._parentdevice._modio._myfh, "ioctl"):
|
||||||
# IOCTL über Netzwerk
|
# IOCTL über Netzwerk
|
||||||
@@ -653,6 +654,7 @@ class IOBase(object):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._parentdevice._modio._gotioerror(
|
self._parentdevice._modio._gotioerror(
|
||||||
"net_ioset", e)
|
"net_ioset", e)
|
||||||
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# IOCTL in Datei simulieren
|
# IOCTL in Datei simulieren
|
||||||
@@ -665,28 +667,26 @@ class IOBase(object):
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._parentdevice._modio._gotioerror("file_ioset", e)
|
self._parentdevice._modio._gotioerror("file_ioset", e)
|
||||||
|
return
|
||||||
|
|
||||||
else:
|
# Für Bitoperationen sperren
|
||||||
# Gepuffertes Schreiben der Outputs
|
self._parentdevice._filelock.acquire()
|
||||||
|
|
||||||
# Für Bitoperationen sperren
|
# Hier gibt es immer nur ein byte, als int holen
|
||||||
self._parentdevice._filelock.acquire()
|
int_byte = self._parentdevice._ba_devdata[self._slc_address.start]
|
||||||
|
|
||||||
# Hier gibt es immer nur ein byte, als int holen
|
# Aktuellen Wert vergleichen und ggf. setzen
|
||||||
int_byte = self._parentdevice._ba_devdata[self._slc_address.start]
|
if not bool(int_byte & self._bitshift) == value:
|
||||||
|
if value:
|
||||||
|
int_byte += self._bitshift
|
||||||
|
else:
|
||||||
|
int_byte -= self._bitshift
|
||||||
|
|
||||||
# Aktuellen Wert vergleichen und ggf. setzen
|
# Zurückschreiben wenn verändert
|
||||||
if not bool(int_byte & self._bitshift) == value:
|
self._parentdevice._ba_devdata[self._slc_address.start] = \
|
||||||
if value:
|
int_byte
|
||||||
int_byte += self._bitshift
|
|
||||||
else:
|
|
||||||
int_byte -= self._bitshift
|
|
||||||
|
|
||||||
# Zurückschreiben wenn verändert
|
self._parentdevice._filelock.release()
|
||||||
self._parentdevice._ba_devdata[self._slc_address.start] = \
|
|
||||||
int_byte
|
|
||||||
|
|
||||||
self._parentdevice._filelock.release()
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if type(value) != bytes:
|
if type(value) != bytes:
|
||||||
@@ -704,7 +704,7 @@ class IOBase(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self._parentdevice._modio._direct_output:
|
if self._parentdevice._shared_procimg:
|
||||||
with self._parentdevice._modio._myfh_lck:
|
with self._parentdevice._modio._myfh_lck:
|
||||||
try:
|
try:
|
||||||
self._parentdevice._modio._myfh.seek(
|
self._parentdevice._modio._myfh.seek(
|
||||||
@@ -715,8 +715,9 @@ class IOBase(object):
|
|||||||
self._parentdevice._modio._myfh.flush()
|
self._parentdevice._modio._myfh.flush()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
self._parentdevice._modio._gotioerror("ioset", e)
|
self._parentdevice._modio._gotioerror("ioset", e)
|
||||||
else:
|
return
|
||||||
self._parentdevice._ba_devdata[self._slc_address] = value
|
|
||||||
|
self._parentdevice._ba_devdata[self._slc_address] = value
|
||||||
|
|
||||||
def unreg_event(self, func=None, edge=None) -> None:
|
def unreg_event(self, func=None, edge=None) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class RevPiModIO(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = "__cleanupfunc", "_autorefresh", "_buffedwrite", "_exit_level", \
|
__slots__ = "__cleanupfunc", "_autorefresh", "_buffedwrite", "_exit_level", \
|
||||||
"_configrsc", "_direct_output", "_exit", "_imgwriter", "_ioerror", \
|
"_configrsc", "_shared_procimg", "_exit", "_imgwriter", "_ioerror", \
|
||||||
"_length", "_looprunning", "_lst_devselect", "_lst_refresh", \
|
"_length", "_looprunning", "_lst_devselect", "_lst_refresh", \
|
||||||
"_maxioerrors", "_myfh", "_myfh_lck", "_monitoring", "_procimg", \
|
"_maxioerrors", "_myfh", "_myfh_lck", "_monitoring", "_procimg", \
|
||||||
"_simulator", "_syncoutputs", "_th_mainloop", "_waitexit", \
|
"_simulator", "_syncoutputs", "_th_mainloop", "_waitexit", \
|
||||||
@@ -76,10 +76,10 @@ class RevPiModIO(object):
|
|||||||
|
|
||||||
self._autorefresh = autorefresh
|
self._autorefresh = autorefresh
|
||||||
self._configrsc = configrsc
|
self._configrsc = configrsc
|
||||||
self._direct_output = shared_procimg or direct_output
|
|
||||||
self._monitoring = monitoring
|
self._monitoring = monitoring
|
||||||
self._procimg = "/dev/piControl0" if procimg is None else procimg
|
self._procimg = "/dev/piControl0" if procimg is None else procimg
|
||||||
self._simulator = simulator
|
self._simulator = simulator
|
||||||
|
self._shared_procimg = shared_procimg or direct_output
|
||||||
self._syncoutputs = syncoutputs
|
self._syncoutputs = syncoutputs
|
||||||
|
|
||||||
# TODO: bei simulator und procimg prüfen ob datei existiert / anlegen?
|
# TODO: bei simulator und procimg prüfen ob datei existiert / anlegen?
|
||||||
@@ -254,6 +254,12 @@ class RevPiModIO(object):
|
|||||||
self, device, simulator=self._simulator
|
self, device, simulator=self._simulator
|
||||||
)
|
)
|
||||||
self.core = dev_new
|
self.core = dev_new
|
||||||
|
elif pt == 135:
|
||||||
|
# RevPi Flat
|
||||||
|
dev_new = devicemodule.Flat(
|
||||||
|
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(
|
||||||
@@ -682,7 +688,7 @@ class RevPiModIO(object):
|
|||||||
self._exit_level |= 2
|
self._exit_level |= 2
|
||||||
self.exit(full=True)
|
self.exit(full=True)
|
||||||
|
|
||||||
def cycleloop(self, func, cycletime=50):
|
def cycleloop(self, func, cycletime=50, blocking=True):
|
||||||
"""
|
"""
|
||||||
Startet den Cycleloop.
|
Startet den Cycleloop.
|
||||||
|
|
||||||
@@ -709,6 +715,7 @@ class RevPiModIO(object):
|
|||||||
|
|
||||||
:param func: Funktion, die ausgefuehrt werden soll
|
:param func: Funktion, die ausgefuehrt werden soll
|
||||||
:param cycletime: Zykluszeit in Millisekunden - Standardwert 50 ms
|
:param cycletime: Zykluszeit in Millisekunden - Standardwert 50 ms
|
||||||
|
:param blocking: Wenn False, blockiert das Programm hier NICHT
|
||||||
:return: None or the return value of the cycle function
|
:return: None or the return value of the cycle function
|
||||||
"""
|
"""
|
||||||
# Prüfen ob ein Loop bereits läuft
|
# Prüfen ob ein Loop bereits läuft
|
||||||
@@ -730,6 +737,16 @@ class RevPiModIO(object):
|
|||||||
"registered function '{0}' ist not callable".format(func)
|
"registered function '{0}' ist not callable".format(func)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Thread erstellen, wenn nicht blockieren soll
|
||||||
|
if not blocking:
|
||||||
|
self._th_mainloop = Thread(
|
||||||
|
target=self.cycleloop,
|
||||||
|
args=(func,),
|
||||||
|
kwargs={"cycletime": cycletime, "blocking": True}
|
||||||
|
)
|
||||||
|
self._th_mainloop.start()
|
||||||
|
return
|
||||||
|
|
||||||
# Zykluszeit übernehmen
|
# Zykluszeit übernehmen
|
||||||
old_cycletime = self._imgwriter.refresh
|
old_cycletime = self._imgwriter.refresh
|
||||||
if not cycletime == self._imgwriter.refresh:
|
if not cycletime == self._imgwriter.refresh:
|
||||||
@@ -751,12 +768,18 @@ class RevPiModIO(object):
|
|||||||
while ec is None and not cycleinfo.last:
|
while ec is None and not cycleinfo.last:
|
||||||
# Auf neue Daten warten und nur ausführen wenn set()
|
# Auf neue Daten warten und nur ausführen wenn set()
|
||||||
if not self._imgwriter.newdata.wait(2.5):
|
if not self._imgwriter.newdata.wait(2.5):
|
||||||
self.exit(full=False)
|
if not self._imgwriter.is_alive():
|
||||||
if self._imgwriter.is_alive():
|
self.exit(full=False)
|
||||||
e = RuntimeError("no new io data in cycle loop")
|
|
||||||
else:
|
|
||||||
e = RuntimeError("autorefresh thread not running")
|
e = RuntimeError("autorefresh thread not running")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Just warn, user has to use maxioerrors to kill program
|
||||||
|
warnings.warn(RuntimeWarning(
|
||||||
|
"no new io data in cycle loop for 2500 milliseconds"
|
||||||
|
))
|
||||||
|
cycleinfo.last = self._exit.is_set()
|
||||||
|
continue
|
||||||
|
|
||||||
self._imgwriter.newdata.clear()
|
self._imgwriter.newdata.clear()
|
||||||
|
|
||||||
# Vor Aufruf der Funktion autorefresh sperren
|
# Vor Aufruf der Funktion autorefresh sperren
|
||||||
@@ -775,11 +798,13 @@ class RevPiModIO(object):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
if self._imgwriter.lck_refresh.locked():
|
if self._imgwriter.lck_refresh.locked():
|
||||||
self._imgwriter.lck_refresh.release()
|
self._imgwriter.lck_refresh.release()
|
||||||
self.exit(full=False)
|
if self._th_mainloop is None:
|
||||||
|
self.exit(full=False)
|
||||||
e = ex
|
e = ex
|
||||||
finally:
|
finally:
|
||||||
# Cycleloop beenden
|
# Cycleloop beenden
|
||||||
self._looprunning = False
|
self._looprunning = False
|
||||||
|
self._th_mainloop = None
|
||||||
|
|
||||||
# Alte autorefresh Zeit setzen
|
# Alte autorefresh Zeit setzen
|
||||||
self._imgwriter.refresh = old_cycletime
|
self._imgwriter.refresh = old_cycletime
|
||||||
@@ -1023,6 +1048,7 @@ class RevPiModIO(object):
|
|||||||
|
|
||||||
# Direct callen da Prüfung in io.IOBase.reg_event ist
|
# Direct callen da Prüfung in io.IOBase.reg_event ist
|
||||||
tup_fire[0].func(tup_fire[1], tup_fire[2])
|
tup_fire[0].func(tup_fire[1], tup_fire[2])
|
||||||
|
self._imgwriter._eventq.task_done()
|
||||||
|
|
||||||
# Laufzeitprüfung
|
# Laufzeitprüfung
|
||||||
if runtime != -1 and \
|
if runtime != -1 and \
|
||||||
@@ -1094,7 +1120,7 @@ class RevPiModIO(object):
|
|||||||
# FileHandler sperren
|
# FileHandler sperren
|
||||||
dev._filelock.acquire()
|
dev._filelock.acquire()
|
||||||
|
|
||||||
if self._monitoring or self._direct_output:
|
if self._monitoring or dev._shared_procimg:
|
||||||
# Alles vom Bus einlesen
|
# Alles vom Bus einlesen
|
||||||
dev._ba_devdata[:] = bytesbuff[dev._slc_devoff]
|
dev._ba_devdata[:] = bytesbuff[dev._slc_devoff]
|
||||||
else:
|
else:
|
||||||
@@ -1181,9 +1207,6 @@ class RevPiModIO(object):
|
|||||||
:param device: nur auf einzelnes Device anwenden
|
:param device: nur auf einzelnes Device anwenden
|
||||||
:return: True, wenn Arbeiten an allen Devices erfolgreich waren
|
:return: True, wenn Arbeiten an allen Devices erfolgreich waren
|
||||||
"""
|
"""
|
||||||
if self._direct_output:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if self._monitoring:
|
if self._monitoring:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"can not write process image, while system is in monitoring "
|
"can not write process image, while system is in monitoring "
|
||||||
@@ -1206,7 +1229,9 @@ class RevPiModIO(object):
|
|||||||
global_ex = None
|
global_ex = None
|
||||||
workokay = True
|
workokay = True
|
||||||
for dev in mylist:
|
for dev in mylist:
|
||||||
if not dev._selfupdate:
|
if dev._shared_procimg:
|
||||||
|
continue
|
||||||
|
elif not dev._selfupdate:
|
||||||
dev._filelock.acquire()
|
dev._filelock.acquire()
|
||||||
|
|
||||||
# Outpus auf Bus schreiben
|
# Outpus auf Bus schreiben
|
||||||
@@ -1348,7 +1373,9 @@ class RevPiModIODriver(RevPiModIOSelected):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_plc(func, cycletime=50, replace_io_file=None):
|
def run_plc(
|
||||||
|
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.
|
||||||
|
|
||||||
@@ -1356,17 +1383,27 @@ def run_plc(func, cycletime=50, replace_io_file=None):
|
|||||||
handle the program exit signal. You will access the .io, .core, .device
|
handle the program exit signal. You will access the .io, .core, .device
|
||||||
via the cycletools in your cycle function.
|
via the cycletools in your cycle function.
|
||||||
|
|
||||||
Shortcut vor this source code:
|
Shortcut for this source code:
|
||||||
rpi = RevPiModIO(autorefresh=True, replace_io_file=replace_io_file)
|
rpi = RevPiModIO(autorefresh=True, replace_io_file=..., debug=...)
|
||||||
rpi.handlesignalend()
|
rpi.handlesignalend()
|
||||||
return rpi.cycleloop(func, cycletime)
|
return rpi.cycleloop(func, cycletime)
|
||||||
|
|
||||||
:param func: Function to run every set milliseconds
|
:param func: Function to run every set milliseconds
|
||||||
:param cycletime: Cycle time in milliseconds
|
:param cycletime: Cycle time in milliseconds
|
||||||
:param replace_io_file: Load replace IO configuration from file
|
:param replace_io_file: Load replace IO configuration from file
|
||||||
|
:param debug: Print all warnings and detailed error messages
|
||||||
|
:param procimg: Use different process image
|
||||||
|
:param configrsc: Use different piCtory configuration
|
||||||
|
|
||||||
:return: None or the return value of the cycle function
|
:return: None or the return value of the cycle function
|
||||||
"""
|
"""
|
||||||
rpi = RevPiModIO(autorefresh=True, replace_io_file=replace_io_file)
|
rpi = RevPiModIO(
|
||||||
|
autorefresh=True,
|
||||||
|
replace_io_file=replace_io_file,
|
||||||
|
debug=debug,
|
||||||
|
procimg=procimg,
|
||||||
|
configrsc=configrsc,
|
||||||
|
)
|
||||||
rpi.handlesignalend()
|
rpi.handlesignalend()
|
||||||
return rpi.cycleloop(func, cycletime)
|
return rpi.cycleloop(func, cycletime)
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ class NetFH(Thread):
|
|||||||
self.__config_changed = False
|
self.__config_changed = False
|
||||||
self.__int_buff = 0
|
self.__int_buff = 0
|
||||||
self.__dictdirty = {}
|
self.__dictdirty = {}
|
||||||
self.__flusherr = False
|
|
||||||
self.__replace_ios_h = b''
|
self.__replace_ios_h = b''
|
||||||
self.__pictory_h = b''
|
self.__pictory_h = b''
|
||||||
self.__sockerr = Event()
|
self.__sockerr = Event()
|
||||||
@@ -210,7 +209,6 @@ class NetFH(Thread):
|
|||||||
|
|
||||||
self._slavesock = so
|
self._slavesock = so
|
||||||
self.__sockerr.clear()
|
self.__sockerr.clear()
|
||||||
self.__flusherr = False
|
|
||||||
|
|
||||||
# Timeout setzen
|
# Timeout setzen
|
||||||
self.set_timeout(int(self.__timeout * 1000))
|
self.set_timeout(int(self.__timeout * 1000))
|
||||||
@@ -219,18 +217,25 @@ class NetFH(Thread):
|
|||||||
for pos in self.__dictdirty:
|
for pos in self.__dictdirty:
|
||||||
self.set_dirtybytes(pos, self.__dictdirty[pos])
|
self.set_dirtybytes(pos, self.__dictdirty[pos])
|
||||||
|
|
||||||
def _direct_send(self, send_bytes: bytes, recv_len: int) -> bytes:
|
def _direct_sr(self, send_bytes: bytes, recv_len: int) -> bytes:
|
||||||
"""
|
"""
|
||||||
Sicherer Zugriff auf send / recv Schnittstelle mit Laengenpruefung.
|
Secure send and receive function for network handler.
|
||||||
|
|
||||||
:param send_bytes: Bytes, die gesendet werden sollen
|
Will raise exception on closed network handler or network errors and
|
||||||
:param recv_len: Anzahl der die empfangen werden sollen
|
set the sockerr flag.
|
||||||
:return: Empfangende Bytes
|
|
||||||
|
:param send_bytes: Bytes to send or empty
|
||||||
|
:param recv_len: Amount of bytes to receive
|
||||||
|
:return: Received bytes
|
||||||
"""
|
"""
|
||||||
if self.__sockend.is_set():
|
if self.__sockend.is_set():
|
||||||
raise ValueError("I/O operation on closed file")
|
raise ValueError("I/O operation on closed file")
|
||||||
|
if self.__sockerr.is_set():
|
||||||
|
raise IOError("not allowed while reconnect")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.__socklock.acquire()
|
||||||
|
|
||||||
with self.__socklock:
|
|
||||||
counter = 0
|
counter = 0
|
||||||
send_len = len(send_bytes)
|
send_len = len(send_bytes)
|
||||||
while counter < send_len:
|
while counter < send_len:
|
||||||
@@ -238,7 +243,7 @@ class NetFH(Thread):
|
|||||||
sent = self._slavesock.send(send_bytes[counter:])
|
sent = self._slavesock.send(send_bytes[counter:])
|
||||||
if sent == 0:
|
if sent == 0:
|
||||||
self.__sockerr.set()
|
self.__sockerr.set()
|
||||||
raise IOError("lost network connection")
|
raise IOError("lost network connection while send")
|
||||||
counter += sent
|
counter += sent
|
||||||
|
|
||||||
self.__buff_recv.clear()
|
self.__buff_recv.clear()
|
||||||
@@ -247,12 +252,20 @@ class NetFH(Thread):
|
|||||||
self.__buff_block, min(recv_len, self.__buff_size)
|
self.__buff_block, min(recv_len, self.__buff_size)
|
||||||
)
|
)
|
||||||
if count == 0:
|
if count == 0:
|
||||||
self.__sockerr.set()
|
raise IOError("lost network connection while receive")
|
||||||
raise IOError("lost network connection")
|
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
self.__buff_recv += self.__buff_block[:count]
|
||||||
recv_len -= count
|
recv_len -= count
|
||||||
|
|
||||||
return bytes(self.__buff_recv)
|
# Create copy in socklock environment
|
||||||
|
return_buffer = bytes(self.__buff_recv)
|
||||||
|
except Exception:
|
||||||
|
self.__sockerr.set()
|
||||||
|
raise
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.__socklock.release()
|
||||||
|
|
||||||
|
return return_buffer
|
||||||
|
|
||||||
def clear_dirtybytes(self, position=None) -> None:
|
def clear_dirtybytes(self, position=None) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -268,42 +281,32 @@ class NetFH(Thread):
|
|||||||
if self.__sockend.is_set():
|
if self.__sockend.is_set():
|
||||||
raise ValueError("I/O operation on closed file")
|
raise ValueError("I/O operation on closed file")
|
||||||
|
|
||||||
error = False
|
|
||||||
try:
|
|
||||||
self.__socklock.acquire()
|
|
||||||
|
|
||||||
if position is None:
|
|
||||||
# Alle Dirtybytes löschen
|
|
||||||
self._slavesock.sendall(_sysdeldirty)
|
|
||||||
else:
|
|
||||||
# Nur bestimmte Dirtybytes löschen
|
|
||||||
# b CM ii xx c0000000 b = 16
|
|
||||||
self._slavesock.sendall(pack(
|
|
||||||
"=c2sH2xc7xc",
|
|
||||||
HEADER_START, b'EY', position, b'\xfe', HEADER_STOP
|
|
||||||
))
|
|
||||||
|
|
||||||
check = self._slavesock.recv(1)
|
|
||||||
if check != b'\x1e':
|
|
||||||
# ACL prüfen und ggf Fehler werfen
|
|
||||||
self.__check_acl(check)
|
|
||||||
|
|
||||||
raise IOError("clear dirtybytes error on network")
|
|
||||||
except AclException:
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
error = True
|
|
||||||
finally:
|
|
||||||
self.__socklock.release()
|
|
||||||
|
|
||||||
# Daten immer übernehmen
|
# Daten immer übernehmen
|
||||||
if position is None:
|
if position is None:
|
||||||
self.__dictdirty = {}
|
self.__dictdirty.clear()
|
||||||
elif position in self.__dictdirty:
|
elif position in self.__dictdirty:
|
||||||
del self.__dictdirty[position]
|
del self.__dictdirty[position]
|
||||||
|
|
||||||
if error:
|
try:
|
||||||
# Fehler nach übernahme der Daten auslösen um diese zu setzen
|
if position is None:
|
||||||
|
# Alle Dirtybytes löschen
|
||||||
|
buff = self._direct_sr(_sysdeldirty, 1)
|
||||||
|
else:
|
||||||
|
# Nur bestimmte Dirtybytes löschen
|
||||||
|
# b CM ii xx c0000000 b = 16
|
||||||
|
buff = self._direct_sr(pack(
|
||||||
|
"=c2sH2xc7xc",
|
||||||
|
HEADER_START, b'EY', position, b'\xfe', HEADER_STOP
|
||||||
|
), 1)
|
||||||
|
if buff != b'\x1e':
|
||||||
|
# ACL prüfen und ggf Fehler werfen
|
||||||
|
self.__check_acl(buff)
|
||||||
|
|
||||||
|
raise IOError("clear dirtybytes error on network")
|
||||||
|
except AclException:
|
||||||
|
self.__dictdirty.clear()
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
self.__sockerr.set()
|
self.__sockerr.set()
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
@@ -334,32 +337,28 @@ class NetFH(Thread):
|
|||||||
if self.__sockend.is_set():
|
if self.__sockend.is_set():
|
||||||
raise ValueError("flush of closed file")
|
raise ValueError("flush of closed file")
|
||||||
|
|
||||||
with self.__socklock:
|
if self.__int_buff == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
# b CM ii ii 00000000 b = 16
|
# b CM ii ii 00000000 b = 16
|
||||||
try:
|
buff = self._direct_sr(pack(
|
||||||
self._slavesock.sendall(pack(
|
"=c2sHH8xc",
|
||||||
"=c2sHH8xc",
|
HEADER_START, b'FD', self.__int_buff, len(self.__by_buff), HEADER_STOP
|
||||||
HEADER_START, b'FD', self.__int_buff, len(self.__by_buff), HEADER_STOP
|
) + self.__by_buff, 1)
|
||||||
) + self.__by_buff)
|
except Exception:
|
||||||
except Exception:
|
raise
|
||||||
self.__flusherr = True
|
finally:
|
||||||
raise
|
# Puffer immer leeren
|
||||||
finally:
|
self.__int_buff = 0
|
||||||
# Puffer immer leeren
|
self.__by_buff.clear()
|
||||||
self.__int_buff = 0
|
|
||||||
self.__by_buff.clear()
|
|
||||||
|
|
||||||
# Rückmeldebyte auswerten
|
if buff != b'\x1e':
|
||||||
blockok = self._slavesock.recv(1)
|
# ACL prüfen und ggf Fehler werfen
|
||||||
if blockok != b'\x1e':
|
self.__check_acl(buff)
|
||||||
# ACL prüfen und ggf Fehler werfen
|
|
||||||
self.__check_acl(blockok)
|
|
||||||
|
|
||||||
self.__flusherr = True
|
self.__sockerr.set()
|
||||||
self.__sockerr.set()
|
raise IOError("flush error on network")
|
||||||
raise IOError("flush error on network")
|
|
||||||
else:
|
|
||||||
self.__flusherr = False
|
|
||||||
|
|
||||||
def get_closed(self) -> bool:
|
def get_closed(self) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -416,21 +415,17 @@ class NetFH(Thread):
|
|||||||
if not (isinstance(arg, bytes) and len(arg) <= 1024):
|
if not (isinstance(arg, bytes) and len(arg) <= 1024):
|
||||||
raise TypeError("arg must be <class 'bytes'>")
|
raise TypeError("arg must be <class 'bytes'>")
|
||||||
|
|
||||||
with self.__socklock:
|
# b CM xx ii iiii0000 b = 16
|
||||||
# b CM xx ii iiii0000 b = 16
|
buff = self._direct_sr(pack(
|
||||||
self._slavesock.sendall(pack(
|
"=c2s2xHI4xc",
|
||||||
"=c2s2xHI4xc",
|
HEADER_START, b'IC', len(arg), request, HEADER_STOP
|
||||||
HEADER_START, b'IC', len(arg), request, HEADER_STOP
|
) + arg, 1)
|
||||||
) + arg)
|
if buff != b'\x1e':
|
||||||
|
# ACL prüfen und ggf Fehler werfen
|
||||||
|
self.__check_acl(buff)
|
||||||
|
|
||||||
# Rückmeldebyte auswerten
|
self.__sockerr.set()
|
||||||
blockok = self._slavesock.recv(1)
|
raise IOError("ioctl error on network")
|
||||||
if blockok != b'\x1e':
|
|
||||||
# ACL prüfen und ggf Fehler werfen
|
|
||||||
self.__check_acl(blockok)
|
|
||||||
|
|
||||||
self.__sockerr.set()
|
|
||||||
raise IOError("ioctl error on network")
|
|
||||||
|
|
||||||
def read(self, length: int) -> bytes:
|
def read(self, length: int) -> bytes:
|
||||||
"""
|
"""
|
||||||
@@ -444,28 +439,14 @@ class NetFH(Thread):
|
|||||||
if self.__sockend.is_set():
|
if self.__sockend.is_set():
|
||||||
raise ValueError("read of closed file")
|
raise ValueError("read of closed file")
|
||||||
|
|
||||||
with self.__socklock:
|
# b CM ii ii 00000000 b = 16
|
||||||
# b CM ii ii 00000000 b = 16
|
buff = self._direct_sr(pack(
|
||||||
self._slavesock.sendall(pack(
|
"=c2sHH8xc",
|
||||||
"=c2sHH8xc",
|
HEADER_START, b'DA', self.__position, length, HEADER_STOP
|
||||||
HEADER_START, b'DA', self.__position, length, HEADER_STOP
|
), length)
|
||||||
))
|
|
||||||
|
|
||||||
self.__position += length
|
self.__position += length
|
||||||
|
return buff
|
||||||
self.__buff_recv.clear()
|
|
||||||
while length > 0:
|
|
||||||
count = self._slavesock.recv_into(
|
|
||||||
self.__buff_block,
|
|
||||||
min(length, self.__buff_size),
|
|
||||||
)
|
|
||||||
if count == 0:
|
|
||||||
self.__sockerr.set()
|
|
||||||
raise IOError("read error on network")
|
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
|
||||||
length -= count
|
|
||||||
|
|
||||||
return bytes(self.__buff_recv)
|
|
||||||
|
|
||||||
def readinto(self, buffer: bytearray) -> int:
|
def readinto(self, buffer: bytearray) -> int:
|
||||||
"""
|
"""
|
||||||
@@ -480,29 +461,14 @@ class NetFH(Thread):
|
|||||||
raise ValueError("read of closed file")
|
raise ValueError("read of closed file")
|
||||||
|
|
||||||
length = len(buffer)
|
length = len(buffer)
|
||||||
with self.__socklock:
|
|
||||||
# b CM ii ii 00000000 b = 16
|
|
||||||
self._slavesock.sendall(pack(
|
|
||||||
"=c2sHH8xc",
|
|
||||||
HEADER_START, b'DA', self.__position, length, HEADER_STOP
|
|
||||||
))
|
|
||||||
|
|
||||||
net_buffer = b''
|
# b CM ii ii 00000000 b = 16
|
||||||
while length > 0:
|
buff = self._direct_sr(pack(
|
||||||
count = self._slavesock.recv_into(
|
"=c2sHH8xc",
|
||||||
self.__buff_block,
|
HEADER_START, b'DA', self.__position, length, HEADER_STOP
|
||||||
min(length, self.__buff_size),
|
), length)
|
||||||
)
|
|
||||||
if count == 0:
|
|
||||||
self.__sockerr.set()
|
|
||||||
raise IOError("read error on network")
|
|
||||||
net_buffer += self.__buff_block[:count]
|
|
||||||
length -= count
|
|
||||||
|
|
||||||
# We received the correct amount of bytes here
|
|
||||||
self.__position += length
|
|
||||||
buffer[:] = net_buffer
|
|
||||||
|
|
||||||
|
buffer[:] = buff
|
||||||
return len(buffer)
|
return len(buffer)
|
||||||
|
|
||||||
def readpictory(self) -> bytes:
|
def readpictory(self) -> bytes:
|
||||||
@@ -519,31 +485,9 @@ class NetFH(Thread):
|
|||||||
"could not read/parse piCtory configuration over network"
|
"could not read/parse piCtory configuration over network"
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.__socklock:
|
buff = self._direct_sr(_syspictory, 4)
|
||||||
self._slavesock.sendall(_syspictory)
|
recv_length, = unpack("=I", buff)
|
||||||
|
return self._direct_sr(b'', recv_length)
|
||||||
self.__buff_recv.clear()
|
|
||||||
recv_lenght = 4
|
|
||||||
while recv_lenght > 0:
|
|
||||||
count = self._slavesock.recv_into(
|
|
||||||
self.__buff_block, recv_lenght
|
|
||||||
)
|
|
||||||
if count == 0:
|
|
||||||
raise IOError("readpictory length error on network")
|
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
|
||||||
recv_lenght -= count
|
|
||||||
|
|
||||||
recv_lenght, = unpack("=I", self.__buff_recv)
|
|
||||||
while recv_lenght > 0:
|
|
||||||
count = self._slavesock.recv_into(
|
|
||||||
self.__buff_block, min(recv_lenght, self.__buff_size)
|
|
||||||
)
|
|
||||||
if count == 0:
|
|
||||||
raise IOError("readpictory file error on network")
|
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
|
||||||
recv_lenght -= count
|
|
||||||
|
|
||||||
return bytes(self.__buff_recv[4:])
|
|
||||||
|
|
||||||
def readreplaceio(self) -> bytes:
|
def readreplaceio(self) -> bytes:
|
||||||
"""
|
"""
|
||||||
@@ -559,31 +503,9 @@ class NetFH(Thread):
|
|||||||
"replace_io_file: could not read/parse over network"
|
"replace_io_file: could not read/parse over network"
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.__socklock:
|
buff = self._direct_sr(_sysreplaceio, 4)
|
||||||
self._slavesock.sendall(_sysreplaceio)
|
recv_length, = unpack("=I", buff)
|
||||||
|
return self._direct_sr(b'', recv_length)
|
||||||
self.__buff_recv.clear()
|
|
||||||
recv_lenght = 4
|
|
||||||
while recv_lenght > 0:
|
|
||||||
count = self._slavesock.recv_into(
|
|
||||||
self.__buff_block, recv_lenght
|
|
||||||
)
|
|
||||||
if count == 0:
|
|
||||||
raise IOError("readreplaceio length error on network")
|
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
|
||||||
recv_lenght -= count
|
|
||||||
|
|
||||||
recv_lenght, = unpack("=I", self.__buff_recv)
|
|
||||||
while recv_lenght > 0:
|
|
||||||
count = self._slavesock.recv_into(
|
|
||||||
self.__buff_block, min(recv_lenght, self.__buff_size)
|
|
||||||
)
|
|
||||||
if count == 0:
|
|
||||||
raise IOError("readreplaceio file error on network")
|
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
|
||||||
recv_lenght -= count
|
|
||||||
|
|
||||||
return bytes(self.__buff_recv[4:])
|
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""Handler fuer Synchronisierung."""
|
"""Handler fuer Synchronisierung."""
|
||||||
@@ -622,7 +544,7 @@ class NetFH(Thread):
|
|||||||
self.__buff_block, recv_lenght
|
self.__buff_block, recv_lenght
|
||||||
)
|
)
|
||||||
if count == 0:
|
if count == 0:
|
||||||
raise IOError("lost network connection")
|
raise IOError("lost network connection on sync")
|
||||||
self.__buff_recv += self.__buff_block[:count]
|
self.__buff_recv += self.__buff_block[:count]
|
||||||
recv_lenght -= count
|
recv_lenght -= count
|
||||||
|
|
||||||
@@ -666,34 +588,26 @@ class NetFH(Thread):
|
|||||||
if self.__sockend.is_set():
|
if self.__sockend.is_set():
|
||||||
raise ValueError("I/O operation on closed file")
|
raise ValueError("I/O operation on closed file")
|
||||||
|
|
||||||
error = False
|
|
||||||
try:
|
|
||||||
self.__socklock.acquire()
|
|
||||||
|
|
||||||
# b CM ii ii 00000000 b = 16
|
|
||||||
self._slavesock.sendall(pack(
|
|
||||||
"=c2sHH8xc",
|
|
||||||
HEADER_START, b'EY', position, len(dirtybytes), HEADER_STOP
|
|
||||||
) + dirtybytes)
|
|
||||||
|
|
||||||
check = self._slavesock.recv(1)
|
|
||||||
if check != b'\x1e':
|
|
||||||
# ACL prüfen und ggf Fehler werfen
|
|
||||||
self.__check_acl(check)
|
|
||||||
|
|
||||||
raise IOError("set dirtybytes error on network")
|
|
||||||
except AclException:
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
error = True
|
|
||||||
finally:
|
|
||||||
self.__socklock.release()
|
|
||||||
|
|
||||||
# Daten immer übernehmen
|
# Daten immer übernehmen
|
||||||
self.__dictdirty[position] = dirtybytes
|
self.__dictdirty[position] = dirtybytes
|
||||||
|
|
||||||
if error:
|
try:
|
||||||
# Fehler nach übernahme der Daten auslösen um diese zu setzen
|
# b CM ii ii 00000000 b = 16
|
||||||
|
buff = self._direct_sr(pack(
|
||||||
|
"=c2sHH8xc",
|
||||||
|
HEADER_START, b'EY', position, len(dirtybytes), HEADER_STOP
|
||||||
|
) + dirtybytes, 1)
|
||||||
|
|
||||||
|
if buff != b'\x1e':
|
||||||
|
# ACL prüfen und ggf Fehler werfen
|
||||||
|
self.__check_acl(buff)
|
||||||
|
|
||||||
|
raise IOError("set dirtybytes error on network")
|
||||||
|
except AclException:
|
||||||
|
# Not allowed, clear for reconnect
|
||||||
|
self.__dictdirty.clear()
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
self.__sockerr.set()
|
self.__sockerr.set()
|
||||||
|
|
||||||
def set_timeout(self, value: int) -> None:
|
def set_timeout(self, value: int) -> None:
|
||||||
@@ -709,20 +623,15 @@ class NetFH(Thread):
|
|||||||
self.__set_systimeout(value)
|
self.__set_systimeout(value)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.__socklock.acquire()
|
|
||||||
|
|
||||||
# b CM ii xx 00000000 b = 16
|
# b CM ii xx 00000000 b = 16
|
||||||
self._slavesock.sendall(pack(
|
buff = self._direct_sr(pack(
|
||||||
"=c2sH10xc",
|
"=c2sH10xc",
|
||||||
HEADER_START, b'CF', value, HEADER_STOP
|
HEADER_START, b'CF', value, HEADER_STOP
|
||||||
))
|
), 1)
|
||||||
check = self._slavesock.recv(1)
|
if buff != b'\x1e':
|
||||||
if check != 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()
|
||||||
finally:
|
|
||||||
self.__socklock.release()
|
|
||||||
|
|
||||||
def tell(self) -> int:
|
def tell(self) -> int:
|
||||||
"""
|
"""
|
||||||
@@ -747,14 +656,13 @@ class NetFH(Thread):
|
|||||||
raise ConfigChanged("configuration on revolution pi was changed")
|
raise ConfigChanged("configuration on revolution pi was changed")
|
||||||
if self.__sockend.is_set():
|
if self.__sockend.is_set():
|
||||||
raise ValueError("write to closed file")
|
raise ValueError("write to closed file")
|
||||||
|
if self.__sockerr.is_set():
|
||||||
if self.__flusherr:
|
raise IOError("not allowed while reconnect")
|
||||||
raise IOError("I/O error since last flush")
|
|
||||||
|
|
||||||
with self.__socklock:
|
with self.__socklock:
|
||||||
self.__int_buff += 1
|
self.__int_buff += 1
|
||||||
|
|
||||||
# Datenblöcke mit Group Seperator in Puffer ablegen
|
# Datenblock mit Position und Länge 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
|
||||||
@@ -802,7 +710,7 @@ class RevPiNetIO(_RevPiModIO):
|
|||||||
:param direct_output: Deprecated, use shared_procimg
|
:param direct_output: Deprecated, use shared_procimg
|
||||||
"""
|
"""
|
||||||
check_ip = compile(
|
check_ip = compile(
|
||||||
r"^(?P<ipn>(25[0-5]|(2[0-4]|[01]?\d|)\d))(\.(?P=ipn)){3}$"
|
r"^(25[0-5]|(2[0-4]|[01]?\d|)\d)(\.(25[0-5]|(2[0-4]|[01]?\d|)\d)){3}$"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Adresse verarbeiten
|
# Adresse verarbeiten
|
||||||
|
|||||||
@@ -15,9 +15,8 @@ __license__ = "LGPLv3"
|
|||||||
# - RevPiGateCANopen_20161102_1_0.rap
|
# - RevPiGateCANopen_20161102_1_0.rap
|
||||||
|
|
||||||
|
|
||||||
# Can be used for :
|
|
||||||
# RevPi AIO 1.0 (RevPiAIO_20170301_1_0.rap)
|
|
||||||
class AIO:
|
class AIO:
|
||||||
|
"""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
|
||||||
@@ -89,9 +88,8 @@ class AIO:
|
|||||||
RTD_4_WIRE = 1 # 4-wire
|
RTD_4_WIRE = 1 # 4-wire
|
||||||
|
|
||||||
|
|
||||||
# Can be used for :
|
|
||||||
# RevPi DI 1.0 (RevPiDI_20160818_1_0.rap)
|
|
||||||
class DI:
|
class DI:
|
||||||
|
"""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
|
||||||
@@ -103,9 +101,8 @@ class DI:
|
|||||||
IN_DEBOUNCE_3MS = 3 # 3ms
|
IN_DEBOUNCE_3MS = 3 # 3ms
|
||||||
|
|
||||||
|
|
||||||
# Can be used for :
|
|
||||||
# RevPi DO 1.0 (RevPiDO_20160818_1_0.rap)
|
|
||||||
class DO:
|
class DO:
|
||||||
|
"""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%
|
||||||
@@ -113,7 +110,19 @@ class DO:
|
|||||||
OUT_PWM_FREQ_400HZ = 10 # 400Hz 10%
|
OUT_PWM_FREQ_400HZ = 10 # 400Hz 10%
|
||||||
|
|
||||||
|
|
||||||
# Can be used for :
|
|
||||||
# RevPi DIO 1.0 (RevPiDIO_20160818_1_0.rap)
|
|
||||||
class DIO(DI, DO):
|
class DIO(DI, DO):
|
||||||
|
"""Memory value mappings for RevPi DIO 1.0 (RevPiDIO_20160818_1_0.rap)."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class COMPACT:
|
||||||
|
"""Memory value mappings for RevPi Compact 1.0 (RevPiCompact_20171023_1_0.rap)."""
|
||||||
|
DIN_DEBOUNCE_OFF = 0 # Off
|
||||||
|
DIN_DEBOUNCE_25US = 1 # 25us
|
||||||
|
DIN_DEBOUNCE_750US = 2 # 750us
|
||||||
|
DIN_DEBOUNCE_3MS = 3 # 3ms
|
||||||
|
|
||||||
|
AIN_MODE_OFF = 0 # Off
|
||||||
|
AIN_MODE_0_10V = 1 # 0 - 10V
|
||||||
|
AIN_MODE_PT100 = 3 # PT100
|
||||||
|
AIN_MODE_PT1000 = 7 # PT1000
|
||||||
|
|||||||
Reference in New Issue
Block a user