replace_io accepts keyword wordorder

Now you can set the wordorder for a replaced IO on virtual devices. This
will help you to get the right values on modbus devices.
This commit is contained in:
2023-01-12 23:26:09 +01:00
parent 0dd9c2637d
commit 36c30ae6d6
3 changed files with 82 additions and 10 deletions

7
.idea/vcs.xml generated
View File

@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="BodyLimit" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SubjectBodySeparation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SubjectLimit" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="$PROJECT_DIR$" vcs="Git" />
</component> </component>

View File

@@ -1139,6 +1139,7 @@ class IntIOReplaceable(IntIO):
- bmk: interne Bezeichnung fuer IO - bmk: interne Bezeichnung fuer IO
- bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte - bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte
- byteorder: Byteorder fuer den IO, Standardwert=little - byteorder: Byteorder fuer den IO, Standardwert=little
- wordorder: Wordorder wird vor byteorder angewendet
- defaultvalue: Standardwert fuer IO - defaultvalue: Standardwert fuer IO
- event: Funktion fuer Eventhandling registrieren - event: Funktion fuer Eventhandling registrieren
- delay: Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt - delay: Verzoegerung in ms zum Ausloesen wenn Wert gleich bleibt
@@ -1179,7 +1180,7 @@ class StructIO(IOBase):
""" """
__slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \ __slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \
"_parentio_length", "_parentio_name" "_parentio_length", "_parentio_name", "_wordorder"
def __init__(self, parentio, name: str, frm: str, **kwargs): def __init__(self, parentio, name: str, frm: str, **kwargs):
""" """
@@ -1192,6 +1193,7 @@ class StructIO(IOBase):
- bmk: Bezeichnung fuer IO - bmk: Bezeichnung fuer IO
- bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte - bit: Registriert IO als <class 'bool'> am angegebenen Bit im Byte
- byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO - byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO
- wordorder: Wordorder wird vor byteorder angewendet
- defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO - defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO
""" """
# Structformatierung prüfen # Structformatierung prüfen
@@ -1200,14 +1202,19 @@ class StructIO(IOBase):
if regex is not None: if regex is not None:
# Byteorder prüfen und übernehmen # Byteorder prüfen und übernehmen
byteorder = kwargs.get("byteorder", parentio._byteorder) byteorder = kwargs.get("byteorder", parentio._byteorder)
if not (byteorder == "little" or byteorder == "big"): if byteorder not in ("little", "big"):
raise ValueError("byteorder must be 'little' or 'big'") raise ValueError("byteorder must be 'little' or 'big'")
bofrm = "<" if byteorder == "little" else ">" bofrm = "<" if byteorder == "little" else ">"
self._wordorder = kwargs.get("wordorder", None)
# Namen des parent fuer export merken # Namen des parent fuer export merken
self._parentio_name = parentio._name self._parentio_name = parentio._name
if frm == "?": if frm == "?":
if self._wordorder:
raise ValueError(
"you can not use wordorder for bit based ios"
)
bitaddress = kwargs.get("bit", 0) bitaddress = kwargs.get("bit", 0)
max_bits = parentio._length * 8 max_bits = parentio._length * 8
if not (0 <= bitaddress < max_bits): if not (0 <= bitaddress < max_bits):
@@ -1225,11 +1232,20 @@ class StructIO(IOBase):
self._parentio_address = parentio.address self._parentio_address = parentio.address
self._parentio_length = parentio._length self._parentio_length = parentio._length
else: else:
byte_length = struct.calcsize(bofrm + frm)
bitaddress = "" bitaddress = ""
bitlength = struct.calcsize(bofrm + frm) * 8 bitlength = byte_length * 8
self._parentio_address = None self._parentio_address = None
self._parentio_defaultvalue = None self._parentio_defaultvalue = None
self._parentio_length = None self._parentio_length = None
if self._wordorder:
if self._wordorder not in ("little", "big"):
raise ValueError("wordorder must be 'little' or 'big'")
if byte_length % 2 != 0:
raise ValueError(
"the byte length of new io must must be even to "
"use wordorder"
)
# [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress] # [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress]
valuelist = [ valuelist = [
@@ -1280,12 +1296,20 @@ class StructIO(IOBase):
# Inline get_structdefaultvalue() # Inline get_structdefaultvalue()
if self._bitshift: if self._bitshift:
return self.get_value() return self.get_value()
else: if self._wordorder == "little" and self._length > 2:
return struct.unpack(
self.__frm,
self._swap_word_order(self.get_value()),
)[0]
return struct.unpack(self.__frm, self.get_value())[0] return struct.unpack(self.__frm, self.get_value())[0]
else: else:
# Inline set_structvalue() # Inline set_structvalue()
if self._bitshift: if self._bitshift:
self.set_value(value) self.set_value(value)
elif self._wordorder == "little" and self._length > 2:
self.set_value(
self._swap_word_order(struct.pack(self.__frm, value))
)
else: else:
self.set_value(struct.pack(self.__frm, value)) self.set_value(struct.pack(self.__frm, value))
@@ -1305,6 +1329,21 @@ class StructIO(IOBase):
""" """
return self._signed return self._signed
@staticmethod
def _swap_word_order(bytes_to_swap) -> bytes:
"""
Swap word order of given bytes.
:param bytes_to_swap: Already length checked bytes to swap words
:return: Bytes with swapped word order
"""
array_length = len(bytes_to_swap)
swap_array = bytearray(bytes_to_swap)
for i in range(0, array_length // 2, 2):
swap_array[-i - 2:array_length - i], swap_array[i:i + 2] = \
swap_array[i:i + 2], swap_array[-i - 2:array_length - i]
return bytes(swap_array)
def get_structdefaultvalue(self): def get_structdefaultvalue(self):
""" """
Gibt die Defaultvalue mit struct Formatierung zurueck. Gibt die Defaultvalue mit struct Formatierung zurueck.
@@ -1313,9 +1352,21 @@ class StructIO(IOBase):
""" """
if self._bitshift: if self._bitshift:
return self._defaultvalue return self._defaultvalue
else: if self._wordorder == "little" and self._length > 2:
return struct.unpack(
self.__frm,
self._swap_word_order(self._defaultvalue),
)[0]
return struct.unpack(self.__frm, self._defaultvalue)[0] return struct.unpack(self.__frm, self._defaultvalue)[0]
def get_wordorder(self) -> str:
"""
Gibt die wordorder für diesen IO zurück.
:return: "little", "big" or "ignored"
"""
return self._wordorder or "ignored"
def get_structvalue(self): def get_structvalue(self):
""" """
Gibt den Wert mit struct Formatierung zurueck. Gibt den Wert mit struct Formatierung zurueck.
@@ -1324,7 +1375,11 @@ class StructIO(IOBase):
""" """
if self._bitshift: if self._bitshift:
return self.get_value() return self.get_value()
else: if self._wordorder == "little" and self._length > 2:
return struct.unpack(
self.__frm,
self._swap_word_order(self.get_value()),
)[0]
return struct.unpack(self.__frm, self.get_value())[0] return struct.unpack(self.__frm, self.get_value())[0]
def set_structvalue(self, value): def set_structvalue(self, value):
@@ -1335,6 +1390,10 @@ class StructIO(IOBase):
""" """
if self._bitshift: if self._bitshift:
self.set_value(value) self.set_value(value)
elif self._wordorder == "little" and self._length > 2:
self.set_value(
self._swap_word_order(struct.pack(self.__frm, value))
)
else: else:
self.set_value(struct.pack(self.__frm, value)) self.set_value(struct.pack(self.__frm, value))
@@ -1342,6 +1401,7 @@ class StructIO(IOBase):
frm = property(_get_frm) frm = property(_get_frm)
signed = property(_get_signed) signed = property(_get_signed)
value = property(get_structvalue, set_structvalue) value = property(get_structvalue, set_structvalue)
wordorder = property(get_wordorder)
class MemIO(IOBase): class MemIO(IOBase):

View File

@@ -403,6 +403,9 @@ class RevPiModIO(object):
"".format(io, creplaceio[io]["bit"]) "".format(io, creplaceio[io]["bit"])
) )
if "wordorder" in creplaceio[io]:
dict_replace["wordorder"] = creplaceio[io]["wordorder"]
if "export" in creplaceio[io]: if "export" in creplaceio[io]:
try: try:
dict_replace["export"] = creplaceio[io].getboolean("export") dict_replace["export"] = creplaceio[io].getboolean("export")
@@ -877,7 +880,7 @@ class RevPiModIO(object):
Exportiert ersetzte IOs dieser Instanz. Exportiert ersetzte IOs dieser Instanz.
Exportiert alle ersetzten IOs, welche mit .replace_io(...) angelegt Exportiert alle ersetzten IOs, welche mit .replace_io(...) angelegt
wurden. Die Datei kann z.B. fuer RevPiPyLoad verwndet werden um Daten wurden. Die Datei kann z.B. fuer RevPiPyLoad verwendet werden um Daten
in den neuen Formaten per MQTT zu uebertragen oder mit RevPiPyControl in den neuen Formaten per MQTT zu uebertragen oder mit RevPiPyControl
anzusehen. anzusehen.
@@ -899,6 +902,8 @@ class RevPiModIO(object):
cp[io.name]["bit"] = str(io._bitaddress) cp[io.name]["bit"] = str(io._bitaddress)
if io._byteorder != "little": if io._byteorder != "little":
cp[io.name]["byteorder"] = io._byteorder cp[io.name]["byteorder"] = io._byteorder
if io._wordorder:
cp[io.name]["wordorder"] = io._wordorder
if type(io.defaultvalue) is bytes: if type(io.defaultvalue) is bytes:
if any(io.defaultvalue): if any(io.defaultvalue):
# Convert each byte to an integer # Convert each byte to an integer