Programming the TelosB

Previous installation guide can be found here: drudoo.com

USB connection

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.

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

Inside the folder we need 3 documents.

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

Open the Makefile in your favorite editor (I’m going to use sublime text, but nano or any other editor works too).

sublime Makefile

And add the following code

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.

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.

#include "Timer.h"

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

After that we can add the rest of our implementation

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:

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.

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

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

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.

touch senseappmsg.h
sublime senseappmsg.h

In the file add the following:

#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.

#include "senseappmsg.h"

interface AMSend as AMSendT;
interface SplitControl as AMControl;

In the implementation we also need a few new variables:

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.

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.

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.

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.

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

cd tinyos-main/support/sdk/java

and run

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

You should now see a series of data like

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.

Temperature sensor

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.

components new SensirionSht11C() as TempSensor;

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

USBC.TempRead -> TempSensor.Temperature;

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

interface Read<uint16_t> as TempRead;

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

uint16_t temparature;

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

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.

btrpkt->temp = temparature;

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

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.

 

Leave a Reply