Exemplo n.º 1
0
    def _write_multiple_registers(self, request_pdu):
        (starting_address, quantity_of_x,
         byte_count) = struct.unpack(">HHB", request_pdu[1:6])

        if (quantity_of_x <= 0) or (quantity_of_x >
                                    123) or (byte_count !=
                                             (quantity_of_x * 2)):
            # maximum allowed size is 123 registers in one reading
            raise modbus.ModbusError(cst.ILLEGAL_DATA_VALUE)

        if self._id == define.GLOBAL_SLAVE:
            count = self._write_globals(starting_address, quantity_of_x,
                                        request_pdu)
        elif self._id == define.CHANNEL_SLAVE_BASE:
            count = 0
            raise modbus.ModbusError(cst.ILLEGAL_DATA_ADDRESS)
        else:
            # look for the block corresponding to the request
            block, offset = self._get_block_and_offset(cst.HOLDING_REGISTERS,
                                                       starting_address,
                                                       quantity_of_x)
            count = 0
            for i in xrange(quantity_of_x):
                count += 1
                block[offset + i] = struct.unpack(
                    ">H", request_pdu[6 + 2 * i:8 + 2 * i])[0]

        return struct.pack(">HH", starting_address, count)
Exemplo n.º 2
0
    def _write_multiple_coils(self, request_pdu):

        (starting_address, quantity_of_x,
         byte_count) = struct.unpack(">HHB", request_pdu[1:6])

        expected_byte_count = quantity_of_x / 8
        if (quantity_of_x % 8) > 0:
            expected_byte_count += 1

        if (quantity_of_x <= 0) or (quantity_of_x > 1968) or (
                byte_count != expected_byte_count):
            # maximum allowed size is 1968 coils
            raise modbus.ModbusError(cst.ILLEGAL_DATA_VALUE)

        # look for the block corresponding to the request
        block, offset = self._get_block_and_offset(cst.COILS, starting_address,
                                                   quantity_of_x)

        count = 0
        for i in xrange(byte_count):
            if count >= quantity_of_x:
                break
            (byte_value, ) = struct.unpack(">B", request_pdu[6 + i])
            for j in xrange(8):
                if byte_value & (1 << j):
                    block[offset + i * 8 + j] = 1
                else:
                    block[offset + i * 8 + j] = 0
                if count >= quantity_of_x:
                    break
                count += 1
        return struct.pack(">HH", starting_address, count)
Exemplo n.º 3
0
    def _read_registers(self, block_type, request_pdu):

        (starting_address,
         quantity_of_x) = struct.unpack(">HH", request_pdu[1:5])

        if (quantity_of_x <= 0) or (quantity_of_x > 125):
            # maximum allowed size is 125 registers in one reading
            LOGGER.debug("quantity_of_x is %d" % quantity_of_x)
            raise modbus.ModbusError(cst.ILLEGAL_DATA_VALUE)

        if (self._id == define.GLOBAL_SLAVE):
            values = self._read_globals(starting_address, quantity_of_x)
        elif (self._id >= define.CHANNEL_SLAVE_BASE):
            values, quantity_of_x = self._read_one_channel(
                self._id - define.CHANNEL_SLAVE_BASE, starting_address,
                quantity_of_x)
        else:
            block, offset = self._get_block_and_offset(block_type,
                                                       starting_address,
                                                       quantity_of_x)
            values = block[offset:offset + quantity_of_x]

        #write the response header
        response = struct.pack(">B", 2 * quantity_of_x)
        #add the values of every register on 2 bytes
        for reg in values:
            response += struct.pack(">H", reg)
        return response
Exemplo n.º 4
0
    def _write_single_coil(self, request_pdu):

        (data_address, value) = struct.unpack(">HH", request_pdu[1:5])
        block, offset = self._get_block_and_offset(cst.COILS, data_address, 1)
        if value == 0:
            block[offset] = 0
        elif value == 0xff00:
            block[offset] = 1
        else:
            raise modbus.ModbusError(cst.ILLEGAL_DATA_VALUE)
        return request_pdu[1:]  #returns echo of the command
Exemplo n.º 5
0
    def _get_block_and_offset(self, block_type, address, length):

        if (block_type == cst.HOLDING_REGISTERS):
            if (self._id == define.GLOBAL_SLAVE):
                block_type = define.ARDUINO_GLOBAL
            elif (self._id >= define.CHANNEL_SLAVE_BASE):
                block_type = define.ARDUINO_MESURES

        for block in self._memory[block_type]:
            if address >= block.starting_address:
                offset = address - block.starting_address
                if block.size >= offset + length:
                    return block, offset

        raise modbus.ModbusError(cst.ILLEGAL_DATA_ADDRESS)
Exemplo n.º 6
0
    def handle_request(self, request_pdu, broadcast=False):

        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 modbus.ModbusError(cst.ILLEGAL_FUNCTION)

                # if read query is broadcasted raises an error
                cant_be_broadcasted = (cst.READ_COILS,
                                       cst.READ_DISCRETE_INPUTS,
                                       cst.READ_INPUT_REGISTERS,
                                       cst.READ_HOLDING_REGISTERS)
                if broadcast and (function_code in cant_be_broadcasted):
                    raise modbus.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 modbus.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())
Exemplo n.º 7
0
    def _read_digital(self, block_type, request_pdu):

        (starting_address,
         quantity_of_x) = struct.unpack(">HH", request_pdu[1:5])

        if (quantity_of_x <= 0) or (quantity_of_x > 2000):
            # maximum allowed size is 2000 bits in one reading
            raise modbus.ModbusError(cst.ILLEGAL_DATA_VALUE)

        block, offset = self._get_block_and_offset(block_type,
                                                   starting_address,
                                                   quantity_of_x)

        values = block[offset:offset + quantity_of_x]

        #pack bits in bytes
        byte_count = quantity_of_x / 8
        if (quantity_of_x % 8) > 0:
            byte_count += 1

        # write the response header
        response = struct.pack(">B", byte_count)

        i, byte_value = 0, 0
        for coil in values:
            if coil:
                byte_value += (1 << i)
            if i >= 7:
                # write the values of 8 bits in a byte
                response += struct.pack(">B", byte_value)
                #reset the counters
                i, byte_value = 0, 0
            else:
                i += 1

        #if there is remaining bits: add one more byte with their values
        if i > 0:
            response += struct.pack(">B", byte_value)
        return response