예제 #1
0
 def init_driver_process_client(self):
     """
     @brief Launch the driver process and driver client
     @retval return driver process and driver client object
     """
     self.log.info("Startup Driver Process")
     self.log.debug("Server Command Port: %d" % self.server_command_port())
     self.log.debug("Server Event Port: %d" % self.server_event_port())
     self.log.debug("Driver Module: %s" % self.driver_module())
     self.log.debug("Driver Class: %s" % self.driver_class())
     
     # Spawn the driver subprocess
     driver_process = ZmqDriverProcess.launch_process(self.server_command_port(), self.server_event_port(), self.driver_module(), self.driver_class())
     self._driver_process = driver_process
     
     self.log.info("Startup Driver Client")
     self.log.debug("Server Address: %s" % self.server_address())
     self.log.debug("Server Command Port: %d" % self.server_command_port())
     self.log.debug("Server Event Port: %d" % self.server_event_port())
     
     # Create client and start messaging.
     driver_client = ZmqDriverClient(self.server_address(), self.server_command_port(),
                                     self.server_event_port())
     self._driver_client = driver_client
     self.clear_events()
     
     driver_client.start_messaging(self.event_received)
     return driver_process, driver_client
예제 #2
0
    def test_connect(self):
        """
        Test to establish device comms and transition to command state.
        """
        # Launch driver process.
        driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)
        
        # Create client and start messaging.
        driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)
        driver_client.start_messaging()
        time.sleep(2)

        # Configure driver for comms and transition to disconnected.
        reply = driver_client.cmd_dvr('configure', self.comms_config)
        time.sleep(2)

        # Establish device comms and transition to command.
        reply = driver_client.cmd_dvr('connect')
        time.sleep(2)

        # Disconnect devcie comms and transition to disconnected.                
        reply = driver_client.cmd_dvr('disconnect')
        time.sleep(2)
        
        # Initialize driver and transition to unconfigured.
        reply = driver_client.cmd_dvr('initialize')
        time.sleep(2)

        # Terminate driver process and stop client messaging.
        driver_client.done()
        driver_process.wait()        
예제 #3
0
    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)
예제 #4
0
    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('Insturment agent %s missing required parameter in start_driver.',
                      self._proc_name)            
            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('Insturment agent %s driver process did not launch.',
                      self._proc_name)
            return InstErrorCode.AGENT_INIT_FAILED

        log.info('Insturment agent %s launched driver process.', self._proc_name)
        
        # 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('Insturment agent %s driver process client started.',
                 self._proc_name)
        time.sleep(1)

        try:        
            retval = self._dvr_client.cmd_dvr('process_echo', 'Test.')
            log.info('Insturment agent %s driver process echo test: %s.',
                     self._proc_name, str(retval))
            
        except Exception:
            self._dvr_proc.terminate()
            self._dvr_proc.wait()
            self._dvr_proc = None
            self._dvr_client = None
            log.error('Insturment agent %s error commanding driver process.',
                      self._proc_name)            
            return InstErrorCode.AGENT_INIT_FAILED

        else:
            log.info('Insturment agent %s started its driver.', self._proc_name)
            self._construct_packet_factories()
예제 #5
0
    def test_process(self):
        """
        Test for correct launch of driver process and communications, including
        asynchronous driver events.
        """
        # Launch driver process.
        driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)
        
        # Create client and start messaging.
        driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)        
        self.clear_events()
        driver_client.start_messaging(self.evt_recd)
        time.sleep(2)

        # Add test to verify process exists.

        # Send a test message to the process interface, confirm result.
        msg = 'I am a ZMQ message going to the process.'
        reply = driver_client.cmd_dvr('process_echo', msg)
        self.assertEqual(reply,'process_echo: '+msg)

        # Send a test message to the driver interface, confirm result.
        msg = 'I am a ZMQ message going to the driver.'
        reply = driver_client.cmd_dvr('driver_echo', msg)
        self.assertEqual(reply, 'driver_echo: '+msg)
        
        # Test the event thread publishes and client side picks up events.
        events = [
            'I am important event #1!',
            'And I am important event #2!'
            ]
        reply = driver_client.cmd_dvr('test_events', events=events)
        time.sleep(2)
        
        # Confirm the events received are as expected.
        self.assertEqual(self.events, events)
        
        # Terminate driver process and stop client messaging.
        driver_client.done()
        driver_process.wait()
예제 #6
0
    def setUp(self):
        super(BarsDriverTest, self).setUp()

        # Zmq parameters used by driver process and client.
        self.server_addr = 'localhost'
        self.cmd_port = 5556
        self.evt_port = 5557

        # Driver module parameters.
        self.dvr_mod = 'ion.services.mi.drivers.uw_bars.driver'
        self.dvr_cls = 'BarsInstrumentDriver'

        self._driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)

        self._driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)
        self._driver_client.start_messaging()
        time.sleep(1)

        self.addCleanup(self._clean_up)
예제 #7
0
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.services.mi.drivers.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)
예제 #8
0
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)
예제 #9
0
class InstrumentAgent(ResourceAgent):
    """
    ResourceAgent derived class for the instrument agent. This class
    logically abstracts instruments as taskable resources in the ION
    system. It directly provides common functionality (common state model,
    common resource interface, point of publication) and creates
    a driver process to specialize for particular hardware.
    """
    def __init__(self, initial_state=InstrumentAgentState.UNINITIALIZED):
        """
        Initialize instrument agent prior to pyon process initialization.
        Define state machine, initialize member variables.
        """
        ResourceAgent.__init__(self)
                
        # Instrument agent state machine.
        self._fsm = InstrumentFSM(InstrumentAgentState, InstrumentAgentEvent, InstrumentAgentEvent.ENTER,
                            InstrumentAgentEvent.EXIT, InstErrorCode.UNHANDLED_EVENT)
        
        # Populate state machine for all state-events.
        self._fsm.add_handler(InstrumentAgentState.POWERED_DOWN, InstrumentAgentEvent.ENTER, self._handler_powered_down_enter)
        self._fsm.add_handler(InstrumentAgentState.POWERED_DOWN, InstrumentAgentEvent.EXIT, self._handler_powered_down_exit)
        
        self._fsm.add_handler(InstrumentAgentState.UNINITIALIZED, InstrumentAgentEvent.ENTER, self._handler_uninitialized_enter)
        self._fsm.add_handler(InstrumentAgentState.UNINITIALIZED, InstrumentAgentEvent.EXIT, self._handler_uninitialized_exit)
        self._fsm.add_handler(InstrumentAgentState.UNINITIALIZED, InstrumentAgentEvent.POWER_DOWN, self._handler_uninitialized_power_down)
        self._fsm.add_handler(InstrumentAgentState.UNINITIALIZED, InstrumentAgentEvent.INITIALIZE, self._handler_uninitialized_initialize)
        self._fsm.add_handler(InstrumentAgentState.UNINITIALIZED, InstrumentAgentEvent.RESET, self._handler_uninitialized_reset)

        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.ENTER, self._handler_inactive_enter)
        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.EXIT, self._handler_inactive_exit)
        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.INITIALIZE, self._handler_inactive_initialize)
        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.RESET, self._handler_inactive_reset)
        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.GO_ACTIVE, self._handler_inactive_go_active)
        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.GET_RESOURCE_COMMANDS, self._handler_get_resource_commands)
        self._fsm.add_handler(InstrumentAgentState.INACTIVE, InstrumentAgentEvent.GET_RESOURCE_PARAMS, self._handler_get_resource_params)

        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.ENTER, self._handler_idle_enter)
        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.EXIT, self._handler_idle_exit)
        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.GO_INACTIVE, self._handler_idle_go_inactive)
        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.RESET, self._handler_idle_reset)
        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.RUN, self._handler_idle_run)
        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.GET_RESOURCE_COMMANDS, self._handler_get_resource_commands)
        self._fsm.add_handler(InstrumentAgentState.IDLE, InstrumentAgentEvent.GET_RESOURCE_PARAMS, self._handler_get_resource_params)

        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.ENTER, self._handler_stopped_enter)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.EXIT, self._handler_stopped_exit)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.GO_INACTIVE, self._handler_stopped_go_inactive)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.RESET, self._handler_stopped_reset)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.CLEAR, self._handler_stopped_clear)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.RESUME, self._handler_stopped_resume)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.GET_RESOURCE_COMMANDS, self._handler_get_resource_commands)
        self._fsm.add_handler(InstrumentAgentState.STOPPED, InstrumentAgentEvent.GET_RESOURCE_PARAMS, self._handler_get_resource_params)

        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.ENTER, self._handler_observatory_enter)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.EXIT, self._handler_observatory_exit)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.GO_INACTIVE, self._handler_observatory_go_inactive)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.RESET, self._handler_observatory_reset)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.CLEAR, self._handler_observatory_clear)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.PAUSE, self._handler_observatory_pause)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.GO_STREAMING, self._handler_observatory_go_streaming)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.GO_DIRECT_ACCESS, self._handler_observatory_go_direct_access)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.GET_RESOURCE_COMMANDS, self._handler_get_resource_commands)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.GET_RESOURCE_PARAMS, self._handler_get_resource_params)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.GET_PARAMS, self._handler_get_params)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.SET_PARAMS, self._handler_observatory_set_params)
        self._fsm.add_handler(InstrumentAgentState.OBSERVATORY, InstrumentAgentEvent.EXECUTE_RESOURCE, self._handler_observatory_execute_resource)

        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.ENTER, self._handler_streaming_enter)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.EXIT, self._handler_streaming_exit)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.GO_INACTIVE, self._handler_streaming_go_inactive)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.RESET, self._handler_streaming_reset)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.GO_OBSERVATORY, self._handler_streaming_go_observatory)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.GET_RESOURCE_COMMANDS, self._handler_get_resource_commands)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.GET_RESOURCE_PARAMS, self._handler_get_resource_params)
        self._fsm.add_handler(InstrumentAgentState.STREAMING, InstrumentAgentEvent.GET_PARAMS, self._handler_get_params)

        self._fsm.add_handler(InstrumentAgentState.DIRECT_ACCESS, InstrumentAgentEvent.ENTER, self._handler_direct_access_enter)
        self._fsm.add_handler(InstrumentAgentState.DIRECT_ACCESS, InstrumentAgentEvent.EXIT, self._handler_direct_access_exit)
        self._fsm.add_handler(InstrumentAgentState.DIRECT_ACCESS, InstrumentAgentEvent.GO_OBSERVATORY, self._handler_direct_access_go_observatory)
        self._fsm.add_handler(InstrumentAgentState.DIRECT_ACCESS, InstrumentAgentEvent.GET_RESOURCE_COMMANDS, self._handler_get_resource_commands)
        self._fsm.add_handler(InstrumentAgentState.DIRECT_ACCESS, InstrumentAgentEvent.GET_RESOURCE_PARAMS, self._handler_get_resource_params)

        ###############################################################################
        # Instrument agent internal parameters.
        ###############################################################################

        # State machine start state, defaults to unconfigured.
        self._initial_state = initial_state

        # Driver configuration. Passed as part of the spawn configuration
        # or with an initialize command. Sets driver specific
        # context.
        self._dvr_config = None
                
        # Process ID of the driver process. Useful to identify and signal
        # the process if necessary. Set by transition to inactive.
        self._dvr_pid = None
                
        # The driver process popen object. To terminate, signal, wait on,
        # or otherwise interact with the driver process via subprocess.
        # Set by transition to inactive.
        self._dvr_proc = None
        
        # The driver client for communicating to the driver process in
        # request-response or event publication. Set by transition to
        # inactive.
        self._dvr_client = None
                
        # UUID of the current transaction.
        self.transaction_id = None
        
        # List of pending transactions.
        self._pending_transactions = []
                                        
        # Dictionary of data stream IDs for data publishing. Constructed
        # by stream_config agent config member during process on_init.
        self._data_streams = {}
        
        # Dictionary of data stream publishers. Constructed by
        # stream_config agent config member during process on_init.
        self._data_publishers = {}

        # Factories for stream packets. Constructed by driver
        # configuration information on transition to inactive.
        self._packet_factories = {}
        
        # Stream registrar to create publishers. Used to create
        # stream publishers, set during process on_init.
        self._stream_registrar = None

        # Latitude value. Set by subscription to platform. Used to
        # append data packets prior to publication.
        self._lat = 0
        
        # Longitude value. Set by subscription to platform. Used to
        # append data packets prior to publication.
        self._lon = 0

        ###############################################################################
        # Instrument agent parameter capabilities.
        ###############################################################################
        
        self.aparam_ia_param = None

    def on_init(self):
        """
        Instrument agent pyon process initialization.
        Init objects that depend on the container services and start state
        machine.
        """
        # The registrar to create publishers.
        self._stream_registrar = StreamPublisherRegistrar(process=self,
                                                    node=self.container.node)
        
        # Set the driver config from the agent config if present.
        self._dvr_config = self.CFG.get('driver_config', None)
        
        # Construct stream publishers.
        self._construct_data_publishers()

        # Start state machine.
        self._fsm.start(self._initial_state)


    ###############################################################################
    # Event callback and handling.
    ###############################################################################

    def evt_recv(self, evt):
        """
        Callback to receive asynchronous driver events.
        @param evt The driver event received.
        """
        log.info('Instrument agent %s received driver event %s', self._proc_name,
                 str(evt))
        
        try:
            if evt['type'] == 'sample':
                name = evt['name']
                value = evt['value']
                value['lat'] = [self._lat]
                value['lon'] = [self._lon]
                value['stream_id'] = self._data_streams[name]
                if isinstance(value, dict):
                    packet = self._packet_factories[name](**value)
                    self._data_publishers[name].publish(packet)        
                    log.info('Instrument agent %s published data packet.',
                             self._proc_name)
                    
        except (KeyError, TypeError) as e:
            pass
        
        except Exception as e:
            log.info('Instrument agent %s error %s', self._proc_name, str(e))

    ###############################################################################
    # Instrument agent state transition interface.
    # All the following commands are forwarded as a eponymous event to
    # the agent state machine and return the state handler result.
    ###############################################################################

    def acmd_power_up(self, *args, **kwargs):
        """
        Agent power_up command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.POWER_UP, *args, **kwargs)
    
    def acmd_power_down(self, *args, **kwargs):
        """
        Agent power_down command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.POWER_DOWN, *args, **kwargs)
    
    def acmd_initialize(self, *args, **kwargs):
        """
        Agent initialize command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.INITIALIZE, *args, **kwargs)

    def acmd_reset(self, *args, **kwargs):
        """
        Agent reset command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.RESET, *args, **kwargs)
    
    def acmd_go_active(self, *args, **kwargs):
        """
        Agent go_active command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GO_ACTIVE, *args, **kwargs)

    def acmd_go_inactive(self, *args, **kwargs):
        """
        Agent go_inactive command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GO_INACTIVE, *args, **kwargs)

    def acmd_run(self, *args, **kwargs):
        """
        Agent run command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.RUN, *args, **kwargs)

    def acmd_clear(self, *args, **kwargs):
        """
        Agent clear command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.CLEAR, *args, **kwargs)

    def acmd_pause(self, *args, **kwargs):
        """
        Agent pause command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.PAUSE, *args, **kwargs)

    def acmd_resume(self, *args, **kwargs):
        """
        Agent resume command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.RESUME, *args, **kwargs)

    def acmd_go_streaming(self, *args, **kwargs):
        """
        Agent go_streaming command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GO_STREAMING, *args, **kwargs)

    def acmd_go_direct_access(self, *args, **kwargs):
        """
        Agent go_direct_access command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GO_DIRECT_ACCESS, *args, **kwargs)

    def acmd_go_observatory(self, *args, **kwargs):
        """
        Agent go_observatory command. Forward with args to state machine.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GO_OBSERVATORY, *args, **kwargs)

    ###############################################################################
    # Misc instrument agent command interface.
    ###############################################################################

    def acmd_get_current_state(self, *args, **kwargs):
        """
        Query the agent current state.
        """
        return self._fsm.get_current_state()

    ###############################################################################
    # Instrument agent capabilities interface. These functions override base
    # class helper functinos for specialized instrument agent behavior.
    ###############################################################################

    def _get_resource_commands(self):
        """
        Get driver resource commands. Send event to state machine and return
        response or empty list if none.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GET_RESOURCE_COMMANDS) or []
    
    def _get_resource_params(self):
        """
        Get driver resource parameters. Send event to state machine and return
        response or empty list if none.
        """
        return self._fsm.on_event(InstrumentAgentEvent.GET_RESOURCE_PARAMS) or []

    ###############################################################################
    # Instrument agent resource interface. These functions override ResourceAgent
    # base class functions to specialize behavior for instrument driver resources.
    ###############################################################################
    
    def get_param(self, resource_id="", name=''):
        """
        Get driver resource parameters. Send get_params event and args to agent
        state machine to handle request.
        NOTE: Need to adjust the ResourceAgent class and client for instrument
        interface needs.
        @param resource_id
        @param name A list of (channel, name) tuples of driver parameter
        to retrieve
        @retval Dict of (channel, name) : value parameter values if handled.
        """
        params = name
        return self._fsm.on_event(InstrumentAgentEvent.GET_PARAMS, params) or {}
        
    def set_param(self, resource_id="", name='', value=''):
        """
        Set driver resource parameters. Send set_params event and args to agent
        state machine to handle set driver resource parameters request.
        NOTE: Need to adjust the ResourceAgent class and client for instrument
        interface needs.
        @param resource_id
        @param name a Dict of (channel, name) : value for driver parameters
        to be set.
        @retval Dict of (channel, name) : None or Error if handled.
        """
        params = name
        return self._fsm.on_event(InstrumentAgentEvent.SET_PARAMS, params) or {}
                
    def execute(self, resource_id="", command=None):
        """
        Execute driver resource command. Send execute_resource event and args
        to agent state machine to handle resource execute request.
        @param resource_id
        @param command agent command object containing the driver command
        to execute
        @retval Resrouce agent command response object if handled.
        """
        return self._fsm.on_event(InstrumentAgentEvent.EXECUTE_RESOURCE, command)
                
    ###############################################################################
    # Instrument agent transaction interface.
    ###############################################################################

    def acmd_start_transaction(self):
        """
        """
        pass
    
    def acmd_end_transaction(self):
        """
        """
        pass

    ###############################################################################
    # Powered down state handlers.
    # TBD. This state requires clarification of use.
    ###############################################################################

    def _handler_powered_down_enter(self, *args, **kwargs):
        """
        Handler upon entry to powered_down state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
    
    def _handler_powered_down_exit(self, *args, **kwargs):
        """
        Handler upon exit from powered_down state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    ###############################################################################
    # Uninitialized state handlers.
    # Default start state. The driver has not been configured or started.
    ###############################################################################

    def _handler_uninitialized_enter(self, *args, **kwargs):
        """
        Handler upon entry to uninitialized state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
    
    def _handler_uninitialized_exit(self,  *args, **kwargs):
        """
        Handler upon exit from uninitialized state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    def _handler_uninitialized_power_down(self,  *args, **kwargs):
        """
        Handler for power_down agent command in uninitialized state.
        """
        result = InstErrorCode.NOT_IMPLEMENTED
        next_state = None
        
        return (next_state, result)

    def _handler_uninitialized_initialize(self,  dvr_config=None, *args, **kwargs):
        """
        Handler for initialize agent command in uninitialized state.
        Attempt to start driver process with driver config supplied as
        argument or in agent configuration. Switch to inactive state if
        successful.
        """
        result = None
        next_state = None

        self._dvr_config = dvr_config or self._dvr_config
        result = self._start_driver(self._dvr_config)
        if not result:
            next_state = InstrumentAgentState.INACTIVE

        return (next_state, result)

    def _handler_uninitialized_reset(self,  *args, **kwargs):
        """
        Handler for reset agent command in uninitialized state.
        Exit and reenter uninitializeds state.
        """
        result = None
        next_state = InstrumentAgentState.UNINITIALIZED
        
        return (next_state, result)

    ###############################################################################
    # Inactive state handlers.
    # The driver is configured and started, but not connected.
    ###############################################################################

    def _handler_inactive_enter(self,  *args, **kwargs):
        """
        Handler upon entry to inactive state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())

    
    def _handler_inactive_exit(self,  *args, **kwargs):
        """
        Handler upon exit from inactive state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())


    def _handler_inactive_initialize(self,  dvr_config=None, *args, **kwargs):
        """
        Handler for initialize command in inactive state. Stop and restart
        driver process using new driver config if supplied.
        """
        result = None
        next_state = None
        
        result = self._stop_driver()
        if result:
            return (next_state, result)
        
        self._dvr_config = dvr_config or self._dvr_config
        result = self._start_driver(self._dvr_config)
        if not result:
            next_state = InstrumentAgentState.INACTIVE
                
        return (next_state, result)

    def _handler_inactive_reset(self,  *args, **kwargs):
        """
        Handler for reset agent command in inactive state.
        Stop the driver process and switch to unitinitalized state if
        successful.
        """
        result = None
        next_state = None
        result = self._stop_driver()
        if not result:
            next_state = InstrumentAgentState.UNINITIALIZED
        
        return (next_state, result)

    def _handler_inactive_go_active(self, dvr_comms=None, *args, **kwargs):
        """
        Handler for go_active agent command in inactive state.
        Attempt to establsih communications with all device channels.
        Switch to active state if any channels activated.
        """
        result = None
        next_state = None
        
        if not dvr_comms:
            dvr_comms = self._dvr_config.get('comms_config', None)
            
        cfg_result = self._dvr_client.cmd_dvr('configure', dvr_comms)
        
        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()
        for (key, val) in con_result.iteritems():
            result[key] = val

        self._active_channels = self._dvr_client.cmd_dvr('get_active_channels')

        if len(self._active_channels)>0:
                next_state = InstrumentAgentState.IDLE
        
        return (next_state, result)

    ###############################################################################
    # Idle state handlers.
    ###############################################################################

    def _handler_idle_enter(self,  *args, **kwargs):
        """
        Handler upon entry to idle state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
                
    def _handler_idle_exit(self,  *args, **kwargs):
        """
        Handler upon exit from idle state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    def _handler_idle_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.
        """
        result = None
        next_state = None
        
        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)]
        
        init_result = self._dvr_client.cmd_dvr('initialize', channels)

        result = dis_result.copy()
        for (key, val) in init_result.iteritems():
            result[key] = val
            
        self._active_channels = self._dvr_client.cmd_dvr('get_active_channels')
            
        if len(self._active_channels)==0:
            next_state = InstrumentAgentState.INACTIVE
            
        return (next_state, result)

    def _handler_idle_reset(self,  *args, **kwargs):
        """
        Handler for reset agent command in idle state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_idle_run(self,  *args, **kwargs):
        """
        Handler for run agent command in idle state.
        Switch to observatory state.
        """
        result = None
        next_state = InstrumentAgentState.OBSERVATORY
        
        return (next_state, result)

    ###############################################################################
    # Stopped state handlers.
    ###############################################################################

    def _handler_stopped_enter(self,  *args, **kwargs):
        """
        Handler for entry into stopped state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
    
    def _handler_stopped_exit(self,  *args, **kwargs):
        """
        Handler for exit from stopped state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    def _handler_stopped_go_inactive(self,  *args, **kwargs):
        """
        Handler for go_inactive agent command in stopped state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_stopped_reset(self,  *args, **kwargs):
        """
        Handler for reset agent command in stopped state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_stopped_clear(self,  *args, **kwargs):
        """
        Handler for clear agent command in stopped state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_stopped_resume(self,  *args, **kwargs):
        """
        Handler for resume agent command in stopped state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    ###############################################################################
    # Observatory state handlers.
    ###############################################################################

    def _handler_observatory_enter(self,  *args, **kwargs):
        """
        Handler upon entry to observatory state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
    
    def _handler_observatory_exit(self,  *args, **kwargs):
        """
        Handler upon exit from observatory state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    def _handler_observatory_go_inactive(self,  *args, **kwargs):
        """
        Handler for go_inactive agent command in observatory state.
        Attempt to disconnect and initialize all active driver channels.
        Switch to inactive state if successful.
        """
        result = None
        next_state = None
        
        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)]
        
        init_result = self._dvr_client.cmd_dvr('initialize', channels)

        result = dis_result.copy()
        for (key, val) in init_result.iteritems():
            result[key] = val
            
        self._active_channels = self._dvr_client.cmd_dvr('get_active_channels')
            
        if len(self._active_channels)==0:
            next_state = InstrumentAgentState.INACTIVE
            
        return (next_state, result)

    def _handler_observatory_reset(self,  *args, **kwargs):
        """
        Handler for reset agent command in observatory state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_observatory_clear(self,  *args, **kwargs):
        """
        Handler for clear agent command in observatory state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_observatory_pause(self,  *args, **kwargs):
        """
        Handler for pause agent command in observatory state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_observatory_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 = None
        next_state = None

        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

        return (next_state, result)

    def _handler_observatory_go_direct_access(self,  *args, **kwargs):
        """
        Handler for go_direct_access agent ommand in observatory state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_get_params(self, params, *args, **kwargs):
        """
        Handler for get_params resource command in observatory state.
        Send get command to driver and return result.
        """
        result = self._dvr_client.cmd_dvr('get', params)
        next_state = None
        
        return (next_state, result)

    def _handler_observatory_set_params(self, params, *args, **kwargs):
        """
        Handler for set_params resource command in observatory state.
        Send the set command to the driver and return result.
        """
        result = self._dvr_client.cmd_dvr('set', params)
        next_state = None
        
        return (next_state, result)

    def _handler_observatory_execute_resource(self, command, *args, **kwargs):
        """
        Handler for execute_resource command in observatory state.
        Issue driver command and return the result.
        """
        result = None
        next_state = None

        if not command:
            raise iex.BadRequest("execute argument 'command' not present")
        if not command.command:
            raise iex.BadRequest("command not set")

        cmd_res = IonObject("AgentCommandResult", command_id=command.command_id,
                            command=command.command)
        cmd_res.ts_execute = get_ion_ts()
        command.command = 'execute_' + command.command
        res = self._dvr_client.cmd_dvr(command.command, *command.args,
                                           **command.kwargs)
        cmd_res.status = 0
        cmd_res.result = res
        result = cmd_res
        
        return (next_state, result)

    ###############################################################################
    # Streaming state handlers.
    ###############################################################################

    def _handler_streaming_enter(self,  *args, **kwargs):
        """
        Handler for entry to streaming state.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
    
    def _handler_streaming_exit(self,  *args, **kwargs):
        """
        Handler upon exit from streaming state.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    def _handler_streaming_go_inactive(self,  *args, **kwargs):
        """
        Handler for go_inactive agent command within streaming state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_streaming_reset(self,  *args, **kwargs):
        """
        Handler for reset agent command within streaming state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    def _handler_streaming_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 = None
        next_state = None
        
        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
            
        return (next_state, result)

    ###############################################################################
    # Direct access state handlers.
    ###############################################################################

    def _handler_direct_access_enter(self,  *args, **kwargs):
        """
        Handler upon direct access entry.
        """
        log.info('Instrument agent entered state %s',
                 self._fsm.get_current_state())
    
    def _handler_direct_access_exit(self,  *args, **kwargs):
        """
        Handler upon direct access exit.
        """
        log.info('Instrument agent left state %s',
                 self._fsm.get_current_state())

    def _handler_direct_access_go_observatory(self,  *args, **kwargs):
        """
        Handler for go_observatory agent command within direct access state.
        """
        result = None
        next_state = None
        
        return (next_state, result)

    ###############################################################################
    # Get resource state handlers.
    # Available for all states with a valid driver process. 
    ###############################################################################

    def _handler_get_resource_params(self,  *args, **kwargs):
        """
        Handler for get_resource_params resource command. Send
        get_resource_params and args to driver and return result.
        """
        result = self._dvr_client.cmd_dvr('get_resource_params')
        next_state = None
        
        return (next_state, result)

    def _handler_get_resource_commands(self,  *args, **kwargs):
        """
        Handler for get_resource_commands resource command. Send
        get_resource_commands and args to driver and return result.
        """
        result = self._dvr_client.cmd_dvr('get_resource_commands')
        next_state = None

        return (next_state, result)

    ###############################################################################
    # Private helpers.
    ###############################################################################

    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('Insturment agent %s missing required parameter in start_driver.',
                      self._proc_name)            
            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('Insturment agent %s driver process did not launch.',
                      self._proc_name)
            return InstErrorCode.AGENT_INIT_FAILED

        log.info('Insturment agent %s launched driver process.', self._proc_name)
        
        # 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('Insturment agent %s driver process client started.',
                 self._proc_name)
        time.sleep(1)

        try:        
            retval = self._dvr_client.cmd_dvr('process_echo', 'Test.')
            log.info('Insturment agent %s driver process echo test: %s.',
                     self._proc_name, str(retval))
            
        except Exception:
            self._dvr_proc.terminate()
            self._dvr_proc.wait()
            self._dvr_proc = None
            self._dvr_client = None
            log.error('Insturment agent %s error commanding driver process.',
                      self._proc_name)            
            return InstErrorCode.AGENT_INIT_FAILED

        else:
            log.info('Insturment agent %s started its driver.', self._proc_name)
            self._construct_packet_factories()

    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
            self._clear_packet_factories()
            log.info('Insturment agent %s stopped its driver.', self._proc_name)
            
        time.sleep(1)

    def _construct_data_publishers(self):
        """
        Construct the stream publishers from the stream_config agent
        config variable.
        @retval None
        """
        stream_config = self.CFG.stream_config

        for (name, stream_id) in stream_config.iteritems():
            self._data_streams[name] = stream_id
            publisher = self._stream_registrar.create_publisher(stream_id=stream_id)
            self._data_publishers[name] = publisher
            log.info('Instrumen agent %s created publisher for stream %s',
                     self._proc_name, name)        
        
    def _construct_packet_factories(self):
        """
        Construct packet factories from packet_config member of the
        driver_config.
        @retval None
        """
        packet_config = self._dvr_config['packet_config']
        for (name, val) in packet_config.iteritems():
            if val:
                mod = val[0]
                cls = val[1]
                import_str = 'from %s import %s' % (mod, cls)
                ctor_str = 'ctor = %s' % cls
                
                try:
                    exec import_str
                    exec ctor_str
                    
                except Exception:
                    log.error('Instrument agent %s had error creating packet factories from %s.%s',
                              self._proc_name, mod, cls)
                
                else:
                    self._packet_factories[name] = ctor
                    log.info('Instrument agent %s created packet factory for stream %s',
                             self._proc_name, name)
                    
    def _clear_packet_factories(self):
        """
        Delete packet factories.
        @retval None
        """
        self._packet_factories.clear()
        log.info('Instrument agent %s deleted packet factories.', self._proc_name)
            
    ###############################################################################
    # Misc and test.
    ###############################################################################

    def test_ia(self):
        log.info('Hello from the instrument agent!')
예제 #10
0
class TestSBE16Driver(PyonTestCase):    
    """
    Integration tests for the sbe16 driver. This class tests and shows
    use patterns for the sbe16 driver as a zmq driver process.
    """    
    
    def setUp(self):
        """
        Setup test cases.
        """

        # Clear driver event list.
        self._events = []

        # The port agent object. Used to start and stop the port agent.
        self._pagent = None
        
        # The driver process popen object.
        self._dvr_proc = None
        
        # The driver client.
        self._dvr_client = None

        # Create and start the port agent.
        mi_logger.info('start')
        self._start_pagent()
        self.addCleanup(self._stop_pagent)    

        # Create and start the driver.
        self._start_driver()
        self.addCleanup(self._stop_driver)        
        
    def _start_pagent(self):
        """
        Construct and start the port agent.
        """
        
        # Create port agent object.
        this_pid = os.getpid()
        self._pagent = EthernetDeviceLogger.launch_process(DEV_ADDR, DEV_PORT,
                        WORK_DIR, 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()
        
        COMMS_CONFIG['port'] = port

        mi_logger.info('Started port agent pid %d listening at port %d', pid, 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(DVR_MOD, DVR_CLS, WORK_DIR, this_pid)
        self._dvr_proc = dvr_proc
        mi_logger.info('Started driver process for %d %d %s %s', cmd_port,
            evt_port, DVR_MOD, DVR_CLS)
        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, DVR_MOD, DVR_CLS)
        
        # 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)
    
    def assertSampleDict(self, val):
        """
        Verify the value is a sample dictionary for the sbe16.
        """
        #{'p': [-6.945], 'c': [0.08707], 't': [20.002], 'time': [1333752198.450622]}        
        self.assertTrue(isinstance(val, dict))
        self.assertTrue(val.has_key('c'))
        self.assertTrue(val.has_key('t'))
        self.assertTrue(val.has_key('p'))
        self.assertTrue(val.has_key('time'))
        c = val['c'][0]
        t = val['t'][0]
        p = val['p'][0]
        time = val['time'][0]
    
        self.assertTrue(isinstance(c, float))
        self.assertTrue(isinstance(t, float))
        self.assertTrue(isinstance(p, float))
        self.assertTrue(isinstance(time, float))
    
    def assertParamDict(self, pd, all_params=False):
        """
        Verify all device parameters exist and are correct type.
        """
        if all_params:
            self.assertEqual(set(pd.keys()), set(PARAMS.keys()))
            #print str(pd)
            #print str(PARAMS)
            for (key, type_val) in PARAMS.iteritems():
                #print key
                self.assertTrue(isinstance(pd[key], type_val))
        else:
            for (key, val) in pd.iteritems():
                self.assertTrue(PARAMS.has_key(key))
                self.assertTrue(isinstance(val, PARAMS[key]))
    
    def assertParamVals(self, params, correct_params):
        """
        Verify parameters take the correct values.
        """
        self.assertEqual(set(params.keys()), set(correct_params.keys()))
        for (key, val) in params.iteritems():
            correct_val = correct_params[key]
            if isinstance(val, float):
                # Verify to 5% of the larger value.
                max_val = max(abs(val), abs(correct_val))
                self.assertAlmostEqual(val, correct_val, delta=max_val*.01)

            else:
                # int, bool, str, or tuple of same
                self.assertEqual(val, correct_val)
    
    def test_process(self):
        """
        Test for correct launch of driver process and communications, including
        asynchronous driver events.
        """
        # Verify processes exist.
        self.assertNotEqual(self._dvr_proc, None)
        drv_pid = self._dvr_proc.pid
        self.assertTrue(isinstance(drv_pid, int))
        
        self.assertNotEqual(self._pagent, None)
        pagent_pid = self._pagent.get_pid()
        self.assertTrue(isinstance(pagent_pid, int))
        
        # Send a test message to the process interface, confirm result.
        msg = 'I am a ZMQ message going to the process.'
        reply = self._dvr_client.cmd_dvr('process_echo', msg)
        self.assertEqual(reply,'process_echo: '+msg)
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)
        
        # Send a test message to the driver interface, confirm result.
        msg = 'I am a ZMQ message going to the driver.'
        reply = self._dvr_client.cmd_dvr('driver_echo', msg)
        self.assertEqual(reply, 'driver_echo: '+msg)
        
        # Test the event thread publishes and client side picks up events.
        events = [
            'I am important event #1!',
            'And I am important event #2!'
            ]
        reply = self._dvr_client.cmd_dvr('test_events', events=events)
        gevent.sleep(1)
        
        # Confirm the events received are as expected.
        self.assertEqual(self._events, events)

        # Test the exception mechanism.
        with self.assertRaises(InstrumentException):
            exception_str = 'Oh no, something bad happened!'
            reply = self._dvr_client.cmd_dvr('test_exceptions', exception_str)
        
        # Verify we received a driver error event.
        gevent.sleep(1)
        error_events = [evt for evt in self._events if isinstance(evt, dict) and evt['type']==DriverAsyncEvent.ERROR]
        self.assertTrue(len(error_events) == 1)
        
    def test_config(self):
        """
        Test to configure the driver process for device comms and transition
        to disconnected state.
        """

        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Initialize the driver and transition to unconfigured.
        reply = self._dvr_client.cmd_dvr('initialize')

        # Test the driver returned state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)
        
    def test_connect(self):
        """
        Test configuring and connecting to the device through the port
        agent. Discover device state.
        """
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('connect')

        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('disconnect')

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Initialize the driver and transition to unconfigured.
        reply = self._dvr_client.cmd_dvr('initialize')
    
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)
        
    def test_get_set(self):
        """
        Test device parameter access.
        """

        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        reply = self._dvr_client.cmd_dvr('connect')
                
        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)
                
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        # Get all device parameters. Confirm all expected keys are retrived
        # and have correct type.
        reply = self._dvr_client.cmd_dvr('get', SBE16Parameter.ALL)
        self.assertParamDict(reply, True)

        # Remember original configuration.
        orig_config = reply
        
        # Grab a subset of parameters.
        params = [
            SBE16Parameter.TA0,
            SBE16Parameter.INTERVAL,
            SBE16Parameter.STORETIME,
            SBE16Parameter.TCALDATE
            ]
        reply = self._dvr_client.cmd_dvr('get', params)
        self.assertParamDict(reply)        

        # Remember the original subset.
        orig_params = reply
        
        # Construct new parameters to set.
        old_date = orig_params[SBE16Parameter.TCALDATE]
        new_params = {
            SBE16Parameter.TA0 : orig_params[SBE16Parameter.TA0] * 1.2,
            SBE16Parameter.INTERVAL : orig_params[SBE16Parameter.INTERVAL] + 1,
            SBE16Parameter.STORETIME : not orig_params[SBE16Parameter.STORETIME],
            SBE16Parameter.TCALDATE : (old_date[0], old_date[1], old_date[2] + 1)
        }

        # Set parameters and verify.
        reply = self._dvr_client.cmd_dvr('set', new_params)
        reply = self._dvr_client.cmd_dvr('get', params)
        self.assertParamVals(reply, new_params)
        
        # Restore original parameters and verify.
        reply = self._dvr_client.cmd_dvr('set', orig_params)
        reply = self._dvr_client.cmd_dvr('get', params)
        self.assertParamVals(reply, orig_params)

        # Retrieve the configuration and ensure it matches the original.
        # Remove samplenum as it is switched by autosample and storetime.
        reply = self._dvr_client.cmd_dvr('get', SBE16Parameter.ALL)
        reply.pop('SAMPLENUM')
        orig_config.pop('SAMPLENUM')
        self.assertParamVals(reply, orig_config)

        # Disconnect from the port agent.
        reply = self._dvr_client.cmd_dvr('disconnect')
        
        # Test the driver is disconnected.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)
        
        # Deconfigure the driver.
        reply = self._dvr_client.cmd_dvr('initialize')
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)        
    
    def test_poll(self):
        """
        Test sample polling commands and events.
        """

        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        reply = self._dvr_client.cmd_dvr('connect')
                
        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)
                
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        # Poll for a sample and confirm result.
        reply = self._dvr_client.cmd_dvr('execute_acquire_sample')
        self.assertSampleDict(reply)
        
        # Poll for a sample and confirm result.
        reply = self._dvr_client.cmd_dvr('execute_acquire_sample')
        self.assertSampleDict(reply)

        # Poll for a sample and confirm result.
        reply = self._dvr_client.cmd_dvr('execute_acquire_sample')
        self.assertSampleDict(reply)
        
        # Confirm that 3 samples arrived as published events.
        gevent.sleep(1)
        sample_events = [evt for evt in self._events if evt['type']==DriverAsyncEvent.SAMPLE]
        self.assertEqual(len(sample_events), 3)

        # Disconnect from the port agent.
        reply = self._dvr_client.cmd_dvr('disconnect')
        
        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)
        
        # Deconfigure the driver.
        reply = self._dvr_client.cmd_dvr('initialize')
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

    def test_autosample(self):
        """
        Test autosample mode.
        """
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('connect')

        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)
        
        # Make sure the device parameters are set to sample frequently and
        # to transmit.
        params = {
            SBE16Parameter.NAVG : 1,
            SBE16Parameter.INTERVAL : 5,
            SBE16Parameter.TXREALTIME : True
        }
        reply = self._dvr_client.cmd_dvr('set', params)
        
        reply = self._dvr_client.cmd_dvr('execute_start_autosample')

        # Test the driver is in autosample mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.AUTOSAMPLE)
        
        # Wait for a few samples to roll in.
        gevent.sleep(30)
        
        # Return to command mode. Catch timeouts and retry if necessary.
        count = 0
        while True:
            try:
                reply = self._dvr_client.cmd_dvr('execute_stop_autosample')
            
            except TimeoutError:
                count += 1
                if count >= 5:
                    self.fail('Could not wakeup device to leave autosample mode.')

            else:
                break

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        # Verify we received at least 2 samples.
        sample_events = [evt for evt in self._events if evt['type']==DriverAsyncEvent.SAMPLE]
        self.assertTrue(len(sample_events) >= 2)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('disconnect')

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Initialize the driver and transition to unconfigured.
        reply = self._dvr_client.cmd_dvr('initialize')
    
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

    @unittest.skip('Not supported by simulator and very long (> 5 min).')
    def test_test(self):
        """
        Test the hardware testing mode.
        """
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('connect')

        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        start_time = time.time()
        reply = self._dvr_client.cmd_dvr('execute_test')

        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.TEST)
        
        while state != SBE16ProtocolState.COMMAND:
            gevent.sleep(5)
            elapsed = time.time() - start_time
            mi_logger.info('Device testing %f seconds elapsed.' % elapsed)
            state = self._dvr_client.cmd_dvr('get_current_state')

        # Verify we received the test result and it passed.
        test_results = [evt for evt in self._events if evt['type']==DriverAsyncEvent.TEST_RESULT]
        self.assertTrue(len(test_results) == 1)
        self.assertEqual(test_results[0]['value']['success'], 'Passed')

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('disconnect')

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Initialize the driver and transition to unconfigured.
        reply = self._dvr_client.cmd_dvr('initialize')
    
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

    def test_errors(self):
        """
        Test response to erroneous commands and parameters.
        """
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Assert for an unknown driver command.
        with self.assertRaises(UnknownCommandError):
            reply = self._dvr_client.cmd_dvr('bogus_command')

        # Assert for a known command, invalid state.
        with self.assertRaises(StateError):
            reply = self._dvr_client.cmd_dvr('execute_acquire_sample')

        # Assert we forgot the comms parameter.
        with self.assertRaises(ParameterError):
            reply = self._dvr_client.cmd_dvr('configure')

        # Assert we send a bad config object (not a dict).
        with self.assertRaises(ParameterError):
            BOGUS_CONFIG = 'not a config dict'            
            reply = self._dvr_client.cmd_dvr('configure', BOGUS_CONFIG)
            
        # Assert we send a bad config object (missing addr value).
        with self.assertRaises(ParameterError):
            BOGUS_CONFIG = COMMS_CONFIG.copy()
            BOGUS_CONFIG.pop('addr')
            reply = self._dvr_client.cmd_dvr('configure', BOGUS_CONFIG)

        # Assert we send a bad config object (bad addr value).
        with self.assertRaises(ParameterError):
            BOGUS_CONFIG = COMMS_CONFIG.copy()
            BOGUS_CONFIG['addr'] = ''
            reply = self._dvr_client.cmd_dvr('configure', BOGUS_CONFIG)
        
        # Configure for comms.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Assert for a known command, invalid state.
        with self.assertRaises(StateError):
            reply = self._dvr_client.cmd_dvr('execute_acquire_sample')

        reply = self._dvr_client.cmd_dvr('connect')
                
        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)

        # Assert for a known command, invalid state.
        with self.assertRaises(StateError):
            reply = self._dvr_client.cmd_dvr('execute_acquire_sample')
                
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        # Poll for a sample and confirm result.
        reply = self._dvr_client.cmd_dvr('execute_acquire_sample')
        self.assertSampleDict(reply)

        # Assert for a known command, invalid state.
        with self.assertRaises(StateError):
            reply = self._dvr_client.cmd_dvr('execute_stop_autosample')
        
        # Assert for a known command, invalid state.
        with self.assertRaises(StateError):
            reply = self._dvr_client.cmd_dvr('connect')

        # Get all device parameters. Confirm all expected keys are retrived
        # and have correct type.
        reply = self._dvr_client.cmd_dvr('get', SBE16Parameter.ALL)
        self.assertParamDict(reply, True)
        
        # Assert get fails without a parameter.
        with self.assertRaises(ParameterError):
            reply = self._dvr_client.cmd_dvr('get')
            
        # Assert get fails without a bad parameter (not ALL or a list).
        with self.assertRaises(ParameterError):
            bogus_params = 'I am a bogus param list.'
            reply = self._dvr_client.cmd_dvr('get', bogus_params)
            
        # Assert get fails without a bad parameter (not ALL or a list).
        #with self.assertRaises(InvalidParameterValueError):
        with self.assertRaises(ParameterError):
            bogus_params = [
                'a bogus parameter name',
                SBE16Parameter.INTERVAL,
                SBE16Parameter.STORETIME,
                SBE16Parameter.TCALDATE
                ]
            reply = self._dvr_client.cmd_dvr('get', bogus_params)        
        
        # Assert we cannot set a bogus parameter.
        with self.assertRaises(ParameterError):
            bogus_params = {
                'a bogus parameter name' : 'bogus value'
            }
            reply = self._dvr_client.cmd_dvr('set', bogus_params)
            
        # Assert we cannot set a real parameter to a bogus value.
        with self.assertRaises(ParameterError):
            bogus_params = {
                SBE16Parameter.INTERVAL : 'bogus value'
            }
            reply = self._dvr_client.cmd_dvr('set', bogus_params)
        
        # Disconnect from the port agent.
        reply = self._dvr_client.cmd_dvr('disconnect')
        
        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)
        
        # Deconfigure the driver.
        reply = self._dvr_client.cmd_dvr('initialize')
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)
    
    @unittest.skip('Not supported by simulator.')
    def test_discover_autosample(self):
        """
        Test the device can discover autosample mode.
        """
        
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('connect')

        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('discover')

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)
        
        # Make sure the device parameters are set to sample frequently.
        params = {
            SBE16Parameter.NAVG : 1,
            SBE16Parameter.INTERVAL : 5
        }
        reply = self._dvr_client.cmd_dvr('set', params)
        
        reply = self._dvr_client.cmd_dvr('execute_start_autosample')

        # Test the driver is in autosample mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.AUTOSAMPLE)
    
        # Let a sample or two come in.
        gevent.sleep(30)
    
        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('disconnect')

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Initialize the driver and transition to unconfigured.
        reply = self._dvr_client.cmd_dvr('initialize')
    
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)

        # Wait briefly before we restart the comms.
        gevent.sleep(10)
    
        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('configure', COMMS_CONFIG)

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('connect')

        # Test the driver is in unknown state.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.UNKNOWN)

        # Configure driver for comms and transition to disconnected.
        count = 0
        while True:
            try:        
                reply = self._dvr_client.cmd_dvr('discover')

            except TimeoutError:
                count += 1
                if count >=5:
                    self.fail('Could not discover device state.')

            else:
                break

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.AUTOSAMPLE)

        # Let a sample or two come in.
        # This device takes awhile to begin transmitting again after you
        # prompt it in autosample mode.
        gevent.sleep(30)

        # Return to command mode. Catch timeouts and retry if necessary.
        count = 0
        while True:
            try:
                reply = self._dvr_client.cmd_dvr('execute_stop_autosample')
            
            except TimeoutError:
                count += 1
                if count >= 5:
                    self.fail('Could not wakeup device to leave autosample mode.')

            else:
                break

        # Test the driver is in command mode.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, SBE16ProtocolState.COMMAND)

        # Configure driver for comms and transition to disconnected.
        reply = self._dvr_client.cmd_dvr('disconnect')

        # Test the driver is configured for comms.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.DISCONNECTED)

        # Initialize the driver and transition to unconfigured.
        reply = self._dvr_client.cmd_dvr('initialize')
    
        # Test the driver is in state unconfigured.
        state = self._dvr_client.cmd_dvr('get_current_state')
        self.assertEqual(state, DriverConnectionState.UNCONFIGURED)
예제 #11
0
    def test_autosample(self):
        """
        Test autosample command and state, including events.
        """
        # Launch driver process.
        driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)
        
        # Create client and start messaging.
        driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)
        driver_client.start_messaging()
        time.sleep(2)

        reply = driver_client.cmd_dvr('configure', self.comms_config)
        time.sleep(2)

        reply = driver_client.cmd_dvr('connect')
        time.sleep(2)
        
        reply = driver_client.cmd_dvr('start_autosample')
        time.sleep(30)
        
        while True:
            reply = driver_client.cmd_dvr('stop_autosample')
            if not reply[SBE37Channel.CTD]:
                break
            time.sleep(2)
        time.sleep(2)

        reply = driver_client.cmd_dvr('disconnect')
        time.sleep(2)
        
        # Deconfigure the driver.
        reply = driver_client.cmd_dvr('initialize')
        time.sleep(2)
        
        # Terminate driver process and stop client messaging.
        driver_client.done()
        driver_process.wait()
예제 #12
0
    def test_poll(self):
        """
        Test sample polling commands and events.
        """
        # Launch driver process.
        driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)
        
        # Create client and start messaging.
        driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)
        self.clear_events()
        driver_client.start_messaging(self.evt_recd)
        time.sleep(2)

        reply = driver_client.cmd_dvr('configure', self.comms_config)
        time.sleep(2)

        reply = driver_client.cmd_dvr('connect')
        time.sleep(2)
        
        reply = driver_client.cmd_dvr('get_active_channels')
        time.sleep(2)
        
        reply = driver_client.cmd_dvr('execute_acquire_sample')
        time.sleep(2)
        
        reply = driver_client.cmd_dvr('execute_acquire_sample')
        time.sleep(2)

        reply = driver_client.cmd_dvr('execute_acquire_sample')
        time.sleep(2)

        print 'EVENTS RECEIVED:'
        print str(self.events)

        reply = driver_client.cmd_dvr('disconnect')
        time.sleep(2)
        
        # Deconfigure the driver.
        reply = driver_client.cmd_dvr('initialize')
        time.sleep(2)
        
        # Terminate driver process and stop client messaging.
        driver_client.done()
        driver_process.wait()
예제 #13
0
    def test_get_set(self):
        """
        Test driver parameter get/set interface including device persistence.
        TA2=-4.858579e-06
        PTCA1=-0.6603433
        TCALDATE=(8, 11, 2005)        
        """
        
        # Launch driver process.
        driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)

        # Create client and start messaging.        
        driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)
        driver_client.start_messaging()
        time.sleep(3)

        # Configure driver for comms and transition to disconnected.
        reply = driver_client.cmd_dvr('configure', self.comms_config)
        time.sleep(2)

        # Establish devcie comms and transition to command.
        reply = driver_client.cmd_dvr('connect')
        time.sleep(2)
        
        # Get all parameters.
        get_params = [
            (SBE37Channel.CTD, SBE37Parameter.ALL)            
        ]
        reply = driver_client.cmd_dvr('get', get_params)
        time.sleep(2)
        
        # Check overall and individual parameter success. Check parameter types.
        self.assertIsInstance(reply, dict)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.TA2)],
                                                            float)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.PTCA1)],
                                                            float)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.TCALDATE)],
                                                            (list, tuple))
        
        # Set up a param dict of the original values.
        old_ta2 = reply[(SBE37Channel.CTD, SBE37Parameter.TA2)]
        old_ptca1 = reply[(SBE37Channel.CTD, SBE37Parameter.PTCA1)]
        old_tcaldate = reply[(SBE37Channel.CTD, SBE37Parameter.TCALDATE)]
        orig_params = {
            (SBE37Channel.CTD, SBE37Parameter.TA2): old_ta2,
            (SBE37Channel.CTD, SBE37Parameter.PTCA1): old_ptca1,
            (SBE37Channel.CTD, SBE37Parameter.TCALDATE): old_tcaldate            
        }

        # Set up a param dict of new values.
        new_ta2 = old_ta2*2
        new_ptcal1 = old_ptca1*2
        new_tcaldate = list(old_tcaldate)
        new_tcaldate[2] = new_tcaldate[2] + 1
        new_tcaldate = tuple(new_tcaldate)
        new_params = {
            (SBE37Channel.CTD, SBE37Parameter.TA2): new_ta2,
            (SBE37Channel.CTD, SBE37Parameter.PTCA1): new_ptcal1,
            (SBE37Channel.CTD, SBE37Parameter.TCALDATE): new_tcaldate
        }
        
        # Set the params to their new values.
        reply = driver_client.cmd_dvr('set', new_params)
        time.sleep(2)
        
        # Check overall success and success of the individual paramters.
        self.assertIsInstance(reply, dict)
        mi_logger.debug('set result: %s', str(reply))
        
        # Get the same paramters back from the driver.
        get_params = [
            (SBE37Channel.CTD, SBE37Parameter.TA2),
            (SBE37Channel.CTD, SBE37Parameter.PTCA1),
            (SBE37Channel.CTD, SBE37Parameter.TCALDATE)
        ]
        reply = driver_client.cmd_dvr('get', get_params)
        time.sleep(2)

        # Check success, and check that the parameters were set to the
        # new values.
        self.assertIsInstance(reply, dict)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.TA2)],
                                                            float)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.PTCA1)],
                                                            float)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.TCALDATE)],
                                                            (list, tuple))
        self.assertAlmostEqual(reply[(SBE37Channel.CTD, SBE37Parameter.TA2)],
                                    new_ta2, delta=abs(0.01*new_ta2))
        self.assertAlmostEqual(reply[(SBE37Channel.CTD, SBE37Parameter.PTCA1)],
                                    new_ptcal1, delta=abs(0.01*new_ptcal1))
        self.assertEqual(reply[(SBE37Channel.CTD, SBE37Parameter.TCALDATE)],
                                                            new_tcaldate)


        # Set the paramters back to their original values.        
        reply = driver_client.cmd_dvr('set', orig_params)
        self.assertIsInstance(reply, dict)
        mi_logger.debug('set result: %s', str(reply))

        # Get the parameters back from the driver.
        reply = driver_client.cmd_dvr('get', get_params)

        # Check overall and individual sucess, and that paramters were
        # returned to their original values.
        self.assertIsInstance(reply, dict)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.TA2)],
                                                    float)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.PTCA1)],
                                                    float)
        self.assertIsInstance(reply[(SBE37Channel.CTD, SBE37Parameter.TCALDATE)],
                                                    (list, tuple))
        self.assertAlmostEqual(reply[(SBE37Channel.CTD, SBE37Parameter.TA2)],
                                            old_ta2, delta=abs(0.01*old_ta2))
        self.assertAlmostEqual(reply[(SBE37Channel.CTD, SBE37Parameter.PTCA1)],
                                        old_ptca1, delta=abs(0.01*old_ptca1))
        self.assertEqual(reply[(SBE37Channel.CTD, SBE37Parameter.TCALDATE)],
                                        old_tcaldate)
        
        # Disconnect driver from the device and transition to disconnected.
        reply = driver_client.cmd_dvr('disconnect', [SBE37Channel.CTD])
        time.sleep(2)
        
        # Deconfigure the driver and transition to unconfigured.
        reply = driver_client.cmd_dvr('initialize', [SBE37Channel.CTD])
        time.sleep(2)
        
        # End driver process and client messaging.
        driver_client.done()
        driver_process.wait()
예제 #14
0
class BarsDriverTest(PyonBarsTestCase):
    """
    Tests involving ZMQ driver process and ZMQ client.
    """

    def setUp(self):
        super(BarsDriverTest, self).setUp()

        # Zmq parameters used by driver process and client.
        self.server_addr = 'localhost'
        self.cmd_port = 5556
        self.evt_port = 5557

        # Driver module parameters.
        self.dvr_mod = 'ion.services.mi.drivers.uw_bars.driver'
        self.dvr_cls = 'BarsInstrumentDriver'

        self._driver_process = ZmqDriverProcess.launch_process(self.cmd_port,
            self.evt_port, self.dvr_mod,  self.dvr_cls)

        self._driver_client = ZmqDriverClient(self.server_addr, self.cmd_port,
                                        self.evt_port)
        self._driver_client.start_messaging()
        time.sleep(1)

        self.addCleanup(self._clean_up)

    def _clean_up(self):
        if self._driver_process:
            try:
                self._driver_client.done()
                self._driver_process.wait()
            finally:
                self._driver_process = None

    def tearDown(self):
        super(BarsDriverTest, self).tearDown()
        self._clean_up()

    def _initialize(self):
        driver_client = self._driver_client

        reply = driver_client.cmd_dvr('initialize', [BarsChannel.INSTRUMENT])
        print("** initialize reply=%s" % str(reply))
        reply = driver_client.cmd_dvr('get_current_state')
        print("** get_current_state reply=%s" % str(reply))
        self.assertEqual(DriverState.UNCONFIGURED, reply)
        time.sleep(1)

    def _connect(self):
        driver_client = self._driver_client

        reply = driver_client.cmd_dvr('get_current_state')
        print("** get_current_state reply=%s" % str(reply))
        self.assertEqual(DriverState.UNCONFIGURED, reply)

        self._initialize()

        configs = {BarsChannel.INSTRUMENT: self.config}
        reply = driver_client.cmd_dvr('configure', configs)
        print("** configure reply=%s" % str(reply))

        reply = driver_client.cmd_dvr('get_current_state')
        print("** get_current_state reply=%s" % str(reply))

        reply = driver_client.cmd_dvr('connect', [BarsChannel.INSTRUMENT])
        print("** connect reply=%s" % str(reply))

        time.sleep(1)

        reply = driver_client.cmd_dvr('get_current_state')
        print("** get_current_state reply=%s" % str(reply))
        self.assertEqual(DriverState.AUTOSAMPLE, reply)

        time.sleep(1)

        reply = driver_client.cmd_dvr('get_status', [BarsChannel.INSTRUMENT])
        print("** get_status reply=%s" % str(reply))
        self.assertEqual(DriverState.AUTOSAMPLE, reply)

        time.sleep(1)

    def _disconnect(self):
        driver_client = self._driver_client

        reply = driver_client.cmd_dvr('disconnect', [BarsChannel.INSTRUMENT])
        print("** disconnect reply=%s" % str(reply))
        reply = driver_client.cmd_dvr('get_current_state')
        print("** get_current_state reply=%s" % str(reply))
        self.assertEqual(DriverState.DISCONNECTED, reply)
        time.sleep(1)

        self._initialize()

    def test_connect_disconnect(self):
        """BARS connect and disconnect"""

        self._connect()
        self._disconnect()

    def test_get(self):
        """BARS get"""

        self._connect()

        driver_client = self._driver_client

        # get a parameter
        cp = (BarsChannel.INSTRUMENT, BarsParameter.TIME_BETWEEN_BURSTS)
        get_params = [cp]

        reply = driver_client.cmd_dvr('get', get_params)
        print "get reply = %s" % str(reply)
        seconds = reply.get(cp)
        assert isinstance(seconds, int)

        self._disconnect()