Peek into TinyOS Programs Vinod Kulathumani
Basics Application consists of one or more components assembled, or wired A component provides and uses interfaces. Interfaces are bidirectional: they specify a set of commands and a set of events For a component to call the commands in an interface, it must implement the events of that interface. A single component may use or provide multiple interfaces and multiple instances of the same interface. Signature - The set of interfaces a component provides + set of interfaces that a component uses
Components Two types of components in nesC modules and configurations Modules provide the implementations of one or more interfaces Configurations are used to assemble other components together connect interfaces used by components to interfaces provided by others Every nesC application described by a top-level configuration
Convention Header File abc.h Interface abc.nc Configuration abcAppC.nc Module [Public] abcC.nc Module [Private] abcP.nc
HelloAppC Configuration configuration HelloAppC { } implementation {
HelloAppC Configuration configuration HelloAppC { } implementation { components HelloC;
HelloC Module module HelloC { } implementation {
HelloC Module module HelloC { uses { interface Boot; interface Leds; } implementation {
HelloC Module module HelloC { uses { interface Boot; interface Leds; } implementation {
Boot Interface interface Boot { event void booted(); }
HelloC Module USE an interface, CAPTURE all of its events! module HelloC { uses { interface Boot; interface Leds; } implementation { event void Boot.booted() { USE an interface, CAPTURE all of its events!
Leds Interface interface Leds { command void led0On(); command void led0Off(); command void led0Toggle(); … command void set(uint8_t val); }
HelloC Module module HelloC { uses { interface Boot; interface Leds; } implementation { event void Boot.booted() { call Leds.led0On();
HelloAppC Configuration configuration HelloAppC { } implementation { components HelloC, MainC, LedsC; // USES -> PROVIDES HelloC.Boot -> MainC.Boot; HelloC.Leds -> LedsC;
Hello Application
Example 2: Blink Configuration – BlinkAppC.nc Module – BlinkC.nc
Configuration configuration BlinkAppC { } implementation {
Implementation module BlinkC { } implementation {
Configuration components list configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new TimerMilliC() as Timer0; components new TimerMilliC() as Timer1; components new TimerMilliC() as Timer2;
Module provides / uses Module BlinkC{ uses interface Timer<TMilli> as Timer0; uses interface Timer<TMilli> as Timer1; uses interface Timer<TMilli> as Timer2; uses interface Leds; uses interface Boot; } implementation { // implementation code omitted
Module provides / uses Module BlinkC{ uses interface Timer<TMilli> as Timer0; uses interface Timer<TMilli> as Timer1; uses interface Timer<TMilli> as Timer2; uses interface Leds; uses interface Boot; } implementation { event void Boot.booted() { call Timer0.start(); …. event Timer0.fired() { … event Timer1.fired() { …
Configuration wiring configuration BlinkAppC { } implementation { components MainC, BlinkC, LedsC; components new TimerMilliC() as Timer0; components new TimerMilliC() as Timer1; components new TimerMilliC() as Timer2; BlinkC.Boot -> MainC.Boot; BlinkC.Timer0 -> Timer0; BlinkC.Timer1 -> Timer1; BlinkC.Timer2 -> Timer2; BlinkC.Leds -> LedsC;
Radio Stacks Your Application Message Queue ActiveMessage AMSend SplitControl Receive Message Queue ActiveMessage CSMA / Acknowledgements Transmit / Receive / Init Radio Hardware
Main Radio Interfaces SplitControl AMSend Receive Provided by ActiveMessageC AMSend Provided by AMSenderC Receive Provided by AMReceiverC
Main Serial Interfaces SplitControl Provided by SerialActiveMessageC AMSend Provided by SerialAMSenderC Receive Provided by SerialAMReceiverC
Setting up the Radio: Configuration configuration MyRadioAppC { } implementation { components MyRadioC, MainC, ActiveMessageC, new AMSenderC(0) as Send0, // send an AM type 0 message new AMReceiverC(0) as Receive0; // receive an AM type 0
Setting up the Radio: Module module MyRadioC { uses { interface Boot; interface SplitControl; interface AMSend; interface Receive; } implementation {
Turn on the Radio event void Boot.booted() { call SplitControl.start(); } event void SplitControl.startDone(error_t error) { post sendMsg(); event void SplitControl.stopDone(error_t error) {
Setting up the Radio: Configuration configuration MyRadioAppC { } implementation { components MyRadioC, MainC, ActiveMessageC, new AMSenderC(0) as Send0, // send an AM type 0 message new AMReceiverC(0) as Receive0; // receive an AM type 0 MyRadioC.Boot -> MainC; MyRadioC.SplitControl -> ActiveMessageC; MyRadioC.AMSend -> Send0; MyRadioC.Receiver -> Receive0;
Payloads A message consists of: Header Payload Optional Footer
message_t typedef nx_struct message_t { nx_uint8_t header[sizeof(message_header_t)]; nx_uint8_t data[TOSH_DATA_LENGTH]; nx_uint8_t footer[sizeof(message_footer_t)]; nx_uint8_t metadata[sizeof(message_metadata_t)]; } message_t;
Payloads : Use Network Types (MyPayload.h) typedef nx_struct MyPayload { nx_uint8_t count; } MyPayload;
Send Messages message_t myMsg; bool sending=false; task void sendMsg() { MyPayload *payload = (MyPayload *)call ASMSend.getPayload(&myMsg); payload->count = (myCount++); if (sending==false) { error_t p; p = call AMSend.send(AM_BROADCAST_ADDR, myMsg, 0); If (p==SUCCESS) sending=true; else post sendMsg(); } event void AMSend.sendDone(message_t *msg, error_t error) { sending=false;
Receive a Message event message_t *Receive.receive(message_t *msg, void *payload, uint8_t length) { MyPayload* pkt = (MyPayload *)payload; uint8_t ct = pkt->count; call Leds.led0Toggle(); return msg; }
RealMainP module RealMainP { provides interface Boot; uses { interface Scheduler; interface Init as PlatformInit; interface Init as SoftwareInit; } } Implementation{ // platform initialization stuff call SoftwareInit.init() signal Boot.booted(); // call scheduler task loop
SoftwareInit in RealMainP Suppose user writes module RandomIntC provides an interface Init should be initialized before use (to generate seed) what if application developer forgets Instead write a configuration RandomC around RandomIntC Module RandomC { provides interface Init; } Implementation RandomC{ components MainC, RandomIntC; MainC.SoftwareInit -> RandomIntc.Init;
SoftwareInit in RealMainP So far we didn’t care in our examples All our examples were applications Did not provide interface Interior components that provide interface may need Init MainC.SoftwareInit may be wired to many Inits Each will be called in sequence
References TinyOS Tutorials – www.tinyos.net David Moss TinyOS 2 tutorial