Page 1
1Software Development Infrastructure for Sensor Networks Operating systems (TinyOS)
Resource (device) management Basic primitives Protocols (MAC, routing) {covered in many previous lectures}
Programming languages and runtime environments Low level (C, nesC) Very high level abstractions (Regiment)
Services needed Synchronization of clocks (RBS) Propagation of new code to all nodes (Trickle) Localization {not today}
Page 2
2Maintenance overheadsRadio transmission scheduling (e.g. TDMA)
+Route discovery & maintenance
+ Clock synchronization
+Code propagation protocol
+Sensor data delivery
System
Application
Be aware of all the background message activitywhen designing application-level suppression.
Page 3
Programming Platform for Sensor Networks: TinyOS
Complements of Jun YangWith contents from D.-O. Kim, D. Culler,
W. Xu
Page 4
4Challenges in programming sensors WSN usually has severe power,
memory, and bandwidth limitations WSN must respond to multiple,
concurrent stimuli At the speed of changes in monitored
phenomena WSN are large-scale distributed
systems
Page 5
5Traditional embedded systems
Event-driven execution and real-time scheduling General-purpose layers are often bloated !
microkernel Strict layering often adds overhead ! expose
hardware controls
Page 6
6Node-level methodology and platform Traditional design methodologies are
node-centric Node-level platforms
Operating system• Abstracts the hardware on a sensor node• Provides services for apps such as, traditionally,
file management, memory allocation, task scheduling, device drivers, networking…
Language platform• Provides a library of components to
programmers
Page 7
7TinyOS Started out as a research project at Berkeley Now probably the de facto platform
Overarching goal: conserving resources No file system No dynamic memory allocation No memory protection Very simple task model Minimal device and networking abstractions Application and OS are coupled—composed
into one image Both are written in a special language nesC
Page 8
8TinyOS components Components: reusable building blocks Each component is specified by a set of interfaces
Provide “hooks” for wiring components together A component C can provide an interface I
C must implement all commands available through I Commands are methods exposed to an upper layer
• An upper layer can call a command A component C can use an interface J
C must implement all events that can be signaled by J These are methods available to a lower layer
• By signaling an event, the lower layer calls the appropriate handler
Components are then wired together into an application
CI
J
Page 9
9Component specificationmodule TimerModule { provides { interface StdControl; interface Timer01; } uses interface Clock as Clk;}…
interface StdControl { command result_t init(); command result_t start(); command result_t stop();}
interface Timer01 { command result_t start(char type, uint32_t interval); command result_t stop(); event result_t timer0Fire(); event result_t timer1Fire();}interface Clock { command result_t setRate(char interval, char scale); event result_t fire();}
TimerModule
Page 10
10Module vs. configurations Two types of components
Module: implements the component specification (interfaces) with application code
Configuration: implements the component specification by wiring existing components
Page 11
11Module implementationmodule TimerModule { provides { interface StdControl; interface Timer01; } uses interface Clock as Clk;}implementation { bool eventFlag; command result_t StdControl.init() { eventFlag = 0; return call Clk.setRate(128, 4); // 4 ticks per sec } event result_t Clk.fire() { eventFlag = !eventFlag; if (eventFlag) signal Timer01.timer0Fire(); else signal Timer01.timer1Fire(); return SUCCESS; } …}
Just like method calls (unlike raising exceptions in Java, e.g.)
Internal state
Page 12
12Configuration implementation
= (equate wire) At least one must be external
! (link wire) Both internal; goes from user to provider
configuration TimerConfiguration { provides { interface StdControl; interface Timer01; }}implementation { components TimerModule, HWClock; StdControl = TimerModule.StdControl; Timer01 = TimerModule.Timer01; TimerModule.Clock ! HWClock.Clock;}
TimerModule
HWClockTim
erCo
nfigu
ratio
n
Page 13
13Commands vs. events{ … status = call UsedInterfaceName.cmdName(args); …} event UsedInterfaceName.eventName(args) {
… return status;}
command cmdName(args) { … return status;}
{ … status = signal ProvidedInterfaceName.eventName(args); …}
Page 14
14FieldMonitor example
Page 15
16Concurrency modelTwo types of execution contexts Tasks
Longer running jobs Time flexible (Currently) simple FIFO scheduling Atomic w.r.t. other tasks, i.e., single-threaded But can be preempted by events
Events (an overloaded term) More precisely, hardware interrupt handlers Time critical Shorten duration as much as possible
• By issuing tasks for later execution LIFO semantics; can preempt tasks and earlier events
Page 16
17Tasks A task is always posted for later
execution; control returns to poster immediately
Scheduler supports a bounded queue of pending tasks Node sleeps when the queue is
empty For simplicity, tasks don’t take
args and don’t return values Typical use
Event necessitates further processing
• Wrap it up in a task Event handler simply posts the task
and can return immediately
implementation { task void TaskName() { … } … … { … post TaskName(); … }}
Page 17
18Execution example
Task A Task B Task C …
Task queueTask BTask C
…Event 1Event 2Event 3
Hardware interrupts
Page 18
19A more complex example Timer01.Timer0Fire()
triggers data acquisition (through ADC) and transmission to base station (through Send)
module SenseAndSend { provides interface StdControl; uses { interface ADC; interface Timer01; interface Send; }}implementation { bool busy; norace unit16_t sensorReading; … command result_t StdControl.init() { busy = FALSE; } event result_t Timer01.Timer0Fire() { bool localBusy; atomic { localBusy = busy; busy = TRUE; } if (!localBusy) { call ADC.getData(); return SUCCESS; } else { return FAILED; } } task void sendData() { … adcPacket.data = sensorReading; … call Send.send(&adcPacket, sizeof(adcPacket.data)); return SUCCESS; } event result_t ADC.dataReady(uint16_t data) { sensorReading = data; post sendData(); atomic { busy = FALSE; } return SUCCESS; } …}
Page 19
20Split-phase operation
Data acquisition doesn’t take place immediately (why?) How does a traditional OS accomplish this?
OS puts thread to sleep when it blocks Why isn’t this approach good enough here?
event result_t Timer01.Timer0Fire() { bool localBusy; atomic { localBusy = busy; busy = TRUE; } if (!localBusy) { call ADC.getData(); return SUCCESS; } else { return FAILED; } } event result_t ADC.dataReady(uint16_t data) { sensorReading = data; post sendData(); atomic { busy = FALSE; } return SUCCESS; }
Page 20
21Posting task in interrupt handler
Why? Make asynchronous code as short as
possible
task void sendData() { … adcPacket.data = sensorReading; … call Send.send(&adcPacket, sizeof(adcPacket.data)); return SUCCESS; } event result_t ADC.dataReady(uint16_t data) { sensorReading = data; post sendData(); atomic { busy = FALSE; } return SUCCESS; }
Page 21
22Race conditions Because of
preemption, race conditions may arise on shared data nesC compiler can
detect them, but with false positives
In case of false positive, declare shared variable with norace keyword
In case of real race conditions, use atomic to make code blocks non-preemptible
bool busy; norace unit16_t sensorReading; … event result_t Timer01.Timer0Fire() { bool localBusy; atomic { localBusy = busy; busy = TRUE; } if (!localBusy) { call ADC.getData(); return SUCCESS; } else { return FAILED; } } task void sendData() { … adcPacket.data = sensorReading; … call Send.send(&adcPacket, sizeof(adcPacket.data)); return SUCCESS; } event result_t ADC.dataReady(uint16_t data) { sensorReading = data; post sendData(); atomic { busy = FALSE; } return SUCCESS; }
Ensures at most one outstanding ADC request at all times
Page 22
23Discussion ?What are the first low level details of
programming to TinyOS that you would like to abstract away?
Page 23
24Discussion Provides framework for concurrency
and modularity Interleaves flows, events, energy
management Never poll, never block Trade off flexibility for more
optimization opportunities Still a node-level platform How do we go from individual sensors to a
sensor field?
Page 24
25Software Development Infrastructure for Sensor Networks Operating systems (TinyOS)
Resource (device) management Basic primitives Protocols (MAC, routing) {covered in many previous lectures}
Programming languages and runtime environments Low level (C, nesC) Very high level abstractions (Regiment)
Services needed Synchronization of clocks (RBS) Propagation of new code to all nodes (Trickle) Localization {not today}