1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-09-01 17:41:54 +01:00

devlib initial commit.

This commit is contained in:
Sergei Trofimov
2015-10-09 09:30:04 +01:00
commit 4e6afe960b
64 changed files with 8938 additions and 0 deletions

192
doc/Makefile Normal file
View File

@@ -0,0 +1,192 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/devlib.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/devlib.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/devlib"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/devlib"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

287
doc/conf.py Normal file
View File

@@ -0,0 +1,287 @@
# -*- coding: utf-8 -*-
#
# devlib documentation build configuration file, created by
# sphinx-quickstart on Tue Aug 11 17:37:27 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import shlex
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['static/templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'devlib'
copyright = u'2015, ARM Limited'
author = u'ARM Limited'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['../build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'devlibdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'devlib.tex', u'devlib Documentation',
u'ARM Limited', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'devlib', u'devlib Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'devlib', u'devlib Documentation',
author, 'devlib', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

31
doc/index.rst Normal file
View File

@@ -0,0 +1,31 @@
.. devlib documentation master file, created by
sphinx-quickstart on Tue Aug 11 17:37:27 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to devlib documentation
===============================
devlib provides an interface for interacting with remote targets, such as
development boards, mobile devices, etc. It also provides means of collecting
various measurements and traces from such targets.
Contents:
.. toctree::
:maxdepth: 2
overview
target
modules
instrumentation
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

238
doc/instrumentation.rst Normal file
View File

@@ -0,0 +1,238 @@
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()``, and
``get_data()`` 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, [kinds]])
This is used to configure an instrument for collection. This must be invoked
before ``start()`` is called to begin collection. ``sites`` and ``kinds``
parameters may be used to specify which channels measurements should be
collected from (if omitted, then measurements will be collected for all
available sites/kinds). This methods sets the ``active_channels`` attribute
of the ``Instrument``.
.. 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`` measurment.
.. method:: Instrument.start()
Starts collecting measurements from ``active_channels``.
.. note:: This method is only implemented by :class:`Instrument`\ s that
support ``CONTINUOUS`` measurment.
.. 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`` measurment.
.. 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
``<site>_<kind>`` (see :class:`InstrumentChannel`). The order of the coluns
will be the same as the order of channels in ``Instrument.active_channels``.
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`` measurment.
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 volage rail or location of a sensor).
A ``measurement_type`` is an instance of :class:`MeasurmentType` that
describes what sort of measurment this is (power, temperature, etc). Each
mesurement 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 volatage 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 measurments are collected (e.g. voltage
rail, sensor, etc).
.. attribute:: InstrumentChannel.kind
A string indingcating the type of measrument that will be collted. This is
the ``name`` of the :class:`MeasurmentType` associated with this channel.
.. attribute:: InstrumentChannel.units
Units in which measurment will be reported. this is determined by the
underlying :class:`MeasurmentType`.
.. attribute:: InstrumentChannel.label
A label that can be attached to measurments 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 |
+=============+=========+===============+
| time | seconds | |
+-------------+---------+---------------+
| temperature | degrees | |
+-------------+---------+---------------+
| 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

263
doc/make.bat Normal file
View File

@@ -0,0 +1,263 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 2> nul
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\devlib.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\devlib.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

172
doc/modules.rst Normal file
View File

@@ -0,0 +1,172 @@
Modules
=======
Modules add additional functionality to the core :class:`Target` interface.
Usually, it is support for specific subsystems on the target. Modules are
instantiated as attributes of the :class:`Target` instance.
hotplug
-------
Kernel ``hotplug`` subsystem allows offlining ("removing") cores from the
system, and onlining them back int. The ``devlib`` module exposes a simple
interface to this subsystem
.. code:: python
from devlib import LocalLinuxTarget
target = LocalLinuxTarget()
# offline cpus 2 and 3, "removing" them from the system
target.hotplug.offline(2, 3)
# bring CPU 2 back in
target.hotplug.online(2)
# Make sure all cpus are online
target.hotplug.online_all()
cpufreq
-------
``cpufreq`` is the kernel subsystem for managing DVFS (Dynamic Voltage and
Frequency Scaling). It allows controlling frequency ranges and switching
policies (governors). The ``devlib`` module exposes the following interface
.. note:: On ARM big.LITTLE systems, all cores on a cluster (usually all cores
of the same type) are in the same frequency domain, so setting
``cpufreq`` state on one core on a cluter will affect all cores on
that cluster. Because of this, some devices only expose cpufreq sysfs
interface (which is what is used by the ``devlib`` module) on the
first cpu in a cluster. So to keep your scripts proable, always use
the fist (online) CPU in a cluster to set ``cpufreq`` state.
.. method:: target.cpufreq.list_governors(cpu)
List cpufreq governors available for the specified cpu. Returns a list of
strings.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.list_governor_tunables(cpu)
List the tunables for the specified cpu's current governor.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.get_governor(cpu)
Returns the name of the currently set governor for the specified cpu.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.set_governor(cpu, governor, **kwargs)
Sets the governor for the specified cpu.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
:param governor: The name of the governor. This must be one of the governors
supported by the CPU (as retrunted by ``list_governors()``.
Keyword arguments may be used to specify governor tunable values.
.. method:: target.cpufreq.get_governor_tunables(cpu)
Return a dict with the values of the specfied CPU's current governor.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.set_governor_tunables(cpu, **kwargs)
Set the tunables for the current governor on the specified CPU.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
Keyword arguments should be used to specify tunable values.
.. method:: target.cpufreq.list_frequencie(cpu)
List DVFS frequencies supported by the specified CPU. Returns a list of ints.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.get_min_frequency(cpu)
target.cpufreq.get_max_frequency(cpu)
target.cpufreq.set_min_frequency(cpu, frequency[, exact=True])
target.cpufreq.set_max_frequency(cpu, frequency[, exact=True])
Get and set min and max frequencies on the specfied CPU. "set" functions are
avialable with all governors other than ``userspace``.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
:param frequency: Frequency to set.
.. method:: target.cpufreq.get_frequency(cpu)
target.cpufreq.set_frequency(cpu, frequency[, exact=True])
Get and set current frequency on the specified CPU. ``set_frequency`` is only
available if the current governor is ``userspace``.
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
:param frequency: Frequency to set.
cpuidle
-------
``cpufreq`` is the kernel subsystem for managing CPU low power (idle) states.
.. method:: taget.cpuidle.get_driver()
Return the name current cpuidle driver.
.. method:: taget.cpuidle.get_governor()
Return the name current cpuidle governor (policy).
.. method:: target.cpuidle.get_states([cpu=0])
Return idle states (optionally, for the specified CPU). Returns a list of
:class:`CpuidleState` instances.
.. method:: target.cpuidle.get_state(state[, cpu=0])
Return :class:`CpuidleState` instance (optionally, for the specified CPU)
representing the specified idle state. ``state`` can be either an integer
index of the state or a string with the states ``name`` or ``desc``.
.. method:: target.cpuidle.enable(state[, cpu=0])
target.cpuidle.disable(state[, cpu=0])
target.cpuidle.enable_all([cpu=0])
target.cpuidle.disable_all([cpu=0])
Enable or disable the specified or all states (optionally on the specified
CPU.
You can also call ``enable()`` or ``disable()`` on :class:`CpuidleState` objects
returned by get_state(s).
cgroups
-------
TODO
hwmon
-----
TODO
API
---
TODO

282
doc/overview.rst Normal file
View File

@@ -0,0 +1,282 @@
Overview
========
A :class:`Target` instance serves as the main interface to the target device.
There currently three target interfaces:
- :class:`LinuxTarget` for interacting with Linux devices over SSH.
- :class:`AndroidTraget` for interacting with Android devices over adb.
- :class:`LocalLinuxTarget`: for interacting with the local Linux host.
They all work in more-or-less the same way, with the major difference being in
how connection settings are specified; though there may also be a few APIs
specific to a particular target type (e.g. :class:`AndroidTarget` exposes
methods for working with logcat).
Acquiring a Target
------------------
To create an interface to your device, you just need to instantiate one of the
:class:`Target` derivatives listed above, and pass it the right
``connection_settings``. Code snippet below gives a typical example of
instantiating each of the three target types.
.. code:: python
from devlib import LocalLinuxTarget, LinuxTarget, AndroidTarget
# Local machine requires no special connection settings.
t1 = LocalLinuxTarget()
# For a Linux device, you will need to provide the normal SSH credentials.
# Both password-based, and key-based authentication is supported (password
# authentication requires sshpass to be installed on your host machine).'
t2 = LinuxTarget(connetion_settings={'host': '192.168.0.5',
'username': 'root',
'password': 'sekrit',
# or
'keyfile': '/home/me/.ssh/id_rsa'})
# For an Android target, you will need to pass the device name as reported
# by "adb devices". If there is only one device visible to adb, you can omit
# this setting and instantiate similar to a local target.
t3 = AndroidTarget(connection_settings={'device': '0123456789abcde'})
Instantiating a target may take a second or two as the remote device will be
queried to initialize :class:`Target`'s internal state. If you would like to
create a :class:`Target` instance but not immediately connect to the remote
device, you can pass ``connect=False`` parameter. If you do that, you would have
to then explicitly call ``t.connect()`` before you can interact with the device.
There are a few additional parameters you can pass in instantiation besides
``connection_settings``, but they are usually unnecessary. Please see
:class:`Target` API documentation for more details.
Target Interface
----------------
This is a quick overview of the basic interface to the device. See
:class:`Targeet` API documentation for the full list of supported methods and
more detailed documentation.
One-time Setup
~~~~~~~~~~~~~~
.. code:: python
from devlib import LocalLinuxTarget
t = LocalLinuxTarget()
t.setup()
This sets up the target for ``devlib`` interaction. This includes creating
working directories, deploying busybox, etc. It's usually enough to do this once
for a new device, as the changes this makes will persist across reboots.
However, there is no issue with calling this multiple times, so, to be on the
safe site, it's a good idea to call this once at the beginning of your scripts.
Command Execution
~~~~~~~~~~~~~~~~~
There are several ways to execute a command on the target. In each case, a
:class:`TargetError` will be raised if something goes wrong. In very case, it is
also possible to specify ``as_root=True`` if the specified command should be
executed as root.
.. code:: python
from devlib import LocalLinuxTarget
t = LocalLinuxTarget()
# Execute a command
output = t.execute('echo $PWD')
# Execute command via a subprocess and return the corresponding Popen object.
# This will block current connection to the device until the command
# completes.
p = t.background('echo $PWD')
output, error = p.communicate()
# Run the command in the background on the device and return immediately.
# This will not block the connection, allowing to immediately execute another
# command.
t.kick_off('echo $PWD')
# This is used to invoke an executable binary on the device. This allows some
# finer-grained control over the invocation, such as specifying the directory
# in which the executable will run; however you're limited to a single binary
# and cannot construct complex commands (e.g. this does not allow chaining or
# piping several commands together).
output = t.invoke('echo', args=['$PWD'], in_directory='/')
File Transfer
~~~~~~~~~~~~~
.. code:: python
from devlib import LocalLinuxTarget
t = LocalLinuxTarget()
# "push" a file from the local machine onto the target device.
t.push('/path/to/local/file.txt', '/path/to/target/file.txt')
# "pull" a file from the target device into a location on the local machine
t.pull('/path/to/target/file.txt', '/path/to/local/file.txt')
# Install the specified binary on the target. This will deploy the file and
# ensure it's executable. This will *not* guarantee that the binary will be
# in PATH. Instead the path to the binary will be returned; this should be
# used to call the binary henceforth.
target_bin = t.install('/path/to/local/bin.exe')
# Example invocation:
output = t.execute('{} --some-option'.format(target_bin))
The usual access permission constraints on the user account (both on the target
and the host) apply.
Process Control
~~~~~~~~~~~~~~~
.. code:: python
import signal
from devlib import LocalLinuxTarget
t = LocalLinuxTarget()
# return PIDs of all running instances of a process
pids = t.get_pids_of('sshd')
# kill a running process. This works the same ways as the kill command, so
# SIGTERM will be used by default.
t.kill(666, signal=signal.SIGKILL)
# kill all running instances of a process.
t.killall('badexe', signal=signal.SIGKILL)
# List processes running on the target. This retruns a list of parsed
# PsEntry records.
entries = t.ps()
# e.g. print virtual memory sizes of all running sshd processes:
print ', '.join(str(e.vsize) for e in entries if e.name == 'sshd')
More...
~~~~~~~
As mentioned previously, the above is not intended to be exhaustive
documentation of the :class:`Target` interface. Please refer to the API
documentation for the full list of attributes and methods and their parameters.
Super User Privileges
---------------------
It is not necessary for the account logged in on the target to have super user
privileges, however the functionality will obviously be diminished, if that is
not the case. ``devilib`` will determine if the logged in user has root
privileges and the correct way to invoke it. You should avoid including "sudo"
directly in your commands, instead, specify ``as_root=True`` where needed. This
will make your scripts portable across multiple devices and OS's.
On-Target Locations
-------------------
File system layouts vary wildly between devices and operating systems.
Hard-coding absolute paths in your scripts will mean there is a good chance they
will break if run on a different device. To help with this, ``devlib`` defines
a couple of "standard" locations and a means of working with them.
working_directory
This is a directory on the target readable and writable by the account
used to log in. This should generally be used for all output generated
by your script on the device and as the destination for all
host-to-target file transfers. It may or may not permit execution so
executables should not be run directly from here.
executables_directory
This directory allows execution. This will be used by ``install()``.
.. code:: python
from devlib import LocalLinuxTarget
t = LocalLinuxTarget()
# t.path is equivalent to Python standard library's os.path, and should be
# used in the same way. This insures that your scripts are portable across
# both target and host OS variations. e.g.
on_target_path = t.path.join(t.working_directory, 'assets.tar.gz')
t.push('/local/path/to/assets.tar.gz', on_target_path)
# Since working_directory is a common base path for on-target locations,
# there a short-hand for the above:
t.push('/local/path/to/assets.tar.gz', t.get_workpath('assets.tar.gz'))
Modules
-------
Additional functionality is exposed via modules. Modules are initialized as
attributes of a target instance. By default, ``hotplug``, ``cpufreq``,
``cpuidle``, ``cgroups`` and ``hwmon`` will attempt to load on target; additional
modules may be specified when creating a :class:`Target` instance.
A module will probe the target for support before attempting to load. So if the
underlying platform does not support particular functionality (e.g. the kernel
on target device was built without hotplug support). To check whether a module
has been successfully installed on a target, you can use ``has()`` method, e.g.
.. code:: python
from devlib import LocalLinuxTarget
t = LocalLinuxTarget()
cpu0_freqs = []
if t.has('cpufreq'):
cpu0_freqs = t.cpufreq.list_frequencies(0)
Please see the modules documentation for more detail.
Measurement and Trace
---------------------
You can collected traces (currently, just ftrace) using
:class:`TraceCollector`\ s. For example
.. code:: python
from devlib import AndroidTarget, FtraceCollector
t = LocalLinuxTarget()
# Initialize a collector specifying the events you want to collect and
# the buffer size to be used.
trace = FtraceCollector(t, events=['power*'], buffer_size=40000)
# clear ftrace buffer
trace.reset()
# start trace collection
trace.start()
# Perform the operations you want to trace here...
import time; time.sleep(5)
# stop trace collection
trace.stop()
# extract the trace file from the target into a local file
trace.get_trace('/tmp/trace.bin')
# View trace file using Kernelshark (must be installed on the host).
trace.view('/tmp/trace.bin')
# Convert binary trace into text format. This would normally be done
# automatically during get_trace(), unless autoreport is set to False during
# instantiation of the trace collector.
trace.report('/tmp/trace.bin', '/tmp/trace.txt')
In a similar way, :class:`Instrument` instances may be used to collect
measurements (such as power) from targets that support it. Please see
instruments documentation for more details.

422
doc/target.rst Normal file
View File

@@ -0,0 +1,422 @@
Target
======
.. class:: Target(connection_settings=None, platform=None, working_directory=None, executables_directory=None, connect=True, modules=None, load_default_modules=True, shell_prompt=DEFAULT_SHELL_PROMPT)
:class:`Target` is the primary interface to the remote device. All interactions
with the device are performed via a :class:`Target` instance, either
directly, or via its modules or a wrapper interface (such as an
:class:`Instrument`).
:param connection_settings: A ``dict`` that specifies how to connect to the remote
device. Its contents depend on the specific :class:`Target` type used (e.g.
:class:`AndroidTarget` expects the adb ``device`` name).
:param platform: A :class:`Target` defines interactions at Operating System level. A
:class:`Platform` describes the underlying hardware (such as CPUs
available). If a :class:`Platform` instance is not specified on
:class:`Target` creation, one will be created automatically and it will
dynamically probe the device to discover as much about the underlying
hardware as it can.
:param working_directory: This is primary location for on-target file system
interactions performed by ``devlib``. This location *must* be readable and
writable directly (i.e. without sudo) by the connection's user account.
It may or may not allow execution. This location will be created,
if necessary, during ``setup()``.
If not explicitly specified, this will be set to a default value
depending on the type of :class:`Target`
:param executables_directory: This is the location to which ``devlib`` will
install executable binaries (either during ``setup()`` or via an
explicit ``install()`` call). This location *must* support execution
(obviously). It should also be possible to write to this location,
possibly with elevated privileges (i.e. on a rooted Linux target, it
should be possible to write here with sudo, but not necessarily directly
by the connection's account). This location will be created,
if necessary, during ``setup()``.
This location does *not* to be same as the system's executables
location. In fact, to prevent devlib from overwriting system's defaults,
it better if this is a separate location, if possible.
If not explicitly specified, this will be set to a default value
depending on the type of :class:`Target`
:param connect: Specifies whether a connections should be established to the
target. If this is set to ``False``, then ``connect()`` must be
explicitly called later on before the :class:`Target` instance can be
used.
:param modules: a list of additional modules to be installed. Some modules will
try to install by default (if supported by the underlying target).
Current default modules are ``hotplug``, ``cpufreq``, ``cpuidle``,
``cgroups``, and ``hwmon``.
See modules documentation for more detail.
:param load_default_modules: If set to ``False``, default modules listed
above will *not* attempt to load. This may be used to either speed up
target instantiation (probing for initializing modules takes a bit of time)
or if there is an issue with one of the modules on a particular device
(the rest of the modules will then have to be explicitly specified in
the ``modules``).
:param shell_prompt: This is a regular expression that matches the shell
prompted on the target. This may be used by some modules that establish
auxiliary connections to a target over UART.
.. attribute:: Target.core_names
This is a list containing names of CPU cores on the target, in the order in
which they are index by the kernel. This is obtained via the underlying
:class:`Platform`.
.. attribute:: Target.core_clusters
Some devices feature heterogeneous core configurations (such as ARM
big.LITTLE). This is a list that maps CPUs onto underlying clusters.
(Usually, but not always, clusters correspond to groups of CPUs with the same
name). This is obtained via the underlying :class:`Platform`.
.. attribute:: Target.big_core
This is the name of the cores that the "big"s in an ARM big.LITTLE
configuration. This is obtained via the underlying :class:`Platform`.
.. attribute:: Target.little_core
This is the name of the cores that the "little"s in an ARM big.LITTLE
configuration. This is obtained via the underlying :class:`Platform`.
.. attribute:: Target.is_connected
A boolean value that indicates whether an active connection exists to the
target device.
.. attribute:: Target.connected_as_root
A boolean value that indicate whether the account that was used to connect to
the target device is "root" (uid=0).
.. attribute:: Target.is_rooted
A boolean value that indicates whether the connected user has super user
privileges on the devices (either is root, or is a sudoer).
.. attribute:: Target.kernel_version
The version of the kernel on the target device. This returns a
:class:`KernelVersion` instance that has separate ``version`` and ``release``
fields.
.. attribute:: Target.os_version
This is a dict that contains a mapping of OS version elements to their
values. This mapping is OS-specific.
.. attribute:: Target.cpuinfo
This is a :class:`Cpuinfo` instance which contains parsed contents of
``/proc/cpuinfo``.
.. attribute:: Target.number_of_cpus
The total number of CPU cores on the target device.
.. attribute:: Target.config
A :class:`KernelConfig` instance that contains parsed kernel config from the
target device. This may be ``None`` if kernel config could not be extracted.
.. attribute:: Target.user
The name of the user logged in on the target device.
.. attribute:: Target.conn
The underlying connection object. This will be ``None`` if an active
connection does not exist (e.g. if ``connect=False`` as passed on
initialization and ``connect()`` has not been called).
.. note:: a :class:`Target` will automatically create a connection per
thread. This will always be set to the connection for the current
thread.
.. method:: Target.connect([timeout])
Establish a connection to the target. It is usually not necessary to call
this explicitly, as a connection gets automatically established on
instantiation.
.. method:: Target.disconnect()
Disconnect from target, closing all active connections to it.
.. method:: Target.get_connection([timeout])
Get an additional connection to the target. A connection can be used to
execute one blocking command at time. This will return a connection that can
be used to interact with a target in parallel while a blocking operation is
being executed.
This should *not* be used to establish an initial connection; use
``connect()`` instead.
.. note:: :class:`Target` will automatically create a connection per
thread, so you don't normally need to use this explicitly in
threaded code. This is generally useful if you want to perform a
blocking operation (e.g. using ``background()``) while at the same
time doing something else in the same host-side thread.
.. method:: Target.setup([executables])
This will perform an initial one-time set up of a device for devlib
interaction. This involves deployment of tools relied on the :class:`Target`,
creation of working locations on the device, etc.
Usually, it is enough to call this method once per new device, as its effects
will persist across reboots. However, it is safe to call this method multiple
times. It may therefore be a good practice to always call it once at the
beginning of a script to ensure that subsequent interactions will succeed.
Optionally, this may also be used to deploy additional tools to the device
by specifying a list of binaries to install in the ``executables`` parameter.
.. method:: Target.reboot([hard [, connect, [timeout]]])
Reboot the target device.
:param hard: A boolean value. If ``True`` a hard reset will be used instead
of the usual soft reset. Hard reset must be supported (usually via a
module) for this to work. Defaults to ``False``.
:param connect: A boolean value. If ``True``, a connection will be
automatically established to the target after reboot. Defaults to
``True``.
:param timeout: If set, this will be used by various (platform-specific)
operations during reboot process to detect if the reboot has failed and
the device has hung.
.. method:: Target.push(source, dest [, timeout])
Transfer a file from the host machine to the target device.
:param source: path of to the file on the host
:param dest: path of to the file on the target
:param timeout: timeout (in seconds) for the transfer; if the transfer does
not complete within this period, an exception will be raised.
.. method:: Target.pull(source, dest [, timeout])
Transfer a file from the target device to the host machine.
:param source: path of to the file on the target
:param dest: path of to the file on the host
:param timeout: timeout (in seconds) for the transfer; if the transfer does
not complete within this period, an exception will be raised.
.. method:: Target.execute(command [, timeout [, check_exit_code [, as_root]]])
Execute the specified command on the target device and return its output.
:param command: The command to be executed.
:param timeout: Timeout (in seconds) for the execution of the command. If
specified, an exception will be raised if execution does not complete
with the specified period.
:param check_exit_code: If ``True`` (the default) the exit code (on target)
from execution of the command will be checked, and an exception will be
raised if it is not ``0``.
:param as_root: The command will be executed as root. This will fail on
unrooted targets.
.. method:: Target.background(command [, stdout [, stderr [, as_root]]])
Execute the command on the target, invoking it via subprocess on the host.
This will return :class:`subprocess.Popen` instance for the command.
:param command: The command to be executed.
:param stdout: By default, standard output will be piped from the subprocess;
this may be used to redirect it to an alternative file handle.
:param stderr: By default, standard error will be piped from the subprocess;
this may be used to redirect it to an alternative file handle.
:param as_root: The command will be executed as root. This will fail on
unrooted targets.
.. note:: This **will block the connection** until the command completes.
.. method:: Target.invoke(binary [, args [, in_directory [, on_cpus [, as_root [, timeout]]]]])
Execute the specified binary on target (must already be installed) under the
specified conditions and return the output.
:param binary: binary to execute. Must be present and executable on the device.
:param args: arguments to be passed to the binary. The can be either a list or
a string.
:param in_directory: execute the binary in the specified directory. This must
be an absolute path.
:param on_cpus: taskset the binary to these CPUs. This may be a single ``int`` (in which
case, it will be interpreted as the mask), a list of ``ints``, in which
case this will be interpreted as the list of cpus, or string, which
will be interpreted as a comma-separated list of cpu ranges, e.g.
``"0,4-7"``.
:param as_root: Specify whether the command should be run as root
:param timeout: If this is specified and invocation does not terminate within this number
of seconds, an exception will be raised.
.. method:: Target.kick_off(command [, as_root])
Kick off the specified command on the target and return immediately. Unlike
``background()`` this will not block the connection; on the other hand, there
is not way to know when the command finishes (apart from calling ``ps()``)
or to get its output (unless its redirected into a file that can be pulled
later as part of the command).
:param command: The command to be executed.
:param as_root: The command will be executed as root. This will fail on
unrooted targets.
.. method:: Target.read_value(path [,kind])
Read the value from the specified path. This is primarily intended for
sysfs/procfs/debugfs etc.
:param path: file to read
:param kind: Optionally, read value will be converted into the specified
kind (which should be a callable that takes exactly one parameter).
.. method:: Target.read_int(self, path)
Equivalent to ``Target.read_value(path, kind=devlab.utils.types.integer)``
.. method:: Target.read_bool(self, path)
Equivalent to ``Target.read_value(path, kind=devlab.utils.types.boolean)``
.. method:: Target.write_value(path, value [, verify])
Write the value to the specified path on the target. This is primarily
intended for sysfs/procfs/debugfs etc.
:param path: file to write into
:param value: value to be written
:param verify: If ``True`` (the default) the value will be read back after
it is written to make sure it has been written successfully. This due to
some sysfs entries silently failing to set the written value without
returning an error code.
.. method:: Target.reset()
Soft reset the target. Typically, this means executing ``reboot`` on the
target.
.. method:: Target.check_responsive()
Returns ``True`` if the target appears to be responsive and ``False``
otherwise.
.. method:: Target.kill(pid[, signal[, as_root]])
Kill a process on the target.
:param pid: PID of the process to be killed.
:param signal: Signal to be used to kill the process. Defaults to
``signal.SIGTERM``.
:param as_root: If set to ``True``, kill will be issued as root. This will
fail on unrooted targets.
.. method:: Target.killall(name[, signal[, as_root]])
Kill all processes with the specified name on the target. Other parameters
are the same as for ``kill()``.
.. method:: Target.get_pids_of(name)
Return a list of PIDs of all running instances of the specified process.
.. method:: Target.ps()
Return a list of :class:`PsEntry` instances for all running processes on the
system.
.. method:: Target.file_exists(self, filepath)
Returns ``True`` if the specified path exists on the target and ``False``
otherwise.
.. method:: Target.list_file_systems()
Lists file systems mounted on the target. Returns a list of
:class:`FstabEntry`\ s.
.. method:: Target.list_directory(path[, as_root])
List (optionally, as root) the contents of the specified directory. Returns a
list of strings.
.. method:: Target.get_workpath(self, path)
Convert the specified path to an absolute path relative to
``working_directory`` on the target. This is a shortcut for
``t.path.join(t.working_directory, path)``
.. method:: Target.tempfile([prefix [, suffix]])
Get a path to a temporary file (optionally, with the specified prefix and/or
suffix) on the target.
.. method:: Target.remove(path[, as_root])
Delete the specified path on the target. Will work on files and directories.
.. method:: Target.core_cpus(core)
Return a list of numeric cpu IDs corresponding to the specified core name.
.. method:: Target.list_online_cpus([core])
Return a list of numeric cpu IDs for all online CPUs (optionally, only for
CPUs corresponding to the specified core).
.. method:: Target.list_offline_cpus([core])
Return a list of numeric cpu IDs for all offline CPUs (optionally, only for
CPUs corresponding to the specified core).
.. method:: Target.getenv(variable)
Return the value of the specified environment variable on the device
.. method:: Target.capture_screen(filepath)
Take a screenshot on the device and save it to the specified file on the
host. This may not be supported by the target.
.. method:: Target.install(filepath[, timeout[, with_name]])
Install an executable on the device.
:param filepath: path to the executable on the host
:param timeout: Optional timeout (in seconds) for the installation
:param with_name: This may be used to rename the executable on the target
.. method:: Target.uninstall(name)
Uninstall the specified executable from the target
.. method:: Target.get_installed(name)
Return the full installation path on the target for the specified executable,
or ``None`` if the executable is not installed.
.. method:: Target.which(name)
Alias for ``get_installed()``
.. method:: Target.is_installed(name)
Returns ``True`` if an executable with the specified name is installed on the
target and ``False`` other wise.