mirror of
https://github.com/naruxde/revpipyload.git
synced 2025-11-08 15:13:52 +01:00
Use struct module for net commands, send files with length, replace SD with WD
The struct module is more efficient than int.from_bytes. piCtory and ReplaceIO file length in the first 4 bytes of transmission Replaced SD with WD cmd, which will write one request, no buffer
This commit is contained in:
@@ -3,22 +3,24 @@
|
|||||||
__author__ = "Sven Sager"
|
__author__ = "Sven Sager"
|
||||||
__copyright__ = "Copyright (C) 2018 Sven Sager"
|
__copyright__ = "Copyright (C) 2018 Sven Sager"
|
||||||
__license__ = "GPLv3"
|
__license__ = "GPLv3"
|
||||||
import proginit
|
|
||||||
import socket
|
import socket
|
||||||
from fcntl import ioctl
|
from fcntl import ioctl
|
||||||
from shared.ipaclmanager import IpAclManager
|
from struct import unpack, pack
|
||||||
from threading import Event, Thread
|
from threading import Event, Thread
|
||||||
from timeit import default_timer
|
from timeit import default_timer
|
||||||
|
|
||||||
|
import proginit
|
||||||
|
from shared.ipaclmanager import IpAclManager
|
||||||
|
|
||||||
# Hashvalues
|
# Hashvalues
|
||||||
HASH_NULL = b'\x00' * 16
|
HASH_NULL = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||||
HASH_FAIL = b'\xff' * 16
|
HASH_FAIL = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
|
||||||
HASH_PICT = HASH_FAIL
|
HASH_PICT = HASH_FAIL
|
||||||
HASH_RPIO = HASH_NULL
|
HASH_RPIO = HASH_NULL
|
||||||
|
|
||||||
|
|
||||||
class RevPiSlave(Thread):
|
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
|
||||||
@@ -59,7 +61,7 @@ class RevPiSlave(Thread):
|
|||||||
def check_connectedacl(self):
|
def check_connectedacl(self):
|
||||||
"""Prueft bei neuen ACLs bestehende Verbindungen."""
|
"""Prueft bei neuen ACLs bestehende Verbindungen."""
|
||||||
for dev in self._th_dev:
|
for dev in self._th_dev:
|
||||||
ip, port = dev._addr
|
ip, port = dev._addr
|
||||||
level = self.__ipacl.get_acllevel(ip)
|
level = self.__ipacl.get_acllevel(ip)
|
||||||
if level < 0:
|
if level < 0:
|
||||||
# Verbindung killen
|
# Verbindung killen
|
||||||
@@ -172,7 +174,6 @@ class RevPiSlave(Thread):
|
|||||||
|
|
||||||
|
|
||||||
class RevPiSlaveDev(Thread):
|
class RevPiSlaveDev(Thread):
|
||||||
|
|
||||||
"""Klasse um eine RevPiModIO Verbindung zu verwalten.
|
"""Klasse um eine RevPiModIO Verbindung zu verwalten.
|
||||||
|
|
||||||
Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
|
Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
|
||||||
@@ -195,7 +196,6 @@ class RevPiSlaveDev(Thread):
|
|||||||
self._devcon, self._addr = devcon
|
self._devcon, self._addr = devcon
|
||||||
self._evt_exit = Event()
|
self._evt_exit = Event()
|
||||||
self.got_replace_ios = False
|
self.got_replace_ios = False
|
||||||
self._writeerror = False
|
|
||||||
|
|
||||||
# Sicherheitsbytes
|
# Sicherheitsbytes
|
||||||
self.ey_dict = {}
|
self.ey_dict = {}
|
||||||
@@ -222,13 +222,12 @@ class RevPiSlaveDev(Thread):
|
|||||||
|
|
||||||
buff_size = 2048
|
buff_size = 2048
|
||||||
dirty = True
|
dirty = True
|
||||||
netcmd = bytearray()
|
|
||||||
buff_block = bytearray(buff_size)
|
buff_block = bytearray(buff_size)
|
||||||
buff_recv = bytearray()
|
buff_recv = bytearray()
|
||||||
while not self._evt_exit.is_set():
|
while not self._evt_exit.is_set():
|
||||||
# Laufzeitberechnung starten
|
# Laufzeitberechnung starten
|
||||||
ot = default_timer()
|
ot = default_timer()
|
||||||
netcmd.clear()
|
buff_recv.clear()
|
||||||
|
|
||||||
# Meldung erhalten
|
# Meldung erhalten
|
||||||
try:
|
try:
|
||||||
@@ -237,27 +236,27 @@ class RevPiSlaveDev(Thread):
|
|||||||
count = self._devcon.recv_into(buff_block, recv_len)
|
count = self._devcon.recv_into(buff_block, recv_len)
|
||||||
if count == 0:
|
if count == 0:
|
||||||
raise IOError("lost network connection")
|
raise IOError("lost network connection")
|
||||||
netcmd += buff_block[:count]
|
buff_recv += buff_block[:count]
|
||||||
recv_len -= count
|
recv_len -= count
|
||||||
|
|
||||||
|
# Unpack ist schneller als Direktzugriff oder Umwandlung
|
||||||
|
netcmd = unpack("=c2sHH8sc", buff_recv)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
proginit.logger.exception(e)
|
proginit.logger.error(e)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Wenn Meldung ungültig ist aussteigen
|
# Wenn Meldung ungültig ist aussteigen
|
||||||
if netcmd[0:1] != b'\x01' or netcmd[-1:] != b'\x17':
|
if netcmd[0] != b'\x01' or netcmd[5] != b'\x17':
|
||||||
if netcmd != b'':
|
proginit.logger.error("net cmd not valid {0}".format(netcmd))
|
||||||
proginit.logger.error(
|
|
||||||
"net cmd not valid {0}".format(netcmd)
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
cmd = netcmd[1:3]
|
cmd = netcmd[1]
|
||||||
if cmd == b'DA':
|
if cmd == b'DA':
|
||||||
# Processabbild übertragen
|
# Processabbild übertragen
|
||||||
# bCMiiii00000000b = 16
|
# b CM ii ii 00000000 b = 16
|
||||||
|
|
||||||
position = int.from_bytes(netcmd[3:5], byteorder="little")
|
position = netcmd[2]
|
||||||
length = int.from_bytes(netcmd[5:7], byteorder="little")
|
length = netcmd[3]
|
||||||
|
|
||||||
fh_proc.seek(position)
|
fh_proc.seek(position)
|
||||||
try:
|
try:
|
||||||
@@ -266,44 +265,72 @@ class RevPiSlaveDev(Thread):
|
|||||||
proginit.logger.error("error while send read data")
|
proginit.logger.error("error while send read data")
|
||||||
break
|
break
|
||||||
|
|
||||||
elif cmd == b'SD':
|
elif cmd == b'WD':
|
||||||
# Ausgänge setzen, wenn acl es erlaubt
|
# Ausgänge setzen, wenn acl es erlaubt
|
||||||
# bCMiiiic0000000b = 16
|
# b CM ii ii c0000000 b = 16
|
||||||
|
|
||||||
# Berechtigung prüfen und ggf. trennen
|
# Berechtigung prüfen und ggf. trennen
|
||||||
if self._acl < 1:
|
if self._acl < 1:
|
||||||
self._devcon.sendall(b'\x18')
|
self._devcon.sendall(b'\x18')
|
||||||
break
|
break
|
||||||
|
|
||||||
position = int.from_bytes(netcmd[3:5], byteorder="little")
|
position = netcmd[2]
|
||||||
length = int.from_bytes(netcmd[5:7], byteorder="little")
|
length = netcmd[3]
|
||||||
control = netcmd[7:8]
|
|
||||||
|
# Datenblock schreiben
|
||||||
|
buff_recv.clear()
|
||||||
|
try:
|
||||||
|
while length > 0:
|
||||||
|
count = self._devcon.recv_into(buff_block, min(length, buff_size))
|
||||||
|
if count == 0:
|
||||||
|
raise IOError("lost network connection")
|
||||||
|
buff_recv += buff_block[:count]
|
||||||
|
length -= count
|
||||||
|
except Exception:
|
||||||
|
proginit.logger.error("error while recv data for wd write")
|
||||||
|
break
|
||||||
|
|
||||||
|
fh_proc.seek(position)
|
||||||
|
fh_proc.write(buff_recv)
|
||||||
|
|
||||||
|
# Record separator character
|
||||||
|
self._devcon.sendall(b'\x1e')
|
||||||
|
|
||||||
|
elif cmd == b'FD':
|
||||||
|
# Ausgänge gepuffert setzen, deutlich schneller als SD
|
||||||
|
# b CM ii ii 00000000 b = 16
|
||||||
|
|
||||||
|
# Berechtigung prüfen und ggf. trennen
|
||||||
|
if self._acl < 1:
|
||||||
|
self._devcon.sendall(b'\x18')
|
||||||
|
break
|
||||||
|
|
||||||
|
buff_recv.clear()
|
||||||
|
counter = netcmd[2]
|
||||||
|
try:
|
||||||
|
while counter > 0:
|
||||||
|
count = self._devcon.recv_into(buff_block, min(counter, buff_size))
|
||||||
|
if count == 0:
|
||||||
|
raise IOError("lost network connection")
|
||||||
|
buff_recv += buff_block[:count]
|
||||||
|
counter -= count
|
||||||
|
except Exception:
|
||||||
|
proginit.logger.error("error while recv data for fd write")
|
||||||
|
break
|
||||||
|
|
||||||
|
# Header: ppllbuff
|
||||||
|
index = 0
|
||||||
|
while index < netcmd[2]:
|
||||||
|
position, length = unpack("=HH", buff_recv[index: index + 4])
|
||||||
|
index += 4
|
||||||
|
|
||||||
if control == b'\x1d' and length > 0:
|
|
||||||
# Empfange Datenblock zu schreiben nach Meldung
|
|
||||||
buff_recv.clear()
|
|
||||||
try:
|
|
||||||
while length > 0:
|
|
||||||
count = self._devcon.recv_into(buff_block, min(length, buff_size))
|
|
||||||
if count == 0:
|
|
||||||
raise IOError("lost network connection")
|
|
||||||
buff_recv += buff_block[:count]
|
|
||||||
length -= count
|
|
||||||
except Exception:
|
|
||||||
proginit.logger.error("error while recv data to write")
|
|
||||||
self._writeerror = True
|
|
||||||
break
|
|
||||||
fh_proc.seek(position)
|
fh_proc.seek(position)
|
||||||
fh_proc.write(buff_recv)
|
fh_proc.write(buff_recv[index:index + length])
|
||||||
|
|
||||||
# Record seperator character
|
index += length
|
||||||
if control == b'\x1c':
|
|
||||||
# Bestätige Schreibvorgang aller Datenblöcke
|
# Record separator character
|
||||||
if self._writeerror:
|
self._devcon.sendall(b'\x1e')
|
||||||
self._devcon.sendall(b'\xff')
|
|
||||||
else:
|
|
||||||
self._devcon.sendall(b'\x1e')
|
|
||||||
self._writeerror = False
|
|
||||||
|
|
||||||
elif cmd == b'\x06\x16':
|
elif cmd == b'\x06\x16':
|
||||||
# Just sync
|
# Just sync
|
||||||
@@ -311,13 +338,9 @@ class RevPiSlaveDev(Thread):
|
|||||||
|
|
||||||
elif cmd == b'CF':
|
elif cmd == b'CF':
|
||||||
# Socket konfigurieren
|
# Socket konfigurieren
|
||||||
# bCMii0000000000b = 16
|
# b CM ii xx 00000000 b = 16
|
||||||
|
|
||||||
try:
|
timeoutms = netcmd[2]
|
||||||
timeoutms = int.from_bytes(netcmd[3:5], byteorder="little")
|
|
||||||
except Exception:
|
|
||||||
proginit.logger.error("can not convert timeout value")
|
|
||||||
break
|
|
||||||
|
|
||||||
if 0 < timeoutms <= 65535:
|
if 0 < timeoutms <= 65535:
|
||||||
self._deadtime = timeoutms / 1000
|
self._deadtime = timeoutms / 1000
|
||||||
@@ -326,7 +349,7 @@ class RevPiSlaveDev(Thread):
|
|||||||
"set socket timeout to {0}".format(self._deadtime)
|
"set socket timeout to {0}".format(self._deadtime)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Record seperator character
|
# Record separator character
|
||||||
self._devcon.sendall(b'\x1e')
|
self._devcon.sendall(b'\x1e')
|
||||||
else:
|
else:
|
||||||
proginit.logger.error("timeout value must be 0 to 65535")
|
proginit.logger.error("timeout value must be 0 to 65535")
|
||||||
@@ -335,16 +358,16 @@ class RevPiSlaveDev(Thread):
|
|||||||
|
|
||||||
elif cmd == b'EY':
|
elif cmd == b'EY':
|
||||||
# Bytes bei Verbindungsabbruch schreiben
|
# Bytes bei Verbindungsabbruch schreiben
|
||||||
# bCMiiiix0000000b = 16
|
# b CM ii ii x0000000 b = 16
|
||||||
|
|
||||||
# Berechtigung prüfen und ggf. trennen
|
# Berechtigung prüfen und ggf. trennen
|
||||||
if self._acl < 1:
|
if self._acl < 1:
|
||||||
self._devcon.sendall(b'\x18')
|
self._devcon.sendall(b'\x18')
|
||||||
break
|
break
|
||||||
|
|
||||||
position = int.from_bytes(netcmd[3:5], byteorder="little")
|
position = netcmd[2]
|
||||||
length = int.from_bytes(netcmd[5:7], byteorder="little")
|
length = netcmd[3]
|
||||||
control = netcmd[7:8]
|
control = netcmd[4][0]
|
||||||
|
|
||||||
ok_byte = b'\xff' if self.__doerror else b'\x1e'
|
ok_byte = b'\xff' if self.__doerror else b'\x1e'
|
||||||
|
|
||||||
@@ -352,7 +375,6 @@ class RevPiSlaveDev(Thread):
|
|||||||
# Alle Dirtybytes löschen
|
# Alle Dirtybytes löschen
|
||||||
self.ey_dict = {}
|
self.ey_dict = {}
|
||||||
|
|
||||||
# Record seperator character
|
|
||||||
self._devcon.sendall(ok_byte)
|
self._devcon.sendall(ok_byte)
|
||||||
proginit.logger.info("cleared all dirty bytes")
|
proginit.logger.info("cleared all dirty bytes")
|
||||||
|
|
||||||
@@ -362,7 +384,6 @@ class RevPiSlaveDev(Thread):
|
|||||||
if position in self.ey_dict:
|
if position in self.ey_dict:
|
||||||
del self.ey_dict[position]
|
del self.ey_dict[position]
|
||||||
|
|
||||||
# Record seperator character
|
|
||||||
self._devcon.sendall(ok_byte)
|
self._devcon.sendall(ok_byte)
|
||||||
proginit.logger.info(
|
proginit.logger.info(
|
||||||
"cleared dirty bytes on position {0}"
|
"cleared dirty bytes on position {0}"
|
||||||
@@ -386,7 +407,6 @@ class RevPiSlaveDev(Thread):
|
|||||||
|
|
||||||
self.ey_dict[position] = bytes(buff_recv)
|
self.ey_dict[position] = bytes(buff_recv)
|
||||||
|
|
||||||
# Record seperator character
|
|
||||||
self._devcon.sendall(ok_byte)
|
self._devcon.sendall(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}"
|
||||||
@@ -401,17 +421,18 @@ class RevPiSlaveDev(Thread):
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
with open(proginit.pargs.configrsc, "rb") as fh_pic:
|
with open(proginit.pargs.configrsc, "rb") as fh_pic:
|
||||||
# Komplette piCtory Datei senden
|
# Komplette piCtory Datei lesen
|
||||||
self._devcon.sendall(fh_pic.read())
|
buff = fh_pic.read()
|
||||||
|
|
||||||
|
self._devcon.sendall(pack("=I", len(buff)) + buff)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
proginit.logger.error(
|
proginit.logger.error(
|
||||||
"error on pictory transfair: {0}".format(e)
|
"error on pictory transfair: {0}".format(e)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
# End-of-Transmission character immer senden
|
# Laufzeitberechnung überspringen
|
||||||
self._devcon.sendall(b'\x04')
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
elif cmd == b'PH':
|
elif cmd == b'PH':
|
||||||
# piCtory md5 Hashwert senden (16 Byte)
|
# piCtory md5 Hashwert senden (16 Byte)
|
||||||
@@ -427,20 +448,25 @@ class RevPiSlaveDev(Thread):
|
|||||||
"".format(proginit.pargs.configrsc)
|
"".format(proginit.pargs.configrsc)
|
||||||
)
|
)
|
||||||
replace_ios = proginit.conf["DEFAULT"].get("replace_ios", "")
|
replace_ios = proginit.conf["DEFAULT"].get("replace_ios", "")
|
||||||
try:
|
if HASH_RPIO != HASH_NULL and replace_ios:
|
||||||
if HASH_RPIO != HASH_NULL and replace_ios:
|
try:
|
||||||
with open(replace_ios, "rb") as fh:
|
with open(replace_ios, "rb") as fh:
|
||||||
# Komplette replace_io Datei senden
|
# Komplette replace_io Datei lesen
|
||||||
self._devcon.sendall(fh.read())
|
buff = fh.read()
|
||||||
except Exception as e:
|
|
||||||
proginit.logger.error(
|
self._devcon.sendall(pack("=I", len(buff)) + buff)
|
||||||
"error on replace_io transfair: {0}".format(e)
|
except Exception as e:
|
||||||
)
|
proginit.logger.error(
|
||||||
break
|
"error on replace_io transfair: {0}".format(e)
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# End-of-Transmission character immer senden
|
# Nulllänge senden, damit client weiter machen kann
|
||||||
self._devcon.sendall(b'\x04')
|
self._devcon.sendall(b'\x00\x00\x00\x00')
|
||||||
continue
|
|
||||||
|
# Laufzeitberechnung überspringen
|
||||||
|
continue
|
||||||
|
|
||||||
elif cmd == b'RH':
|
elif cmd == b'RH':
|
||||||
# Replace_IOs md5 Hashwert senden (16 Byte)
|
# Replace_IOs md5 Hashwert senden (16 Byte)
|
||||||
@@ -459,10 +485,10 @@ class RevPiSlaveDev(Thread):
|
|||||||
|
|
||||||
elif cmd == b'IC':
|
elif cmd == b'IC':
|
||||||
# Net-IOCTL ausführen
|
# Net-IOCTL ausführen
|
||||||
# bCMiiiiii000000b = 16
|
# b CM xx ii iiii0000 b = 16
|
||||||
|
|
||||||
request = int.from_bytes(netcmd[3:7], byteorder="little")
|
request = unpack("=I4x", netcmd[4])[0]
|
||||||
length = int.from_bytes(netcmd[7:9], byteorder="little")
|
length = netcmd[3]
|
||||||
|
|
||||||
buff_recv.clear()
|
buff_recv.clear()
|
||||||
try:
|
try:
|
||||||
@@ -503,13 +529,13 @@ class RevPiSlaveDev(Thread):
|
|||||||
|
|
||||||
elif proginit.pargs.developermode and cmd == b'DV':
|
elif proginit.pargs.developermode and cmd == b'DV':
|
||||||
# Development options
|
# Development options
|
||||||
# bCMc00000000000b = 16
|
# b CM ii ii c0000000 b = 16
|
||||||
if self._acl < 9:
|
if self._acl < 9:
|
||||||
# Spezieller ACL-Wert für Entwicklung
|
# Spezieller ACL-Wert für Entwicklung
|
||||||
self._devcon.sendall(b'\x18')
|
self._devcon.sendall(b'\x18')
|
||||||
break
|
break
|
||||||
|
|
||||||
c = netcmd[3:4]
|
c = netcmd[4][0]
|
||||||
if c == b'a':
|
if c == b'a':
|
||||||
# CMD a = Switch ACL to 0
|
# CMD a = Switch ACL to 0
|
||||||
self._acl = 0
|
self._acl = 0
|
||||||
@@ -517,7 +543,7 @@ class RevPiSlaveDev(Thread):
|
|||||||
self._devcon.sendall(b'\x1e')
|
self._devcon.sendall(b'\x1e')
|
||||||
elif c == b'b':
|
elif c == b'b':
|
||||||
# CMD b = Aktiviert/Deaktiviert den Fehlermodus
|
# CMD b = Aktiviert/Deaktiviert den Fehlermodus
|
||||||
if netcmd[4:5] == b'\x01':
|
if netcmd[4][1] == b'\x01':
|
||||||
self.__doerror = True
|
self.__doerror = True
|
||||||
proginit.logger.warning("DV: set do_error")
|
proginit.logger.warning("DV: set do_error")
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user