230 likes | 536 Views
LAB (Embedded System): Programming on Sensor Networks. TinyOS and NesC. What is TinyOS?. NesC A superset of C Main feature: Component based programming with separation of declaration and definition TinyOS An event-driven operating system Developed using NesC
E N D
LAB (Embedded System): Programming on Sensor Networks TinyOS and NesC
What is TinyOS? • NesC • A superset of C • Main feature: • Component based programming with separation of declaration and definition • TinyOS • An event-driven operating system • Developed using NesC • Support for many types of motes • At least 15 Motes types are supported by NesC/TinyOS (source: SNM)
NesC Concepts • Component • Module • Configuration • Interface • Command (Sync Vs Async Commands) • Event • Split-Phase • Task
Let’s start simple • Goal: write an anti-theft device. • Two parts: • Detecting theft. • Assume: thieves put the motes in their pockets. • So, a “dark” mote is a stolen mote. • Theft detection algorithm: every N ms check if light sensor is below some threshold • Reporting theft. • Assume: bright flashing lights deter thieves. • Theft reporting algorithm: light the red LED for a little while! • What we’ll see • Basic components, interfaces, wiring • Essential system interfaces for startup, timing, sensor sampling
Components • A component is based on C dialect • A component is similar to Java object • It provides encapsulated state and couple state with functionality • A component is not really a Java object • No inheritance and usually Singleton • Components have only private variables • Only functions could be used to pass the variables between components • Two types of components • Modules • Configuration
Data Type declaration uint8_t int8_t uint16_t int16_t bool Components #include … moduleAntiTheftC { uses interface ….; } implementation { int8_t var1; } configuration AntiTheftAppC { } implementation { components AntiTheftC , ..; ….. }
Module & Interface • Module has implementation of functions • It uses pure local namespace • Component has to declare function it uses and provides • NesC Interface is very Similar to Java Interface • Declaration of functions
Interface interface Boot { /* Signaled when OS booted */ event void booted(); } interface Timer<tag> { command void startOneShot(uint32_t period); command void startPeriodic(uint32_t period); event void fired(); } interface Read<val_t> { command error_t read(); event void readDone(error_t ok, val_t val); }
interface Boot { /* Signaled when OS booted */ event void booted(); } interface Timer<tag> { command void startOneShot(uint32_t period); command void startPeriodic(uint32_t period); event void fired(); } Module & Interface module AntiTheftC { uses interface Boot; uses interface Timer<TMilli> as Check; uses interface Read<uint16_t>; } implementation { event void Boot.booted() { call Check.startPeriodic(1000); } event void Check.fired() { call Read.read(); } event void Read.readDone(error_t ok, uint16_t val) { if (ok == SUCCESS && val < 200) theftLed(); } } Programs are built out of named components A component provides and uses interfaces Interfaces contain commands and events, which are just functions A module is a component implemented in C
Module & Interface Interfaces specify the interaction between two components, the provider and the user. This interaction is just a function call. commands are calls from user to provider events are calls from provider to user module AntiTheftC { uses interface Boot; uses interface Timer<TMilli> as Check; uses interface Read<uint16_t>; } implementation { event void Boot.booted() { call Check.startPeriodic(1000); } event void Check.fired() { call Read.read(); } event void Read.readDone(error_t ok, uint16_t val) { if (ok == SUCCESS && val < 200) theftLed(); } } interface Boot { /* Signaled when OS booted */ event void booted(); } interface Timer<tag> { command void startOneShot(uint32_t period); command void startPeriodic(uint32_t period); event void fired(); }
Module & Interface module AntiTheftC { uses interface Boot; uses interface Timer<TMilli> as Check; uses interface Read<uint16_t>; } implementation { event void Boot.booted() { call Check.startPeriodic(1000); } event void Check.fired() { call Read.read(); } event void Read.readDone(error_t ok, uint16_t val) { if (ok == SUCCESS && val < 200) theftLed(); } } • All long-running operations are split-phase: • A command starts the op: read • An event signals op completion: readDone interface Read<val_t> { command error_t read(); event void readDone(error_t ok, val_t val); }
Module & Interface module AntiTheftC { uses interface Boot; uses interface Timer<TMilli> as Check; uses interface Read<uint16_t>; } implementation { event void Boot.booted() { call Check.startPeriodic(1000); } event void Check.fired() { call Read.read(); } event void Read.readDone( error_t ok, uint16_t val) { if (ok == SUCCESS && val < 200) theftLed(); } } • All long-running operations are split-phase: • A command starts the op: read • An event signals op completion: readDone • Errors are signalled using the error_t type, typically • Commands only allow one outstanding request • Events report any problems occurring in the op interface Read<val_t> { command error_t read(); event void readDone(error_t ok, val_t val); }
Module & Interface module TimerMilliC{ provides interface Timer<TMilli> as TimerMilli[uint8_t num]; } implementation { ..... command void TimerMilli.startPeriodic[uint8_t id]( uint32_t dt ) { ... } command void TimerMilli.startOneShot[uint8_t id]( uint32_t dt ) { .... } void tossim_timer_handle(sim_event_t* evt) { .. signal TimerMilli.fired[id](); } }
Configuration • Recall: Components have two types • Module • Configuration • Configuration • Wire components together • Has two operations • user -> provider (or provider <- ser) • = (between two providers mostly) • To export interface
Configurations generic configuration TimerMilliC() { provides interface Timer<TMilli>; } implementation { ... } configuration AntiTheftAppC { } implementation { components AntiTheftC, MainC, LedsC; AntiTheftC.Boot -> MainC.Boot; AntiTheftC.Leds -> LedsC; components new TimerMilliC() as MyTimer; AntiTheftC.Check -> MyTimer; components new PhotoC(); AntiTheftC.Read -> PhotoC; } generic configuration PhotoC() { provides interface Read; } implementation { ... } A configuration is a component built out of other components. It wires “used” to “provided” interfaces. It can instantiate generic components It can itself provide and use interfaces
Split-Phase • Split-phase in hardware then split-phase in software • Two phase • Downcall : Command – start the operation • Upcall : Event – operation has been completed
Command & Event • All commands are implemented by all providers of an interface • All events are implemented by all users of an interface • Example Interface Send { command error_t send(message_t* msg, uint8_t len); event void sendDone(message_t* msg, error_t error); } module SendC { uses interface Send; uses interface Boot; } Implementation { event void Boot.booted() { call Send.send(NULL, 0); } event void sendDone(message_t* msg, error_t error) { //do nothing } }
Task • Task • Are deferred procedure call • Event are usually signaled by posting a task • Task are strictly local to a module • No parameters • No return type • No defined in any interface • Each task is non-preemptive and atomic with respect to other tasks • A task can post itself
Async Vs Sync command • Async are preemptable commands • Unlike task Async commands are not atomic with respect to other commands • Async command cannot call a Sync command • Can call other Async commands • Can post task which may call a Sync command • Sync commands calls are blocking like normal function call
TinyOS and NesC limitations • Thread Vs event driven • TinyOS is event-driven and not a thread base OS • Threads have better response time • Event drive OS has less memory requirements • Event driven model drawbacks: • requires manual configuration • Manual state handling • Difficult to change code without changing already written state handlers • All Events have to be implemented by a user of an interface • Even if user of a interface is not interested in many of them
Exercise 1 • Take a random number in every 1000ms • If it is even then toggle the led0 • If there are two consecutive even numbers, toggle the led1 • If there are two consecutive odd numbers, toggle the led2 module XYZ{ uses interface Random; } implementation { } configuration XYZC{} implementation { ….. components RandomLfsrC; }
Exercise 2 • Take a random number in every 1000ms • NODE 1: If the number is even, sends it to NODE 2 then toggle the led0, NODE 2 receives the packet check the number is even and toggle led 0 • NODE 2: If the number is odd, sends it to NODE 1 then toggle the led2, NODE 1 receives the packet check the number is odd and toggle led 2