nesC:
A Programming Language
for Motes
David Gay, Phil Levis, Eric Brewer, Rob von
Behren, Nikita Borisov, Mike Chen, David
Culler
Intel Research, UC Berkeley
The State of the Motes

TinyOS programs hard to write

No compiler:



verbose, unwieldy syntax
many compile-time checks missing
No support for common idioms:



state-machine-like programs
split-phase operations
atomicity guarantees, etc
A Long-term Solution

We are working on an improved language


Component-based
Better support for common idioms



split-phase ops, state-machines, etc
Clean atomicity model
Very much in the design/investigation stage
A Short-term Solution: nesC


A cleaned up language for TinyOS
Goals:




Easier to use
Allow whole-program optimisations
Base for language experimentation
Pronounced “nestlé”
nesC: Easier to Use


Nicer syntax
Check errors




Missing connections
Type errors in connections
Cycles, incorrect directions
Interfaces:

Group related functionality (caller, callee):

sendMsg:



users: call send(m), implement sendDone(m)
implementer: implement send(m), call sendDone(m)
Concise wiring
The Old Model

comp3
Components

comp1:
C code



specification:


comp2:
.desc
comp4
.comp: specification
.C: behaviour
.desc: select and wire


accepts commands
uses commands
signals events
handles events
application:
.desc
The Old Model, continued

4 kinds of components:

.desc only (ex: cnt_to_leds):


.C and .comp (ex: CLOCK):


a component implemented in C
.desc and .comp (ex: GENERIC_COMM):


top-level components and wiring for an application
a component implemented by connecting other components
.C, .comp and .desc (ex: INT_TO_RFM):

a component implemented in C with predefined wiring to other
components
The nesC Model

comp3
Components: 1 file

comp1:
module

specification
implementation



specification

comp2:
configuration
comp4
module: C behaviour
configuration:
select and wire

provides interface
requires interface
application:
configuration
The nesC Model, continued

2 kinds of components



module: was .C and .comp
configuration: was .desc and .comp
What happened to the other 2 kinds of components ?

.desc only (ex: cnt_to_leds):


use a configuration with empty specification { }
.C, .comp and .desc (ex: INT_TO_RFM):



use a configuration and module (2 files)
naming convention: IntToRfm (configuration), IntToRfmM (module)
allows module to be re-used with different wiring
Interfaces

Group related functionality, e.g.:



split-phase operation (send, sendDone)
standard control interface: init, power
Specifies bi-directional calls (defines, uses):
interface SendMsg {
defines command result_t send(uint16_t to, TOS_MsgPtr msg);
uses event result_t sendDone(TOS_MsgPtr msg, result_t ok);
}

if component C with interface I has function f:


if I is required and f is uses, C must define f
if I is provided and f is defines, C must define f
Some Interfaces
interface Leds {
defines {
command result_t
command result_t
command result_t
command result_t
...
}
}
init();
redOn();
redOff();
redToggle();
interface StdControl {
defines {
command result_t init();
command result_t power(char mode);
}
}
interface Clock {
defines command result_t setRate(char interval, char scale);
uses event result_t fire();
}
Some More Interfaces
interface ReceiveMsg {
uses event TOS_MsgPtr receive(TOS_MsgPtr m);
}
interface SendMsg {
defines command result_t send(uint16_t to, TOS_MsgPtr msg);
uses event result_t sendDone(TOS_MsgPtr msg, result_t ok);
}
interface ADC {
defines command result_t getData();
defines command result_t getContinuousData();
uses event result_t dataReady(uint16_t data);
}


But where did the Active Message type go ?
But where did the ADC port go ?
Parameterised Interfaces

Specify a numeric parameter for an interface in a component:




argument value specified in configurations
dynamic dispatch (receive, sendDone), implicit argument (send)
Like the current scheme for receiving active messages
Used also for ADC ports, exclusive EEPROM access
interface Receive {
uses event receive(MsgPtr m);
}
interface Send {
defines command send(MsgPtr m);
uses event sendDone(MsgPtr m);
}
configuration GenericComm {
provides interface Send[char id];
provides interface Receive[char id];
}
implementation { ... }
configuration MyApp ... implementation {
uses MyMain, GenericComm;
MyMain.Msg1 -> GenericComm.Send[12];
MyMain.Msg2 -> GenericComm.Receive[99];
}
module MyMain {
requires interface Send Msg1;
requires interface Receive Msg2;
}
implementation {
event Msg2.receive(MsgPtr m) {
call Msg1.send(myMsg);
}
}
Miscellaneous Features

default events and commands (cf: _NULL_FUNC)


some commands, events not always connected
specify default behaviour in the absence of connection, e.g.:
default event TOS_MsgPtr receive(TOS_MsgPtr msg)
{ return msg; }

includes is used to include C types/constants/etc for use
in an interface or component



these types are accessible to all components that use the interface
or component
use, e.g., to share packet format specification across components
nesC source code is not preprocessed
Implementation

nesc1 takes a “closed” component (no interfaces) and:

Checks nesC errors




Unknown/multiply-defined interfaces, components, etc
Connections (missing, cyclical, type-incorrect, wrong direction)
Checks (most) C errors
Generates one C-file for the application


Includes only reachable code (prunes out unreachable functions)
Generated in reverse-topological-call-order


Allows gcc’s inliner to do a much better inlining job
avr-gcc compiles nesc1 output

Generated code has #line directives, so clean error messages
Status


Compiler complete (some bugs expected)
Basic infrastructure and components for Mica



(old) radio stack
ADC, Clock, Leds, EEPROM, serial port
Apps ported:



Blink, CntTo{Leds,Rfm,LedsAndRfm}, RfmToLeds
SenseToLeds, Chirp, Oscilloscope, EEPROMTest
GenericBase
Status: Code Size
Application
C (TinyOS) nesC
Savings
Blink
CntToLeds
SenseToLeds
Oscilloscope
1092
1170
1636
2792
796
972
1086
2230
27%
17%
34%
20%
RfmToLeds
GenericBase
CntToRfm
5226
4544
5220
4168
4632
4678
20%
-2%
10%
CntToLedsAndRfm 5544
Chirp
5516
EEPROMTest
7830
4850
4948
6220
13%
10%
21%
Plans

Goal: Switch all TinyOS C code to nesC

Stage 1: convert all “standard” components & apps







Who: The TinyOS team
Support: Mica, Rene2, all sensor boards
Stage 1a: Phil Levis will “port” TOSSIM to nesC
Stage 1b: Eric Brewer will write porting guide, nesC tutorial
Stage 2: distribute nesC in next TinyOS release
Stage 3: discontinue support for macros/perl scripts
Goal: Improve nesC

See Eric’s talk
Open Issues




Naming Convention (Java-inspired)
Interface design
Revisit some component designs
Directory structure
Conclusions

nesC much nicer to use than TinyOS




nesC produces smaller code than TinyOS



No more obscure C compiler warnings/errors
No more obscure bugs due to typos
No more obscure infinite loops due to wiring restrictions
Prunes unreachable code
Inlining across component boundaries
The best is yet to come!


Short-term: multiple instantiation, better inlining selection,
packet format specification
Long-term: language improvements for bug prevention
Packet Format Specification

Write a C file with the packet type:
// IntMsg.th: The message type for IntToRfm/RfmToInt
typedef struct {
char val;
int src;
} IntMsg;
enum {
AM_INTMSG = 4
};


Use it in nesC components via includes
Automatic generation of corresponding Java type and
marshaller/unmarshaller
Components

components
module C1 {
requires interface triangle;
} implementation { ... }
module C2 {
provides interface triangle in;
requires {
interface triangle out;
interface rectangle side; }
} implementation { ... }
configuration C3 {
provides interface triangle;
provides interface rectangle;
} implementation { ... }
C1
C2
C3
Configurations

Connect components
configuration app { }
implementation {
uses c1, c2, c3;
c1 -> c2; // implicit interface sel.
c2.out -> c3.triangle;
c3 <- c2.side;
}

Partial configurations:
component c2c3 {
provides interface triangle t1;
}
implementation {
uses c2, c3;
t1 -> c2.in;
c2.out -> c3.triangle;
c3 <- c2.side;
}
C1
C2
C3
C2
C3
Modules


“C” implementation of
components
all top-level declarations
private, except those
specified in the components
interface
module C2 {
provides interface send in;
requires interface send out;
} implementation {
enum { ready, busy } state;
command in.send(Message m) {
if (state == busy) return 0;
state = busy;
call out.send(m);
return 1;
}
}
event out.send_done(Message m) {
state = ready;
signal in.send_done(m);
}
...
Descargar

Programming Languages for Motes