def _set_params(self, *args, **kwargs): """ Issue commands to the instrument to set various parameters Also called when setting parameters during startup and direct access In the event an exception is generated dur @throws InstrumentParameterException if parameter does not exist or Maxrate is out of range @throws InstrumentCommandException if failed to set """ params = args[0] self._verify_not_readonly(*args, **kwargs) old_config = self._param_dict.get_config() exception = None for key in params: if key not in self._param_dict._param_dict: exception = InstrumentParameterException("Bad parameter: %r" % key) break val = self._param_dict.format(key, params[key]) log.debug("KEY = %s VALUE = %s", str(key), str(val)) if key == Parameter.MAX_RATE and float( params[key]) not in VALID_MAXRATES: exception = InstrumentParameterException( "Maxrate %s out of range" % val) break # Check for existence in dict (send only on change) if self._param_dict.get( key) is None or val != self._param_dict.format(key): if not self._do_cmd_resp(Command.SET, key, val): exception = InstrumentCommandException( 'Error setting: %s = %s' % (key, val)) break self._param_dict.set_value(key, params[key]) time.sleep(0.5) # Get new param dict config. If it differs from the old config, # tell driver superclass to publish a config change event. new_config = self._param_dict.get_config() log.debug("new_config: %s == old_config: %s", new_config, old_config) if old_config != new_config: self._do_cmd_resp(Command.SAVE, expected_prompt=Prompt.COMMAND) log.debug("configuration has changed. Send driver event") self._driver_event(DriverAsyncEvent.CONFIG_CHANGE) # Raise any exceptions encountered due to errors setting the parameter(s) if exception is not None: raise exception
def _send_command(self, command, *args, **kwargs): if not COMMAND_SEM.acquire(False): return 'BUSY' try: cmd_func = getattr(self.driver, command, None) if cmd_func and callable(cmd_func): reply = cmd_func(*args, **kwargs) else: raise InstrumentCommandException('Unknown driver command.') return reply finally: COMMAND_SEM.release()
def cmd_driver(self, msg): """ Process a command message against the driver. If the command exists as a driver attribute, call it passing supplied args and kwargs and returning the driver result. Special messages that are not forwarded to the driver are: 'stop_driver_process' - signal to close messaging and terminate. 'test_events' - populate event queue with test data. 'process_echo' - echos the message back. If the command is not found in the driver, an echo message is replied to the client. @param msg A driver command message. @retval The driver command result. """ cmd = msg.get('cmd', None) args = msg.get('args', None) kwargs = msg.get('kwargs', None) cmd_func = getattr(self.driver, cmd, None) log.debug("DriverProcess.cmd_driver(): cmd=%s, cmd_func=%s" %(cmd, cmd_func)) if cmd == 'stop_driver_process': self.stop_messaging() return'stop_driver_process' elif cmd == 'test_events': events = kwargs['events'] if type(events) != list: events = [events] for event in events: self.events.put(event) reply = 'test_events' elif cmd == 'process_echo': reply = 'ping from resource ppid:%s, resource:%s' % (str(self.ppid), str(self.driver)) elif cmd_func: try: reply = cmd_func(*args, **kwargs) except Exception as e: reply = e if not isinstance(e, InstrumentException): trace = traceback.format_exc() log.critical("Python error, Trace follows: \n%s" %trace) else: reply = InstrumentCommandException('Unknown driver command.') return reply
def _do_cmd_resp(self, cmd, *args, **kwargs): """ Perform a command-response on the device. Overridden: special "write delay" & command resending reliability improvements, no need for wakeup, default build command used for all commands @param cmd The command to execute. @param args positional arguments to pass to the build handler. @param expected_prompt kwarg offering a specific prompt to look for other than the ones in the protocol class itself. @param response_regex kwarg with a compiled regex for the response to match. Groups that match will be returned as a string. Cannot be supplied with expected_prompt. May be helpful for instruments that do not have a prompt. @retval resp_result The (possibly parsed) response result including the first instance of the prompt matched. If a regex was used, the prompt will be an empty string and the response will be the joined collection of matched groups. @raises InstrumentTimeoutException if the response did not occur in time. @raises InstrumentProtocolException if command could not be built or if response was not recognized. """ timeout = kwargs.get('timeout', DEFAULT_CMD_TIMEOUT) expected_prompt = kwargs.get('expected_prompt', None) response_regex = kwargs.get('response_regex', None) if response_regex and not isinstance(response_regex, RE_PATTERN): raise InstrumentProtocolException('Response regex is not a compiled pattern!') if expected_prompt and response_regex: raise InstrumentProtocolException('Cannot supply both regex and expected prompt!') retry_count = 5 retry_num = 0 cmd_line = "" result = "" prompt = "" for retry_num in xrange(retry_count): # Clear line and prompt buffers for result. self._linebuf = '' self._promptbuf = '' cmd_line = self._do_cmd(cmd, *args, **kwargs) # Wait for the prompt, prepare result and return, timeout exception if response_regex: result_tuple = self._get_response(timeout, response_regex=response_regex, expected_prompt=expected_prompt) result = "".join(result_tuple) else: (prompt, result) = self._get_response(timeout, expected_prompt=expected_prompt) # Confirm the entire command was sent, otherwise resend retry_count number of times if len(cmd_line) > 1 and \ (expected_prompt is not None or (response_regex is not None))\ and not result.startswith(cmd_line): # and cmd_line not in result: log.debug("_do_cmd_resp: Send command: %s failed %s attempt, result = %s.", cmd, retry_num, result) if retry_num >= retry_count: raise InstrumentCommandException('_do_cmd_resp: Failed %s attempts sending command: %s' % (retry_count, cmd)) else: break log.debug("_do_cmd_resp: Sent command: %s, %s reattempts, expected_prompt=%s, result=%s.", cmd_line, retry_num, expected_prompt, result) resp_handler = self._response_handlers.get((self.get_current_state(), cmd), None) or \ self._response_handlers.get(cmd, None) resp_result = None if resp_handler: resp_result = resp_handler(result, prompt) time.sleep(0.3) # give some time for the instrument connection to keep up return resp_result
def cmd_driver(self, msg): """ Process a command message against the driver. If the command exists as a driver attribute, call it passing supplied args and kwargs and returning the driver result. Special messages that are not forwarded to the driver are: 'stop_driver_process' - signal to close messaging and terminate. 'test_events' - populate event queue with test data. 'process_echo' - echos the message back. If the command is not found in the driver, an echo message is replied to the client. @param msg A driver command message. @retval The driver command result. """ cmd = msg.get('cmd', None) args = msg.get('args', None) kwargs = msg.get('kwargs', None) cmd_func = getattr(self.driver, cmd, None) log.debug("DriverProcess.cmd_driver(): cmd=%s, cmd_func=%s" % (cmd, cmd_func)) if cmd == 'stop_driver_process': self.stop_messaging() return 'stop_driver_process' elif cmd == 'test_events': events = kwargs['events'] self.events += events reply = 'test_events' elif cmd == 'process_echo': reply = 'ping from resource ppid:%s, resource:%s' % (str( self.ppid), str(self.driver)) #try: # msg = args[0] #except IndexError: # msg = 'no message to echo' # reply = 'process_echo: %s' % msg elif cmd_func: try: reply = cmd_func(*args, **kwargs) except Exception as e: reply = e # Command error events are better handled in the agent directly. #event = { # 'type' : DriverAsyncEvent.ERROR, # 'value' : str(e), # 'exception' : e, # 'time' : time.time() #} #self.send_event(event) if not isinstance(e, InstrumentException): trace = traceback.format_exc() log.critical("Python error, Trace follows: \n%s" % trace) else: reply = InstrumentCommandException('Unknown driver command.') # Command error events are better handled in the agent directly. #event = { # 'type' : DriverAsyncEvent.ERROR, # 'value' : str(reply), # 'exception' : reply, # 'time' : time.time() #} #self.send_event(event) return reply