コード例 #1
0
    def testExecute(self):
        client = MagicMock()
        client.framer = self._ascii
        client.framer._buffer = b'deadbeef'
        client.framer.processIncomingPacket = MagicMock()
        client.framer.processIncomingPacket.return_value = None
        client.framer.buildPacket = MagicMock()
        client.framer.buildPacket.return_value = b'deadbeef'
        client.framer.sendPacket = MagicMock()
        client.framer.sendPacket.return_value = len(b'deadbeef')

        request = MagicMock()
        request.get_response_pdu_size.return_value = 10
        request.unit_id = 1
        tm = ModbusTransactionManager(client)
        tm._recv = MagicMock(return_value=b'abcdef')
        self.assertEqual(tm.retries, 3)
        self.assertEqual(tm.retry_on_empty, False)
        # tm._transact = MagicMock()
        # some response
        # tm._transact.return_value = (b'abcdef', None)
        tm.getTransaction = MagicMock()
        tm.getTransaction.return_value = 'response'
        response = tm.execute(request)
        self.assertEqual(response, 'response')
        # No response
        tm._recv = MagicMock(return_value=b'abcdef')
        # tm._transact.return_value = (b'', None)
        tm.transactions = []
        tm.getTransaction = MagicMock()
        tm.getTransaction.return_value = None
        response = tm.execute(request)
        self.assertIsInstance(response, ModbusIOException)

        # No response with retries
        tm.retry_on_empty = True
        tm._recv = MagicMock(side_effect=iter([b'', b'abcdef']))
        # tm._transact.side_effect = [(b'', None), (b'abcdef', None)]
        response = tm.execute(request)
        self.assertIsInstance(response, ModbusIOException)

        # retry on invalid response
        tm.retry_on_invalid = True
        tm._recv = MagicMock(side_effect=iter([b'', b'abcdef', b'deadbe', b'123456']))
        # tm._transact.side_effect = [(b'', None), (b'abcdef', None)]
        response = tm.execute(request)
        self.assertIsInstance(response, ModbusIOException)

        # Unable to decode response
        tm._recv = MagicMock(side_effect=ModbusIOException())
        # tm._transact.side_effect = [(b'abcdef', None)]
        client.framer.processIncomingPacket.side_effect = MagicMock(side_effect=ModbusIOException())
        self.assertIsInstance(tm.execute(request), ModbusIOException)
コード例 #2
0
    def run(self):
        """ тут производится обновление """
        if self._logger is not None:
            self._logger.info("[{n}]: Попытка запуска испытания".format(n=self.name))
        try:
            self.reset()
        except ConnectionException:
            if self._logger is not None:
                self._logger.error("[{n}]: Невозможно подключиться к хосту [{h}]".format(n=self.name, h=self._host))
            raise ConnectionException("Не удалось подключиться к хосту {h}".format(h=self._host))

        if self._logger is not None:
            self._logger.info("[{n}]: Испытание запущено".format(n=self.name))

        try:
            while not self.__exit:
                self._update()
                time.sleep(self._invfreq)
        except AttributeError:
            if self._logger is not None:
                self._logger.error("[{n}]: Связь была прервана, необходим перезапуск испытания".format(n=self.name))
            raise ModbusIOException("Связь была оборвана")
        except ConnectionException:
            if self._logger is not None:
                self._logger.error("[{n}]: Невозможно подключиться к хосту [{h}]".format(n=self.name, h=self._host))
            raise ConnectionException("Не удалось подключиться к хосту {h}".format(h=self._host))
コード例 #3
0
    def processIncomingPacket(self, data, callback):
        ''' The new packet processing pattern

        This takes in a new request packet, adds it to the current
        packet stream, and performs framing on it. That is, checks
        for complete messages, and once found, will process all that
        exist.  This handles the case when we read N + 1 or 1 / N
        messages at a time instead of 1.

        The processed and decoded messages are pushed to the callback
        function to process and send.

        :param data: The new packet data
        :param callback: The function to send results to
        '''
        self.addToFrame(data)
        while self.isFrameReady():
            if self.checkFrame():
                result = self.decoder.decode(self.getFrame())
                if result is None:
                    raise ModbusIOException("Unable to decode response")
                self.populateResult(result)
                self.advanceFrame()
                callback(result)  # defer or push to a thread?
            else: break
コード例 #4
0
    def sync_write(self, value: int | float | str, obj: ModbusObj) -> None:
        """Write value to Modbus object.

        Args:
            value: Value to write
            obj: Object instance.
        """
        if obj.func_write is None:
            raise ModbusException("Object cannot be overwritten")
        if isinstance(value, str):
            raise NotImplementedError(
                "Modbus expected numbers to write. Got `str`.")

        payload = self._build_payload(value=value, obj=obj)

        if obj.func_write is ModbusWriteFunc.WRITE_REGISTER and isinstance(
                payload, list):
            # FIXME: hotfix
            assert len(payload) == 1
            payload = payload[0]  # type: ignore

        request = self.write_funcs[obj.func_write](
            obj.address,
            payload,
            unit=self._device_obj.property_list.rtu.unit,  # type: ignore
        )
        if request.isError():
            raise ModbusIOException("0x80")  # todo: resp.string
        self._LOG.debug("Successfully write",
                        extra={
                            "object": obj,
                            "value": value
                        })
コード例 #5
0
 def execute(self, request):
     _logger.info("AsyncFifoTransactionManager.execute(%s)", str(request))
     self.request = request
     self.request.transaction_id = self.getNextTID()
     self.frame = self.client.framer.buildPacket(self.request)
     try:
         self.recvsize = self.client.framer.getResponseSize(self.request)
     except NotImplementedException:
         self.recvsize = 0
     time_since_last_read = time.time() - self.client._last_frame_end
     _logger.info(" time_since_last_read: %f, _silent_interval: %f",
                  time_since_last_read, self.client._silent_interval)
     if time_since_last_read < self.client._silent_interval:
         _logger.debug(" will delay to wait for 3.5 char")
         self.client.ioloop.add_timeout(
             datetime.timedelta(seconds=(self.client._silent_interval -
                                         time_since_last_read)),
             partial(self._sendAsyncRequest, self.frame))
     else:
         try:
             self._sendSyncRequest(self.frame)
         except socket.error as ex:
             self.delTransaction(self.request.transaction_id)
             raise ModbusIOException(str(ex))
     return self._buildResponse(self.request.transaction_id)
コード例 #6
0
    def _sendPacket(self, message, callback):
        """
        Sends packets on the bus with 3.5char delay between frames
        :param message: Message to be sent over the bus
        :return:
        """
        @gen.coroutine
        def sleep(timeout):
            yield gen.sleep(timeout)

        try:
            waiting = self.stream.connection.in_waiting
            if waiting:
                result = self.stream.connection.read(waiting)
                LOGGER.info("Cleanup recv buffer before send: " +
                            hexlify_packets(result))
        except OSError as e:
            self.transaction.getTransaction(
                message.transaction_id).set_exception(ModbusIOException(e))
            return

        start = time.time()
        if self.last_frame_end:
            waittime = self.last_frame_end + self.silent_interval - start
            if waittime > 0:
                LOGGER.debug("Waiting for 3.5 char before next send - %f ms",
                             waittime)
                sleep(waittime)

        self.state = ModbusTransactionState.SENDING
        LOGGER.debug("send: " + hexlify_packets(message))
        self.stream.write(message, callback)
コード例 #7
0
ファイル: transaction.py プロジェクト: ibaranov-cp/jhu05
    def execute(self, request):
        ''' Starts the producer to send the next request to
        consumer.write(Frame(request))
        '''
        retries = self.retries
        request.transaction_id = self.getNextTID()
        _logger.debug("Running transaction %d" % request.transaction_id)
        expected_response_length = None
        if hasattr(request, "get_response_pdu_size"):
            response_pdu_size = request.get_response_pdu_size()
            if response_pdu_size:
                expected_response_length = self._calculate_response_length(
                    response_pdu_size)

        while retries > 0:
            try:
                last_exception = None
                self.client.connect()
                packet = self.client.framer.buildPacket(request)
                if _logger.isEnabledFor(logging.DEBUG):
                    _logger.debug("send: " +
                                  " ".join([hex(byte2int(x)) for x in packet]))
                self.client._send(packet)
                exception = False
                result = self.client._recv(expected_response_length or 1024)
                while result and expected_response_length and len(
                        result) < expected_response_length:
                    if not exception and not self._check_response(result):
                        exception = True
                        expected_response_length = self._calculate_exception_length(
                        )
                        continue
                    result += self.client._recv(expected_response_length -
                                                len(result))

                if not result and self.retry_on_empty:
                    retries -= 1
                    continue

                if _logger.isEnabledFor(logging.DEBUG):
                    _logger.debug("recv: " +
                                  " ".join([hex(byte2int(x)) for x in result]))
                self.client.framer.processIncomingPacket(
                    result, self.addTransaction)
                break
            except (socket.error, ModbusIOException,
                    InvalidResponseRecievedException) as msg:
                self.client.close()
                _logger.debug("Transaction failed. (%s) " % msg)
                retries -= 1
                last_exception = msg
        response = self.getTransaction(request.transaction_id)
        if not response:
            last_exception = last_exception or (
                "No Response "
                "received from the remote unit")
            response = ModbusIOException(last_exception)

        return response
コード例 #8
0
    def test_read_slave_registers_on_ModbusIOException_exits(self, MockExit):
        slave_id = 1
        self.mock_client.read_holding_registers.side_effect = ModbusIOException(
        )

        self.reader.read_slave(slave_id)

        MockExit.assert_called()
コード例 #9
0
ファイル: transaction.py プロジェクト: Qing-Q/ICSwiki
 def _process(self, callback, error=False):
     """
     Process incoming packets irrespective error condition
     """
     data = self.getRawFrame() if error else self.getFrame()
     result = self.decoder.decode(data)
     if result is None:
         raise ModbusIOException("Unable to decode request")
     self.populateResult(result)
     self.advanceFrame()
     callback(result)  # defer or push to a thread?
コード例 #10
0
 def _process(self, callback, error=False, client_address=None):
     """
     Process incoming packets irrespective error condition
     """
     data = self.getRawFrame() if error else self.getFrame()
     result = self.decoder.decode(data, client_address)
     if result is None:
         raise ModbusIOException("Unable to decode request")
     elif error and result.function_code < 0x80:
         raise InvalidMessageRecievedException(result)
     else:
         self.populateResult(result)
         self.advanceFrame()
         callback(result)  # defer or push to a thread?
コード例 #11
0
 def processIncomingPacket(self, data, callback):
     _logger.info("AsyncModbusRtuFramer.processIncomingPacket(%s)", str(data))
     _logger.debug("  FRAME READY? " + str(self.isFrameReady()))
     while self.isFrameReady():
         _logger.debug("  FRAME CHECK? " + str(self.checkFrame()))
         if self.checkFrame():
             result = self.decoder.decode(self.getFrame())
             if result is None:
                 raise ModbusIOException("Unable to decode response")
             self.populateResult(result)
             self.advanceFrame()
             self.resetFrame()
             callback(result)  # defer or push to a thread?
             return
         else: self.resetFrame() # clear possible errors
コード例 #12
0
    def sync_read(self, obj: ModbusObj) -> ModbusObj:
        """Read data from Modbus object.

        Updates object and return value.
        """
        resp = self.read_funcs[obj.func_read](
            address=obj.address,
            count=obj.quantity,
            unit=self._device_obj.property_list.rtu.unit,  # type: ignore
        )
        if resp.isError():
            obj.set_property(value=ModbusIOException(str(resp)))
        else:
            value = self._decode_response(resp=resp, obj=obj)
            obj.set_property(value=value)
        return obj
コード例 #13
0
    def processIncomingPacket(self, data, callback, unit, **kwargs):
        """
        The new packet processing pattern

        This takes in a new request packet, adds it to the current
        packet stream, and performs framing on it. That is, checks
        for complete messages, and once found, will process all that
        exist.  This handles the case when we read N + 1 or 1 // N
        messages at a time instead of 1.

        The processed and decoded messages are pushed to the callback
        function to process and send.

        :param data: The new packet data
        :param callback: The function to send results to
        :param unit: Process if unit id matches, ignore otherwise (could be a
               list of unit ids (server) or single unit id(client/server)
        :param single: True or False (If True, ignore unit address validation)

        """
        self.addToFrame(data)
        if not isinstance(unit, (list, tuple)):
            unit = [unit]
        single = kwargs.get('single', False)
        while self.isFrameReady():
            if self.checkFrame():
                if self._validate_unit_id(unit, single):
                    result = self.decoder.decode(self.getFrame())
                    if result is None:
                        raise ModbusIOException("Unable to decode response")
                    self.populateResult(result)
                    self.advanceFrame()
                    callback(result)  # defer or push to a thread?
                else:
                    _logger.debug("Not a valid unit id - {}, "
                                  "ignoring!!".format(self._header['uid']))
                    self.resetFrame()
                    break

            else:
                _logger.debug("Frame check failed, ignoring!!")
                self.resetFrame()
                break
コード例 #14
0
    def testTcpExecuteFailure(self):
        protocol = ModbusTcpProtocol()
        protocol.store = MagicMock()
        request = MagicMock()
        protocol._send = MagicMock()

        # CASE-1: test NoSuchSlaveException exceptions
        request.execute.side_effect = NoSuchSlaveException()
        self.assertRaises(NoSuchSlaveException, protocol._execute(request))
        self.assertTrue(request.doException.called)

        # CASE-2: NoSuchSlaveException with ignore_missing_slaves = true
        protocol.ignore_missing_slaves = True
        request.execute.side_effect = NoSuchSlaveException()
        self.assertEqual(protocol._execute(request), None)

        # test other exceptions
        request.execute.side_effect = ModbusIOException()
        self.assertRaises(ModbusIOException, protocol._execute(request))
        self.assertTrue(protocol._send.called)
コード例 #15
0
 def _on_timeout():
     LOGGER.warning("timeout")
     _clear_timer()
     if self.stream:
         self.io_loop.remove_handler(self.stream.fileno())
     self.framer.resetFrame()
     transaction = self.transaction.getTransaction(request.transaction_id)
     if self.state != ModbusTransactionState.IDLE:
         self.state = ModbusTransactionState.IDLE
         if self.stream:
             try:
                 waiting = self.stream.connection.in_waiting
                 if waiting:
                     result = self.stream.connection.read(waiting)
                     LOGGER.info(
                         "Cleanup recv buffer after timeout: " + hexlify_packets(result))
             except OSError as ex:
                 self.close()
                 if transaction:
                     transaction.set_exception(ModbusIOException(ex))
                 return
     if transaction:
         transaction.set_exception(TimeOutException())
コード例 #16
0
 def _on_fd_error(fd, *args):
     _clear_timer()
     self.io_loop.remove_handler(fd)
     self.close()
     self.transaction.getTransaction(
         request.transaction_id).set_exception(ModbusIOException(*args))
コード例 #17
0
    def testExecute(self, mock_time):
        mock_time.time.side_effect = count()

        client = MagicMock()
        client.framer = self._ascii
        client.framer._buffer = b'deadbeef'
        client.framer.processIncomingPacket = MagicMock()
        client.framer.processIncomingPacket.return_value = None
        client.framer.buildPacket = MagicMock()
        client.framer.buildPacket.return_value = b'deadbeef'
        client.framer.sendPacket = MagicMock()
        client.framer.sendPacket.return_value = len(b'deadbeef')
        client.framer.decode_data = MagicMock()
        client.framer.decode_data.return_value = {
            "unit": 1,
            "fcode": 222,
            "length": 27
        }
        request = MagicMock()
        request.get_response_pdu_size.return_value = 10
        request.unit_id = 1
        request.function_code = 222
        tm = ModbusTransactionManager(client)
        tm._recv = MagicMock(return_value=b'abcdef')
        self.assertEqual(tm.retries, 3)
        self.assertEqual(tm.retry_on_empty, False)
        # tm._transact = MagicMock()
        # some response
        # tm._transact.return_value = (b'abcdef', None)

        tm.getTransaction = MagicMock()
        tm.getTransaction.return_value = 'response'
        response = tm.execute(request)
        self.assertEqual(response, 'response')
        # No response
        tm._recv = MagicMock(return_value=b'abcdef')
        # tm._transact.return_value = (b'', None)
        tm.transactions = []
        tm.getTransaction = MagicMock()
        tm.getTransaction.return_value = None
        response = tm.execute(request)
        self.assertIsInstance(response, ModbusIOException)

        # No response with retries
        tm.retry_on_empty = True
        tm._recv = MagicMock(side_effect=iter([b'', b'abcdef']))
        # tm._transact.side_effect = [(b'', None), (b'abcdef', None)]
        response = tm.execute(request)
        self.assertIsInstance(response, ModbusIOException)

        # wrong handle_local_echo
        tm._recv = MagicMock(
            side_effect=iter([b'abcdef', b'deadbe', b'123456']))
        client.handle_local_echo = True
        tm.retry_on_empty = False
        tm.retry_on_invalid = False
        self.assertEqual(
            tm.execute(request).message, '[Input/Output] Wrong local echo')
        client.handle_local_echo = False

        # retry on invalid response
        tm.retry_on_invalid = True
        tm._recv = MagicMock(
            side_effect=iter([b'', b'abcdef', b'deadbe', b'123456']))
        # tm._transact.side_effect = [(b'', None), (b'abcdef', None)]
        response = tm.execute(request)
        self.assertIsInstance(response, ModbusIOException)

        # Unable to decode response
        tm._recv = MagicMock(side_effect=ModbusIOException())
        # tm._transact.side_effect = [(b'abcdef', None)]
        client.framer.processIncomingPacket.side_effect = MagicMock(
            side_effect=ModbusIOException())
        self.assertIsInstance(tm.execute(request), ModbusIOException)

        # Broadcast
        client.broadcast_enable = True
        request.unit_id = 0
        response = tm.execute(request)
        self.assertEqual(response, b'Broadcast write sent - '
                         b'no response expected')
コード例 #18
0
 def execute(self, request):
     """ Starts the producer to send the next request to
     consumer.write(Frame(request))
     """
     with self._transaction_lock:
         try:
             _logger.debug("Current transaction state - {}".format(
                 ModbusTransactionState.to_string(self.client.state))
             )
             retries = self.retries
             request.transaction_id = self.getNextTID()
             _logger.debug("Running transaction "
                           "{}".format(request.transaction_id))
             _buffer = hexlify_packets(self.client.framer._buffer)
             if _buffer:
                 _logger.debug("Clearing current Frame "
                               ": - {}".format(_buffer))
                 self.client.framer.resetFrame()
             broadcast = (self.client.broadcast_enable
                          and request.unit_id == 0)
             if broadcast:
                 self._transact(request, None, broadcast=True)
                 response = b'Broadcast write sent - no response expected'
             else:
                 expected_response_length = None
                 if not isinstance(self.client.framer, ModbusSocketFramer):
                     if hasattr(request, "get_response_pdu_size"):
                         response_pdu_size = request.get_response_pdu_size()
                         if isinstance(self.client.framer, ModbusAsciiFramer):
                             response_pdu_size = response_pdu_size * 2
                         if response_pdu_size:
                             expected_response_length = self._calculate_response_length(response_pdu_size)
                 if request.unit_id in self._no_response_devices:
                     full = True
                 else:
                     full = False
                 c_str = str(self.client)
                 if "modbusudpclient" in c_str.lower().strip():
                     full = True
                     if not expected_response_length:
                         expected_response_length = Defaults.ReadSize
                 response, last_exception = self._transact(
                     request,
                     expected_response_length,
                     full=full,
                     broadcast=broadcast
                 )
                 if not response and (
                         request.unit_id not in self._no_response_devices):
                     self._no_response_devices.append(request.unit_id)
                 elif request.unit_id in self._no_response_devices and response:
                     self._no_response_devices.remove(request.unit_id)
                 if not response and self.retry_on_empty and retries:
                     while retries > 0:
                         if hasattr(self.client, "state"):
                             _logger.debug("RESETTING Transaction state to "
                                           "'IDLE' for retry")
                             self.client.state = ModbusTransactionState.IDLE
                         _logger.debug("Retry on empty - {}".format(retries))
                         response, last_exception = self._transact(
                             request,
                             expected_response_length
                         )
                         if not response:
                             retries -= 1
                             continue
                         # Remove entry
                         self._no_response_devices.remove(request.unit_id)
                         break
                 addTransaction = partial(self.addTransaction,
                                          tid=request.transaction_id)
                 self.client.framer.processIncomingPacket(response,
                                                          addTransaction,
                                                          request.unit_id)
                 response = self.getTransaction(request.transaction_id)
                 if not response:
                     if len(self.transactions):
                         response = self.getTransaction(tid=0)
                     else:
                         last_exception = last_exception or (
                             "No Response received from the remote unit"
                             "/Unable to decode response")
                         response = ModbusIOException(last_exception,
                                                      request.function_code)
                 if hasattr(self.client, "state"):
                     _logger.debug("Changing transaction state from "
                                   "'PROCESSING REPLY' to "
                                   "'TRANSACTION_COMPLETE'")
                     self.client.state = (
                         ModbusTransactionState.TRANSACTION_COMPLETE)
             return response
         except ModbusIOException as ex:
             # Handle decode errors in processIncomingPacket method
             _logger.exception(ex)
             self.client.state = ModbusTransactionState.TRANSACTION_COMPLETE
             return ex
コード例 #19
0
        def _on_receive(fd, events):
            LOGGER.debug("_on_receive: %s, %s", fd, events)

            try:
                waiting = self.stream.connection.in_waiting
                if waiting:
                    LOGGER.debug("waiting = %d", waiting)
                    data = self.stream.connection.read(waiting)
                    LOGGER.debug(
                        "recv: " + hexlify_packets(data))
            except OSError as ex:
                _clear_timer()
                self.close()
                self.transaction.getTransaction(request.transaction_id).set_exception(ModbusIOException(ex))
                return

            self.framer.addToFrame(data)

            # check if we have regular frame or modbus exception
            fcode = self.framer.decode_data(self.framer.getRawFrame()).get("fcode", 0)
            if fcode and (
                  (fcode > 0x80 and len(self.framer.getRawFrame()) == exception_response_length)
                or
                  (len(self.framer.getRawFrame()) == expected_response_length)
            ):
                _clear_timer()
                self.io_loop.remove_handler(fd)
                self.state = ModbusTransactionState.IDLE
                self.framer.processIncomingPacket(
                    b'',            # already sent via addToFrame()
                    self._handle_response,
                    0,              # don't care for `single=True`
                    single=True,
                    tid=request.transaction_id
                )