diff --git a/doc/index.html b/doc/index.html
index cd2c3d2..51a6d4c 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -16,6 +16,9 @@ Modules
logsystem
Modul fuer die Verwaltung der Logdateien.
+picontrolserver
+Modul fuer die Verwaltung der PLC-Slave Funktionen.
+
plcsystem
Modul fuer die Verwaltung der PLC Funktionen.
diff --git a/doc/picontrolserver.html b/doc/picontrolserver.html
new file mode 100644
index 0000000..d72e85c
--- /dev/null
+++ b/doc/picontrolserver.html
@@ -0,0 +1,190 @@
+
+
+picontrolserver
+
+
+
+
+picontrolserver
+
+Modul fuer die Verwaltung der PLC-Slave Funktionen.
+
+
+Global Attributes
+
+
+Classes
+
+
+Functions
+
+
+
+RevPiSlave
+
+RevPi PLC-Server.
+
+ Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert
+ neue Verbindungen. Dieser werden dann als RevPiSlaveDev abgebildet.
+
+ Ueber die angegebenen ACLs koennen Zugriffsbeschraenkungen vergeben werden.
+
+
+
+
+Derived from
+Thread
+
+Class Attributes
+
+
+Class Methods
+
+
+Methods
+
+
+RevPiSlave
+Instantiiert RevPiSlave-Klasse.
+
+newlogfile
+Konfiguriert die FileHandler auf neue Logdatei.
+
+run
+Startet Serverkomponente fuer die Annahme neuer Verbindungen.
+
+stop
+Beendet Slaveausfuehrung.
+
+
+
+Static Methods
+
+
+
+RevPiSlave (Constructor)
+RevPiSlave (acl, port=55234 )
+
+Instantiiert RevPiSlave-Klasse.
+
+acl
+
+Stringliste mit Leerstellen getrennt
+ port
+
+Listen Port fuer plc Slaveserver
+
+
+
+RevPiSlave.newlogfile
+newlogfile ( )
+
+Konfiguriert die FileHandler auf neue Logdatei.
+
+
+RevPiSlave.run
+run ( )
+
+Startet Serverkomponente fuer die Annahme neuer Verbindungen.
+
+
+RevPiSlave.stop
+stop ( )
+
+Beendet Slaveausfuehrung.
+
+
+
+
+RevPiSlaveDev
+
+Klasse um eine RevPiModIO Verbindung zu verwalten.
+
+ Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
+ Netzwerk mit dem Prozessabbild auszutauschen.
+
+
+
+
+Derived from
+Thread
+
+Class Attributes
+
+
+Class Methods
+
+
+Methods
+
+
+RevPiSlaveDev
+Init RevPiSlaveDev-Class.
+
+run
+Verarbeitet Anfragen von Remoteteilnehmer.
+
+stop
+Beendet Verbindungsthread.
+
+
+
+Static Methods
+
+
+
+RevPiSlaveDev (Constructor)
+RevPiSlaveDev (devcon, acl )
+
+Init RevPiSlaveDev-Class.
+
+devcon
+
+Tuple der Verbindung
+ deadtime
+
+Timeout der Vararbeitung
+ acl
+
+Berechtigungslevel
+
+
+
+RevPiSlaveDev.run
+run ( )
+
+Verarbeitet Anfragen von Remoteteilnehmer.
+
+
+RevPiSlaveDev.stop
+stop ( )
+
+Beendet Verbindungsthread.
+
+
+
+
\ No newline at end of file
diff --git a/doc/revpipyload.html b/doc/revpipyload.html
index 2bcdc96..23d8a8d 100644
--- a/doc/revpipyload.html
+++ b/doc/revpipyload.html
@@ -32,29 +32,14 @@ begrenzt werden!
Global Attributes
-configrsc picontrolreset procimg pyloadverion rapcatalog re_ipacl
+pyloadversion re_ipacl
Classes
-LogReader
-Ermoeglicht den Zugriff auf die Logdateien.
-
-PipeLogwriter
-File PIPE fuer das Schreiben des APP Log.
-
-RevPiPlc
-Verwaltet das PLC Python Programm.
-
RevPiPyLoad
Hauptklasse, die alle Funktionen zur Verfuegung stellt.
-
-RevPiSlave
-RevPi PLC-Server.
-
-RevPiSlaveDev
-Klasse um eine RevPiModIO Verbindung zu verwalten.
@@ -64,344 +49,11 @@ Functions
_ipmatch
Prueft IP gegen ACL List und gibt ACL aus.
-_zeroprocimg
-Setzt Prozessabbild auf NULL.
-
refullmatch
re.fullmatch wegen alter python version aus wheezy nachgebaut.
-
-LogReader
-
-Ermoeglicht den Zugriff auf die Logdateien.
-
- Beinhaltet Funktionen fuer den Abruf der gesamten Logdatei fuer das
- RevPiPyLoad-System und die Logdatei der PLC-Anwendung.
-
-
-
-
-Derived from
-None
-
-Class Attributes
-
-
-Class Methods
-
-
-Methods
-
-
-LogReader
-Instantiiert LogReader-Klasse.
-
-closeall
-Fuehrt close auf File Handler durch.
-
-load_applog
-Uebertraegt Logdaten des PLC Programms Binaer.
-
-load_plclog
-Uebertraegt Logdaten des Loaders Binaer.
-
-
-
-Static Methods
-
-
-
-LogReader (Constructor)
-LogReader ( )
-
-Instantiiert LogReader-Klasse.
-
-
-LogReader.closeall
-closeall ( )
-
-Fuehrt close auf File Handler durch.
-
-
-LogReader.load_applog
-load_applog (start, count )
-
-Uebertraegt Logdaten des PLC Programms Binaer.
-
-start
-
-Startbyte
- count
-
-Max. Byteanzahl zum uebertragen
-
-
-Returns:
-
-Binary() der Logdatei
-
-
-
-LogReader.load_plclog
-load_plclog (start, count )
-
-Uebertraegt Logdaten des Loaders Binaer.
-
-start
-
-Startbyte
- count
-
-Max. Byteanzahl zum uebertragen
-
-
-Returns:
-
-Binary() der Logdatei
-
-
-
-
-
-PipeLogwriter
-
-File PIPE fuer das Schreiben des APP Log.
-
- Spezieller LogFile-Handler fuer die Ausgabe des subprocess fuer das Python
- PLC Programm. Die Ausgabe kann nicht auf einen neuen FileHandler
- umgeschrieben werden. Dadurch waere es nicht moeglich nach einem logrotate
- die neue Datei zu verwenden. Ueber die PIPE wird dies umgangen.
-
-
-
-
-Derived from
-Thread
-
-Class Attributes
-
-
-Class Methods
-
-
-Methods
-
-
-PipeLogwriter
-Instantiiert PipeLogwriter-Klasse.
-
-__del__
-Close file handler.
-
-_configurefh
-Konfiguriert den FileHandler fuer Ausgaben der PLCAPP.
-
-logline
-Schreibt eine Zeile in die Logdatei oder stdout.
-
-newlogfile
-Konfiguriert den FileHandler auf eine neue Logdatei.
-
-run
-Prueft auf neue Logzeilen und schreibt diese.
-
-stop
-Beendetden Thread und die FileHandler werden geschlossen.
-
-
-
-Static Methods
-
-
-
-PipeLogwriter (Constructor)
-PipeLogwriter (logfilename )
-
-Instantiiert PipeLogwriter-Klasse.
-
-logfilename
-
-Dateiname fuer Logdatei
-
-
-
-PipeLogwriter.__del__
-__del__ ( )
-
-Close file handler.
-
-
-PipeLogwriter._configurefh
-_configurefh ( )
-
-Konfiguriert den FileHandler fuer Ausgaben der PLCAPP.
-
-Returns:
-
-FileHandler-Objekt
-
-
-
-PipeLogwriter.logline
-logline (message )
-
-Schreibt eine Zeile in die Logdatei oder stdout.
-
-message
-
-Logzeile zum Schreiben
-
-
-
-PipeLogwriter.newlogfile
-newlogfile ( )
-
-Konfiguriert den FileHandler auf eine neue Logdatei.
-
-
-PipeLogwriter.run
-run ( )
-
-Prueft auf neue Logzeilen und schreibt diese.
-
-
-PipeLogwriter.stop
-stop ( )
-
-Beendetden Thread und die FileHandler werden geschlossen.
-
-
-
-
-RevPiPlc
-
-Verwaltet das PLC Python Programm.
-
- Dieser Thread startet das PLC Python Programm und ueberwacht es. Sollte es
- abstuerzen kann es automatisch neu gestartet werden. Die Ausgaben des
- Programms werden in eine Logdatei umgeleitet, damit der Entwickler sein
- Programm analysieren und debuggen kann.
-
-
-
-
-Derived from
-Thread
-
-Class Attributes
-
-
-Class Methods
-
-
-Methods
-
-
-RevPiPlc
-Instantiiert RevPiPlc-Klasse.
-
-_configureplw
-Konfiguriert den PipeLogwriter fuer Ausgaben der PLCAPP.
-
-_setuppopen
-Setzt UID und GID fuer das PLC Programm.
-
-_spopen
-Startet das PLC Programm.
-
-newlogfile
-Konfiguriert die FileHandler auf neue Logdatei.
-
-run
-Fuehrt PLC-Programm aus und ueberwacht es.
-
-stop
-Beendet PLC-Programm.
-
-
-
-Static Methods
-
-
-
-RevPiPlc (Constructor)
-RevPiPlc (program, arguments, pversion )
-
-Instantiiert RevPiPlc-Klasse.
-
-
-RevPiPlc._configureplw
-_configureplw ( )
-
-Konfiguriert den PipeLogwriter fuer Ausgaben der PLCAPP.
-
-Returns:
-
-PipeLogwriter()
-
-
-
-RevPiPlc._setuppopen
-_setuppopen ( )
-
-Setzt UID und GID fuer das PLC Programm.
-
-
-RevPiPlc._spopen
-_spopen (lst_proc )
-
-Startet das PLC Programm.
-
-lst_proc
-
-Prozessliste
-
-
-Returns:
-
-subprocess
-
-
-
-RevPiPlc.newlogfile
-newlogfile ( )
-
-Konfiguriert die FileHandler auf neue Logdatei.
-
-
-RevPiPlc.run
-run ( )
-
-Fuehrt PLC-Programm aus und ueberwacht es.
-
-
-RevPiPlc.stop
-stop ( )
-
-Beendet PLC-Programm.
-
-
-
RevPiPyLoad
@@ -826,162 +478,6 @@ Statuscode:
-
-RevPiSlave
-
-RevPi PLC-Server.
-
- Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert
- neue Verbindungen. Dieser werden dann als RevPiSlaveDev abgebildet.
-
- Ueber die angegebenen ACLs koennen Zugriffsbeschraenkungen vergeben werden.
-
-
-
-
-Derived from
-Thread
-
-Class Attributes
-
-
-Class Methods
-
-
-Methods
-
-
-RevPiSlave
-Instantiiert RevPiSlave-Klasse.
-
-newlogfile
-Konfiguriert die FileHandler auf neue Logdatei.
-
-run
-Startet Serverkomponente fuer die Annahme neuer Verbindungen.
-
-stop
-Beendet Slaveausfuehrung.
-
-
-
-Static Methods
-
-
-
-RevPiSlave (Constructor)
-RevPiSlave (acl, port=55234 )
-
-Instantiiert RevPiSlave-Klasse.
-
-acl
-
-Stringliste mit Leerstellen getrennt
- port
-
-Listen Port fuer plc Slaveserver
-
-
-
-RevPiSlave.newlogfile
-newlogfile ( )
-
-Konfiguriert die FileHandler auf neue Logdatei.
-
-
-RevPiSlave.run
-run ( )
-
-Startet Serverkomponente fuer die Annahme neuer Verbindungen.
-
-
-RevPiSlave.stop
-stop ( )
-
-Beendet Slaveausfuehrung.
-
-
-
-
-RevPiSlaveDev
-
-Klasse um eine RevPiModIO Verbindung zu verwalten.
-
- Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
- Netzwerk mit dem Prozessabbild auszutauschen.
-
-
-
-
-Derived from
-Thread
-
-Class Attributes
-
-
-Class Methods
-
-
-Methods
-
-
-RevPiSlaveDev
-Init RevPiSlaveDev-Class.
-
-run
-Verarbeitet Anfragen von Remoteteilnehmer.
-
-stop
-Beendet Verbindungsthread.
-
-
-
-Static Methods
-
-
-
-RevPiSlaveDev (Constructor)
-RevPiSlaveDev (devcon, acl )
-
-Init RevPiSlaveDev-Class.
-
-devcon
-
-Tuple der Verbindung
- deadtime
-
-Timeout der Vararbeitung
- acl
-
-Berechtigungslevel
-
-
-
-RevPiSlaveDev.run
-run ( )
-
-Verarbeitet Anfragen von Remoteteilnehmer.
-
-
-RevPiSlaveDev.stop
-stop ( )
-
-Beendet Verbindungsthread.
-
-
-
_ipmatch
_ipmatch (ipaddress, dict_acl )
@@ -1003,14 +499,6 @@ int() ACL Wert oder -1 wenn nicht gefunden
-
-_zeroprocimg
-_zeroprocimg ( )
-
-Setzt Prozessabbild auf NULL.
-
-
-
refullmatch
refullmatch (regex, string )
diff --git a/eric-revpipyload.api b/eric-revpipyload.api
index abc1126..b406d34 100644
--- a/eric-revpipyload.api
+++ b/eric-revpipyload.api
@@ -1,3 +1,28 @@
+logsystem.LogReader.closeall?4()
+logsystem.LogReader.load_applog?4(start, count)
+logsystem.LogReader.load_plclog?4(start, count)
+logsystem.LogReader?1()
+logsystem.PipeLogwriter.__del__?6()
+logsystem.PipeLogwriter._configurefh?5()
+logsystem.PipeLogwriter.logline?4(message)
+logsystem.PipeLogwriter.newlogfile?4()
+logsystem.PipeLogwriter.run?4()
+logsystem.PipeLogwriter.stop?4()
+logsystem.PipeLogwriter?1(logfilename)
+picontrolserver.RevPiSlave.newlogfile?4()
+picontrolserver.RevPiSlave.run?4()
+picontrolserver.RevPiSlave.stop?4()
+picontrolserver.RevPiSlave?1(acl, port=55234)
+picontrolserver.RevPiSlaveDev.run?4()
+picontrolserver.RevPiSlaveDev.stop?4()
+picontrolserver.RevPiSlaveDev?1(devcon, acl)
+plcsystem.RevPiPlc._configureplw?5()
+plcsystem.RevPiPlc._setuppopen?5()
+plcsystem.RevPiPlc._spopen?5(lst_proc)
+plcsystem.RevPiPlc.newlogfile?4()
+plcsystem.RevPiPlc.run?4()
+plcsystem.RevPiPlc.stop?4()
+plcsystem.RevPiPlc?1(program, arguments, pversion)
procimgserver.ProcimgServer.devices?4()
procimgserver.ProcimgServer.ios?4(type)
procimgserver.ProcimgServer.loadrevpimodio?4()
@@ -5,7 +30,8 @@ procimgserver.ProcimgServer.setvalue?4(device, io, value)
procimgserver.ProcimgServer.start?4()
procimgserver.ProcimgServer.stop?4()
procimgserver.ProcimgServer.values?4()
-procimgserver.ProcimgServer?1(logger, xmlserver, configrsc, procimg, aclmode)
+procimgserver.ProcimgServer?1(xmlserver, aclmode)
+proginit._zeroprocimg?5(self)
proginit.cleanup?4()
proginit.configure?4()
proginit.forked?7
@@ -14,25 +40,9 @@ proginit.logapp?7
proginit.logger?7
proginit.logplc?7
proginit.pargs?7
+proginit.picontrolreset?7
+proginit.rapcatalog?7
proginit.startdir?7
-revpipyload.LogReader.closeall?4()
-revpipyload.LogReader.load_applog?4(start, count)
-revpipyload.LogReader.load_plclog?4(start, count)
-revpipyload.LogReader?1()
-revpipyload.PipeLogwriter.__del__?6()
-revpipyload.PipeLogwriter._configurefh?5()
-revpipyload.PipeLogwriter.logline?4(message)
-revpipyload.PipeLogwriter.newlogfile?4()
-revpipyload.PipeLogwriter.run?4()
-revpipyload.PipeLogwriter.stop?4()
-revpipyload.PipeLogwriter?1(logfilename)
-revpipyload.RevPiPlc._configureplw?5()
-revpipyload.RevPiPlc._setuppopen?5()
-revpipyload.RevPiPlc._spopen?5(lst_proc)
-revpipyload.RevPiPlc.newlogfile?4()
-revpipyload.RevPiPlc.run?4()
-revpipyload.RevPiPlc.stop?4()
-revpipyload.RevPiPlc?1(program, arguments, pversion)
revpipyload.RevPiPyLoad._loadconfig?5()
revpipyload.RevPiPyLoad._plcthread?5()
revpipyload.RevPiPyLoad._sigexit?5(signum, frame)
@@ -61,19 +71,7 @@ revpipyload.RevPiPyLoad.xml_reload?4()
revpipyload.RevPiPyLoad.xml_setconfig?4(dc, loadnow=False)
revpipyload.RevPiPyLoad.xml_setpictoryrsc?4(filebytes, reset=False)
revpipyload.RevPiPyLoad?1()
-revpipyload.RevPiSlave.newlogfile?4()
-revpipyload.RevPiSlave.run?4()
-revpipyload.RevPiSlave.stop?4()
-revpipyload.RevPiSlave?1(acl, port=55234)
-revpipyload.RevPiSlaveDev.run?4()
-revpipyload.RevPiSlaveDev.stop?4()
-revpipyload.RevPiSlaveDev?1(devcon, acl)
revpipyload._ipmatch?5(ipaddress, dict_acl)
-revpipyload._zeroprocimg?5()
-revpipyload.configrsc?7
-revpipyload.picontrolreset?7
-revpipyload.procimg?7
-revpipyload.pyloadverion?7
-revpipyload.rapcatalog?7
+revpipyload.pyloadversion?7
revpipyload.re_ipacl?7
revpipyload.refullmatch?4(regex, string)
diff --git a/revpipyload.e4p b/revpipyload.e4p
index b25c5a4..d890648 100644
--- a/revpipyload.e4p
+++ b/revpipyload.e4p
@@ -1,7 +1,7 @@
-
+
en_US
@@ -20,6 +20,7 @@
revpipyload/procimgserver.py
revpipyload/logsystem.py
revpipyload/plcsystem.py
+ revpipyload/picontrolserver.py
diff --git a/revpipyload/picontrolserver.py b/revpipyload/picontrolserver.py
new file mode 100644
index 0000000..13965dd
--- /dev/null
+++ b/revpipyload/picontrolserver.py
@@ -0,0 +1,362 @@
+# -*- coding: utf-8 -*-
+#
+# RevPiPyLoad
+#
+# Webpage: https://revpimodio.org/revpipyplc/
+# (c) Sven Sager, License: LGPLv3
+#
+"""Modul fuer die Verwaltung der PLC-Slave Funktionen."""
+import proginit
+import socket
+from threading import Event, Thread
+from timeit import default_timer
+from revpipyload import _ipmatch
+
+
+class RevPiSlave(Thread):
+
+ """RevPi PLC-Server.
+
+ Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert
+ neue Verbindungen. Dieser werden dann als RevPiSlaveDev abgebildet.
+
+ Ueber die angegebenen ACLs koennen Zugriffsbeschraenkungen vergeben werden.
+
+ """
+
+ def __init__(self, acl, port=55234):
+ """Instantiiert RevPiSlave-Klasse.
+ @param acl Stringliste mit Leerstellen getrennt
+ @param port Listen Port fuer plc Slaveserver"""
+ super().__init__()
+ self._evt_exit = Event()
+ self.exitcode = None
+ self._port = port
+ self.so = None
+ self._th_dev = []
+ self.zeroonerror = False
+ self.zeroonexit = False
+
+ # ACLs aufbereiten
+ self.dict_acl = {}
+ for host in acl.split():
+ aclsplit = host.split(",")
+ self.dict_acl[aclsplit[0]] = \
+ 0 if len(aclsplit) == 1 else int(aclsplit[1])
+
+ def newlogfile(self):
+ """Konfiguriert die FileHandler auf neue Logdatei."""
+ pass
+
+ def run(self):
+ """Startet Serverkomponente fuer die Annahme neuer Verbindungen."""
+ proginit.logger.debug("enter RevPiSlave.run()")
+
+ # Socket öffnen und konfigurieren
+ self.so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ while not self._evt_exit.is_set():
+ try:
+ self.so.bind(("", self._port))
+ except:
+ proginit.logger.warning("can not bind socket - retry")
+ self._evt_exit.wait(1)
+ else:
+ break
+ self.so.listen(15)
+
+ # Mit Socket arbeiten
+ while not self._evt_exit.is_set():
+ self.exitcode = -1
+
+ # Verbindung annehmen
+ proginit.logger.debug("accept new connection")
+ try:
+ tup_sock = self.so.accept()
+ except:
+ if not self._evt_exit.is_set():
+ proginit.logger.exception("accept exception")
+ continue
+
+ # ACL prüfen
+ aclstatus = _ipmatch(tup_sock[1][0], self.dict_acl)
+ if aclstatus == -1:
+ tup_sock[0].close()
+ proginit.logger.warning(
+ "host ip '{}' does not match revpiacl - disconnect"
+ "".format(tup_sock[1][0])
+ )
+ else:
+ # Thread starten
+ th = RevPiSlaveDev(tup_sock, aclstatus)
+ th.start()
+ self._th_dev.append(th)
+
+ # Liste von toten threads befreien
+ self._th_dev = [
+ th_check for th_check in self._th_dev if th_check.is_alive()
+ ]
+
+ # Alle Threads beenden
+ for th in self._th_dev:
+ th.stop()
+
+ # Socket schließen
+ self.so.close()
+ self.so = None
+
+ self.exitcode = 0
+
+ proginit.logger.debug("leave RevPiSlave.run()")
+
+ def stop(self):
+ """Beendet Slaveausfuehrung."""
+ proginit.logger.debug("enter RevPiSlave.stop()")
+
+ self._evt_exit.set()
+ if self.so is not None:
+ try:
+ self.so.shutdown(socket.SHUT_RDWR)
+ except:
+ pass
+
+ proginit.logger.debug("leave RevPiSlave.stop()")
+
+
+class RevPiSlaveDev(Thread):
+
+ """Klasse um eine RevPiModIO Verbindung zu verwalten.
+
+ Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
+ Netzwerk mit dem Prozessabbild auszutauschen.
+
+ """
+
+ def __init__(self, devcon, acl):
+ """Init RevPiSlaveDev-Class.
+
+ @param devcon Tuple der Verbindung
+ @param deadtime Timeout der Vararbeitung
+ @param acl Berechtigungslevel
+
+ """
+ super().__init__()
+ self._acl = acl
+ self.daemon = True
+ self._deadtime = None
+ self._devcon, self._addr = devcon
+ self._evt_exit = Event()
+ self._writeerror = False
+
+ # Sicherheitsbytes
+ self.ey_dict = {}
+
+ def run(self):
+ """Verarbeitet Anfragen von Remoteteilnehmer."""
+ proginit.logger.debug("enter RevPiSlaveDev.run()")
+
+ proginit.logger.info(
+ "got new connection from host {} with acl {}".format(
+ self._addr, self._acl)
+ )
+
+ # Prozessabbild öffnen
+ fh_proc = open(proginit.pargs.procimg, "r+b", 0)
+
+ dirty = True
+ while not self._evt_exit.is_set():
+ # Laufzeitberechnung starten
+ ot = default_timer()
+
+ # Meldung erhalten
+ try:
+ netcmd = self._devcon.recv(16)
+ except:
+ break
+
+ # Wenn Meldung ungültig ist aussteigen
+ if netcmd[0:1] != b'\x01' or netcmd[-1:] != b'\x17':
+ if netcmd != b'':
+ proginit.logger.error(
+ "net cmd not valid {}".format(netcmd)
+ )
+ break
+
+ cmd = netcmd[1:3]
+ if cmd == b'DA':
+ # Processabbild übertragen
+ # bCMiiii00000000b = 16
+
+ position = int.from_bytes(netcmd[3:5], byteorder="little")
+ length = int.from_bytes(netcmd[5:7], byteorder="little")
+
+ fh_proc.seek(position)
+ try:
+ self._devcon.sendall(fh_proc.read(length))
+ except:
+ proginit.logger.error("error while send read data")
+ break
+
+ elif cmd == b'SD' and self._acl == 1:
+ # Ausgänge empfangen, wenn acl es erlaubt
+ # bCMiiiic0000000b = 16
+
+ position = int.from_bytes(netcmd[3:5], byteorder="little")
+ length = int.from_bytes(netcmd[5:7], byteorder="little")
+ control = netcmd[7:8]
+
+ if control == b'\x1d' and length > 0:
+ try:
+ block = self._devcon.recv(length)
+ except:
+ proginit.logger.error("error while recv data to write")
+ self._writeerror = True
+ break
+ fh_proc.seek(position)
+
+ # Länge der Daten prüfen
+ if len(block) == length:
+ fh_proc.write(block)
+ else:
+ proginit.logger.error("got wrong length to write")
+ break
+
+ # Record seperator character
+ if control == b'\x1c':
+ if self._writeerror:
+ self._devcon.send(b'\xff')
+ else:
+ self._devcon.send(b'\x1e')
+ self._writeerror = False
+
+ elif cmd == b'\x06\x16':
+ # Just sync
+ self._devcon.send(b'\x06\x16')
+
+ elif cmd == b'CF':
+ # Socket konfigurieren
+ # bCMii0000000000b = 16
+
+ timeoutms = int.from_bytes(netcmd[3:5], byteorder="little")
+
+ self._deadtime = timeoutms / 1000
+ self._devcon.settimeout(self._deadtime)
+
+ # Record seperator character
+ self._devcon.send(b'\x1e')
+
+ elif cmd == b'EY':
+ # Bytes bei Verbindungsabbruch schreiben
+ # bCMiiiix0000000b = 16
+
+ position = int.from_bytes(
+ netcmd[3:5], byteorder="little"
+ )
+ length = int.from_bytes(
+ netcmd[5:7], byteorder="little"
+ )
+ if netcmd[7:8] == b'\xFF':
+ # Dirtybytes löschen
+ if position in self.ey_dict:
+ del self.ey_dict[position]
+
+ # Record seperator character
+ self._devcon.send(b'\x1e')
+ proginit.logger.info(
+ "cleared dirty bytes on position {}"
+ "".format(position)
+ )
+
+ else:
+ # Dirtybytes hinzufügen
+ bytesbuff = bytearray()
+ try:
+ while not self._evt_exit.is_set() \
+ and len(bytesbuff) < length:
+ block = self._devcon.recv(1024)
+ bytesbuff += block
+ if block == b'':
+ break
+
+ except:
+ proginit.logger.error("error while recv dirty bytes")
+ break
+
+ # Länge der Daten prüfen
+ if len(bytesbuff) == length:
+ self.ey_dict[position] = bytesbuff
+ else:
+ proginit.logger.error("got wrong length to write")
+ break
+
+ # Record seperator character
+ self._devcon.send(b'\x1e')
+ proginit.logger.info(
+ "got dirty bytes to write on error on position {}"
+ "".format(position)
+ )
+
+ elif cmd == b'PI':
+ # piCtory Konfiguration senden
+ proginit.logger.debug(
+ "transfair pictory configuration: {}"
+ "".format(proginit.pargs.configrsc)
+ )
+ fh_pic = open(proginit.pargs.configrsc, "rb")
+ while True:
+ data = fh_pic.read(1024)
+ if data:
+ # FIXME: Fehler fangen
+ self._devcon.send(data)
+ else:
+ fh_pic.close()
+ break
+
+ # End-of-Transmission character
+ self._devcon.send(b'\x04')
+ continue
+
+ elif cmd == b'EX':
+ # Sauber Verbindung verlassen
+ dirty = False
+ self._evt_exit.set()
+ continue
+
+ else:
+ # Kein gültiges CMD gefunden, abbruch!
+ break
+
+ # Verarbeitungszeit prüfen
+ if self._deadtime is not None:
+ comtime = default_timer() - ot
+ if comtime > self._deadtime:
+ proginit.logger.warning(
+ "runtime more than {} ms: {}!".format(
+ int(self._deadtime * 1000), comtime
+ )
+ )
+ # TODO: Soll ein Fehler ausgelöst werden?
+
+ # Dirty verlassen
+ if dirty:
+ for pos in self.ey_dict:
+ fh_proc.seek(pos)
+ fh_proc.write(self.ey_dict[pos])
+
+ proginit.logger.error("dirty shutdown of connection")
+
+ fh_proc.close()
+ self._devcon.close()
+ self._devcon = None
+
+ proginit.logger.info("disconnected from {}".format(self._addr))
+ proginit.logger.debug("leave RevPiSlaveDev.run()")
+
+ def stop(self):
+ """Beendet Verbindungsthread."""
+ proginit.logger.debug("enter RevPiSlaveDev.stop()")
+
+ self._evt_exit.set()
+ if self._devcon is not None:
+ self._devcon.shutdown(socket.SHUT_RDWR)
+
+ proginit.logger.debug("leave RevPiSlaveDev.stop()")
diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py
index 11bc795..5775e7e 100755
--- a/revpipyload/revpipyload.py
+++ b/revpipyload/revpipyload.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# RevPiPyLoad
-# Version: see global var pyloadverion
+# Version: see global var pyloadversion
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
@@ -32,11 +32,11 @@ begrenzt werden!
"""
import gzip
import logsystem
+import picontrolserver
import plcsystem
import proginit
import os
import signal
-import socket
import tarfile
import zipfile
from concurrent import futures
@@ -47,12 +47,10 @@ from shutil import rmtree
from tempfile import mkstemp
from threading import Event
from time import asctime
-from timeit import default_timer
from xmlrpc.client import Binary
from xmlrpc.server import SimpleXMLRPCServer
-pyloadverion = "0.4.3"
-pyloadverion = "0.5.0"
+pyloadversion = "0.5.0"
re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[0-1] ?)*"
@@ -83,362 +81,6 @@ def refullmatch(regex, string):
return m is not None and m.end() == len(string)
-def _zeroprocimg():
- """Setzt Prozessabbild auf NULL."""
- if os.path.exists(procimg):
- f = open(procimg, "w+b", 0)
- f.write(bytes(4096))
-
-
-
-class RevPiSlave(Thread):
-
- """RevPi PLC-Server.
-
- Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert
- neue Verbindungen. Dieser werden dann als RevPiSlaveDev abgebildet.
-
- Ueber die angegebenen ACLs koennen Zugriffsbeschraenkungen vergeben werden.
-
- """
-
- def __init__(self, acl, port=55234):
- """Instantiiert RevPiSlave-Klasse.
- @param acl Stringliste mit Leerstellen getrennt
- @param port Listen Port fuer plc Slaveserver"""
- super().__init__()
- self._evt_exit = Event()
- self.exitcode = None
- self._port = port
- self.so = None
- self._th_dev = []
- self.zeroonerror = False
- self.zeroonexit = False
-
- # ACLs aufbereiten
- self.dict_acl = {}
- for host in acl.split():
- aclsplit = host.split(",")
- self.dict_acl[aclsplit[0]] = \
- 0 if len(aclsplit) == 1 else int(aclsplit[1])
-
- def newlogfile(self):
- """Konfiguriert die FileHandler auf neue Logdatei."""
- pass
-
- def run(self):
- """Startet Serverkomponente fuer die Annahme neuer Verbindungen."""
- proginit.logger.debug("enter RevPiSlave.run()")
-
- # Socket öffnen und konfigurieren
- self.so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- while not self._evt_exit.is_set():
- try:
- self.so.bind(("", self._port))
- except:
- proginit.logger.warning("can not bind socket - retry")
- self._evt_exit.wait(1)
- else:
- break
- self.so.listen(15)
-
- # Mit Socket arbeiten
- while not self._evt_exit.is_set():
- self.exitcode = -1
-
- # Verbindung annehmen
- proginit.logger.debug("accept new connection")
- try:
- tup_sock = self.so.accept()
- except:
- if not self._evt_exit.is_set():
- proginit.logger.exception("accept exception")
- continue
-
- # ACL prüfen
- aclstatus = _ipmatch(tup_sock[1][0], self.dict_acl)
- if aclstatus == -1:
- tup_sock[0].close()
- proginit.logger.warning(
- "host ip '{}' does not match revpiacl - disconnect"
- "".format(tup_sock[1][0])
- )
- else:
- # Thread starten
- th = RevPiSlaveDev(tup_sock, aclstatus)
- th.start()
- self._th_dev.append(th)
-
- # Liste von toten threads befreien
- self._th_dev = [
- th_check for th_check in self._th_dev if th_check.is_alive()
- ]
-
- # Alle Threads beenden
- for th in self._th_dev:
- th.stop()
-
- # Socket schließen
- self.so.close()
- self.so = None
-
- self.exitcode = 0
-
- proginit.logger.debug("leave RevPiSlave.run()")
-
- def stop(self):
- """Beendet Slaveausfuehrung."""
- proginit.logger.debug("enter RevPiSlave.stop()")
-
- self._evt_exit.set()
- if self.so is not None:
- try:
- self.so.shutdown(socket.SHUT_RDWR)
- except:
- pass
-
- proginit.logger.debug("leave RevPiSlave.stop()")
-
-
-class RevPiSlaveDev(Thread):
-
- """Klasse um eine RevPiModIO Verbindung zu verwalten.
-
- Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
- Netzwerk mit dem Prozessabbild auszutauschen.
-
- """
-
- def __init__(self, devcon, acl):
- """Init RevPiSlaveDev-Class.
-
- @param devcon Tuple der Verbindung
- @param deadtime Timeout der Vararbeitung
- @param acl Berechtigungslevel
-
- """
- super().__init__()
- self._acl = acl
- self.daemon = True
- self._deadtime = None
- self._devcon, self._addr = devcon
- self._evt_exit = Event()
- self._writeerror = False
-
- # Sicherheitsbytes
- self.ey_dict = {}
-
- def run(self):
- """Verarbeitet Anfragen von Remoteteilnehmer."""
- proginit.logger.debug("enter RevPiSlaveDev.run()")
-
- proginit.logger.info(
- "got new connection from host {} with acl {}".format(
- self._addr, self._acl)
- )
-
- # Prozessabbild öffnen
- fh_proc = open(procimg, "r+b", 0)
-
- dirty = True
- while not self._evt_exit.is_set():
- # Laufzeitberechnung starten
- ot = default_timer()
-
- # Meldung erhalten
- try:
- netcmd = self._devcon.recv(16)
- except:
- break
-
- # Wenn Meldung ungültig ist aussteigen
- if netcmd[0:1] != b'\x01' or netcmd[-1:] != b'\x17':
- if netcmd != b'':
- proginit.logger.error(
- "net cmd not valid {}".format(netcmd)
- )
- break
-
- cmd = netcmd[1:3]
- if cmd == b'DA':
- # Processabbild übertragen
- # bCMiiii00000000b = 16
-
- position = int.from_bytes(netcmd[3:5], byteorder="little")
- length = int.from_bytes(netcmd[5:7], byteorder="little")
-
- fh_proc.seek(position)
- try:
- self._devcon.sendall(fh_proc.read(length))
- except:
- proginit.logger.error("error while send read data")
- break
-
- elif cmd == b'SD' and self._acl == 1:
- # Ausgänge empfangen, wenn acl es erlaubt
- # bCMiiiic0000000b = 16
-
- position = int.from_bytes(netcmd[3:5], byteorder="little")
- length = int.from_bytes(netcmd[5:7], byteorder="little")
- control = netcmd[7:8]
-
- if control == b'\x1d' and length > 0:
- try:
- block = self._devcon.recv(length)
- except:
- proginit.logger.error("error while recv data to write")
- self._writeerror = True
- break
- fh_proc.seek(position)
-
- # Länge der Daten prüfen
- if len(block) == length:
- fh_proc.write(block)
- else:
- proginit.logger.error("got wrong length to write")
- break
-
- # Record seperator character
- if control == b'\x1c':
- if self._writeerror:
- self._devcon.send(b'\xff')
- else:
- self._devcon.send(b'\x1e')
- self._writeerror = False
-
- elif cmd == b'\x06\x16':
- # Just sync
- self._devcon.send(b'\x06\x16')
-
- elif cmd == b'CF':
- # Socket konfigurieren
- # bCMii0000000000b = 16
-
- timeoutms = int.from_bytes(netcmd[3:5], byteorder="little")
-
- self._deadtime = timeoutms / 1000
- self._devcon.settimeout(self._deadtime)
-
- # Record seperator character
- self._devcon.send(b'\x1e')
-
- elif cmd == b'EY':
- # Bytes bei Verbindungsabbruch schreiben
- # bCMiiiix0000000b = 16
-
- position = int.from_bytes(
- netcmd[3:5], byteorder="little"
- )
- length = int.from_bytes(
- netcmd[5:7], byteorder="little"
- )
- if netcmd[7:8] == b'\xFF':
- # Dirtybytes löschen
- if position in self.ey_dict:
- del self.ey_dict[position]
-
- # Record seperator character
- self._devcon.send(b'\x1e')
- proginit.logger.info(
- "cleared dirty bytes on position {}"
- "".format(position)
- )
-
- else:
- # Dirtybytes hinzufügen
- bytesbuff = bytearray()
- try:
- while not self._evt_exit.is_set() \
- and len(bytesbuff) < length:
- block = self._devcon.recv(1024)
- bytesbuff += block
- if block == b'':
- break
-
- except:
- proginit.logger.error("error while recv dirty bytes")
- break
-
- # Länge der Daten prüfen
- if len(bytesbuff) == length:
- self.ey_dict[position] = bytesbuff
- else:
- proginit.logger.error("got wrong length to write")
- break
-
- # Record seperator character
- self._devcon.send(b'\x1e')
- proginit.logger.info(
- "got dirty bytes to write on error on position {}"
- "".format(position)
- )
-
- elif cmd == b'PI':
- # piCtory Konfiguration senden
- proginit.logger.debug(
- "transfair pictory configuration: {}".format(configrsc)
- )
- fh_pic = open(configrsc, "rb")
- while True:
- data = fh_pic.read(1024)
- if data:
- # FIXME: Fehler fangen
- self._devcon.send(data)
- else:
- fh_pic.close()
- break
-
- # End-of-Transmission character
- self._devcon.send(b'\x04')
- continue
-
- elif cmd == b'EX':
- # Sauber Verbindung verlassen
- dirty = False
- self._evt_exit.set()
- continue
-
- else:
- # Kein gültiges CMD gefunden, abbruch!
- break
-
- # Verarbeitungszeit prüfen
- if self._deadtime is not None:
- comtime = default_timer() - ot
- if comtime > self._deadtime:
- proginit.logger.warning(
- "runtime more than {} ms: {}!".format(
- int(self._deadtime * 1000), comtime
- )
- )
- # TODO: Soll ein Fehler ausgelöst werden?
-
- # Dirty verlassen
- if dirty:
- for pos in self.ey_dict:
- fh_proc.seek(pos)
- fh_proc.write(self.ey_dict[pos])
-
- proginit.logger.error("dirty shutdown of connection")
-
- fh_proc.close()
- self._devcon.close()
- self._devcon = None
-
- proginit.logger.info("disconnected from {}".format(self._addr))
- proginit.logger.debug("leave RevPiSlaveDev.run()")
-
- def stop(self):
- """Beendet Verbindungsthread."""
- proginit.logger.debug("enter RevPiSlaveDev.stop()")
-
- self._evt_exit.set()
- if self._devcon is not None:
- self._devcon.shutdown(socket.SHUT_RDWR)
-
- proginit.logger.debug("leave RevPiSlaveDev.stop()")
-
-
class RevPiPyLoad():
"""Hauptklasse, die alle Funktionen zur Verfuegung stellt.
@@ -546,7 +188,9 @@ class RevPiPyLoad():
# PLC Thread konfigurieren
self.plc = self._plcthread()
if self.plcslave:
- self.th_plcslave = RevPiSlave(self.plcslaveacl, self.plcslaveport)
+ self.th_plcslave = picontrolserver.RevPiSlave(
+ self.plcslaveacl, self.plcslaveport
+ )
else:
self.th_plcslave = None
@@ -612,15 +256,17 @@ class RevPiPyLoad():
self.xsrv.register_function(
lambda: os.system(proginit.picontrolreset),
"resetpicontrol")
+ self.xsrv.register_function(
self.xml_plcslavestop, "plcslavestop")
self.xsrv.register_function(
- lambda: os.system(picontrolreset), "resetpicontrol")
+ lambda: os.system(proginit.picontrolreset),
+ "resetpicontrol")
self.xsrv.register_function(
self.xml_setconfig, "set_config")
self.xsrv.register_function(
self.xml_setpictoryrsc, "set_pictoryrsc")
- self.xsrv.register_function(lambda: pyloadverion, "version")
+ self.xsrv.register_function(lambda: pyloadversion, "version")
self.xsrv.register_function(lambda: self.xmlrpc, "xmlmodus")
proginit.logger.debug("created xmlrpc server")
@@ -1119,7 +765,7 @@ class RevPiPyLoad():
if self.th_plcslave is not None and self.th_plcslave.is_alive():
return -2
else:
- self.th_plcslave = RevPiSlave(
+ self.th_plcslave = picontrolserver.RevPiSlave(
self.plcslaveacl, self.plcslaveport
)
self.th_plcslave.start()