Skip to content

Commit

Permalink
SOCKET/TLS framer using message decode(). (#2129)
Browse files Browse the repository at this point in the history
  • Loading branch information
janiversen committed Jun 18, 2024
1 parent b187401 commit 1cfc681
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 61 deletions.
44 changes: 11 additions & 33 deletions pymodbus/framer/socket_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,47 +72,25 @@ def frameProcessIncomingPacket(self, single, callback, slave, tid=None, **kwargs
The processed and decoded messages are pushed to the callback
function to process and send.
"""
def check_frame(self):
"""Check and decode the next frame."""
if not self._buffer:
Log.debug("Frame check, no more data!")
return False
if not len(self._buffer) >= self._hsize +1:
Log.debug("Frame check failed, short frame {} >= {} !!", len(self._buffer), self._hsize+2)
return False
(
self._header["tid"],
self._header["pid"],
self._header["len"],
self._header["uid"],
) = struct.unpack(">HHHB", self._buffer[0 : self._hsize])
if self._header["len"] == 2 and len(self._buffer) >= self._hsize + 2:
self._header["len"] = 3
if self._header["len"] < 2:
length = self._hsize + self._header["len"] -1
self._buffer = self._buffer[length:]
self._header = {"tid": 0, "pid": 0, "len": 0, "uid": 0}
elif len(self._buffer) - self._hsize + 1 >= self._header["len"]:
return True
Log.debug("Frame check failed, missing part of message len {}, MBAP len {} !!", len(self._buffer), self._header["len"])
return False

while True:
if not check_frame(self):
return
used_len, use_tid, dev_id, data = self.message_handler.decode(self._buffer)
if not data:
if not used_len:
return
self._buffer = self._buffer[used_len :]
continue
self._header["uid"] = dev_id
self._header["tid"] = use_tid
self._header["pid"] = 0
if not self._validate_slave_id(slave, single):
header_txt = self._header["uid"]
Log.debug("Not a valid slave id - {}, ignoring!!", header_txt)
Log.debug("Not a valid slave id - {}, ignoring!!", dev_id)
self.resetFrame()
return
length = self._hsize + self._header["len"] -1
data = self._buffer[self._hsize : length]
if (result := self.decoder.decode(data)) is None:
self.resetFrame()
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
length = self._hsize + self._header["len"] -1
self._buffer = self._buffer[length:]
self._buffer = self._buffer[used_len:]
self._header = {"tid": 0, "pid": 0, "len": 0, "uid": 0}
if tid and tid != result.transaction_id:
self.resetFrame()
Expand Down
52 changes: 24 additions & 28 deletions pymodbus/framer/tls_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, decoder, client=None):
"""
super().__init__(decoder, client)
self._hsize = 0x0
self.message_encoder = MessageTLS([0], True)
self.message_handler = MessageTLS([0], True)

def decode_data(self, data):
"""Decode data."""
Expand All @@ -47,38 +47,34 @@ def decode_data(self, data):
def frameProcessIncomingPacket(self, single, callback, slave, _tid=None, **kwargs):
"""Process new packet pattern."""
# no slave id for Modbus Security Application Protocol
def check_frame(self):
"""Check and decode the next frame."""
if len(self._buffer) > self._hsize:
# we have at least a complete message, continue
if len(self._buffer) - self._hsize >= 1:
return True
# we don't have enough of a message yet, wait
return False

if not len(self._buffer) > self._hsize:
return
if not check_frame(self):
Log.debug("Frame check failed, ignoring!!")
self.resetFrame()
return
if not self._validate_slave_id(slave, single):
Log.debug("Not in valid slave id - {}, ignoring!!", slave)
self.resetFrame()
return
data = self._buffer[self._hsize :]
if (result := self.decoder.decode(data)) is None:
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
self._buffer = b""
self._header = {}
callback(result) # defer or push to a thread?

while True:
used_len, use_tid, dev_id, data = self.message_handler.decode(self._buffer)
if not data:
if not used_len:
return
self._buffer = self._buffer[used_len :]
continue
self._header["uid"] = dev_id
self._header["tid"] = use_tid
self._header["pid"] = 0

if not self._validate_slave_id(slave, single):
Log.debug("Not in valid slave id - {}, ignoring!!", slave)
self.resetFrame()
return
if (result := self.decoder.decode(data)) is None:
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
self._buffer = b""
self._header = {}
callback(result) # defer or push to a thread?

def buildPacket(self, message):
"""Create a ready to send modbus packet.
:param message: The populated request/response to send
"""
data = message.function_code.to_bytes(1,'big') + message.encode()
packet = self.message_encoder.encode(data, message.slave_id, message.transaction_id)
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
return packet

0 comments on commit 1cfc681

Please sign in to comment.