Esempio n. 1
0
    def setUp(self):
        """
        Sets up and connects the _client.
        """

        TrhphClientTest._end_client_if_any()

        super(TrhphClientTest, self).setUp()

        host = self.device_address
        port = self.device_port
        self._samples_recd = 0
        outfile = file('trhph_output.txt', 'w')
        prefix_state = True
        _client = TrhphClient(host, port, outfile, prefix_state)

        # set the class and instance variables to refer to this object:
        TrhphClientTest._trhph_client = self._client = _client

        # prepare client including going to the main menu
        _client.set_data_listener(self._data_listener)
        _client.set_generic_timeout(self._timeout)

        log.info("connecting")
        _client.connect()
Esempio n. 2
0
class TrhphInstrumentProtocol(InstrumentProtocol):
    """
    The protocol for the TrhphChannel.INSTRUMENT channel.
    """

    def __init__(self, evt_callback=None):
        """
        Creates and initializes a protocol object to the UNCOFIGURED state.
        """
        InstrumentProtocol.__init__(self, evt_callback)

        self.trhph_client = None

        self._host = None
        self._port = None

        self._state = DriverState.UNCONFIGURED

        # TODO probably promote this convenience to super-class?
        self._timeout = 30
        """Default timeout value for operations accepting an optional timeout
        argument."""

    def get_current_state(self):
        """
        Gets the current state of the protocol.
        """
        return self._state

    def _assert_state(self, obj):
        """
        Asserts that the current state is the same as the one given (if not
        a list) or that is one of the elements of the given list.
        """
        cs = self.get_current_state()
        if isinstance(obj, list):
            if cs in obj:
                return
            else:
                raise AssertionError("current state=%s, expected one of %s" %
                                 (cs, str(obj)))
        state = obj
        if cs != state:
            raise AssertionError("current state=%s, expected=%s" % (cs, state))

    def initialize(self, *args, **kwargs):
        """
        Resets the protocol to the UNCONFIGURED state.
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" %
                      (str(args), str(kwargs)))

        self._assert_state([DriverState.UNCONFIGURED,
                            DriverState.DISCONNECTED])

        super(TrhphInstrumentProtocol, self).initialize(*args, **kwargs)

        self._state = DriverState.UNCONFIGURED

    def configure(self, config, *args, **kwargs):
        """
        Sets _host/_port according to the given config object and sets the
        current state as DriverState.DISCONNECTED.
        Note that super.configure is not called but instead and adjusted
        version of it.
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("config=%s args=%s kwargs=%s" %
                      (str(config), str(args), str(kwargs)))

        self._assert_state(DriverState.UNCONFIGURED)

        # Parameters for TrhphClient:
        # with direct access to the instrument:
        #   self._host = config['device_addr']
        #   self._port = config['device_port']
        # but we're now connecting through the EthernetDeviceLogger:
        self._host = config['server_addr']
        self._port = config['server_port']
        self._base_configure(config, *args, **kwargs)

        self._state = DriverState.DISCONNECTED

        return InstErrorCode.OK

    def _base_configure(self, config, *args, **kwargs):
        """
        This is as super.configure but with adjustments so we actually use
        TrhphClient (in attach) instead of LoggerClient.
        The base class is under changes so this all may change as well.
        """
        log.info('Configuring for device comms.')

        method = config['method']

        if method == 'ethernet':
            device_addr = config['device_addr']
            device_port = config['device_port']
            #server_addr = config['server_addr']
            server_port = config['server_port']
            self._logger = EthernetDeviceLogger(device_addr, device_port,
                                            server_port)
            #self._logger_client = LoggerClient(server_addr, server_port)

        elif method == 'serial':
            # The config dict does not have a valid connection method.
            raise InstrumentConnectionException()

        else:
            # The config dict does not have a valid connection method.
            raise InstrumentConnectionException()

        return InstErrorCode.OK

    def connect(self, *args, **kwargs):
        """
        It calls super.connect, which calls attach, where the actual connection
        happens, and sets _state to DriverState.CONNECTED.
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" %
                      (str(args), str(kwargs)))

        self._assert_state([DriverState.UNCONFIGURED,
                            DriverState.DISCONNECTED])

        # TODO Note that super.connect calls attach; it would be better that
        # the attach call be done by client code so for example it is
        # possible to separate the intervening states (DISCONNECTED,
        # CONNECTED, ATTACHED, DETACHED).
        super(TrhphInstrumentProtocol, self).connect(*args, **kwargs)

        self._state = DriverState.CONNECTED

    def _data_listener(self, sample):
        """
        The callback used to announce a DATA_RECEIVED event to the driver.
        """
        log.info("_data_listener: sample = %s" % str(sample))

#        log.debug("announcing to driver: %s" % str(sample))
#        self.announce_to_driver(DriverAnnouncement.DATA_RECEIVED,
#                                data_sample=sample)

    def disconnect(self, *args, **kwargs):
        """
        Calls super.disconnect and sets state to DriverState.DISCONNECTED
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" %
                      (str(args), str(kwargs)))

        super(TrhphInstrumentProtocol, self).disconnect(*args, **kwargs)

        self._state = DriverState.DISCONNECTED

    def attach(self, *args, **kwargs):
        """
        Sets up the trhph_client and connects to the instrument.
        Note that super.attach is not called.
        """
        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" %
                      (str(args), str(kwargs)))

        # TODO better handling of the intervening states related with
        # connection and attachment -- see comment above in connect().
#        self._assert_state(DriverState.CONNECTED)

        self._setup_trhph_client()

        return InstErrorCode.OK

    def _setup_trhph_client(self):
        """
        Called by attach() to create the supporting TrhphClient object and do
        the connection. A file trhph_output.txt in the current directory is
        specified for the TrhphClient to log out all received messages from
        the instrument.
        """
        host = self._host
        port = self._port
        outfile = file('trhph_output.txt', 'w')
        log.info("setting TrhphClient to connect to %s:%s" % (host, port))
        self.trhph_client = TrhphClient(host, port, outfile, True)
        self.trhph_client.set_data_listener(self._data_listener)
        self.trhph_client.connect()

    def detach(self, *args, **kwargs):
        """
        Ends the TrhphClient and returns InstErrorCode.OK.
        Note that super.detach is not called.
        """
        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" %
                      (str(args), str(kwargs)))

        self.trhph_client.end()
        self.trhph_client = None

        return InstErrorCode.OK

    ########################################################################
    # Channel command interface.
    ########################################################################

    def get(self, params, *args, **kwargs):
        """
        Gets the value of the requested parameters.
        It handles TIME_BETWEEN_BURSTS, VERBOSE_MODE.
        """
        if log.isEnabledFor(logging.DEBUG):
            log.debug("params=%s args=%s kwargs=%s" %
                      (str(params), str(args), str(kwargs)))

        assert isinstance(params, list)

        # TODO actually it should be ATTACHED if we want consistency with the
        # states related with connection and attachment.
        self._assert_state(DriverState.CONNECTED)

        timeout = kwargs.get('timeout', self._timeout)

        # gather data collection params if any of them are requested:
        data_coll_params = {}
        if TrhphParameter.TIME_BETWEEN_BURSTS in params or \
           TrhphParameter.VERBOSE_MODE in params:
            seconds, is_data_only = self._get_data_collection_params(timeout)
            data_coll_params[TrhphParameter.TIME_BETWEEN_BURSTS] = seconds
            data_coll_params[TrhphParameter.VERBOSE_MODE] = is_data_only

        params = list(set(params))  # remove any duplicates

        result = {}
        for param in params:
            if param == TrhphParameter.TIME_BETWEEN_BURSTS or \
               param == TrhphParameter.VERBOSE_MODE:
                value = data_coll_params[param]
            else:
                value = InstErrorCode.INVALID_PARAMETER
            result[param] = value

        return result

    def _get_data_collection_params(self, timeout):
        """
        Gets the get_data_collection_params.
        """
        try:
            return self.trhph_client.get_data_collection_params(timeout)
        except TimeoutException, e:
            raise InstrumentTimeoutException(str(e))
        except TrhphClientException, e:
            return InstErrorCode.MESSAGING_ERROR
Esempio n. 3
0
class TrhphInstrumentDriver(InstrumentDriver):
    """
    TRHPH driver
    """
    def __init__(self, evt_callback):
        """
        Constructor.

        @param evt_callback Driver process event callback.
        """
        InstrumentDriver.__init__(self, evt_callback)

        # _trhph_client created in configure()
        self._trhph_client = None

        self._state = TrhphDriverState.UNCONFIGURED

        # TODO probably promote this convenience to super-class?
        self._timeout = 30
        """Default timeout value for operations accepting an optional timeout
        argument."""


    def _assert_state(self, obj):
        """
        Asserts that the current state is either the same as the one given (if
        not a list) or one of the elements of the given list.

        @raises StateError if the assertion fails
        """
        cs = self.get_current_state()
        if isinstance(obj, list):
            if cs in obj:
                return  # OK
            else:
                raise StateError(
                        "current state=%s not one of %s" % (cs, str(obj)))
        state = obj
        if cs != state:
            raise StateError(
                    "current state=%s, expected=%s" % (cs, state))

    #############################################################
    # Device connection interface.
    #############################################################

    def initialize(self, *args, **kwargs):
        """
        Initialize driver connection, bringing communications parameters
        into unconfigured state (no connection object).

        @raises StateError if command not allowed in current
                 state
        """

#        print
#        print("trhph driver: args=%s kwargs=%s" % (str(args), str(kwargs)))
#        print("trhph driver: state=%s" % str(self._state))
#        print("trhph driver: _trhph_client=%s" % str(self._trhph_client))
#        print

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" % (str(args), str(kwargs)))

        if self._state == TrhphDriverState.UNCONFIGURED:
            assert self._trhph_client is None
            return

#        assert self._trhph_client is not None
#        try:
#            self._trhph_client.end()
#        finally:
#            self._trhph_client = None
        if self._trhph_client is not None:
            try:
                self._trhph_client.end()
            finally:
                self._trhph_client = None

        self._state = TrhphDriverState.UNCONFIGURED

    def configure(self, *args, **kwargs):
        """
        Configure the driver for communications with the device via
        port agent / logger (valid but unconnected connection object).

        @param config comms config dict.

        @raises StateError if command not allowed in current
                state
        @throws ParameterError if missing comms or invalid
                config dict.
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" % (str(args), str(kwargs)))

        self._assert_state(TrhphDriverState.UNCONFIGURED)

        config = kwargs.get('config', None)
        if config is None:
#            raise ParameterError("'config' parameter required")
            config = args[0]

        # Verify dict and construct connection client.
        try:
            addr = config['addr']
            port = config['port']

            if isinstance(addr, str) and \
               isinstance(port, int) and len(addr) > 0:
#                self._connection = LoggerClient(addr, port)

                def _data_listener(sample):
                    log.info("_data_listener: sample = %s" % str(sample))

                host = addr
                outfile = file('trhph_output.txt', 'w')
                log.info("setting TrhphClient to connect to %s:%s" % (host, port))
                self.trhph_client = TrhphClient(host, port, outfile, True)
                self.trhph_client.set_data_listener(_data_listener)

            else:
                raise ParameterError('Invalid comms config dict')

        except (TypeError, KeyError):
            raise ParameterError('Invalid comms config dict.')

        self._state = TrhphDriverState.DISCONNECTED

    def connect(self, *args, **kwargs):
        """
        Establish communications with the device via port agent / logger
        (connected connection object).

        @raises StateError if command not allowed in current
                state
        @throws InstrumentConnectionException if the connection failed.
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" % (str(args), str(kwargs)))

        self._assert_state(TrhphDriverState.DISCONNECTED)

        self.trhph_client.connect()

        self._state = TrhphDriverState.CONNECTED

    def disconnect(self, *args, **kwargs):
        """
        Disconnect from device via port agent / logger.
        @raises StateError if command not allowed in current
                state
        """

        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" % (str(args), str(kwargs)))

        self._assert_state(TrhphDriverState.CONNECTED)

        self.trhph_client.end()

        self._state = TrhphDriverState.DISCONNECTED


    #############################################################
    # Command and control interface.
    #############################################################

    def get(self, *args, **kwargs):
        """
        Retrieve device parameters.

        @param params DriverParameter.ALL or a list of parameters to retrieve.
        @param timeout Timeout for each involved instrument interation,
                self._timeout by default.

        @retval parameter : value dict.
        @raises ParameterError if missing or invalid get parameters.
        @raises StateError if command not allowed in current state
        """
        
        if log.isEnabledFor(logging.DEBUG):
            log.debug("args=%s kwargs=%s" % (str(args), str(kwargs)))

        self._assert_state(TrhphDriverState.CONNECTED)

        params = kwargs.get('params', None)
        if params is None:
            raise ParameterError(
                    "'params' parameter required")

        if params == DriverParameter.ALL:
            params = TrhphParameter.list()
        elif not isinstance(params, (list, tuple)):
            raise ParameterError(
                    'params must be list or tuple.')

        timeout = kwargs.get('timeout', self._timeout)

        # gather data collection params if any of them are requested:
        data_collec_params = {}
        if TrhphParameter.TIME_BETWEEN_BURSTS in params or \
           TrhphParameter.VERBOSE_MODE in params:
            seconds, is_data_only = self._get_data_collection_params(timeout)
            verbose = not is_data_only
            data_collec_params[TrhphParameter.TIME_BETWEEN_BURSTS] = seconds
            data_collec_params[TrhphParameter.VERBOSE_MODE] = verbose

        params = list(set(params))  # remove any duplicates

        result = {}
        for param in params:
            if param == TrhphParameter.TIME_BETWEEN_BURSTS or \
               param == TrhphParameter.VERBOSE_MODE:
                value = data_collec_params[param]
            else:
#                value = InstErrorCode.INVALID_PARAMETER
                raise ParameterError('invalid parameter %s' % param)
            result[param] = value

        return result

    def _get_data_collection_params(self, timeout):
        """
        Gets the get_data_collection_params.
        """
        try:
            return self.trhph_client.get_data_collection_params(timeout)
        except TimeoutException, e:
            raise TimeoutError(str(e))
        except TrhphClientException, e:
            raise InstrumentException(str(e))