TimerM
StdControl Timer
HWClock
module TimerM {
provides {
interface StdControl;
interface Timer[uint8_t id];
}
uses interface Clock;
}
implementation {
... a dialect of C ...
}
Figure 2: Specification and graphical depiction of the
TimerM component. Provided interfaces are shown above the
TimerM component and used interfaces are below. Downward
arrows depict commands and upward arrows depict events.
interface StdControl {
command result_t init();
command result_t start();
command result_t stop();
}
interface Timer {
command result_t start(char type, uint32_t interval);
command result_t stop();
event result_t fired();
}
interface Clock {
command result_t setRate(char interval, char scale);
event result_t fire();
}
interface SendMsg {
command result_t send(uint16_t address,
uint8_t length,
TOS_MsgPtr msg);
event result_t sendDone(TOS_MsgPtr msg,
result_t success);
}
Figure 3: Sample TinyOS interface types.
nents and functionality are not included in the application
binary. Inlining occurs across component boundaries and
improves both size and efficiency; Section 3.1 evaluates
these optimizations.
A component has two classes of interfaces: those it pro-
vides and those it uses. These interfaces define how the
component directly interacts with other components. An
interface generally models some service (e.g., sending a
message) and is specified by an interface type. Figure 2
shows a simplified form of the TimerM component, part
of the TinyOS timer service, that provides the StdCon-
trol and Timer interfaces and uses a Clock interface (all
shown in Figure 3). A component can provide or use the
same interface type several times as long as it gives each
instance a separate name.
Interfaces are bidirectional and contain both commands
and events. A command is a function that is implemented
by the providers of an interface, an event is a function that
is implemented by its users. For instance, the Timer inter-
face (Figure 3) defines start and stop commands and a
fired event. Although the interaction between the timer
and its client could have been provided via two separate in-
terfaces (one for its commands and another for its events),
grouping them in the same interface makes the specifica-
tion much clearer and helps prevent bugs when wiring com-
ponents together.
nesC has two types of components: modules and config-
urations. Modules provide code and are written in a dialect
of C with extensions for calling and implementing com-
HWClock
Clock
TimerC
TimerM
Clock
StdControl
Timer
StdControl
Timer
configuration TimerC {
provides {
interface StdControl;
interface Timer[uint8_t id];
}
}
implementation {
components TimerM, HWClock;
StdControl = TimerM.StdControl;
Timer = TimerM.Timer;
TimerM.Clk -> HWClock.Clock;
}
Figure 4: TinyOS’s Timer Service: the TimerC configura-
tion.
mands and events. A module declares private state vari-
ables and data buffers, which only it can reference. Config-
urations are used to wire other components together, con-
necting interfaces used by components to interfaces pro-
vided by others. Figure 4 illustrates the TinyOS timer ser-
vice, which is a configuration (TimerC) that wires the timer
module (TimerM) to the hardware clock component (HW-
Clock). Configurations allow multiple components to be
aggregated together into a single “supercomponent” that
exposes a single set of interfaces. For example, the TinyOS
networking stack is a configuration wiring together 21 sep-
arate modules and 10 sub-configurations.
Each component has its own interface namespace,
which it uses to refer to the commands and events that
it uses. When wiring interfaces together, a configuration
makes the connection between the local name of an inter-
face used by one component to the local name of the inter-
face provided by another. That is, a component invokes an
interface without referring explicitly to its implementation.
This makes it easy to perform interpositioning by introduc-
ing a new component in the component graph that uses and
provides the same interface.
Interfaces can be wired multiple times; for example, in
Figure 5 the StdControl interface of Main is wired to
Photo, TimerC, and Multihop. This fan-out is transpar-
ent to the caller. nesC allows fan-out as long as the return
type has a function for combining the results of all the calls.
For example, for result t, this is a logical-AND; a fan-
out returns failure if any subcall fails.
A component can provide a parameterized interface that
exports many instances of the same interface, parameter-
ized by some identifier (typically a small integer). For ex-
ample, the the Timer interface in Figure 2 is parameterized
with an 8-bit id, which is passed to the commands and
events of that interface as an extra parameter. In this case,
the parameterized interface allows the single Timer com-
ponent to implement multiple separate timer interfaces, one
for each client component. A client of a parameterized in-
terface must specify the ID as a constant in the wiring con-
figuration; to avoid conflicts in ID selection, nesC provides
a special unique keyword that selects a unique identifier
for each client.
Every TinyOS application is described by a top-level
configuration that wires together the components used. An
example is shown graphically in Figure 5: SurgeC is a sim-
ple application that periodically (TimerC) acquires light