182 704 building reliable distributed systems lu
play

182.704 Building Reliable Distributed Systems LU Matthias Fgger, - PowerPoint PPT Presentation

182.704 Building Reliable Distributed Systems LU Matthias Fgger, Alexander Kler, Ulrich Schmid WS 2014 course Wireless Nodes, nesC, TinyOS The target systems Wireless motes cluster ATAVRRZ200 demonstration kit from Atmel >= 4 motes


  1. 182.704 Building Reliable Distributed Systems LU Matthias Függer, Alexander Kößler, Ulrich Schmid WS 2014 course Wireless Nodes, nesC, TinyOS

  2. The target systems Wireless motes cluster ATAVRRZ200 demonstration kit from Atmel >= 4 motes a single mote AT86RF230 radio transceiver 2450 MHz band ATmega 1281V MC

  3. First steps 1. get your accounts 2. login to a PC in ECS lab and get a copy of TinyOS git clone ssh://trac/ecs/repo/git/lva/brds/tinyos 3. set environment variables (.bashrc) export TOSROOT="/homes/koe/tinyos" export TOSDIR="$TOSROOT/tos" export MAKERULES="$TOSROOT/support/make/Makerules" 4. in apps/Blink/ execute make rz200 5. connect mote via programmer and execute make rz200 install Binary is generated and downloaded via avrdude

  4. ncc – nesc compiler for tinyos > make iris ncc -o build/iris/main.exe -Os -Wall -Wshadow -Wnesc-all -target=iris -fnesc-cfile=build/iris/app.c -board=micasb -DDEFINED_TOS_AM_GROUP=0x22 --param max-inline-insns-single=100000 -DIDENT_APPNAME=\"BlinkAppC\" -DIDENT_USERNAME=\"fuegger\" -DIDENT_HOSTNAME=\"ecslab6\ „ -DIDENT_USERHASH=0x894ea284L -DIDENT_TIMESTAMP=0x4bc706feL -DIDENT_UIDHASH=0xee40a21fL -fnesc-dump=wiring -fnesc-dump='interfaces(!abstract())' -fnesc-dump='referenced(interfacedefs, components)' -fnesc-dumpfile=build/iris/wiring-check.xml BlinkAppC.nc -lm compiled BlinkAppC to build/iris/main.exe 2268 bytes in ROM 51 bytes in RAM avr-objcopy --output-target=srec build/iris/main.exe build/iris/main.srec avr-objcopy --output-target=ihex build/iris/main.exe build/iris/main.ihex writing TOS image ncc calls nescc, which calls gcc

  5. Memory requirements ATmega1281/V usage: Flash: 128KB EEPROM: 4KB RAM: 8KB  2268 bytes in ROM = 2.3 KB (1.7%) [.text segment size] 51 bytes in RAM = 0.05 KB (0.4%) [.bss segment size] This is quite bad for a blinking application, but good for an operating system!

  6. A threaded version in apps/tosthreads/apps/Blink/ execute > make rz200 threads tells nesc to use thread lib instead  5358 bytes in ROM = 5.3 KB (4.1%) 993 bytes in RAM= 1.0 KB (12.1%) The latter is problematic (only static variables, no dynamic varibles yet). Context switching needs quite some memory!

  7. Where to find code? apps/ example applications apps/tosthreads/apps/ example TOSthreads applications tos/interfaces all the interfaces tos/system/ major hardware independent code, implementing interfaces tos/chips + tos/platforms hardware dependent code tos/lib/ TinyOS add-ons ( timer , radio transceiver, TOSthreads, …)

  8. Example Blink BlinkC.nc #include "Timer.h" module BlinkC { uses interface … provides interface … } BlinkC

  9. Example Blink BlinkC.nc interface Timer<precision_tag> { #include "Timer.h" command void startPeriodic (uint32_t dt); command void startOneShot(uint32_t dt); module BlinkC command void stop(); { event void fired (); uses interface Timer<TMilli> as Timer0; uses interface Timer<TMilli> as Timer1; command bool isRunning(); uses interface Timer<TMilli> as Timer2; command bool isOneShot(); } command void startPeriodicAt(uint32_t t0, uint32_t dt); command void startOneShotAt(uint32_t t0, uint32_t dt); command uint32_t getNow(); BlinkC command uint32_t gett0(); command uint32_t getdt(); } event command interfaces can be typed general interfaces - Timer0 for compile-time wiring checking - more than 1 interface per module possible!

  10. Command/event model Command/event model functions, commands, events, tasks function (inside Module) uint8_t myFunction(uint8_t x) {…} y = myFunction(x); command (between Modules) (async) command uint8_t myInterface.myCommand(uint8_t x) {…} y = call myInterface.myCommand(x); event (between Modules) (async) event void myInterface.mySignal(uint8_t x) {…} signal myInterface.mySignal(x); task (inside Module – main execution primitive) task void myTask() {…} post myTask();

  11. Command/event model Split phase (call back) a longer computation (1) call f(x) returns; y = f(x) f(x) call f(x) returns signals f(x); y = f(x) (2) start f(x) f(x) done

  12. Command/event versus task What to do and what not (deferred procedure calls) (1) call f(x); f(x) signal/call g(y); g(y) etc... call f(x); (2) f(x) post g(); g(y)

  13. Command/event versus task What to do and what not (deferred procedure calls) in some module’s implementation that provides the interface Someone: x:= 0; // in implementation scope command error_t Someone.doThis() { // do it and obtain x x := f(.); signal Someone.done(x); } some other module which uses Someone to repeatedly do this: .... for (uint8_t i=0; i++; i < 10) { Someone.doThis(); } .... event void Someone.done(uint8_t x) { // obtain x }

  14. Command/event versus task What to do and what not (deferred procedure calls) in some module’s implementation that provides the interface Someone: command error_t Someone.doThis() { // dot it and obtain x x = 1; signal Someone.done(x); } a “clever” solution: ... i:= 0; Someone.doThis(); ... event void Someone.done(uint8_t x) { // obtain x i++; if (i < 10) { Someone.doThis(); } }

  15. Command/event versus task What to do and what not (deferred procedure calls) in some module’s implementation that provides the interface Someone: original implementation task implementation command error_t Someone.doThis() { command error_t Someone.doThis() { // dot it and obtain x // dot it and obtain x x = 1; x = 1; signal Someone.done(x); return post Someone.doneTask; } } task void doneTask() { signal Someone.done(x); now we can use: } ... i:= 0; Someone.doThis(); ... event void Someone.done(uint8_t x) { // obtain x i++; if (i < 10) { Someone.doThis(); } }

  16. Example Blink BlinkC.nc implementation { event void Boot.booted() #include "Timer.h" { call Timer0.startPeriodic( 250 ); module BlinkC call Timer1.startPeriodic( 500 ); { call Timer2.startPeriodic( 1000 ); uses interface Timer<TMilli> as Timer0; } uses interface Timer<TMilli> as Timer1; event void Timer0.fired() uses interface Timer<TMilli> as Timer2; { uses interface Leds; call Leds.led0Toggle(); uses interface Boot; } } BlinkC event void Timer1.fired() { uses call Leds.led1Toggle(); } Timer0 Timer1 Timer2 Leds Boot event void Timer2.fired() { call Leds.led2Toggle(); } }

  17. Example Blink BlinkC.nc BlinkAppC.nc -> wiring from user to provider #include "Timer.h" configuration BlinkAppC { module BlinkC } { implementation uses interface Timer<TMilli> as Timer0; { uses interface Timer<TMilli> as Timer1; components MainC, BlinkC, LedsC; uses interface Timer<TMilli> as Timer2; components new TimerMilliC() as Timer0; uses interface Leds; components new TimerMilliC() as Timer1; uses interface Boot; components new TimerMilliC() as Timer2; } long version: BlinkC BlinkC.Boot -> MainC.Boot; BlinkC -> MainC.Boot; BlinkC.Timer0 -> Timer0.Timer; BlinkC.Timer0 -> Timer0; uses BlinkC.Timer1 -> Timer1.Timer; BlinkC.Timer1 -> Timer1; BlinkC.Timer2 -> Timer2.Timer; BlinkC.Timer2 -> Timer2; BlinkC.Leds -> LedsC.Leds; BlinkC.Leds -> LedsC; Timer0 Timer1 Timer2 Leds Boot } provides TimerMilliC TimerMilliC TimerMilliC LedsC MainC

  18. Booting tos/system/MainC #include "hardware.h" configuration MainC { provides interface Boot; uses interface Init as SoftwareInit; } implementation { components PlatformC, RealMainP , TinySchedulerC; RealMainP.Scheduler -> TinySchedulerC; RealMainP.PlatformInit -> PlatformC; // Export the SoftwareInit and Booted for applications SoftwareInit = RealMainP.SoftwareInit; Boot = RealMainP; }

  19. Booting tos/system/RealMainC module RealMainP @safe() { implementation { provides interface Boot; int main() @C() @spontaneous() { uses interface Scheduler; atomic uses interface Init as PlatformInit; { uses interface Init as SoftwareInit; platform_bootstrap(); } call Scheduler.init(); call PlatformInit.init(); while (call Scheduler.runNextTask()); call SoftwareInit.init(); while (call Scheduler.runNextTask()); } __nesc_enable_interrupt(); signal Boot.booted(); call Scheduler.taskLoop(); return -1; } default command error_t PlatformInit.init() { return SUCCESS; } default command error_t SoftwareInit.init() { return SUCCESS; } default event void Boot.booted() { } }

  20. TinyOS Scheduling Policies  Non-Preemptive FIFO • Small • Easy • Fast  Thread Based Priority Queues using Preemptive Jobs • Bigger • Not that easy • „Slow“

  21. Concurrency in nesC Execution model in nesC is „ run-to-completion “ tasks  • No preemption • Atomic with respect to other tasks • Not atomic with respect to interrupt handlers  Code divided into two parts: • Syncronous Code: functions, commands, events, tasks that are only reachable from tasks • Asyncronous Code: used in interrupt handlers (must be marked async)  Race conditions: • No race conditions between tasks • Avoid race conditions by protection through an atomic statement • Calls to functions are only protected if every call is protected • Compiler detects race conditions

  22. nesC Tasks in TinyOS 2.x post processTask(); … task void processTask() { //do work if (moreToProcess){ post processTask(); } } post will only fail iff the task is already posted but execution has not started yet

Recommend


More recommend