mirror of
https://github.com/ARM-software/devlib.git
synced 2025-10-30 05:23:20 +00:00
doc: documenting Platforms and Modules
Adding documentation for Platforms and Modules API.
This commit is contained in:
196
doc/modules.rst
196
doc/modules.rst
@@ -1,3 +1,5 @@
|
||||
.. _modules:
|
||||
|
||||
Modules
|
||||
=======
|
||||
|
||||
@@ -64,7 +66,7 @@ policies (governors). The ``devlib`` module exposes the following interface
|
||||
: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)
|
||||
.. method:: target.cpufreq.set_governor(cpu, governor, \*\*kwargs)
|
||||
|
||||
Sets the governor for the specified cpu.
|
||||
|
||||
@@ -83,7 +85,7 @@ policies (governors). The ``devlib`` module exposes the following interface
|
||||
: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)
|
||||
.. method:: target.cpufreq.set_governor_tunables(cpu, \*\*kwargs)
|
||||
|
||||
Set the tunables for the current governor on the specified CPU.
|
||||
|
||||
@@ -169,4 +171,192 @@ TODO
|
||||
API
|
||||
---
|
||||
|
||||
TODO
|
||||
Generic Module API Description
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Modules implement discrete, optional pieces of functionality ("optional" in the
|
||||
sense that the functionality may or may not be present on the target device, or
|
||||
that it may or may not be necessary for a particular application).
|
||||
|
||||
Every module (ultimately) derives from :class:`Module` class. A module must
|
||||
define the following class attributes:
|
||||
|
||||
:name: A unique name for the module. This cannot clash with any of the existing
|
||||
names and must be a valid Python identifier, but is otherwise free-from.
|
||||
:kind: This identifies the type of functionality a module implements, which in
|
||||
turn determines the interface implemented by the module (all modules of
|
||||
the same kind must expose a consistent interface). This must be a valid
|
||||
Python identifier, but is otherwise free-form, though, where possible,
|
||||
one should try to stick to an already-defined kind/interface, lest we end
|
||||
up with a bunch of modules implementing similar functionality but
|
||||
exposing slightly different interfaces.
|
||||
|
||||
.. note:: It is possible to omit ``kind`` when defining a module, in
|
||||
which case the module's ``name`` will be treated as its
|
||||
``kind`` as well.
|
||||
|
||||
:stage: This defines when the module will be installed into a :class:`Target`.
|
||||
Currently, the following values are allowed:
|
||||
|
||||
:connected: The module is installed after a connection to the target has
|
||||
been established. This is the default.
|
||||
:early: The module will be installed when a :class:`Target` is first
|
||||
created. This should be used for modules that do not rely on a
|
||||
live connection to the target.
|
||||
|
||||
Additionally, a module must implement a static (or class) method :func:`probe`:
|
||||
|
||||
.. method:: Module.probe(target)
|
||||
|
||||
This method takes a :class:`Target` instance and returns ``True`` if this
|
||||
module is supported by that target, or ``False`` otherwise.
|
||||
|
||||
.. note:: If the moudule ``stage`` is ``"early"``, this method cannot assume
|
||||
that a connection has been established (i.e. it can only access
|
||||
attrubutes of the Target that do not rely on a connection).
|
||||
|
||||
Installation and invocation
|
||||
***************************
|
||||
|
||||
The default installation method will create an instance of a module (the
|
||||
:class:`Target` instance being the sole argument) and assign it to the target
|
||||
instance attribute named after the module's ``kind`` (or ``name`` if ``kind`` is
|
||||
``None``).
|
||||
|
||||
It is possible to change the installation procedure for a module by overriding
|
||||
the default :func:`install` method. The method must have the following
|
||||
signature:
|
||||
|
||||
.. method:: Module.install(cls, target, **kwargs)
|
||||
|
||||
Install the module into the target instance.
|
||||
|
||||
|
||||
Implementation and Usage Patterns
|
||||
*********************************
|
||||
|
||||
There are two common ways to implement the above API, corresponding to the two
|
||||
common uses for modules:
|
||||
|
||||
- If a module provides an interface to a particular set of functionality (e.g.
|
||||
an OS subsystem), that module would typically derive directly form
|
||||
:class:`Module` and would leave ``kind`` unassigned, so that it is accessed
|
||||
by it name. Its instance's methods and attributes provide the interface for
|
||||
interacting with its functionality. For examples of this type of module, see
|
||||
the subsystem modules listed above (e.g. ``cpufreq``).
|
||||
- If a module provides a platform- or infrastructure-specific implementation of
|
||||
a common function, the module would derive from one of :class:`Module`
|
||||
subclasses that define the interface for that function. In that case the
|
||||
module would be accessible via the common ``kind`` defined its super. The
|
||||
module would typically implement :func:`__call__` and be invoked directly. For
|
||||
examples of this type of module, see common function interface definitions
|
||||
below.
|
||||
|
||||
|
||||
Common Function Interfaces
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This section documents :class:`Module` classes defining interface for common
|
||||
functions. Classes derived from them provide concrete implementations for
|
||||
specific platforms.
|
||||
|
||||
|
||||
HardResetModule
|
||||
***************
|
||||
|
||||
.. attribute:: HardResetModule.kind
|
||||
|
||||
"hard_reset"
|
||||
|
||||
.. method:: HardResetModule.__call__()
|
||||
|
||||
Must be implemented by derived classes.
|
||||
|
||||
Implements hard reset for a target devices. The equivalent of physically
|
||||
power cycling the device. This may be used by client code in situatians
|
||||
where the target becomes unresponsive and/or a regular reboot is not
|
||||
possible.
|
||||
|
||||
|
||||
BootModule
|
||||
**********
|
||||
|
||||
.. attribute:: BootModule.kind
|
||||
|
||||
"hard_reset"
|
||||
|
||||
.. method:: BootModule.__call__()
|
||||
|
||||
Must be implemented by derived classes.
|
||||
|
||||
Implements a boot proceedure. This takes the device from (hard or soft)
|
||||
reset to a booted state where the device is ready to accept connections. For
|
||||
a lot of commercial devices the process is entirely automatic, however some
|
||||
devices (e.g. development boards), my require additional steps, such as
|
||||
interactions with the bootloader, in order to boot into the OS.
|
||||
|
||||
.. method:: Bootmodule.update(\*\*kwargs)
|
||||
|
||||
Update the boot settings. Some boot sequencies allow specifying settings
|
||||
that will be utilized during boot (e.g. linux kernel boot command line). The
|
||||
default implmentation will set each setting in ``kwargs`` as an attribute of
|
||||
the boot module (or update the existing attribute).
|
||||
|
||||
|
||||
FlashModule
|
||||
***********
|
||||
|
||||
.. attribute:: FlashModule.kind
|
||||
|
||||
"flash"
|
||||
|
||||
.. method:: __call__(image_bundle=None, images=None, boot_config=None)
|
||||
|
||||
Must be implemented by derived classes.
|
||||
|
||||
Flash the target platform with the specified images.
|
||||
|
||||
:param image_bundle: A compressed bundle of image files with any associated
|
||||
metadata. The format of the bundle is specific to a
|
||||
particular implmentation.
|
||||
:param images: A dict mapping image names/identifiers to the path on the
|
||||
host file system of the corresponding image file. If both
|
||||
this and ``image_bundle`` are specified, individual images
|
||||
will override those in the bundle.
|
||||
:param boot_config: Some platforms require specifying boot arguments at the
|
||||
time of flashing the images, rather than during each
|
||||
reboot. For other platforms, this will be ignored.
|
||||
|
||||
|
||||
Module Registration
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Modules are specified on :class:`Target` or :class:`Platform` creation by name.
|
||||
In order to find the class associated with the name, the module needs to be
|
||||
registered with ``devlib``. This is accomplished by passing the module class
|
||||
into :func:`register_module` method once it is defined.
|
||||
|
||||
.. note:: If you're wiring a module to be included as part of ``devlib`` code
|
||||
base, you can place the file with the module class under
|
||||
``devlib/modules/`` in the source and it will be automatically
|
||||
enumarated. There is no need to explicitly register it in that case.
|
||||
|
||||
The code snippet below illustrates an implementation of a hard reset function
|
||||
for an "Acme" device.
|
||||
|
||||
.. code:: python
|
||||
|
||||
import os
|
||||
from devlib import HardResetModule, register_module
|
||||
|
||||
|
||||
class AcmeHardReset(HardResetModule):
|
||||
|
||||
name = 'acme_hard_reset'
|
||||
|
||||
def __call__(self):
|
||||
# Assuming Acme board comes with a "reset-acme-board" utility
|
||||
os.system('reset-acme-board {}'.format(self.target.name))
|
||||
|
||||
register_module(AcmeHardReset)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user