Пример #1
0
    def handle(self):
        ''' Callback when we receive any data
        '''
        while self.running:
            try:
                data = self.request.recv(1024)
                if data:
                    if _logger.isEnabledFor(logging.DEBUG):
                        _logger.debug(
                            "recv: " +
                            " ".join([hex(byte2int(x)) for x in data]))
                    if isinstance(self.framer, ModbusAsciiFramer):
                        unit_address = int(data[1:3], 16)
                    elif isinstance(self.framer, ModbusBinaryFramer):
                        unit_address = byte2int(data[1])
                    else:
                        unit_address = byte2int(data[0])

                    if unit_address in self.server.context:
                        self.framer.processIncomingPacket(data, self.execute)
            except Exception as msg:
                # since we only have a single socket, we cannot exit
                # Clear frame buffer
                self.framer.resetFrame()
                _logger.error("Socket error occurred %s" % msg)
Пример #2
0
    def checkFrame(self):
        """
        Check if the next frame is available.
        Return True if we were successful.

        1. Populate header
        2. Discard frame if UID does not match
        """
        try:
            self.populateHeader()

            frame_size = self._header['len']
            # print(frame_size)
            # print(len(self._buffer))
            data = self._buffer[:frame_size - 2]
            crc = self._buffer[frame_size - 2:frame_size]
            crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
            # print(crc)
            # print(self._buffer.hex())
            # print(crc_val)
            # print(len(data))
            if checkCRC(data, crc_val):
                return True
            else:
                _logger.debug("CRC invalid, discarding header!!")
                self.resetFrame()
                return False
        except (IndexError, KeyError, struct.error):
            return False
Пример #3
0
    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
Пример #4
0
    def calculateRtuFrameSize(cls, buffer):
        ''' Calculates the size of the message

        :param buffer: A buffer containing the data that have been received.
        :returns: The number of bytes in the response.
        '''
        hi_byte = byte2int(buffer[2])
        lo_byte = byte2int(buffer[3])
        return (hi_byte << 16) + lo_byte + 6
Пример #5
0
    def calculateRtuFrameSize(cls, data):
        ''' Calculates the size of the message

        :param data: A buffer containing the data that have been received.
        :returns: The number of bytes in the response.
        '''
        hi_byte = byte2int(data[2])
        lo_byte = byte2int(data[3])
        return (hi_byte << 16) + lo_byte + 6
Пример #6
0
    def dataReceived(self, data):
        ''' Callback when we receive any data

        :param data: The data sent by the client
        '''
        if _logger.isEnabledFor(logging.DEBUG):
            _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
        if not self.factory.control.ListenOnly:
            unit_address = byte2int(data[0])
            if unit_address in self.factory.store:
                self.framer.processIncomingPacket(data, self._execute)
Пример #7
0
    def dataReceived(self, data):
        ''' Callback when we receive any data

        :param data: The data sent by the client
        '''
        if _logger.isEnabledFor(logging.DEBUG):
            _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
        if not self.factory.control.ListenOnly:
            unit_address = byte2int(data[0])
            if unit_address in self.factory.store:
                self.framer.processIncomingPacket(data, self._execute)
Пример #8
0
    def decode(self, data):
        ''' Decodes a the response

        Since the identifier is device dependent, we just return the
        raw value that a user can decode to whatever it should be.

        :param data: The packet data to decode
        '''
        self.byte_count = byte2int(data[0])
        self.identifier = data[1:self.byte_count + 1]
        status = byte2int(data[-1])
        self.status = status == ModbusStatus.SlaveOn
Пример #9
0
def hexlify_packets(packet):
    """
    Returns hex representation of bytestring recieved
    :param packet:
    :return:
    """
    if not packet:
        return ''
    if IS_PYTHON3:
        return " ".join([hex(byte2int(x)) for x in packet])
    else:
        return u" ".join([hex(byte2int(x)) for x in packet])
Пример #10
0
 def checkFrame(self):
     '''
     Check if the next frame is available. Return True if we were
     successful.
     '''
     try:
         self.populateHeader()
         frame_size = self.__header['len']
         data = self.__buffer[:frame_size - 2]
         crc = self.__buffer[frame_size - 2:frame_size]
         crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
         return checkCRC(data, crc_val)
     except (IndexError, KeyError):
         return False
Пример #11
0
    def decode(self, data):
        ''' Decodes a the response

        :param data: The packet data to decode
        '''
        length = byte2int(data[0])
        status = struct.unpack('>H', data[1:3])[0]
        self.status = (status == ModbusStatus.Ready)
        self.event_count = struct.unpack('>H', data[3:5])[0]
        self.message_count = struct.unpack('>H', data[5:7])[0]

        self.events = []
        for e in range(7, length + 1):
            self.events.append(byte2int(data[e]))
Пример #12
0
    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)
        self.client.framer.resetFrame()
        expected_response_length = None
        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)

        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._send(packet)
                # exception = False
                result = self._recv(expected_response_length or 1024)

                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, InvalidMessageRecievedException) 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:
            if len(self.transactions):
                response = self.getTransaction(tid=0)
            else:
                last_exception = last_exception or ("No Response "
                                                    "received from the remote unit")
                response = ModbusIOException(last_exception)

        return response
Пример #13
0
    def _check_response(self, response):
        ''' Checks if the response is a Modbus Exception.
        '''
        if isinstance(self.client.framer, ModbusSocketFramer):
            if len(response) >= 8 and byte2int(response[7]) > 128:
                return False
        elif isinstance(self.client.framer, ModbusAsciiFramer):
            if len(response) >= 5 and int(response[3:5], 16) > 128:
                return False
        elif isinstance(self.client.framer, (ModbusRtuFramer, ModbusBinaryFramer)):
            if len(response) >= 2 and byte2int(response[1]) > 128:
                return False

        return True
Пример #14
0
 def checkFrame(self):
     '''
     Check if the next frame is available. Return True if we were
     successful.
     '''
     try:
         self.populateHeader()
         frame_size = self._header['len']
         data = self._buffer[:frame_size - 2]
         crc = self._buffer[frame_size - 2:frame_size]
         crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
         return checkCRC(data, crc_val)
     except (IndexError, KeyError):
         return False
Пример #15
0
    def handle(self):
        '''Callback when we receive any data, until self.running becomes not True.  Blocks indefinitely
        awaiting data.  If shutdown is required, then the global socket.settimeout(<seconds>) may be
        used, to allow timely checking of self.running.  However, since this also affects socket
        connects, if there are outgoing socket connections used in the same program, then these will
        be prevented, if the specfied timeout is too short.  Hence, this is unreliable.

        To respond to Modbus...Server.server_close() (which clears each handler's self.running),
        derive from this class to provide an alternative handler that awakens from time to time when
        no input is available and checks self.running.  Use Modbus...Server( handler=... ) keyword
        to supply the alternative request handler class.

        '''
        while self.running:
            try:
                data = self.request.recv(1024)
                if not data: self.running = False
                if _logger.isEnabledFor(logging.DEBUG):
                    _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
                # if not self.server.control.ListenOnly:
                self.framer.processIncomingPacket(data, self.execute)
            except socket.timeout as msg:
                if _logger.isEnabledFor(logging.DEBUG):
                    _logger.debug("Socket timeout occurred %s", msg)
                pass
            except socket.error as msg:
                _logger.error("Socket error occurred %s" % msg)
                self.running = False
            except:
                _logger.error("Socket exception occurred %s" % traceback.format_exc() )
                self.running = False
Пример #16
0
 def handle(self):
     ''' Callback when we receive any data
     '''
     reset_frame = False
     while self.running:
         try:
             data, self.socket = self.request
             if not data:
                 self.running = False
             if _logger.isEnabledFor(logging.DEBUG):
                 _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
             # if not self.server.control.ListenOnly:
             self.framer.processIncomingPacket(data, self.execute)
         except socket.timeout:
             pass
         except socket.error as msg:
             _logger.error("Socket error occurred %s" % msg)
             self.running = False
             reset_frame = True
         except Exception as msg:
             _logger.error(msg)
             self.running = False
             reset_frame = True
         finally:
             if reset_frame:
                 self.framer.resetFrame()
                 reset_frame = False
Пример #17
0
    def _helper(self, data):
        """
        This factory is used to generate the correct request object
        from a valid request packet. This decodes from a list of the
        currently implemented request types.

        :param data: The request packet to decode
        :returns: The decoded request or illegal function request object
        """
        function_code = byte2int(data[0])
        request = self.__lookup.get(function_code, lambda: None)()
        if not request:
            _logger.debug("Factory Request[%d]" % function_code)
            request = IllegalFunctionRequest(function_code)
        else:
            fc_string = "%s: %s" % (
                str(self.__lookup[function_code]).split('.')[-1].rstrip(
                    "'>"),
                function_code
            )
            _logger.debug("Factory Request[%s]" % fc_string)
        request.decode(data[1:])

        if hasattr(request, 'sub_function_code'):
            lookup = self.__sub_lookup.get(request.function_code, {})
            subtype = lookup.get(request.sub_function_code, None)
            if subtype: request.__class__ = subtype

        return request
Пример #18
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
        '''
        _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
        self.addToFrame(data)
        while self.isFrameReady():
            if self.checkFrame():
                result = self.decoder.decode(self.getFrame())
                if result is None:
                    raise ModbusIOException("Unable to decode request")
                self.populateResult(result)
                self.advanceFrame()
                callback(result)  # defer or push to a thread?
            else:
                break
Пример #19
0
    def _helper(self, data, client_address=None):
        '''
        This factory is used to generate the correct request object
        from a valid request packet. This decodes from a list of the
        currently implemented request types.

        :param data: The request packet to decode
        :returns: The decoded request or illegal function request object
        '''
        function_code = byte2int(data[0])
        if client_address != None :
           extra = {
                'ip_source'   : client_address[0],
                'port_source' : client_address[1],
                'fonction_code' : function_code,
	    		'requete' : str(data)
            }
        else :
            extra = {
                'fonction_code' : function_code,
	    		'requete' : str(data)
            }
        #_logger.debug("test:"+ str(data))
        _logger.debug("traité " + str(extra),extra=extra)
        request = self.__lookup.get(function_code, lambda: None)()
        if not request:
            request = IllegalFunctionRequest(function_code)
        request.decode(data[1:])

        if hasattr(request, 'sub_function_code'):
            lookup = self.__sub_lookup.get(request.function_code, {})
            subtype = lookup.get(request.sub_function_code, None)
            if subtype: request.__class__ = subtype

        return request
Пример #20
0
 def handle(self):
     ''' Callback when we receive any data
     '''
     reset_frame = False
     while self.running:
         try:
             data, self.request = self.request
             if not data:
                 self.running = False
             if _logger.isEnabledFor(logging.DEBUG):
                 _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
             # if not self.server.control.ListenOnly:
             self.framer.processIncomingPacket(data, self.execute)
         except socket.timeout: pass
         except socket.error as msg:
             _logger.error("Socket error occurred %s" % msg)
             self.running = False
             reset_frame = True
         except Exception as msg:
             _logger.error(msg)
             self.running = False
             reset_frame = True
         finally:
             if reset_frame:
                 self.framer.resetFrame()
                 reset_frame = False
Пример #21
0
    def _helper(self, data):
        '''
        This factory is used to generate the correct response object
        from a valid response packet. This decodes from a list of the
        currently implemented request types.

        :param data: The response packet to decode
        :returns: The decoded request or an exception response object
        '''
        function_code = byte2int(data[0])
        _logger.debug("Factory Response[%d]" % function_code)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            code = function_code & 0x7f  # strip error portion
            response = ExceptionResponse(code, ecode.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])

        if hasattr(response, 'sub_function_code'):
            lookup = self.__sub_lookup.get(response.function_code, {})
            subtype = lookup.get(response.sub_function_code, None)
            if subtype: response.__class__ = subtype

        return response
Пример #22
0
    def decode(self, data):
        ''' Decodes response pdu

        :param data: The packet data to decode
        '''
        self.byte_count = byte2int(data[0])
        self.bits = unpack_bitstring(data[1:])
Пример #23
0
    def _helper(self, data):
        '''
        This factory is used to generate the correct response object
        from a valid response packet. This decodes from a list of the
        currently implemented request types.

        :param data: The response packet to decode
        :returns: The decoded request or an exception response object
        '''
        fc_string = function_code = byte2int(data[0])
        if function_code in self.__lookup:
            fc_string = "%s: %s" % (
                str(self.__lookup[function_code]).split('.')[-1].rstrip("'>"),
                function_code
            )
        _logger.debug("Factory Response[%s]" % fc_string)
        response = self.__lookup.get(function_code, lambda: None)()
        if function_code > 0x80:
            code = function_code & 0x7f  # strip error portion
            response = ExceptionResponse(code, ecode.IllegalFunction)
        if not response:
            raise ModbusException("Unknown response %d" % function_code)
        response.decode(data[1:])

        if hasattr(response, 'sub_function_code'):
            lookup = self.__sub_lookup.get(response.function_code, {})
            subtype = lookup.get(response.sub_function_code, None)
            if subtype: response.__class__ = subtype

        return response
Пример #24
0
    def handle(self):
        '''Callback when we receive any data, until self.running becomes not True.  Blocks indefinitely
        awaiting data.  If shutdown is required, then the global socket.settimeout(<seconds>) may be
        used, to allow timely checking of self.running.  However, since this also affects socket
        connects, if there are outgoing socket connections used in the same program, then these will
        be prevented, if the specfied timeout is too short.  Hence, this is unreliable.

        To respond to Modbus...Server.server_close() (which clears each handler's self.running),
        derive from this class to provide an alternative handler that awakens from time to time when
        no input is available and checks self.running.  Use Modbus...Server( handler=... ) keyword
        to supply the alternative request handler class.

        '''
        while self.running:
            try:
                data = self.request.recv(1024)
                if not data: self.running = False
                if _logger.isEnabledFor(logging.DEBUG):
                    _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
                # if not self.server.control.ListenOnly:
                self.framer.processIncomingPacket(data, self.execute)
            except socket.timeout as msg:
                if _logger.isEnabledFor(logging.DEBUG):
                    _logger.debug("Socket timeout occurred %s", msg)
                pass
            except socket.error as msg:
                _logger.error("Socket error occurred %s" % msg)
                self.running = False
            except:
                _logger.error("Socket exception occurred %s" %
                              traceback.format_exc())
                self.running = False
Пример #25
0
    def decode(self, data):
        ''' Decodes response pdu

        :param data: The packet data to decode
        '''
        self.byte_count = byte2int(data[0])
        self.bits = unpack_bitstring(data[1:])
Пример #26
0
    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)
        if hasattr(request, "get_response_pdu_size"):
            response_pdu_size = request.get_response_pdu_size()
            expected_response_length = self._calculate_response_length(
                response_pdu_size)
        else:
            expected_response_length = 1024

        while retries > 0:
            try:
                self.client.connect()
                self.client._send(self.client.framer.buildPacket(request))
                result = self.client._recv(expected_response_length)

                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 as msg:
                self.client.close()
                _logger.debug("Transaction failed. (%s) " % msg)
                retries -= 1
        return self.getTransaction(request.transaction_id)
Пример #27
0
    def _helper(self, data):
        """
        This factory is used to generate the correct request object
        from a valid request packet. This decodes from a list of the
        currently implemented request types.

        :param data: The request packet to decode
        :returns: The decoded request or illegal function request object
        """
        function_code = byte2int(data[0])
        request = self.__lookup.get(function_code, lambda: None)()
        if not request:
            log.event("Modbus, Illegal Function Request[%d]" % function_code)
            request = IllegalFunctionRequest(function_code)
        else:
            fc_string = "%s: %s" % (str(
                self.__lookup[function_code]).split('.')[-1].rstrip("'>"),
                                    function_code)
            log.event("Modbus, Request[%s]" % fc_string)
        request.decode(data[1:])

        if hasattr(request, 'sub_function_code'):
            lookup = self.__sub_lookup.get(request.function_code, {})
            subtype = lookup.get(request.sub_function_code, None)
            if subtype: request.__class__ = subtype

        return request
Пример #28
0
    def populateHeader(self):
        ''' Try to set the headers `uid`, `len` and `crc`.

        This method examines `self._buffer` and writes meta
        information into `self._header`. It calculates only the
        values for headers that are not already in the dictionary.

        Beware that this method will raise an IndexError if
        `self._buffer` is not yet long enough.
        '''
        self._header['uid'] = byte2int(self._buffer[0])
        func_code = byte2int(self._buffer[1])
        pdu_class = self.decoder.lookupPduClass(func_code)
        size = pdu_class.calculateRtuFrameSize(self._buffer)
        self._header['len'] = size
        self._header['crc'] = self._buffer[size - 2:size]
Пример #29
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
        '''
        _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
        self.addToFrame(data)
        while True:
            if self.isFrameReady():
                if self.checkFrame():
                    self._process(callback)
                else: self.resetFrame()
            else:
                if len(self._buffer):
                    # Possible error ???
                    if self._header['len'] < 2:
                        self._process(callback, error=True)
                break
Пример #30
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
        '''
        _logger.debug(' '.join([hex(byte2int(x)) for x in data]))
        self.addToFrame(data)
        while True:
            if self.isFrameReady():
                if self.checkFrame():
                    self._process(callback)
                else: self.resetFrame()
            else:
                if len(self.__buffer):
                    # Possible error ???
                    if self.__header['len'] < 2:
                        self._process(callback, error=True)
                break
Пример #31
0
    def populateHeader(self):
        ''' Try to set the headers `uid`, `len` and `crc`.

        This method examines `self.__buffer` and writes meta
        information into `self.__header`. It calculates only the
        values for headers that are not already in the dictionary.

        Beware that this method will raise an IndexError if
        `self.__buffer` is not yet long enough.
        '''
        self.__header['uid'] = byte2int(self.__buffer[0])
        func_code = byte2int(self.__buffer[1])
        pdu_class = self.decoder.lookupPduClass(func_code)
        size = pdu_class.calculateRtuFrameSize(self.__buffer)
        self.__header['len'] = size
        self.__header['crc'] = self.__buffer[size - 2:size]
Пример #32
0
    def execute(self, request=None):
        """
        Executes a transaction
        :param request: Request to be written on to the bus
        :return:
        """
        request.transaction_id = self.transaction.getNextTID()

        def callback(*args):
            LOGGER.debug("in callback - {}".format(request.transaction_id))
            while True:
                waiting = self.stream.connection.in_waiting
                if waiting:
                    data = self.stream.connection.read(waiting)
                    LOGGER.debug(
                        "recv: " + " ".join([hex(byte2int(x)) for x in data]))
                    unit = self.framer.decode_data(data).get("uid", 0)
                    self.framer.processIncomingPacket(
                        data,
                        self._handle_response,
                        unit,
                        tid=request.transaction_id
                    )
                    break

        packet = self.framer.buildPacket(request)
        LOGGER.debug("send: " + " ".join([hex(byte2int(x)) for x in packet]))
        self.stream.write(packet, callback=callback)
        f = self._build_response(request.transaction_id)
        return f
Пример #33
0
    def decode(self, data):
        ''' Decode the register response packet

        :param data: The response to decode
        '''
        bytecount = byte2int(data[0])
        for i in range(1, bytecount, 2):
            self.registers.append(struct.unpack('>H', data[i:i + 2])[0])
Пример #34
0
 def decode(self, data):
     """ Decodes response pdu
     :param data: The packet data to decode
     """
     byte_count = byte2int(data[0])
     self.values = []
     for i in range(1, byte_count + 1, 2):
         self.values.append(struct.unpack('>H', data[i:i + 2])[0])
Пример #35
0
    def decode(self, data):
        ''' Decode the register response packet

        :param data: The response to decode
        '''
        bytecount = byte2int(data[0])
        for i in range(1, bytecount, 2):
            self.registers.append(struct.unpack('>H', data[i:i + 2])[0])
Пример #36
0
    def _dataReceived(self, data):
        ''' Get response, check for valid message, decode result

        :param data: The data returned from the server
        '''
        _logger.debug("recv: " + " ".join([hex(byte2int(x)) for x in data]))
        unit = self.framer.decode_data(data).get("uid", 0)
        self.framer.processIncomingPacket(data, self._handleResponse, unit=unit)
Пример #37
0
    def checkFrame(self):
        """
        Check if the next frame is available.
        Return True if we were successful.

        1. Populate header
        2. Discard frame if UID does not match
        """
        try:
            self.populateHeader()
            frame_size = self._header['len']
            data = self._buffer[:frame_size - 2]
            crc = self._buffer[frame_size - 2:frame_size]
            crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
            return checkCRC(data, crc_val)
        except (IndexError, KeyError):
            return False
Пример #38
0
    def checkFrame(self):
        """
        Check if the next frame is available.
        Return True if we were successful.

        1. Populate header
        2. Discard frame if UID does not match
        """
        try:
            self.populateHeader()
            frame_size = self._header['len']
            data = self._buffer[:frame_size - 2]
            crc = self._header['crc']
            crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
            return checkCRC(data, crc_val)
        except (IndexError, KeyError, struct.error):
            return False
Пример #39
0
    def _dataReceived(self, data):
        ''' Get response, check for valid message, decode result

        :param data: The data returned from the server
        '''
        _logger.debug("recv: " + " ".join([hex(byte2int(x)) for x in data]))
        unit = self.framer.decode_data(data).get("uid", 0)
        self.framer.processIncomingPacket(data, self._handleResponse, unit=unit)
Пример #40
0
def hexlify_packets(packet):
    """
    Returns hex representation of bytestring recieved
    :param packet:
    :return:
    """
    if not packet:
        return ''
    return " ".join([hex(byte2int(x)) for x in packet])
    def decode(self, data):
        """ Decodes response pdu

        :param data: The packet data to decode
        """
        byte_count = byte2int(data[0])
        self.values = []
        for i in range(1, byte_count + 1, 2):
            self.values.append(struct.unpack('>H', data[i:i + 2])[0])
Пример #42
0
    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:
                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 as msg:
                self.client.close()
                _logger.debug("Transaction failed. (%s) " % msg)
                retries -= 1
        return self.getTransaction(request.transaction_id)
Пример #43
0
 def execute(self, request, **kwargs):
     """
     Starts the producer to send the next request to
     consumer.write(Frame(request))
     """
     request.transaction_id = self.transaction.getNextTID()
     packet = self.framer.buildPacket(request)
     _logger.debug("send: " + " ".join([hex(byte2int(x)) for x in packet]))
     self.transport.write(packet)
     return self._buildResponse(request.transaction_id)
Пример #44
0
 def execute(self, request, **kwargs):
     """
     Starts the producer to send the next request to
     consumer.write(Frame(request))
     """
     request.transaction_id = self.transaction.getNextTID()
     packet = self.framer.buildPacket(request)
     _logger.debug("send: " + " ".join([hex(byte2int(x)) for x in packet]))
     self.transport.write(packet)
     return self._buildResponse(request.transaction_id)
Пример #45
0
    def datagramReceived(self, data, addr):
        ''' Callback when we receive any data

        :param data: The data sent by the client
        '''
        _logger.debug("Client Connected [%s]" % addr)
        if _logger.isEnabledFor(logging.DEBUG):
            _logger.debug(" ".join([hex(byte2int(x)) for x in data]))
        if not self.control.ListenOnly:
            continuation = lambda request: self._execute(request, addr)
            self.framer.processIncomingPacket(data, continuation)
Пример #46
0
    def datagramReceived(self, data, addr):
        ''' Callback when we receive any data

        :param data: The data sent by the client
        '''
        _logger.debug("Client Connected [%s]" % addr)
        if _logger.isEnabledFor(logging.DEBUG):
            _logger.debug(" ".join([hex(byte2int(x)) for x in data]))
        if not self.control.ListenOnly:
            continuation = lambda request: self._execute(request, addr)
            self.framer.processIncomingPacket(data, continuation)
Пример #47
0
 def execute(self, request=None):
     """
     Executes a transaction
     :param request:
     :return:
     """
     request.transaction_id = self.transaction.getNextTID()
     packet = self.framer.buildPacket(request)
     LOGGER.debug("send: " + " ".join([hex(byte2int(x)) for x in packet]))
     self.stream.write(packet)
     return self._build_response(request.transaction_id)
Пример #48
0
    def populateHeader(self, data=None):
        """
        Try to set the headers `uid`, `len` and `crc`.

        This method examines `self._buffer` and writes meta
        information into `self._header`.

        Beware that this method will raise an IndexError if
        `self._buffer` is not yet long enough.
        """
        data = data if data is not None else self._buffer
        self._header['uid'] = byte2int(data[0])
        func_code = byte2int(data[1])
        pdu_class = self.decoder.lookupPduClass(func_code)
        size = pdu_class.calculateRtuFrameSize(data)
        self._header['len'] = size

        if len(data) < size:
            # crc yet not available
            raise IndexError
        self._header['crc'] = data[size - 2:size]
Пример #49
0
def unpack_bitstring(string):
    """ Creates bit array out of a string

    :param string: The modbus data packet to decode

    example::

        bytes  = 'bytes to decode'
        result = unpack_bitstring(bytes)
    """
    byte_count = len(string)
    bits = []
    for byte in range(byte_count):
        if IS_PYTHON3:
            value = byte2int(int(string[byte]))
        else:
            value = byte2int(string[byte])
        for _ in range(8):
            bits.append((value & 1) == 1)
            value >>= 1
    return bits
Пример #50
0
def unpack_bitstring(string):
    """ Creates bit array out of a string

    :param string: The modbus data packet to decode

    example::

        bytes  = 'bytes to decode'
        result = unpack_bitstring(bytes)
    """
    byte_count = len(string)
    bits = []
    for byte in range(byte_count):
        if IS_PYTHON3:
            value = byte2int(int(string[byte]))
        else:
            value = byte2int(string[byte])
        for _ in range(8):
            bits.append((value & 1) == 1)
            value >>= 1
    return bits
Пример #51
0
    def decode(self, data):
        ''' Decodes the incoming request

        :param data: The data to decode into the address
        '''
        self.records = []
        byte_count = byte2int(data[0])
        for count in range(1, byte_count, 7):
            decoded = struct.unpack('>BHHH', data[count:count+7])
            record  = FileRecord(file_number=decoded[1],
                record_number=decoded[2], record_length=decoded[3])
            if decoded[0] == 0x06: self.records.append(record)
Пример #52
0
    def on_receive(self, *args):
        """
        On data recieve call back
        :param args: data received
        :return:
        """
        data = args[0] if len(args) > 0 else None

        if not data:
            return
        LOGGER.debug("recv: " + " ".join([hex(byte2int(x)) for x in data]))
        unit = self.framer.decode_data(data).get("uid", 0)
        self.framer.processIncomingPacket(data, self._handle_response, unit=unit)
Пример #53
0
    def checkFrame(self):
        """
        Check if the next frame is available.
        Return True if we were successful.

        1. Populate header
        2. Discard frame if UID does not match
        """
        try:
            self.populateHeader()
            frame_size = self._header['len']
            data = self._buffer[:frame_size - 2]
            crc = self._buffer[frame_size - 2:frame_size]
            crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
            if checkCRC(data, crc_val):
                return True
            else:
                _logger.debug("CRC invalid, discarding header!!")
                self.resetFrame()
                return False
        except (IndexError, KeyError, struct.error):
            return False
Пример #54
0
    def decode(self, data):
        ''' Decodes a the response

        :param data: The packet data to decode
        '''
        count, self.records = 1, []
        byte_count = byte2int(data[0])
        while count < byte_count:
            response_length, reference_type = struct.unpack('>BB', data[count:count+2])
            count += response_length + 1 # the count is not included
            record = FileRecord(response_length=response_length,
                record_data=data[count - response_length + 1:count])
            if reference_type == 0x06: self.records.append(record)
Пример #55
0
def computeLRC(data):
    """ Used to compute the longitudinal redundancy check
    against a string. This is only used on the serial ASCII
    modbus protocol. A full description of this implementation
    can be found in appendex B of the serial line modbus description.

    :param data: The data to apply a lrc to
    :returns: The calculated LRC

    """
    lrc = sum(byte2int(a) for a in data) & 0xff
    lrc = (lrc ^ 0xff) + 1
    return lrc & 0xff