From ea99f3f3fe63966d7b570d746a147de0a9bf18e8 Mon Sep 17 00:00:00 2001 From: NaruX Date: Sun, 23 Jun 2019 15:32:26 +0200 Subject: [PATCH 01/10] =?UTF-8?q?replace=5Fio=5Ffile=20nimmt=20nun=20Wert?= =?UTF-8?q?=20:network:=20und=20l=C3=A4d=20Konfiguration=20=C3=BCber=20Rev?= =?UTF-8?q?PiPyLoad=20.=5Fconfigure=5Freplace=5Fio=20ist=20eigenst=C3=A4nd?= =?UTF-8?q?ige=20Funktion=20.=5Fget=5Fcpreplaceio=20f=C3=BCr=20=C3=9Cbersc?= =?UTF-8?q?hreibungen=20bei=20Vererbung=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.modio.html | 32 ++++++++++++--- doc/revpimodio2.netio.html | 32 ++++++++++++++- eric-revpimodio2.api | 6 ++- revpimodio2/modio.py | 82 ++++++++++++++++++++++---------------- revpimodio2/netio.py | 77 ++++++++++++++++++++++++++++++----- 5 files changed, 175 insertions(+), 54 deletions(-) diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index 2841f45..30e412e 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -86,6 +86,9 @@ Methods _get_configrsc Getter function. +_get_cpreplaceio +Laed die replace_io_file Konfiguration und verarbeitet sie. + _get_cycletime Gibt Aktualisierungsrate in ms der Prozessabbildsynchronisierung aus. @@ -219,19 +222,27 @@ RevPiModIO._configure _configure(jconfigrsc)

Verarbeitet die piCtory Konfigurationsdatei. -

+

+
jconfigrsc:
+
+Data to build IOs as of JSON +
+

RevPiModIO._configure_replace_io

-_configure_replace_io() +_configure_replace_io(creplaceio)

Importiert ersetzte IOs in diese Instanz.

Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) in eine Datei exportiert worden sind. Diese IOs werden in dieser Instanz wiederhergestellt. -

- -

+

+
ireplaceio:
+
+Data to replace ios as +
+

RevPiModIO._create_myfh

_create_myfh() @@ -249,6 +260,17 @@ Getter function.
Pfad der verwendeten piCtory Konfiguration
+ +

+RevPiModIO._get_cpreplaceio

+_get_cpreplaceio() +

+Laed die replace_io_file Konfiguration und verarbeitet sie. +

+
Returns:
+
+ der replace io daten +

RevPiModIO._get_cycletime

diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index 4c614a8..bc0c938 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -12,7 +12,7 @@ RevPiModIO Hauptklasse fuer Netzwerkzugriff.

Global Attributes

- +
__author__
__copyright__
__license__
_sysdeldirty
_sysexit
_sysflush
_syspictory
_syssync
__author__
__copyright__
__license__
_sysdeldirty
_sysexit
_sysflush
_syspictory
_sysreplaceio
_syssync

Classes

@@ -110,6 +110,9 @@ Methods readpictory Ruft die piCtory Konfiguration ab. +readreplaceio +Ruft die replace_io Konfiguration ab. + run Handler fuer Synchronisierung. @@ -293,6 +296,17 @@ Ruft die piCtory Konfiguration ab.
piCtory Datei
+ +

+NetFH.readreplaceio

+readreplaceio() +

+Ruft die replace_io Konfiguration ab. +

+
Returns:
+
+ replace_io_file +

NetFH.run

@@ -402,6 +416,9 @@ Methods _create_myfh Erstellt NetworkFileObject. +_get_cpreplaceio +Laed die replace_io Konfiguration ueber das Netzwerk. + disconnect Trennt Verbindungen und beendet autorefresh inkl. @@ -456,7 +473,18 @@ RevPiNetIO._create_myfh

Erstellt NetworkFileObject. return FileObject -

+

+

+RevPiNetIO._get_cpreplaceio

+_get_cpreplaceio() +

+Laed die replace_io Konfiguration ueber das Netzwerk. +

+
Returns:
+
+ der replace io daten +
+

RevPiNetIO.disconnect

disconnect() diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index 270362a..692878b 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -141,9 +141,10 @@ revpimodio2.io.StructIO.signed?7 revpimodio2.io.StructIO.value?7 revpimodio2.io.StructIO?1(parentio, name, frm, **kwargs) revpimodio2.modio.RevPiModIO._configure?5(jconfigrsc) -revpimodio2.modio.RevPiModIO._configure_replace_io?5() +revpimodio2.modio.RevPiModIO._configure_replace_io?5(creplaceio) revpimodio2.modio.RevPiModIO._create_myfh?5() revpimodio2.modio.RevPiModIO._get_configrsc?5() +revpimodio2.modio.RevPiModIO._get_cpreplaceio?5() revpimodio2.modio.RevPiModIO._get_cycletime?5() revpimodio2.modio.RevPiModIO._get_ioerrors?5() revpimodio2.modio.RevPiModIO._get_length?5() @@ -191,6 +192,7 @@ revpimodio2.netio.NetFH.ioctl?4(request, arg=b'') revpimodio2.netio.NetFH.name?7 revpimodio2.netio.NetFH.read?4(length) revpimodio2.netio.NetFH.readpictory?4() +revpimodio2.netio.NetFH.readreplaceio?4() revpimodio2.netio.NetFH.run?4() revpimodio2.netio.NetFH.seek?4(position) revpimodio2.netio.NetFH.set_dirtybytes?4(position, dirtybytes) @@ -200,6 +202,7 @@ revpimodio2.netio.NetFH.timeout?7 revpimodio2.netio.NetFH.write?4(bytebuff) revpimodio2.netio.NetFH?1(address, timeout=500) revpimodio2.netio.RevPiNetIO._create_myfh?5() +revpimodio2.netio.RevPiNetIO._get_cpreplaceio?5() revpimodio2.netio.RevPiNetIO.disconnect?4() revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) @@ -211,5 +214,6 @@ revpimodio2.netio._sysdeldirty?8 revpimodio2.netio._sysexit?8 revpimodio2.netio._sysflush?8 revpimodio2.netio._syspictory?8 +revpimodio2.netio._sysreplaceio?8 revpimodio2.netio._syssync?8 revpimodio2.summary.Summary?1(summary) diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 589d297..81551bd 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -106,6 +106,7 @@ class RevPiModIO(object): # Nur Konfigurieren, wenn nicht vererbt if type(self) == RevPiModIO: self._configure(self.get_jconfigrsc()) + self._configure_replace_io(self._get_cpreplaceio()) def __del__(self): """Zerstoert alle Klassen um aufzuraeumen.""" @@ -128,7 +129,8 @@ class RevPiModIO(object): self.writeprocimg() def _configure(self, jconfigrsc): - """Verarbeitet die piCtory Konfigurationsdatei.""" + """Verarbeitet die piCtory Konfigurationsdatei. + @param jconfigrsc: Data to build IOs as of JSON""" # Filehandler konfigurieren, wenn er noch nicht existiert if self._myfh is None: @@ -252,11 +254,6 @@ class RevPiModIO(object): Warning ) - # Replace IO aus Datei verarbeiten - if self._replace_io_file is not None: - self._configure_replace_io() - self._lck_replace_io = True - # ImgWriter erstellen self._imgwriter = helpermodule.ProcimgWriter(self) @@ -291,88 +288,83 @@ class RevPiModIO(object): # Summary Klasse instantiieren self.summary = summarymodule.Summary(jconfigrsc["Summary"]) - def _configure_replace_io(self): + def _configure_replace_io(self, creplaceio): """Importiert ersetzte IOs in diese Instanz. Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) in eine Datei exportiert worden sind. Diese IOs werden in dieser Instanz wiederhergestellt. + @param ireplaceio: Data to replace ios as + """ - cp = ConfigParser() + need_replace_lock = False - try: - with open(self._replace_io_file, "r") as fh: - cp.read_file(fh) - except Exception as e: - raise RuntimeError( - "replace_io_file: could not read file '{0}' | {1}" - "".format(self._replace_io_file, e) - ) - - for io in cp: + for io in creplaceio: if io == "DEFAULT": continue # IO prüfen - parentio = cp[io].get("replace", "") + parentio = creplaceio[io].get("replace", "") # Funktionsaufruf vorbereiten dict_replace = { - "frm": cp[io].get("frm"), + "frm": creplaceio[io].get("frm"), } # Convert defaultvalue from config file - if "defaultvalue" in cp[io]: + if "defaultvalue" in creplaceio[io]: if dict_replace["frm"] == "?": try: dict_replace["defaultvalue"] = \ - cp[io].getboolean("defaultvalue") + creplaceio[io].getboolean("defaultvalue") except Exception: raise ValueError( "replace_io_file: could not convert '{0}' " "defaultvalue '{1}' to boolean" - "".format(io, cp[io].get("defaultvalue")) + "".format(io, creplaceio[io].get("defaultvalue")) ) else: try: dict_replace["defaultvalue"] = \ - cp[io].getint("defaultvalue") + creplaceio[io].getint("defaultvalue") except Exception: raise ValueError( "replace_io_file: could not convert '{0}' " "defaultvalue '{1}' to integer" - "".format(io, cp[io].get("bit")) + "".format(io, creplaceio[io].get("bit")) ) # Get bitaddress from config file - if "bit" in cp[io]: + if "bit" in creplaceio[io]: try: - dict_replace["bit"] = cp[io].getint("bit", 0) + dict_replace["bit"] = creplaceio[io].getint("bit", 0) except Exception: raise ValueError( "replace_io_file: could not convert '{0}' " "bit '{1}' to integer" - "".format(io, cp[io].get("bit")) + "".format(io, creplaceio[io].get("bit")) ) # Sonstige Werte laden, wenn vorhanden - if "bmk" in cp[io]: - dict_replace["bmk"] = cp[io].get("bmk") - if "byteorder" in cp[io]: - dict_replace["byteorder"] = cp[io].get("byteorder") + if "bmk" in creplaceio[io]: + dict_replace["bmk"] = creplaceio[io].get("bmk") + if "byteorder" in creplaceio[io]: + dict_replace["byteorder"] = creplaceio[io].get("byteorder") # IO ersetzen try: self.io[parentio].replace_io(name=io, **dict_replace) + need_replace_lock = True except Exception as e: raise RuntimeError( "replace_io_file: can not replace '{0}' with '{1}' " - "| RevPiModIO message: {2}".format( - parentio, io, e - ) + "| RevPiModIO message: {2}".format(parentio, io, e) ) + # Sperre für weiter .replace_io Aufrufe setzen + self._lck_replace_io = need_replace_lock + def _create_myfh(self): """Erstellt FileObject mit Pfad zum procimg. return FileObject""" @@ -384,6 +376,25 @@ class RevPiModIO(object): @return Pfad der verwendeten piCtory Konfiguration""" return self._configrsc + def _get_cpreplaceio(self): + """Laed die replace_io_file Konfiguration und verarbeitet sie. + @return der replace io daten""" + cp = ConfigParser() + + # TODO: verfeinern! + + if self._replace_io_file: + try: + with open(self._replace_io_file, "r") as fh: + cp.read_file(fh) + except Exception as e: + raise RuntimeError( + "replace_io_file: could not read/parse file '{0}' | {1}" + "".format(self._replace_io_file, e) + ) + + return cp + def _get_cycletime(self): """Gibt Aktualisierungsrate in ms der Prozessabbildsynchronisierung aus. @return Millisekunden""" @@ -1049,6 +1060,7 @@ class RevPiModIOSelected(RevPiModIO): ) self._configure(self.get_jconfigrsc()) + self._configure_replace_io(self._get_cpreplaceio()) if len(self.device) == 0: if type(self) == RevPiModIODriver: diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index d8c899f..78bfcaf 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -6,6 +6,7 @@ __license__ = "LGPLv3" import socket import warnings +from configparser import ConfigParser from json import loads as jloads from re import compile from threading import Thread, Event, Lock @@ -21,6 +22,8 @@ _sysexit = b'\x01EX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysdeldirty = b'\x01EY\x00\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x17' # piCtory Konfiguration laden _syspictory = b'\x01PI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' +# ReplaceIO Konfiguration laden +_sysreplaceio = b'\x01RP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' # Übertragene Bytes schreiben _sysflush = b'\x01SD\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x17' @@ -330,19 +333,48 @@ class NetFH(Thread): self._slavesock.send(_syspictory) byte_buff = bytearray() - while not self.__sockend: - data = self._slavesock.recv(1024) + zero_byte = 0 + while not self.__sockend and zero_byte < 100: + data = self._slavesock.recv(128) + if data == b'': + zero_byte += 1 byte_buff += data if data.find(b'\x04') >= 0: # NOTE: Nur suchen oder Ende prüfen? - return byte_buff[:-1] + return bytes(byte_buff[:-1]) self.__sockerr.set() raise IOError("readpictory error on network") self.__trigger = True + def readreplaceio(self): + """Ruft die replace_io Konfiguration ab. + @return replace_io_file""" + if self.__sockend: + raise ValueError("read of closed file") + + with self.__socklock: + self._slavesock.send(_sysreplaceio) + + byte_buff = bytearray() + zero_byte = 0 + while not self.__sockend and zero_byte < 100: + data = self._slavesock.recv(128) + if data == b'': + zero_byte += 1 + + byte_buff += data + if data.find(b'\x04') >= 0: + # NOTE: Nur suchen oder Ende prüfen? + return bytes(byte_buff[:-1]) + + self.__sockerr.set() + raise IOError("readreplaceio error on network") + + self.__trigger = True + def run(self): """Handler fuer Synchronisierung.""" while not self.__sockend: @@ -542,14 +574,14 @@ class RevPiNetIO(_RevPiModIO): # Vererben super().__init__( - autorefresh, - monitoring, - syncoutputs, - "{0}:{1}".format(*self._address), - None, - simulator, - debug, - replace_io_file + autorefresh=autorefresh, + monitoring=monitoring, + syncoutputs=syncoutputs, + procimg="{0}:{1}".format(*self._address), + configrsc=None, + simulator=simulator, + debug=debug, + replace_io_file=replace_io_file ) # Netzwerkfilehandler anlegen @@ -558,6 +590,7 @@ class RevPiNetIO(_RevPiModIO): # Nur Konfigurieren, wenn nicht vererbt if type(self) == RevPiNetIO: self._configure(self.get_jconfigrsc()) + self._configure_replace_io(self._get_cpreplaceio()) def _create_myfh(self): """Erstellt NetworkFileObject. @@ -565,6 +598,27 @@ class RevPiNetIO(_RevPiModIO): self._buffedwrite = True return NetFH(self._address) + def _get_cpreplaceio(self): + """Laed die replace_io Konfiguration ueber das Netzwerk. + @return der replace io daten""" + + # Normale Verwendung über Elternklasse erledigen + if self._replace_io_file != ":network:": + return super()._get_cpreplaceio() + + # Replace IO Daten über das Netzwerk beziehen + byte_buff = self._myfh.readreplaceio() + + cp = ConfigParser() + try: + cp.read_string(byte_buff.decode("utf-8")) + except Exception as e: + raise RuntimeError( + "replace_io_file: could not read/parse network data | {0}" + "".format(e) + ) + return cp + def disconnect(self): """Trennt Verbindungen und beendet autorefresh inkl. alle Threads.""" self.cleanup() @@ -693,6 +747,7 @@ class RevPiNetIOSelected(RevPiNetIO): ) self._configure(self.get_jconfigrsc()) + self._configure_replace_io(self._get_cpreplaceio()) if len(self.device) == 0: if type(self) == RevPiNetIODriver: From 2009ed9ce5cad5d18b0612843aa3ff46a373055e Mon Sep 17 00:00:00 2001 From: NaruX Date: Fri, 16 Aug 2019 22:32:27 +0200 Subject: [PATCH 02/10] =?UTF-8?q?Reconnect=20sicherer=20gestaltet=20Abfrag?= =?UTF-8?q?e=20von=20.reconnecting=20eingebaut=20Dirtybytes=20und=20Timeou?= =?UTF-8?q?t=20l=C3=B6sen=20keine=20Exception=20mehr=20aus=20sondern=20ein?= =?UTF-8?q?en=20Reconnect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.netio.html | 66 ++++++++++++++++- eric-revpimodio2.api | 4 ++ eric-revpimodio2.bas | 1 + revpimodio2/netio.py | 142 ++++++++++++++++++++++++++----------- 4 files changed, 168 insertions(+), 45 deletions(-) diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index 48b8224..f92c724 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -18,6 +18,9 @@ Global Attributes Classes + + + @@ -37,6 +40,37 @@ Functions
AclExceptionProbleme mit Berechtigungen.
NetFH Netzwerk File Handler fuer das Prozessabbild.
None


+ +

AclException

+

+Probleme mit Berechtigungen. +

+

+Derived from

+Exception +

+Class Attributes

+ + +
None
+

+Class Methods

+ + +
None
+

+Methods

+ + +
None
+

+Static Methods

+ + +
None
+ + +

NetFH

@@ -54,7 +88,7 @@ Thread

Class Attributes

- +
__slots__
closed
name
timeout
__slots__
closed
name
reconnecting
timeout

Class Methods

@@ -98,6 +132,9 @@ Methods get_name Verbindugnsnamen zurueckgeben. +get_reconnecting +Interner reconnect aktiv wegen Netzwerkfehlern. + get_timeout Gibt aktuellen Timeout zurueck. @@ -241,6 +278,17 @@ Verbindugnsnamen zurueckgeben.
IP:PORT
+ +

+NetFH.get_reconnecting

+get_reconnecting() +

+Interner reconnect aktiv wegen Netzwerkfehlern. +

+
Returns:
+
+True, wenn reconnect aktiv +

NetFH.get_timeout

@@ -385,7 +433,7 @@ _RevPiModIO

Class Attributes

- +
__slots__
__slots__
reconnecting

Class Methods

@@ -408,6 +456,9 @@ Methods get_jconfigrsc Laedt die piCotry Konfiguration und erstellt ein . +get_reconnecting +Interner reconnect aktiv wegen Netzwerkfehlern. + net_cleardefaultvalues Loescht Defaultwerte vom PLC Slave. @@ -476,6 +527,17 @@ Laedt die piCotry Konfiguration und erstellt ein .
der piCtory Konfiguration
+ +

+RevPiNetIO.get_reconnecting

+get_reconnecting() +

+Interner reconnect aktiv wegen Netzwerkfehlern. +

+
Returns:
+
+True, wenn reconnect aktiv +

RevPiNetIO.net_cleardefaultvalues

diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index 6572765..6316765 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -192,11 +192,13 @@ revpimodio2.netio.NetFH.closed?7 revpimodio2.netio.NetFH.flush?4() revpimodio2.netio.NetFH.get_closed?4() revpimodio2.netio.NetFH.get_name?4() +revpimodio2.netio.NetFH.get_reconnecting?4() revpimodio2.netio.NetFH.get_timeout?4() revpimodio2.netio.NetFH.ioctl?4(request, arg=b'') revpimodio2.netio.NetFH.name?7 revpimodio2.netio.NetFH.read?4(length) revpimodio2.netio.NetFH.readpictory?4() +revpimodio2.netio.NetFH.reconnecting?7 revpimodio2.netio.NetFH.run?4() revpimodio2.netio.NetFH.seek?4(position) revpimodio2.netio.NetFH.set_dirtybytes?4(position, dirtybytes) @@ -208,8 +210,10 @@ revpimodio2.netio.NetFH?1(address, timeout=500) revpimodio2.netio.RevPiNetIO._create_myfh?5() revpimodio2.netio.RevPiNetIO.disconnect?4() revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() +revpimodio2.netio.RevPiNetIO.get_reconnecting?4() revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) revpimodio2.netio.RevPiNetIO.net_setdefaultvalues?4(device=None) +revpimodio2.netio.RevPiNetIO.reconnecting?7 revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False) revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None, direct_output=False) revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None, direct_output=False) diff --git a/eric-revpimodio2.bas b/eric-revpimodio2.bas index 3eda7c3..dea047d 100644 --- a/eric-revpimodio2.bas +++ b/eric-revpimodio2.bas @@ -1,3 +1,4 @@ +AclException Exception Base Device Connect Core Core Base diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index c2da6a4..e0a9363 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -25,6 +25,13 @@ _syspictory = b'\x01PI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysflush = b'\x01SD\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x17' +class AclException(Exception): + + """Probleme mit Berechtigungen.""" + + pass + + class NetFH(Thread): """Netzwerk File Handler fuer das Prozessabbild. @@ -54,7 +61,7 @@ class NetFH(Thread): self.__flusherr = False self.__sockact = False self.__sockerr = Event() - self.__sockend = False + self.__sockend = Event() self.__socklock = Lock() self.__timeout = None self.__trigger = False @@ -90,10 +97,10 @@ class NetFH(Thread): if bytecode == b'\x18': # Alles beenden, wenn nicht erlaubt - self.__sockend = True + self.__sockend.set() self.__sockerr.set() self._slavesock.close() - raise RuntimeError( + raise AclException( "write access to the process image is not permitted - use " "monitoring=True or check aclplcslave.conf on RevPi and " "reload revpipyload!" @@ -151,11 +158,12 @@ class NetFH(Thread): @returns Empfangende Bytes """ - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") with self.__socklock: self._slavesock.sendall(send_bytes) + # FIXME: Schleife bis Daten empfangen sind einbauen recv = self._slavesock.recv(recv_count) self.__trigger = True return recv @@ -163,10 +171,13 @@ class NetFH(Thread): def clear_dirtybytes(self, position=None): """Entfernt die konfigurierten Dirtybytes vom RevPi Slave. @param position Startposition der Dirtybytes""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") - with self.__socklock: + error = False + try: + self.__socklock.acquire() + if position is None: # Alle Dirtybytes löschen self._slavesock.sendall(_sysdeldirty) @@ -184,40 +195,52 @@ class NetFH(Thread): # ACL prüfen und ggf Fehler werfen self.__check_acl(check) - self.__sockerr.set() raise IOError("clear dirtybytes error on network") + except AclException: + raise + except Exception: + error = True + finally: + self.__socklock.release() - # Daten bei Erfolg übernehmen + # Daten immer übernehmen if position is None: self.__dictdirty = {} elif position in self.__dictdirty: del self.__dictdirty[position] + if error: + # Fehler nach übernahme der Daten auslösen um diese zu setzen + self.__sockerr.set() + self.__trigger = True def close(self): """Verbindung trennen.""" - if self.__sockend: + if self.__sockend.is_set(): return - self.__sockend = True + self.__sockend.set() self.__sockerr.set() # Vom Socket sauber trennen if self._slavesock is not None: - with self.__socklock: - try: - if self.__sockend: - self._slavesock.send(_sysexit) - else: - self._slavesock.shutdown(socket.SHUT_RDWR) - except Exception: - pass + try: + self.__socklock.acquire() + self._slavesock.send(_sysexit) + + # NOTE: Wird das benötigt? + self._slavesock.shutdown(socket.SHUT_RDWR) + except Exception: + pass + finally: + self.__socklock.release() + self._slavesock.close() def flush(self): """Schreibpuffer senden.""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("flush of closed file") with self.__socklock: @@ -248,13 +271,18 @@ class NetFH(Thread): def get_closed(self): """Pruefen ob Verbindung geschlossen ist. @return True, wenn Verbindung geschlossen ist""" - return self.__sockend + return self.__sockend.is_set() def get_name(self): """Verbindugnsnamen zurueckgeben. @return IP:PORT""" return "{0}:{1}".format(*self._address) + def get_reconnecting(self): + """Interner reconnect aktiv wegen Netzwerkfehlern. + @return True, wenn reconnect aktiv""" + return self.__sockerr.is_set() + def get_timeout(self): """Gibt aktuellen Timeout zurueck. @return in Millisekunden""" @@ -264,7 +292,7 @@ class NetFH(Thread): """IOCTL Befehle ueber das Netzwerk senden. @param request Request as @param arg Argument as """ - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("read of closed file") if not (isinstance(arg, bytes) and len(arg) <= 1024): @@ -295,7 +323,7 @@ class NetFH(Thread): """Daten ueber das Netzwerk lesen. @param length Anzahl der Bytes @return Gelesene """ - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("read of closed file") with self.__socklock: @@ -307,8 +335,8 @@ class NetFH(Thread): ) bytesbuff = bytearray() - while not self.__sockend and len(bytesbuff) < length: - rbytes = self._slavesock.recv(1024) + while not self.__sockend.is_set() and len(bytesbuff) < length: + rbytes = self._slavesock.recv(256) if rbytes == b'': self.__sockerr.set() @@ -323,33 +351,36 @@ class NetFH(Thread): def readpictory(self): """Ruft die piCtory Konfiguration ab. @return piCtory Datei""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("read of closed file") with self.__socklock: self._slavesock.send(_syspictory) byte_buff = bytearray() - while not self.__sockend: - data = self._slavesock.recv(1024) + while not self.__sockend.is_set(): + data = self._slavesock.recv(256) byte_buff += data if data.find(b'\x04') >= 0: + self.__trigger = True + # NOTE: Nur suchen oder Ende prüfen? return byte_buff[:-1] self.__sockerr.set() raise IOError("readpictory error on network") - self.__trigger = True - def run(self): """Handler fuer Synchronisierung.""" - while not self.__sockend: + while not self.__sockend.is_set(): # Bei Fehlermeldung neu verbinden if self.__sockerr.is_set(): self._connect() + if self.__sockerr.is_set(): + # Verhindert bei Scheitern 100% CPU last + self.__sockend.wait(self.__waitsync) else: # Kein Fehler aufgetreten, sync durchführen wenn socket frei @@ -380,7 +411,7 @@ class NetFH(Thread): def seek(self, position): """Springt an angegebene Position. @param position An diese Position springen""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("seek of closed file") self.__position = int(position) @@ -388,10 +419,13 @@ class NetFH(Thread): """Konfiguriert Dirtybytes fuer Prozessabbild bei Verbindungsfehler. @param positon Startposition zum Schreiben @param dirtybytes die geschrieben werden sollen""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") - with self.__socklock: + error = False + try: + self.__socklock.acquire() + self._slavesock.sendall( b'\x01EY' + position.to_bytes(length=2, byteorder="little") + @@ -406,24 +440,35 @@ class NetFH(Thread): # ACL prüfen und ggf Fehler werfen self.__check_acl(check) - self.__sockerr.set() raise IOError("set dirtybytes error on network") + except AclException: + raise + except Exception: + error = True + finally: + self.__socklock.release() - # Daten erfolgreich übernehmen - self.__dictdirty[position] = dirtybytes + # Daten immer übernehmen + self.__dictdirty[position] = dirtybytes - self.__trigger = True + if error: + # Fehler nach übernahme der Daten auslösen um diese zu setzen + self.__sockerr.set() + + self.__trigger = True def set_timeout(self, value): """Setzt Timeoutwert fuer Verbindung. @param value Timeout in Millisekunden""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") # Timeoutwert verarbeiten (könnte Exception auslösen) self.__set_systimeout(value) - with self.__socklock: + try: + self.__socklock.acquire() + self._slavesock.send( b'\x01CF' + value.to_bytes(length=2, byteorder="little") + @@ -431,15 +476,18 @@ class NetFH(Thread): ) check = self._slavesock.recv(1) if check != b'\x1e': - self.__sockerr.set() raise IOError("set timeout error on network") + except Exception: + self.__sockerr.set() + finally: + self.__socklock.release() - self.__trigger = True + self.__trigger = True def tell(self): """Gibt aktuelle Position zurueck. @return int aktuelle Position""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") return self.__position @@ -447,7 +495,7 @@ class NetFH(Thread): """Daten ueber das Netzwerk schreiben. @param bytebuff Bytes zum schreiben @return Anzahl geschriebener bytes""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("write to closed file") if self.__flusherr: @@ -469,6 +517,7 @@ class NetFH(Thread): closed = property(get_closed) name = property(get_name) + reconnecting = property(get_reconnecting) timeout = property(get_timeout, set_timeout) @@ -579,6 +628,11 @@ class RevPiNetIO(_RevPiModIO): mynh.close() return jloads(byte_buff.decode("utf-8")) + def get_reconnecting(self): + """Interner reconnect aktiv wegen Netzwerkfehlern. + @return True, wenn reconnect aktiv""" + return self._myfh.reconnecting + def net_cleardefaultvalues(self, device=None): """Loescht Defaultwerte vom PLC Slave. @param device nur auf einzelnes Device anwenden, sonst auf Alle""" @@ -646,6 +700,8 @@ class RevPiNetIO(_RevPiModIO): dev._offset + dev._slc_out.start, dirtybytes ) + reconnecting = property(get_reconnecting) + class RevPiNetIOSelected(RevPiNetIO): From 383f9b88d05471957ee6653674ac690d31eeffa8 Mon Sep 17 00:00:00 2001 From: NaruX Date: Sat, 17 Aug 2019 18:55:05 +0200 Subject: [PATCH 03/10] Lock des replace_io bei Verwendung von replace_io_file entfernt --- revpimodio2/io.py | 7 ------- revpimodio2/modio.py | 9 +-------- revpimodio2/netio.py | 4 ++-- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 0ca6e7d..b5e766d 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -1000,13 +1000,6 @@ class IntIOReplaceable(IntIO): >Python3 struct """ - # Sperre prüfen - if self._parentdevice._modio._lck_replace_io: - raise RuntimeError( - "can not use this function while using an external " - "replace_io_file" - ) - # StructIO erzeugen io_new = StructIO( self, diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index ba7a835..0022721 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -37,7 +37,7 @@ class RevPiModIO(object): "_maxioerrors", "_myfh", "_myfh_lck", "_monitoring", "_procimg", \ "_simulator", "_syncoutputs", "_th_mainloop", "_waitexit", \ "core", "app", "device", "exitsignal", "io", "summary", "_debug", \ - "_lck_replace_io", "_replace_io_file", "_run_on_pi" + "_replace_io_file", "_run_on_pi" def __init__( self, autorefresh=False, monitoring=False, syncoutputs=True, @@ -85,7 +85,6 @@ class RevPiModIO(object): self._imgwriter = None self._ioerror = 0 self._length = 0 - self._lck_replace_io = False self._looprunning = False self._lst_devselect = [] self._lst_refresh = [] @@ -308,8 +307,6 @@ class RevPiModIO(object): @param ireplaceio: Data to replace ios as """ - need_replace_lock = False - for io in creplaceio: if io == "DEFAULT": continue @@ -365,16 +362,12 @@ class RevPiModIO(object): # IO ersetzen try: self.io[parentio].replace_io(name=io, **dict_replace) - need_replace_lock = True except Exception as e: raise RuntimeError( "replace_io_file: can not replace '{0}' with '{1}' " "| RevPiModIO message: {2}".format(parentio, io, e) ) - # Sperre für weiter .replace_io Aufrufe setzen - self._lck_replace_io = need_replace_lock - def _create_myfh(self): """Erstellt FileObject mit Pfad zum procimg. return FileObject""" diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index d3f565c..e8e4287 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -582,8 +582,8 @@ class RevPiNetIO(_RevPiModIO): configrsc=None, simulator=simulator, debug=debug, - replace_io_file=replace_io_file - direct_output + replace_io_file=replace_io_file, + direct_output=direct_output, ) # Netzwerkfilehandler anlegen From e7c8c5f9583fe7b0b01b63f43e5a5daa3de842e8 Mon Sep 17 00:00:00 2001 From: NaruX Date: Sat, 17 Aug 2019 20:36:43 +0200 Subject: [PATCH 04/10] export_replaced_ios mit Dateinamen als default versehen (PyLoad name) Merge-Fehler beseitigt --- doc/revpimodio2.modio.html | 2 +- eric-revpimodio2.api | 2 +- revpimodio2/modio.py | 2 +- revpimodio2/netio.py | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index 4fef3d2..8d26ae8 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -505,7 +505,7 @@ Entfernt auch alle Devices aus autorefresh

RevPiModIO.export_replaced_ios

-export_replaced_ios(filename) +export_replaced_ios(filename="replace_ios.conf")

Exportiert ersetzte IOs dieser Instanz.

diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index e9edf68..c47caab 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -166,7 +166,7 @@ revpimodio2.modio.RevPiModIO.cycleloop?4(func, cycletime=50) revpimodio2.modio.RevPiModIO.cycletime?7 revpimodio2.modio.RevPiModIO.debug?7 revpimodio2.modio.RevPiModIO.exit?4(full=True) -revpimodio2.modio.RevPiModIO.export_replaced_ios?4(filename) +revpimodio2.modio.RevPiModIO.export_replaced_ios?4(filename="replace_ios.conf") revpimodio2.modio.RevPiModIO.get_jconfigrsc?4() revpimodio2.modio.RevPiModIO.handlesignalend?4(cleanupfunc=None) revpimodio2.modio.RevPiModIO.ioerrors?7 diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 0022721..e253807 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -687,7 +687,7 @@ class RevPiModIO(object): if not self._monitoring: self.writeprocimg(dev) - def export_replaced_ios(self, filename): + def export_replaced_ios(self, filename="replace_ios.conf"): """Exportiert ersetzte IOs dieser Instanz. Exportiert alle ersetzten IOs, welche mit .replace_io(...) angelegt diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index dee129f..7877825 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -380,7 +380,7 @@ class NetFH(Thread): def readreplaceio(self): """Ruft die replace_io Konfiguration ab. @return replace_io_file""" - if self.__sockend: + if self.__sockend.is_set(): raise ValueError("read of closed file") with self.__socklock: @@ -388,21 +388,21 @@ class NetFH(Thread): byte_buff = bytearray() zero_byte = 0 - while not self.__sockend and zero_byte < 100: + while not self.__sockend.is_set() and zero_byte < 100: data = self._slavesock.recv(128) if data == b'': zero_byte += 1 byte_buff += data if data.find(b'\x04') >= 0: + self.__trigger = True + # NOTE: Nur suchen oder Ende prüfen? return bytes(byte_buff[:-1]) self.__sockerr.set() raise IOError("readreplaceio error on network") - self.__trigger = True - def run(self): """Handler fuer Synchronisierung.""" while not self.__sockend.is_set(): From 27da0c8e801d91c8fa8a401c4f8059bac46ed65e Mon Sep 17 00:00:00 2001 From: NaruX Date: Sun, 18 Aug 2019 09:46:10 +0200 Subject: [PATCH 05/10] =?UTF-8?q?F=C3=BCr=20Export=20default-Werte=20festg?= =?UTF-8?q?elegt,=20die=20nicht=20exportiert=20werden=20m=C3=BCssen=20Fehl?= =?UTF-8?q?erbehebung=20bei=20Import-Fehlermeldungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- revpimodio2/modio.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index e253807..401b4fc 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -317,8 +317,21 @@ class RevPiModIO(object): # Funktionsaufruf vorbereiten dict_replace = { "frm": creplaceio[io].get("frm"), + "byteorder": creplaceio[io].get("byteorder", "little"), + "bmk": creplaceio[io].get("bmk", ""), } + # Get bitaddress from config file + if "bit" in creplaceio[io]: + try: + dict_replace["bit"] = creplaceio[io].getint("bit") + except Exception: + raise ValueError( + "replace_io_file: could not convert '{0}' " + "bit '{1}' to integer" + "".format(io, creplaceio[io]["bit"]) + ) + # Convert defaultvalue from config file if "defaultvalue" in creplaceio[io]: if dict_replace["frm"] == "?": @@ -329,7 +342,7 @@ class RevPiModIO(object): raise ValueError( "replace_io_file: could not convert '{0}' " "defaultvalue '{1}' to boolean" - "".format(io, creplaceio[io].get("defaultvalue")) + "".format(io, creplaceio[io]["defaultvalue"]) ) else: try: @@ -339,26 +352,9 @@ class RevPiModIO(object): raise ValueError( "replace_io_file: could not convert '{0}' " "defaultvalue '{1}' to integer" - "".format(io, creplaceio[io].get("bit")) + "".format(io, creplaceio[io]["defaultvalue"]) ) - # Get bitaddress from config file - if "bit" in creplaceio[io]: - try: - dict_replace["bit"] = creplaceio[io].getint("bit", 0) - except Exception: - raise ValueError( - "replace_io_file: could not convert '{0}' " - "bit '{1}' to integer" - "".format(io, creplaceio[io].get("bit")) - ) - - # Sonstige Werte laden, wenn vorhanden - if "bmk" in creplaceio[io]: - dict_replace["bmk"] = creplaceio[io].get("bmk") - if "byteorder" in creplaceio[io]: - dict_replace["byteorder"] = creplaceio[io].get("byteorder") - # IO ersetzen try: self.io[parentio].replace_io(name=io, **dict_replace) @@ -710,8 +706,10 @@ class RevPiModIO(object): # Optional values if io._bitaddress >= 0: cp[io.name]["bit"] = str(io._bitaddress) - cp[io.name]["byteorder"] = io._byteorder - cp[io.name]["defaultvalue"] = str(io.defaultvalue) + if io._byteorder != "little": + cp[io.name]["byteorder"] = io._byteorder + if io.defaultvalue != 0: + cp[io.name]["defaultvalue"] = str(io.defaultvalue) if io.bmk != "": cp[io.name]["bmk"] = io.bmk From 21973eb7df68ef25149c4150f1b64b170e82e799 Mon Sep 17 00:00:00 2001 From: NaruX Date: Mon, 19 Aug 2019 16:35:27 +0200 Subject: [PATCH 06/10] =?UTF-8?q?NetFH=20braucht=20min.=20RevPiPyLoad=200.?= =?UTF-8?q?8.0=20da=20hashwerte=20=C3=BCbertragen=20werden=20NetFH=20wirft?= =?UTF-8?q?=20ConfigChanged=20bei=20ge=C3=A4nderten=20piCtory=20oder=20rep?= =?UTF-8?q?lace=5Fios=20Dateien?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.netio.html | 52 ++++++++++++++++++++++++++-- eric-revpimodio2.api | 3 ++ eric-revpimodio2.bas | 1 + revpimodio2/netio.py | 71 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index b0478a0..c8ed847 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -12,7 +12,7 @@ RevPiModIO Hauptklasse fuer Netzwerkzugriff.

Global Attributes

- +
__author__
__copyright__
__license__
_sysdeldirty
_sysexit
_sysflush
_syspictory
_sysreplaceio
_syssync
__author__
__copyright__
__license__
_sysdeldirty
_sysexit
_sysflush
_syspictory
_syspictoryh
_sysreplaceio
_sysreplaceioh
_syssync

Classes

@@ -21,6 +21,9 @@ Classes AclException Probleme mit Berechtigungen. +ConfigChanged +Aenderung der piCtory oder replace_ios Datei. + NetFH Netzwerk File Handler fuer das Prozessabbild. @@ -69,6 +72,37 @@ Static Methods None + +

+ +

ConfigChanged

+

+Aenderung der piCtory oder replace_ios Datei. +

+

+Derived from

+Exception +

+Class Attributes

+ + +
None
+

+Class Methods

+ + +
None
+

+Methods

+ + +
None
+

+Static Methods

+ + +
None
+

@@ -470,6 +504,9 @@ Methods disconnect Trennt Verbindungen und beendet autorefresh inkl. +exit +Beendet mainloop() und optional autorefresh. + get_jconfigrsc Laedt die piCotry Konfiguration und erstellt ein . @@ -544,7 +581,18 @@ RevPiNetIO.disconnect disconnect()

Trennt Verbindungen und beendet autorefresh inkl. alle Threads. -

+

+

+RevPiNetIO.exit

+exit(full=True) +

+Beendet mainloop() und optional autorefresh. +

+
See Also:
+
+#RevPiModIO.exit(...) +
+

RevPiNetIO.get_jconfigrsc

get_jconfigrsc() diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index c47caab..cff22a8 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -212,6 +212,7 @@ revpimodio2.netio.NetFH?1(address, timeout=500) revpimodio2.netio.RevPiNetIO._create_myfh?5() revpimodio2.netio.RevPiNetIO._get_cpreplaceio?5() revpimodio2.netio.RevPiNetIO.disconnect?4() +revpimodio2.netio.RevPiNetIO.exit?4(full=True) revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() revpimodio2.netio.RevPiNetIO.get_reconnecting?4() revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) @@ -224,6 +225,8 @@ revpimodio2.netio._sysdeldirty?8 revpimodio2.netio._sysexit?8 revpimodio2.netio._sysflush?8 revpimodio2.netio._syspictory?8 +revpimodio2.netio._syspictoryh?8 revpimodio2.netio._sysreplaceio?8 +revpimodio2.netio._sysreplaceioh?8 revpimodio2.netio._syssync?8 revpimodio2.summary.Summary?1(summary) diff --git a/eric-revpimodio2.bas b/eric-revpimodio2.bas index dea047d..19333b7 100644 --- a/eric-revpimodio2.bas +++ b/eric-revpimodio2.bas @@ -1,5 +1,6 @@ AclException Exception Base Device +ConfigChanged Exception Connect Core Core Base DeviceNotFoundError Exception diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index 7877825..cadb30c 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -22,8 +22,10 @@ _sysexit = b'\x01EX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysdeldirty = b'\x01EY\x00\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x17' # piCtory Konfiguration laden _syspictory = b'\x01PI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' +_syspictoryh = b'\x01PH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' # ReplaceIO Konfiguration laden _sysreplaceio = b'\x01RP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' +_sysreplaceioh = b'\x01RH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' # Übertragene Bytes schreiben _sysflush = b'\x01SD\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x17' @@ -35,6 +37,13 @@ class AclException(Exception): pass +class ConfigChanged(Exception): + + """Aenderung der piCtory oder replace_ios Datei.""" + + pass + + class NetFH(Thread): """Netzwerk File Handler fuer das Prozessabbild. @@ -59,9 +68,12 @@ class NetFH(Thread): self.daemon = True self.__by_buff = b'' + self.__config_changed = False self.__int_buff = 0 self.__dictdirty = {} self.__flusherr = False + self.__replace_ios_h = b'' + self.__pictory_h = b'' self.__sockact = False self.__sockerr = Event() self.__sockend = Event() @@ -134,6 +146,37 @@ class NetFH(Thread): so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: so.connect(self._address) + + # Hashwerte anfordern + so.sendall(_syspictoryh + _sysreplaceioh) + + # Hashwerte empfangen + byte_buff = bytearray() + zero_byte = 0 + while not self.__sockend.is_set() and zero_byte < 100 \ + and len(byte_buff) < 32: + data = so.recv(32) + if data == b'': + zero_byte += 1 + byte_buff += data + + # Änderung an piCtory prüfen + if self.__pictory_h and byte_buff[:16] != self.__pictory_h: + self.__config_changed = True + self.close() + raise ConfigChanged( + "configuration on revolution pi was changed") + else: + self.__pictory_h = byte_buff[:16] + + # Änderung an replace_ios prüfen + if self.__replace_ios_h and byte_buff[16:] != self.__replace_ios_h: + self.__config_changed = True + self.close() + raise ConfigChanged( + "configuration on revolution pi was changed") + else: + self.__replace_ios_h = byte_buff[16:] except Exception: so.close() else: @@ -174,6 +217,10 @@ class NetFH(Thread): def clear_dirtybytes(self, position=None): """Entfernt die konfigurierten Dirtybytes vom RevPi Slave. @param position Startposition der Dirtybytes""" + if self.__config_changed: + raise ConfigChanged( + "configuration on revolution pi was changed" + ) if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") @@ -243,6 +290,10 @@ class NetFH(Thread): def flush(self): """Schreibpuffer senden.""" + if self.__config_changed: + raise ConfigChanged( + "configuration on revolution pi was changed" + ) if self.__sockend.is_set(): raise ValueError("flush of closed file") @@ -295,6 +346,8 @@ class NetFH(Thread): """IOCTL Befehle ueber das Netzwerk senden. @param request Request as @param arg Argument as """ + if self.__config_changed: + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("read of closed file") @@ -326,6 +379,8 @@ class NetFH(Thread): """Daten ueber das Netzwerk lesen. @param length Anzahl der Bytes @return Gelesene """ + if self.__config_changed: + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("read of closed file") @@ -443,6 +498,8 @@ class NetFH(Thread): def seek(self, position): """Springt an angegebene Position. @param position An diese Position springen""" + if self.__config_changed: + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("seek of closed file") self.__position = int(position) @@ -451,6 +508,8 @@ class NetFH(Thread): """Konfiguriert Dirtybytes fuer Prozessabbild bei Verbindungsfehler. @param positon Startposition zum Schreiben @param dirtybytes die geschrieben werden sollen""" + if self.__config_changed: + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") @@ -519,6 +578,8 @@ class NetFH(Thread): def tell(self): """Gibt aktuelle Position zurueck. @return int aktuelle Position""" + if self.__config_changed: + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") return self.__position @@ -527,6 +588,8 @@ class NetFH(Thread): """Daten ueber das Netzwerk schreiben. @param bytebuff Bytes zum schreiben @return Anzahl geschriebener bytes""" + if self.__config_changed: + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("write to closed file") @@ -674,6 +737,14 @@ class RevPiNetIO(_RevPiModIO): """Trennt Verbindungen und beendet autorefresh inkl. alle Threads.""" self.cleanup() + def exit(self, full=True): + """Beendet mainloop() und optional autorefresh. + @see #RevPiModIO.exit(...)""" + try: + super().exit(full) + except ConfigChanged: + pass + def get_jconfigrsc(self): """Laedt die piCotry Konfiguration und erstellt ein . @return der piCtory Konfiguration""" From 2d17e6f1fa9c7a16d6cb7d535047b20e80edd306 Mon Sep 17 00:00:00 2001 From: NaruX Date: Mon, 19 Aug 2019 18:10:42 +0200 Subject: [PATCH 07/10] =?UTF-8?q?Disconnect=20bei=20ver=C3=A4nderter=20rep?= =?UTF-8?q?lace=5Fios=20Datei=20nur,=20wenn=20diese=20angefordert=20wrude?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.netio.html | 5 ++++- eric-revpimodio2.api | 2 +- revpimodio2/netio.py | 36 +++++++++++++++++++++++------------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index c8ed847..98bea51 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -211,13 +211,16 @@ Static Methods

NetFH (Constructor)

-NetFH(address, timeout=500) +NetFH(address, check_replace_ios, timeout=500)

Init NetFH-class.

address
IP Adresse, Port des RevPi als +
check_replace_ios
+
+Prueft auf veraenderungen der Datei
timeout
Timeout in Millisekunden der Verbindung diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index cff22a8..3d2c2e1 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -208,7 +208,7 @@ revpimodio2.netio.NetFH.set_timeout?4(value) revpimodio2.netio.NetFH.tell?4() revpimodio2.netio.NetFH.timeout?7 revpimodio2.netio.NetFH.write?4(bytebuff) -revpimodio2.netio.NetFH?1(address, timeout=500) +revpimodio2.netio.NetFH?1(address, check_replace_ios, timeout=500) revpimodio2.netio.RevPiNetIO._create_myfh?5() revpimodio2.netio.RevPiNetIO._get_cpreplaceio?5() revpimodio2.netio.RevPiNetIO.disconnect?4() diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index cadb30c..db500ce 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -54,20 +54,25 @@ class NetFH(Thread): """ - __slots__ = "__by_buff", "__int_buff", "__dictdirty", "__flusherr", \ - "__position", "__sockact", "__sockerr", "__sockend", "__socklock", \ - "__timeout", "__trigger", "__waitsync", \ - "_address", "_slavesock", \ - "daemon" + __slots__ = "__by_buff", "__check_replace_ios", "__config_changed", \ + "__int_buff", "__dictdirty", "__flusherr", "__replace_ios_h", \ + "__pictory_h", "__position", "__sockact", "__sockerr", "__sockend", \ + "__socklock", "__timeout", "__trigger", "__waitsync", "_address", \ + "_slavesock", "daemon" - def __init__(self, address, timeout=500): + def __init__(self, address, check_replace_ios, timeout=500): """Init NetFH-class. + @param address IP Adresse, Port des RevPi als - @param timeout Timeout in Millisekunden der Verbindung""" + @param check_replace_ios Prueft auf veraenderungen der Datei + @param timeout Timeout in Millisekunden der Verbindung + + """ super().__init__() self.daemon = True self.__by_buff = b'' + self.__check_replace_ios = check_replace_ios self.__config_changed = False self.__int_buff = 0 self.__dictdirty = {} @@ -148,14 +153,18 @@ class NetFH(Thread): so.connect(self._address) # Hashwerte anfordern - so.sendall(_syspictoryh + _sysreplaceioh) + recv_len = 16 + so.sendall(_syspictoryh) + if self.__check_replace_ios: + so.sendall(_sysreplaceioh) + recv_len += 16 # Hashwerte empfangen byte_buff = bytearray() zero_byte = 0 while not self.__sockend.is_set() and zero_byte < 100 \ - and len(byte_buff) < 32: - data = so.recv(32) + and len(byte_buff) < recv_len: + data = so.recv(recv_len) if data == b'': zero_byte += 1 byte_buff += data @@ -170,7 +179,8 @@ class NetFH(Thread): self.__pictory_h = byte_buff[:16] # Änderung an replace_ios prüfen - if self.__replace_ios_h and byte_buff[16:] != self.__replace_ios_h: + if self.__check_replace_ios and self.__replace_ios_h \ + and byte_buff[16:] != self.__replace_ios_h: self.__config_changed = True self.close() raise ConfigChanged( @@ -710,7 +720,7 @@ class RevPiNetIO(_RevPiModIO): """Erstellt NetworkFileObject. return FileObject""" self._buffedwrite = True - return NetFH(self._address) + return NetFH(self._address, self._replace_io_file == ":network:") def _get_cpreplaceio(self): """Laed die replace_io Konfiguration ueber das Netzwerk. @@ -748,7 +758,7 @@ class RevPiNetIO(_RevPiModIO): def get_jconfigrsc(self): """Laedt die piCotry Konfiguration und erstellt ein . @return der piCtory Konfiguration""" - mynh = NetFH(self._address) + mynh = NetFH(self._address, False) byte_buff = mynh.readpictory() mynh.close() return jloads(byte_buff.decode("utf-8")) From d61d76b6f3dc5e2827d13bcabfc474418aa836ea Mon Sep 17 00:00:00 2001 From: NaruX Date: Tue, 20 Aug 2019 09:36:19 +0200 Subject: [PATCH 08/10] =?UTF-8?q?Bugfix:=20prefire=20mit=20as=5Fthread=20h?= =?UTF-8?q?atte=20Fehler=20bei=20=C3=9Cbergabe=20in=20Queue=20Netzwerkklas?= =?UTF-8?q?sen=20zeigen=20=C3=BCber=20.config=5Fchanged=20an,=20dass=20Neu?= =?UTF-8?q?instanzierung=20n=C3=B6tig=20ist=20=5Fconnect=20von=20NetFH=20l?= =?UTF-8?q?=C3=B6st=20ConfigChanged-Exception=20aus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.netio.html | 38 ++++++++++++++++++++++++++++++++++++-- eric-revpimodio2.api | 4 ++++ revpimodio2/helper.py | 14 +++++++------- revpimodio2/modio.py | 2 +- revpimodio2/netio.py | 31 +++++++++++++++++++++++++------ 5 files changed, 73 insertions(+), 16 deletions(-) diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index 98bea51..3f674ae 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -122,7 +122,7 @@ Thread

Class Attributes

- +
__slots__
closed
name
reconnecting
timeout
__slots__
closed
config_changed
name
reconnecting
timeout

Class Methods

@@ -163,6 +163,9 @@ Methods get_closed Pruefen ob Verbindung geschlossen ist. +get_config_changed +Pruefen ob RevPi Konfiguration geaendert wurde. + get_name Verbindugnsnamen zurueckgeben. @@ -307,6 +310,17 @@ Pruefen ob Verbindung geschlossen ist.
True, wenn Verbindung geschlossen ist
+
+

+NetFH.get_config_changed

+get_config_changed() +

+Pruefen ob RevPi Konfiguration geaendert wurde. +

+
Returns:
+
+True, wenn RevPi Konfiguration geaendert ist +

NetFH.get_name

@@ -484,7 +498,7 @@ _RevPiModIO

Class Attributes

- +
__slots__
reconnecting
__slots__
config_changed
reconnecting

Class Methods

@@ -510,6 +524,9 @@ Methods exit Beendet mainloop() und optional autorefresh. +get_config_changed +Pruefen ob RevPi Konfiguration geaendert wurde. + get_jconfigrsc Laedt die piCotry Konfiguration und erstellt ein . @@ -595,6 +612,20 @@ Beendet mainloop() und optional autorefresh.
#RevPiModIO.exit(...)
+ +

+RevPiNetIO.get_config_changed

+get_config_changed() +

+Pruefen ob RevPi Konfiguration geaendert wurde. +

+ In diesem Fall ist die Verbindung geschlossen und RevPiNetIO muss + neu instanziert werden. +

+
Returns:
+
+True, wenn RevPi Konfiguration geaendert ist +

RevPiNetIO.get_jconfigrsc

@@ -612,6 +643,9 @@ RevPiNetIO.get_reconnecting get_reconnecting()

Interner reconnect aktiv wegen Netzwerkfehlern. +

+ Das Modul versucht intern die Verbindung neu herzustellen. Es ist + kein weiteres Zutun noetig.

Returns:
diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index 3d2c2e1..bc83c7f 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -190,8 +190,10 @@ revpimodio2.netio.NetFH._direct_send?5(send_bytes, recv_count) revpimodio2.netio.NetFH.clear_dirtybytes?4(position=None) revpimodio2.netio.NetFH.close?4() revpimodio2.netio.NetFH.closed?7 +revpimodio2.netio.NetFH.config_changed?7 revpimodio2.netio.NetFH.flush?4() revpimodio2.netio.NetFH.get_closed?4() +revpimodio2.netio.NetFH.get_config_changed?4() revpimodio2.netio.NetFH.get_name?4() revpimodio2.netio.NetFH.get_reconnecting?4() revpimodio2.netio.NetFH.get_timeout?4() @@ -211,8 +213,10 @@ revpimodio2.netio.NetFH.write?4(bytebuff) revpimodio2.netio.NetFH?1(address, check_replace_ios, timeout=500) revpimodio2.netio.RevPiNetIO._create_myfh?5() revpimodio2.netio.RevPiNetIO._get_cpreplaceio?5() +revpimodio2.netio.RevPiNetIO.config_changed?7 revpimodio2.netio.RevPiNetIO.disconnect?4() revpimodio2.netio.RevPiNetIO.exit?4(full=True) +revpimodio2.netio.RevPiNetIO.get_config_changed?4() revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() revpimodio2.netio.RevPiNetIO.get_reconnecting?4() revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py index 0197694..abb8bcc 100644 --- a/revpimodio2/helper.py +++ b/revpimodio2/helper.py @@ -289,7 +289,7 @@ class ProcimgWriter(Thread): """ - __slots__ = "__dict_delay", "__eventth", "__eventqth", "__eventwork", \ + __slots__ = "__dict_delay", "__eventth", "_eventqth", "__eventwork", \ "_adjwait", "_eventq", "_ioerror", "_maxioerrors", "_modio", \ "_refresh", "_work", "daemon", "lck_refresh", "newdata" @@ -299,7 +299,7 @@ class ProcimgWriter(Thread): super().__init__() self.__dict_delay = {} self.__eventth = Thread(target=self.__exec_th) - self.__eventqth = queue.Queue() + self._eventqth = queue.Queue() self.__eventwork = False self._adjwait = 0 self._eventq = queue.Queue() @@ -340,7 +340,7 @@ class ProcimgWriter(Thread): or regfunc.edge == FALLING and not boolor: if regfunc.delay == 0: if regfunc.as_thread: - self.__eventqth.put( + self._eventqth.put( (regfunc, io_event._name, io_event.value), False ) @@ -363,7 +363,7 @@ class ProcimgWriter(Thread): for regfunc in dev._dict_events[io_event]: if regfunc.delay == 0: if regfunc.as_thread: - self.__eventqth.put( + self._eventqth.put( (regfunc, io_event._name, io_event.value), False ) @@ -390,7 +390,7 @@ class ProcimgWriter(Thread): """Laeuft als Thread, der Events als Thread startet.""" while self.__eventwork: try: - tup_fireth = self.__eventqth.get(timeout=1) + tup_fireth = self._eventqth.get(timeout=1) th = EventCallback( tup_fireth[0].func, tup_fireth[1], tup_fireth[2] ) @@ -415,7 +415,7 @@ class ProcimgWriter(Thread): self.__eventwork = value if not value: # Nur leeren beim deaktivieren - self.__eventqth = queue.Queue() + self._eventqth = queue.Queue() self._eventq = queue.Queue() self.__dict_delay = {} @@ -533,7 +533,7 @@ class ProcimgWriter(Thread): if self.__dict_delay[tup_fire] <= 0: # Verzögertes Event übernehmen und löschen if tup_fire[0].as_thread: - self.__eventqth.put(tup_fire, False) + self._eventqth.put(tup_fire, False) else: self._eventq.put(tup_fire, False) del self.__dict_delay[tup_fire] diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 401b4fc..f21a5e3 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -850,7 +850,7 @@ class RevPiModIO(object): or regfunc.edge == RISING and io.value \ or regfunc.edge == FALLING and not io.value: if regfunc.as_thread: - self._imgwriter.__eventqth.put( + self._imgwriter._eventqth.put( (regfunc, io._name, io.value), False ) else: diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index db500ce..1c9eeb7 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -187,6 +187,9 @@ class NetFH(Thread): "configuration on revolution pi was changed") else: self.__replace_ios_h = byte_buff[16:] + except ConfigChanged: + so.close() + raise except Exception: so.close() else: @@ -228,9 +231,7 @@ class NetFH(Thread): """Entfernt die konfigurierten Dirtybytes vom RevPi Slave. @param position Startposition der Dirtybytes""" if self.__config_changed: - raise ConfigChanged( - "configuration on revolution pi was changed" - ) + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("I/O operation on closed file") @@ -301,9 +302,7 @@ class NetFH(Thread): def flush(self): """Schreibpuffer senden.""" if self.__config_changed: - raise ConfigChanged( - "configuration on revolution pi was changed" - ) + raise ConfigChanged("configuration on revolution pi was changed") if self.__sockend.is_set(): raise ValueError("flush of closed file") @@ -337,6 +336,11 @@ class NetFH(Thread): @return True, wenn Verbindung geschlossen ist""" return self.__sockend.is_set() + def get_config_changed(self): + """Pruefen ob RevPi Konfiguration geaendert wurde. + @return True, wenn RevPi Konfiguration geaendert ist""" + return self.__config_changed + def get_name(self): """Verbindugnsnamen zurueckgeben. @return IP:PORT""" @@ -621,6 +625,7 @@ class NetFH(Thread): return len(bytebuff) closed = property(get_closed) + config_changed = property(get_config_changed) name = property(get_name) reconnecting = property(get_reconnecting) timeout = property(get_timeout, set_timeout) @@ -755,6 +760,15 @@ class RevPiNetIO(_RevPiModIO): except ConfigChanged: pass + def get_config_changed(self): + """Pruefen ob RevPi Konfiguration geaendert wurde. + + In diesem Fall ist die Verbindung geschlossen und RevPiNetIO muss + neu instanziert werden. + + @return True, wenn RevPi Konfiguration geaendert ist""" + return self._myfh.config_changed + def get_jconfigrsc(self): """Laedt die piCotry Konfiguration und erstellt ein . @return der piCtory Konfiguration""" @@ -765,6 +779,10 @@ class RevPiNetIO(_RevPiModIO): def get_reconnecting(self): """Interner reconnect aktiv wegen Netzwerkfehlern. + + Das Modul versucht intern die Verbindung neu herzustellen. Es ist + kein weiteres Zutun noetig. + @return True, wenn reconnect aktiv""" return self._myfh.reconnecting @@ -835,6 +853,7 @@ class RevPiNetIO(_RevPiModIO): dev._offset + dev._slc_out.start, dirtybytes ) + config_changed = property(get_config_changed) reconnecting = property(get_reconnecting) From 35d790ec013304767ae8782771086f36b6c38fd2 Mon Sep 17 00:00:00 2001 From: NaruX Date: Tue, 20 Aug 2019 14:39:58 +0200 Subject: [PATCH 09/10] =?UTF-8?q?Wenn=20RevPiPyLoad=20falsche=20replace=5F?= =?UTF-8?q?ios=20Datei=20hat,=20wird=20Fehler=20geworfen=20IO-Pr=C3=BCfung?= =?UTF-8?q?=20bei=20replace=20wird=20nicht=20f=C3=BCr=20Selected/Driver=20?= =?UTF-8?q?durchgef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.netio.html | 2 +- eric-revpimodio2.api | 1 + revpimodio2/modio.py | 10 ++++++---- revpimodio2/netio.py | 7 +++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index 3f674ae..4dd24da 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -12,7 +12,7 @@ RevPiModIO Hauptklasse fuer Netzwerkzugriff.

Global Attributes

- +
__author__
__copyright__
__license__
_sysdeldirty
_sysexit
_sysflush
_syspictory
_syspictoryh
_sysreplaceio
_sysreplaceioh
_syssync
HASH_FAIL
__author__
__copyright__
__license__
_sysdeldirty
_sysexit
_sysflush
_syspictory
_syspictoryh
_sysreplaceio
_sysreplaceioh
_syssync

Classes

diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index bc83c7f..28da249 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -185,6 +185,7 @@ revpimodio2.modio.RevPiModIO.writeprocimg?4(device=None) revpimodio2.modio.RevPiModIO?1(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False) revpimodio2.modio.RevPiModIODriver?1(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None, direct_output=False) revpimodio2.modio.RevPiModIOSelected?1(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None, direct_output=False) +revpimodio2.netio.HASH_FAIL?7 revpimodio2.netio.NetFH._connect?5() revpimodio2.netio.NetFH._direct_send?5(send_bytes, recv_count) revpimodio2.netio.NetFH.clear_dirtybytes?4(position=None) diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index f21a5e3..a87a661 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -359,10 +359,12 @@ class RevPiModIO(object): try: self.io[parentio].replace_io(name=io, **dict_replace) except Exception as e: - raise RuntimeError( - "replace_io_file: can not replace '{0}' with '{1}' " - "| RevPiModIO message: {2}".format(parentio, io, e) - ) + # NOTE: Bei Selected/Driver kann nicht geprüft werden + if len(self._lst_devselect) == 0: + raise RuntimeError( + "replace_io_file: can not replace '{0}' with '{1}' " + "| RevPiModIO message: {2}".format(parentio, io, e) + ) def _create_myfh(self): """Erstellt FileObject mit Pfad zum procimg. diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index 1c9eeb7..0040168 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -28,6 +28,8 @@ _sysreplaceio = b'\x01RP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' _sysreplaceioh = b'\x01RH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17' # Übertragene Bytes schreiben _sysflush = b'\x01SD\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x17' +# Hashvalues +HASH_FAIL = b'\xff' * 16 class AclException(Exception): @@ -452,6 +454,11 @@ class NetFH(Thread): if self.__sockend.is_set(): raise ValueError("read of closed file") + if self.__replace_ios_h == HASH_FAIL: + raise RuntimeError( + "replace_io_file: could not read/parse over network" + ) + with self.__socklock: self._slavesock.send(_sysreplaceio) From b2ada1a58d9727255a187da24677edcf740290e9 Mon Sep 17 00:00:00 2001 From: NaruX Date: Mon, 26 Aug 2019 13:10:00 +0200 Subject: [PATCH 10/10] piCtory Datei fehlerhaft bei HASH_FAIL --- doc/revpimodio2.netio.html | 2 +- revpimodio2.e4p | 4 ++-- revpimodio2/__init__.py | 2 +- revpimodio2/netio.py | 7 ++++++- setup.py | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index 4dd24da..33a96e6 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -223,7 +223,7 @@ Init NetFH-class. IP Adresse, Port des RevPi als
check_replace_ios
-Prueft auf veraenderungen der Datei +Prueft auf Veraenderungen der Datei
timeout
Timeout in Millisekunden der Verbindung diff --git a/revpimodio2.e4p b/revpimodio2.e4p index ff6c635..1c11c87 100644 --- a/revpimodio2.e4p +++ b/revpimodio2.e4p @@ -1,7 +1,7 @@ - + en_US @@ -9,7 +9,7 @@ Python3 Console Das Modul stellt alle Devices und IOs aus der piCtory Konfiguration in Python3 zur Verfügung. Es ermöglicht den direkten Zugriff auf die Werte über deren vergebenen Namen. Lese- und Schreibaktionen mit dem Prozessabbild werden von dem Modul selbst verwaltet, ohne dass sich der Programmierer um Offsets und Adressen kümmern muss. Für die Gatewaymodule wie ModbusTCP oder Profinet sind eigene 'Inputs' und 'Outputs' über einen bestimmten Adressbereich definierbar. Auf diese IOs kann mit Python3 über den Namen direkt auf die Werte zugegriffen werden. - 2.4.0 + 2.4.1 Sven Sager akira@narux.de diff --git a/revpimodio2/__init__.py b/revpimodio2/__init__.py index 95f8679..c1d6aa2 100644 --- a/revpimodio2/__init__.py +++ b/revpimodio2/__init__.py @@ -22,7 +22,7 @@ __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" __name__ = "revpimodio2" -__version__ = "2.4.0" +__version__ = "2.4.1" # Global package values OFF = 0 diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index 0040168..d307d3d 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -66,7 +66,7 @@ class NetFH(Thread): """Init NetFH-class. @param address IP Adresse, Port des RevPi als - @param check_replace_ios Prueft auf veraenderungen der Datei + @param check_replace_ios Prueft auf Veraenderungen der Datei @param timeout Timeout in Millisekunden der Verbindung """ @@ -428,6 +428,11 @@ class NetFH(Thread): if self.__sockend.is_set(): raise ValueError("read of closed file") + if self.__pictory_h == HASH_FAIL: + raise RuntimeError( + "could not read/parse piCtory configuration over network" + ) + with self.__socklock: self._slavesock.send(_syspictory) diff --git a/setup.py b/setup.py index d17ee21..43f9371 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( license="LGPLv3", name="revpimodio2", - version="2.4.0", + version="2.4.1", packages=["revpimodio2"], python_requires="~=3.2",