Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Register your application with the OpenWSN stack

This is the only step that requires you to edit anything outside of those two main application files. Goto your openwsnopendefs.h file and add a UNIQUE identifier to the "//component identifiers" enum structure (see below).

Code Block
languagecpp
//component identifiers
enum {
   COMPONENT_NULL                      = 0x00,
   //cross-layers
   COMPONENT_IDMANAGER                 = 0x01,
   COMPONENT_OPENQUEUE                 = 0x02,
  .
  .
  .
   //App applications
   COMPONENT_OHLONEC6T                       = 0x1e0x1a,
   COMPONENT_HELICEXAMPLE                  = 0x1b, //--YOUR APP IDENTIFIER--//
 = 0x1f,  .
   .
   COMPONENT_IMU  UECHO                     = 0x200x23,
   COMPONENT_RLEDSUINJECT                     = 0x210x24,
   COMPONENT_RREG RRT                     = 0x22,
   COMPONENT_RWELLKNOWN                = 0x230x25,
   COMPONENT_RTSECURITY                        = 0x240x26,
   COMPONENT_REX                       = 0x25, //--YOUR APP IDENTIFIER--//
   .
   .
   .
};

We also need to go to openwsn.c, and add rex_init() into our main initialization function (rex_init()is described below):

Code Block
languagecpp
openwsn.c
void openwsn_init() {
   // drivers
   openserial};

We also need to go to openapps.c, and add cexample_init() into our main initialization function (cexample_init()is described below):

Code Block
languagecpp
openwsn.c
.
.
.
#include "cleds.h"
#include "cexample.h" // add header file
#include "cstorm.h"
.
.
.
void openapps_init() {
   // CoAP
   c6t_init();
   cinfo_init();
   cexample_init(); // add initial function
   cleds__init();
   cstorm_init();
   cwellknown_init();
   rrt_init();
  .
  .
  .
  rex_init(); //initialize your app here
  rleds_init();
  rreg_init();
  .
  .
  .
}

Basic application Structure

...

}

Basic application Structure

The core of our app lives in cexample.c, while rexcexample.h only holds prototyping information. Taking a closer look at rexcexample.c, we notice some basic include statements. No matter what your app does, you will likely need most of these:

Code Block
languagecpp
#include "openwsnopendefs.h"
#include "cexample.h"
#include  //basic OpenWSN information"opencoap.h"
#include "opentimers.h"
#include "rexopenqueue.h"       
#include "opencoappacketfunctions.h"    //CoAP
features
#include "opentimersopenserial.h"
 //Timer support
#include "openqueueopenrandom.h"  
//OpenWSN packet formats
#include "packetfunctionsscheduler.h"
#include "openserialADC_Channel.h"

 //Support for serial interface in case you want to debug
#include "scheduler.h"   //The ability to push your application tasks to the OS sheduler
#include "ADC_Channel.h" //ADC functionality

Basic application Structure

The application defines some basic properties: How long is our timer period? How large will our packets be? What is the short name of our application when others access it via CoAP?

No Format
/// inter-packet period (in ms)
#define REXPERIOD    5000           //5 seconds
#define PAYLOADLEN   62#include "IEEE802154E.h"

Basic application Structure

The application defines some basic properties: How long is our timer period? How large will our packets be? What is the short name of our application when others access it via CoAP?

No Format
/// inter-packet period (in ms)
#define CEXAMPLEPERIOD  10000
#define PAYLOADLEN      40
const uint8_t cexample_path0[] = "ex";

We now need to create an cexample_init() function, which will be called when OpenWSN first starts. This function will initialize the variables that describe the "cexample" app to CoAP. Furthermore, we point to two callback functions: One is called when receives a packet from CoAP, and one is called when cexample is done sending a packet to CoAP. We will not use these functions in this example, but they may be useful to you in the future. Consider them like higher-level interrupts that alert your application of network traffic over IPv6. We then register the app with CoAP, and start a timer (describe below).

Code Block
languagecpp
void cexample_init() {
   // prepare the resource descriptor for the /ex path
   cexample_vars.desc.path0len            //bytes const= uint8_t rex_path0[] = "rex"; //application name on the internet

We now need to create an rex_init() function, which will be called when OpenWSN first starts. This function will initialize the variables that describe the "rex" app to CoAP. Furthermore, we point to two callback functions: One is called when receives a packet from CoAP, and one is called when rex is done sending a packet to CoAP. We will not use these functions in this example, but they may be useful to you in the future. Consider them like higher-level interrupts that alert your application of network traffic over IPv6. We then register the app with CoAP, and start a timer (describe below).

Code Block
languagecpp
void rex_init() {sizeof(cexample_path0)-1;
   cexample_vars.desc.path0val             = (uint8_t*)(&cexample_path0);
   cexample_vars.desc.path1len             = 0;
   cexample_vars.desc.path1val             = //NULL;
prepare the resource descriptor for the /rex path cexample_vars.desc.componentID        rex  = COMPONENT_CEXAMPLE;
   cexample_vars.desc.path0lendiscoverable             = sizeof(rex_path0)-1TRUE;
   rexcexample_vars.desc.path0val callbackRx            = (uint8_t*)(&rex_path0)&cexample_receive;
   rexcexample_vars.desc.path1lencallbackSendDone     = &cexample_sendDone;
   
  = 0;
   rex_vars.desc.path1valopencoap_register(&cexample_vars.desc);
     cexample_vars.timerId       = NULL;opentimers_start(CEXAMPLEPERIOD,
   rex_vars.desc.componentID          = COMPONENT_REX;    rex_vars.desc.callbackRx           = &rex_receive;    rex_vars.desc.callbackSendDone     = &rex_sendDone;        //Register and start timer now
   opencoap_register(&rex_vars.desc);
   rex_vars.timerId    = opentimers_start(REXPERIODTIMER_PERIODIC,TIME_MS,
                                                TIMER_PERIODIC,
                                                rex_timer_cb);
}

...

cexample_timer_cb);

}

Starting a periodic timer

In the above lines, our app starts an openTimer, which is a higher-level timer module you can use to execute single or periodic tasks within OpenWSN. The code above tells openTimers to call the function rex

cexample_timer_cb(), once every

...

CEXAMPLEPERIOD milliseconds. We set the timer type to TIMER_PERIODIC, to tell the timer module to execute

...

 cexample_timer_cb() periodically, rather than just one time.

Executing a function once the timer expires

Once every 5 seconds we will want to run the ADC, collect a readings, and send it out. When the timer fires it will call rexcexample_timer_cb():

Code Block
languagecpp
//timer fired, but we don't want to execute task in ISR mode
//instead, push task to scheduler with COAP priority, and let scheduler take care of it
void rexcexample_timer_cb(){
   scheduler_push_task(rexcexample_task_cb,TASKPRIO_COAP);
}

...

Every micro-controller has a different means by which to sample its ADC. In the rex example, we are using the ADC on an MSP430. The code to take an ADC reading will be different for each micro controller. Please see the rex example in the OpenWSN repository for how to do it on the MSP430, or edit the code below to suit your purposes:

...

languagecpp

...

Code Block
languagecpp
void cexample_task_cb() {
   OpenQueueEntry_t*    pkt;
   owerror_t            outcome;
   uint8_t              i;
   
   uint16_t             x_int       = 0;
   uint16_t             sum         = 0;
   uint16_t             avg         = 0;
   
   // don't run if not synch
   if (ieee154e_isSynch() == FALSE) return;
   
   // don't run on dagroot
   if (idmanager_getIsDAGroot()) {
      opentimers_stop(cexample_vars.timerId);
      return;
   numOptions;}
    
   //Take ADC reding here and store it in the avg value

  uint16_t avg = SampleADC(); //This will be custom for your platform
   
   // create a CoAP RD packet
   pkt = openqueue_getFreePacketBuffer(COMPONENT_CEXAMPLE);
   if (pkt==NULL) {
      openserial_printError(COMPONENT_REX,ERR_NO_FREE_PACKET_BUFFER,
         COMPONENT_CEXAMPLE,
         ERR_NO_FREE_PACKET_BUFFER,
         (errorparameter_t)0,
                0,
           (errorparameter_t)0
      );
      openqueue_freePacketBuffer(pkt);
      return;
   }
   // take ownership over that packet
   pkt->creator                   = COMPONENT_REXCEXAMPLE;
   pkt->owner                     = COMPONENT_REXCEXAMPLE;
   // CoAP payload
   packetfunctions_reserveHeaderSize(pkt,PAYLOADLEN);
   for (i=0;i<PAYLOADLEN;i++) {
      pkt->payload[i] = i;
  
}      pkt->payload[0i] = (avg>>8)&0xff;    pkt->payload[1] = (avg>>0)&0xff;
       numOptions = 0i;
   //}
location-path option  avg = packetfunctions_reserveHeaderSize(pkt,sizeof(rex_path0)-1)openrandom_get16b();
   memcpy(&pkt->payload[0],&rex_path0,sizeof(rex_path0)-1);                = packetfunctions_reserveHeaderSize(pkt,1)(avg>>8)&0xff;
   pkt->payload[01]                  = (COAP_OPTION_LOCATIONPATH-COAP_OPTION_CONTENTTYPE) << 4 |avg>>0)&0xff;
   packetfunctions_reserveHeaderSize(pkt,1);
   pkt->payload[0]   sizeof(rex_path0)-1= COAP_PAYLOAD_MARKER;
   numOptions++;
   // content-type option
   packetfunctions_reserveHeaderSize(pkt,2);
   pkt->payload[0]                =  =(COAP_OPTION_NUM_CONTENTFORMAT - COAP_OPTION_NUM_CONTENTTYPEURIPATH) << 4
|          1;    pkt->payload[1]                  = COAP_MEDTYPE_APPOCTETSTREAM;   | numOptions++1;
   pkt->payload[1]  // metadata    pkt->l4_destination_port         = WKPCOAP_UDPMEDTYPE_COAPAPPOCTETSTREAM;
   pkt->l3_destinationORsource.type = ADDR_128B// location-path option
   packetfunctions_reserveHeaderSize(pkt,sizeof(cexample_path0)-1);
   memcpy(&pkt->l3_destinationORsource.addr_128b>payload[0],&ipAddr_motesEecs,16,cexample_path0,sizeof(cexample_path0)-1);
   // send
   outcome = opencoap_send(pkt,packetfunctions_reserveHeaderSize(pkt,1);
   pkt->payload[0]                = ((COAP_OPTION_NUM_URIPATH) << 4)   | (sizeof(cexample_path0)-1);
   
 COAP_TYPE_NON,  // metadata
   pkt->l4_destination_port       = WKP_UDP_COAP;
   pkt->l3_destinationAdd.type    = ADDR_128B;
   COAP_CODE_REQ_PUT,memcpy(&pkt->l3_destinationAdd.addr_128b[0],&ipAddr_motesEecs,16);
   
   // send
   outcome       = opencoap_send(
       numOptionspkt,
      COAP_TYPE_NON,
      COAP_CODE_REQ_PUT,
      1,
      &rexcexample_vars.desc
   );
   
   // avoid overflowing the queue if fails
   if (outcome==E_FAIL) {
      openqueue_freePacketBuffer(pkt);
   }
   
   return;
}

The above function allocates an OpenWSN packet, sets its ownership properties to the REX CEXAMPLE app. It also samples the ADC and stores the ADC result in a 16bit variable. This variable is then passed into an OpenWSN packet, along with some CoAP settings. Furthermore, the application selects a destination address 
"pkt->l3_destinationORsource.addr_128b0" which denotes the IPv6 address our packet is intended for. In this case the address is "ipAddr_motesEecs," which is the IPv6 address of our server (http://motes.eecs.berkeley.edu).(Note: this server is temporally down) If you are running your own CoAP server, replace this address with the address of your server. Feel free to use our server however, as it is already running and you can simply store all your sensor readings there. 

Setting up OpenVisualizer to forward IPv6 CoAP packets

...