Skip to content

Commit

Permalink
fix #165, #174, #169, #175, #147, #146
Browse files Browse the repository at this point in the history
  • Loading branch information
dhoomakethu committed Jun 22, 2017
1 parent 4d96b95 commit f5f9f2c
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 25 deletions.
15 changes: 15 additions & 0 deletions pymodbus/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ def __init__(self, string=""):
message = "[Connection] %s" % string
ModbusException.__init__(self, message)


class InvalidResponseRecievedException(ModbusException):
"""
Error resulting from invalid response received or decoded
"""


def __init__(self, string=""):
''' Initialize the exception
:param string: The message to append to the error
'''
message = "[Invalid Response] %s" % string
ModbusException.__init__(self, message)

#---------------------------------------------------------------------------#
# Exported symbols
#---------------------------------------------------------------------------#
Expand Down
10 changes: 8 additions & 2 deletions pymodbus/mei_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pymodbus.device import ModbusControlBlock
from pymodbus.device import DeviceInformationFactory
from pymodbus.pdu import ModbusExceptions as merror
from pymodbus.compat import iteritems, byte2int
from pymodbus.compat import iteritems, byte2int, IS_PYTHON3

_MCB = ModbusControlBlock()

Expand Down Expand Up @@ -132,7 +132,13 @@ def encode(self):

for (object_id, data) in iteritems(self.information):
packet += struct.pack('>BB', object_id, len(data))
packet += data.encode()
if IS_PYTHON3:
if isinstance(data, bytes):
packet += data
else:
packet += data.encode()
else:
packet += data.encode()
return packet

def decode(self, data):
Expand Down
23 changes: 13 additions & 10 deletions pymodbus/other_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def decode(self, data):
'''
pass

def execute(self):
def execute(self, context=None):
''' Run a read exeception status request against the store
:returns: The populated response
Expand Down Expand Up @@ -144,7 +144,7 @@ def decode(self, data):
'''
pass

def execute(self):
def execute(self, context=None):
''' Run a read exeception status request against the store
:returns: The populated response
Expand Down Expand Up @@ -249,7 +249,7 @@ def decode(self, data):
'''
pass

def execute(self):
def execute(self, context=None):
''' Run a read exeception status request against the store
:returns: The populated response
Expand Down Expand Up @@ -359,12 +359,12 @@ def decode(self, data):
'''
pass

def execute(self):
def execute(self, context=None):
''' Run a read exeception status request against the store
:returns: The populated response
'''
identifier = b'\x70\x79\x6d\x6f\x64\x62\x75\x73'
identifier = b'Pymodbus'
return ReportSlaveIdResponse(identifier)

def __str__(self):
Expand Down Expand Up @@ -392,14 +392,17 @@ def __init__(self, identifier=b'\x00', status=True, **kwargs):
ModbusResponse.__init__(self, **kwargs)
self.identifier = identifier
self.status = status
self.byte_count = None

def encode(self):
''' Encodes the response
:returns: The byte encoded message
'''
if self.status: status = ModbusStatus.SlaveOn
else: status = ModbusStatus.SlaveOff
if self.status:
status = ModbusStatus.SlaveOn
else:
status = ModbusStatus.SlaveOff
length = len(self.identifier) + 2
packet = int2byte(length)
packet += self.identifier # we assume it is already encoded
Expand All @@ -414,8 +417,8 @@ def decode(self, data):
:param data: The packet data to decode
'''
length = byte2int(data[0])
self.identifier = data[1:length + 1]
self.byte_count = byte2int(data[0])
self.identifier = data[1:self.byte_count + 1]
status = byte2int(data[-1])
self.status = status == ModbusStatus.SlaveOn

Expand All @@ -425,7 +428,7 @@ def __str__(self):
:returns: The string representation of the response
'''
arguments = (self.function_code, self.identifier, self.status)
return "ResportSlaveIdResponse(%d, %d, %d)" % arguments
return "ResportSlaveIdResponse(%s, %s, %s)" % arguments

#---------------------------------------------------------------------------#
# TODO Make these only work on serial
Expand Down
38 changes: 26 additions & 12 deletions pymodbus/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from binascii import b2a_hex, a2b_hex

from pymodbus.exceptions import ModbusIOException, NotImplementedException
from pymodbus.exceptions import InvalidResponseRecievedException
from pymodbus.constants import Defaults
from pymodbus.interfaces import IModbusFramer
from pymodbus.utilities import checkCRC, computeCRC
Expand Down Expand Up @@ -107,7 +108,6 @@ def execute(self, 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()
Expand All @@ -116,12 +116,12 @@ def execute(self, request):

while retries > 0:
try:
last_exception = None
self.client.connect()
packet = self.client.framer.buildPacket(request)
if _logger.isEnabledFor(logging.DEBUG):
_logger.debug("send: " + " ".join([hex(byte2int(x)) for x in packet]))
self.client._send(packet)

exception = False
result = self.client._recv(expected_response_length or 1024)
while result and expected_response_length and len(result) < expected_response_length:
Expand All @@ -139,12 +139,18 @@ def execute(self, request):
_logger.debug("recv: " + " ".join([hex(byte2int(x)) for x in result]))
self.client.framer.processIncomingPacket(result, self.addTransaction)
break
except socket.error as msg:
except (socket.error, ModbusIOException, InvalidResponseRecievedException) as msg:
self.client.close()
_logger.debug("Transaction failed. (%s) " % msg)
retries -= 1
return self.getTransaction(request.transaction_id)
last_exception = msg
response = self.getTransaction(request.transaction_id)
if not response:
last_exception = last_exception or ("No Response "
"received from the remote unit")
response = ModbusIOException(last_exception)

return response

def addTransaction(self, request, tid=None):
''' Adds a transaction to the handler
Expand Down Expand Up @@ -432,9 +438,12 @@ def _process(self, callback, error=False):
result = self.decoder.decode(data)
if result is None:
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
self.advanceFrame()
callback(result) # defer or push to a thread?
elif error and result.function_code < 0x80:
raise InvalidResponseRecievedException(result)
else:
self.populateResult(result)
self.advanceFrame()
callback(result) # defer or push to a thread?

def resetFrame(self):
''' Reset the entire message frame.
Expand Down Expand Up @@ -670,9 +679,12 @@ def _process(self, callback, error=False):
result = self.decoder.decode(data)
if result is None:
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
self.advanceFrame()
callback(result) # defer or push to a thread?
elif error and result.function_code < 0x80:
raise InvalidResponseRecievedException(result)
else:
self.populateResult(result)
self.advanceFrame()
callback(result) # defer or push to a thread?

def getRawFrame(self):
"""
Expand Down Expand Up @@ -811,7 +823,8 @@ def processIncomingPacket(self, data, callback):
self.populateResult(result)
self.advanceFrame()
callback(result) # defer this
else: break
else:
break

def buildPacket(self, message):
''' Creates a ready to send modbus packet
Expand Down Expand Up @@ -972,7 +985,8 @@ def processIncomingPacket(self, data, callback):
self.populateResult(result)
self.advanceFrame()
callback(result) # defer or push to a thread?
else: break
else:
break

def buildPacket(self, message):
''' Creates a ready to send modbus packet
Expand Down
2 changes: 1 addition & 1 deletion test/test_other_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def testReportSlaveId(self):
self.assertEqual(request.execute().function_code, 0x11)

response = ReportSlaveIdResponse(request.execute().identifier, True)
self.assertEqual(response.encode(), b'\x0apymodbus\xff')
self.assertEqual(response.encode(), b'\x0aPymodbus\xff')
response.decode(b'\x03\x12\x00')
self.assertEqual(response.status, False)
self.assertEqual(response.identifier, b'\x12\x00')
Expand Down

0 comments on commit f5f9f2c

Please sign in to comment.