Upload
lekhanh
View
217
Download
2
Embed Size (px)
Citation preview
Architectures and Applications for Wireless Sensor Networks (01204525)
Node Programming
Chaiporn [email protected]
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