[Tinyos Core WG] Meeting: October 11

Philip Levis pal at cs.stanford.edu
Tue Oct 10 12:06:14 PDT 2006


Wednesday, October 11, 2006 9:30 AM US Pacific Time  W
Bridge: 3, Passcode: 3003712

Numbers:
US: 1-916-356-2663 or 1-888-875-9370 (non-Intel)
UK: +44 1793 402663
Denmark: +45 4527 5090

Agenda:
   Resource management results from NSDI submission
   Release plans
   TEP 109 and 101 wrap-up (newest versions attached)
   TEP 1 (attached)

-------------- next part --------------
===================================
Analog-to-Digital Converters (ADCs)
===================================

:TEP: 101
:Group: Core Working Group 
:Type: Documentary
:Status: Draft
:TinyOS-Version: 2.x
:Author: Jan-Hinrich Hauer, Philip Levis, Vlado Handziski, David Gay

:Draft-Created: 20-Dec-2004
:Draft-Version: $Revision: 1.1.2.8 $
:Draft-Modified: $Date: 2006/10/09 11:05:59 $
:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>

.. Note::

   This memo documents a part of TinyOS for the TinyOS Community, and
   requests discussion and suggestions for improvements.  Distribution
   of this memo is unlimited. This memo is in full compliance with
   [TEP1]_.


Abstract
====================================================================

This TEP proposes a hardware abstraction for analog-to-digital converters (ADCs)
in TinyOS 2.x, which is aligned to the three-layer Hardware Abstraction
Architecture (HAA) specified in [TEP2]. It describes some design principles and
documents the set of hardware-independent interfaces to an ADC.

1. Introduction
====================================================================

Analog-to-digital converters (ADCs) are devices that convert analog input
signals to discrete digital output signals, typically voltage to a binary
number.  The interested reader can refer to Appendix A for a brief overview of
the ADC hardware on some current TinyOS platforms.  In earlier versions of
TinyOS, the distinction between a sensor and an ADC were blurred: this led
components that had nothing to do with an ADC to still resemble one
programatically, even though the semantics and forms of operation were
completely different.  To compensate for the difference non-ADC sensors
introduced additional interfaces, such as ``ADCError``, that were tightly bound
to sensor acquisition but separate in wiring. The separation between the ADC and
``ADCError`` interface is bug prone and problematic, as is the equation of a
sensor and an ADC. TinyOS 2.x separates the structure and interfaces of an ADC
from those of sensors (which may be on top of an ADC, but this fact is hidden
from higher level components). This TEP presents how TinyOS 2.x structures ADC
software. TEP 109 (Sensor Boards) shows how a platform can present actual named
sensors [TEP109]_. 

As can be seen in Appendix A the ADC hardware used on TinyOS platforms differ in
many respects, which makes it difficult to find a chip independent
representation for an ADC. Even if there were such a representation, the
configuration details of an ADC would still depend on the actual device
producing the input signal (sensor).  Neither a platform independent application
nor the ADC hardware stack itself has access to this information, as it can only
be determined on a platform or sensorboard level. For example, determining which
ADC port a sensor is attached to and how a conversion result is to be
interpreted is a platform-specific determination. However, in a similar way as
the message buffer abstraction ``message_t`` is declared per link layer (see
[TEP111]_), an ADC configuration abstraction can be declared per ADC chip and
still be passed between components using standard TinyOS interfaces. This TEP
proposes the ``AdcConfigure`` interface as the standard interface for
configuring an ADC in TinyOS 2.x. It describes how an ADC configuration
structure is declared per ADC chip and that a **platform** is responsible to
define the configuration for every sensor attached to the ADC.

In spite of their hardware differences, one aspect represents a common
denominator of all ADCs: they produce conversion results. To facilitate sensor
software development conversion results are returned by the ADC hardware stack
using the standard TinyOS interfaces ``Read``, ``ReadNow`` and ``ReadStream``
(see `2. Interfaces`_ and [TEP114]_). Conversion results are returned as
uninterpreted values and translating them to engineering units can only be done
with the configuration knowledge of the respective platform, for example, the
reference voltage or the resistance of a reference resistor in ratiometric
measurements.  Translating uninterpreted values to engineering units is
performed by components located on top of the ADC hardware stack and out of the
scope of this TEP.

The top layer of abstraction of an ADC - the Hardware Interface Layer (HIL) -
thus provides the standard TinyOS interfaces ``Read``, ``ReadNow`` and
``ReadStream`` and uses the ``AdcConfigure`` interface for hardware
configuration (why it **uses** and does not **provide** ``AdcConfigure`` is
explained below). 

Following the principles of the HAA [TEP2]_ the Hardware Adaptation Layer (HAL,
which resides below the HIL) of an ADC should expose all the chip-specific
capabilities of the chip.  For example, the ADC12 on the MSP430 MCU supports a
"Repeat-Sequence-of-Channels Mode" and therefore this function should be
accessible on the HAL of the **MSP430 ADC12** hardware abstraction.  Other ADCs
might not exhibit such functionality and might therefore - on the level of HAL -
provide only an interface to perform single conversions. Since all ADCs have the
same HIL representation it may thus be necessary to perform some degree of
software emulation in the HIL implementation.  For example, a ``ReadStream``
command can be emulated by multiple single conversion commands. Below the HAL
resides the Hardware Presentation Layer (HPL), a stateless component that
provides access to the hardware registers (see [TEP2]_). The general structure
(without virtualization) of the ADC hardware stack is as follows ::


        ^                     |
        |                     |
        |                   Read,
   AdcConfigure             ReadNow (+ Resource),
        |                   ReadStream
        |                     |
        |                     V
  +----------------------------------+
  |  Hardware Interface Layer (HIL)  |
  |  (chip-specific implementation)  |
  +----------------------------------+
                   |
                   |
   chip-specific interface(s) + Resource
     (e.g. Msp430Adc12SingleChannel)
                   |
                   V
  +----------------------------------+
  |  Hardware Adaptation Layer (HAL) |
  |  (chip-specific implementation)  |
  +----------------------------------+
                   |
                   |
         chip-specific interface(s)
             (e.g. HplAdc12)
                   |
                   V
  +----------------------------------+
  | Hardware Presentation Layer (HPL)|
  | (chip-specific implementation)   |
  +----------------------------------+


The rest of this TEP specifies:

* the set of standard TinyOS interfaces for collecting ADC conversion
  results and for configuring an ADC (`2. Interfaces`_)
* guidelines on how an ADC's HAL should expose chip-specific 
  interfaces (`3. HAL guidelines`_)
* what components an ADC's HIL MUST implement (`4. HIL requirements`_)
* guidelines on how the HIL should be implemented 
  (`5. HIL guidelines`_)
* a section pointing to current implementations (`6. Implementation`_)

This TEP ends with appendices documenting, as an example, the ADC implementation
for the TI MSP430 MCU.


2. Interfaces
====================================================================

This TEP proposes the ``AdcConfigure`` interface for ADC hardware configuration
and the ``Read``, ``ReadNow`` and ``ReadStream`` interfaces to acquire
conversion results. A ``Read[Now|Stream]`` interface is always provided in
conjunction with an ``AdcConfigure`` interface.

Interface for configuring the ADC hardware
--------------------------------------------------------------------

The ``AdcConfigure`` interface is defined as follows::

  interface AdcConfigure<adc_config_t> 
  {
    async command adc_config_t getConfiguration(); 
  }

This interface is used by the ADC implementation to retrieve the desired
hardware configuration of an ADC client. ``adc_config_t`` is a chip-specific
data type (simple or structured) that contains all information necessary to
configure the respective ADC hardware. For example, on the ADC12 of the MSP430
the ``AdcConfigure`` interface will be instantiated with the
``msp430adc12_channel_config_t`` structure. A client MUST always return the
same configuration through an ``AdcConfigure`` interface. If a client wants to
use the ADC with different configurations it must provide multiple instances of
the ``AdcConfigure`` interface. 


Interfaces for acquiring conversion results
--------------------------------------------------------------------
   
This TEP proposes to adopt the following three generic, source-independent data
collection interfaces from [TEP114]_ for the collection of ADC conversion
results on the level of HIL::

  interface Read< size_type >
  interface ReadNow< size_type >
  interface ReadStream< size_type >

Every data collection interface is associated with an ``AdcConfigure`` interface
(how this association is realized is explained in Section `4.  HIL
requirements`_).  As the resolution of conversion results is chip-specific, the
``size_type`` parameter reflects an upper bound for the chip-specific resolution
of the conversion results - the actual resolution may be smaller (e.g.  uint16_t
for a 12-bit ADC). The above interfaces are specified in [TEP114]_, in the
following their usage is explained with respect to ADCs.

Read
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``Read`` interface can be used to sample an ADC channel and return a single
conversion result as an uninterpreted value. The meaning of the ``Read``
interface is explained in [TEP114]_.

ReadNow
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``ReadNow`` interface is similar to the ``Read`` interface. The difference
is that if a call to ``ReadNow.read()`` succeeds, the ADC starts to sample the
channel immediately (more precisely: when ``SUCCESS`` is returned the hardware
has started the sampling process). Due to its timing constraints the ``ReadNow``
interface is always provided in conjunction with an instance of the ``Resource``
interface (a client must reserve the ADC before the client may call
``ReadNow.read()``).  Please refer to [TEP108]_ on how the ``Resource``
interface should be used by a client component.

ReadStream
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``ReadStream`` interface can be used to sample an ADC channel multiple times
with a specified sampling period. The meaning of the ``ReadStream`` interface
is explained in [TEP114]_ .


3. HAL guidelines
====================================================================

As explained in `1. Introduction`_ the HAL exposes the full capabilities of the
ADC hardware. Therefore only chip- and platform-dependent clients can wire to
the HAL. Although the HAL is chip-specific, both, in terms of implementation
and representation, its design should follow the guidelines described below to
facilitate the mapping to the HIL representation. Appendix B shows the
signature of the HAL for the MSP430.

Resource reservation
--------------------------------------------------------------------

As the ADC hardware is a shared resource that is usually multiplexed between
several clients some form of access arbitration is necessary.  The HAL should
therefore provide a parameterized ``Resource`` interface, instantiate a standard
arbiter component and connect the ``Resource`` interface to the arbiter as
described in [TEP108]_. To ensure fair and uniform arbitration on all platforms
the standard round robin arbiter is recommended. The meaning of resource
arbiters and the ``Resource`` interface is the topic of [TEP108]_.

Configuration and sampling
--------------------------------------------------------------------

As the ADC hardware is a shared resource the HAL should support hardware
configuration and sampling per client (although per-port configuration is
possible, it is not recommended, because it forces all clients to use the same
configuration for a given port).  Therefore the HAL should provide sampling
interfaces parameterized by a client identifier. An HAL client can use its
instance of the sampling interface to configure the ADC hardware, start the
sampling process and acquire conversion results. It wires to a sampling
interface using a unique client identifier (this may be hidden by a
virtualization component). All commands and events in the sampling interface
should be 'async' to reflect the potential timing requirements of clients on
the level of HAL. An HAL may provide multiple different parameterized sampling
interfaces, depending on the hardware capabilities.  This allows to
differentiate/group ADC functionality, for example single vs.  repeated
sampling, single channel vs.  multiple channels or low-frequency vs.
high-frequency sampling.  Every sampling interface should allow the client to
individually configure the ADC hardware, for example by including the
configuration data as parameters in the sampling commands.  However, if
configuration data is passed as a pointer, the HAL component MUST NOT reference
it after the return of the respective command.  Appendix B shows the HAL
interfaces for the MSP430.

HAL virtualization
--------------------------------------------------------------------

In order to hide wiring complexities and/or export only a subset of all ADC
functions generic ADC wrapper components may be provided on the level of HAL.
Such components can also be used to ensure that a sampling interface is always
provided with a ``Resource`` interface and both are instantiated with the same
client ID if this is required by the HAL implementation.


4. HIL requirements
====================================================================

The following generic components MUST be provided on all platforms that have an
ADC::

  AdcReadClient 
  AdcReadNowClient 
  AdcReadStreamClient 

These components provide virtualized access to the HIL of an ADC. They are
instantiated by an ADC client and provide/use the four interfaces described in
`2.  Interfaces`_. An ADC client may instantiate multiple such components. The
following paragraphs describe their signatures. Appendix C shows the
``AdcReadClient`` for the MSP430.  

AdcReadClient
--------------------------------------------------------------------
::

  generic configuration AdcReadClient() {
    provides {
      interface Read< size_type >;
    }
    uses {
      interface AdcConfigure< config_type >;
    }
  }

The ``AdcReadClient`` component provides a ``Read`` interface for acquiring
single conversion results. The associated ADC channel (port) and further
configuration details are returned by the ``AdcConfigure.getConfiguration()``
command. It is the task of the client to wire this interface to a component
that provides the client's ADC configuration. The HIL implementation will use
the ``AdcConfigure`` interface to dynamically "pull" the client's ADC settings
when it translates the ``Read.read()`` command to a chip-specific sampling
command.  Note that both, ``size_type`` and ``config_type``, are only
placeholders and will be instantiated by the respective HIL implementation (for
an example, see the AdcReadClient for the MSP430 in Appendix C).

AdcReadNowClient
--------------------------------------------------------------------
::

  generic configuration AdcReadNowClient() {
    provides {
      interface Resource;
      interface ReadNow< size_type >;
    }
    uses {
      interface AdcConfigure< config_type >;
    }
  }

The ``AdcReadNowClient`` component provides a ``ReadNow`` interface for
acquiring single conversion results. In contrast to ``Read.read()`` when a call
to ``ReadNow.read()`` succeeds, the ADC starts to sample the channel
immediately (a successful ``Read.read()`` command may not have this
implication, see [TEP114]_ and `2. Interfaces`_). A client MUST reserve the ADC
through the ``Resource`` interface before the client may call
``ReadNow.read()`` and it must release the ADC through the ``Resource``
interface when it no longer needs to access it (for more details on the
``Resource`` interface please refer to [TEP108]_).  The associated ADC channel
(port) and further configuration details are returned by the
``AdcConfigure.getConfiguration()`` command. It is the task of the client to
wire this interface to a component that provides the client's ADC
configuration.  The HIL implementation will use the ``AdcConfigure`` interface
to dynamically "pull" the client's ADC settings when it translates the
``ReadNow.read()`` command to a chip-specific sampling command. Note that both,
``size_type`` and ``config_type``, are only placeholders and will be
instantiated by the respective HIL implementation (for an example how this is
done for the AdcReadClient see Appendix C).

AdcReadStreamClient
--------------------------------------------------------------------
::

  generic configuration AdcReadStreamClient() {
    provides {
      interface ReadStream< size_type >;
    }
    uses {
      interface AdcConfigure< config_type>;
    }
  }

The ``AdcReadStreamClient`` component provides a ``ReadStream`` interface for
acquiring multiple conversion results at once. The ``ReadStream`` interface is
explained in [TEP114]_ and `2. Interfaces`_. The ``AdcConfigure`` interface is
used in the same way as described in the section on the ``AdcReadClient``.
Note that both, ``size_type`` and ``config_type``, are only placeholders and
will be instantiated by the respective HIL implementation (for an example how
this is done for the AdcReadClient see Appendix C).

5. HIL guidelines
====================================================================

The HIL implementation of an ADC stack has two main tasks: it translates a
``Read``, ``ReadNow`` or ``ReadStream`` request to a chip-specific HAL sampling
command and it abstracts from the ``Resource`` interface (the latter only for
the ``AdcReadClient`` and ``AdcReadStreamClient``). The first task is solved
with the help of the ``AdcConfigure`` interface which is used by the HIL
implementation to retrieve a client's ADC configuration.  The second task MAY
be performed by the following library components: ``ArbitratedReadC``, and
``ArbitratedReadStreamC`` (in tinyos-2.x/tos/system) - please refer to the
Atmel Atmega 128 HAL implementation (in tinyos-2.x/tos/chips/atm128/adc), for
an example.  Note that since the ``ReadNow`` interface is always provided in
conjunction with a ``Resource`` interface the HIL implementation does not have
to perform the ADC resource reservation for an ``AdcReadNowClient`, but may
simply forward an instance of the ``Resource`` interface from the HAL to the
``AdcReadNowClient``.

The typical sequence of events is as follows: When a client requests data
through the ``Read`` or ``ReadStream`` interface the HIL will request access to
the HAL using the ``Resource`` interface.  After the HIL has been granted
access, it will "pull" the client's ADC configuration using the
``AdcConfigure`` interface and translate the client's ``Read`` or
``ReadStream`` command to a chip-specific HAL command. Once the HIL is
signalled the conversion result(s) from the HAL it releases the ADC through the
``Resource`` interface and signals the conversion result(s) to the client
though the ``Read`` or ``ReadStream`` interface.  When a client requests data
through the ``ReadNow`` interface the HIL translates the client's command to
the chip-specific HAL command without using the ``Resource`` interface (it may
check ownership of the client through the ``ArbiterInfo`` interface - this
check can also be done in the HAL implementation). Once the HIL is signalled
the conversion result(s) it forwards it to the respective ``ReadNow`` client.

6. Implementation
====================================================================

The implementation of the ADC12 stack on the MSP430 can be found in
``tinyos-2.x/tos/chips/msp430/adc12``:

  * ``HplAdc12P.nc`` is the HPL implementation
  * ``Msp430Adc12P.nc`` is the HAL implementation
  * ``AdcP.nc`` is the HIL implementation
  * ``AdcReadClientC.nc``, ``AdcReadNowClientC.nc`` and
    ``AdcReadStreamClientC.nc`` provide virtualized access to the HIL
  * Please refer to the ``README.txt`` to 

The Atmel Atmega 128 ADC implementation can be found in
``tinyos-2.x/tos/chips/atm128/adc``:

  * ``HplAtm128AdcC.nc`` is the HPL implementation
  * ``Atm128AdcP.nc`` is the HAL implementation
  * ``WireAdcP.nc`` and the library components for arbitrating 'Read', 
    'ReadNow' and 'ReadStream', ``ArbitratedReadC`` and
    ``ArbitratedReadStreamC`` (in ``tinyos-2.x/tos/system``), realize
    the HAL
  * ``AdcReadClientC.nc``, ``AdcReadNowClientC.nc`` and
    ``AdcReadStreamClientC.nc`` provide access to the ADC on a per-client
    basis via the platform-independent interfaces 'Read', 'ReadNow' and
    'ReadStream', respectively, and the atmega-specific ADC configuration 
    interface ``Atm128AdcConfig.nc``


Appendix A: Hardware differences between platforms
====================================================================

The following table compares the characteristics of two microcontrollers
commonly used in TinyOS platforms:

+----------------------+----------------------+---------------------+
|                      | Atmel Atmega 128     | TI MSP430 ADC12     |
+======================+======================+=====================+
|Resolution            | 10-bit               | 12-bit              |
+----------------------+----------------------+---------------------+
|channels              |- 8 multiplexed       |- 8 individually     |
|                      |  external channels   |  configurable       |
|                      |- 16 differential     |  external channels  |
|                      |  voltage input       |- internal channels  |
|                      |  combinations        |  (AVcc, temperature,|
|                      |- 2 differential      |  reference voltages)|
|                      |  inputs with gain    |                     |
|                      |  amplification       |                     |
+----------------------+----------------------+---------------------+
|internal reference    | 2.56V                | 1.5V or 2.5V        |
|voltage               |                      |                     |
+----------------------+----------------------+---------------------+
|conversion reference  |- positive terminal:  | individually        |
|                      |  AVcc or 2.56V  or   | selectable per      |
|                      |  AREF (external)     | channel:            |
|                      |- negative terminal:  |                     |
|                      |  GND                 |- AVcc and AVss      |
|                      |                      |- Vref+ and AVss     |
|                      |                      |- Veref+ and AVss    |
|                      |                      |- AVcc and (Vref- or |
|                      |                      |  Veref-)            |
|                      |                      |- AVref+ and (Vref-  |
|                      |                      |  or Veref-)         |
|                      |                      |- Veref+ and (Vref-  |
|                      |                      |  or Veref-)         |
+----------------------+----------------------+---------------------+
|conversion modes      |- single channel      |- single conversion  |
|                      |  conversion mode     |  mode               |
|                      |- free running mode   |- repeat single      |
|                      |  (channels and       |  conversion mode    |
|                      |  reference voltages  |- sequence mode      |
|                      |  can be switched     |  (sequence <= 16    |
|                      |  between samples)    |  channels)          |
|                      |                      |- repeat sequence    |
|                      |                      |  mode               |
+----------------------+----------------------+---------------------+
|conversion clock      |clkADC with prescaler |ACLK, MCLK, SMCLK or |
|source                |                      |ADC-oscillator (5MHz)|
|                      |                      |with prescaler       |
|                      |                      |respectively         |
+----------------------+----------------------+---------------------+
|sample-hold-time      |1.5 clock cycles      |selectable values    |
|                      |(fixed)               |from 4 to 1024 clock |
|                      |                      |cycles               |
+----------------------+----------------------+---------------------+
|conversion triggering |by software           |by software or timers|
+----------------------+----------------------+---------------------+
|conversion during     |yes                   |yes                  |
|sleep mode possible   |                      |                     |
+----------------------+----------------------+---------------------+
|interrupts            |after each conversion |after single or      |
|                      |                      |sequence conversion  |
+----------------------+----------------------+---------------------+


Appendix B: an HAL representation: MSP430 ADC12
====================================================================

The following section shows the HAL signature for the ADC12 of the TI MSP430
MCU. It reflects the four MSP430 ADC12 conversion modes as it lets a client
sample an ADC channel once ("Single-channel-single-conversion") or repeatedly
("Repeat-single-channel"), multiple times ("Sequence-of-channels") or multiple
times repeatedly ("Repeat-sequence-of-channels"). In contrast to the single
channel conversion modes the sequence conversion modes trigger a single
interrupt after multiple samples and thus enable high-frequency sampling. The
``DMAExtension`` interface is used to reset the state machine when the DMA is
responsible for data transfer::

  configuration Msp430Adc12P 
  { 
    provides {
      interface Resource[uint8_t id]; 
      interface Msp430Adc12SingleChannel as SingleChannel[uint8_t id]; 
      interface AsyncStdControl as DMAExtension[uint8_t id];
    }
  }

  interface Msp430Adc12SingleChannel 
  {   
    async command error_t configureSingle(const msp430adc12_channel_config_t *config);
    async command error_t configureSingleRepeat(const msp430adc12_channel_config_t *config, uint16_t jiffies);
    async command error_t configureMultiple( const msp430adc12_channel_config_t *config, uint16_t buffer[], uint16_t numSamples, uint16_t jiffies);
    async command error_t configureMultipleRepeat(const msp430adc12_channel_config_t *config, uint16_t buffer[], uint8_t numSamples, uint16_t jiffies);
    async command error_t getData();
    async event error_t singleDataReady(uint16_t data);
    async event uint16_t* multipleDataReady(uint16_t buffer[], uint16_t numSamples); 
  }


Appendix C: an HIL representation: MSP430 ADC12
====================================================================

The signature of the AdcReadClientC component for the MSP430 ADC12 is as
follows::

  generic configuration AdcReadClientC() {
    provides interface Read<uint16_t>;
    uses interface AdcConfigure<const msp430adc12_channel_config_t*>;
  }

.. [TEP1] TEP 1: TEP Structure and Keywords. 
.. [TEP2] TEP 2: Hardware Abstraction Architecture. 
.. [TEP108] TEP 108: Resource Arbitration. 
.. [TEP109] TEP 109: Sensor Boards. 
.. [TEP111] TEP 111: message_t 
.. [TEP114] TEP 114: SIDs: Source and Sink Independent Drivers. 
-------------- next part --------------
=========================
Sensors and Sensor Boards
=========================

:TEP: 109
:Group: Core Working Group 
:Type: Documentary
:Status: Draft
:TinyOS-Version: 2.x
:Author: David Gay, Phil Levis, Wei Hong, Joe Polastre, and Gilman Tolle

:Draft-Created: 10-Jun-2006
:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>

.. Note::

   This memo documents a part of TinyOS for the TinyOS Community, and
   requests discussion and suggestions for improvements.  Distribution
   of this memo is unlimited. This memo is in full compliance with
   TEP 1.

Abstract
====================================================================

This memo documents how sensor drivers are organized in TinyOS and how
sets of sensor drivers are combined into sensor boards and sensor
platforms, along with general principles followed by the components
that provide access to sensors.

1. Principles
====================================================================

This section describes the basic organization principles for sensor
drivers in TinyOS.

For background, a sensor may be attached to the microcontroller on a
TinyOS platform through a few different types of connections:

 * Included within the microcontroller itself
 * Connected to general-purpose IO pins for level/edge detection
 * Connected to an ADC in the microcontroller for voltage sampling
 * Connected to general-purpose IO pins for digital communication
 * Connected through a standard digital bus protocol (1-Wire, I2C, SPI)

Physically, these connections may also be decoupled by attaching the
sensors to a `sensor board`, which can be removed from the TinyOS
platform, and may fit multiple different TinyOS platforms.

The capabilities of a physical sensor are made available to a TinyOS
application through a `sensor driver`. 

According to the HAA [TEP2]_, TinyOS devices should provide both
simple hardware-independent interfaces for common-case use (HIL) and
rich hardware-dependent interfaces for special-case use (HAL). Sensor
drivers should follow this spirit as well.

TinyOS 2.x represents each sensor as an individual component. This
allows the compilation process to minimize the amount of code
included. A sensor board containing multiple sensors should be
represented as a collection of components, one for each sensor,
contained within a sensor board directory.

Sensors, being physical devices that may be shared, can benefit from
virtualization and arbitration. This document describes a design
pattern for sensor virtualization that may be followed by sensor
drivers.

The same physical sensor may be attached to multiple different TinyOS
platforms, through platform-dependent interconnections. The common
logic of sensor driver should be factored into chip-dependent,
platform-independent components, and those components should be bound
to the hardware resources on a platform by platform-dependent
components, and to the hardware resources on a sensor board by
sensorboard-dependent components.

A physical sensor has a general class and a specific set of
performance characteristics, captured by the make and model of the
sensor itself. The naming of the sensor driver components should
reflect the specifc name of the sensor, and optionally provide a
component with a generic name for application authors who only care
about the general class of the sensor.

This document takes no position on the meaning of the values returned
by sensor drivers. They may be raw uninterpreted values or they may
have some physical meaning. If a driver returns uninterpreted values,
the driver may provide additional interfaces that would allow
higher-level clients to interpret the value properly.

2. Sensor HIL Components
====================================================================

A sensor HIL component MUST provide:

- One or more SID interfaces [TEP114]_, for reading data.

A sensor HIL component MAY provide:

- One or more SID interfaces [TEP114]_, for reading or
  writing calibration coefficients or control registers.

A sensor device driver SHOULD be a generic component that virtualizes
access to the sensor. A sensor device driver can provide such
virtualization for itself by defining a nesC generic client
component. When a client component is being used, a call to a
top-level SID interface should be delayed when the device is busy,
rather than failing. This virtualization may be easier to accomplish
by using one of the arbiters provided by the system.

For example::

  generic configuration SensirionSht11C() {
    provides interface Read<uint16_t> as Temperature;
    provides interface ReadStream<uint16_t> as TemperatureStream;
    provides interface Read<uint16_t> as Humidity;
    provides interface ReadStream<uint16_t> as HumidityStream;
  }
  implementation {
    // connect to the ADC HIL, GPIO HAL, or sensor's HAL
  }

When a HIL component is being used, the sensor MUST initialize itself,
either by including the `MainC` component and wiring to the
`SoftwareInit` interface, or by allowing a lower-level component (like
an ADC) to initialize itself.

In addition, the HIL sensor driver MUST start the physical sensor
automatically. For sensors without a constant power draw, the sensor
MAY be started once at boot time by wiring to the `MainC.Boot`
interface. Sensors that draw appreciable power MUST be started in
response to a call to one of the top-level SID interfaces, and stopped
some time after that call completes. One of the power-management
components described in [TEP115]_ may be useful for this purpose.

Generally, simple types are made up of octets. However, sensor values
often have levels of precision besides a multiple of 8. A device MAY
specify the precision of one of its interfaces with the DeviceMetadata
interface::

  interface DeviceMetadata {
    command uint8_t getSignificantBits();
  }

The name of the instance of DeviceMetadata SHOULD clearly indicate
which interface it corresponds to.

A value contained returned from the device through a SID interface
MAY be left shifted so that it covers as much of the type's range as
possible. For example, if a 12-bit ADC reading is presented as a
16-bit Read interface::

  component DemoSensorC {
    provides interface Read<uint16_t>;
  }

then the driver MAY shift the 12-bit value left so that its range is
0x0000 - 0xfff0, rather than 0x0000 - 0x0fff. 

Sensor driver components SHOULD be named according to the make and
model of the sensing device being presented. Using specific names
gives the developer the option to bind to a particular sensor, which
provides compile-time detection of missing sensors. However, wrapper
components using "common" names MAY also be provided by the driver
author, to support application developers who are only concerned with
the particular type of the sensor and not its make, model, or detailed
performance characteristics.

A "common" naming layer atop a HIL may look like this::

  generic configuration TemperatureC() {
    provides interface Read<uint16_t>;
    provides interface ReadStream<uint16_t>;
  }
  implementation {
    components new SensirionSht11C();
    Read = SensirionSht11C.Temperature;
    ReadStream = SensirionSht11C.TemperatureStream;
  }

  generic configuration HumidityC() {
    provides interface Read<uint16_t>;
    provides interface ReadStream<uint16_t>;
  }
  implementation {
    components new SensirionSht11C();
    Read = SensirionSht11C.Humidity;
    ReadStream = SensirionSht11C.HumidityStream;
  }

3. Sensor HAL Components
====================================================================

Sensors with a richer interface than would be supported by the SID
interfaces MAY provide a HAL component in addition to a HIL
component.

A sensor HAL component MUST provide:

- A SID-based interface or a specific hardware-dependent interface
  with commands for sampling and controlling the sensor device.

A sensor HAL component MAY need to provide:

- A `StdControl` or `SplitControl` interface for manual power
  management by the user, following the conventions described in
  [TEP115]_.

- A Resource[] interface for requesting access to the device and
  possibly performing automated power management.

- Any other interfaces needed to control the device.

For example::

  configuration SensirionSht11DeviceC {
    provides interface Resource[ uint8_t client ];
    provides interface SensirionSht11[ uint8_t client ];
  }
  implementation {
    // connect to the sensor's platform-dependent HPL here
  }

4. Directory Organization Guidelines
====================================================================

Because the same physical sensor may be attached to TinyOS platforms
in many different ways, the organization of sensor drivers should
reflect the distinction between sensor and sensor interconnect.

Sensor components commonly exist at three levels:
platform-independent, sensorboard-dependent, and
platform-dependent. Factoring a sensor driver into these three pieces
allows for greater code reuse when the same sensor is attached to
different sensorboards or platforms.

Platform-independent sensor driver components for a particular sensor,
like protocol logic, when in the core TinyOS 2.x source tree, SHOULD
be placed into "tos/chips/<sensor>", where <sensor> reflects the make
and model of the sensor device being supported. When not a part of the
core source tree, this directory can be placed anywhere as long as the
nesC compiler recieves a `-I` directive pointing to the sensor's
directory. However, not all sensors have a sufficiently large amount
of platform-independent logic to justify a separate "chips"
directory. Sensor chips are more likely to be digital sensors than
analog sensors, for example.

A sensor board is a collection of sensor components with a fixed name,
intended for attachment to multiple platforms. Each sensor board MUST
have its own directory named <sensorboard>. Default TinyOS 2.x sensor
boards are placed in "tos/sensorboards/<sensorboard>", but sensor
board directories can be placed anywhere as long as the nesC compiler
receives a `-I` directive pointing to the sensor board's directory.

Both sensors and sensor boards MUST have unique names. Case is
significant, but two sensor boards MUST differ in more than case. This
is necessary to support platforms where filename case differences are
not significant.

Each sensor board directory MUST contain a `.sensor` file.  This file
is a perl script which gets executed as part of the `ncc` nesC
compiler frontend. It can add or modify any compile-time options
necessary for a particular sensor board. It MAY modify the following
perl variables, and MUST NOT modify any others:

- @new_args: This is the array of arguments which will be passed to
  nescc. For instance, you might add an include directive to @new_args
  with push @new_args, `-Isomedir`. This could be used to include
  subdirectories.

- @commonboards: This can be set to a list of sensor board names which
  should be added to the include path list. These sensor boards must be
  in tinyos-2.x/tos/sensorboards.

If the sensor board wishes to define any C types or constants, it
SHOULD place these in a file named <sensorboard>.h in the sensor
board's directory.

A sensor board directory MAY contain a "chips" directory, with
subdirectories for each of the sensors connected to the sensor board.
If a "chips" subdirectory is used, sensorboard-dependent driver
components needed to connect platform-independent logic to a
particular attachment for that sensor should be placed in
"<sensorboard>/chips/<sensor>".

Components needed to connect the platform-independent sensor driver
components or sensorboard-dependent components to the hardware
resources available on a particular platform SHOULD be placed in
"tos/<platform>/chips/<sensor>". In addition, components for a sensor
that only exists on a particular platform should be placed in a such a
directory.

Sensors that exist as part of a larger chip, like a MCU internal
voltage sensor, SHOULD be placed in a subdirectory of the chip's
directory. "tos/<chip>/sensors/<sensor>".

The `.platform` and `.sensor` files need to include enough `-I`
directives to locate all of the necessary components needed to support
the sensors on a platform and/or sensorboard.

All of these directory organization guidelines are only intended for
code that will enter the core source tree. In general, sensor
components may be placed anywhere as long as the nesC compiler
receives enough `-I` directives to locate all of the necessary pieces.

5. Authors' Addresses
====================================================================

| David Gay
| 2150 Shattuck Ave, Suite 1300
| Intel Research
| Berkeley, CA 94704
|
| phone - +1 510 495 3055
|
| email - david.e.gay at intel.com
|
| Wei Hong
| Arch Rock
| 657 Mission St. Suite 600
| San Francisco, CA 94105
|
| email - wei.hong at gmail.com
|
| Philip Levis
| 358 Gates Hall
| Computer Science Department
| 353 Serra Mall
| Stanford, CA 94305
|
| phone - +1 650 725 9046
|
| email - pal at cs.stanford.edu
| 
| Joe Polastre
| 467 Soda Hall
| UC Berkeley
| Berkeley, CA 94720
|
| email - polastre at cs.berkeley.edu
|
| Gilman Tolle
| Arch Rock
| 657 Mission St. Suite 600
| San Francisco, CA 94105
|
| email - gtolle at archrock.com

6. Citations
====================================================================

.. [TEP2] TEP 2: Hardware Abstraction Architecture
.. [TEP114] TEP 114: SIDs: Source and Sink Indepedent Drivers
.. [TEP115] TEP 115: Power Management of Non-Virtualized Devices

Appendix A: Sensor Driver Examples
====================================================================

1. Analog ADC-Connected Sensor
------------------------------

The Analog sensor requires two components

* a component to present the sensor itself (HamamatsuS1087ParC)

* a component to select the appropriate hardware resources, such as
  ADC port 4, reference voltage 1.5V, and a slow sample and hold time
  (HamamatsuS1087ParP).

The AdcReadClientC component and underlying machinery handles all of
the arbitration and access to the ADC.

::

  tos/platforms/telosa/chips/s1087/HamamatsuS1087ParC.nc

  generic configuration HamamatsuS1087ParC() {
    provides interface Read<uint16_t>;
    provides interface ReadStream<uint16_t>;
  }
  implementation {
    components new AdcReadClientC();
    Read = AdcReadClientC;

    components new AdcReadStreamClientC();
    ReadStream = AdcReadStreamClientC;

    components HamamatsuS1087ParP;
    AdcReadClientC.Msp430Adc12Config -> HamamatsuS1087ParP;
    AdcReadStreamClientC.Msp430Adc12Config -> HamamatsuS1087ParP;
  }
  
::

  tos/platforms/telosa/chips/s1087/HamamatsuS1087ParP.nc

  module HamamatsuS1087ParP {
    provides interface Msp430Adc12Config;
  }
  implementation {

    async command msp430adc12_channel_config_t 
      Msp430Adc12Config.getChannelSettings() {
 
      msp430adc12_channel_config_t config = {
        inch: INPUT_CHANNEL_A4,
        sref: REFERENCE_VREFplus_AVss,
        ref2_5v: REFVOLT_LEVEL_1_5,
        adc12ssel: SHT_SOURCE_ACLK,
        adc12div: SHT_CLOCK_DIV_1,
        sht: SAMPLE_HOLD_4_CYCLES,
        sampcon_ssel: SAMPCON_SOURCE_SMCLK,
        sampcon_id: SAMPCON_CLOCK_DIV_1
      };
      
      return config;
    }
  }

2. Binary Pin-Connected Sensor
------------------------------

The Binary sensor gets a bit more complex, because it has three
components: 

* one to present the sensor (UserButtonC)

* one to execute the driver logic (UserButtonLogicP)

* one to select the appropriate hardware resources, such as MSP430
  Port 27 (HplUserButtonC).

Note that the presentation of this sensor is not arbitrated because
none of the operations are split-phase. 

::

  tos/platforms/telosa/UserButtonC.nc

  configuration UserButtonC {
    provides interface Get<bool>;
    provides interface Notify<bool>;
  }
  implementation {

    components UserButtonLogicP;

    components HplUserButtonC;
    UserButtonLogicP.GpioInterrupt -> HplUserButtonC.GpioInterrupt;
    UserButtonLogicP.GeneralIO -> HplUserButtonC.GeneralIO;

    Get = UserButtonLogicP;
    Notify = UserButtonLogicP;
  }

::

  tos/platforms/telosa/UserButtonLogicP.nc
 
  module UserButtonLogicP {
    provides interface Get<bool>;
    provides interface Notify<bool>;

    uses interface GeneralIO;
    uses interface GpioInterrupt; 
  }
  implementation {
    norace bool m_pinHigh;

    task void sendEvent();
 
    command bool Get.get() { return call GeneralIO.get(); }

    command error_t Notify.enable() {
      call GeneralIO.makeInput();

      if ( call GeneralIO.get() ) {
        m_pinHigh = TRUE;
        return call GpioInterrupt.enableFallingEdge();
      } else {
        m_pinHigh = FALSE;
        return call GpioInterrupt.enableRisingEdge();
      }
    }

    command error_t Notify.disable() {
      return call GpioInterrupt.disable();
    }

    async event void GpioInterrupt.fired() {
      call GpioInterrupt.disable();

      m_pinHigh = !m_pinHigh;

      post sendEvent();
    }

    task void sendEvent() {
      bool pinHigh;
      pinHigh = m_pinHigh;
    
      signal Notify.notify( pinHigh );
    
      if ( pinHigh ) {
        call GpioInterrupt.enableFallingEdge();
      } else {
        call GpioInterrupt.enableRisingEdge();
      }
    }
  }

::

  tos/platforms/telosa/HplUserButtonC.nc

  configuration HplUserButtonC {
    provides interface GeneralIO;
    provides interface GpioInterrupt;
  }
  implementation {

    components HplMsp430GeneralIOC as GeneralIOC;

    components new Msp430GpioC() as UserButtonC;
    UserButtonC -> GeneralIOC.Port27;
    GeneralIO = UserButtonC;

    components HplMsp430InterruptC as InterruptC;

    components new Msp430InterruptC() as InterruptUserButtonC;
    InterruptUserButtonC.HplInterrupt -> InterruptC.Port27;
    GpioInterrupt = InterruptUserButtonC.Interrupt;
  }

3. Digital Bus-Connected Sensor
-------------------------------

The Digital sensor is the most complex out of the set, and includes
six components:

* one to present the sensor (SensirionSht11C)

* one to request arbitrated access and to transform the sensor HAL
  into the sensor HIL (SensirionSht11P)

* one to present the sensor HAL (HalSensirionSht11C)

* one to perform the driver logic needed to support the HAL, which
  twiddles pins according to a sensor-specific protocol
  (SensirionSht11LogicP).

* one to select the appropriate hardware resources, such as the clock,
  data, and power pins, and to provide an arbiter for the sensor
  (HplSensirionSht11C).

* one to perform the power control logic needed to support the power
  manager associated with the arbiter (HplSensirionSht11P).

This bus-connected sensor is overly complex because it does not rely
on a shared framework of bus manipulation components. A sensor built
on top of the I2C or SPI bus would likely require fewer components.

::

  tos/platforms/telosa/chips/sht11/SensirionSht11C.nc
  
  generic configuration SensirionSht11C() {  
    provides interface Read<uint16_t> as Temperature;
    provides interface Read<uint16_t> as Humidity;
  }
  implementation {
    components new SensirionSht11ReaderP();
  
    Temperature = SensirionSht11ReaderP.Temperature;
    Humidity = SensirionSht11ReaderP.Humidity;
  
    components HalSensirionSht11C;
  
    enum { TEMP_KEY = unique("Sht11.Resource") };
    enum { HUM_KEY = unique("Sht11.Resource") };
  
    SensirionSht11ReaderP.TempResource -> HalSensirionSht11C.Resource[ TEMP_KEY ];
    SensirionSht11ReaderP.Sht11Temp -> HalSensirionSht11C.SensirionSht11[ TEMP_KEY ];
    SensirionSht11ReaderP.HumResource -> HalSensirionSht11C.Resource[ HUM_KEY ];
    SensirionSht11ReaderP.Sht11Hum -> HalSensirionSht11C.SensirionSht11[ HUM_KEY ];
  }
  
::
  
  tos/chips/sht11/SensirionSht11ReaderP.nc
  
  generic module SensirionSht11ReaderP() {
    provides interface Read<uint16_t> as Temperature;
    provides interface Read<uint16_t> as Humidity;
    
    uses interface Resource as TempResource;
    uses interface Resource as HumResource;
    uses interface SensirionSht11 as Sht11Temp;
    uses interface SensirionSht11 as Sht11Hum;
  }
  implementation {
    command error_t Temperature.read() {
      call TempResource.request();
      return SUCCESS;
    }
  
    event void TempResource.granted() {
      error_t result;
      if ((result = call Sht11Temp.measureTemperature()) != SUCCESS) {
        call TempResource.release();
        signal Temperature.readDone( result, 0 );
      }
    }
  
    event void Sht11Temp.measureTemperatureDone( error_t result, uint16_t val ) {
      call TempResource.release();
      signal Temperature.readDone( result, val );
    }
  
    command error_t Humidity.read() {
      call HumResource.request();
      return SUCCESS;
    }
  
    event void HumResource.granted() {
      error_t result;
      if ((result = call Sht11Hum.measureHumidity()) != SUCCESS) {
        call HumResource.release();
        signal Humidity.readDone( result, 0 );
      }
    }
  
    event void Sht11Hum.measureHumidityDone( error_t result, uint16_t val ) {
      call HumResource.release();
      signal Humidity.readDone( result, val );
    }
  
    event void Sht11Temp.resetDone( error_t result ) { }
    event void Sht11Temp.measureHumidityDone( error_t result, uint16_t val ) { }
    event void Sht11Temp.readStatusRegDone( error_t result, uint8_t val ) { }
    event void Sht11Temp.writeStatusRegDone( error_t result ) { }
  
    event void Sht11Hum.resetDone( error_t result ) { }
    event void Sht11Hum.measureTemperatureDone( error_t result, uint16_t val ) { }
    event void Sht11Hum.readStatusRegDone( error_t result, uint8_t val ) { }
    event void Sht11Hum.writeStatusRegDone( error_t result ) { }
  
    default event void Temperature.readDone( error_t result, uint16_t val ) { }
    default event void Humidity.readDone( error_t result, uint16_t val ) { }
  }
  
::
  
  tos/platforms/telosa/chips/sht11/HalSensirionSht11C.nc
  
  configuration HalSensirionSht11C {
    provides interface Resource[ uint8_t client ];
    provides interface SensirionSht11[ uint8_t client ];
  }
  implementation {
    components new SensirionSht11LogicP();
    SensirionSht11 = SensirionSht11LogicP;
  
    components HplSensirionSht11C;
    Resource = HplSensirionSht11C.Resource;
    SensirionSht11LogicP.DATA -> HplSensirionSht11C.DATA;
    SensirionSht11LogicP.CLOCK -> HplSensirionSht11C.SCK;
    SensirionSht11LogicP.InterruptDATA -> HplSensirionSht11C.InterruptDATA;
    
    components new TimerMilliC();
    SensirionSht11LogicP.Timer -> TimerMilliC;
  
    components LedsC;
    SensirionSht11LogicP.Leds -> LedsC;
  }
  
::
  
  tos/chips/sht11/SensirionSht11LogicP.nc
  
  generic module SensirionSht11LogicP() {
    provides interface SensirionSht11[ uint8_t client ];
  
    uses interface GeneralIO as DATA;
    uses interface GeneralIO as CLOCK;
    uses interface GpioInterrupt as InterruptDATA;
  
    uses interface Timer<TMilli>;
  
    uses interface Leds;
  }
  implementation {
  
    ... bus protocol details omitted for brevity ...
  
  }
  
::
  
  tos/platforms/telosa/chips/sht11/HplSensirionSht11C.nc
  
  configuration HplSensirionSht11C {
    provides interface Resource[ uint8_t id ];
    provides interface GeneralIO as DATA;
    provides interface GeneralIO as SCK;
    provides interface GpioInterrupt as InterruptDATA;
  }
  implementation {
    components HplMsp430GeneralIOC;
    
    components new Msp430GpioC() as DATAM;
    DATAM -> HplMsp430GeneralIOC.Port15;
    DATA = DATAM;
  
    components new Msp430GpioC() as SCKM;
    SCKM -> HplMsp430GeneralIOC.Port16;
    SCK = SCKM;
  
    components new Msp430GpioC() as PWRM;
    PWRM -> HplMsp430GeneralIOC.Port17;
  
    components HplSensirionSht11P;
    HplSensirionSht11P.PWR -> PWRM;
    HplSensirionSht11P.DATA -> DATAM;
    HplSensirionSht11P.SCK -> SCKM;
  
    components new TimerMilliC();
    HplSensirionSht11P.Timer -> TimerMilliC;
  
    components HplMsp430InterruptC;
    components new Msp430InterruptC() as InterruptDATAC;
    InterruptDATAC.HplInterrupt -> HplMsp430InterruptC.Port15;
    InterruptDATA = InterruptDATAC.Interrupt;
  
    components new FcfsArbiterC( "Sht11.Resource" ) as Arbiter;
    Resource = Arbiter;
    
    components new SplitControlPowerManagerC();
    SplitControlPowerManagerC.SplitControl -> HplSensirionSht11P;
    SplitControlPowerManagerC.ArbiterInit -> Arbiter.Init;
    SplitControlPowerManagerC.ArbiterInfo -> Arbiter.ArbiterInfo;
    SplitControlPowerManagerC.ResourceController -> Arbiter.ResourceController;
  }
  
::
  
  tos/platforms/telosa/chips/sht11/HplSensirionSht11P.nc
  
  module HplSensirionSht11P {
    provides interface SplitControl;
    uses interface Timer<TMilli>;
    uses interface GeneralIO as PWR;
    uses interface GeneralIO as DATA;
    uses interface GeneralIO as SCK;
  }
  implementation {
    task void stopTask();
  
    command error_t SplitControl.start() {
      call PWR.makeOutput();
      call PWR.set();
      call Timer.startOneShot( 11 );
      return SUCCESS;
    }
    
    event void Timer.fired() {
      signal SplitControl.startDone( SUCCESS );
    }
  
    command error_t SplitControl.stop() {
      call SCK.makeInput();
      call SCK.clr();
      call DATA.makeInput();
      call DATA.clr();
      call PWR.clr();
      post stopTask();
      return SUCCESS;
    }
  
    task void stopTask() {
      signal SplitControl.stopDone( SUCCESS );
    }
  }
-------------- next part --------------
============================
TEP Structure and Keywords 
============================

:TEP: 1
:Group: Core Working Group 
:Type: Best Current Practice
:Status: Draft
:TinyOS-Version: All
:Author: Philip Levis

:Draft-Created: 18-Oct-2004
:Draft-Version: $Revision: 1.1.2.3 $
:Draft-Modified: $Date: 2006/06/13 08:27:16 $
:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>

.. Note::

   This document specifies a Best Current Practices for the
   TinyOS Community, and requests discussion and suggestions for
   improvements.  Distribution of this memo is unlimited.

Abstract
====================================================================

This memo describes the structure all TinyOS Extension Proposal (TEP)
documents follow, and defines the meaning of several key words in
those documents.

1. Introduction
====================================================================

In order to simplify management, reading, and tracking development,
all TinyOS Extension Proposals (TEPs) MUST have a particular
structure. Additionally, to simplify development and improve
implementation interoperability, all TEPs MUST observe the meaning of
several key words that specify levels of compliance. This document
describes and follows both.

2. Keywords
====================================================================

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in TEP 1.

Note that the force of these words is modified by the requirement
level of the document in which they are used.

2.1 MUST
--------------------------------------------------------------------

MUST: This word, or the terms "REQUIRED" or "SHALL", mean that the
definition is an absolute requirement of the specification.

2.2 MUST NOT
--------------------------------------------------------------------

MUST NOT: This phrase, or the phrase "SHALL NOT", mean that the
definition is an absolute prohibition of the specification.

2.3 SHOULD
--------------------------------------------------------------------

SHOULD: This word, or the adjective "RECOMMENDED", mean that there
may exist valid reasons in particular circumstances to ignore a
particular item, but the full implications must be understood and
carefully weighed before choosing a different course.

2.4 SHOULD NOT
--------------------------------------------------------------------

SHOULD NOT: This phrase, or the phrase "NOT RECOMMENDED" mean that
there may exist valid reasons in particular circumstances when the
particular behavior is acceptable or even useful, but the full
implications should be understood and the case carefully weighed
before implementing any behavior described with this label.

2.5 MAY
--------------------------------------------------------------------

MAY: This word, or the adjective "OPTIONAL", mean that an item is
truly optional.  One implementer may choose to include the item
because a particular application requires it or because the
implementer feels that it enhances the system while another
implementer may omit the same item.  An implementation which does not
include a particular option MUST be prepared to interoperate with
another implementation which does include the option, though perhaps
with reduced functionality. In the same vein an implementation which
does include a particular option MUST be prepared to interoperate with
another implementation which does not include the option (except, of
course, for the feature the option provides.)

2.6 Guidance in the use of these Imperatives
--------------------------------------------------------------------

Imperatives of the type defined in this memo must be used with care
and sparingly.  In particular, they MUST only be used where it is
actually required for interoperation or to limit behavior which has
potential for causing harm (e.g., limiting retransmissions)  For
example, they must not be used to try to impose a particular method
on implementors where the method is not required for
interoperability.


3. TEP Structure
====================================================================

TEPs have two major parts, a header and a body. The header states
document metadata, for management and status. The body contains the 
content of the proposal.

All TEPs MUST follow the TEP docutils template, and conform to 
reStructuredText standards [1]_, to enable translation from 
reStructuredText to HTML and Latex.

3.1 TEP Header
--------------------------------------------------------------------

The TEP header has several fields which MUST be included, as well as
others which MAY be included. The first six header fields MUST be
included in all TEPs, in the order stated here.

The first field is "TEP," and specifies the TEP number of the
document. A TEP's number is unique.. This document is TEP 1. The 
TEP type (discussed below)
determines how a number is assigned to it. Generally, when a document
is ready to be a TEP, it is assigned the smallest available number.
BCP TEPs start at 1 and all other TEPs (Documentary, Experimental,
and Informational) start at 101.

The second field states the name of the working group that produced
the document. This document was produced by the Core Working Group.

The third field is "Type," and specifies the type of TEP the document
is. There are four types of TEP: Best Current Practice (BCP),
Documentary, Informational, and Experimental. This document is Best
Current Practice.

Best Current Practice is the closest thing TEPs have to a standard: it
represents conclusions from significant experience and work by its
authors. Developers desiring to add code (or TEPs) to TinyOS SHOULD
follow all current BCPs. 

Documentary TEPs describe a system or protocol that exists; a
documentary TEP MUST reference an implementation that a reader can
easily obtain.  Documentary TEPs simplify interoperability when 
needed, and document TinyOS service implementations.

Informational TEPs provide information that is of interest to the
community. Informational TEPs include data gathered on radio behavior,
hardware characteristics, other aspects of TinyOS software/hardware,
organizational and logistic information,
or experiences which could help the community achieve its goals.  

Experimental TEPs describe a completely experimental approach to a
problem, which are outside the TinyOS core and will not necessarily
become part of it.  Unlike Documentary TEPs, Experimental TEPs may 
describe systems that do not have a reference implementation.

The fourth field is "Status," which specifies the status of the TEP.
A TEP status can either be "Draft," which means it is a work in
progress, "Final," which means it is complete and will not change, or
"Obsolete," which means it should no longer be considered. If a TEP is
"Obsolete" because it has been replaced by another TEP, then the new
TEP number should follow "Obsolete," such as "Obsolete by TEP 1231."

If a TEP is Best Current Practices or Documentary, then it MUST
include an additional field, "TinyOS-Version:," which states what
version(s) of TinyOS the document pertains to. This document pertains
to all versions of TinyOS, until made obsolete by a future TEP. This
field MUST appear after the Status field and before the Author field.

The final required field is Author, which states the names of the
authors of the document. Full contact information should not be listed
here (see Section 3.2).

If a TEP is a Draft, then four additional fields MUST be included:
Draft-Created, Draft-Modified, Draft-Version, and Draft-Discuss.
Draft-Created states the date the document was created, Draft-Modified
states when it was last modified. Draft-Version specifies the version
of the draft, which MUST increase every time a modification is
made. Draft-Discuss specifies the email address of a mailing list
where the draft is being discussed. Final and Obsolete TEPs MUST NOT
have these fields, which are for Drafts only.

3.2 TEP Body
--------------------------------------------------------------------

The first element of the TEP body MUST be the title of the document. A
TEP SHOULD follow the title with an Abstract, which gives a brief
overview of the content of the TEP. Longer TEPs MAY, after the
Abstract, have a Table of Contents. After the Abstract and Table of
Contents there SHOULD be an Introduction, stating the problem the TEP
seeks to solve and providing needed background information.

If a TEP is Documentary, it MUST have a section entitled
"Implementation," which instructs the reader how to obtain the
implementation documented.

If a TEP is Best Current Practices, it MUST have a section entitled
"Reference," which points the reader to one or more reference uses of
the practices.

The last section of a TEP (but before citations, if there are any),
entitled "Author's Address" or "Author's Addresses" MUST contain
detailed author contact information.

4. Reference
====================================================================

The reference use of this document is TEP 1 (itself).

5. Acknowledgments
====================================================================

The definitions of the compliance terms are a direct copy of
definitions taken from IETF RFC 2119.

6. Author's Address
====================================================================

| Philip Levis
| 467 Soda Hall
| UC Berkeley
| Berkeley, CA 94720
|
| phone - +1 510 290 5283
|
| email - pal at cs.berkeley.edu

7. Citations
====================================================================

.. [1] reStructuredText Markup Specification. <http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html>
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.millennium.berkeley.edu/pipermail/tinyos-2.0wg/attachments/20061010/8ec710bd/tep101-0001.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.millennium.berkeley.edu/pipermail/tinyos-2.0wg/attachments/20061010/8ec710bd/tep109-0001.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.millennium.berkeley.edu/pipermail/tinyos-2.0wg/attachments/20061010/8ec710bd/tep1-0001.html
-------------- next part --------------

Phil


More information about the Tinyos-2.0wg mailing list