TinyOS Tutorial

advertisement
TinyOS Tutorial
Communication Networks I
Wenyuan Xu
Fall 2006
Lecture Overview
 1.
Hardware Primer
 2.
Introduction to TinyOS
 3.
Programming TinyOS
 4.
Network Communication
UC Berkeley Family of Motes
Mica2 and Mica2Dot

ATmega128 CPU

Self-programming
 128KB Instruction EEPROM
 4KB Data EEPROM

Chipcon CC1000

Manchester encoding
 Tunable frequency



38K or 19K baud
Lower power consumption


315, 433 or 900MHz
2 AA batteries
Expansion

51 pin I/O Connector
1 inch
MTS300CA Sensor Board
Programming Board (MIB510)
Hardware Setup Overview
Lecture Overview
 1.
Hardware Primer
 2.
Introduction to TinyOS
 3.
Programming TinyOS
 4.
Network Communication
What is TinyOS?

An operation system

An open-source development environment

Not an operation system for general purpose, it is
designed for wireless embedded sensor network.

Official website: http://www.tinyos.net/

Programming language: NesC (an extension of C)

It features a component-based architecture.

Supported platforms include Linux, Windows 2000/XP
with Cygwin.
Install TinyOS and the ‘make’

Download

http://www.tinyos.net/download.html

From within the application’s
directory:


Directory Structure
/apps
make (re)install.<node id>
<platform>
<node id> is an integer between 0
and 255
 <platform> may be mica2,
mica2dot, or all
Example: make install.0 mica2

/Blink
/Forwarder
/contrib
/doc
/tools
/java
/tos
/interfaces
/lib
/platform
/mica
/mica2
/mica2dot
/sensorboard
/micasb
/system
/types

make pc

Generates an executable that can
be run a pc for
Build Tool Chain
Convert NesC into C
and compile to exec
Modify exec with
platform-specific
options
Set the mote ID
Reprogram the
mote
Lecture Overview
 1.
Hardware Primer
 2.
Introduction to TinyOS
 3.
Programming TinyOS
 4.
Network Communication
Characteristics of Network Sensors


Small physical size and low power consumption
Concurrency-intensive operation
 multiple

Limited Physical Parallelism and Controller
Hierarchy
 primitive

flows, not wait-command-respond
direct-to-device interface
Diversity in Design and Usage
 application
specific, not general purpose
 huge device variation
actuators
=> efficient modularity
=> migration across HW/SW boundary

sensors
Robust Operation
 numerous,
unattended, critical
=> narrow interfaces
network
storage
A Operating System for Tiny Devices?

Main Concept

HURRY UP AND SLEEP!!


provide framework for concurrency and modularity




Sleep as often as possible to save power
Commands, events, tasks
interleaving flows, events - never poll, never block
Separation of construction and composition
Programs are built out of components

Libraries and components are written in nesC.
 Applications are too -- just additional components composed with the OS
components

Each component is specified by an interface


Provides “hooks” for wiring components together
Components are statically wired together based on their interfaces

Increases runtime efficiency
Programming TinyOs




A component provides and uses interfaces.
A interface defines a logically related set of commands and events.
Components implement the events they use and the commands they
provide:
Component
Commands
Events
Use
Can call
Must implement
Provide
Must implement
Can signal
There are two types of components in nesC:




Modules. It implements application code.
Configurations. It assemble other components together, called wiring
A component does not care if another component is a module or
configuration
A component may be composed of other components via configurations
Component Syntax - Module

A component specifies a set of interfaces by which it is connected to other
components
 provides a set of interfaces to others
 uses a set of interfaces provided by others
module ForwarderM {
provides {
interface StdControl;
}
uses {
interface StdControl as CommControl;
interface ReceiveMsg;
interface SendMsg;
interface Leds;
}
}
implementation {
…// code implementing all provided commands
and used events
}
uses
provides
CommControl
ReceiveMsg
StdControl
ForwarderM
SendMsg
Leds
Component Syntax - Configuration
Component
Selection
configuration Forwarder { }
implementation
{
components Main, LedsC;
components GenericComm as Comm;
components ForwarderM;
Main.StdControl -> ForwarderM.StdControl;
ForwarderM.CommControl -> Comm;
ForwarderM.SendMsg -> Comm.SendMsg[AM_INTMSG];
ForwarderM.ReceiveMsg -> Comm.ReceiveMsg[AM_INTMSG];
ForwarderM.Leds -> LedsC;
Wiring the
Components
together
}
Forwarder
uses
provides
StdControl
CommControl
Main
StdControl
ReceiveMsg
StdControl
ForwarderM
ReceiveMsg
SendMsg
GenericComm
SendMsg
Leds
Leds
LedsC
Configuration Wires

A configuration can bind an interface user to a
provider using -> or <


Bounce responsibilities using =



User.interface -> Provider.interface
Provider.interface <- User.interface
User1.interface = User2.interface
Provider1.interface = Provider2.interface
The interface may be implicit if there is no
ambiguity

e.g., User.interface -> Provider 
User.interface -> Provider.interface
Interface Syntax- interface StdControl

Look in <tos>/tos/interfaces/StdControl.nc
interface StdControl {
// Initialize the component and its subcomponents.
command result_t init();
// Start the component and its subcomponents.
command result_t start();
// Stop the component and pertinent subcomponents
command result_t stop();
}


Multiple components may provide and use this interface
Every component should provide this interface

This is good programming technique, it is not a language specification
Interface Syntax- interface SendMsg

Look in <tos>/tos/interfaces/SendMsg.nc
includes AM; // includes AM.h located in <tos>\tos\types\
interface SendMsg {
// send a message
command result_t send(uint16_t address, uint8_t length,
TOS_MsgPtr msg);
// an event indicating the previous message was sent
event result_t sendDone(TOS_MsgPtr msg, result_t success);
}


Includes both command and event.
Split the task of sending a message into two parts, send
and sendDone.
Component implementation
Command
implementation
(interface provided)
module ForwarderM {
//interface declaration
}
implementation {
command result_t StdControl.init()
{
call CommControl.init();
call Leds.init();
return SUCCESS;
}
command result_t StdControl.start() {…}
command result_t StdControl.stop() {…}
event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr m)
{
call Leds.yellowToggle();
call SendMsg.send(TOS_BCAST_ADDR, sizeof(IntMsg), m);
return m;
}
Event
implementation
(interface used)
event result_t SendMsg.sendDone(TOS_MsgPtr msg, bool success)
{
call Leds.greenToggle();
return success;
}
}
TinyOS Commands and Events
{
...
status = call CmdName(args)
...
}
event EvtName)(args) {
...
return status;
}
command CmdName(args) {
...
return status;
}
{
...
status = signal EvtName(args)
...
}
TinyOs Concurrency Model



TinyOS executes only one program consisting of a set of
components.
Two type threads:
 Task
 Hardware event handler
Tasks:


Time flexible
Longer background processing jobs
 Atomic with respect to other tasks (single threaded)
 Preempted by event

Hardware event handlers



Time critical
Shorter duration (hand off to task if need be)
Interrupts task and other hardware handler.
 Last-in first-out semantics (no priority among events)
 executed in response to a hardware interrupt
Tasks


Provide concurrency internal to a component
 longer running operations
Scheduling:



Currently simple FIFO scheduler
Bounded number of pending tasks
When idle, shuts down node except clock

Uses non-blocking task queue data structure

Simple event-driven structure + control over complete application/system graph

instead of complex task priorities and IPC
{
...
post TaskName();
...
}
task void TaskName {
...
}
TinyOS Execution Contexts
events
Tasks
commands
Interrupts
Hardware



Events generated by interrupts preempt
tasks
Tasks do not preempt tasks
Both essential process state transitions
Event-Driven Sensor Access Pattern
command result_t StdControl.start() {
return call Timer.start(TIMER_REPEAT, 200);
SENSE
}
event result_t Timer.fired() {
return call sensor.getData();
Timer
}
Photo
event result_t sensor.dataReady(uint16_t data) {
display(data)
return SUCCESS;
}





clock event handler initiates data collection
sensor signals data ready event
data event handler calls output command
device sleeps or handles other activity while waiting
conservative send/ack at component boundary
LED
Lecture Overview
 1.
Hardware Primer
 2.
Introduction to TinyOS
 3.
NesC Syntax
 4.
Network Communication
Inter-Node Communication

General idea:
 Sender:
Fill message
buffer with data
Specify
Recipients
Pass buffer
to OS
Determine when
message buffer
can be reused
 Receiver:
OS Buffers
incoming message
in a free buffer
Signal
application with
new message
OS obtains free
buffer to store
next message
TOS Active Messages


Message is “active” because it
contains the destination
address, group ID, and type.
‘group’: group IDs create a
virtual network


an 8 bit value specified in
<tos>/apps/Makelocal
The address is a 16-bit value
specified by “make”

– make install.<id> mica2

“length” specifies the size of
the message .

“crc” is the check sum
Preamble Sync Header (5)
typedef struct TOS_Msg {
// the following are transmitted
uint16_t addr;
uint8_t type;
uint8_t group;
uint8_t length;
int8_t data[TOSH_DATA_LENGTH];
uint16_t crc;
// the following are not transmitted
uint16_t strength;
uint8_t ack;
uint16_t time;
uint8_t sendSecurityMode;
uint8_t receiveSecurityMode;
} TOS_Msg;
Payload (29)
CRC (2)
TOS Active Messages (continue)
Sending a message



Define the message
format
Define a unique
active message
number
How does TOS
know the AM
number?
includes Int16Msg;
module ForwarderM {
//interface declaration
}
implementation {
event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr m)
{
call Leds.yellowToggle();
call SendMsg.send(TOS_BCAST_ADDR,
sizeof(IntMsg), m);
return m;
}
destination
length
event result_t SendMsg.sendDone(TOS_MsgPtr msg, bool success)
{
call Leds.greenToggle();
return success;
}
File: Int16Msg.h
struct Int16Msg {
uint16_t val;
};
enum {
AM_INTMSG = 47
};
}
configuration Forwarder { }
implementation
{ …
ForwarderM.SendMsg -> Comm.SendMsg[AM_INTMSG];
ForwarderM.ReceiveMsg -> Comm.ReceiveMsg[AM_INTMSG];
}
Receiving a message



Define the message
format
Define a unique
active message
number
How does TOS
know the AM
number?
includes Int16Msg;
module ForwarderM {
Message received
//interface declaration
}
implementation {
event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr m)
{
call Leds.yellowToggle();
call SendMsg.send(TOS_BCAST_ADDR,
sizeof(IntMsg), m);
return m;
}
event result_t SendMsg.sendDone(TOS_MsgPtr msg, bool success)
{
call Leds.greenToggle();
return success;
}
File: Int16Msg.h
struct Int16Msg {
uint16_t val;
};
enum {
AM_INTMSG = 47
};
}
configuration Forwarder { }
implementation
{ …
ForwarderM.SendMsg -> Comm.SendMsg[AM_INTMSG];
ForwarderM.ReceiveMsg -> Comm.ReceiveMsg[AM_INTMSG];
}
Where exactly is the radio stuff?
Mica2
StdControl
StdControl
CC1000RadioC
BareSendMsg
ReceiveMsg
BareSendMsg
ReceiveMsg
CC1000RadioIntM
Spi bus interrupt handler



Connection between Chipcon CC1000 radio and the
ATmega128 processor: SPI bus.
Spibus interrupt handler: SpiByteFifo.dataReady()
SpiByteFifo.dataReady() will be called every 8 ticks.
file:CC1000RadioIntM.nc
async event result_t SpiByteFifo.dataReady(uint8_t data_in) {
…
switch (RadioState) {
case RX_STATE: {...}
case DISABLED_STATE: {…}
case IDLE_STATE: {...}
case PRETX_STATE: {...}
case SYNC_STATE: {...}
case RX_STATE: {...}
return SUCCESS;
}
Preamble Sync Header (5)
Payload (29)
CRC (2)
Receiving a message (1)

IDLE_STATE SYNC_STATE

Listen to the preamble, if the enough bytes of preamble are received, entering
SYCN_STATE
file:CC1000RadioIntM.nc
async event result_t SpiByteFifo.dataReady(uint8_t data_in) {
…
switch (RadioState) {
…
case IDLE_STATE:
{ if (((data_in == (0xaa)) || (data_in == (0x55)))) {
PreambleCount++;
if (PreambleCount > CC1K_ValidPrecursor) {
PreambleCount = SOFCount = 0;
RxBitOffset = RxByteCnt = 0;
usRunningCRC = 0;
rxlength = MSG_DATA_SIZE-2;
RadioState = SYNC_STATE;
}
}
}…
}
Preamble Sync Header (5)
Payload (29)
CRC (2)
Receiving a message (2)

SYNC_STATE  RX_STATE





look for a SYNC_WORD (0x33cc).
Save the last received byte and current received byte
Use a bit shift compare to find the byte boundary for the sync byte
Retain the shift value and use it to collect all of the packet data
SYNC_STATE  IDLE_STATE

didn't find the SYNC_WORD after a reasonable number of tries, so set the radio
state back to idel:

RadioState = IDLE_STATE;
file:CC1000RadioIntM.nc
async event result_t SpiByteFifo.dataReady(uint8_t data_in) {
…
switch (RadioState) {
case SYNC_STATE: …
{ if ( find SYCN_WORD) {
…
RadioState = RX_STATE;
} else if ( too many preamble) {
…
RadioState = IDLE_STATE; }
}…
}
Preamble Sync Header (5)
Payload (29)
CRC (2)
Receiving a message (3)

RX_STATE IDLE_STATE/SENDING_ACK

Keep receiving bytes and calculate CRC until the end of the packet.
 The end of the packet are specified by the length in the packet header
 Pass the message to the application layer, no matter whether the
message passed the CRC check
file:CC1000RadioIntM.nc
async event result_t SpiByteFifo.dataReady(uint8_t data_in) { …
switch (RadioState) {
…
case RX_STATE:
{ …RxByteCnt++;
if (RxByteCnt <= rxlength) {
usRunningCRC = crcByte(usRunningCRC,Byte);
if (RxByteCnt == HEADER_LENGTH_OFFSET) {
rxlength = rxbufptr->length;}
} else if (RxByteCnt == CRCBYTE_OFFSET) {
if (rxbufptr->crc == usRunningCRC) {
rxbufptr->crc = 1;
} else {
rxbufptr->crc = 0;
}…
RadioState = IDLE_STATE;
post PacketRcvd();
}…
Preamble Sync Header (5)
Payload (29)
CRC (2)
Error Detection – CRC

CRC – Cyclic Redundancy Check
 Polynomial

cods or checksums
Procedure:
1. Let r be the degree of the code polynomial. Append r zero bits to
the end of the transmitted bit string. Call the entire bit string S(x)
2. Divide S(x) by the code polynomial using modulo 2 division.
3. Subtract the remainder from S(x) using modulo 2 subtraction.

The result is the checksummed message
Generating a CRC – example

Message: 1011


1 * x3 + 0 * x2 + 1 * x + 1= x3 + x + 1
Code Polynomial: x2 + 1 (101)
Step 1: Compute S(x)
r=2
S(x) = 101100
Step 2: Modulo 2 divide
101
1011
101100
101
001
000
010
000
100
101
01
Step 3: Modulo 2 subtract
the remainder from S(x)
101100
- 01
101101
Checksummed Message
Remainder
Decoding a CRC – example

Procedure
1. Let n be the length of the checksummed message in bits
2. Divide the checksummed message by the code polynomial using
modulo 2 division. If the remaidner is zero, there is no error detected.
Case 1:
Checksummed
message (n=6):
101101
1011
Original message
101
Case 2:
1001
101101
101
001
000
010
000
101
101
00
Remainder = 0
(No error detected)
101
1000
101001
101
000
000
000
000
001
000
01
Remainder = 1
(Error detected)
CRC in TinyOS

Calculate the CRC byte by byte
crc=0x0000;
while (more bytes) {
crc=crc^b<<8;
calculate the high byte of crc
}

file: system/crc.h
uint16_t crcByte(uint16_t crc, uint8_t b)
{
uint8_t i;
crc = crc ^ b << 8;
i = 8;
do
if (crc & 0x8000)
crc = crc << 1 ^ 0x1021;
else
crc = crc << 1;
while (--i);
return crc;
Code Polynomial: CRC-CCITT
0x1021 = 0001 0000 0010 0001
x16 + x12 + x5 + 1
}
Example:
10001 0000 0010 0001
10…
10110110110110110110110110110100
10001000000100001
01111101100101111
00000000000000000
11111011001011111
…
Further Reading

Go through the on-line tutorial:


Search the help archive:


http://www.tinyos.net/tinyos-1.x/doc/nesc/ref.pdf
Getting started guide


http://www.tinyos.net/search.html
NesC language reference manual:


http://www.tinyos.net/tinyos-1.x/doc/tutorial/index.html
http://www.xbow.com/Support/Support_pdf_files/Getting_Started_Guide
.pdf
Hardware manual:

http://www.xbow.com/Support/Support_pdf_files/MPRMIB_Series_Users_Manual.pdf
Reference

“Programming TinyOS”, David Culler, Phil Levis,
Rob Szewczyk, Joe Polastre University of California,
BerkeleyIntel Research Berkeley

“TinyOS Tutorial”, Chien-Liang Fok,
http://www.princeton.edu/~wolf/EECS579/imotes/tos_tut
orial.pdf

“Computer Networks”, Badri Nath
http://www.cs.rutgers.edu/dataman/552dir/notes/
week2-one.pdf
Download