Example #1
0
 def _handle(self, request):
     """handle a received sentence"""
     
     if self._verbose:
         LOGGER.debug(utils.get_log_buffer("-->", request))
     
     #gets a query for analyzing the request
     query = self._make_query()
     
     retval = call_hooks("modbus.Server.before_handle_request", (self, request))
     if retval:
         request = retval
         
     response = self._databank.handle_request(query, request)
     retval = call_hooks("modbus.Server.after_handle_request", (self, response))
     if retval:
         response = retval
             
     if response and self._verbose:
         LOGGER.debug(utils.get_log_buffer("<--", response))
     return response
Example #2
0
    def _handle(self, request):
        """handle a received sentence"""

        if self._verbose:
            LOGGER.debug(utils.get_log_buffer("-->", request))

        #gets a query for analyzing the request
        query = self._make_query()

        retval = call_hooks("modbus.Server.before_handle_request", (self, request))
        if retval:
            request = retval

        response = self._databank.handle_request(query, request)
        retval = call_hooks("modbus.Server.after_handle_request", (self, response))
        if retval:
            response = retval

        if response and self._verbose:
            LOGGER.debug(utils.get_log_buffer("<--", response))
        return response
Example #3
0
    def handle_request(self, request_pdu, broadcast=False):
        """
        parse the request pdu, makes the corresponding action
        and returns the response pdu
        """
        with self._data_lock:  #thread-safe
            try:
                retval = call_hooks("modbus.Slave.handle_request",
                                    (self, request_pdu))
                if retval <> None:
                    return retval

                # get the function code
                (function_code, ) = struct.unpack(">B", request_pdu[0])

                # check if the function code is valid. If not returns error response
                if not self._fn_code_map.has_key(function_code):
                    raise ModbusError(defines.ILLEGAL_FUNCTION)

                # if read query is broadcasted raises an error
                cant_be_broadcasted = (defines.READ_COILS,
                                       defines.READ_DISCRETE_INPUTS,
                                       defines.READ_INPUT_REGISTERS,
                                       defines.READ_HOLDING_REGISTERS)
                if broadcast and (function_code in cant_be_broadcasted):
                    raise ModbusInvalidRequestError(
                        "Function %d can not be broadcasted" % function_code)

                #execute the corresponding function
                response_pdu = self._fn_code_map[function_code](request_pdu)
                if response_pdu:
                    if broadcast:
                        call_hooks("modbus.Slave.on_handle_broadcast",
                                   (self, response_pdu))
                        LOGGER.debug(
                            "broadcast: %s" %
                            (utils.get_log_buffer("!!", response_pdu)))
                        return ""
                    else:
                        return struct.pack(">B", function_code) + response_pdu
                raise Exception("No response for function %d" % function_code)

            except ModbusError, excpt:
                LOGGER.debug(str(excpt))
                call_hooks("modbus.Slave.on_exception",
                           (self, function_code, excpt))
                return struct.pack(">BB", function_code + 128,
                                   excpt.get_exception_code())
Example #4
0
    def handle_request(self, request_pdu, broadcast=False):
        """
        parse the request pdu, makes the corresponding action
        and returns the response pdu
        """
        with self._data_lock:  # thread-safe
            try:
                retval = call_hooks("modbus.Slave.handle_request", (self, request_pdu))
                if retval <> None:
                    return retval

                # get the function code
                (function_code,) = struct.unpack(">B", request_pdu[0])

                # check if the function code is valid. If not returns error response
                if not self._fn_code_map.has_key(function_code):
                    raise ModbusError(defines.ILLEGAL_FUNCTION)

                # if read query is broadcasted raises an error
                cant_be_broadcasted = (
                    defines.READ_COILS,
                    defines.READ_DISCRETE_INPUTS,
                    defines.READ_INPUT_REGISTERS,
                    defines.READ_HOLDING_REGISTERS,
                )
                if broadcast and (function_code in cant_be_broadcasted):
                    raise ModbusInvalidRequestError("Function %d can not be broadcasted" % function_code)

                # execute the corresponding function
                response_pdu = self._fn_code_map[function_code](request_pdu)
                if response_pdu:
                    if broadcast:
                        call_hooks("modbus.Slave.on_handle_broadcast", (self, response_pdu))
                        LOGGER.debug("broadcast: %s" % (utils.get_log_buffer("!!", response_pdu)))
                        return ""
                    else:
                        return struct.pack(">B", function_code) + response_pdu
                raise Exception("No response for function %d" % function_code)

            except ModbusError, excpt:
                LOGGER.debug(str(excpt))
                call_hooks("modbus.Slave.on_exception", (self, function_code, excpt))
                return struct.pack(">BB", function_code + 128, excpt.get_exception_code())
Example #5
0
    def execute(self, slave, function_code, starting_address,
                quantity_of_x=0, output_value=0, data_format="", expected_length=-1):
        """
        Execute a modbus query and returns the data part of the answer as a tuple
        The returned tuple depends on the query function code. see modbus protocol
        specification for details
        data_format makes possible to extract the data like defined in the
        struct python module documentation
        """

        pdu = ""
        is_read_function = False
        nb_of_digits = 0

        #open the connection if it is not already done
        self.open()

        #Build the modbus pdu and the format of the expected data.
        #It depends of function code. see modbus specifications for details.
        if function_code == defines.READ_COILS or function_code == defines.READ_DISCRETE_INPUTS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address, quantity_of_x)
            byte_count = quantity_of_x / 8
            if (quantity_of_x % 8) > 0:
                byte_count += 1
            nb_of_digits = quantity_of_x
            if not data_format:
                data_format = ">"+(byte_count*"B")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = byte_count + 5  #slave + func + bytcodeLen + bytecode + crc1 + crc2

        elif function_code == defines.READ_INPUT_REGISTERS or function_code == defines.READ_HOLDING_REGISTERS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address, quantity_of_x)
            if not data_format:
                data_format = ">"+(quantity_of_x*"H")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 2*quantity_of_x + 5  #slave + func + bytcodeLen + bytecode x 2 + crc1 + crc2

        elif (function_code == defines.WRITE_SINGLE_COIL) or (function_code == defines.WRITE_SINGLE_REGISTER):
            if function_code == defines.WRITE_SINGLE_COIL:
                if output_value != 0:
                    output_value = 0xff00
            pdu = struct.pack(">BHH", function_code, starting_address, output_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + value1+value2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_COILS:
            byte_count = len(output_value) / 8
            if (len(output_value) % 8) > 0:
                byte_count += 1
            pdu = struct.pack(">BHHB", function_code, starting_address, len(output_value), byte_count)
            i, byte_value = 0, 0
            for j in output_value:
                if j > 0:
                    byte_value += pow(2, i)
                if i == 7:
                    pdu += struct.pack(">B", byte_value)
                    i, byte_value = 0, 0
                else:
                    i += 1
            if i > 0:
                pdu += struct.pack(">B", byte_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_REGISTERS:
            byte_count = 2 * len(output_value)
            pdu = struct.pack(">BHHB", function_code, starting_address, len(output_value), byte_count)
            for j in output_value:
                pdu += struct.pack(">H", j)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        else:
            raise ModbusFunctionNotSupportedError("The %d function code is not supported. " % (function_code))

        # instantiate a query which implements the MAC (TCP or RTU) part of the protocol
        query = self._make_query()

        # add the mac part of the protocol to the request
        request = query.build_request(pdu, slave)

        # send the request to the slave
        retval = call_hooks("modbus.Master.before_send", (self, request))
        if retval <> None:
            request = retval
        if self._verbose:
            LOGGER.debug(utils.get_log_buffer("-> ", request))
        self._send(request)

        call_hooks("modbus.Master.after_send", (self))

        if slave != 0:
            # receive the data from the slave
            response = self._recv(expected_length)
            retval = call_hooks("modbus.Master.after_recv", (self, response))
            if retval <> None:
                response = retval
            if self._verbose:
                LOGGER.debug(utils.get_log_buffer("<- ", response))

            # extract the pdu part of the response
            response_pdu = query.parse_response(response)

            # analyze the received data
            (return_code, byte_2) = struct.unpack(">BB", response_pdu[0:2])

            if return_code > 0x80:
                # the slave has returned an error
                exception_code = byte_2
                raise ModbusError(exception_code)
            else:
                if is_read_function:
                    # get the values returned by the reading function
                    byte_count = byte_2
                    data = response_pdu[2:]
                    if byte_count != len(data):
                        # the byte count in the pdu is invalid
                        raise ModbusInvalidResponseError, "Byte count is %d while actual number of bytes is %d. " \
                            % (byte_count, len(data))
                else:
                    # returns what is returned by the slave after a writing function
                    data = response_pdu[1:]

                #returns the data as a tuple according to the data_format
                #(calculated based on the function or user-defined)
                result = struct.unpack(data_format, data)
                if nb_of_digits > 0:
                    digits = []
                    for byte_val in result:
                        for i in xrange(8):
                            if (len(digits) >= nb_of_digits):
                                break
                            digits.append(byte_val % 2)
                            byte_val = byte_val >> 1
                    result = tuple(digits)
                return result
Example #6
0
    def execute(self,
                slave,
                function_code,
                starting_address,
                quantity_of_x=0,
                output_value=0,
                data_format="",
                expected_length=-1):
        """
        Execute a modbus query and returns the data part of the answer as a tuple
        The returned tuple depends on the query function code. see modbus protocol
        specification for details
        data_format makes possible to extract the data like defined in the
        struct python module documentation
        """

        pdu = ""
        is_read_function = False
        nb_of_digits = 0

        #open the connection if it is not already done
        self.open()

        #Build the modbus pdu and the format of the expected data.
        #It depends of function code. see modbus specifications for details.
        if function_code == defines.READ_COILS or function_code == defines.READ_DISCRETE_INPUTS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address,
                              quantity_of_x)
            byte_count = quantity_of_x / 8
            if (quantity_of_x % 8) > 0:
                byte_count += 1
            nb_of_digits = quantity_of_x
            if not data_format:
                data_format = ">" + (byte_count * "B")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = byte_count + 5  #slave + func + bytcodeLen + bytecode + crc1 + crc2

        elif function_code == defines.READ_INPUT_REGISTERS or function_code == defines.READ_HOLDING_REGISTERS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address,
                              quantity_of_x)
            if not data_format:
                data_format = ">" + (quantity_of_x * "H")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 2 * quantity_of_x + 5  #slave + func + bytcodeLen + bytecode x 2 + crc1 + crc2

        elif (function_code == defines.WRITE_SINGLE_COIL) or (
                function_code == defines.WRITE_SINGLE_REGISTER):
            if function_code == defines.WRITE_SINGLE_COIL:
                if output_value != 0:
                    output_value = 0xff00
            pdu = struct.pack(">BHH", function_code, starting_address,
                              output_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + value1+value2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_COILS:
            byte_count = len(output_value) / 8
            if (len(output_value) % 8) > 0:
                byte_count += 1
            pdu = struct.pack(">BHHB", function_code, starting_address,
                              len(output_value), byte_count)
            i, byte_value = 0, 0
            for j in output_value:
                if j > 0:
                    byte_value += pow(2, i)
                if i == 7:
                    pdu += struct.pack(">B", byte_value)
                    i, byte_value = 0, 0
                else:
                    i += 1
            if i > 0:
                pdu += struct.pack(">B", byte_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_REGISTERS:
            byte_count = 2 * len(output_value)
            pdu = struct.pack(">BHHB", function_code, starting_address,
                              len(output_value), byte_count)
            for j in output_value:
                pdu += struct.pack(">H", j)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        else:
            raise ModbusFunctionNotSupportedError(
                "The %d function code is not supported. " % (function_code))

        # instantiate a query which implements the MAC (TCP or RTU) part of the protocol
        query = self._make_query()

        # add the mac part of the protocol to the request
        request = query.build_request(pdu, slave)

        # send the request to the slave
        retval = call_hooks("modbus.Master.before_send", (self, request))
        if retval <> None:
            request = retval
        if self._verbose:
            LOGGER.debug(utils.get_log_buffer("-> ", request))
        self._send(request)

        call_hooks("modbus.Master.after_send", (self))

        if slave != 0:
            # receive the data from the slave
            response = self._recv(expected_length)
            retval = call_hooks("modbus.Master.after_recv", (self, response))
            if retval <> None:
                response = retval
            if self._verbose:
                LOGGER.debug(utils.get_log_buffer("<- ", response))

            # extract the pdu part of the response
            response_pdu = query.parse_response(response)

            # analyze the received data
            (return_code, byte_2) = struct.unpack(">BB", response_pdu[0:2])

            if return_code > 0x80:
                # the slave has returned an error
                exception_code = byte_2
                raise ModbusError(exception_code)
            else:
                if is_read_function:
                    # get the values returned by the reading function
                    byte_count = byte_2
                    data = response_pdu[2:]
                    if byte_count != len(data):
                        # the byte count in the pdu is invalid
                        raise ModbusInvalidResponseError, "Byte count is %d while actual number of bytes is %d. " \
                            % (byte_count, len(data))
                else:
                    # returns what is returned by the slave after a writing function
                    data = response_pdu[1:]

                #returns the data as a tuple according to the data_format
                #(calculated based on the function or user-defined)
                result = struct.unpack(data_format, data)
                if nb_of_digits > 0:
                    digits = []
                    for byte_val in result:
                        for i in xrange(8):
                            if (len(digits) >= nb_of_digits):
                                break
                            digits.append(byte_val % 2)
                            byte_val = byte_val >> 1
                    result = tuple(digits)
                return result