def _get_request_length(self, mbap): """Parse the mbap and returns the number of bytes to be read""" if len(mbap) < 6: raise ModbusInvalidRequestError("The mbap is only %d bytes long", len(mbap)) length = struct.unpack(">HHH", mbap[:6])[2] return length
def parse_request(self, request): """Extract the pdu from a modbus request""" if len(request) > 6: mbap, pdu = request[:7], request[7:] self._request_mbap.unpack(mbap) error_str = self._request_mbap.check_length(len(pdu)) if len(error_str) > 0: raise ModbusInvalidMbapError(error_str) return self._request_mbap.unit_id, pdu else: raise ModbusInvalidRequestError("Request length is only {0} bytes. ".format(len(request)))
def handle_request(self, request_pdu, broadcast=False): """ parse the request pdu, makes the corresponding action and returns the response pdu """ logger.debug("Slave (ID: %d) is handling request" % self._id) with self._data_lock: # thread-safe try: # get the function code (self.function_code, ) = struct.unpack(">B", request_pdu[:1]) # check if the function code is valid. If not returns error response if not self.function_code in self._fn_code_map: raise ModbusError(defines.ILLEGAL_FUNCTION) can_broadcast = [ defines.WRITE_MULTIPLE_COILS, defines.WRITE_MULTIPLE_REGISTERS, defines.WRITE_SINGLE_COIL, defines.WRITE_SINGLE_REGISTER, ] if broadcast and (self.function_code not in can_broadcast): raise ModbusInvalidRequestError( "Function %d can not be broadcasted" % self.function_code) # execute the corresponding function try: response_pdu = self._fn_code_map[self.function_code]( request_pdu) except struct.error: raise ModbusError(exception_code=3) if response_pdu: if broadcast: # not really sure whats going on here - better log it! logger.info("Modbus broadcast: %s" % (utils.get_log_buffer("!!", response_pdu))) return "" else: return struct.pack(">B", self.function_code) + response_pdu raise Exception("No response for function %d" % self.function_code) except ModbusError as e: logger.error( "Exception caught: %s. (A proper response will be sent to the peer)", e, ) return struct.pack(">BB", self.function_code + 128, e.get_exception_code())
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: # get the function code (self.function_code, ) = struct.unpack(">B", request_pdu[0]) # check if the function code is valid. If not returns error response if not self.function_code in self._fn_code_map: 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 (self.function_code in cant_be_broadcasted): raise ModbusInvalidRequestError( "Function %d can not be broadcasted" % self.function_code) # execute the corresponding function response_pdu = self._fn_code_map[self.function_code]( request_pdu) if response_pdu: if broadcast: #not really sure whats going on here - better log it! logger.info("broadcast: %s" % (utils.get_log_buffer("!!", response_pdu))) return "" else: return struct.pack(">B", self.function_code) + response_pdu raise Exception("No response for function %d" % self.function_code) except ModbusError as e: logger.error( 'Exception caught: {0}. (A proper response will be sent to the peer)' .format(e)) return struct.pack(">BB", self.function_code + 128, e.get_exception_code())