Architectures and Applications for Wireless Sensor ...cpj/204525/slides/02a-Programming.pdf ·...

Preview:

Citation preview

Architectures and Applications for Wireless Sensor Networks (01204525)

Node Programming

Chaiporn Jaikaeochaiporn.j@ku.ac.th

Department of Computer EngineeringKasetsart University

2

Outline

Microcontroller programming

Software development cycle

Hardware abstraction

Event-driven programming model

Multithreaded programming model

Tmote Sky

3

For microcontrollers with bootstrap loader (BSL) installed

4

Microcontroller

flash

memory

Bootstrap

Loader

Typical Development Process

Source code (C/Assembly)

Cross Compiler/Assembler

Machine code

Serial/USB

5

Build a Simple Application

Let's build a simple application

Make mote output something

What can be used as output?

6

Tmote Sky's Schematic Available on LMS

7

Example: Blinking Sky LED

Task: turn the blue LED on/off repeatedly

Idea

Configure pin P5.6 for output

Repeatedly set the pin logic level to 0 and 1

Add some delay before toggling pin level

Directory Structure

Create a new folder sky-apps

8

sky-apps

blink.c

Makefile

Code – blink.c

9

#include <msp430x16x.h>

int main()

{

WDTCTL = WDTPW | WDTHOLD;

P5DIR |= (1 << 6);

for (;;)

{

P5OUT |= (1 << 6);

__delay_cycles(500000L);

P5OUT &= ~(1 << 6);

__delay_cycles(500000L);

}

return 0;

}

Make P5.6 output

Send logic 1 to P5.6

Send logic 0 to P5.6

Stop watchdog timer

blink.c

Compiling

Make an ELF binary by running cross compiler

Extract machine code into ihex format

10

$ msp430-gcc -mmcu=msp430f1611 -o blink.elf blink.c

$ msp430-objcopy --output-target=ihex blink.elf blink.hex

11

Uploading Machine Code

Plug a Sky mote into a USB port and make sure it is recognized by the OS

Send the machine code to BSL

$ <contiki-dir>/tools/sky/msp430-bsl-linux --telosb \-c <serial-device> -r –e –I –p blink.hex

$ <contiki-dir>/tools/sky/mote-list-<os>

Creating Makefile

Makefile helps avoid repetitive typing

Run make upload DEVICE=<serial-device>

12

CC=msp430-gcc

CFLAGS=-mmcu=msp430f1611

OBJCOPY=msp430-objcopy

CONTIKI=$(HOME)/src/contiki-dev

PROJECT=blink

all: $(PROJECT).hex

upload: $(PROJECT).hex

$(CONTIKI)/tools/sky/msp430-bsl-linux --telosb -c $(DEVICE) -r -e -I -p $<

%.hex: %.elf

$(OBJCOPY) --output-target=ihex $< $@

%.elf: %.c

$(CC) $(CFLAGS) -o $@ $<

Makefile

Exercise: Blue Beacon

Modify blink.c so that it repeatedly

turns Blue LED on for ~0.1 second

turns Blue LED off for ~1 second

13

Blink in Another Platform

E.g., AVR microcontroller

14

#include <avr/io.h>

#include <util/delay.h>

int main()

{

DDRD |= (1 << 5); // Make PD5 output

while (1)

{

PORTD |= (1 << 5); // Send logic 1 to PD5

_delay_ms(1000);

PORTD &= ~(1 << 5); // Send logic 0 to PD5

_delay_ms(1000);

}

return 0;

}

15

Hardware Abstraction

Tmote Sky Hardware

Tmote Sky API Implementation

Contiki Directory Structure

Create a new folder contiki-app

16

contiki-apps

blink.c

Makefile

Blink – with Contiki

17

#include "contiki.h"

#include "dev/leds.h"

/*------------------------------------------------------*/

PROCESS(blink_process, "Blink Application");

AUTOSTART_PROCESSES(&blink_process);

/*------------------------------------------------------*/

PROCESS_THREAD(blink_process, ev, data)

{

PROCESS_BEGIN();

watchdog_stop();

for (;;)

{

leds_off(LEDS_BLUE);

clock_wait(CLOCK_SECOND/2);

leds_on(LEDS_BLUE);

clock_wait(CLOCK_SECOND/2);

}

PROCESS_END();

}

blink.c

Contiki Makefile

Make sky the default platform

Build and upload the application

18

CONTIKI_WITH_RIME = 1

CONTIKI = <your-contiki-location>

include $(CONTIKI)/Makefile.include

Makefile

$ make TARGET=sky savetarget

$ make blink.upload

Exercise: Contiki Blue Beacon

Create a new app beacon.c that repeatedly

turns Blue LED on for ~0.1 second

turns Blue LED off for ~1 second

19

20

Event-Driven Programming Model

Most WSN OS frameworks provide event-based programming environment

Idle loop

Radio event handler

Sensor event handler

Timer event handler

Boot event handler

Handled by Kernel Handled by developer

Blink – Event-Driven Version

21

#include "contiki.h"

#include "dev/leds.h"

/*-----------------------------------------------*/

PROCESS(blink_process, "Blink Application");

AUTOSTART_PROCESSES(&blink_process);

/*-----------------------------------------------*/

static struct ctimer timer;

static void callback(void *ptr)

{

leds_toggle(LEDS_BLUE);

ctimer_reset(&timer);

}

PROCESS_THREAD(blink_process, ev, data)

{

PROCESS_BEGIN();

ctimer_set(&timer, CLOCK_SECOND/2, callback, NULL);

PROCESS_END();

}

blink-evt.c

Exercise: Event-Based Beacon

Create a new event-based app beacon-event.c that repeatedly

turns Blue LED on for ~0.1 second

turns Blue LED off for ~1 second

22

Exercise: Double Beacons

Write a new Contiki application that

turns Blue LED on for 0.1 second and off for 1 second

And at the same time,

turns Red LED on for 0.1 second and off for 0.75 second

First, try it with the event-based model

Name it double-beacons-event.c

23

Double Beacons – Event-Based

Process and variable declarations

24

#include "contiki.h"

#include "dev/leds.h"

/*-------------------------------------------------------------*/

PROCESS(double_beacon_process, "Double Beacons Application");

AUTOSTART_PROCESSES(&double_beacon_process);

/*-------------------------------------------------------------*/

enum

{

STATE_ON,

STATE_OFF

};

int state_blue, state_red;

static struct ctimer timer_blue, timer_red;

double-beacons-evt.c

Double Beacons – Event-Based

Blue's callback

25

static void callback_blue(void *ptr)

{

if (state_blue == STATE_ON)

{

leds_off(LEDS_BLUE);

state_blue = STATE_OFF;

ctimer_set(&timer_blue, CLOCK_SECOND, callback_blue, NULL);

}

else if (state_blue == STATE_OFF)

{

leds_on(LEDS_BLUE);

state_blue = STATE_ON;

ctimer_set(&timer_blue, CLOCK_SECOND*0.1, callback_blue, NULL);

}

}

double-beacons-evt.c

Double Beacons – Event-Based

Red's callback

26

static void callback_red(void *ptr)

{

if (state_red == STATE_ON)

{

leds_off(LEDS_RED);

state_red = STATE_OFF;

ctimer_set(&timer_red, CLOCK_SECOND*0.75, callback_red, NULL);

}

else if (state_red == STATE_OFF)

{

leds_on(LEDS_RED);

state_red = STATE_ON;

ctimer_set(&timer_red, CLOCK_SECOND*0.1, callback_red, NULL);

}

}

double-beacons-evt.c

Double Beacons – Event-Based

Main process

27

PROCESS_THREAD(double_beacon_process, ev, data)

{

PROCESS_BEGIN();

state_blue = STATE_OFF;

state_red = STATE_OFF;

callback_blue(NULL);

callback_red(NULL);

PROCESS_END();

}

double-beacons-evt.c

Exercise: Sequential Beacons

Rewrite the Double Beacons application in a sequential style

Name it double-beacons-seq.c

28

Problem with Event-Driven Model

Threads: sequential code flowEvents: unstructured code flow

29

Double Beacons – Multi-process?

30

PROCESS_THREAD(

beacon_red_process, ev, data)

{

PROCESS_BEGIN();

watchdog_stop();

for (;;)

{

leds_on(LEDS_RED);

clock_wait(CLOCK_SECOND/10);

leds_off(LEDS_RED);

clock_wait(CLOCK_SECOND*0.75);

}

PROCESS_END();

}

PROCESS_THREAD(

beacon_blue_process, ev, data)

{

PROCESS_BEGIN();

watchdog_stop();

for (;;)

{

leds_on(LEDS_BLUE);

clock_wait(CLOCK_SECOND/10);

leds_off(LEDS_BLUE);

clock_wait(CLOCK_SECOND);

}

PROCESS_END();

}

#include "contiki.h"

#include "dev/leds.h"

/*---------------------------------------------------------*/

PROCESS(beacon_blue_process, "Beacon Blue Application");

PROCESS(beacon_red_process, "Beacon Red Application");

AUTOSTART_PROCESSES(&beacon_blue_process,&beacon_red_process);

/*---------------------------------------------------------*/

double-beacons-seq.c

Events Require One Stack

Four event handlers, one stack

Eventhandler 1Eventhandler 2Eventhandler 3

Stack is reused for every event handler

Eventhandler 4

31

Problem with Multithreading

Four threads, each with its own stack

Thread 1 Thread 2 Thread 3 Thread 4

32

33

Emulating Concurrency

Previous example wouldn't work because of the blocking while-loop

Other parts of the system will be unresponsive

Must return to kernel inside of the while-loops

During kernel's idle loop, keep jumping into the while-loops

Coroutines

Generalized subroutines

Allow multiple entry points for suspending and resuming execution at certain locations

Can be used to implement:

Cooperative multitasking

Actor model of concurrency

34

Routine 2

Subroutines vs. Coroutines

Routine 1

Subroutines

Routine 2Routine 1

Coroutines

call

call

return

return

yield yield

yield

yield

35

“Subroutines are a special case of coroutines.”--Donald Knuth

Fundamental Algorithms. The Art of Computer Programming

36

Programming Model

Kernel's

Idle loop

Task 2

Event handler2

Task 1

Event handler1

Handled by Kernel Handled by developer

call

returncall

return

continue

yield

yield

continue

Implementing Continuation

Each coroutine must be able to continue from where it last yielded

Routine 1

37

Main

Loop

continue

yield

continue

yield

Implementing Continuation

Use computed goto statement

Non-standard, supported by GCC

Use switch..case, Duff's device style

38

39

Duff's Device

Invented to optimize data transfer by means of loop unwinding

Switch cases are used like GOTO labels

do {*to = *from++;

} while(--count > 0);

register n = (count + 7) / 8;switch(count % 8) {case 0: do { *to = *from++;case 7: *to = *from++;case 6: *to = *from++;case 5: *to = *from++;case 4: *to = *from++;case 3: *to = *from++;case 2: *to = *from++;case 1: *to = *from++;

} while(--n > 0);}

40

Protothreads

Invented by Adam Dunkels and Oliver Schmidt

Used in the Contiki OS

Provides light-weight mechanism for concurrent programming using standard C macros and switch-case statements

Heavily inspired by Duff's Device and Simon Tatham's Coroutines in C

See

http://dunkels.com/adam/pt/expansion.html

Protothreads

Protothreads require only one stack

E.g, four protothreads, each with its own stack

Events require one stack

Protothread 1Protothread 2Protothread 3Protothread 4

Just like events

41

Six-line implementation

Protothreads implemented using the C switch statement

Heavily inspired by Duff's Device and Simon Tatham's Coroutines in C

struct pt { unsigned short lc; };

#define PT_INIT(pt) pt->lc = 0

#define PT_BEGIN(pt) switch(pt->lc) { case 0:

#define PT_EXIT(pt) pt->lc = 0; return 2

#define PT_WAIT_UNTIL(pt, c) pt->lc = __LINE__; case __LINE__: \

if(!(c)) return 0

#define PT_END(pt) } pt->lc = 0; return 1

42

Double Beacons – Protothreads

Setup and declarations

43

#include "contiki.h"

#include "dev/leds.h"

/*---------------------------------------------------------*/

PROCESS(beacon_blue_process, "Beacon Blue Application");

PROCESS(beacon_red_process, "Beacon Red Application");

AUTOSTART_PROCESSES(&beacon_blue_process,&beacon_red_process);

/*---------------------------------------------------------*/

double-beacons-pt.c

Double Beacons – Protothreads

Blue beacon process

44

PROCESS_THREAD(beacon_red_process, ev, data)

{

static struct etimer et;

PROCESS_BEGIN();

for (;;)

{

leds_off(LEDS_RED);

etimer_set(&et,CLOCK_SECOND*0.75);

PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

leds_on(LEDS_RED);

etimer_set(&et,CLOCK_SECOND*0.1);

PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

}

PROCESS_END();

}

double-beacons-pt.c

Double Beacons – Protothreads

Red beacon process

45

PROCESS_THREAD(beacon_blue_process, ev, data)

{

static struct etimer et;

PROCESS_BEGIN();

for (;;)

{

leds_off(LEDS_BLUE);

etimer_set(&et,CLOCK_SECOND);

PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

leds_on(LEDS_BLUE);

etimer_set(&et,CLOCK_SECOND*0.1);

PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

}

PROCESS_END();

}

double-beacons-pt.c

46

Protothreads Limitations

Local variables must be manually preserved

Local variables are created on stack

They are destroyed when function returns

So they should be stored in an explicit state object

Or declared static, if reentrancy is not required

Cannot take advantage of multi-processing

switch-case statements are not allowed

There is also a 'goto' implementation of PT

Recommended