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.bad = ( (0x80, '\x80\x00\x00\x00'), # Unknown Function (0x81, '\x81\x00\x00\x00'), # error message )
def __init__(self, framer=None, **kwargs): self._connected = False self.framer = framer or ModbusSocketFramer(ClientDecoder()) if isinstance(self.framer, type): # Framer class not instance self.framer = self.framer(ClientDecoder(), client=None) if isinstance(self.framer, ModbusSocketFramer): self.transaction = DictTransactionManager(self, **kwargs) else: self.transaction = FifoTransactionManager(self, **kwargs)
def __implementation(method): ''' Returns the requested framer :method: The serial framer to instantiate :returns: The requested serial framer ''' method = method.lower() if method == 'ascii': return ModbusAsciiFramer(ClientDecoder()) elif method == 'rtu': return ModbusRtuFramer(ClientDecoder()) elif method == 'binary': return ModbusBinaryFramer(ClientDecoder()) raise ParameterException("Invalid framer method requested")
def _framer(method): if method == "ascii": framer = ModbusAsciiFramer(ClientDecoder()) elif method == "rtu": framer = ModbusRtuFramer(ClientDecoder()) elif method == "binary": framer = ModbusBinaryFramer(ClientDecoder()) elif method == "socket": framer = ModbusSocketFramer(ClientDecoder()) else: framer = None return framer
def __init__(self, framer=None, **kwargs): ''' Initializes the framer module :param framer: The framer to use for the protocol ''' self._connected = False self.framer = framer or ModbusSocketFramer(ClientDecoder()) if isinstance(self.framer, type): # Framer class not instance self.framer = self.framer(ClientDecoder(), client=None) if isinstance(self.framer, ModbusSocketFramer): self.transaction = DictTransactionManager(self, **kwargs) else: self.transaction = FifoTransactionManager(self, **kwargs)
def __init__(self, client, timeout=2): self.client = client self.decoder = ClientDecoder() self.framer = ModbusSocketFramer(self.decoder, client=self) self._ack_waiter: Optional[asyncio.Future[None]] = None self.transaction = DictTransactionManager(self) self.timeout = timeout
def __init__(self, framer=None): ''' Initializes the framer module :param framer: The framer to use for the protocol ''' self.framer = framer or ModbusSocketFramer(ClientDecoder()) self._requests = deque() # link queue to tid
def main(): """ The main runner function """ options = get_options() if options.debug: try: log.setLevel(logging.DEBUG) logging.basicConfig() except Exception as ex: print("Logging is not supported on this system") # split the query into a starting and ending range query = [int(p) for p in options.query.split(':')] try: log.debug("Initializing the client") framer = ModbusSocketFramer(ClientDecoder()) reader = LoggingContextReader(options.output) factory = ScraperFactory(framer, reader, query) # how to connect based on TCP vs Serial clients if isinstance(framer, ModbusSocketFramer): reactor.connectTCP(options.host, options.port, factory) else: SerialModbusClient(factory, options.port, reactor) log.debug("Starting the client") reactor.run() log.debug("Finished scraping the client") except Exception as ex: print(ex)
def decode(self, message): """ Attempt to decode the supplied message :param message: The messge to decode """ if IS_PYTHON3: value = message if self.encode else c.encode(message, 'hex_codec') else: value = message if self.encode else message.encode('hex') print("=" * 80) print("Decoding Message %s" % value) print("=" * 80) decoders = [ self.framer(ServerDecoder(), client=None), self.framer(ClientDecoder(), client=None) ] for decoder in decoders: print("%s" % decoder.decoder.__class__.__name__) print("-" * 80) try: decoder.addToFrame(message) if decoder.checkFrame(): unit = decoder._header.get("uid", 0x00) decoder.advanceFrame() decoder.processIncomingPacket(message, self.report, unit) else: self.check_errors(decoder, message) except Exception as ex: self.check_errors(decoder, message)
def decode(self, message): ''' Attempt to decode the supplied message :param message: The messge to decode ''' value = message if self.encode else message.encode('hex') print("=" * 80) print("Decoding Message %s" % value) print("=" * 80) decoders = [ self.framer(ServerDecoder()), self.framer(ClientDecoder()), ] for decoder in decoders: print("%s" % decoder.decoder.__class__.__name__) print("-" * 80) try: decoder.addToFrame(message.encode()) if decoder.checkFrame(): decoder.advanceFrame() decoder.processIncomingPacket(message, self.report) else: self.check_errors(decoder, message) except Exception as ex: self.check_errors(decoder, message)
class ModbusTcpClientProtocol(ModbusClientProtocol): """ Async TCP Client protocol based on twisted. Default framer: ModbusSocketFramer """ framer = ModbusSocketFramer(ClientDecoder())
def __init__(self, framer=ModbusSocketFramer(ClientDecoder())): ''' Initializes the framer module :param framer: The framer to use for the protocol ''' self.done = False self.framer = framer
def __init__(self, framer=None): ''' Initializes the framer module :param framer: The framer to use for the protocol ''' self.framer = framer or ModbusSocketFramer(ClientDecoder()) serial = not isinstance(framer, ModbusSocketFramer) self.transaction = ModbusTransactionManager(self, serial)
def __init__(self, factory, *args, **kwargs): """ Setup the client and start listening on the serial port :param factory: The factory to build clients with """ protocol = factory.buildProtocol(None) self.decoder = ClientDecoder() serialport.SerialPort.__init__(self, protocol, *args, **kwargs)
def __init__(self, port, baud=9600): self.port = port self.baud = baud self.connection = serial.Serial( port, baud, timeout=float(self.kByteLength * self.kMaxReadSize) / baud) self.client_framer = ModbusRtuFramer(decoder=ClientDecoder()) self.server_framer = ModbusRtuFramer(decoder=ServerDecoder())
def main(): log.debug("Initializing the client") framer = ModbusFramer(ClientDecoder(), client=None) reader = LoggingLineReader() factory = ExampleFactory(framer, reader) SerialModbusClient(factory, SERIAL_PORT, reactor) # factory = reactor.connectTCP("localhost", 502, factory) log.debug("Starting the client") reactor.run()
def _framer(cls, method): """ Returns the requested framer :method: The serial framer to instantiate :returns: The requested serial framer """ method = method.lower() if method == 'ascii': return ModbusAsciiFramer(ClientDecoder()) elif method == 'rtu': return ModbusRtuFramer(ClientDecoder()) elif method == 'binary': return ModbusBinaryFramer(ClientDecoder()) elif method == 'socket': return ModbusSocketFramer(ClientDecoder()) raise ParameterException("Invalid framer method requested")
def __init__(self, framer, *args, **kwargs): ''' Setup the client and start listening on the serial port :param factory: The factory to build clients with ''' self.decoder = ClientDecoder() proto_cls = kwargs.pop("proto_cls", None) proto = SerialClientFactory(framer, proto_cls).buildProtocol() SerialPort.__init__(self, proto, *args, **kwargs)
def __init__(self, framer=None): ''' Initializes the framer module :param framer: The framer to use for the protocol ''' self.framer = framer or ModbusSocketFramer(ClientDecoder()) if isinstance(self.framer, ModbusSocketFramer): self.transaction = DictTransactionManager(self) else: self.transaction = FifoTransactionManager(self)
def __implementation(method): """ Returns the requested framer :method: The serial framer to instantiate :returns: The requested serial framer """ method = method.lower() if method == 'rtu': return ModbusRtuFramer(ClientDecoder()) raise ParameterException("Invalid framer method requested")
def __init__(self, host='127.0.0.1', port=Defaults.Port): ''' Initialize a client instance :param host: The host to connect to (default 127.0.0.1) :param port: The modbus port to connect to (default 502) ''' self.host = host self.port = port self.socket = None BaseModbusClient.__init__(self, ModbusSocketFramer(ClientDecoder()))
def testSerialClientConnect(self, mock_serial, mock_seriostream, mock_ioloop): """ Test the tornado serial client client connect """ client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP, framer=ModbusRtuFramer( ClientDecoder()), port=SERIAL_PORT) self.assertTrue(client.port, SERIAL_PORT) self.assertFalse(client._connected) client.connect() self.assertTrue(client._connected) client.close()
def __init__(self, framer=None, **kwargs): """ Initializes the framer module :param framer: The framer to use for the protocol """ deprecated(self.__class__.__name__) self.framer = framer or ModbusSocketFramer(ClientDecoder()) if isinstance(self.framer, ModbusSocketFramer): self.transaction = DictTransactionManager(self, **kwargs) else: self.transaction = FifoTransactionManager(self, **kwargs)
def __init__(self, framer=None, **kwargs): """ Initializes the framer module :param framer: The framer to use for the protocol. Default: ModbusSocketFramer :type framer: pymodbus.transaction.ModbusSocketFramer """ self._connected = False super(BaseAsyncModbusClient, self).__init__(framer or ModbusSocketFramer(ClientDecoder()), **kwargs)
def testSerialClientInit(self): """ Test the tornado serial client client initialize """ client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP, framer=ModbusRtuFramer( ClientDecoder()), port=SERIAL_PORT) self.assertEqual(0, len(list(client.transaction))) self.assertTrue(isinstance(client.framer, ModbusRtuFramer)) framer = object() client = AsyncModbusSerialClient(framer=framer) self.assertTrue(framer is client.framer)
def testClientProtocolDataReceived(self): ''' Test the client protocol data received ''' protocol = ModbusClientProtocol(ModbusSocketFramer(ClientDecoder())) protocol.connectionMade() out = [] data = b'\x00\x00\x12\x34\x00\x06\xff\x01\x01\x02\x00\x04' # setup existing request d = protocol._buildResponse(0x00) d.addCallback(lambda v: out.append(v)) protocol.dataReceived(data) self.assertTrue(isinstance(out[0], ReadCoilsResponse))
def __init__(self, host='127.0.0.1', port=Defaults.Port, framer=ModbusSocketFramer, **kwargs): """ Initialize a client instance :param host: The host to connect to (default 127.0.0.1) :param port: The modbus port to connect to (default 502) :param source_address: The source address tuple to bind to (default ('', 0)) :param timeout: The timeout to use for this socket (default Defaults.Timeout) :param framer: The modbus framer to use (default ModbusSocketFramer) .. note:: The host argument will accept ipv4 and ipv6 hosts """ self.host = host self.port = port self.source_address = kwargs.get('source_address', ('', 0)) self.socket = None self.timeout = kwargs.get('timeout', Defaults.Timeout) self.transaction_id = kwargs.get('transaction', Defaults.TransactionId) self.protocol_id = kwargs.get('protocol', Defaults.ProtocolId) self.unit_id = kwargs.get('unit', Defaults.UnitId) Defaults.UnitId = 0x05 self.skip_encode = kwargs.get('skip_encode', False) serverCertFile = './servercert.pem' serverKeyFile = './serverkey.pem' caCertFile = './servercert.pem' deviceCertFile = './conf-/devicecert.pem' deviceKeyFile = './conf-/devicekey.pem' sslIntervalSeconds = 6 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) logger.debug( "using caCertFile={0}, deviceCertFile={1}, deviceKeyFile={2}". format(caCertFile, deviceCertFile, deviceKeyFile)) sslSocket = ssl.wrap_socket(sock, ca_certs=caCertFile, cert_reqs=ssl.CERT_REQUIRED, certfile=deviceCertFile, keyfile=deviceKeyFile, ssl_version=ssl.PROTOCOL_TLSv1_2, do_handshake_on_connect=True, ciphers='ECDHE-RSA-AES256-SHA') self.sslSocket = sslSocket BaseModbusClient.__init__(self, framer(ClientDecoder(), self), **kwargs)
def __init__(self, host='127.0.0.1', port=Defaults.Port, framer=ModbusSocketFramer, **kwargs): """ Initialize a client instance :param host: The host to connect to (default 127.0.0.1) :param port: The modbus port to connect to (default 502) :param framer: The modbus framer to use (default ModbusSocketFramer) :param timeout: The timeout to use for this socket (default None) """ self.host = host self.port = port self.socket = None self.timeout = kwargs.get('timeout', None) BaseModbusClient.__init__(self, framer(ClientDecoder(), self), **kwargs)
def testSerialClientExecute(self, mock_serial, mock_seriostream, mock_ioloop): """ Test the tornado serial client client execute method """ client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP, framer=ModbusRtuFramer( ClientDecoder()), port=SERIAL_PORT) client.connect() client.stream = Mock() client.stream.write = Mock() request = ReadCoilsRequest(1, 1) d = client.execute(request) tid = request.transaction_id self.assertEqual(d, client.transaction.getTransaction(tid))
def testClientProtocolConnectionMade(self, protocol): """ Test the client protocol close :return: """ protocol = protocol(ModbusSocketFramer(ClientDecoder())) transport = mock.MagicMock() factory = mock.MagicMock() if isinstance(protocol, ModbusUdpClientProtocol): protocol.factory = factory protocol.connection_made(transport) assert protocol.transport == transport assert protocol.connected if isinstance(protocol, ModbusUdpClientProtocol): assert protocol.factory.protocol_made_connection.call_count == 1
class SimpleFactoryTest(unittest.TestCase): ''' This is the unittest for the pymod.exceptions module ''' def setUp(self): ''' Initializes the test environment ''' self.client = ClientDecoder() self.server = ServerDecoder() self.request = ( (0x01, b'\x01\x00\x01\x00\x01'), # read coils (0x02, b'\x02\x00\x01\x00\x01'), # read discrete inputs (0x03, b'\x03\x00\x01\x00\x01'), # read holding registers (0x04, b'\x04\x00\x01\x00\x01'), # read input registers (0x05, b'\x05\x00\x01\x00\x01'), # write single coil (0x06, b'\x06\x00\x01\x00\x01'), # write single register (0x07, b'\x07'), # read exception status (0x08, b'\x08\x00\x00\x00\x00'), # read diagnostic (0x0b, b'\x0b'), # get comm event counters (0x0c, b'\x0c'), # get comm event log (0x0f, b'\x0f\x00\x01\x00\x08\x01\x00\xff'), # write multiple coils (0x10, b'\x10\x00\x01\x00\x02\x04\0xff\xff'), # write multiple registers (0x11, b'\x11'), # report slave id (0x14, b'\x14\x0e\x06\x00\x04\x00\x01\x00\x02' \ b'\x06\x00\x03\x00\x09\x00\x02'), # read file record (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \ b'\x06\xaf\x04\xbe\x10\x0d'), # write file record (0x16, b'\x16\x00\x01\x00\xff\xff\x00'), # mask write register (0x17, b'\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'),# read/write multiple registers (0x18, b'\x18\x00\x01'), # read fifo queue (0x2b, b'\x2b\x0e\x01\x00'), # read device identification ) self.response = ( (0x01, b'\x01\x01\x01'), # read coils (0x02, b'\x02\x01\x01'), # read discrete inputs (0x03, b'\x03\x02\x01\x01'), # read holding registers (0x04, b'\x04\x02\x01\x01'), # read input registers (0x05, b'\x05\x00\x01\x00\x01'), # write single coil (0x06, b'\x06\x00\x01\x00\x01'), # write single register (0x07, b'\x07\x00'), # read exception status (0x08, b'\x08\x00\x00\x00\x00'), # read diagnostic (0x0b, b'\x0b\x00\x00\x00\x00'), # get comm event counters (0x0c, b'\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'), # get comm event log (0x0f, b'\x0f\x00\x01\x00\x08'), # write multiple coils (0x10, b'\x10\x00\x01\x00\x02'), # write multiple registers (0x11, b'\x11\x03\x05\x01\x54'), # report slave id (device specific) (0x14, b'\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05' \ b'\x06\x33\xcd\x00\x40'), # read file record (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \ b'\x06\xaf\x04\xbe\x10\x0d'), # write file record (0x16, b'\x16\x00\x01\x00\xff\xff\x00'), # mask write register (0x17, b'\x17\x02\x12\x34'), # read/write multiple registers (0x18, b'\x18\x00\x01\x00\x01\x00\x00'), # read fifo queue (0x2b, b'\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'), # read device identification ) self.exception = ( (0x81, b'\x81\x01\xd0\x50'), # illegal function exception (0x82, b'\x82\x02\x90\xa1'), # illegal data address exception (0x83, b'\x83\x03\x50\xf1'), # illegal data value exception (0x84, b'\x84\x04\x13\x03'), # skave device failure exception (0x85, b'\x85\x05\xd3\x53'), # acknowledge exception (0x86, b'\x86\x06\x93\xa2'), # slave device busy exception (0x87, b'\x87\x08\x53\xf2'), # memory parity exception (0x88, b'\x88\x0a\x16\x06'), # gateway path unavailable exception (0x89, b'\x89\x0b\xd6\x56'), # gateway target failed exception ) self.bad = ( (0x80, b'\x80\x00\x00\x00'), # Unknown Function (0x81, b'\x81\x00\x00\x00'), # error message ) def tearDown(self): ''' Cleans up the test environment ''' del self.bad del self.request del self.response def testExceptionLookup(self): ''' Test that we can look up exception messages ''' for func, _ in self.exception: response = self.client.lookupPduClass(func) self.assertNotEqual(response, None) for func, _ in self.exception: response = self.server.lookupPduClass(func) self.assertNotEqual(response, None) def testResponseLookup(self): ''' Test a working response factory lookup ''' for func, _ in self.response: response = self.client.lookupPduClass(func) self.assertNotEqual(response, None) def testRequestLookup(self): ''' Test a working request factory lookup ''' for func, _ in self.request: request = self.client.lookupPduClass(func) self.assertNotEqual(request, None) def testResponseWorking(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", func) def testResponseErrors(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 testRequestsWorking(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", func) def testClientFactoryFails(self): ''' Tests that a client factory will fail to decode a bad message ''' self.client._helper = _raise_exception actual = self.client.decode(None) self.assertEqual(actual, None) def testServerFactoryFails(self): ''' Tests that a server factory will fail to decode a bad message ''' self.server._helper = _raise_exception actual = self.server.decode(None) self.assertEqual(actual, None) def testServerRegisterCustomRequest(self): class CustomRequest(ModbusRequest): function_code = 0xff self.server.register(CustomRequest) assert self.client.lookupPduClass(CustomRequest.function_code) CustomRequest.sub_function_code = 0xff self.server.register(CustomRequest) assert self.server.lookupPduClass(CustomRequest.function_code) def testClientRegisterCustomResponse(self): class CustomResponse(ModbusResponse): function_code = 0xff self.client.register(CustomResponse) assert self.client.lookupPduClass(CustomResponse.function_code) CustomResponse.sub_function_code = 0xff self.client.register(CustomResponse) assert self.client.lookupPduClass(CustomResponse.function_code) #---------------------------------------------------------------------------# # 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 testRequestErrors(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")
def setUp(self): ''' Initializes the test environment ''' self.client = ClientDecoder() self.server = ServerDecoder() self.request = ( (0x01, b'\x01\x00\x01\x00\x01'), # read coils (0x02, b'\x02\x00\x01\x00\x01'), # read discrete inputs (0x03, b'\x03\x00\x01\x00\x01'), # read holding registers (0x04, b'\x04\x00\x01\x00\x01'), # read input registers (0x05, b'\x05\x00\x01\x00\x01'), # write single coil (0x06, b'\x06\x00\x01\x00\x01'), # write single register (0x07, b'\x07'), # read exception status (0x08, b'\x08\x00\x00\x00\x00'), # read diagnostic (0x0b, b'\x0b'), # get comm event counters (0x0c, b'\x0c'), # get comm event log (0x0f, b'\x0f\x00\x01\x00\x08\x01\x00\xff'), # write multiple coils (0x10, b'\x10\x00\x01\x00\x02\x04\0xff\xff'), # write multiple registers (0x11, b'\x11'), # report slave id (0x14, b'\x14\x0e\x06\x00\x04\x00\x01\x00\x02' \ b'\x06\x00\x03\x00\x09\x00\x02'), # read file record (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \ b'\x06\xaf\x04\xbe\x10\x0d'), # write file record (0x16, b'\x16\x00\x01\x00\xff\xff\x00'), # mask write register (0x17, b'\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'),# read/write multiple registers (0x18, b'\x18\x00\x01'), # read fifo queue (0x2b, b'\x2b\x0e\x01\x00'), # read device identification ) self.response = ( (0x01, b'\x01\x01\x01'), # read coils (0x02, b'\x02\x01\x01'), # read discrete inputs (0x03, b'\x03\x02\x01\x01'), # read holding registers (0x04, b'\x04\x02\x01\x01'), # read input registers (0x05, b'\x05\x00\x01\x00\x01'), # write single coil (0x06, b'\x06\x00\x01\x00\x01'), # write single register (0x07, b'\x07\x00'), # read exception status (0x08, b'\x08\x00\x00\x00\x00'), # read diagnostic (0x0b, b'\x0b\x00\x00\x00\x00'), # get comm event counters (0x0c, b'\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'), # get comm event log (0x0f, b'\x0f\x00\x01\x00\x08'), # write multiple coils (0x10, b'\x10\x00\x01\x00\x02'), # write multiple registers (0x11, b'\x11\x03\x05\x01\x54'), # report slave id (device specific) (0x14, b'\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05' \ b'\x06\x33\xcd\x00\x40'), # read file record (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \ b'\x06\xaf\x04\xbe\x10\x0d'), # write file record (0x16, b'\x16\x00\x01\x00\xff\xff\x00'), # mask write register (0x17, b'\x17\x02\x12\x34'), # read/write multiple registers (0x18, b'\x18\x00\x01\x00\x01\x00\x00'), # read fifo queue (0x2b, b'\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'), # read device identification ) self.exception = ( (0x81, b'\x81\x01\xd0\x50'), # illegal function exception (0x82, b'\x82\x02\x90\xa1'), # illegal data address exception (0x83, b'\x83\x03\x50\xf1'), # illegal data value exception (0x84, b'\x84\x04\x13\x03'), # skave device failure exception (0x85, b'\x85\x05\xd3\x53'), # acknowledge exception (0x86, b'\x86\x06\x93\xa2'), # slave device busy exception (0x87, b'\x87\x08\x53\xf2'), # memory parity exception (0x88, b'\x88\x0a\x16\x06'), # gateway path unavailable exception (0x89, b'\x89\x0b\xd6\x56'), # gateway target failed exception ) self.bad = ( (0x80, b'\x80\x00\x00\x00'), # Unknown Function (0x81, b'\x81\x00\x00\x00'), # error message )
class SimpleFactoryTest(unittest.TestCase): ''' This is the unittest for the pymod.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.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 testResponseLookup(self): ''' Test a working response factory lookup ''' for func, _ in self.response: response = self.client.lookupPduClass(func) self.assertNotEqual(response, None) def testRequestLookup(self): ''' Test a working request factory lookup ''' for func, _ in self.request: request = self.client.lookupPduClass(func) self.assertNotEqual(request, None) def testResponseWorking(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", func) def testResponseErrors(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 testRequestsWorking(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", func) def testClientFactoryFails(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 testServerFactoryFails(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 testRequestErrors(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")