From 5900b66866601dd9af33806a94a0a6286aa43e19 Mon Sep 17 00:00:00 2001 From: "Mark M. Evans" Date: Tue, 20 Oct 2015 12:05:44 -0700 Subject: [PATCH 1/6] Riptide 1.3.0 pymodbus internal pre-release (riptide1) with dhoomakethu's fix for bashwork#101. --- .gitignore | 2 ++ pymodbus/version.py | 7 ++++--- requirements.txt | 17 +++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 5ba77b1e9..6a2ab17a7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ build/ dist/ pymodbus.egg-info/ .coverage +*env/ +.idea/ diff --git a/pymodbus/version.py b/pymodbus/version.py index c002097b4..3c7aafe98 100644 --- a/pymodbus/version.py +++ b/pymodbus/version.py @@ -9,7 +9,7 @@ class Version(object): - def __init__(self, package, major, minor, micro): + def __init__(self, package, major, minor, micro, pre=""): ''' :param package: Name of the package that this is a version of. @@ -21,12 +21,13 @@ def __init__(self, package, major, minor, micro): self.major = major self.minor = minor self.micro = micro + self.pre = pre def short(self): ''' Return a string in canonical short version format .. ''' - return '%d.%d.%d' % (self.major, self.minor, self.micro) + return '%d.%d.%d%s' % (self.major, self.minor, self.micro, self.pre) def __str__(self): ''' Returns a string representation of the object @@ -35,7 +36,7 @@ def __str__(self): ''' return '[%s, version %s]' % (self.package, self.short()) -version = Version('pymodbus', 1, 3, 0) +version = Version('pymodbus', 1, 3, 0, "riptide1") version.__name__ = 'pymodbus' # fix epydoc error #---------------------------------------------------------------------------# diff --git a/requirements.txt b/requirements.txt index 39d95377b..5eb9b6bcf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,17 +5,18 @@ # ------------------------------------------------------------------- # if you want to run the tests and code coverage, uncomment these # ------------------------------------------------------------------- -#coverage==3.5.3 -#mock==1.0b1 -#nose==1.2.1 -#pep8==1.3.3 +coverage>=3.5.3 +mock>=1.0b1 +nose>=1.2.1 +pep8>=1.3.3 +-e . # ------------------------------------------------------------------- # if you want to use the asynchronous version, uncomment these # ------------------------------------------------------------------- -#Twisted==12.2.0 -#zope.interface==4.0.1 -#pyasn1==0.1.4 -#pycrypto==2.6 +Twisted==15.2.1 +zope.interface==4.1.2 +pyasn1==0.1.7 +pycrypto==2.6.1 #wsgiref==0.1.2 # ------------------------------------------------------------------- # if you want to build the documentation, uncomment these From d42fc9dbe465c5e8cac0067f0f67d0ee167d9a89 Mon Sep 17 00:00:00 2001 From: "Mark M. Evans" Date: Tue, 20 Oct 2015 12:15:40 -0700 Subject: [PATCH 2/6] Use a PEP 404 compliant version. Start at rc93101 to usurp any other real release candidates. --- pymodbus/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymodbus/version.py b/pymodbus/version.py index 3c7aafe98..b2c26da95 100644 --- a/pymodbus/version.py +++ b/pymodbus/version.py @@ -36,7 +36,7 @@ def __str__(self): ''' return '[%s, version %s]' % (self.package, self.short()) -version = Version('pymodbus', 1, 3, 0, "riptide1") +version = Version('pymodbus', 1, 3, 0, "rc93101") version.__name__ = 'pymodbus' # fix epydoc error #---------------------------------------------------------------------------# From 742365a3c8f97f79ce6ea1dcdaef0051b058fbea Mon Sep 17 00:00:00 2001 From: "Mark M. Evans" Date: Tue, 20 Oct 2015 21:14:08 -0700 Subject: [PATCH 3/6] Include Workaround for bug 101 bashwork#101 --- pymodbus/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymodbus/version.py b/pymodbus/version.py index b2c26da95..421863b0a 100644 --- a/pymodbus/version.py +++ b/pymodbus/version.py @@ -36,7 +36,7 @@ def __str__(self): ''' return '[%s, version %s]' % (self.package, self.short()) -version = Version('pymodbus', 1, 3, 0, "rc93101") +version = Version('pymodbus', 1, 3, 0, "rc93102") version.__name__ = 'pymodbus' # fix epydoc error #---------------------------------------------------------------------------# From 548917015ef0337a49721f16b7fc2b5048261162 Mon Sep 17 00:00:00 2001 From: dhoomakethu Date: Fri, 20 Nov 2015 12:40:12 -0800 Subject: [PATCH 4/6] version bumped to c93103 --- pymodbus/transaction.py | 50 ++++++++++++++++++++++++++++++++--------- pymodbus/version.py | 2 +- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/pymodbus/transaction.py b/pymodbus/transaction.py index 2c5b393b4..71cc79b3d 100644 --- a/pymodbus/transaction.py +++ b/pymodbus/transaction.py @@ -343,7 +343,6 @@ def processIncomingPacket(self, data, callback): :param data: The new packet data :param callback: The function to send results to ''' - _logger.debug(" ".join([hex(ord(x)) for x in data])) self.addToFrame(data) while True: if self.isFrameReady(): @@ -474,7 +473,11 @@ def advanceFrame(self): it or determined that it contains an error. It also has to reset the current frame header handle ''' - self.__buffer = self.__buffer[self.__header['len']:] + try: + self.__buffer = self.__buffer[self.__header['len']:] + except KeyError: + # Error response, no header len found + self.resetFrame() self.__header = {} def resetFrame(self): @@ -563,15 +566,21 @@ def processIncomingPacket(self, data, callback): :param callback: The function to send results to ''' self.addToFrame(data) - while self.isFrameReady(): - if self.checkFrame(): - result = self.decoder.decode(self.getFrame()) - if result is None: - raise ModbusIOException("Unable to decode response") - self.populateResult(result) - self.advanceFrame() - callback(result) # defer or push to a thread? - else: self.resetFrame() # clear possible errors + while True: + if self.isFrameReady(): + if self.checkFrame(): + self._process(callback) + else: + # Could be an error response + if len(self.__buffer): + # Possible error ??? + self._process(callback, error=True) + else: + if len(self.__buffer): + # Possible error ??? + if self.__header['len'] < 2: + self._process(callback, error=True) + break def buildPacket(self, message): ''' Creates a ready to send modbus packet @@ -585,6 +594,25 @@ def buildPacket(self, message): packet += struct.pack(">H", computeCRC(packet)) return packet + def _process(self, callback, error=False): + """ + Process incoming packets irrespective error condition + """ + data = self.getRawFrame() if error else self.getFrame() + 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? + + def getRawFrame(self): + """ + Returns the complete buffer + """ + return self.__buffer + + #---------------------------------------------------------------------------# # Modbus ASCII Message diff --git a/pymodbus/version.py b/pymodbus/version.py index 421863b0a..6b93b6977 100644 --- a/pymodbus/version.py +++ b/pymodbus/version.py @@ -36,7 +36,7 @@ def __str__(self): ''' return '[%s, version %s]' % (self.package, self.short()) -version = Version('pymodbus', 1, 3, 0, "rc93102") +version = Version('pymodbus', 1, 3, 0, "rc93103") version.__name__ = 'pymodbus' # fix epydoc error #---------------------------------------------------------------------------# From 3033e0871af1dcedf06c8bd6f752fc3bee6409da Mon Sep 17 00:00:00 2001 From: dhoomakethu Date: Wed, 23 Dec 2015 15:28:13 +0530 Subject: [PATCH 5/6] fixed issue with pymodbus timing over serial --- pymodbus/bit_read_message.py | 4 +++- pymodbus/bit_write_message.py | 3 ++- pymodbus/file_message.py | 7 +++++-- pymodbus/register_read_message.py | 6 ++++-- pymodbus/register_write_message.py | 2 ++ pymodbus/transaction.py | 27 +++++++++++++++++++++++++-- pymodbus/version.py | 2 +- 7 files changed, 42 insertions(+), 9 deletions(-) diff --git a/pymodbus/bit_read_message.py b/pymodbus/bit_read_message.py index f0dd6e312..72cb988df 100644 --- a/pymodbus/bit_read_message.py +++ b/pymodbus/bit_read_message.py @@ -14,6 +14,7 @@ class ReadBitsRequestBase(ModbusRequest): ''' Base class for Messages Requesting bit values ''' _rtu_frame_size = 8 + _pdu_length = 2 # func + bytcodeLen def __init__(self, address, count, **kwargs): ''' Initializes the read request data @@ -23,7 +24,8 @@ def __init__(self, address, count, **kwargs): ''' ModbusRequest.__init__(self, **kwargs) self.address = address - self.count = count + self.count = count + self._pdu_length += count def encode(self): ''' Encodes a request pdu diff --git a/pymodbus/bit_write_message.py b/pymodbus/bit_write_message.py index 64f291daf..4c62b48e0 100644 --- a/pymodbus/bit_write_message.py +++ b/pymodbus/bit_write_message.py @@ -39,6 +39,7 @@ class WriteSingleCoilRequest(ModbusRequest): ''' function_code = 5 _rtu_frame_size = 8 + _pdu_length = 5 # func + adress1 + adress2 + value1+value2 def __init__(self, address=None, value=None, **kwargs): ''' Initializes a new instance @@ -148,7 +149,7 @@ class WriteMultipleCoilsRequest(ModbusRequest): ''' function_code = 15 _rtu_byte_count_pos = 6 - + _pdu_length = 5 # func + adress1 + adress2 + outputQuant1 + outputQuant2 def __init__(self, address=None, values=None, **kwargs): ''' Initializes a new instance diff --git a/pymodbus/file_message.py b/pymodbus/file_message.py index 366517cef..85edb7d89 100644 --- a/pymodbus/file_message.py +++ b/pymodbus/file_message.py @@ -31,8 +31,10 @@ def __init__(self, **kwargs): self.file_number = kwargs.get('file_number', 0x00) self.record_number = kwargs.get('record_number', 0x00) self.record_data = kwargs.get('record_data', '') - self.record_length = kwargs.get('record_length', len(self.record_data) / 2) - self.response_length = kwargs.get('response_length', len(self.record_data) + 1) + self.record_length = kwargs.get('record_length', + len(self.record_data) / 2) + self.response_length = kwargs.get('response_length', + len(self.record_data) + 1) def __eq__(self, relf): ''' Compares the left object to the right @@ -286,6 +288,7 @@ class MaskWriteRegisterRequest(ModbusRequest): ''' function_code = 0x16 _rtu_frame_size = 10 + _pdu_length = 7 # func + adress1 + adress2 + andMaskHi + andMaskLo + orMaskHi + orMaskLo def __init__(self, address=0x0000, and_mask=0xffff, or_mask=0x0000, **kwargs): ''' Initializes a new instance diff --git a/pymodbus/register_read_message.py b/pymodbus/register_read_message.py index 06d82925f..fa27a86d9 100644 --- a/pymodbus/register_read_message.py +++ b/pymodbus/register_read_message.py @@ -13,6 +13,7 @@ class ReadRegistersRequestBase(ModbusRequest): Base class for reading a modbus register ''' _rtu_frame_size = 8 + _pdu_length = 2 #func + bytcodeLen def __init__(self, address, count, **kwargs): ''' Initializes a new instance @@ -23,7 +24,7 @@ def __init__(self, address, count, **kwargs): ModbusRequest.__init__(self, **kwargs) self.address = address self.count = count - + self._pdu_length += 2*count def encode(self): ''' Encodes the request packet @@ -213,7 +214,7 @@ class ReadWriteMultipleRegistersRequest(ModbusRequest): ''' function_code = 23 _rtu_byte_count_pos = 10 - + _pdu_length = 2 #func + bytcodeLen def __init__(self, **kwargs): ''' Initializes a new request message @@ -231,6 +232,7 @@ def __init__(self, **kwargs): self.write_registers = [self.write_registers] self.write_count = len(self.write_registers) self.write_byte_count = self.write_count * 2 + self._pdu_length+=2*count #slave + func + bytcodeLen + bytecode x 2 + crc1 + crc2 def encode(self): ''' Encodes the request packet diff --git a/pymodbus/register_write_message.py b/pymodbus/register_write_message.py index b49db4901..bc13c4a56 100644 --- a/pymodbus/register_write_message.py +++ b/pymodbus/register_write_message.py @@ -19,6 +19,7 @@ class WriteSingleRegisterRequest(ModbusRequest): ''' function_code = 6 _rtu_frame_size = 8 + _pdu_length = 5 # func + adress1 + adress2 + outputQuant1 + outputQuant2 def __init__(self, address=None, value=None, **kwargs): ''' Initializes a new instance @@ -123,6 +124,7 @@ class WriteMultipleRegistersRequest(ModbusRequest): ''' function_code = 16 _rtu_byte_count_pos = 6 + _pdu_length = 5 #func + adress1 + adress2 + outputQuant1 + outputQuant2 def __init__(self, address=None, values=None, **kwargs): ''' Initializes a new instance diff --git a/pymodbus/transaction.py b/pymodbus/transaction.py index 71cc79b3d..b2a6bfa4b 100644 --- a/pymodbus/transaction.py +++ b/pymodbus/transaction.py @@ -49,6 +49,26 @@ def __init__(self, client, **kwargs): self.client = client self.retry_on_empty = kwargs.get('retry_on_empty', Defaults.RetryOnEmpty) self.retries = kwargs.get('retries', Defaults.Retries) + self._set_adu_size() + + def _set_adu_size(self): + # base ADU size of modbus frame in bytes + if isinstance(self.client.framer, ModbusSocketFramer): + self.base_adu_size = 7 # tid(2), pid(2), length(2), uid(1) + elif isinstance(self.client.framer, ModbusRtuFramer): + self.base_adu_size = 3 # address(1), CRC(2) + elif isinstance(self.client.framer, ModbusAsciiFramer): + self.base_adu_size = 4 # Address(2), LRC(2) + elif isinstance(self.client.framer, ModbusBinaryFramer): + self.base_adu_size = 3 #, Address(1), CRC(2) + else: + self.base_adu_size = -1 + + def _calculate_response_length(self, expected_pdu_size): + if self.base_adu_size == -1: + return 1024 + else: + return self.base_adu_size + expected_pdu_size def execute(self, request): ''' Starts the producer to send the next request to @@ -57,7 +77,7 @@ def execute(self, request): retries = self.retries request.transaction_id = self.getNextTID() _logger.debug("Running transaction %d" % request.transaction_id) - + expected_response_length = self._calculate_response_length(request._pdu_length) while retries > 0: try: self.client.connect() @@ -65,7 +85,9 @@ def execute(self, request): # I need to fix this to read the header and the result size, # as this may not read the full result set, but right now # it should be fine... - result = self.client._recv(1024) + + result = self.client._recv(expected_response_length) + # result = self.client._recv(1024) if not result and self.retry_on_empty: retries -= 1 continue @@ -79,6 +101,7 @@ def execute(self, request): retries -= 1 return self.getTransaction(request.transaction_id) + def addTransaction(self, request, tid=None): ''' Adds a transaction to the handler diff --git a/pymodbus/version.py b/pymodbus/version.py index 6b93b6977..873672bd0 100644 --- a/pymodbus/version.py +++ b/pymodbus/version.py @@ -36,7 +36,7 @@ def __str__(self): ''' return '[%s, version %s]' % (self.package, self.short()) -version = Version('pymodbus', 1, 3, 0, "rc93103") +version = Version('pymodbus', 1, 3, 0, "rc93104") version.__name__ = 'pymodbus' # fix epydoc error #---------------------------------------------------------------------------# From b908d955dc0db5657c69cb0529e924f2f5b895fe Mon Sep 17 00:00:00 2001 From: dhoomakethu Date: Wed, 23 Dec 2015 21:58:30 +0530 Subject: [PATCH 6/6] Add RIPTIDE.md to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6a2ab17a7..b6695b6b1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ pymodbus.egg-info/ .coverage *env/ .idea/ +RIPTIDE.md