Programming the TelosB

> Previous installation guide can be found here: Getting TinyOS to work on Linux using TelosB

It is pretty hard to debug on the TelosB since it doesn’t have a native interface to read debug messages. It is possible to use the LED’s but they don’t show much. The TelosB has three LED’s and can only turn on or off, so the possibilities are limited.

Let’s try and set up a serial USB connection between the device and the computer, so we can read the debug messages on the screen.

To start go to the TinyOS folder and make a new folder inside apps.

1
2
cd tinyos-main/apps/
mkdir USB && cd USB

Inside the folder we need 3 documents.

1
touch Makefile && touch USBAppC.nc && touch USBC.nc

Open the Makefile in your favorite editor.

1
vi Makefile

And add the following code

1
2
COMPONENT=USBAppC
include $(MAKERULES)

Before we get into sending data over serial, let’s setup a simple program that makes the LED blink. This is for us to see if the program actually works and for us to know if the timer is fired. When the timer is fired we should send data over serial and see the LED blink.

In the USBAppC.nc file let’s setup the componenets needed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
configuration USBAppC {
}

implementation {
  components USBC, MainC, LedsC;
  components new TimerMilliC() as Timer;

  USBC.Boot -> MainC.Boot;
  USBC.Leds -> LedsC;
  USBC.Timer -> Timer;
}

What we do here is just to declare the normal componenets needed (Main for boot, Leds for LED and USBC for the rest of the program).

In the USBC.nc file we need a few more things.

First we need to include our timer interface and setup the modules needed.

1
2
3
4
5
6
7
8
9
#include "Timer.h"

module USBC {
    uses {
	interface Boot;
	interface Leds;
	interface Timer<TMilli>;
    }
}

After that we can add the rest of our implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
implementation {
    #define SAMPLING_FREQUENCY 1000

    bool LEDon = FALSE;

    event void Boot.booted() {
	call Timer.startPeriodic(SAMPLING_FREQUENCY);
    }

    event void Timer.fired() {
	if (LEDon) {
	    call Leds.led1Off();
	    LEDon = FALSE;
	} else {
	    call Leds.led1On();
	    LEDon = TRUE;
	}
    }
}

What we do here is first to define a `SAMPLING_FREQUENCY` so we are sure we send data at the same frequency. Then we create a boolean to check if the LED is on or not. We also have an event that checks if the TelosB has booted up, if it has, then we start the timer.

Based on the timer we can check if the LED is on or not and then turn it off. Pretty simple stuff and it is easy to test out.

To compile and run the program, connect the TelosB to your USB stick and run:

1
make telosb install

> Remember to be root!

You should now see a blinking green LED on the board.

Next let’s add a few extra things to the program. In the USBAppC.nc file we need two new components.

1
2
components SerialActiveMessageC;
components new SerialAMSenderC(100) as Send;

After adding these, let’s bind them to their controls.

1
2
USBC.AMControl -> SerialActiveMessageC;
USBC.AMSendT -> Send;

That’s enough for this file, but before we move on to the USBC.nc file we need a few one.

When we send a message over serial we need an structure for the message to be send as. So let’s create a new file and add a few things.

1
2
touch senseappmsg.h
vi senseappmsg.h

In the file add the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#ifndef TMP_H
#define TMP_H


typedef nx_struct TemptoUartMsg {
nx_uint16_t nodeid;
nx_uint16_t temp;
} TemptoUartMsg;

#endif

What we do here is to create a new struct that contains a node ID and the value we want to send. I want this applicaiton to end up sending the temperature, so I call the other variable for temp.

Back to the USBC.nc file we need two new interfaces and an include.

1
2
3
4
#include "senseappmsg.h"

interface AMSend as AMSendT;
interface SplitControl as AMControl;

In the implementation we also need a few new variables:

1
2
3
bool busy = FALSE;
message_t package;
uint16_t counter = 0;

In the Boot event we need to start an AMControl function which is part of the SplitControl interface. This is done so we can actually send data over the serial port. If we don’t start this nothing will happen and our program will hand and be busy all the time.

Next we need a task to send the data to the computer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
task void SendTemptoUart(){
    if (!busy){
	TemptoUartMsg* btrpkt = (TemptoUartMsg*)(call AMSendT.getPayload(&package, NULL));

	btrpkt->nodeid = TOS_NODE_ID;

	btrpkt->temp = counter;

	if (call AMSendT.send(AM_BROADCAST_ADDR, &package, sizeof(TemptoUartMsg)) == SUCCESS) {
	    busy=TRUE;
	} else {

	}
    }
}

What we do here is first to check if the sender is busy, if it is we won’t try and send anything new. Then we create the message as a pointer of type TemptoUartMsg (remember the struct we made before?). Then we populate the struct with our data, first we take the node ID, then the counter value.

Next we check if the call to send the value is sucessful and if it is then we say that the program is busy.

To make sure the program knows when it is not busy anymore we add a sendDone event.

1
2
3
4
5
event void AMSendT.sendDone(message_t* msg, error_t error) {
    if (&package == msg) {
	busy = FALSE;
    }
}

To send the data, let’s modify our `Timer.fired` from earlier.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
event void Timer.fired() {
    if (LEDon && !busy) {
	call Leds.led1On();
	counter++;
	post SendTemptoUart();
	LEDon = FALSE;
    } else {
	call Leds.led1Off();
	LEDon = TRUE;
    }
}

This time we check if the program is not busy, then we increment the counter and send the data to the computer.

The program actually works now, but the compiler complains before we added the last two events.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
event void AMControl.startDone(error_t err) {
    if (err == SUCCESS) {

    } else {

    }
}

event void AMControl.stopDone(error_t err) {

}

When compiling there shouldn’t be any problems.

Afterwards go to

1
cd tinyos-main/support/sdk/java

and run

1
java net.tinyos.tools.Listen -comm serial@/dev/ttyUSB0:telos

You should now see a series of data like

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
00 FF FF 00 00 04 00 64 00 01 00 01
00 FF FF 00 00 04 00 64 00 01 00 02
00 FF FF 00 00 04 00 64 00 01 00 03
00 FF FF 00 00 04 00 64 00 01 00 04
00 FF FF 00 00 04 00 64 00 01 00 05
00 FF FF 00 00 04 00 64 00 01 00 06
00 FF FF 00 00 04 00 64 00 01 00 07
00 FF FF 00 00 04 00 64 00 01 00 08
00 FF FF 00 00 04 00 64 00 01 00 09
00 FF FF 00 00 04 00 64 00 01 00 0A
00 FF FF 00 00 04 00 64 00 01 00 0B
00 FF FF 00 00 04 00 64 00 01 00 0C
00 FF FF 00 00 04 00 64 00 01 00 0D
00 FF FF 00 00 04 00 64 00 01 00 0E
00 FF FF 00 00 04 00 64 00 01 00 0F
00 FF FF 00 00 04 00 64 00 01 00 10

Where the last couple of digits in each row is the hex value of the counter.

With the USB connection up and running let’s try and get it to read the temperature and then send that data to the computer.

First we need to get access to the SensirionSht11C sensor. We can do that by adding it as a component in the USBAppC.nc file.

1
components new SensirionSht11C() as TempSensor;

We also need to connect it to our USBC.nc file which can be done by

1
USBC.TempRead -> TempSensor.Temperature;

In the USBC.nc file we add a new interface:

1
interface Read<uint16_t> as TempRead;

We also need a new variable to store the temparature in, so let’s add another uint16_t:

1
uint16_t temparature;

In the end we need a new event called TempRead.readDone.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
event void TempRead.readDone(error_t result, uint16_t data) {

  if (result == SUCCESS){

    temparature=data;
    post SendTemptoUart();

  } else {
  }
}

And we finish off with changing counter to temparature.

1
btrpkt->temp = temparature;

The program should now output the temperature in Hex and look something like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
00 FF FF 00 00 04 00 64 00 01 19 A6
00 FF FF 00 00 04 00 64 00 01 19 A6
00 FF FF 00 00 04 00 64 00 01 19 A6
00 FF FF 00 00 04 00 64 00 01 19 A7
00 FF FF 00 00 04 00 64 00 01 19 A8
00 FF FF 00 00 04 00 64 00 01 19 A9
00 FF FF 00 00 04 00 64 00 01 19 A9
00 FF FF 00 00 04 00 64 00 01 19 AA
00 FF FF 00 00 04 00 64 00 01 19 AA
00 FF FF 00 00 04 00 64 00 01 19 AA
00 FF FF 00 00 04 00 64 00 01 19 AB
00 FF FF 00 00 04 00 64 00 01 19 AC

This probably looks like rubbish but the last two digits are the acutal temperature. When looking at `19 A6`, and converting it from hex to decimal we get `6566`. This then needs to be converted to the actual temperate in celcius which can be done using `-39.60+0.01*6566` which gives us `26.06C`, which in turn can be converted to fahrenheit by doing `26.06*1.8+32`, which is `79.88F`.

Next up we can try and look at how to intercept the data from the TelosB to a java program and convert the temperature on the go.