Difference between revisions of "CoAP -03"

From TinyOS Wiki
Jump to: navigation, search
 
(51 intermediate revisions by 3 users not shown)
Line 1: Line 1:
= TinyOS CoAP =
+
= TinyOS CoAP (-03) =
 +
 
 +
 
 +
 
 +
 
 +
 
 +
'''This page is outdated!!!'''
 +
 
 +
CoapBlip has been updated to draft-ietf-core-coap-13. See detailed instruction for installing CoapBlip here: [[CoAP_-13]]
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
  
 
__TOC__
 
__TOC__
  
This page describes how to setup the TinyOS CoAP implementation based on [http://sourceforge.net/projects/libcoap/ libcoap], which implements the Constrained Application Protocol (CoAP) [[http://tools.ietf.org/id/draft-ietf-core-coap-03.txt]].
+
This page describes how to setup the TinyOS CoAP (-03) implementation based on [http://sourceforge.net/projects/libcoap/ libcoap] and uses the TinyOS blip-rpl stack for UDP communication.
  
This adaptation uses the TinyOS [[BLIP_Tutorial|blip]] stack for UDP communication.
+
libcoap implements the Constrained Application Protocol (CoAP) [[http://tools.ietf.org/id/draft-ietf-core-coap-03.txt]] based on the following drafts:
  
= Installation instructions =
+
* 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
 +
 
 +
Furthermore, libcoap provides sample CoAP server and client implementations, which have participated in several plug-fests of the IETF CoRE working group.
 +
 
 +
(Documentation for a test version of CoapBlip implementing coap-13 is available at [[CoAP -13]].)
 +
 
 +
= 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
  
== Get the code ==
+
The code has been tested on TelosB nodes only, yet. The sample implementation depends on TelosB sensors.
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:
+
= Installation instructions =
  
<pre>
 
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
 
</pre>
 
  
Then set the TOSROOT, TOSDIR and MAKERULES environment variables appropriately.
+
== Get the code ==
<pre>
+
Make sure you have [[Installing TinyOS|installed]] TinyOS and the source code.
export TOSROOT=your tinyos-main directory
 
export TOSDIR=$TOSROOT/tos
 
export MAKERULES=$TOSROOT/support/make/Makerules
 
</pre>
 
  
 
== Compile libcoap and examples ==
 
== Compile libcoap and examples ==
  
 
<pre>
 
<pre>
cd $TOSROOT/apps/CoapBlip/libcoap
+
cd $TOSROOT/support/sdk/c/coap
 
autoconf
 
autoconf
 
./configure
 
./configure
Line 39: Line 56:
 
== Compile and install CoapBlip application ==
 
== Compile and install CoapBlip application ==
  
To install the CoAP application on the mote, run the following set of commands.
+
To install the CoAP application on the mote, attach the mote via USB and run the following set of commands:
  
 
<pre>
 
<pre>
Line 46: Line 63:
 
</pre>
 
</pre>
  
== Setup IPv6 ip-driver ==
+
== Setting up PppRouter and ppp connection ==
  
To install the IPBaseStation application for IPv6 support on the second attached mote, run the following set of commands.
+
To install the PppRouter application for IPv6 support on the second attached mote, execute
  
  cd $TOSROOT/apps/IPBaseStation
+
  cd $TOSROOT/apps/PppRouter
make telosb blip install bsl,/dev/ttyUSB1
 
  
Next, build the routing driver.
+
and edit the Makefile by commenting the following line (21) out:
First, create the required TinyOS serial library by doing the the following steps:
 
  
  cd $TOSROOT/support/sdk/c/sf
+
  PFLAGS += -DBLIP_DERIVE_SHORTADDRS
./bootstrap
 
./configure
 
make
 
  
Then for building the driver run
+
Then install the PppRouter on the mote:
  
  cd $TOSROOT/support/sdk/c/blip
+
  make telosb blip install bsl,/dev/ttyUSB1
./bootstrap.sh
 
./configure
 
make
 
  
Now, the ip-driver has to be executed to establish the tunnel between the host an the mote
+
Next, start the ppp connection by executing
  
  sudo ./driver/ip-driver /dev/ttyUSB1 telosb
+
  sudo pppd debug passive noauth nodetach 115200 /dev/ttyUSB1 nocrtscts nocdtrcts lcp-echo-interval 0 noccp noip ipv6 ::23,::24
 +
 +
After entering the sudo password, a similar output should be printed on your screen:
  
After entering the sudo password, the a similar output should be printed on your screen:
 
 
<pre>
 
<pre>
2011-02-14T18:03:00.323CET: INFO: Read config from 'serial_tun.conf'
+
using channel 1
2011-02-14T18:03:00.323CET: INFO: Using channel 16
+
Using interface ppp0
2011-02-14T18:03:00.323CET: INFO: Retries: 5
+
Connect: ppp0 <--> /dev/ttyUSB1
2011-02-14T18:03:00.323CET: INFO: telnet console server running on port 6106
+
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xc33c412b> <pcomp> <accomp>]
2011-02-14T18:03:00.325CET: INFO: created tun device: tun0
+
rcvd [LCP ConfRej id=0x1 <magic 0xc33c412b> <pcomp>]
2011-02-14T18:03:00.609CET: INFO: interface device successfully initialized
+
sent [LCP ConfReq id=0x2 <asyncmap 0x0> <accomp>]
2011-02-14T18:03:00.609CET: INFO: starting radvd on device tun0
+
rcvd [LCP ConfAck id=0x2 <asyncmap 0x0> <accomp>]
2011-02-14T18:03:01.652CET: INFO: Starting to proxy for 0x1
+
rcvd [LCP ConfReq id=0x3 <mru 1280> <asyncmap 0x0> <accomp>]
 +
sent [LCP ConfAck id=0x3 <mru 1280> <asyncmap 0x0> <accomp>]
 +
sent [IPV6CP ConfReq id=0x1 <addr fe80::0000:0000:0000:0023>]
 +
rcvd [IPV6CP ConfReq id=0x1 <addr fe80::0000:0000:0000:0000>]
 +
sent [IPV6CP ConfNak id=0x1 <addr fe80::0000:0000:0000:0024>]
 +
rcvd [IPV6CP ConfReq id=0x2 <addr fe80::0000:0000:0000:0000>]
 +
sent [IPV6CP ConfNak id=0x2 <addr fe80::757d:cee8:dcad:b877>]
 +
rcvd [IPV6CP ConfReq id=0x3 <addr fe80::0000:0000:0000:0024>]
 +
sent [IPV6CP ConfAck id=0x3 <addr fe80::0000:0000:0000:0024>]
 +
sent [IPV6CP ConfReq id=0x1 <addr fe80::0000:0000:0000:0023>]
 +
rcvd [IPV6CP ConfAck id=0x1 <addr fe80::0000:0000:0000:0023>]
 +
local  LL address fe80::0000:0000:0000:0023
 +
remote LL address fe80::0000:0000:0000:0024
 +
Script /etc/ppp/ipv6-up started (pid 23284)
 +
Script /etc/ppp/ipv6-up finished (pid 23284), status = 0x0
 
</pre>
 
</pre>
  
The ip-driver has been setup successfully and you can now start the CoAP client.
+
Open a new terminal and run
 +
 
 +
sudo ifconfig ppp0 add fec0::100/64
 +
 
 +
The ppp connection is now established.
  
 
= Run CoAP example 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:
+
To run the CoAP example client and request a resource from the server execute the following commands :
  
  cd $TOSROOT/apps/CoapBlip/libcoap/examples
+
  cd $TOSROOT/support/sdk/c/coap/examples
 
  ./coap-client -m get coap://[fec0::3]:61616/<URI> -t binary
 
  ./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.
 
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:
+
For TelosB motes, currently the following resources are supported and can be enabled/disabled in the Makefile of the CoAP application:
*hum (Humidity)
+
 
*temp (Temperature)
+
Note: Due to restricted memory capacities on TelosB motes, you may not be able to enable all resources at the same time!
*volt (Voltage)
+
 
*r   (Temperature, Humidity and Voltage)
+
{| border="1"
*led (State of the LED's)
+
! scope="col" | &nbsp;Resource&nbsp;
 +
! scope="col" | &nbsp;GET&nbsp;
 +
! scope="col" | &nbsp;PUT&nbsp;
 +
! scope="col" | Comments
 +
|-
 +
| scope="row"  | &nbsp;/st
 +
| align="center" | X
 +
| align="center" | -
 +
| align="center" | Temperature
 +
|-
 +
| scope="row" | &nbsp;/sh
 +
| align="center" | X
 +
| align="center" | -
 +
| align="center" | Humidity
 +
|-
 +
| scope="row"  | &nbsp;/sv
 +
| align="center" | X
 +
| align="center" | -
 +
| align="center" | Voltage
 +
|-
 +
| scope="row"  | &nbsp;/r
 +
| align="center" | X
 +
| align="center" | -
 +
| align="center" | Temperature, Humidity<br> and Voltage
 +
|-
 +
| scope="row"  | &nbsp;/l
 +
| align="center" | X
 +
| align="center" | X
 +
| align="center" | LEDs
 +
|-
 +
| scope="row"  | &nbsp;/ck
 +
| align="center" | (X)  
 +
| align="center" | X
 +
| align="center" | AES Encryption Key
 +
|-
 +
| scope="row"  | &nbsp;/rt
 +
| align="center" | X
 +
| align="center" |
 +
| align="center" | Routing Table
 +
|-
 +
| scope="row" | &nbsp;.well-known/core
 +
| align="center" | X
 +
| align="center" |
 +
| align="center" | Well-Known URIs
 +
|}
 +
 
 +
For using the PUT method, the following commands can be use:
 +
 
 +
'''LED's''':
 +
 
 +
This command sets the LED's of the mote to state 2 (OFF, ON, OFF):
  
Note by requesting the Resource temp 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:
+
echo -e -n \\x02 | ./coap-client -m put coap://[fec0::3]:61616/l -T 3a -t binary -f -
  
./coap-client -m get coap://[fec0::3]:61616/temp -T <TOKEN> -t binary
+
'''AES Encryption Key''':
  
where TOKEN might be any string, e.g. 3a.
+
Since the AES key contains 25 values, the most convenient way is to store the key in a file and send its content 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 executing
 +
 +
./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 =
 
= Important parts of TinyOS CoAP =
Line 118: Line 205:
 
| Makefile extension for CoAP
 
| Makefile extension for CoAP
 
|-
 
|-
| $TOSROOT/tos/lib/app/coap/*
+
| $TOSROOT/support/sdk/c/coap/*
 +
| libcoap C-Implementation
 +
|-
 +
| $TOSROOT/support/sdk/c/coap/example/*
 +
| Example client and server using libcoap
 +
|-
 +
| $TOSROOT/tos/lib/net/coap/*
 
| Core libcoap TinyOS adaptation
 
| Core libcoap TinyOS adaptation
 
|-
 
|-
Line 126: Line 219:
 
|-
 
|-
 
| $TOSROOT/tos/interfaces/WriteResource.nc
 
| $TOSROOT/tos/interfaces/WriteResource.nc
 +
|-
 +
| $TOSROOT/tos/interfaces/CoAPClient.nc
 +
|-
 +
| $TOSROOT/tos/interfaces/CoAPServer.nc
 
|-
 
|-
 
| $TOSROOT/tos/interfaces/LibCoAP.nc
 
| $TOSROOT/tos/interfaces/LibCoAP.nc
Line 134: Line 231:
 
= Wiring your resource to the application =
 
= 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.
+
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 human readable units using fixed-point calculations.
  
 
== ReadResource ==
 
== ReadResource ==
  
The ReadResource interface currently provides three functions:
+
The ReadResource interface provides three functions:
  
 
  interface ReadResource {
 
  interface ReadResource {
     command error_t get(coap_tid_t id);        
+
     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 getDone(error_t result, coap_tid_t id, uint8_t asyn_message, uint8_t* val, size_t buflen);
     event void getPreAck(coap_tid_t id);  
+
     event void getDoneDeferred(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.
+
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. Currently, the timeout is set to 500 ms and does not lead to any deferred message exchange on TelosB motes.
  
 
Example code to wire temperature and humidity sensor on TelosB motes:
 
Example code to wire temperature and humidity sensor on TelosB motes:
Line 157: Line 256:
 
   
 
   
 
     components new CoapReadResourceC(uint16_t, KEY_TEMP) as CoapReadTempResource;
 
     components new CoapReadResourceC(uint16_t, KEY_TEMP) as CoapReadTempResource;
     CoapReadTempResource.Read -> HumTempSensor.Temperature;
+
    components new CoapBufferTempTranslateC() as CoapBufferTempTranslate;
 +
     CoapReadTempResource.Read -> CoapBufferTempTranslate.ReadTemp;
 +
    CoapBufferTempTranslate.Read -> HumTempSensor.Temperature;
 
     CoapUdpServerC.ReadResource[KEY_TEMP] -> CoapReadTempResource.ReadResource;
 
     CoapUdpServerC.ReadResource[KEY_TEMP] -> CoapReadTempResource.ReadResource;
 
   
 
   
 
     components new CoapReadResourceC(uint16_t, KEY_HUM) as CoapReadHumResource;
 
     components new CoapReadResourceC(uint16_t, KEY_HUM) as CoapReadHumResource;
     CoapReadHumResource.Read -> HumTempSensor.Humidity;
+
    components new CoapBufferHumTranslateC() as CoapBufferHumTranslate;
 +
     CoapReadHumResource.Read -> CoapBufferHumTranslate.ReadHum;
 +
    CoapBufferHumTranslate.Read -> HumTempSensor.Humidity;
 
     CoapUdpServerC.ReadResource[KEY_HUM] -> CoapReadHumResource.ReadResource;
 
     CoapUdpServerC.ReadResource[KEY_HUM] -> CoapReadHumResource.ReadResource;
 
  }
 
  }
Line 174: Line 277:
  
 
  default command error_t ReadResource.get[uint16_t uri_key](coap_tid_t id) {
 
  default command error_t ReadResource.get[uint16_t uri_key](coap_tid_t id) {
   //get not available for this resource, handle this case
+
   //GET not available for this resource, handle this case
 
   return FAIL;
 
   return FAIL;
 
  }
 
  }
  
 
After the sensor is read, ''getDone()'' is signaled and returns the sensor data. The following function handles this event:
 
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,
 
  event void ReadResource.getDone[uint16_t uri_key](error_t result,
 
                                                   coap_tid_t id,
 
                                                   coap_tid_t id,
 
                                                   uint8_t asyn_message,
 
                                                   uint8_t asyn_message,
 
                                                   uint8_t* val_buf,
 
                                                   uint8_t* val_buf,
                                                   uint8_t buflen) {
+
                                                   size_t buflen) {
 
   
 
   
 
  //send response with sensor value
 
  //send response with sensor value
 
  }
 
  }
  
The same implementation holds for the ''getPreAck()'' event.
+
The same implementation holds for the ''getDoneDeferred()'' event.
  
 
== WriteResource ==
 
== WriteResource ==
Line 195: Line 299:
  
 
The interface looks as follows:
 
The interface looks as follows:
 +
 
  interface WriteResource {
 
  interface WriteResource {
     command error_t put(uint8_t* val, uint8_t buflen);
+
     command error_t put(uint8_t *val, uint8_t buflen, coap_tid_t id);
     event void putDone(error_t result);
+
     event void putDone(error_t result, coap_tid_t id, uint8_t asyn_message);
 +
    event void putDoneDeferred(coap_tid_t id);
 
  }
 
  }
  
Line 214: Line 320:
 
  }
 
  }
  
Accessing the WriteResource out of the application, the ''put()'' function as well as its '''default''' command has to be implemented.  
+
Accessing the WriteResource out of the application, the ''put()'' function as well as its '''default''' command have to be implemented.  
  
  call WriteResource.put[get_key(uri->path.s, uri->path.length)](buf, *buflen)
+
  call WriteResource.put[get_key(uri->path.s, uri->path.length)](buf, *buflen, *id)
 
   
 
   
  default command error_t WriteResource.put[uint16_t uri_key](uint8_t* val, uint8_t buflen) {
+
  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
+
  //PUT not available for this resource, handle this case
 
  return FAIL;
 
  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.
 +
[[Image:CoapBlipC_doc.png|center]]
 +
 +
 +
= 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. [http://hinrg.cs.jhu.edu/joomla/images/stories/coap-ipsn.pdf Paper] [http://hinrg.cs.jhu.edu/joomla/images/stories/presentation-coap.pdf Presentation Slides]
 +
 +
There is also a video on youtube.com available: http://www.youtube.com/watch?v=zkB4uDhPblM

Latest revision as of 23:43, 10 July 2013

TinyOS CoAP (-03)

This page is outdated!!!

CoapBlip has been updated to draft-ietf-core-coap-13. See detailed instruction for installing CoapBlip here: CoAP_-13




This page describes how to setup the TinyOS CoAP (-03) implementation based on libcoap and uses the TinyOS blip-rpl 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

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

(Documentation for a test version of CoapBlip implementing coap-13 is available at CoAP -13.)

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

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

Installation instructions

Get the code

Make sure you have installed TinyOS and the source code.

Compile libcoap and examples

cd $TOSROOT/support/sdk/c/coap
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

Setting up PppRouter and ppp connection

To install the PppRouter application for IPv6 support on the second attached mote, execute

cd $TOSROOT/apps/PppRouter

and edit the Makefile by commenting the following line (21) out:

PFLAGS += -DBLIP_DERIVE_SHORTADDRS

Then install the PppRouter on the mote:

make telosb blip install bsl,/dev/ttyUSB1

Next, start the ppp connection by executing

sudo pppd debug passive noauth nodetach 115200 /dev/ttyUSB1 nocrtscts nocdtrcts lcp-echo-interval 0 noccp noip ipv6 ::23,::24

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

using channel 1
Using interface ppp0
Connect: ppp0 <--> /dev/ttyUSB1
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xc33c412b> <pcomp> <accomp>]
rcvd [LCP ConfRej id=0x1 <magic 0xc33c412b> <pcomp>]
sent [LCP ConfReq id=0x2 <asyncmap 0x0> <accomp>]
rcvd [LCP ConfAck id=0x2 <asyncmap 0x0> <accomp>]
rcvd [LCP ConfReq id=0x3 <mru 1280> <asyncmap 0x0> <accomp>]
sent [LCP ConfAck id=0x3 <mru 1280> <asyncmap 0x0> <accomp>]
sent [IPV6CP ConfReq id=0x1 <addr fe80::0000:0000:0000:0023>]
rcvd [IPV6CP ConfReq id=0x1 <addr fe80::0000:0000:0000:0000>]
sent [IPV6CP ConfNak id=0x1 <addr fe80::0000:0000:0000:0024>]
rcvd [IPV6CP ConfReq id=0x2 <addr fe80::0000:0000:0000:0000>]
sent [IPV6CP ConfNak id=0x2 <addr fe80::757d:cee8:dcad:b877>]
rcvd [IPV6CP ConfReq id=0x3 <addr fe80::0000:0000:0000:0024>]
sent [IPV6CP ConfAck id=0x3 <addr fe80::0000:0000:0000:0024>]
sent [IPV6CP ConfReq id=0x1 <addr fe80::0000:0000:0000:0023>]
rcvd [IPV6CP ConfAck id=0x1 <addr fe80::0000:0000:0000:0023>]
local  LL address fe80::0000:0000:0000:0023
remote LL address fe80::0000:0000:0000:0024
Script /etc/ppp/ipv6-up started (pid 23284)
Script /etc/ppp/ipv6-up finished (pid 23284), status = 0x0

Open a new terminal and run

sudo ifconfig ppp0 add fec0::100/64

The ppp connection is now established.

Run CoAP example client

To run the CoAP example client and request a resource from the server execute the following commands :

cd $TOSROOT/support/sdk/c/coap/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:

Note: Due to restricted memory capacities on TelosB motes, you may not be able to enable all resources at the same time!

 Resource   GET   PUT  Comments
 /st X - Temperature
 /sh X - Humidity
 /sv X - Voltage
 /r X - Temperature, Humidity
and Voltage
 /l X X LEDs
 /ck (X) X AES Encryption Key
 /rt X Routing Table
 .well-known/core X Well-Known URIs

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

LED's:

This 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 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 executing

./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/support/sdk/c/coap/* libcoap C-Implementation
$TOSROOT/support/sdk/c/coap/example/* Example client and server using libcoap
$TOSROOT/tos/lib/net/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 human readable 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, size_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. Currently, the timeout is set to 500 ms and does not lead to any deferred message exchange on TelosB motes.

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;
   components new CoapBufferTempTranslateC() as CoapBufferTempTranslate;
   CoapReadTempResource.Read -> CoapBufferTempTranslate.ReadTemp;
   CoapBufferTempTranslate.Read -> HumTempSensor.Temperature;
   CoapUdpServerC.ReadResource[KEY_TEMP] -> CoapReadTempResource.ReadResource;

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

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,
                                                  size_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 have 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

There is also a video on youtube.com available: http://www.youtube.com/watch?v=zkB4uDhPblM