From 044acb03d5df94530cc24daf2fd8f9012d788aa5 Mon Sep 17 00:00:00 2001 From: bashwork Date: Thu, 27 Sep 2012 12:47:05 -0500 Subject: [PATCH] Allowing overloading of message encoding * 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 --- doc/quality/current.coverage | 30 +++++++++--------- doc/sphinx/library/interfaces.rst | 3 ++ doc/sphinx/library/payload.rst | 4 +-- examples/common/modbus-payload.py | 44 +++++++++++++++++---------- pymodbus/client/common.py | 49 ++++++++++++++---------------- pymodbus/interfaces.py | 20 ++++++++++++ pymodbus/payload.py | 39 ++++++++++++------------ pymodbus/pdu.py | 26 ++++++++++++++-- pymodbus/register_write_message.py | 12 ++++++-- test/test_interfaces.py | 6 ++++ test/test_payload.py | 42 +++++++++++++------------ test/test_pdu.py | 8 ++--- test/test_server_async.py | 2 +- 13 files changed, 176 insertions(+), 109 deletions(-) diff --git a/doc/quality/current.coverage b/doc/quality/current.coverage index 552e95f10..376726edb 100644 --- a/doc/quality/current.coverage +++ b/doc/quality/current.coverage @@ -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% @@ -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 diff --git a/doc/sphinx/library/interfaces.rst b/doc/sphinx/library/interfaces.rst index 9c5a9c3ec..cb10d0c62 100644 --- a/doc/sphinx/library/interfaces.rst +++ b/doc/sphinx/library/interfaces.rst @@ -23,3 +23,6 @@ API Documentation .. autoclass:: IModbusSlaveContext :members: + +.. autoclass:: IPayloadBuilder + :members: diff --git a/doc/sphinx/library/payload.rst b/doc/sphinx/library/payload.rst index d81f80312..4083aa2ca 100644 --- a/doc/sphinx/library/payload.rst +++ b/doc/sphinx/library/payload.rst @@ -12,8 +12,8 @@ API Documentation .. automodule:: pymodbus.payload -.. autoclass:: PayloadBuilder +.. autoclass:: BinaryPayloadBuilder :members: -.. autoclass:: PayloadDecoder +.. autoclass:: BinaryPayloadDecoder :members: diff --git a/examples/common/modbus-payload.py b/examples/common/modbus-payload.py index 46072ff7a..b24b4a1ba 100755 --- a/examples/common/modbus-payload.py +++ b/examples/common/modbus-payload.py @@ -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 #---------------------------------------------------------------------------# @@ -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 @@ -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 diff --git a/pymodbus/client/common.py b/pymodbus/client/common.py index 25e3b66fd..4b0caa143 100644 --- a/pymodbus/client/common.py +++ b/pymodbus/client/common.py @@ -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): @@ -32,7 +31,7 @@ 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 @@ -40,11 +39,10 @@ def read_coils(self, address, count=1, unit=Defaults.UnitId): :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 @@ -52,11 +50,10 @@ def read_discrete_inputs(self, address, count=1, unit=Defaults.UnitId): :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 @@ -64,11 +61,10 @@ def write_coil(self, address, value, unit=Defaults.UnitId): :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 @@ -76,11 +72,10 @@ def write_coils(self, address, values, unit=Defaults.UnitId): :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 @@ -88,11 +83,10 @@ def write_register(self, address, value, unit=Defaults.UnitId): :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 @@ -100,11 +94,10 @@ def write_registers(self, address, values, unit=Defaults.UnitId): :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 @@ -112,11 +105,10 @@ def read_holding_registers(self, address, count=1, unit=Defaults.UnitId): :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 @@ -124,20 +116,23 @@ def read_input_registers(self, address, count=1, unit=Defaults.UnitId): :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' ] diff --git a/pymodbus/interfaces.py b/pymodbus/interfaces.py index 4509a95d0..8587e94e2 100644 --- a/pymodbus/interfaces.py +++ b/pymodbus/interfaces.py @@ -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', ] diff --git a/pymodbus/payload.py b/pymodbus/payload.py index 6e0f9a848..2a617976d 100644 --- a/pymodbus/payload.py +++ b/pymodbus/payload.py @@ -6,13 +6,14 @@ modbus messages payloads. ''' from struct import pack, unpack +from pymodbus.interfaces import IPayloadBuilder from pymodbus.constants import Endian from pymodbus.utilities import pack_bitstring from pymodbus.utilities import unpack_bitstring from pymodbus.exceptions import ParameterException -class PayloadBuilder(object): +class BinaryPayloadBuilder(IPayloadBuilder): ''' A utility that helps build payload messages to be written with the various modbus messages. It really is just @@ -20,10 +21,10 @@ class PayloadBuilder(object): time looking up the format strings. What follows is a simple example:: - builder = PayloadBuilder(endian=Endian.Little) + builder = BinaryPayloadBuilder(endian=Endian.Little) builder.add_8bit_uint(1) builder.add_16bit_uint(2) - payload = builder.tostring() + payload = builder.build() ''' def __init__(self, payload=None, endian=Endian.Little): @@ -35,19 +36,19 @@ def __init__(self, payload=None, endian=Endian.Little): self._payload = payload or [] self._endian = endian - def reset(self): - ''' Reset the payload buffer - ''' - self._payload = [] - - def tostring(self): + def __str__(self): ''' Return the payload buffer as a string :returns: The payload buffer as a string ''' return ''.join(self._payload) - def tolist(self): + def reset(self): + ''' Reset the payload buffer + ''' + self._payload = [] + + def build(self): ''' Return the payload buffer as a list This list is two bytes per element and can @@ -55,7 +56,7 @@ def tolist(self): :returns: The payload buffer as a list ''' - string = self.tostring() + string = str(self) length = len(string) string = string + ('\x00' * (length % 2)) return [string[i:i+2] for i in xrange(0, length, 2)] @@ -163,7 +164,7 @@ def add_string(self, value): self._payload.append(pack(fstring, c)) -class PayloadDecoder(object): +class BinaryPayloadDecoder(object): ''' A utility that helps decode payload messages from a modbus reponse message. It really is just a simple wrapper around @@ -191,15 +192,16 @@ def fromRegisters(registers, endian=Endian.Little): reading a collection of registers from a modbus device. The registers are treated as a list of 2 byte values. + We have to do this because of how the data has already + been decoded by the rest of the library. :param registers: The register results to initialize with :param endian: The endianess of the payload :returns: An initialized PayloadDecoder ''' - fstring = endian + 'H' - if isinstance(registers, list): - payload = ''.join(pack(fstring, x) for x in registers) - return PayloadDecoder(payload, endian) + if isinstance(registers, list): # repack into flat binary + payload = ''.join(pack('>H', x) for x in registers) + return BinaryPayloadDecoder(payload, endian) raise ParameterException('Invalid collection of registers supplied') @staticmethod @@ -214,9 +216,8 @@ def fromCoils(coils, endian=Endian.Little): :returns: An initialized PayloadDecoder ''' if isinstance(coils, list): -# TODO endianess issue here payload = pack_bitstring(coils) - return PayloadDecoder(payload, endian) + return BinaryPayloadDecoder(payload, endian) raise ParameterException('Invalid collection of coils supplied') def reset(self): @@ -324,4 +325,4 @@ def decode_string(self, size=1): #---------------------------------------------------------------------------# # Exported Identifiers #---------------------------------------------------------------------------# -__all__ = ["PayloadBuilder", "PayloadDecoder"] +__all__ = ["BinaryPayloadBuilder", "BinaryPayloadDecoder"] diff --git a/pymodbus/pdu.py b/pymodbus/pdu.py index 6c21b8f00..6090ac075 100644 --- a/pymodbus/pdu.py +++ b/pymodbus/pdu.py @@ -41,6 +41,14 @@ class ModbusPDU(object): .. attribute:: check This is used for LRC/CRC in the serial modbus protocols + + .. attribute:: skip_encode + + This is used when the message payload has already been encoded. + Generally this will occur when the PayloadBuilder is being used + to create a complicated message. By setting this to True, the + request will pass the currently encoded message through instead + of encoding it again. ''' def __init__(self, **kwargs): @@ -48,6 +56,7 @@ def __init__(self, **kwargs): self.transaction_id = kwargs.get('transaction', Defaults.TransactionId) self.protocol_id = kwargs.get('protocol', Defaults.ProtocolId) self.unit_id = kwargs.get('unit', Defaults.UnitId) + self.skip_encode = kwargs.get('skip_encode', False) self.check = 0x0000 def encode(self): @@ -136,6 +145,17 @@ class ModbusExceptions(Singleton): GatewayPathUnavailable = 0x0A GatewayNoResponse = 0x0B + @classmethod + def decode(cls, code): + ''' Given an error code, translate it to a + string error name. + + :param code: The code number to translate + ''' + values = dict((v, k) for k, v in cls.__dict__.items() + if not k.startswith('__') and not callable(v)) + return values.get(code, None) + class ExceptionResponse(ModbusResponse): ''' Base class for a modbus exception PDU ''' @@ -149,6 +169,7 @@ def __init__(self, function_code, exception_code=None, **kwargs): :param exception_code: The specific modbus exception to return ''' ModbusResponse.__init__(self, **kwargs) + self.original_code = function_code self.function_code = function_code | self.ExceptionOffset self.exception_code = exception_code @@ -171,8 +192,9 @@ def __str__(self): :returns: The string representation of an exception response ''' - parameters = (self.function_code, self.exception_code) - return "Exception Response (%d, %d)" % parameters + message = ModbusExceptions.decode(self.exception_code) + parameters = (self.function_code, self.original_code, message) + return "Exception Response(%d, %d, %s)" % parameters class IllegalFunctionRequest(ModbusRequest): diff --git a/pymodbus/register_write_message.py b/pymodbus/register_write_message.py index d3bd7b0a8..a1dcf91f7 100644 --- a/pymodbus/register_write_message.py +++ b/pymodbus/register_write_message.py @@ -35,6 +35,8 @@ def encode(self): :returns: The encoded packet ''' + if self.skip_encode: + return self.value return struct.pack('>HH', self.address, self.value) def decode(self, data): @@ -130,9 +132,9 @@ def __init__(self, address=None, values=None, **kwargs): ''' ModbusRequest.__init__(self, **kwargs) self.address = address - if not values: values = [] - elif not hasattr(values, '__iter__'): values = [values] - self.values = values + self.values = values or [] + if not hasattr(values, '__iter__'): + values = [values] self.count = len(self.values) self.byte_count = self.count * 2 @@ -142,8 +144,12 @@ def encode(self): :returns: The encoded packet ''' packet = struct.pack('>HHB', self.address, self.count, self.byte_count) + if self.skip_encode: + return packet + ''.join(self.values) + for value in self.values: packet += struct.pack('>H', value) + return packet def decode(self, data): diff --git a/test/test_interfaces.py b/test/test_interfaces.py index c9cb84a2b..093f9453d 100644 --- a/test/test_interfaces.py +++ b/test/test_interfaces.py @@ -54,6 +54,12 @@ def testModbusSlaveContextInterface(self): self.assertRaises(NotImplementedException, lambda: instance.getValues(x,x,x)) self.assertRaises(NotImplementedException, lambda: instance.setValues(x,x,x)) + def testModbusPayloadBuilderInterface(self): + ''' Test that the base class isn't implemented ''' + x = None + instance = IPayloadBuilder() + self.assertRaises(NotImplementedException, lambda: instance.build()) + #---------------------------------------------------------------------------# # Main #---------------------------------------------------------------------------# diff --git a/test/test_payload.py b/test/test_payload.py index 8d3ee33e9..453d82fce 100644 --- a/test/test_payload.py +++ b/test/test_payload.py @@ -11,7 +11,7 @@ import unittest from pymodbus.exceptions import ParameterException from pymodbus.constants import Endian -from pymodbus.payload import PayloadBuilder, PayloadDecoder +from pymodbus.payload import BinaryPayloadBuilder, BinaryPayloadDecoder #---------------------------------------------------------------------------# # Fixture @@ -51,7 +51,7 @@ def tearDown(self): def testLittleEndianPayloadBuilder(self): ''' Test basic bit message encoding/decoding ''' - builder = PayloadBuilder(endian=Endian.Little) + builder = BinaryPayloadBuilder(endian=Endian.Little) builder.add_8bit_uint(1) builder.add_16bit_uint(2) builder.add_32bit_uint(3) @@ -64,11 +64,11 @@ def testLittleEndianPayloadBuilder(self): builder.add_64bit_float(6.25) builder.add_string('test') builder.add_bits(self.bitstring) - self.assertEqual(self.little_endian_payload, builder.tostring()) + self.assertEqual(self.little_endian_payload, str(builder)) def testBigEndianPayloadBuilder(self): ''' Test basic bit message encoding/decoding ''' - builder = PayloadBuilder(endian=Endian.Big) + builder = BinaryPayloadBuilder(endian=Endian.Big) builder.add_8bit_uint(1) builder.add_16bit_uint(2) builder.add_32bit_uint(3) @@ -81,20 +81,20 @@ def testBigEndianPayloadBuilder(self): builder.add_64bit_float(6.25) builder.add_string('test') builder.add_bits(self.bitstring) - self.assertEqual(self.big_endian_payload, builder.tostring()) + self.assertEqual(self.big_endian_payload, str(builder)) def testPayloadBuilderReset(self): ''' Test basic bit message encoding/decoding ''' - builder = PayloadBuilder() + builder = BinaryPayloadBuilder() builder.add_8bit_uint(0x12) builder.add_8bit_uint(0x34) builder.add_8bit_uint(0x56) builder.add_8bit_uint(0x78) - self.assertEqual('\x12\x34\x56\x78', builder.tostring()) - self.assertEqual(['\x12\x34', '\x56\x78'], builder.tolist()) + self.assertEqual('\x12\x34\x56\x78', str(builder)) + self.assertEqual(['\x12\x34', '\x56\x78'], builder.build()) builder.reset() - self.assertEqual('', builder.tostring()) - self.assertEqual([], builder.tolist()) + self.assertEqual('', str(builder)) + self.assertEqual([], builder.build()) #-----------------------------------------------------------------------# # Payload Decoder Tests @@ -102,7 +102,7 @@ def testPayloadBuilderReset(self): def testLittleEndianPayloadDecoder(self): ''' Test basic bit message encoding/decoding ''' - decoder = PayloadDecoder(self.little_endian_payload, endian=Endian.Little) + decoder = BinaryPayloadDecoder(self.little_endian_payload, endian=Endian.Little) self.assertEqual(1, decoder.decode_8bit_uint()) self.assertEqual(2, decoder.decode_16bit_uint()) self.assertEqual(3, decoder.decode_32bit_uint()) @@ -118,7 +118,7 @@ def testLittleEndianPayloadDecoder(self): def testBigEndianPayloadDecoder(self): ''' Test basic bit message encoding/decoding ''' - decoder = PayloadDecoder(self.big_endian_payload, endian=Endian.Big) + decoder = BinaryPayloadDecoder(self.big_endian_payload, endian=Endian.Big) self.assertEqual(1, decoder.decode_8bit_uint()) self.assertEqual(2, decoder.decode_16bit_uint()) self.assertEqual(3, decoder.decode_32bit_uint()) @@ -134,7 +134,7 @@ def testBigEndianPayloadDecoder(self): def testPayloadDecoderReset(self): ''' Test the payload decoder reset functionality ''' - decoder = PayloadDecoder('\x12\x34') + decoder = BinaryPayloadDecoder('\x12\x34') self.assertEqual(0x12, decoder.decode_8bit_uint()) self.assertEqual(0x34, decoder.decode_8bit_uint()) decoder.reset() @@ -143,28 +143,30 @@ def testPayloadDecoderReset(self): def testPayloadDecoderRegisterFactory(self): ''' Test the payload decoder reset functionality ''' payload = [1,2,3,4] - decoder = PayloadDecoder.fromRegisters(payload, endian=Endian.Little) - encoded = '\x01\x00\x02\x00\x03\x00\x04\x00' + decoder = BinaryPayloadDecoder.fromRegisters(payload, endian=Endian.Little) + encoded = '\x00\x01\x00\x02\x00\x03\x00\x04' self.assertEqual(encoded, decoder.decode_string(8)) - decoder = PayloadDecoder.fromRegisters(payload, endian=Endian.Big) + decoder = BinaryPayloadDecoder.fromRegisters(payload, endian=Endian.Big) encoded = '\x00\x01\x00\x02\x00\x03\x00\x04' self.assertEqual(encoded, decoder.decode_string(8)) - self.assertRaises(ParameterException, lambda: PayloadDecoder.fromRegisters('abcd')) + self.assertRaises(ParameterException, + lambda: BinaryPayloadDecoder.fromRegisters('abcd')) def testPayloadDecoderCoilFactory(self): ''' Test the payload decoder reset functionality ''' payload = [1,0,0,0, 1,0,0,0, 0,0,0,1, 0,0,0,1] - decoder = PayloadDecoder.fromCoils(payload, endian=Endian.Little) + decoder = BinaryPayloadDecoder.fromCoils(payload, endian=Endian.Little) encoded = '\x11\x88' self.assertEqual(encoded, decoder.decode_string(2)) - decoder = PayloadDecoder.fromCoils(payload, endian=Endian.Big) + decoder = BinaryPayloadDecoder.fromCoils(payload, endian=Endian.Big) encoded = '\x11\x88' self.assertEqual(encoded, decoder.decode_string(2)) - self.assertRaises(ParameterException, lambda: PayloadDecoder.fromCoils('abcd')) + self.assertRaises(ParameterException, + lambda: BinaryPayloadDecoder.fromCoils('abcd')) #---------------------------------------------------------------------------# diff --git a/test/test_pdu.py b/test/test_pdu.py index bc0cc2189..a09468d77 100644 --- a/test/test_pdu.py +++ b/test/test_pdu.py @@ -46,10 +46,10 @@ def testRequestExceptionFactory(self): ''' Test all error methods ''' request = ModbusRequest() request.function_code = 1 - for error in [getattr(ModbusExceptions, i) - for i in dir(ModbusExceptions) if '__' not in i]: - result = request.doException(error) - self.assertEqual(str(result), "Exception Response (129, %d)" % error) + errors = dict((ModbusExceptions.decode(c), c) for c in range(1,20)) + for error, code in errors.items(): + result = request.doException(code) + self.assertEqual(str(result), "Exception Response(129, 1, %s)" % error) def testCalculateRtuFrameSize(self): ''' Test the calculation of Modbus/RTU frame sizes ''' diff --git a/test/test_server_async.py b/test/test_server_async.py index e7ec9c731..18438e3d1 100644 --- a/test/test_server_async.py +++ b/test/test_server_async.py @@ -84,7 +84,7 @@ def testUdpServerStartup(self): def testSerialServerStartup(self): ''' Test that the modbus serial async server starts correctly ''' with patch('twisted.internet.reactor') as mock_reactor: - StartSerialServer(context=None) + StartSerialServer(context=None, port='/dev/pts/0') self.assertEqual(mock_reactor.run.call_count, 1) #---------------------------------------------------------------------------#