Instrumentation =============== The ``Instrument`` API provide a consistent way of collecting measurements from a target. Measurements are collected via an instance of a class derived from :class:`Instrument`. An ``Instrument`` allows collection of measurement from one or more channels. An ``Instrument`` may support ``INSTANTANEOUS`` or ``CONTINUOUS`` collection, or both. Example ------- The following example shows how to use an instrument to read temperature from an Android target. .. code-block:: ipython # import and instantiate the Target and the instrument # (note: this assumes exactly one android target connected # to the host machine). In [1]: from devlib import AndroidTarget, HwmonInstrument In [2]: t = AndroidTarget() In [3]: i = HwmonInstrument(t) # Set up the instrument on the Target. In case of HWMON, this is # a no-op, but is included here for completeness. In [4]: i.setup() # Find out what the instrument is capable collecting from the # target. In [5]: i.list_channels() Out[5]: [CHAN(battery/temp1, battery_temperature), CHAN(exynos-therm/temp1, exynos-therm_temperature)] # Set up a new measurement session, and specify what is to be # collected. In [6]: i.reset(sites=['exynos-therm']) # HWMON instrument supports INSTANTANEOUS collection, so invoking # take_measurement() will return a list of measurements take from # each of the channels configured during reset() In [7]: i.take_measurement() Out[7]: [exynos-therm_temperature: 36.0 degrees] API --- Instrument ~~~~~~~~~~ .. class:: Instrument(target, **kwargs) An ``Instrument`` allows collection of measurement from one or more channels. An ``Instrument`` may support ``INSTANTANEOUS`` or ``CONTINUOUS`` collection, or both. .. attribute:: Instrument.mode A bit mask that indicates collection modes that are supported by this instrument. Possible values are: :INSTANTANEOUS: The instrument supports taking a single sample via ``take_measurement()``. :CONTINUOUS: The instrument supports collecting measurements over a period of time via ``start()``, ``stop()``, ``get_data()``, and (optionally) ``get_raw`` methods. .. note:: It's possible for one instrument to support more than a single mode. .. attribute:: Instrument.active_channels Channels that have been activated via ``reset()``. Measurements will only be collected for these channels. .. method:: Instrument.list_channels() Returns a list of :class:`InstrumentChannel` instances that describe what this instrument can measure on the current target. A channel is a combination of a ``kind`` of measurement (power, temperature, etc) and a ``site`` that indicates where on the target the measurement will be collected from. .. method:: Instrument.get_channels(measure) Returns channels for a particular ``measure`` type. A ``measure`` can be either a string (e.g. ``"power"``) or a :class:`MeasurmentType` instance. .. method:: Instrument.setup(*args, **kwargs) This will set up the instrument on the target. Parameters this method takes are particular to subclasses (see documentation for specific instruments below). What actions are performed by this method are also instrument-specific. Usually these will be things like installing executables, starting services, deploying assets, etc. Typically, this method needs to be invoked at most once per reboot of the target (unless ``teardown()`` has been called), but see documentation for the instrument you're interested in. .. method:: Instrument.reset(sites=None, kinds=None, channels=None) This is used to configure an instrument for collection. This must be invoked before ``start()`` is called to begin collection. This methods sets the ``active_channels`` attribute of the ``Instrument``. If ``channels`` is provided, it is a list of names of channels to enable and ``sites`` and ``kinds`` must both be ``None``. Otherwise, if one of ``sites`` or ``kinds`` is provided, all channels matching the given sites or kinds are enabled. If both are provided then all channels of the given kinds at the given sites are enabled. If none of ``sites``, ``kinds`` or ``channels`` are provided then all available channels are enabled. .. method:: Instrument.take_measurment() Take a single measurement from ``active_channels``. Returns a list of :class:`Measurement` objects (one for each active channel). .. note:: This method is only implemented by :class:`Instrument`\ s that support ``INSTANTANEOUS`` measurement. .. method:: Instrument.start() Starts collecting measurements from ``active_channels``. .. note:: This method is only implemented by :class:`Instrument`\ s that support ``CONTINUOUS`` measurement. .. method:: Instrument.stop() Stops collecting measurements from ``active_channels``. Must be called after :func:`start()`. .. note:: This method is only implemented by :class:`Instrument`\ s that support ``CONTINUOUS`` measurement. .. method:: Instrument.get_data(outfile) Write collected data into ``outfile``. Must be called after :func:`stop()`. Data will be written in CSV format with a column for each channel and a row for each sample. Column heading will be channel, labels in the form ``_`` (see :class:`InstrumentChannel`). The order of the columns will be the same as the order of channels in ``Instrument.active_channels``. If reporting timestamps, one channel must have a ``site`` named ``"timestamp"`` and a ``kind`` of a :class:`MeasurmentType` of an appropriate time unit which will be used, if appropriate, during any post processing. .. note:: Currently supported time units are seconds, milliseconds and microseconds, other units can also be used if an appropriate conversion is provided. This returns a :class:`MeasurementCsv` instance associated with the outfile that can be used to stream :class:`Measurement`\ s lists (similar to what is returned by ``take_measurement()``. .. note:: This method is only implemented by :class:`Instrument`\ s that support ``CONTINUOUS`` measurement. .. method:: Instrument.get_raw() Returns a list of paths to files containing raw output from the underlying source(s) that is used to produce the data CSV. If now raw output is generated or saved, an empty list will be returned. The format of the contents of the raw files is entirely source-dependent. .. attribute:: Instrument.sample_rate_hz Sample rate of the instrument in Hz. Assumed to be the same for all channels. .. note:: This attribute is only provided by :class:`Instrument`\ s that support ``CONTINUOUS`` measurement. Instrument Channel ~~~~~~~~~~~~~~~~~~ .. class:: InstrumentChannel(name, site, measurement_type, **attrs) An :class:`InstrumentChannel` describes a single type of measurement that may be collected by an :class:`Instrument`. A channel is primarily defined by a ``site`` and a ``measurement_type``. A ``site`` indicates where on the target a measurement is collected from (e.g. a voltage rail or location of a sensor). A ``measurement_type`` is an instance of :class:`MeasurmentType` that describes what sort of measurement this is (power, temperature, etc). Each measurement type has a standard unit it is reported in, regardless of an instrument used to collect it. A channel (i.e. site/measurement_type combination) is unique per instrument, however there may be more than one channel associated with one site (e.g. for both voltage and power). It should not be assumed that any site/measurement_type combination is valid. The list of available channels can queried with :func:`Instrument.list_channels()`. .. attribute:: InstrumentChannel.site The name of the "site" from which the measurements are collected (e.g. voltage rail, sensor, etc). .. attribute:: InstrumentChannel.kind A string indicating the type of measurement that will be collected. This is the ``name`` of the :class:`MeasurmentType` associated with this channel. .. attribute:: InstrumentChannel.units Units in which measurement will be reported. this is determined by the underlying :class:`MeasurmentType`. .. attribute:: InstrumentChannel.label A label that can be attached to measurements associated with with channel. This is constructed with :: '{}_{}'.format(self.site, self.kind) Measurement Types ~~~~~~~~~~~~~~~~~ In order to make instruments easer to use, and to make it easier to swap them out when necessary (e.g. change method of collecting power), a number of standard measurement types are defined. This way, for example, power will always be reported as "power" in Watts, and never as "pwr" in milliWatts. Currently defined measurement types are +-------------+-------------+---------------+ | name | units | category | +=============+=============+===============+ | count | count | | +-------------+-------------+---------------+ | percent | percent | | +-------------+-------------+---------------+ | time_us | microseconds| time | +-------------+-------------+---------------+ | time_ms | milliseconds| time | +-------------+-------------+---------------+ | temperature | degrees | thermal | +-------------+-------------+---------------+ | power | watts | power/energy | +-------------+-------------+---------------+ | voltage | volts | power/energy | +-------------+-------------+---------------+ | current | amps | power/energy | +-------------+-------------+---------------+ | energy | joules | power/energy | +-------------+-------------+---------------+ | tx | bytes | data transfer | +-------------+-------------+---------------+ | rx | bytes | data transfer | +-------------+-------------+---------------+ | tx/rx | bytes | data transfer | +-------------+-------------+---------------+ .. instruments: Available Instruments --------------------- This section lists instruments that are currently part of devlib. TODO