CoAP -03

From TinyOS Wiki
Revision as of 07:18, 14 February 2011 by Mab (talk | contribs) (Get the code)
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
./configure
make

Compile and install CoapBlip application

cd $TOSROOT/apps/CoapBlip
make telosb blip coap install,3

Run it

blip IPBaseStation

blip ip-driver

./coap-server ./coap-client

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;
}