Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions pymodbus/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,51 @@ def _set_adu_size(self):

def _calculate_response_length(self, expected_pdu_size):
if self.base_adu_size == -1:
return 1024
return None
else:
return self.base_adu_size + expected_pdu_size

def _calculate_exception_length(self):
''' Returns the length of the Modbus Exception Response according to
the type of Framer.
'''
if isinstance(self.client.framer, ModbusSocketFramer):
return self.base_adu_size + 2 # Fcode(1), ExcecptionCode(1)
elif isinstance(self.client.framer, ModbusAsciiFramer):
return self.base_adu_size + 4 # Fcode(2), ExcecptionCode(2)
elif isinstance(self.client.framer, (ModbusRtuFramer, ModbusBinaryFramer)):
return self.base_adu_size + 2 # Fcode(1), ExcecptionCode(1)

return None

def _check_response(self, response):
''' Checks if the response is a Modbus Exception.
'''
if isinstance(self.client.framer, ModbusSocketFramer):
if len(response) >= 8 and byte2int(response[7]) > 128:
return False
elif isinstance(self.client.framer, ModbusAsciiFramer):
if len(response) >= 5 and int(response[3:5], 16) > 128:
return False
elif isinstance(self.client.framer, (ModbusRtuFramer, ModbusBinaryFramer)):
if len(response) >= 2 and byte2int(response[1]) > 128:
return False

return True

def execute(self, request):
''' Starts the producer to send the next request to
consumer.write(Frame(request))
'''
retries = self.retries
request.transaction_id = self.getNextTID()
_logger.debug("Running transaction %d" % request.transaction_id)

expected_response_length = None
if hasattr(request, "get_response_pdu_size"):
response_pdu_size = request.get_response_pdu_size()
expected_response_length = self._calculate_response_length(response_pdu_size)
else:
expected_response_length = 1024
if response_pdu_size:
expected_response_length = self._calculate_response_length(response_pdu_size)

while retries > 0:
try:
Expand All @@ -92,11 +121,20 @@ def execute(self, request):
if _logger.isEnabledFor(logging.DEBUG):
_logger.debug("send: " + " ".join([hex(byte2int(x)) for x in packet]))
self.client._send(packet)
result = self.client._recv(expected_response_length)

exception = False
result = self.client._recv(expected_response_length or 1024)
while result and expected_response_length and len(result) < expected_response_length:
if not exception and not self._check_response(result):
exception = True
expected_response_length = self._calculate_exception_length()
continue
result += self.client._recv(expected_response_length - len(result))

if not result and self.retry_on_empty:
retries -= 1
continue

if _logger.isEnabledFor(logging.DEBUG):
_logger.debug("recv: " + " ".join([hex(byte2int(x)) for x in result]))
self.client.framer.processIncomingPacket(result, self.addTransaction)
Expand Down