| Device-Aware API and Board |
| ========================== |
| |
| If you need to implement test behavior for device (DUT or station) in a |
| board-specific way, use or extend |
| :py:class:`cros.factory.device.board.DeviceBoard`. This class provides |
| board-specific functionality, e.g.: |
| |
| - forcing device charge state |
| - observing on-board sensors such as temperature sensors |
| - querying the EC (embedded controller) |
| - directly reading/writing values over the I2C bus |
| |
| Obtaining a Board object |
| ------------------------ |
| To obtain a :py:class:`cros.factory.device.board.DeviceBoard` object for the |
| device under test, use the following function: |
| |
| .. py:module:: cros.factory.device.device_utils |
| |
| .. autofunction:: CreateDUTInterface |
| .. autofunction:: CreateStationInterface |
| |
| .. _board-api-extending: |
| |
| Extending the Board class |
| ------------------------- |
| The base implementation of all boards is |
| :py:class:`cros.factory.device.board.DeviceBoard`. Currently if board_class |
| is not specified, device_utils.CreateDUTInterface() function will return an |
| instance of interface for ChromeOS devices using the subclass |
| :py:class:`cros.factory.device.boards.chromeos.ChromeOSBoard`. However, you may |
| find that you need to customize or override certain functionality for your |
| project. To do so: |
| |
| #. Define a new subclass of |
| :py:class:`cros.factory.device.boards.chromeos.ChromeOSBoard` |
| in the :py:mod:`cros.factory.device.boards` package. In general, |
| for a board named :samp:`{xxx}`, you will add a |
| file :samp:`private-overlays/overlay-{xxx}-private/chromeos-base/chromeos-factory-board/files/py/device/boards/{xxx}.py` |
| containing the following:: |
| |
| import factory_common # pylint: disable=W0611 |
| |
| from cros.factory.device.boards import chromeos |
| from cros.factory.device import component |
| |
| |
| # Implement or import and override the components with difference. |
| class XxxPower(components.DeviceComponent): |
| def DoSomething(self): |
| pass |
| |
| |
| class XxxBoard(chromeos.ChromeOSBoard): |
| # ... implement/override methods here ... |
| |
| @component.DeviceProperty |
| def power(self): |
| return XXXPower(self) |
| |
| |
| Generally, your class should be derived from the |
| :py:class:`cros.factory.device.boards.chromeos.ChromeOSBoard` class, but |
| if your device is not ChromeOS, you may wish to directly subclass |
| :py:class:`cros.factory.device.boards.android.AndroidBoard` or |
| :py:class:`cros.factory.device.board.DeviceBoard`. |
| |
| #. Specify that your implementation should be used. To do this, in |
| :samp:`private-overlays/overlay-{board}-private/chromeos-base/chromeos-factory-board/files/board/board_setup_factory.sh`, |
| write a Python dict expression to specify the board and link to use just like |
| the following:: |
| |
| export CROS_FACTORY_DUT_OPTIONS="{'board_class':'XXXBoard','link_class':'XXXLink'}" |
| |
| board_class refers to the class name under `cros.factory.device.boards`, |
| and link_class refers to the class name under `cros.factory.device.links`. |
| |
| Adding new modules to the Board class |
| ------------------------------------- |
| If you need to perform some system operation in a highly CrOS-specific |
| or board-specific way, you may need to add a new property or method to the |
| :py:class:`cros.factory.device.board.DeviceBoard` class. |
| |
| Let's say that you're working on a cool new CrOS device ("mintyfresh") |
| with a built-in air freshener, and you need to write a test for this |
| game-changing new component. Consider the following questions: |
| |
| - **Is there a mostly standard way of controlling the air freshener |
| across CrOS devices, but that might be different for certain |
| devices?** (For instance, you can call ``ectool airfreshener 1`` to |
| enable the air freshener, but CrOS devices with a non-standard EC |
| may need to implement this differently.) |
| |
| In this case, add an abstract module ``airfreshener.py`` to |
| :py:mod:`cros.factory.device` and include that in |
| :py:class:`cros.factory.device.board.DeviceBoard` as a new DeviceProperty |
| ``airfreshener``. |
| it will work for "standard" devices but can be overridden as necessary. |
| |
| - **Is the functionality totally one-off for your device?** (For instance, |
| you need to control the device via a hard-coded register on the I2C bus.) |
| |
| If so, add an abstract method to |
| :py:class:`cros.factory.device.board.DeviceBoard` and provide the |
| implementation directly in your |
| :py:class:`cros.factory.device.boards.mintyfresh.MintyFreshBoard` class. |
| Don't provide an implementation in |
| :py:class:`cros.factory.device.boards.chromeos.ChromeOSBoard`, since |
| it wouldn't be useful on other boards anyway. |
| |
| - **Is the functionality confidential?** |
| |
| If so, simply implement your functionality in |
| :py:class:`cros.factory.device.boards.mintyfresh.MintyFreshBoard`. |
| Once the device is launched, add a method to |
| :py:class:`cros.factory.device.board.DeviceBoard` and move your |
| implementation to |
| :py:class:`cros.factory.device.boards.chromeos.ChromeOSBoard` so it |
| can be re-used for future devices. |
| |
| |
| API Documentation |
| ----------------- |
| |
| .. py:module:: cros.factory.device.board |
| |
| .. autoclass:: DeviceBoard |
| :members: |
| |
| .. py:module:: cros.factory.device.link |
| |
| .. autoclass:: DeviceLink |
| :members: |