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)
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)
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
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
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)
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())
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