]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - doc/txt/tep109.txt
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / doc / txt / tep109.txt
index ba8809fc7b98a56519d6def7792c923c032cb924..3945ffc6d427dd9ca644d9f0f6ae5f0f80295496 100644 (file)
@@ -5,12 +5,9 @@ Sensors and Sensor Boards
 :TEP: 109
 :Group: Core Working Group 
 :Type: Documentary
-:Status: Draft
+:Status: Final
 :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>
+:Author: David Gay, Philip Levis, Wei Hong, Joe Polastre, and Gilman Tolle
 
 .. Note::
 
@@ -33,7 +30,7 @@ that provide access to sensors.
 This section describes the basic organization principles for sensor
 drivers in TinyOS.
 
-For background, a sensor may be attached to the microcontroller on a
+For background, a sensor can be attached to the microcontroller on a
 TinyOS platform through a few different types of connections:
 
  * Included within the microcontroller itself
@@ -42,47 +39,51 @@ TinyOS platform through a few different types of connections:
  * 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
+Physically, these connections can 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.
+platform, and could attach to 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
+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.
+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
+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
+Sensors, being physical devices that can be shared, can benefit from
 virtualization and arbitration. This document describes a design
-pattern for sensor virtualization that may be followed by sensor
+pattern for sensor virtualization that SHOULD be followed by sensor
 drivers.
 
-The same physical sensor may be attached to multiple different TinyOS
+The same physical sensor can 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
+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 assumes that sensors return uninterpreted values of
-arbitrary size or datatype. Conversion of sensor values to something
-with actual physical meaning is beyond the scope of this document.
+sensor itself. The naming of the sensor driver components SHOULD
+reflect the specifc name of the sensor, and MAY provide a component
+with a generic name for application authors who only care about the
+general class of the sensor.
+
+This document requires that sensor components specify the range (in
+bits) of values returned by sensor drivers, but takes no position on
+the meaning of these values. 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 obtain information (e.g. calibration
+coefficients) needed to properly interpret the value.
 
 2. Sensor HIL Components
 ====================================================================
@@ -100,17 +101,20 @@ 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.
+top-level SID interface SHOULD be delayed when the device is busy,
+rather than failing. Using one of the system arbiters can make the
+implementation of this requirement easier to accomplish.
 
 For example::
 
   generic configuration SensirionSht11C() {
     provides interface Read<uint16_t> as Temperature;
     provides interface ReadStream<uint16_t> as TemperatureStream;
+    provides interface DeviceMetadata as TemperatureDeviceMetadata;
+
     provides interface Read<uint16_t> as Humidity;
     provides interface ReadStream<uint16_t> as HumidityStream;
+    provides interface DeviceMetadata as HumidityDeviceMetadata;
   }
   implementation {
     // connect to the ADC HIL, GPIO HAL, or sensor's HAL
@@ -126,32 +130,25 @@ 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.
+some time after that call completes. Using one of the power-management
+components described in [TEP115]_ can make this implementation easier.
 
 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::
+often have levels of precision besides a multiple of 8. To account for
+such cases, each device MUST specify the precision of each one of its
+interfaces by providing 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::
+The name of the instance of DeviceMetadata MUST clearly indicate which
+interface it corresponds to.
 
-  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. 
+The getSignificantBits() call MUST return the number of significant
+bits in the reading. For example, a sensor reading taken from a 12-bit
+ADC would typically return the value 12 (it might return less if, e.g.,
+physical constraints limit the maximum A/D result to 10-bits).
 
 Sensor driver components SHOULD be named according to the make and
 model of the sensing device being presented. Using specific names
@@ -162,26 +159,30 @@ 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::
+A "common" naming layer atop a HIL might look like this::
 
   generic configuration TemperatureC() {
     provides interface Read<uint16_t>;
     provides interface ReadStream<uint16_t>;
+    provides interface DeviceMetadata;
   }
   implementation {
     components new SensirionSht11C();
     Read = SensirionSht11C.Temperature;
     ReadStream = SensirionSht11C.TemperatureStream;
+    DeviceMetadata = SensirionSht11C.TemperatureDeviceMetadata;
   }
 
   generic configuration HumidityC() {
     provides interface Read<uint16_t>;
     provides interface ReadStream<uint16_t>;
+    provides interface DeviceMetadata;
   }
   implementation {
     components new SensirionSht11C();
     Read = SensirionSht11C.Humidity;
     ReadStream = SensirionSht11C.HumidityStream;
+    DeviceMetadata = SensirionSht11C.HumidityDeviceMetadata;
   }
 
 3. Sensor HAL Components
@@ -202,10 +203,12 @@ A sensor HAL component MAY need to provide:
   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.
+- A `Resource` interface for requesting access to the device and
+  possibly performing automated power management, following
+  the conventions described in [TEP108]_ and [TEP115]_.
 
-- Any other interfaces needed to control the device.
+- Any other interfaces needed to control the device, e.g., to
+  read or write calibration coefficients.
 
 For example::
 
@@ -217,114 +220,132 @@ For example::
     // connect to the sensor's platform-dependent HPL here
   }
 
-4. Sensor HPL Components
+4. Sensor Component Organization and Compiler Interaction Guidelines
 ====================================================================
 
-A sensor HPL is necessarily platform-dependent or
-sensorboard-dependent. These components should provide access to the
-physical resources needed by the sensor, in a platform-independent
-manner that can be used by the shared logic of the sensor HAL
-components. In the case of bus-based sensors, this HPL may be nothing
-more than wiring to the appropriate bus interface for use by the HAL
-component.
+Sensors are associated either with a particular sensor board or with a
+particular platform. Both sensors and sensor boards MUST have unique
+names. Case is significant, but two sensor (or sensor board) names
+MUST differ in more than case. This is necessary to support platforms
+where filename case differences are not significant.
+
+Each sensor board MUST have its own directory whose name is the sensor
+board's unique name (referred to as <sensorboard> in the rest of this
+section). 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. Each sensor board directory
+MUST contain a ``.sensor`` file (described below). 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.
 
-For example::
+A sensor board MAY contain components that override the default TinyOS
+*demo sensors*. This allows the sensor board to easily be used with
+TinyOS sample applications that use the demo sensors. If a sensor 
+board wishes to override the default demo sensor:
 
-  configuration HplSensirionSht11C {
-    provides interface Init;
-    provides interface Resource[ uint8_t id ];
-    provides interface GeneralIO as DATA;
-    provides interface GeneralIO as SCK;
-    provides interface GpioInterrupt as InterruptDATA;
-  }
-  implementation {
-    // connect to platform or sensorboard-dependent resources
-    // power-manage the sensor through platform-specific means
-  }
+* It MUST provide a generic component named ``DemoSensorC`` with the
+  following signature::
 
-5. Directory Organization Guidelines
-====================================================================
+    provides interface Read<uint16_t>;
+    provides interface DeviceMetadata;
 
-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.
+* It MAY provide a generic component named ``DemoSensorNowC`` with the
+  following signature::
 
-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>".
+    provides interface ReadNow<uint16_t>;
+    provides interface DeviceMetadata;
 
-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.
+  This component SHOULD sample the same sensor as ``DemoSensorC``.
 
-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.
+* It MAY provide a generic component named ``DemoSensorStreamC`` with the
+  following signature::
 
-6. Authors' Addresses
+    provides interface ReadStream<uint16_t>;
+    provides interface DeviceMetadata;
+
+  This component SHOULD sample the same sensor as ``DemoSensorC``.
+
+These components MUST be an alias for one of the sensor board's usual
+sensors, though they change the precision of the sensor if necessary.
+For instance, if ``DemoSensorC`` is an alias for a 20-bit sensor that
+provides a ``Read<uint32_t>`` interface, ``DemoSensorC`` would still
+provide ``Read<uint16_t>`` and would include code to reduce the
+precision of the aliased sensor.
+
+
+4.1 Compiler Interaction
+------------------------
+
+When the ``ncc`` nesC compiler frontend is passed a ``-board=X`` option,
+it executes the ``.sensor`` file found in the sensor board directory
+``X``.  This file is a perl script which can add or modify any
+compile-time options necessary for the sensor board. It MAY modify the
+following perl variables, and MUST NOT modify any others:
+
+- ``@includes``: This array contains the TinyOS search path, i.e., the
+  directories which will be passed to nescc (the TinyOS-agnostic nesC
+  compiler) as ``-I`` arguments. You MUST add to ``@includes`` any
+  directories needed to compile this sensor board's components.  For
+  instance, if your sensor boards depends on support code found in
+  ``tos/chips/sht11``, you would add ``"%T/chips/sht11"`` to ``@includes``.
+
+- ``@new_args``: This is the array of arguments which will be passed to
+  nescc. You MUST add any arguments other than ``-I`` that are necessary
+  to compile your sensor board components to ``@new_args``.
+
+If a sensor is associated with a platform `P` rather than a sensor
+board, then that platform MUST ensure that, when compiling for
+platform `P`, all directories needed to compile that sensor's 
+component are added to the TinyOS search path (see [TEP131]_ for
+information on how to set up a TinyOS platform).
+
+4.2 Sensor Components
+---------------------
+
+A particular sensor is typically supported by many components,
+including the HIL and HAL components from Sections 2 and 3, A/D
+conversion components (for analog sensors), digital bus components
+(e.g., SPI, for digital sensors), system services (timers, resource
+and power management, ...), glue components (to connect sensors,
+sensor boards and platforms), etc.  These components can be divided
+into three classes: sensorboard-dependent, platform-dependent and
+platform-independent. The sensorboard and platform MUST ensure
+(Section 4.1) that all these components can be found at compile-time.
+
+Because the same physical sensor can be used on many platforms or
+sensor boards, and attached in many different ways, to maximize code
+reuse the organization of sensor drivers SHOULD reflect the
+distinction between sensor and sensor interconnect. The sensor
+components SHOULD be platform-independent, while the sensor
+interconnect components are typically sensorboard or
+platform-dependent. However, some sensors (e.g. analong sensors) will
+not have a sufficiently large amount of platform-independent logic to
+justify creating platform-independent components.
+
+The following guidelines specify how to organize sensor and sensor
+interconnect components within TinyOS's directory hierarchy. These
+guidelines are only relevant to components that are part of the core
+source tree. The string ``<sensor>`` SHOULD reflect the make and model
+of the sensor device.
+
+- Platform-independent sensor components 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>``.
+
+- Other platform-independent sensor components SHOULD be placed
+  in ``tos/chips/<sensor>``.
+
+- Sensorboard-dependent sensor and sensor interconnect components
+  SHOULD be placed either in the ``<sensorboard>`` directory or in a
+  ``<sensorboard>/chips/<sensor>`` directory.
+
+- Platform-dependent sensor and sensor interconnect components SHOULD
+  be placed in ``tos/<platform>/chips/<sensor>``.
+
+5. Authors' Addresses
 ====================================================================
 
 | David Gay
@@ -367,10 +388,549 @@ receives enough `-I` directives to locate all of the necessary pieces.
 |
 | email - gtolle@archrock.com
 
-7. Citations
+6. Citations
 ====================================================================
 
 .. [TEP2] TEP 2: Hardware Abstraction Architecture
+.. [TEP108] TEP 108: Resource Arbitration
 .. [TEP114] TEP 114: SIDs: Source and Sink Indepedent Drivers
 .. [TEP115] TEP 115: Power Management of Non-Virtualized Devices
+.. [TEP131] TEP 131: Creating a New Platform for TinyOS 2.x
+
+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
+
+  // HIL for the HamamatsuS1087 analog photodiode sensor
+  generic configuration HamamatsuS1087ParC() {
+    provides interface Read<uint16_t>;
+    provides interface ReadStream<uint16_t>;
+    provides interface DeviceMetadata;
+  }
+  implementation {
+    // Create a new A/D client and connect it to the Hamamatsu S1087 A/D
+    // parameters
+    components new AdcReadClientC();
+    Read = AdcReadClientC;
+
+    components new AdcReadStreamClientC();
+    ReadStream = AdcReadStreamClientC;
+
+    components HamamatsuS1087ParP;
+    DeviceMetadata = HamamatsuS1087ParP;
+    AdcReadClientC.AdcConfigure -> HamamatsuS1087ParP;
+    AdcReadStreamClientC.AdcConfigure -> HamamatsuS1087ParP;
+  }
+  
+::
+
+  tos/platforms/telosa/chips/s1087/HamamatsuS1087ParP.nc
+
+  #include "Msp430Adc12.h"
+
+  // A/D parameters for the Hamamatsu - see the MSP430 A/D converter manual,
+  // Hamamatsu specification, Telos hardware schematic and TinyOS MSP430
+  // A/D converter component specifications for the explanation of these
+  // parameters
+  module HamamatsuS1087ParP {
+    provides interface AdcConfigure<const msp430adc12_channel_config_t*>;
+    provides interface DeviceMetadata;
+  }
+  implementation {
+    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
+    };
+    async command const msp430adc12_channel_config_t* AdcConfigure.getConfiguration() {
+      return &config;
+    }
+
+    command uint8_t DeviceMetadata.getSignificantBits() { return 12; }
+  }
+
+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
+
+  // HIL for the user button sensor on Telos-family motes
+  configuration UserButtonC {
+    provides interface Get<bool>; // Get button status
+    provides interface Notify<bool>; // Get button-press notifications
+    provides interface DeviceMetadata;
+  }
+  implementation {
+
+    // Simply connect the button logic to the button HPL
+    components UserButtonLogicP;
+    Get = UserButtonLogicP;
+    Notify = UserButtonLogicP;
+    DeviceMetadata = UserButtonLogicP;
+
+    components HplUserButtonC;
+    UserButtonLogicP.GpioInterrupt -> HplUserButtonC.GpioInterrupt;
+    UserButtonLogicP.GeneralIO -> HplUserButtonC.GeneralIO;
+  }
+
+::
+
+  tos/platforms/telosa/UserButtonLogicP.nc
+  // Transform the low-level (GeneralIO and GpioInterrupt) interface to the
+  // button to high-level SID interfaces  
+  module UserButtonLogicP {
+    provides interface Get<bool>;
+    provides interface Notify<bool>;
+    provides interface DeviceMetadata;
+
+    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 the pin is high, we need to trigger on falling edge interrupt, and
+      // vice-versa
+      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();
+    }
+
+    // Button changed, signal user (in a task) and update interrupt detection
+    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();
+      }
+    }
+
+    command uint8_t DeviceMetadata.getSignificantBits() { return 1; }
+  }
+
+::
+
+  tos/platforms/telosa/HplUserButtonC.nc
+
+  // HPL for the user button sensor on Telos-family motes - just provides
+  // access to the I/O and interrupt control for the pin to which the
+  // button is connected
+  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
+  
+  // HIL interface to Sensirion SHT11 temperature and humidity sensor
+  generic configuration SensirionSht11C() {  
+    provides interface Read<uint16_t> as Temperature;
+    provides interface DeviceMetadata as TemperatureDeviceMetadata;
+    provides interface Read<uint16_t> as Humidity;
+    provides interface DeviceMetadata as HumidityDeviceMetadata;
+  }
+  implementation {
+    // Instantiate the module providing the HIL interfaces
+    components new SensirionSht11ReaderP();
+  
+    Temperature = SensirionSht11ReaderP.Temperature;
+    TemperatureDeviceMetadata = SensirionSht11ReaderP.TemperatureDeviceMetadata;
+    Humidity = SensirionSht11ReaderP.Humidity;
+    HumidityDeviceMetadata = SensirionSht11ReaderP.HumidityDeviceMetadata;
+
+    // And connect it to the HAL component for the Sensirion SHT11
+    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
+  
+  // Convert Sensirion SHT11 HAL to HIL interfaces for a single
+  // client, performing automatic resource arbitration
+  generic module SensirionSht11ReaderP() {
+    provides interface Read<uint16_t> as Temperature;
+    provides interface DeviceMetadata as TemperatureDeviceMetadata;
+    provides interface Read<uint16_t> as Humidity;
+    provides interface DeviceMetadata as HumidityDeviceMetadata;
+    
+    // Using separate resource interfaces for temperature and humidity allows
+    // temperature and humidity measurements to be requested simultaneously
+    // (if a single Resource interface was used, a request for temperature would
+    // prevent any humidity requests until the temperature measurement was complete) 
+    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() {
+      // Start by requesting access to the SHT11
+      return call TempResource.request();
+    }
+  
+    event void TempResource.granted() {
+      error_t result;
+      // If the HAL measurement fails, release the SHT11 and signal failure
+      if ((result = call Sht11Temp.measureTemperature()) != SUCCESS) {
+        call TempResource.release();
+        signal Temperature.readDone( result, 0 );
+      }
+    }
+  
+    event void Sht11Temp.measureTemperatureDone( error_t result, uint16_t val ) {
+      // Release the SHT11 and signal the result
+      call TempResource.release();
+      signal Temperature.readDone( result, val );
+    }
+
+    command uint8_t TemperatureDeviceMetadata.getSignificantBits() { return 14; }
+
+    command error_t Humidity.read() {
+      // Start by requesting access to the SHT11
+      return call HumResource.request();
+    }
+  
+    event void HumResource.granted() {
+      error_t result;
+      // If the HAL measurement fails, release the SHT11 and signal failure
+      if ((result = call Sht11Hum.measureHumidity()) != SUCCESS) {
+        call HumResource.release();
+        signal Humidity.readDone( result, 0 );
+      }
+    }
+  
+    event void Sht11Hum.measureHumidityDone( error_t result, uint16_t val ) {
+      // Release the SHT11 and signal the result
+      call HumResource.release();
+      signal Humidity.readDone( result, val );
+    }
+  
+    command uint8_t HumidityDeviceMetadata.getSignificantBits() { return 12; }
+
+    // Dummy handlers for unused portions of the HAL interface
+    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 ) { }
+  
+    // We need default handlers as a client may wire to only the Temperature
+    // sensor or only the Humidity sensor
+    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
+  
+  // HAL interface to Sensirion SHT11 temperature and humidity sensor
+  configuration HalSensirionSht11C {
+    // The SHT11 HAL uses resource arbitration to allow the sensor to shared
+    // between multiple clients and for automatic power management (the SHT11
+    // is switched off when no clients are waiting to use it)
+    provides interface Resource[ uint8_t client ];
+    provides interface SensirionSht11[ uint8_t client ];
+  }
+  implementation {
+    // The HAL implementation logic
+    components new SensirionSht11LogicP();
+    SensirionSht11 = SensirionSht11LogicP;
+  
+    // And it's wiring to the SHT11 HPL - the actual resource management is
+    // provided at the HPL layer
+    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
+
+  // Low-level, platform-specific glue-code to access the SHT11 sensor found
+  // on telos-family motes - here  the HPL just provides resource management
+  // and access to the SHT11 data, clock and interrupt pins
+  configuration HplSensirionSht11C {
+    provides interface Resource[ uint8_t id ];
+    provides interface GeneralIO as DATA;
+    provides interface GeneralIO as SCK;
+    provides interface GpioInterrupt as InterruptDATA;
+  }
+  implementation {
+    // Pins used to access the SHT11
+    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;
+  
+    // HPL logic for switching the SHT11 on and off
+    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;
+  
+    // The arbiter and power manager for the SHT11
+    components new FcfsArbiterC( "Sht11.Resource" ) as Arbiter;
+    Resource = Arbiter;
+    
+    components new SplitControlPowerManagerC();
+    SplitControlPowerManagerC.SplitControl -> HplSensirionSht11P;
+    SplitControlPowerManagerC.ArbiterInit -> Arbiter.Init;
+    SplitControlPowerManagerC.ArbiterInfo -> Arbiter.ArbiterInfo;
+    SplitControlPowerManagerC.ResourceDefaultOwner -> Arbiter.ResourceDefaultOwner;
+  }
+  
+::
+  
+  tos/platforms/telosa/chips/sht11/HplSensirionSht11P.nc
+  
+  // Switch the SHT11 on and off, and handle the 11ms warmup delay
+  module HplSensirionSht11P {
+    // The SplitControl interface powers the SHT11 on or off (it's automatically
+    // called by the SHT11 power manager, see HplSensirionSht11C)
+    // We use a SplitControl interface as we need to wait 11ms for the sensor to
+    // warm up
+    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() {
+      // Power SHT11 on and wait for 11ms
+      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() {
+      // Power the SHT11 off
+      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 );
+    }
+  }
 
+4. MDA100 Sensor Board Directory Organization
+---------------------------------------------
+
+Here we show the organization of the sensor board directory for the
+mica-family Xbow MDA100CA and MDA100CB sensor boards, which have
+temperature and light sensors. It is found in
+``tos/sensorboards/mda100``::
+
+  ./tos/sensorboards/mda100:
+  .sensor                                      # Compiler configuration
+  ArbitratedPhotoDeviceP.nc                    # Light sensor support component
+  ArbitratedTempDeviceP.nc                     # Temperature sensor support component
+  DemoSensorC.nc                               # Override TinyOS's default sensor
+  PhotoC.nc                                    # Light sensor HIL
+  PhotoImplP.nc                                        # Light sensor support component
+  PhotoTempConfigC.nc                          # Shared support component
+  PhotoTempConfigP.nc                          # Shared support component
+  SharedAnalogDeviceC.nc                       # Shared support component
+  SharedAnalogDeviceP.nc                       # Shared support component
+  TempC.nc                                     # Temperature Sensor HIL
+  ca/TempImplP.nc                              # Temperature sensor support component
+                                               # (MDA100CA board)
+  cb/TempImplP.nc                              # Temperature sensor support component
+                                               # (MDA100CB board)
+  mda100.h                                     # Header file for mda100
+
+This sensor board provides only a HIL (PhotoC and TempC components), and overrides the
+TinyOS demo sensor (DemoSensorC). The demo sensor is an alias for PhotoC.
+
+The two forms of the mda100 differ only by the wiring of the
+temperature sensor.  The user has to specify which form of the sensor
+board is in use by providing a ``-I%T/sensorboards/mda100/ca`` or
+``-I%T/sensorboards/mda100/cb`` compiler option.
+
+This sensor board relies on a platform-provided ``MicaBusC`` component
+that specifies how the mica-family sensor board bus is connected to
+the microcontroller.