Example #1
0
    def __init__(self, context, framer=None, identity=None, **kwargs):
        """ Overloaded initializer for the socket server

        If the identify structure is not passed in, the ModbusControlBlock
        uses its own empty structure.

        :param context: The ModbusServerContext datastore
        :param framer: The framer strategy to use
        :param identity: An optional identify structure
        :param port: The serial port to attach to
        :param stopbits: The number of stop bits to use
        :param bytesize: The bytesize of the serial messages
        :param parity: Which kind of parity to use
        :param baudrate: The baud rate to use for the serial device
        :param timeout: The timeout to use for the serial device

        """
        self.threads = []
        self.decoder = ServerDecoder()
        self.framer = framer or ModbusAsciiFramer
        self.context = context or ModbusServerContext()
        self.control = ModbusControlBlock()

        if isinstance(identity, ModbusDeviceIdentification):
            self.control.Identity.update(identity)

        self.device = kwargs.get('port', 0)
        self.stopbits = kwargs.get('stopbits', Defaults.Stopbits)
        self.bytesize = kwargs.get('bytesize', Defaults.Bytesize)
        self.parity = kwargs.get('parity', Defaults.Parity)
        self.baudrate = kwargs.get('baudrate', Defaults.Baudrate)
        self.timeout = kwargs.get('timeout', Defaults.Timeout)
        self.socket = None
        self._connect()
        self.is_running = True
Example #2
0
 def setUp(self):
     """ Sets up the test environment """
     self.client = None
     self.decoder = ServerDecoder()
     self._tcp = pymodbus3.transaction.ModbusSocketFramer(
         decoder=self.decoder)
     self._rtu = pymodbus3.transaction.ModbusRtuFramer(decoder=self.decoder)
     self._ascii = pymodbus3.transaction.ModbusAsciiFramer(
         decoder=self.decoder)
     self._binary = pymodbus3.transaction.ModbusBinaryFramer(
         decoder=self.decoder)
     self._manager = pymodbus3.transaction.DictTransactionManager(
         self.client)
     self._queue_manager = pymodbus3.transaction.FifoTransactionManager(
         self.client)
Example #3
0
    def __init__(self, store, framer=None, identity=None):
        """ Overloaded initializer for the modbus factory

        If the identify structure is not passed in, the ModbusControlBlock
        uses its own empty structure.

        :param store: The ModbusServerContext datastore
        :param framer: The framer strategy to use
        :param identity: An optional identify structure

        """
        self.decoder = ServerDecoder()
        self.framer = framer or ModbusSocketFramer
        self.store = store or ModbusServerContext()
        self.control = ModbusControlBlock()
        self.access = ModbusAccessControl()

        if isinstance(identity, ModbusDeviceIdentification):
            self.control.Identity.update(identity)
Example #4
0
    def __init__(self, context, framer=None, identity=None, address=None):
        """ Overloaded initializer for the socket server

        If the identify structure is not passed in, the ModbusControlBlock
        uses its own empty structure.

        :param context: The ModbusServerContext datastore
        :param framer: The framer strategy to use
        :param identity: An optional identify structure
        :param address: An optional (interface, port) to bind to.
        """
        self.threads = []
        self.decoder = ServerDecoder()
        self.framer = framer or ModbusSocketFramer
        self.context = context or ModbusServerContext()
        self.control = ModbusControlBlock()
        self.address = address or ("", Defaults.Port)

        if isinstance(identity, ModbusDeviceIdentification):
            self.control.Identity.update(identity)

        socketserver.ThreadingUDPServer.__init__(
            self, self.address, ModbusDisconnectedRequestHandler)
Example #5
0
class SimpleFactoryTest(unittest.TestCase):
    """
    This is the unittest for the pymodbus3.exceptions module
    """
    def setUp(self):
        """ Initializes the test environment """
        self.client = ClientDecoder()
        self.server = ServerDecoder()
        self.request = (
            (0x01, '\x01\x00\x01\x00\x01'),  # read coils
            (0x02, '\x02\x00\x01\x00\x01'),  # read discrete inputs
            (0x03, '\x03\x00\x01\x00\x01'),  # read holding registers
            (0x04, '\x04\x00\x01\x00\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b'),  # get comm event counters
            (0x0c, '\x0c'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08\x01\x00\xff'),  # write multiple coils
            (0x10,
             '\x10\x00\x01\x00\x02\x04\0xff\xff'),  # write multiple registers
            (0x11, '\x11'),  # report slave id
            (0x14,
             '\x14\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02'
             ),  # read file record
            (0x15,
             '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
             ),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'
             ),  # read/write multiple registers
            (0x18, '\x18\x00\x01'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x00'),  # read device identification
        )

        self.response = (
            (0x01, '\x01\x01\x01'),  # read coils
            (0x02, '\x02\x01\x01'),  # read discrete inputs
            (0x03, '\x03\x02\x01\x01'),  # read holding registers
            (0x04, '\x04\x02\x01\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07\x00'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b\x00\x00\x00\x00'),  # get comm event counters
            (0x0c,
             '\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08'),  # write multiple coils
            (0x10, '\x10\x00\x01\x00\x02'),  # write multiple registers
            (0x11,
             '\x11\x03\x05\x01\x54'),  # report slave id (device specific)
            (0x14, '\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05\x06\x33\xcd\x00\x40'
             ),  # read file record
            (0x15,
             '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
             ),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x02\x12\x34'),  # read/write multiple registers
            (0x18, '\x18\x00\x01\x00\x01\x00\x00'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'
             ),  # read device identification
        )

        self.exception = (
            (0x81, '\x81\x01\xd0\x50'),  # illegal function exception
            (0x82, '\x82\x02\x90\xa1'),  # illegal data address exception
            (0x83, '\x83\x03\x50\xf1'),  # illegal data value exception
            (0x84, '\x84\x04\x13\x03'),  # skave device failure exception
            (0x85, '\x85\x05\xd3\x53'),  # acknowledge exception
            (0x86, '\x86\x06\x93\xa2'),  # slave device busy exception
            (0x87, '\x87\x08\x53\xf2'),  # memory parity exception
            (0x88, '\x88\x0a\x16\x06'),  # gateway path unavailable exception
            (0x89, '\x89\x0b\xd6\x56'),  # gateway target failed exception
        )

        self.bad = (
            (0x80, '\x80\x00\x00\x00'),  # Unknown Function
            (0x81, '\x81\x00\x00\x00'),  # error message
        )

    def tearDown(self):
        """ Cleans up the test environment """
        del self.bad
        del self.request
        del self.response

    def test_exception_lookup(self):
        """ Test that we can look up exception messages """
        for func, _ in self.exception:
            response = self.client.lookup_pdu_class(func)
            self.assertNotEqual(response, None)

        for func, _ in self.exception:
            response = self.server.lookup_pdu_class(func)
            self.assertNotEqual(response, None)

    def test_response_lookup(self):
        """ Test a working response factory lookup """
        for func, _ in self.response:
            response = self.client.lookup_pdu_class(func)
            self.assertNotEqual(response, None)

    def test_request_lookup(self):
        """ Test a working request factory lookup """
        for func, _ in self.request:
            request = self.client.lookup_pdu_class(func)
            self.assertNotEqual(request, None)

    def test_response_working(self):
        """ Test a working response factory decoders """
        for func, msg in self.response:
            try:
                self.client.decode(msg)
            except ModbusException:
                self.fail("Failed to Decode Response Message " + str(func))

    def test_response_errors(self):
        """ Test a response factory decoder exceptions """
        self.assertRaises(ModbusException, self.client._helper, self.bad[0][1])
        self.assertEqual(
            self.client.decode(self.bad[1][1]).function_code, self.bad[1][0],
            "Failed to decode error PDU")

    def test_requests_working(self):
        """ Test a working request factory decoders """
        for func, msg in self.request:
            try:
                self.server.decode(msg)
            except ModbusException:
                self.fail("Failed to Decode Request Message " + str(func))

    def test_client_factory_fails(self):
        """ Tests that a client factory will fail to decode a bad message """
        self.client._helper = _raise_exception
        actual = self.client.decode(None)
        self.assertEquals(actual, None)

    def test_server_factory_fails(self):
        """ Tests that a server factory will fail to decode a bad message """
        self.server._helper = _raise_exception
        actual = self.server.decode(None)
        self.assertEquals(actual, None)

#---------------------------------------------------------------------------#
# I don't actually know what is supposed to be returned here, I assume that
# since the high bit is set, it will simply echo the resulting message
#---------------------------------------------------------------------------#

    def test_request_errors(self):
        """ Test a request factory decoder exceptions """
        for func, msg in self.bad:
            result = self.server.decode(msg)
            self.assertEqual(result.ErrorCode, 1,
                             "Failed to decode invalid requests")
            self.assertEqual(
                result.execute(None).function_code, func,
                "Failed to create correct response message")
Example #6
0
    def setUp(self):
        """ Initializes the test environment """
        self.client = ClientDecoder()
        self.server = ServerDecoder()
        self.request = (
            (0x01, '\x01\x00\x01\x00\x01'),  # read coils
            (0x02, '\x02\x00\x01\x00\x01'),  # read discrete inputs
            (0x03, '\x03\x00\x01\x00\x01'),  # read holding registers
            (0x04, '\x04\x00\x01\x00\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b'),  # get comm event counters
            (0x0c, '\x0c'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08\x01\x00\xff'),  # write multiple coils
            (0x10,
             '\x10\x00\x01\x00\x02\x04\0xff\xff'),  # write multiple registers
            (0x11, '\x11'),  # report slave id
            (0x14,
             '\x14\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02'
             ),  # read file record
            (0x15,
             '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
             ),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'
             ),  # read/write multiple registers
            (0x18, '\x18\x00\x01'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x00'),  # read device identification
        )

        self.response = (
            (0x01, '\x01\x01\x01'),  # read coils
            (0x02, '\x02\x01\x01'),  # read discrete inputs
            (0x03, '\x03\x02\x01\x01'),  # read holding registers
            (0x04, '\x04\x02\x01\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07\x00'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b\x00\x00\x00\x00'),  # get comm event counters
            (0x0c,
             '\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08'),  # write multiple coils
            (0x10, '\x10\x00\x01\x00\x02'),  # write multiple registers
            (0x11,
             '\x11\x03\x05\x01\x54'),  # report slave id (device specific)
            (0x14, '\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05\x06\x33\xcd\x00\x40'
             ),  # read file record
            (0x15,
             '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
             ),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x02\x12\x34'),  # read/write multiple registers
            (0x18, '\x18\x00\x01\x00\x01\x00\x00'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'
             ),  # read device identification
        )

        self.exception = (
            (0x81, '\x81\x01\xd0\x50'),  # illegal function exception
            (0x82, '\x82\x02\x90\xa1'),  # illegal data address exception
            (0x83, '\x83\x03\x50\xf1'),  # illegal data value exception
            (0x84, '\x84\x04\x13\x03'),  # skave device failure exception
            (0x85, '\x85\x05\xd3\x53'),  # acknowledge exception
            (0x86, '\x86\x06\x93\xa2'),  # slave device busy exception
            (0x87, '\x87\x08\x53\xf2'),  # memory parity exception
            (0x88, '\x88\x0a\x16\x06'),  # gateway path unavailable exception
            (0x89, '\x89\x0b\xd6\x56'),  # gateway target failed exception
        )

        self.bad = (
            (0x80, '\x80\x00\x00\x00'),  # Unknown Function
            (0x81, '\x81\x00\x00\x00'),  # error message
        )
Example #7
0
class SimpleFactoryTest(unittest.TestCase):
    """
    This is the unittest for the pymodbus3.exceptions module
    """

    def setUp(self):
        """ Initializes the test environment """
        self.client = ClientDecoder()
        self.server = ServerDecoder()
        self.request = (
            (0x01, '\x01\x00\x01\x00\x01'),  # read coils
            (0x02, '\x02\x00\x01\x00\x01'),  # read discrete inputs
            (0x03, '\x03\x00\x01\x00\x01'),  # read holding registers
            (0x04, '\x04\x00\x01\x00\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b'),  # get comm event counters
            (0x0c, '\x0c'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08\x01\x00\xff'),  # write multiple coils
            (0x10, '\x10\x00\x01\x00\x02\x04\0xff\xff'),  # write multiple registers
            (0x11, '\x11'),  # report slave id
            (0x14, '\x14\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02'),  # read file record
            (0x15, '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'),  # read/write multiple registers
            (0x18, '\x18\x00\x01'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x00'),  # read device identification
        )

        self.response = (
            (0x01, '\x01\x01\x01'),  # read coils
            (0x02, '\x02\x01\x01'),  # read discrete inputs
            (0x03, '\x03\x02\x01\x01'),  # read holding registers
            (0x04, '\x04\x02\x01\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07\x00'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b\x00\x00\x00\x00'),  # get comm event counters
            (0x0c, '\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08'),  # write multiple coils
            (0x10, '\x10\x00\x01\x00\x02'),  # write multiple registers
            (0x11, '\x11\x03\x05\x01\x54'),  # report slave id (device specific)
            (0x14, '\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05\x06\x33\xcd\x00\x40'),  # read file record
            (0x15, '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x02\x12\x34'),  # read/write multiple registers
            (0x18, '\x18\x00\x01\x00\x01\x00\x00'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'),  # read device identification
        )

        self.exception = (
            (0x81, '\x81\x01\xd0\x50'),  # illegal function exception
            (0x82, '\x82\x02\x90\xa1'),  # illegal data address exception
            (0x83, '\x83\x03\x50\xf1'),  # illegal data value exception
            (0x84, '\x84\x04\x13\x03'),  # skave device failure exception
            (0x85, '\x85\x05\xd3\x53'),  # acknowledge exception
            (0x86, '\x86\x06\x93\xa2'),  # slave device busy exception
            (0x87, '\x87\x08\x53\xf2'),  # memory parity exception
            (0x88, '\x88\x0a\x16\x06'),  # gateway path unavailable exception
            (0x89, '\x89\x0b\xd6\x56'),  # gateway target failed exception
        )

        self.bad = (
            (0x80, '\x80\x00\x00\x00'),  # Unknown Function
            (0x81, '\x81\x00\x00\x00'),  # error message
        )

    def tearDown(self):
        """ Cleans up the test environment """
        del self.bad
        del self.request
        del self.response

    def test_exception_lookup(self):
        """ Test that we can look up exception messages """
        for func, _ in self.exception:
            response = self.client.lookup_pdu_class(func)
            self.assertNotEqual(response, None)

        for func, _ in self.exception:
            response = self.server.lookup_pdu_class(func)
            self.assertNotEqual(response, None)

    def test_response_lookup(self):
        """ Test a working response factory lookup """
        for func, _ in self.response:
            response = self.client.lookup_pdu_class(func)
            self.assertNotEqual(response, None)

    def test_request_lookup(self):
        """ Test a working request factory lookup """
        for func, _ in self.request:
            request = self.client.lookup_pdu_class(func)
            self.assertNotEqual(request, None)

    def test_response_working(self):
        """ Test a working response factory decoders """
        for func, msg in self.response:
            try:
                self.client.decode(msg)
            except ModbusException:
                self.fail("Failed to Decode Response Message " + str(func))

    def test_response_errors(self):
        """ Test a response factory decoder exceptions """
        self.assertRaises(ModbusException, self.client._helper, self.bad[0][1])
        self.assertEqual(
            self.client.decode(self.bad[1][1]).function_code,
            self.bad[1][0],
            "Failed to decode error PDU"
        )

    def test_requests_working(self):
        """ Test a working request factory decoders """
        for func, msg in self.request:
            try:
                self.server.decode(msg)
            except ModbusException:
                self.fail("Failed to Decode Request Message " + str(func))

    def test_client_factory_fails(self):
        """ Tests that a client factory will fail to decode a bad message """
        self.client._helper = _raise_exception
        actual = self.client.decode(None)
        self.assertEquals(actual, None)

    def test_server_factory_fails(self):
        """ Tests that a server factory will fail to decode a bad message """
        self.server._helper = _raise_exception
        actual = self.server.decode(None)
        self.assertEquals(actual, None)

#---------------------------------------------------------------------------#
# I don't actually know what is supposed to be returned here, I assume that
# since the high bit is set, it will simply echo the resulting message
#---------------------------------------------------------------------------#
    def test_request_errors(self):
        """ Test a request factory decoder exceptions """
        for func, msg in self.bad:
            result = self.server.decode(msg)
            self.assertEqual(
                result.ErrorCode, 1, "Failed to decode invalid requests"
            )
            self.assertEqual(
                result.execute(None).function_code, func,
                "Failed to create correct response message"
            )
Example #8
0
    def setUp(self):
        """ Initializes the test environment """
        self.client = ClientDecoder()
        self.server = ServerDecoder()
        self.request = (
            (0x01, '\x01\x00\x01\x00\x01'),  # read coils
            (0x02, '\x02\x00\x01\x00\x01'),  # read discrete inputs
            (0x03, '\x03\x00\x01\x00\x01'),  # read holding registers
            (0x04, '\x04\x00\x01\x00\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b'),  # get comm event counters
            (0x0c, '\x0c'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08\x01\x00\xff'),  # write multiple coils
            (0x10, '\x10\x00\x01\x00\x02\x04\0xff\xff'),  # write multiple registers
            (0x11, '\x11'),  # report slave id
            (0x14, '\x14\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02'),  # read file record
            (0x15, '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'),  # read/write multiple registers
            (0x18, '\x18\x00\x01'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x00'),  # read device identification
        )

        self.response = (
            (0x01, '\x01\x01\x01'),  # read coils
            (0x02, '\x02\x01\x01'),  # read discrete inputs
            (0x03, '\x03\x02\x01\x01'),  # read holding registers
            (0x04, '\x04\x02\x01\x01'),  # read input registers
            (0x05, '\x05\x00\x01\x00\x01'),  # write single coil
            (0x06, '\x06\x00\x01\x00\x01'),  # write single register
            (0x07, '\x07\x00'),  # read exception status
            (0x08, '\x08\x00\x00\x00\x00'),  # read diagnostic
            (0x0b, '\x0b\x00\x00\x00\x00'),  # get comm event counters
            (0x0c, '\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'),  # get comm event log
            (0x0f, '\x0f\x00\x01\x00\x08'),  # write multiple coils
            (0x10, '\x10\x00\x01\x00\x02'),  # write multiple registers
            (0x11, '\x11\x03\x05\x01\x54'),  # report slave id (device specific)
            (0x14, '\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05\x06\x33\xcd\x00\x40'),  # read file record
            (0x15, '\x15\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'),  # write file record
            (0x16, '\x16\x00\x01\x00\xff\xff\x00'),  # mask write register
            (0x17, '\x17\x02\x12\x34'),  # read/write multiple registers
            (0x18, '\x18\x00\x01\x00\x01\x00\x00'),  # read fifo queue
            (0x2b, '\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'),  # read device identification
        )

        self.exception = (
            (0x81, '\x81\x01\xd0\x50'),  # illegal function exception
            (0x82, '\x82\x02\x90\xa1'),  # illegal data address exception
            (0x83, '\x83\x03\x50\xf1'),  # illegal data value exception
            (0x84, '\x84\x04\x13\x03'),  # skave device failure exception
            (0x85, '\x85\x05\xd3\x53'),  # acknowledge exception
            (0x86, '\x86\x06\x93\xa2'),  # slave device busy exception
            (0x87, '\x87\x08\x53\xf2'),  # memory parity exception
            (0x88, '\x88\x0a\x16\x06'),  # gateway path unavailable exception
            (0x89, '\x89\x0b\xd6\x56'),  # gateway target failed exception
        )

        self.bad = (
            (0x80, '\x80\x00\x00\x00'),  # Unknown Function
            (0x81, '\x81\x00\x00\x00'),  # error message
        )