class InstrumentDriverTestCase(IonIntegrationTestCase): """ Base class for instrument driver tests """ # configuration singleton _test_config = InstrumentDriverTestConfig() @classmethod def initialize(cls, *args, **kwargs): """ Initialize the test_configuration singleton """ cls._test_config.initialize(*args, **kwargs) # Port agent process object. port_agent = None def setUp(self): """ @brief Setup test cases. """ log.debug("InstrumentDriverTestCase setUp") # Test to ensure we have initialized our test config if not self._test_config.initialized: return TestNotInitialized( msg= "Tests non initialized. Missing InstrumentDriverTestCase.initalize(...)?" ) self.clear_events() self.init_comm_config() def tearDown(self): """ @brief Test teardown """ log.debug("InstrumentDriverTestCase tearDown") def clear_events(self): """ @brief Clear the event list. """ self.events = [] def event_received(self, evt): """ @brief Simple callback to catch events from the driver for verification. """ self.events.append(evt) def comm_config_file(self): """ @brief Return the path the the driver comm config yaml file. @return if comm_config.yml exists return the full path """ repo_dir = Config().get('working_repo') driver_path = self._test_config.driver_module p = re.compile('\.') driver_path = p.sub('/', driver_path) abs_path = "%s/%s/%s" % (repo_dir, os.path.dirname(driver_path), CommConfig.config_filename()) log.debug(abs_path) return abs_path def init_comm_config(self): """ @brief Create the comm config object by reading the comm_config.yml file. """ log.info("Initialize comm config") config_file = self.comm_config_file() log.debug(" -- reading comm config from: %s" % config_file) if not os.path.exists(config_file): raise TestNoCommConfig( msg= "Missing comm config. Try running start_driver or switch_driver" ) self.comm_config = CommConfig.get_config_from_file(config_file) def init_port_agent(self): """ @brief Launch the driver process and driver client. This is used in the integration and qualification tests. The port agent abstracts the physical interface with the instrument. @retval return the pid to the logger process """ log.info("Startup Port Agent") # Create port agent object. this_pid = os.getpid() # Working dir and delim are hard coded here because this launch process # will change with the new port agent. self.port_agent = EthernetDeviceLogger.launch_process( self.comm_config.device_addr, self.comm_config.device_port, self._test_config.working_dir, self._test_config.delimeter, this_pid) pid = self.port_agent.get_pid() while not pid: gevent.sleep(.1) pid = self.port_agent.get_pid() port = self.port_agent.get_port() while not port: gevent.sleep(.1) port = self.port_agent.get_port() log.info('Started port agent pid %d listening at port %d' % (pid, port)) return port def stop_port_agent(self): """ Stop the port agent. """ if self.port_agent: pid = self.port_agent.get_pid() if pid: log.info('Stopping pagent pid %i' % pid) self.port_agent.stop() else: log.info('No port agent running.') def init_driver_process_client(self): """ @brief Launch the driver process and driver client @retval return driver process and driver client object """ log.info("Startup Driver Process") this_pid = os.getpid() (dvr_proc, cmd_port, evt_port) = ZmqDriverProcess.launch_process( self._test_config.driver_module, self._test_config.driver_class, self._test_config.working_dir, this_pid) self.driver_process = dvr_proc log.info('Started driver process for %d %d %s %s' % (cmd_port, evt_port, self._test_config.driver_module, self._test_config.driver_class)) log.info('Driver process pid %d' % self.driver_process.pid) # Create driver client. self.driver_client = ZmqDriverClient('localhost', cmd_port, evt_port) log.info('Created driver client for %d %d %s %s' % (cmd_port, evt_port, self._test_config.driver_module, self._test_config.driver_class)) # Start client messaging. self.driver_client.start_messaging(self.event_received) log.info('Driver messaging started.') gevent.sleep(.5) def stop_driver_process_client(self): """ Stop the driver_process. """ if self.driver_process: log.info('Stopping driver process pid %d' % self.driver_process.pid) if self.driver_client: self.driver_client.done() self.driver_process.wait() self.driver_client = None else: try: log.info('Killing driver process.') self.driver_process.kill() except OSError: pass self.driver_process = None ### # Private Methods ### def _kill_process(self): """ @brief Ensure a driver process has been killed """ process = self._driver_process pid = process.pid log.debug("Killing driver process. PID: %d" % pid) # For some reason process.kill and process.terminate didn't actually kill the process. # that's whay we had to use the os kill command. We have to call process.wait so that # the returncode attribute is updated which could be blocking. process.poll didn't # seem to work. for sig in [signal.SIGTERM, signal.SIGKILL]: if (process.returncode != None): break else: log.debug("Sending signal %s to driver process" % sig) os.kill(pid, sig) process.wait() if (process.returncode == None): raise Exception( "TODO: Better exception. Failed to kill driver process. PID: %d" % self._driver_process.pid)
class InstrumentDriverTestCase(IonIntegrationTestCase): """ Base class for instrument driver tests """ # configuration singleton _test_config = InstrumentDriverTestConfig() @classmethod def initialize(cls, *args, **kwargs): """ Initialize the test_configuration singleton """ cls._test_config.initialize(*args, **kwargs) # Port agent process object. port_agent = None def setUp(self): """ @brief Setup test cases. """ log.debug("InstrumentDriverTestCase setUp") # Test to ensure we have initialized our test config if not self._test_config.initialized: return TestNotInitialized(msg="Tests non initialized. Missing InstrumentDriverTestCase.initalize(...)?") self.clear_events() self.init_comm_config() def tearDown(self): """ @brief Test teardown """ log.debug("InstrumentDriverTestCase tearDown") def clear_events(self): """ @brief Clear the event list. """ self.events = [] def event_received(self, evt): """ @brief Simple callback to catch events from the driver for verification. """ self.events.append(evt) def comm_config_file(self): """ @brief Return the path the the driver comm config yaml file. @return if comm_config.yml exists return the full path """ repo_dir = Config().get("working_repo") driver_path = self._test_config.driver_module p = re.compile("\.") driver_path = p.sub("/", driver_path) abs_path = "%s/%s/%s" % (repo_dir, os.path.dirname(driver_path), CommConfig.config_filename()) log.debug(abs_path) return abs_path def init_comm_config(self): """ @brief Create the comm config object by reading the comm_config.yml file. """ log.info("Initialize comm config") config_file = self.comm_config_file() log.debug(" -- reading comm config from: %s" % config_file) if not os.path.exists(config_file): raise TestNoCommConfig(msg="Missing comm config. Try running start_driver or switch_driver") self.comm_config = CommConfig.get_config_from_file(config_file) def init_port_agent(self): """ @brief Launch the driver process and driver client. This is used in the integration and qualification tests. The port agent abstracts the physical interface with the instrument. @retval return the pid to the logger process """ log.info("Startup Port Agent") # Create port agent object. this_pid = os.getpid() # Working dir and delim are hard coded here because this launch process # will change with the new port agent. self.port_agent = EthernetDeviceLogger.launch_process( self.comm_config.device_addr, self.comm_config.device_port, self._test_config.working_dir, self._test_config.delimeter, this_pid, ) pid = self.port_agent.get_pid() while not pid: gevent.sleep(0.1) pid = self.port_agent.get_pid() port = self.port_agent.get_port() while not port: gevent.sleep(0.1) port = self.port_agent.get_port() log.info("Started port agent pid %d listening at port %d" % (pid, port)) return port def stop_port_agent(self): """ Stop the port agent. """ if self.port_agent: pid = self.port_agent.get_pid() if pid: log.info("Stopping pagent pid %i" % pid) self.port_agent.stop() else: log.info("No port agent running.") def init_driver_process_client(self): """ @brief Launch the driver process and driver client @retval return driver process and driver client object """ log.info("Startup Driver Process") this_pid = os.getpid() (dvr_proc, cmd_port, evt_port) = ZmqDriverProcess.launch_process( self._test_config.driver_module, self._test_config.driver_class, self._test_config.working_dir, this_pid ) self.driver_process = dvr_proc log.info( "Started driver process for %d %d %s %s" % (cmd_port, evt_port, self._test_config.driver_module, self._test_config.driver_class) ) log.info("Driver process pid %d" % self.driver_process.pid) # Create driver client. self.driver_client = ZmqDriverClient("localhost", cmd_port, evt_port) log.info( "Created driver client for %d %d %s %s" % (cmd_port, evt_port, self._test_config.driver_module, self._test_config.driver_class) ) # Start client messaging. self.driver_client.start_messaging(self.event_received) log.info("Driver messaging started.") gevent.sleep(0.5) def stop_driver_process_client(self): """ Stop the driver_process. """ if self.driver_process: log.info("Stopping driver process pid %d" % self.driver_process.pid) if self.driver_client: self.driver_client.done() self.driver_process.wait() self.driver_client = None else: try: log.info("Killing driver process.") self.driver_process.kill() except OSError: pass self.driver_process = None ### # Private Methods ### def _kill_process(self): """ @brief Ensure a driver process has been killed """ process = self._driver_process pid = process.pid log.debug("Killing driver process. PID: %d" % pid) # For some reason process.kill and process.terminate didn't actually kill the process. # that's whay we had to use the os kill command. We have to call process.wait so that # the returncode attribute is updated which could be blocking. process.poll didn't # seem to work. for sig in [signal.SIGTERM, signal.SIGKILL]: if process.returncode != None: break else: log.debug("Sending signal %s to driver process" % sig) os.kill(pid, sig) process.wait() if process.returncode == None: raise Exception( "TODO: Better exception. Failed to kill driver process. PID: %d" % self._driver_process.pid )
class CiLogger(object): """ ResourceAgent derived class for the CI Logger. This class interfaces CG components to driver resources in the ION system. It provides support for the CG DCL_Control and Data_Mgr interfaces and translates/forwards these on to the CI driver and CG_Logger. """ def __init__(self): log.debug("CiLogger.__init__:") # start driver driver_config = { 'svr_addr': 'localhost', 'cmd_port': 5556, 'evt_port': 5557, 'dvr_mod': 'ion.agents.instrument.drivers.sbe37.sbe37_driver', 'dvr_cls': 'SBE37Driver' } result = self._start_driver(driver_config) if not isinstance(result, int): log.error("CiLogger.__init__: " + result[1]) return log.info("CiLogger.__init__: started driver with process id of " + str(result)) # configure driver and have it start the port agent comms_config = { SBE37Channel.CTD: { 'method': 'ethernet', 'device_addr': 'sbe37-simulator.oceanobservatories.org', 'device_port': 4001, 'server_addr': 'localhost', 'server_port': 8888 } } cfg_result = self._dvr_client.cmd_dvr('configure', comms_config) channels = [ key for (key, val) in cfg_result.iteritems() if not InstErrorCode.is_error(val) ] con_result = self._dvr_client.cmd_dvr('connect', channels) result = cfg_result.copy() try: for (key, val) in con_result.iteritems(): result[key] = val except: log.error("CiLogger.__init__: driver connection failure - " + str(con_result)) return self._active_channels = self._dvr_client.cmd_dvr('get_active_channels') if len(self._active_channels) <= 0: log.error( "CiLogger.__init__: driver connection failure - no active channels" ) return log.info("CiLogger.__init__: driver connected to instrument " + comms_config[SBE37Channel.CTD]['device_addr']) def start_streaming(self): log.info("CiLogger.start_streaming():") return CgMsgTypes.ACK, "Instrument started" ############################################################################### # Event callback and handling. ############################################################################### def evt_recv(self, evt): """ Callback to receive asynchronous driver events. @param evt The driver event received. """ log.info('CiLogger.evt_recv(): received driver event %s', str(evt)) # TODO: send 'sample' events to the CG_Logger ############################################################################### # Private helpers. ############################################################################### def _go_inactive(self, *args, **kwargs): """ Handler for go_inactive agent command in idle state. Attempt to disconnect and initialize all active driver channels. Swtich to inactive state if successful. """ channels = self._dvr_client.cmd_dvr('get_active_channels') dis_result = self._dvr_client.cmd_dvr('disconnect', channels) [ key for (key, val) in dis_result.iteritems() if not InstErrorCode.is_error(val) ] self._stop_driver() def _go_streaming(self, *args, **kwargs): """ Handler for go_streaming agent command in observatory state. Send start autosample command to driver and switch to streaming state if successful. """ result = self._dvr_client.cmd_dvr('start_autosample', *args, **kwargs) if isinstance(result, dict): if any([val == None for val in result.values()]): next_state = InstrumentAgentState.STREAMING def _go_observatory(self, *args, **kwargs): """ Handler for go_observatory agent command within streaming state. Command driver to stop autosampling, and switch to observatory mode if successful. """ result = self._dvr_client.cmd_dvr('stop_autosample', *args, **kwargs) if isinstance(result, dict): if all([val == None for val in result.values()]): next_state = InstrumentAgentState.OBSERVATORY def _start_driver(self, dvr_config): """ Start the driver process and driver client. @param dvr_config The driver configuration. @param comms_config The driver communications configuration. @retval None or error. """ try: cmd_port = dvr_config['cmd_port'] evt_port = dvr_config['evt_port'] dvr_mod = dvr_config['dvr_mod'] dvr_cls = dvr_config['dvr_cls'] svr_addr = dvr_config['svr_addr'] except (TypeError, KeyError): # Not a dict. or missing required parameter. log.error( 'CiLogger._start_driver(): missing required parameter in start_driver.' ) return InstErrorCode.REQUIRED_PARAMETER # Launch driver process. self._dvr_proc = ZmqDriverProcess.launch_process( cmd_port, evt_port, dvr_mod, dvr_cls) self._dvr_proc.poll() if self._dvr_proc.returncode: # Error proc didn't start. log.error( 'CiLogger._start_driver(): driver process did not launch.') return InstErrorCode.AGENT_INIT_FAILED log.info('CiLogger._start_driver(): launched driver process.') # Create client and start messaging. self._dvr_client = ZmqDriverClient(svr_addr, cmd_port, evt_port) self._dvr_client.start_messaging(self.evt_recv) log.info('CiLogger._start_driver(): driver process client started.') time.sleep(1) try: retval = self._dvr_client.cmd_dvr('process_echo', 'Test.') log.info( 'CiLogger._start_driver(): driver process echo test: %s.' % str(retval)) except Exception: self._dvr_proc.terminate() self._dvr_proc.wait() self._dvr_proc = None self._dvr_client = None log.error( 'CiLogger._start_driver(): error commanding driver process.') return InstErrorCode.AGENT_INIT_FAILED else: log.info('CiLogger._start_driver(): started its driver.') return self._dvr_proc.pid def _stop_driver(self): """ Stop the driver process and driver client. @retval None. """ if self._dvr_client: self._dvr_client.done() self._dvr_proc.wait() self._dvr_proc = None self._dvr_client = None log.info('CiLogger._stop_driver(): stopped its driver.') time.sleep(1)
class CiLogger(object): """ ResourceAgent derived class for the CI Logger. This class interfaces CG components to driver resources in the ION system. It provides support for the CG DCL_Control and Data_Mgr interfaces and translates/forwards these on to the CI driver and CG_Logger. """ def __init__(self): log.debug("CiLogger.__init__:") # start driver driver_config = {'svr_addr': 'localhost', 'cmd_port': 5556, 'evt_port': 5557, 'dvr_mod': 'ion.agents.instrument.drivers.sbe37.sbe37_driver', 'dvr_cls': 'SBE37Driver'} result = self._start_driver(driver_config) if not isinstance(result, int): log.error("CiLogger.__init__: " + result[1]) return log.info("CiLogger.__init__: started driver with process id of " + str(result)) # configure driver and have it start the port agent comms_config = {SBE37Channel.CTD: {'method':'ethernet', 'device_addr': 'sbe37-simulator.oceanobservatories.org', 'device_port': 4001, 'server_addr': 'localhost', 'server_port': 8888} } cfg_result = self._dvr_client.cmd_dvr('configure', comms_config) channels = [key for (key, val) in cfg_result.iteritems() if not InstErrorCode.is_error(val)] con_result = self._dvr_client.cmd_dvr('connect', channels) result = cfg_result.copy() try: for (key, val) in con_result.iteritems(): result[key] = val except: log.error("CiLogger.__init__: driver connection failure - " + str(con_result)) return self._active_channels = self._dvr_client.cmd_dvr('get_active_channels') if len(self._active_channels) <= 0: log.error("CiLogger.__init__: driver connection failure - no active channels") return log.info("CiLogger.__init__: driver connected to instrument " + comms_config[SBE37Channel.CTD]['device_addr']) def start_streaming(self): log.info("CiLogger.start_streaming():") return CgMsgTypes.ACK, "Instrument started" ############################################################################### # Event callback and handling. ############################################################################### def evt_recv(self, evt): """ Callback to receive asynchronous driver events. @param evt The driver event received. """ log.info('CiLogger.evt_recv(): received driver event %s', str(evt)) # TODO: send 'sample' events to the CG_Logger ############################################################################### # Private helpers. ############################################################################### def _go_inactive(self, *args, **kwargs): """ Handler for go_inactive agent command in idle state. Attempt to disconnect and initialize all active driver channels. Swtich to inactive state if successful. """ channels = self._dvr_client.cmd_dvr('get_active_channels') dis_result = self._dvr_client.cmd_dvr('disconnect', channels) [key for (key, val) in dis_result.iteritems() if not InstErrorCode.is_error(val)] self._stop_driver() def _go_streaming(self, *args, **kwargs): """ Handler for go_streaming agent command in observatory state. Send start autosample command to driver and switch to streaming state if successful. """ result = self._dvr_client.cmd_dvr('start_autosample', *args, **kwargs) if isinstance(result, dict): if any([val == None for val in result.values()]): next_state = InstrumentAgentState.STREAMING def _go_observatory(self, *args, **kwargs): """ Handler for go_observatory agent command within streaming state. Command driver to stop autosampling, and switch to observatory mode if successful. """ result = self._dvr_client.cmd_dvr('stop_autosample', *args, **kwargs) if isinstance(result, dict): if all([val == None for val in result.values()]): next_state = InstrumentAgentState.OBSERVATORY def _start_driver(self, dvr_config): """ Start the driver process and driver client. @param dvr_config The driver configuration. @param comms_config The driver communications configuration. @retval None or error. """ try: cmd_port = dvr_config['cmd_port'] evt_port = dvr_config['evt_port'] dvr_mod = dvr_config['dvr_mod'] dvr_cls = dvr_config['dvr_cls'] svr_addr = dvr_config['svr_addr'] except (TypeError, KeyError): # Not a dict. or missing required parameter. log.error('CiLogger._start_driver(): missing required parameter in start_driver.') return InstErrorCode.REQUIRED_PARAMETER # Launch driver process. self._dvr_proc = ZmqDriverProcess.launch_process(cmd_port, evt_port, dvr_mod, dvr_cls) self._dvr_proc.poll() if self._dvr_proc.returncode: # Error proc didn't start. log.error('CiLogger._start_driver(): driver process did not launch.') return InstErrorCode.AGENT_INIT_FAILED log.info('CiLogger._start_driver(): launched driver process.') # Create client and start messaging. self._dvr_client = ZmqDriverClient(svr_addr, cmd_port, evt_port) self._dvr_client.start_messaging(self.evt_recv) log.info('CiLogger._start_driver(): driver process client started.') time.sleep(1) try: retval = self._dvr_client.cmd_dvr('process_echo', 'Test.') log.info('CiLogger._start_driver(): driver process echo test: %s.' %str(retval)) except Exception: self._dvr_proc.terminate() self._dvr_proc.wait() self._dvr_proc = None self._dvr_client = None log.error('CiLogger._start_driver(): error commanding driver process.') return InstErrorCode.AGENT_INIT_FAILED else: log.info('CiLogger._start_driver(): started its driver.') return self._dvr_proc.pid def _stop_driver(self): """ Stop the driver process and driver client. @retval None. """ if self._dvr_client: self._dvr_client.done() self._dvr_proc.wait() self._dvr_proc = None self._dvr_client = None log.info('CiLogger._stop_driver(): stopped its driver.') time.sleep(1)
class DriverIntegrationTestSupport(object): """ Common functionality helpful for driver integration testing. """ def __init__(self, driver_module, driver_class, device_addr, device_port, delim=None, work_dir='/tmp/'): """ @param driver_module @param driver_class @param device_addr @param device_port @param delim 2-element delimiter to indicate traffic from the driver in the logfile. See EthernetDeviceLogger.launch_process for default value. @param work_dir by default, '/tmp/' """ object.__init__(self) self.driver_module = driver_module self.driver_class = driver_class self.device_addr = device_addr self.device_port = device_port self.delim = delim self.work_dir = work_dir # Should clear this in setup self._events = [] self._dvr_client = None def start_pagent(self): """ Construct and start the port agent. @retval port Port that was used for connection to agent """ # Create port agent object. this_pid = os.getpid() self._pagent = EthernetDeviceLogger.launch_process(self.device_addr, self.device_port, self.work_dir, self.delim, this_pid) pid = self._pagent.get_pid() while not pid: gevent.sleep(.1) pid = self._pagent.get_pid() port = self._pagent.get_port() while not port: gevent.sleep(.1) port = self._pagent.get_port() mi_logger.info('Started port agent pid %d listening at port %d', pid, port) return port def stop_pagent(self): """ Stop the port agent. """ if self._pagent: pid = self._pagent.get_pid() if pid: mi_logger.info('Stopping pagent pid %i', pid) self._pagent.stop() else: mi_logger.info('No port agent running.') def start_driver(self): """ Start the driver process. """ # Launch driver process based on test config. this_pid = os.getpid() (dvr_proc, cmd_port, evt_port) = ZmqDriverProcess.launch_process(self.driver_module, self.driver_class, self.work_dir, this_pid) self._dvr_proc = dvr_proc mi_logger.info('Started driver process for %d %d %s %s', cmd_port, evt_port, self.driver_module, self.driver_class) mi_logger.info('Driver process pid %d', self._dvr_proc.pid) # Create driver client. self._dvr_client = ZmqDriverClient('localhost', cmd_port, evt_port) mi_logger.info('Created driver client for %d %d %s %s', cmd_port, evt_port, self.driver_module, self.driver_class) # Start client messaging. self._dvr_client.start_messaging(self.evt_recd) mi_logger.info('Driver messaging started.') gevent.sleep(.5) def stop_driver(self): """ Method to shut down the driver process. Attempt normal shutdown, and kill the process if unsuccessful. """ if self._dvr_proc: mi_logger.info('Stopping driver process pid %d', self._dvr_proc.pid) if self._dvr_client: self._dvr_client.done() self._dvr_proc.wait() self._dvr_client = None else: try: mi_logger.info('Killing driver process.') self._dvr_proc.kill() except OSError: pass self._dvr_proc = None def evt_recd(self, evt): """ Simple callback to catch events from the driver for verification. """ self._events.append(evt)
class DriverIntegrationTestSupport(object): """ Common functionality helpful for driver integration testing. """ def __init__(self, driver_module, driver_class, device_addr, device_port, delim=None, work_dir='/tmp/'): """ @param driver_module @param driver_class @param device_addr @param device_port @param delim 2-element delimiter to indicate traffic from the driver in the logfile. See EthernetDeviceLogger.launch_process for default value. @param work_dir by default, '/tmp/' """ object.__init__(self) self.driver_module = driver_module self.driver_class = driver_class self.device_addr = device_addr self.device_port = device_port self.delim = delim self.work_dir = work_dir # Should clear this in setup self._events = [] self._dvr_client = None def start_pagent(self): """ Construct and start the port agent. @retval port Port that was used for connection to agent """ # Create port agent object. this_pid = os.getpid() self._pagent = EthernetDeviceLogger.launch_process( self.device_addr, self.device_port, self.work_dir, self.delim, this_pid) pid = self._pagent.get_pid() while not pid: gevent.sleep(.1) pid = self._pagent.get_pid() port = self._pagent.get_port() while not port: gevent.sleep(.1) port = self._pagent.get_port() mi_logger.info('Started port agent pid %d listening at port %d', pid, port) return port def stop_pagent(self): """ Stop the port agent. """ if self._pagent: pid = self._pagent.get_pid() if pid: mi_logger.info('Stopping pagent pid %i', pid) self._pagent.stop() else: mi_logger.info('No port agent running.') def start_driver(self): """ Start the driver process. """ # Launch driver process based on test config. this_pid = os.getpid() (dvr_proc, cmd_port, evt_port) = ZmqDriverProcess.launch_process(self.driver_module, self.driver_class, self.work_dir, this_pid) self._dvr_proc = dvr_proc mi_logger.info('Started driver process for %d %d %s %s', cmd_port, evt_port, self.driver_module, self.driver_class) mi_logger.info('Driver process pid %d', self._dvr_proc.pid) # Create driver client. self._dvr_client = ZmqDriverClient('localhost', cmd_port, evt_port) mi_logger.info('Created driver client for %d %d %s %s', cmd_port, evt_port, self.driver_module, self.driver_class) # Start client messaging. self._dvr_client.start_messaging(self.evt_recd) mi_logger.info('Driver messaging started.') gevent.sleep(.5) def stop_driver(self): """ Method to shut down the driver process. Attempt normal shutdown, and kill the process if unsuccessful. """ if self._dvr_proc: mi_logger.info('Stopping driver process pid %d', self._dvr_proc.pid) if self._dvr_client: self._dvr_client.done() self._dvr_proc.wait() self._dvr_client = None else: try: mi_logger.info('Killing driver process.') self._dvr_proc.kill() except OSError: pass self._dvr_proc = None def evt_recd(self, evt): """ Simple callback to catch events from the driver for verification. """ self._events.append(evt)