CoAP -03

From TinyOS Wiki
Revision as of 08:19, 16 May 2011 by Mab (talk | contribs) (Installation instructions)
Jump to: navigation, search

TinyOS CoAP

This page describes how to setup the TinyOS CoAP implementation based on libcoap.

This adaptation uses the TinyOS blip stack for UDP communication.

libcoap implements the Constrained Application Protocol (CoAP) [[1]] based on the following drafts:

  • draft-ietf-core-coap-03
  • draft-ietf-core-link-format-01
  • draft-ietf-core-block-00
  • draft-ietf-core-observe-00
  • draft-bormann-coap-misc-06

libcoap provides sample CoAP server and client implementations, which have participated in several plug-fests of the IETF CoRE working group.

TinyOS libcoap Adaptation Limitations

  • only GET and PUT methods supported, POST and DELETE methods not supported
  • draft-ietf-core-block-00, draft-ietf-core-observe-00 not yet implemented, code needs to be changed from time.h to TinyOS timers
  • currently only content-type application/octet-stream implemented
  • .well-known/core resource is not created

The code has been tested on TelosB nodes only, yet. The sample implementation depends on TelosB sensors.

Installation instructions

The CoAP code might make it into the tinyos-main SVN repository soon. These instructions are still for the independent code repository.

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 http://www.comnets.uni-bremen.de/~thp/git/tinyos-main.git/
cd tinyos-main
git checkout -b blip-coap-storage-support origin/blip-coap-storage-support
git submodule init
git submodule update

Then set the TOSROOT, TOSDIR and MAKERULES environment variables appropriately.

export TOSROOT=your tinyos-main directory (e.g. /home/USER/src/tinyos-main)
export TOSDIR=$TOSROOT/tos
export MAKERULES=$TOSROOT/support/make/Makerules

Compile libcoap and examples

cd $TOSROOT/apps/CoapBlip/libcoap
git checkout -b tinyos-support-binary-output origin/tinyos-support-binary-output 
autoconf
./configure
make

Compile and install CoapBlip application

To install the CoAP application on the mote, attach the mote via USB and run the following set of commands.

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

Setup IPBasestation and IPv6 ip-driver

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. First, create the required TinyOS serial library by doing the the following steps:

cd $TOSROOT/support/sdk/c/sf
./bootstrap
./configure
make

Then for building the driver run

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 the mote

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

After entering the sudo password, the a similar 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

The ip-driver has been setup successfully and you can now start the CoAP client.

Run CoAP example client

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

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

whereas URI specifies the resource you want to access and the response will be in binary representation. For TelosB motes, currently the following resources are supported and can be enabled/disabled in the Makefile of the CoAP application:

 Resource   GET   PUT  Comments
 /st X - Temperature
 /sh X - Humidity
 /sv X - Voltage
 /r X - Temperature, humidity
and Voltage
 /l X X LED's
 /ck (X) X AES Encryption Key


Note by requesting the Resource /st and /r, the CoAP message exchange turns into an asynchronous (deferred) message exchange. For this reason, a Token is required. The following command should be used instead:

./coap-client -m get coap://[fec0::3]:61616/<URI> -T <TOKEN> -t binary

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

For using the PUT method, the following commands can be use:

LED's:

The following command sets the LED's of the mote to state 2 (OFF, ON, OFF):

echo -e -n \\x02 | ./coap-client -m put coap://[fec0::3]:61616/l -T 3a -t binary -f -

AES Encryption Key:

Since the AES key contains 25 values, the most convenient way is to store the key in a file and send its content after with the PUT method to the mote. To do so, at first create the HEX file with example values by using this command:

echo -e -n \\xFF\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x10\\x11\\x12\\x13\\x14\\x15\\x16 >> file

Then send the file to the mote by using

./coap-client -m put coap://[fec0::3]:61616/ck -T 3a -t binary -f file

You can also, implemented for testing purposes, read the Key from storage by using the GET method:

./coap-client -m get coap://[fec0::3]:61616/ck -T 3a -t binary

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/CoAPClient.nc
$TOSROOT/tos/interfaces/CoAPServer.nc
$TOSROOT/tos/interfaces/LibCoAP.nc
CoAP interfaces

Wiring your resource to the application

Accessing resources on the mote, parameterized ReadResource and WriteResource interfaces have been introduced to provide multiple independent instances of the same interface for all available resources. This design scheme saves code space, eliminates fan-outs and allows portability to different motes by simply changing the wiring. For hardware dependent calculations of the retrieved sensor values, the CoAPBuffer{Volt|Hum|Temp}Translate components have been introduced. These components can be optional used to transform the received buffer values from the sensors to SI units using fixed-point calculations.

ReadResource

The ReadResource interface 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 getDoneDeferred(coap_tid_t id);
}

To read a resource, the get() command can be called. As parameter it takes the Message ID (id) to uniquely identify the response signaled back to the caller by getDone() or getDoneDeferred. 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, getDoneDeferred() 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 getDoneDeferred() 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, coap_tid_t id);
   event void putDone(error_t result, coap_tid_t id, uint8_t asyn_message);
   event void putDoneDeferred(coap_tid_t id);
}

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, *id)

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

putDoneDeferred is currently not implemented but might be used in the future.

CoAPBuffer{Volt|Hum|Temp}Translate

These components are used for calculations of the corresponding SI unit of the received sensor values. By providing and using the Read interface, they can easily be connected between the CoapReadResource and the sensor components to calculate fix-point values (real SI value * 100) of the respective sensor value. These components are hardware dependent and have to be adapted when changing hardware and/or sensors.

For using the Translate components for temperature and humidity, change the above given configuration to

configuration CoapBlipC {

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

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

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

The graph below shows the structure of the CoAP application with the above given wiring.

CoapBlipC doc.png


Further information

Some more information can be found in the following publication:

Koojana Kuladinithi, Olaf Bergmann, Thomas Pötsch, Markus Becker & Carmelita Görg: Implementation of CoAP and its Application in Transport Logistics. In Proc. Of ‘Extending the Internet to Low power and Lossy Networks’ (IP+SN 2011). Chicago, USA. 11th of April 2011. Paper Presentation Slides