Skip to content

Commit

Permalink
Allowing overloading of message encoding
Browse files Browse the repository at this point in the history
* allow codes like payload builder to encode
* added IPayloadBuilder interface (future)
* renamed builder methods to reflect vision
* added error code decoding to name
* fixed affected tests
  • Loading branch information
bashwork committed Sep 27, 2012
1 parent f96541d commit 044acb0
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 109 deletions.
30 changes: 15 additions & 15 deletions doc/quality/current.coverage
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
Name Stmts Miss Cover Missing
---------------------------------------------------------------
pymodbus 15 2 87% 36-37
pymodbus 15 6 60% 24-27, 36-37
pymodbus.bit_read_message 68 0 100%
pymodbus.bit_write_message 95 0 100%
pymodbus.client 0 0 100%
pymodbus.client.async 68 0 100%
pymodbus.client.common 45 0 100%
pymodbus.client.sync 148 0 100%
pymodbus.client.async 70 0 100%
pymodbus.client.common 36 0 100%
pymodbus.client.sync 147 0 100%
pymodbus.constants 36 0 100%
pymodbus.datastore 5 0 100%
pymodbus.datastore.context 50 0 100%
Expand All @@ -18,24 +18,24 @@ pymodbus.events 60 0 100%
pymodbus.exceptions 22 0 100%
pymodbus.factory 77 0 100%
pymodbus.file_message 181 0 100%
pymodbus.interfaces 43 0 100%
pymodbus.interfaces 46 0 100%
pymodbus.internal 0 0 100%
pymodbus.internal.ptwisted 16 10 38% 26-37
pymodbus.mei_message 68 0 100%
pymodbus.internal.ptwisted 16 2 88% 29-30
pymodbus.mei_message 70 0 100%
pymodbus.other_message 145 0 100%
pymodbus.payload 134 0 100%
pymodbus.pdu 66 0 100%
pymodbus.payload 140 2 99% 205, 224
pymodbus.pdu 72 0 100%
pymodbus.register_read_message 124 0 100%
pymodbus.register_write_message 87 0 100%
pymodbus.register_write_message 91 2 98% 39, 148
pymodbus.server 0 0 100%
pymodbus.server.async 107 75 30% 40-41, 48, 55-57, 64-73, 80-84, 108-115, 135-142, 149-153, 160-169, 177-180, 192-199, 208-214, 227-238
pymodbus.server.sync 184 0 100%
pymodbus.transaction 263 51 81% 54-72, 240, 244, 384, 414-423, 558-567, 637, 714-723, 749-750
pymodbus.server.async 113 39 65% 55-58, 65-74, 81-86, 151-156, 163-172, 180-184
pymodbus.server.sync 186 0 100%
pymodbus.transaction 275 53 81% 63-81, 116-117, 259, 263, 403, 433-442, 577-586, 656, 733-742, 768-769
pymodbus.utilities 67 0 100%
pymodbus.version 13 0 100%
---------------------------------------------------------------
TOTAL 2646 138 95%
TOTAL 2679 104 96%
----------------------------------------------------------------------
Ran 249 tests in 1.448s
Ran 255 tests in 0.981s

OK
3 changes: 3 additions & 0 deletions doc/sphinx/library/interfaces.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ API Documentation

.. autoclass:: IModbusSlaveContext
:members:

.. autoclass:: IPayloadBuilder
:members:
4 changes: 2 additions & 2 deletions doc/sphinx/library/payload.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ API Documentation

.. automodule:: pymodbus.payload

.. autoclass:: PayloadBuilder
.. autoclass:: BinaryPayloadBuilder
:members:

.. autoclass:: PayloadDecoder
.. autoclass:: BinaryPayloadDecoder
:members:
44 changes: 28 additions & 16 deletions examples/common/modbus-payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@
--------------------------------------------------------------------------
'''
from pymodbus.constants import Endian
from pymodbus.payload import PayloadDecoder
from pymodbus.payload import PayloadBuilder
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.client.sync import ModbusTcpClient as ModbusClient

#---------------------------------------------------------------------------#
# configure the client logging
#---------------------------------------------------------------------------#
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.INFO)

#---------------------------------------------------------------------------#
# We are going to use a simple client to send our requests
#---------------------------------------------------------------------------#
Expand All @@ -27,15 +35,15 @@
# - an 8 bit int 0x12
# - an 8 bit bitstring [0,1,0,1,1,0,1,0]
#---------------------------------------------------------------------------#
builder = PayloadBuilder(endian=Endian.Little)
builder = BinaryPayloadBuilder(endian=Endian.Little)
builder.add_string('abcdefgh')
builder.add_32bit_float(22.34)
builder.add_16bit_uint(0x1234)
builder.add_8bit_int(0x12)
builder.add_bites([0,1,0,1,1,0,1,0])
payload = builder.tolist()
builder.add_bits([0,1,0,1,1,0,1,0])
payload = builder.build()
address = 0x01
result = client.write_registers(address, payload)
result = client.write_registers(address, payload, skip_encode=True)

#---------------------------------------------------------------------------#
# If you need to decode a collection of registers in a weird layout, the
Expand All @@ -53,16 +61,20 @@
address = 0x01
count = 8
result = client.read_input_registers(address, count)
decoder = PayloadDecoder.fromRegisters(result.registers, endian=Endian.Little)
decoded = [
decoder.decode_string(8),
decoder.decode_32bit_float(),
decoder.decode_16bit_uint(),
decoder.decode_8bit_int(),
decoder.decode_bits(),
]
for decode in decoded:
print decode
decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little)
decoded = {
'string': decoder.decode_string(8),
'float': decoder.decode_32bit_float(),
'16uint': decoder.decode_16bit_uint(),
'8int': decoder.decode_8bit_int(),
'bits': decoder.decode_bits(),
}

print "-" * 60
print "Decoded Data"
print "-" * 60
for name, value in decoded.items():
print ("%s\t" % name), value

#---------------------------------------------------------------------------#
# close the client
Expand Down
49 changes: 22 additions & 27 deletions pymodbus/client/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from pymodbus.diag_message import *
from pymodbus.file_message import *
from pymodbus.other_message import *
from pymodbus.constants import Defaults


class ModbusClientMixin(object):
Expand All @@ -32,112 +31,108 @@ class ModbusClientMixin(object):
response = client.read_coils(1, 10)
'''

def read_coils(self, address, count=1, unit=Defaults.UnitId):
def read_coils(self, address, count=1, **kwargs):
'''
:param address: The starting address to read from
:param count: The number of coils to read
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = ReadCoilsRequest(address, count)
request.unit_id = unit
request = ReadCoilsRequest(address, count, **kwargs)
return self.execute(request)

def read_discrete_inputs(self, address, count=1, unit=Defaults.UnitId):
def read_discrete_inputs(self, address, count=1, **kwargs):
'''
:param address: The starting address to read from
:param count: The number of discretes to read
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = ReadDiscreteInputsRequest(address, count)
request.unit_id = unit
request = ReadDiscreteInputsRequest(address, count, **kwargs)
return self.execute(request)

def write_coil(self, address, value, unit=Defaults.UnitId):
def write_coil(self, address, value, **kwargs):
'''
:param address: The starting address to write to
:param value: The value to write to the specified address
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = WriteSingleCoilRequest(address, value)
request.unit_id = unit
request = WriteSingleCoilRequest(address, value, **kwargs)
return self.execute(request)

def write_coils(self, address, values, unit=Defaults.UnitId):
def write_coils(self, address, values, **kwargs):
'''
:param address: The starting address to write to
:param values: The values to write to the specified address
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = WriteMultipleCoilsRequest(address, values)
request.unit_id = unit
request = WriteMultipleCoilsRequest(address, values, **kwargs)
return self.execute(request)

def write_register(self, address, value, unit=Defaults.UnitId):
def write_register(self, address, value, **kwargs):
'''
:param address: The starting address to write to
:param value: The value to write to the specified address
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = WriteSingleRegisterRequest(address, value)
request.unit_id = unit
request = WriteSingleRegisterRequest(address, value, **kwargs)
return self.execute(request)

def write_registers(self, address, values, unit=Defaults.UnitId):
def write_registers(self, address, values, **kwargs):
'''
:param address: The starting address to write to
:param values: The values to write to the specified address
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = WriteMultipleRegistersRequest(address, values)
request.unit_id = unit
request = WriteMultipleRegistersRequest(address, values, **kwargs)
return self.execute(request)

def read_holding_registers(self, address, count=1, unit=Defaults.UnitId):
def read_holding_registers(self, address, count=1, **kwargs):
'''
:param address: The starting address to read from
:param count: The number of registers to read
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = ReadHoldingRegistersRequest(address, count)
request.unit_id = unit
request = ReadHoldingRegistersRequest(address, count, **kwargs)
return self.execute(request)

def read_input_registers(self, address, count=1, unit=Defaults.UnitId):
def read_input_registers(self, address, count=1, **kwargs):
'''
:param address: The starting address to read from
:param count: The number of registers to read
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = ReadInputRegistersRequest(address, count)
request.unit_id = unit
request = ReadInputRegistersRequest(address, count, **kwargs)
return self.execute(request)

def readwrite_registers(self, *args, **kwargs):
'''
:param unit: The slave unit this request is targeting
:param read_address: The address to start reading from
:param read_count: The number of registers to read from address
:param write_address: The address to start writing to
:param write_registers: The registers to write to the specified address
:param unit: The slave unit this request is targeting
:returns: A deferred response handle
'''
request = ReadWriteMultipleRegistersRequest(*args, **kwargs)
request.unit_id = kwargs.get('unit', Defaults.UnitId)
return self.execute(request)

#---------------------------------------------------------------------------#
# Exported symbols
#---------------------------------------------------------------------------#
__all__ = [ 'ModbusClientMixin' ]
20 changes: 20 additions & 0 deletions pymodbus/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,30 @@ def setValues(self, fx, address, values):
'''
raise NotImplementedException("set context values")


class IPayloadBuilder(object):
'''
This is an interface to a class that can build a payload
for a modbus register write command. It should abstract
the codec for encoding data to the required format
(bcd, binary, char, etc).
'''

def build(self):
''' Return the payload buffer as a list
This list is two bytes per element and can
thus be treated as a list of registers.
:returns: The payload buffer as a list
'''
raise NotImplementedException("set context values")

#---------------------------------------------------------------------------#
# Exported symbols
#---------------------------------------------------------------------------#
__all__ = [
'Singleton',
'IModbusDecoder', 'IModbusFramer', 'IModbusSlaveContext',
'IPayloadBuilder',
]
Loading

0 comments on commit 044acb0

Please sign in to comment.