bindip für PlcSlave wird jetzt verarbeitet

Fehlerabfang bei piCtory-Übertragung
IOCTL über das Netzwerk implementiert
Parameter --developermode implementiert
This commit is contained in:
2018-12-12 10:03:50 +01:00
parent 2fac129232
commit 637348111b
3 changed files with 116 additions and 32 deletions

View File

@@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "GPLv3" __license__ = "GPLv3"
import proginit import proginit
import socket import socket
from fcntl import ioctl
from shared.ipaclmanager import IpAclManager from shared.ipaclmanager import IpAclManager
from threading import Event, Thread from threading import Event, Thread
from timeit import default_timer from timeit import default_timer
@@ -16,23 +17,32 @@ class RevPiSlave(Thread):
"""RevPi PLC-Server. """RevPi PLC-Server.
Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert
neue Verbindungen. Dieser werden dann als RevPiSlaveDev abgebildet. neue Verbindungen. Diese werden dann als RevPiSlaveDev abgebildet.
Ueber die angegebenen ACLs koennen Zugriffsbeschraenkungen vergeben werden. Ueber die angegebenen ACLs koennen Zugriffsbeschraenkungen vergeben werden.
""" """
def __init__(self, ipacl, port=55234): def __init__(self, ipacl, port=55234, bindip=""):
"""Instantiiert RevPiSlave-Klasse. """Instantiiert RevPiSlave-Klasse.
@param ipacl AclManager <class 'IpAclManager'> @param ipacl AclManager <class 'IpAclManager'>
@param port Listen Port fuer plc Slaveserver""" @param port Listen Port fuer plc Slaveserver
if not type(ipacl) == IpAclManager: @param bindip IP-Adresse an die der Dienst gebunden wird (leer=alle)
"""
if not isinstance(ipacl, IpAclManager):
raise ValueError("parameter ipacl must be <class 'IpAclManager'>") raise ValueError("parameter ipacl must be <class 'IpAclManager'>")
if not type(port) == int: if not (isinstance(port, int) and 0 < port <= 65535):
raise ValueError("parameter port must be <class 'int'>") raise ValueError(
"parameter port must be <class 'int'> and in range 1 - 65535"
)
if not isinstance(bindip, str):
raise ValueError("parameter bindip must be <class 'str'>")
super().__init__() super().__init__()
self.__ipacl = ipacl self.__ipacl = ipacl
self._bindip = bindip
self._evt_exit = Event() self._evt_exit = Event()
self.exitcode = None self.exitcode = None
self._port = port self._port = port
@@ -68,17 +78,19 @@ class RevPiSlave(Thread):
"""Startet Serverkomponente fuer die Annahme neuer Verbindungen.""" """Startet Serverkomponente fuer die Annahme neuer Verbindungen."""
proginit.logger.debug("enter RevPiSlave.run()") proginit.logger.debug("enter RevPiSlave.run()")
# Socket öffnen und konfigurieren # Socket öffnen und konfigurieren bis Erfolg oder Ende
self.so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while not self._evt_exit.is_set(): while not self._evt_exit.is_set():
try: try:
self.so.bind(("", self._port)) self.so.bind((self._bindip, self._port))
except Exception: except Exception as e:
proginit.logger.warning("can not bind socket - retry") proginit.logger.warning(
"can not bind socket: {0} - retry".format(e)
)
self._evt_exit.wait(1) self._evt_exit.wait(1)
else: else:
self.so.listen(15)
break break
self.so.listen(15)
# Mit Socket arbeiten # Mit Socket arbeiten
while not self._evt_exit.is_set(): while not self._evt_exit.is_set():
@@ -156,6 +168,7 @@ class RevPiSlaveDev(Thread):
""" """
super().__init__() super().__init__()
self.__doerror = False
self._acl = acl self._acl = acl
self.daemon = True self.daemon = True
self._deadtime = None self._deadtime = None
@@ -273,7 +286,7 @@ class RevPiSlaveDev(Thread):
proginit.logger.error("can not convert timeout value") proginit.logger.error("can not convert timeout value")
break break
if 0 < timeoutms < 65535: if 0 < timeoutms <= 65535:
self._deadtime = timeoutms / 1000 self._deadtime = timeoutms / 1000
self._devcon.settimeout(self._deadtime) self._devcon.settimeout(self._deadtime)
proginit.logger.debug( proginit.logger.debug(
@@ -300,12 +313,14 @@ class RevPiSlaveDev(Thread):
length = int.from_bytes(netcmd[5:7], byteorder="little") length = int.from_bytes(netcmd[5:7], byteorder="little")
control = netcmd[7:8] control = netcmd[7:8]
ok_byte = b'\xff' if self.__doerror else b'\x1e'
if control == b'\xff': if control == b'\xff':
# Alle Dirtybytes löschen # Alle Dirtybytes löschen
self.ey_dict = {} self.ey_dict = {}
# Record seperator character # Record seperator character
self._devcon.send(b'\x1e') self._devcon.send(ok_byte)
proginit.logger.info("cleared all dirty bytes") proginit.logger.info("cleared all dirty bytes")
elif control == b'\xfe': elif control == b'\xfe':
@@ -315,7 +330,7 @@ class RevPiSlaveDev(Thread):
del self.ey_dict[position] del self.ey_dict[position]
# Record seperator character # Record seperator character
self._devcon.send(b'\x1e') self._devcon.send(ok_byte)
proginit.logger.info( proginit.logger.info(
"cleared dirty bytes on position {0}" "cleared dirty bytes on position {0}"
"".format(position) "".format(position)
@@ -344,7 +359,7 @@ class RevPiSlaveDev(Thread):
break break
# Record seperator character # Record seperator character
self._devcon.send(b'\x1e') self._devcon.send(ok_byte)
proginit.logger.info( proginit.logger.info(
"got dirty bytes to write on error on position {0}" "got dirty bytes to write on error on position {0}"
"".format(position) "".format(position)
@@ -356,19 +371,20 @@ class RevPiSlaveDev(Thread):
"transfair pictory configuration: {0}" "transfair pictory configuration: {0}"
"".format(proginit.pargs.configrsc) "".format(proginit.pargs.configrsc)
) )
fh_pic = open(proginit.pargs.configrsc, "rb") try:
while True: with open(proginit.pargs.configrsc, "rb") as fh_pic:
data = fh_pic.read(1024) # Komplette piCtory Datei senden
if data: self._devcon.sendall(fh_pic.read())
# FIXME: Fehler fangen except Exception as e:
self._devcon.send(data) proginit.logger.error(
else: "error on pictory transfair: {0}".format(e)
fh_pic.close() )
break break
else:
# End-of-Transmission character continue
self._devcon.send(b'\x04') finally:
continue # End-of-Transmission character immer senden
self._devcon.send(b'\x04')
elif cmd == b'EX': elif cmd == b'EX':
# Sauber Verbindung verlassen # Sauber Verbindung verlassen
@@ -376,8 +392,68 @@ class RevPiSlaveDev(Thread):
self._evt_exit.set() self._evt_exit.set()
continue continue
elif cmd == b'IC':
# Net-IOCTL ausführen
# bCMiiiiii000000b = 16
request = int.from_bytes(netcmd[3:7], byteorder="little")
length = int.from_bytes(netcmd[7:9], byteorder="little")
arg = self._devcon.recv(length)
# Berechtigung prüfen und ggf. trennen
if self._acl < 1:
self._devcon.send(b'\x18')
break
try:
if proginit.pargs.procimg == "/dev/piControl0":
# Läuft auf RevPi
ioctl(fh_proc, request, arg)
proginit.logger.debug(
"ioctl {0} with {1} successful"
"".format(request, arg)
)
else:
# Simulation
proginit.logger.warning(
"ioctl {0} with {1} simulated".format(request, arg)
)
except Exception as ex:
proginit.logger.error(ex)
self._devcon.send(b'\xff')
else:
self._devcon.send(b'\x1e')
elif proginit.pargs.developermode and cmd == b'DV':
# Development options
# bCMc00000000000b = 16
if self._acl < 9:
# Spezieller ACL-Wert für Entwicklung
self._devcon.send(b'\x18')
break
c = netcmd[3:4]
if c == b'a':
# CMD a = Switch ACL to 0
self._acl = 0
proginit.logger.warning("DV: set acl to 0")
self._devcon.send(b'\x1e')
elif c == b'b':
# CMD b = Aktiviert/Deaktiviert den Fehlermodus
if netcmd[4:5] == b'\x01':
self.__doerror = True
proginit.logger.warning("DV: set do_error")
else:
self.__doerror = False
proginit.logger.warning("DV: reset do_error")
self._devcon.send(b'\x1e')
else: else:
# Kein gültiges CMD gefunden, abbruch! # Kein gültiges CMD gefunden, abbruch!
proginit.logger.error(
"found unknown net cmd: {0}".format(cmd)
)
break break
# Verarbeitungszeit prüfen # Verarbeitungszeit prüfen

View File

@@ -65,7 +65,11 @@ def configure():
) )
parser.add_argument( parser.add_argument(
"-v", "--verbose", action="count", dest="verbose", "-v", "--verbose", action="count", dest="verbose",
help="Switch on verbose logging" help="Switch on verbose logging: info -v debug -vv"
)
parser.add_argument(
"--developermode", action="store_true", dest="developermode",
default=False
) )
global pargs global pargs
pargs = parser.parse_args() pargs = parser.parse_args()

View File

@@ -73,8 +73,12 @@ class RevPiPyLoad():
self.xml_ps = None self.xml_ps = None
# Berechtigungsmanger # Berechtigungsmanger
self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1) if proginit.pargs.developermode:
self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4) self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=9)
self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=9)
else:
self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1)
self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4)
# Threads/Prozesse # Threads/Prozesse
self.th_plcmqtt = None self.th_plcmqtt = None
@@ -519,7 +523,7 @@ class RevPiPyLoad():
if self.plcslave: if self.plcslave:
th_plc = picontrolserver.RevPiSlave( th_plc = picontrolserver.RevPiSlave(
self.plcslaveacl, self.plcslaveport self.plcslaveacl, self.plcslaveport, self.plcslavebindip
) )
proginit.logger.debug("leave RevPiPyLoad._plcslave()") proginit.logger.debug("leave RevPiPyLoad._plcslave()")