CoAP -03

From TinyOS Wiki
Revision as of 08:56, 14 February 2011 by Thp (talk | contribs) (Run it)
Jump to: navigation, search

TinyOS CoAP

This page describes how to setup the TinyOS CoAP implementation based on libcoap, which implements the Constrained Application Protocol (CoAP) [[1]].

This adaptation uses the TinyOS blip stack for UDP communication.

Installation instructions

Get the code

The code for the TinyOS adaptation of libcoap is in a git repository. That repository is a clone of the tinyos-main svn repository. libcoap as an external project is included using git submodule.

In order to get yourself a copy:

git clone -b blip-coap-server-client-unification http://www.comnets.uni-bremen.de/~mab/git/tinyos-main.git/
cd tinyos-main
git submodule init
git submodule update

Then set the TOSROOT and TOSDIR environment variables appropriately.

Compile libcoap and examples

cd $TOSROOT/apps/CoapBlip/libcoap
autoconf
./configure
make

Compile and install CoapBlip application

To install the CoAP application on the mote, run the following set of commands.

cd $TOSROOT/apps/CoapBlip
make telosb blip coap install bsl,/dev/ttyUSB0

Run it

To install the IPBaseStation application for IPv6 support on the second attached mote, run the following set of commands.

cd $TOSROOT/apps/IPBaseStation
make telosb blip install bsl,/dev/ttyUSB1

Next, build the routing driver. Go to

cd $TOSROOT/support/sdk/c/blip

and run the following commands:

cd $TOSROOT/support/sdk/c/blip
./bootstrap.sh
./configure
make

Now the ip-driver has to be executed to establish the tunnel between the host an mote

sudo ./driver/ip-driver /dev/ttyUSB1 telosb

After entering the sudo password, the following output should be printed on your screen:

2011-02-14T18:03:00.323CET: INFO: Read config from 'serial_tun.conf'
2011-02-14T18:03:00.323CET: INFO: Using channel 16
2011-02-14T18:03:00.323CET: INFO: Retries: 5
2011-02-14T18:03:00.323CET: INFO: telnet console server running on port 6106
2011-02-14T18:03:00.325CET: INFO: created tun device: tun0
2011-02-14T18:03:00.609CET: INFO: interface device successfully initialized
2011-02-14T18:03:00.609CET: INFO: starting radvd on device tun0
2011-02-14T18:03:01.652CET: INFO: Starting to proxy for 0x1

In a new terminal execute the following commands to run the CoAP client and request a resource from the server:

cd $TOSROOT/apps/CoapBlip/libcoap/examples
./coap-client -m get coap://[fec0::3]:61616/URI

whereas URI specifies the resource you want to access. For TelosB motes, currently the following resources are supported:

  • hum (Humidity)
  • temp (Temperature)
  • led (State of the LED's)
  • par (Photosynthetically Active Radiation
  • tsr (Total Solar Radiation)

Note that retrieving the temperature sensor value, the CoAP message exchange turns into an asynchronous message exchange. For this reason, a Token is required. The following command should be used instead:

./coap-client -m get coap://[fec0::3]:61616/temp -T TOKEN

where TOKEN might be any string, e.g. 3a.

Important parts of TinyOS CoAP

$TOSROOT/apps/CoapBlip/* Sample application
$TOSROOT/support/make/coap.extra Makefile extension for CoAP
$TOSROOT/tos/lib/app/coap/* Core libcoap TinyOS adaptation
$TOSROOT/tos/interfaces/ReadResource.nc
$TOSROOT/tos/interfaces/WriteResource.nc
$TOSROOT/tos/interfaces/LibCoAP.nc
CoAP interfaces

Wiring your resource to the application

To read values of the sensors, the parameterized ReadResource interface has been introduced to provide multiple independent instances of the same interface for all available sensors. This design scheme saves code space, eliminates fan-outs and allows portability to different motes by simply changing the wiring.

ReadResource

The ReadResource interface currently provides three functions:

interface ReadResource {
   command error_t get(coap_tid_t id);         
   event void getDone(error_t result, coap_tid_t id, uint8_t asyn_message, uint8_t* val, uint8_t buflen); 
   event void getPreAck(coap_tid_t id); 
}

The getDone() event is signaled if the sensor reading has finished within a predefined time (PREACK_TIMEOUT) to create a immediate response. In case of a deferred message response, i.e. sensor data retrieval takes longer as defined in PREACK_TIMEOUT, getPreAck() is signaled to establish a asynchronous message exchange.

Example code to wire temperature and humidity sensor on TelosB motes:

configuration CoapBlipC {

} implementation {
   CoapBlipP.CoAPServer -> CoapUdpServerC;
   components new SensirionSht11C() as HumTempSensor;

   components new CoapReadResourceC(uint16_t, KEY_TEMP) as CoapReadTempResource;
   CoapReadTempResource.Read -> HumTempSensor.Temperature;
   CoapUdpServerC.ReadResource[KEY_TEMP] -> CoapReadTempResource.ReadResource;

   components new CoapReadResourceC(uint16_t, KEY_HUM) as CoapReadHumResource;
   CoapReadHumResource.Read -> HumTempSensor.Humidity;
   CoapUdpServerC.ReadResource[KEY_HUM] -> CoapReadHumResource.ReadResource;
}

The mapping of the parameterized ReadResource to its corresponding sensor is done by its key value which is mapped at compile-time to a constant integer by a predefined mapping function (get_key()) in tinyos_coap_ressources.h. Here the key "KEY_TEMP" corresponds to a 0 whereas the key "KEY_HUM" is mapped to 1.

Requesting data from a sensor, the following command needs to be called:

call ReadResource.get[get_key(uri->path.s, uri->path.length)](*id);

In case of an inappropriate call of get() in the application, e.g. for a non existing URI, the default function below must be implemented in the application to handle this exception:

default command error_t ReadResource.get[uint16_t uri_key](coap_tid_t id) {
 //get not available for this resource, handle this case
 return FAIL;
}

After the sensor is read, getDone() is signaled and returns the sensor data. The following function handles this event:

event void ReadResource.getDone[uint16_t uri_key](error_t result,
                                                  coap_tid_t id,
                                                  uint8_t asyn_message,
                                                  uint8_t* val_buf,
                                                  uint8_t buflen) {

//send response with sensor value
}

The same implementation holds for the getPreAck() event.

WriteResource

Since the LED resource, for example, provides both, Read- and Write-Resource interfaces, another component (CoapLedResource) is used to provide full access to the LedsC module. While ReadResource provides the get() command, the WriteResource provides the put() command to modify or change the state of a resource.

The interface looks as follows:

interface WriteResource {
   command error_t put(uint8_t* val, uint8_t buflen);
   event void putDone(error_t result);
}

For accessing the LED resource, the wiring looks like this:

configuration CoapBlipC {

} implementation {
   CoapBlipP.CoAPServer -> CoapUdpServerC;
   CoapBlipP.Leds -> LedsC;

   components new CoapLedResourceC(KEY_LED) as CoapLedResource;
   CoapLedResource.Leds -> LedsC;
   CoapUdpServerC.ReadResource[KEY_LED]  -> CoapLedResource.ReadResource;
   CoapUdpServerC.WriteResource[KEY_LED] -> CoapLedResource.WriteResource;
}

Accessing the WriteResource out of the application, the put() function as well as its default command has to be implemented.

call WriteResource.put[get_key(uri->path.s, uri->path.length)](buf, *buflen)

default command error_t WriteResource.put[uint16_t uri_key](uint8_t* val, uint8_t buflen) {
//put not available for this resource, handle this case
return FAIL;
}