Exemple #1
0
    def _recv( self, size ):
        """Replicate the approximate semantics of a socket recv; return what's available.  However,
        don't return Nothing (indicating an EOF).  So, wait for up to remaining 'self.timeout'
        for something to show up, but return immediately with whatever is there.

        We'll do it simply -- just read one at a time from the serial port.  We could find out how
        many bytes are available using the TIOCINQ ioctl, but this won't work on non-Posix systems.
        We can't just use the built-in Serial's read method and adjust its own _timeout to reflect
        our own remaining timeout -- we must only block 'til we have at least one character, and
        then continue reading 'til no more input is immediately available; there is no way to invoke
        Serial.read to indicate that.

        """
        if not self.socket:
            raise ConnectionException( self.__str__() )
        begun			= misc.timer()
        request			= None
        try:
            request		= modbus_rtu_read( fd=self.socket.fd, decoder=self.framer.decoder,
                                                   size=size, timeout=self.timeout )
        except Exception as exc:
            logging.warning( "Receive Exception %s; %s", exc, traceback.format_exc() )

        if request:
            return request

        # Nothing within timeout; potential client failure, disconnected hardware?  Force a re-open
        self.close()
        logging.debug( "Receive failure in %7.3f/%7.3fs", misc.timer() - begun, self.timeout )
        raise ConnectionException("Receive from (%s, %s) failed: Timeout" % (
            getattr( self, 'host', '(serial)' ), self.port ))
Exemple #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))
Exemple #3
0
    def _send(self, request):
        """ Sends data on the underlying socket

        If receive buffer still holds some data then flush it.

        Sleep if last send finished less than 3.5 character
        times ago.

        :param request: The encoded request to send
        :return: The number of bytes written
        """
        if not self.socket:
            raise ConnectionException(self.__str__())
        if request:
            try:
                waitingbytes = self._in_waiting()
                if waitingbytes:
                    result = self.socket.read(waitingbytes)
                    if _logger.isEnabledFor(logging.WARNING):
                        _logger.warning("Cleanup recv buffer before "
                                        "send: " + hexlify_packets(result))
            except NotImplementedError:
                pass

            size = self.socket.write(request)
            return size
        return 0
Exemple #4
0
    async def read_voltage(self):
        """reads the voltage off of ADAM-6024's inputs for channels 0-5.

        Parameters
        ----------
        None

        Returns
        -------
        volts : List of floats
            the voltages on the ADAM's input channels
        """
        try:
            readout = await self.client.read_input_registers(0, 8, unit=1)
            voltages = [self.counts_to_volts(r) for r in readout.registers]
            return voltages
        except AttributeError:
            # read_input_registers() *returns* (not raises) a
            # ModbusIOException in the event of loss of ADAM network
            # connectivity, which causes an AttributeError when we try
            # to access the registers field. But the whole thing is
            # really a connectivity problem, so we re-raise it as a
            # ConnectionException, which we know how to handle. Weird
            # exception handling is a known issue with pymodbus so it
            # may see a fix in a future version, which may require
            # minor code changes on our part.
            # https://github.com/riptideio/pymodbus/issues/298
            raise ConnectionException(f"Unable to reach modbus device at "
                                      f"{self.clientip}:{self.clientport}.")
Exemple #5
0
    def _send(self, request):
        ''' Sends data on the underlying socket

        If receive buffer still holds some data then flush it.

        Sleep if last send finished less than 3.5 character
        times ago.

        :param request: The encoded request to send
        :return: The number of bytes written
        '''
        if not self.socket:
            raise ConnectionException(self.__str__())
        if request:
            ts = time.time()
            if ts < self._last_frame_end + self._silent_interval:
                _logger.debug("will sleep to wait for 3.5 char")
                time.sleep(self._last_frame_end + self._silent_interval - ts)

            try:
                waitingbytes = self.socket.inWaiting()
                if waitingbytes:
                    result = self.socket.read(waitingbytes)
                    if _logger.isEnabledFor(logging.WARNING):
                        _logger.warning("cleanup recv buffer before send: " +
                                        " ".join([hex(ord(x))
                                                  for x in result]))
            except NotImplementedError:
                pass

            size = self.socket.write(request)
            self._last_frame_end = time.time()
            return size
        return 0
Exemple #6
0
    def _handle_abrupt_socket_close(self, size, data, duration):
        """ Handle unexpected socket close by remote end

        Intended to be invoked after determining that the remote end
        has unexpectedly closed the connection, to clean up and handle
        the situation appropriately.

        :param size: The number of bytes that was attempted to read
        :param data: The actual data returned
        :param duration: Duration from the read was first attempted
               until it was determined that the remote closed the
               socket
        :return: The more than zero bytes read from the remote end
        :raises: ConnectionException If the remote end didn't send any
                 data at all before closing the connection.
        """
        self.close()
        readsize = ("read of %s bytes" % size if size else "unbounded read")
        msg = ("%s: Connection unexpectedly closed "
               "%.6f seconds into %s" % (self, duration, readsize))
        if data:
            result = b"".join(data)
            msg += " after returning %s bytes" % len(result)
            _logger.warning(msg)
            return result
        msg += " without response from unit before it closed connection"
        raise ConnectionException(msg)
Exemple #7
0
    def _recv(self, size):
        """ Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read if the peer sent a response, or a zero-length
                 response if no data packets were received from the client at
                 all.
        :raises: ConnectionException if the socket is not initialized, or the
                 peer either has closed the connection before this method is
                 invoked or closes it before sending any data before timeout.
        """
        if not self.socket:
            raise ConnectionException(self.__str__())

        # socket.recv(size) waits until it gets some data from the host but
        # not necessarily the entire response that can be fragmented in
        # many packets.
        # To avoid the splitted responses to be recognized as invalid
        # messages and to be discarded, loops socket.recv until full data
        # is received or timeout is expired.
        # If timeout expires returns the read data, also if its length is
        # less than the expected size.
        self.socket.setblocking(0)

        timeout = self.timeout

        # If size isn't specified read up to 4096 bytes at a time.
        if size is None:
            recv_size = 4096
        else:
            recv_size = size

        data = []
        data_length = 0
        time_ = time.time()
        end = time_ + timeout
        while recv_size > 0:
            ready = select.select([self.socket], [], [], end - time_)
            if ready[0]:
                recv_data = self.socket.recv(recv_size)
                if recv_data == b'':
                    return self._handle_abrupt_socket_close(
                        size, data,
                        time.time() - time_)
                data.append(recv_data)
                data_length += len(recv_data)
            time_ = time.time()

            # If size isn't specified continue to read until timeout expires.
            if size:
                recv_size = size - data_length

            # Timeout is reduced also if some data has been received in order
            # to avoid infinite loops when there isn't an expected response
            # size and the slave sends noisy data continuosly.
            if time_ > end:
                break

        return b"".join(data)
Exemple #8
0
    def test_read_slave_registers_on_ConnectionException_exits(self, MockExit):
        slave_id = 1
        self.mock_client.read_holding_registers.side_effect = ConnectionException(
        )

        self.reader.read_slave(slave_id)

        MockExit.assert_called()
Exemple #9
0
    def __enter__(self):
        """ Implement the client with enter block

        :returns: The current instance of the client
        """
        if not self.connect():
            raise ConnectionException("Failed to connect[%s]" % (self.__str__()))
        return self
Exemple #10
0
 def execute(self, request=None):
     '''
     :param request: The request to process
     :returns: The result of the request execution
     '''
     if self.transaction:
         return self.transaction.execute(request)
     raise ConnectionException("Client Not Connected")
Exemple #11
0
 def execute(self, request=None):
     """
     :param request: The request to process
     :returns: The result of the request execution
     """
     if not self.connect():
         raise ConnectionException("Failed to connect[%s]" % (self.__str__()))
     return self.transaction.execute(request)
Exemple #12
0
    def _recv(self, size):
        """ Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read
        """
        if not self.socket:
            raise ConnectionException(self.__str__())
        return self.socket.recvfrom(size)[0]
Exemple #13
0
    def _recv( self, size ):
        """On a receive timeout, closes the socket and raises a ConnectionException.  Otherwise,
        returns the available input."""
        if not self.socket:
            raise ConnectionException( self.__str__() )
        begun			= misc.timer()
        timeout			= self.timeout # This computes the remaining timeout available
        logging.debug( "Receive begins  in %7.3f/%7.3fs", misc.timer() - begun, timeout )
        r,w,e			= select.select( [self.socket], [], [], timeout )
        if r:
            logging.debug( "Receive reading in %7.3f/%7.3fs", misc.timer() - begun, timeout )
            result		= super( modbus_client_tcp, self )._recv( size )
            logging.debug( "Receive success in %7.3f/%7.3fs", misc.timer() - begun, timeout )
            return result

        self.close()
        logging.debug( "Receive failure in %7.3f/%7.3fs", misc.timer() - begun, timeout )
        raise ConnectionException("Receive from (%s, %s) failed: Timeout" % (
                getattr( self, 'host', '(serial)' ), self.port ))
Exemple #14
0
    def connectionLost(self, reason):
        """ Called upon a client disconnect

        :param reason: The reason for the disconnect
        """
        _logger.debug("Client disconnected from modbus server: %s" % reason)
        self._connected = False
        for tid in list(self.transaction):
            self.transaction.getTransaction(tid).errback(
                Failure(ConnectionException('Connection lost during request')))
Exemple #15
0
    def setTransport(self, stream):

        # clear frame buffer
        self.framer.advanceFrame()
        # clear all transaction with exception
        for tid in self.transaction:
            future = self.transaction.getTransaction(tid)
            future.set_exception(ConnectionException("Slave closed"))
        self.transport = stream
        self.connected = stream != None
Exemple #16
0
    def _recv(self, size):
        ''' Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read
        '''
        if not self.socket:
            raise ConnectionException(self.__str__())
        result = self.socket.read(size)
        self._last_frame_end = time.time()
        return result
Exemple #17
0
    def _send(self, request):
        ''' Sends data on the underlying socket

        :param request: The encoded request to send
        :return: The number of bytes written
        '''
        if not self.socket:
            raise ConnectionException(self.__str__())
        if request:
            return self.socket.write(request)
        return 0
Exemple #18
0
    def test__ProductionDevice_getRegisters__NoConnection(self):

        plant = ProductionPlant()
        plant.load('test_data/modmap_testing.yaml', self.testPlantname())

        for dev in plant.devices:
            dev.get_registers = Mock(
                side_effect=ConnectionException('Failed to connect'))

        # No Raises
        plant.get_registers()
Exemple #19
0
    def _send(self, request):
        """ Sends data on the underlying socket

        :param request: The encoded request to send
        :return: The number of bytes written
        """
        if not self.socket:
            raise ConnectionException(self.__str__())
        if request:
            return self.socket.sendto(request, (self.host, self.port))
        return 0
Exemple #20
0
 async def connect(self, ip, port):
     self.clientip = ip
     self.clientport = port
     if self.simulation_mode:
         self.client = MockModbusClient(self.clientip, self.clientport)
     else:
         try:
             self.client = ModbusClient(self.clientip, self.clientport)
         except AttributeError:
             raise ConnectionException(
                 "Unable to connect to modbus device at "
                 f"{self.clientip}:{self.clientport}.")
Exemple #21
0
    def _buildResponse(self):
        ''' Helper method to return a deferred response
        for the current request.

        :returns: A defer linked to the latest request
        '''
        if not self._connected:
            return defer.fail(ConnectionException('Client is not connected'))

        d = defer.Deferred()
        self._requests.append(d)
        return d
Exemple #22
0
    def _recv(self, size):
        """ Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read
        """
        if not self.socket:
            raise ConnectionException(self.__str__())
        if size is None:
            size = self._wait_for_data()
        result = self.socket.read(size)
        return result
Exemple #23
0
 def execute(self, request):
     ''' Starts the producer to send the next request to
     consumer.write(Frame(request))
     '''
     request.transaction_id = self.transaction.getNextTID()
     packet = self.framer.buildPacket(request)
     if not self.transport:
         raise ConnectionException("Slave not connected")
     yield self.transport.write(packet)
     future = TracebackFuture()
     self.transaction.addTransaction(future, request.transaction_id)
     res = yield future
     raise gen.Return(res)
Exemple #24
0
    def _recv(self, size):
        ''' Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read
        '''
        if not self.socket:
            raise ConnectionException(self.__str__())

        rd = self.socket.read(size)
        if _logger.isEnabledFor(logging.DEBUG):
            _logger.debug(" ".join([hex(ord(x)) for x in rd]))
        return rd
Exemple #25
0
    def _build_response(self, tid):
        """
        Prepare for a response, returns a future
        :param tid:
        :return: Future
        """
        f = Future()

        if not self._connected:
            f.set_exception(ConnectionException("Client is not connected"))
            return f

        self.transaction.addTransaction(f, tid)
        return f
Exemple #26
0
    def _recv(self, size):
        """ Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read
        """
        if not self.socket:
            raise ConnectionException(self.__str__())
        if size is None:
            _logger.debug("Shall wait for data")
            size = self._wait_for_data()
        result = self.socket.read(size)
        _logger.debug("Finished reading socket....")
        return result
Exemple #27
0
    def _buildResponse(self, tid):
        """ Helper method to return a deferred response
        for the current request.

        :param tid: The transaction identifier for this response
        :returns: A defer linked to the latest request
        """
        if not self._connected:
            return defer.fail(
                Failure(ConnectionException('Client is not connected')))

        d = defer.Deferred()
        self.transaction.addTransaction(d, tid)
        return d
Exemple #28
0
    def _buildResponse(self, tid):
        """
        Helper method to return a deferred response
        for the current request.

        :param tid: The transaction identifier for this response
        :returns: A defer linked to the latest request
        """
        f = self.create_future()
        if not self._connected:
            self.raise_future(f,
                              ConnectionException('Client is not connected'))
        else:
            self.transaction.addTransaction(f, tid)
        return f
Exemple #29
0
    def _send(self, request):
        ''' Sends data on the underlying socket

        :param request: The encoded request to send
        :return: The number of bytes written
        '''
        if not self.socket:
            raise ConnectionException(self.__str__())
        if request:
            self.socket.flushInput()
            n = self.socket.write(request)
            if _logger.isEnabledFor(logging.DEBUG):
                _logger.debug("   written %d bytes" % n)
                _logger.debug(" ".join([hex(ord(x)) for x in request]))
            return n
        return 0
Exemple #30
0
    def _send(self, request):
        """ Sends data on the underlying socket

        :param request: The encoded request to send
        :return: The number of bytes written
        """
        if not self.socket:
            raise ConnectionException(self.__str__())
        if self.state == ModbusTransactionState.RETRYING:
            data = self._check_read_buffer()
            if data:
                return data

        if request:
            return self.socket.send(request)
        return 0