Patrick Barrett / libexositecoap
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers exosite.c Source File

exosite.c

00001 /*****************************************************************************
00002 *
00003 *  exosite.c - Exosite Activator Library
00004 *  Copyright (C) 2015 Exosite LLC
00005 *
00006 *  Redistribution and use in source and binary forms, with or without
00007 *  modification, are permitted provided that the following conditions
00008 *  are met:
00009 *
00010 *    Redistributions of source code must retain the above copyright
00011 *    notice, this list of conditions and the following disclaimer.
00012 *
00013 *    Redistributions in binary form must reproduce the above copyright
00014 *    notice, this list of conditions and the following disclaimer in the
00015 *    documentation and/or other materials provided with the
00016 *    distribution.
00017 *
00018 *    Neither the name of Texas Instruments Incorporated nor the names of
00019 *    its contributors may be used to endorse or promote products derived
00020 *    from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00025 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00026 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00028 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00029 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00030 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00031 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00032 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 *
00034 *****************************************************************************/
00035 #include "exosite_pal.h"
00036 #include "exosite.h"
00037 #include "coap.h"
00038 
00039 #include <stdlib.h>
00040 #include <stdbool.h>
00041 #include <time.h>
00042 #include <string.h>
00043 #include <ctype.h>
00044 
00045 // Internal Functions
00046 
00047 static void exo_process_waiting_datagrams(exo_op *op, uint8_t count);
00048 static void exo_process_active_ops(exo_op *op, uint8_t count);
00049 exo_error exo_build_msg_activate(coap_pdu *pdu, const char *vendor, const char *model, const char *serial_number);
00050 exo_error exo_build_msg_read(coap_pdu *pdu, const char *alias);
00051 exo_error exo_build_msg_observe(coap_pdu *pdu, const char *alias);
00052 exo_error exo_build_msg_write(coap_pdu *pdu, const char *alias, const char *value);
00053 exo_error exo_build_msg_rst(coap_pdu *pdu, const uint16_t mid, const uint64_t token, const uint8_t tkl);
00054 exo_error exo_build_msg_ack(coap_pdu *pdu, const uint16_t mid);
00055 uint8_t exosite_validate_cik(char *cik);
00056 
00057 // Local Variables
00058 static char cik[CIK_LENGTH  + 1];
00059 static const char *vendor;
00060 static const char *model;
00061 static const char *serial;
00062 static uint16_t message_id_counter;
00063 static exo_device_state device_state = EXO_STATE_UNINITIALIZED;
00064 
00065 // Internal Constants
00066 static const int MINIMUM_DATAGRAM_SIZE = 576; // RFC791: all hosts must accept minimum of 576 octets
00067 
00068 /*!
00069  * \brief  Initializes the Exosite library
00070  *
00071  * This **MUST** be called before any other exosite library calls are called.
00072  *
00073  * \param[in] *vendor  Pointer to string containing the vendor name
00074  * \param[in] *model   Pointer to string containing the model name
00075  * \param[in] *serial  Pointer to string containing the serial number
00076  *
00077  * \return EXO_ERROR, EXO_OK on success, else error code
00078  */
00079 exo_error exo_init(const char *vendor_in, const char *model_in, const char *serial_in)
00080 {
00081   device_state = EXO_STATE_UNINITIALIZED;
00082 
00083   if (exopal_init() != 0) {
00084     return EXO_FATAL_ERROR_PAL;
00085   }
00086 
00087   srand(time(NULL));
00088   message_id_counter = rand();
00089 
00090   serial = serial_in;
00091   vendor = vendor_in;
00092   model = model_in;
00093 
00094   if (exopal_retrieve_cik(cik) > 1){
00095     return EXO_FATAL_ERROR_PAL;
00096   } else {
00097     cik[40] = 0;
00098   }
00099 
00100   if (exopal_udp_sock() != 0) {
00101     return EXO_FATAL_ERROR_PAL;
00102   }
00103 
00104   device_state = EXO_STATE_INITIALIZED;
00105 
00106   return EXO_OK;
00107 }
00108 
00109 /*!
00110  * \brief  Queues a Write to the Exosite One Platform
00111  *
00112  * Queues a request to write to a dataport.
00113  *
00114  * \param[in] *alias    Alias of dataport to write to, pointer must remain
00115  *                      valid until the request has been sent.
00116  * \param[in] callback  Function pointer to call on success
00117  *
00118  * \return EXO_ERROR, EXO_OK on success or error code
00119  *
00120  */
00121 
00122 void exo_write(exo_op *op, const char * alias, const char * value)
00123 {
00124   op->type = EXO_WRITE;
00125   op->state = EXO_REQUEST_NEW;
00126   op->alias = alias;
00127   op->value = (char *)value; // this is kinda dirty, I know
00128   op->value_max = 0;
00129   op->mid = 0;
00130 }
00131 
00132 /*!
00133  * \brief  Queues a Read from the Exosite One Platform
00134  *
00135  * Queues a request to read a dataport. If the request is successful, the
00136  * provided callback will be called with a single parameter, a pointer to the
00137  * result as a C string.
00138  *
00139  * \param[in] *alias    Alias of dataport to read from, pointer must remain
00140  *                      valid until the request has been sent.
00141  * \param[in] callback  Function pointer to call on success
00142  *
00143  * \return EXO_ERROR, EXO_OK on success or error code
00144  *
00145  */
00146 void exo_read(exo_op *op, const char * alias, char * value, const size_t value_max)
00147 {
00148   op->type = EXO_READ;
00149   op->state = EXO_REQUEST_NEW;
00150   op->alias = alias;
00151   op->value = value;
00152   op->value_max = value_max;
00153   op->mid = 0;
00154 }
00155 
00156 /*!
00157  * \brief  Subscribes to a Dataport on the Exosite One Platform
00158  *
00159  * Begins a subscription to a dataport  The callback is called any time the
00160  * value is updated as well as when the subscription is started.
00161  *
00162  * \param[in] alias     Alias of dataport to read from
00163  * \param[in] callback  Function pointer to call on change
00164  *
00165  * \return EXO_ERROR, EXO_OK on success or error code
00166  *
00167  */
00168 void exo_subscribe(exo_op *op, const char * alias, char * value, const size_t value_max)
00169 {
00170   op->type = EXO_SUBSCRIBE;
00171   op->state = EXO_REQUEST_NEW;
00172   op->alias = alias;
00173   op->value = value;
00174   op->value_max = value_max;
00175   op->mid = 0;
00176 }
00177 
00178 /*!
00179  * \brief  Activates the Device on the Platform
00180  *
00181  * Queues an activation request. Usually only used internally.
00182  *
00183  */
00184 void exo_activate(exo_op *op)
00185 {
00186   op->type = EXO_ACTIVATE;
00187   op->state = EXO_REQUEST_NEW;
00188   op->alias = NULL;
00189   op->value = NULL;
00190   op->value_max = 0;
00191   op->mid = 0;
00192 }
00193 
00194 void exo_op_init(exo_op *op)
00195 {
00196   op->type = EXO_NULL;
00197   op->state = EXO_REQUEST_NULL;
00198   op->alias = NULL;
00199   op->value = NULL;
00200   op->value_max = 0;
00201   op->mid = 0;
00202   op->obs_seq = 0;
00203   op->tkl = 0;
00204   op->token = 0;
00205   op->timeout = 0;
00206   op->retries = 0;
00207 }
00208 
00209 void exo_op_done(exo_op *op)
00210 {
00211   if (exo_is_op_subscribe(op)) {
00212     op->state = EXO_REQUEST_SUBSCRIBED;
00213   } else {
00214     exo_op_init(op);
00215   }
00216 }
00217 
00218 uint8_t exo_is_op_valid(exo_op *op)
00219 {
00220   return op->type != EXO_NULL;
00221 }
00222 
00223 uint8_t exo_is_op_success(exo_op *op)
00224 {
00225   return op->state == EXO_REQUEST_SUCCESS;
00226 }
00227 
00228 uint8_t exo_is_op_finished(exo_op *op)
00229 {
00230   return op->state == EXO_REQUEST_SUCCESS || op->state == EXO_REQUEST_ERROR;
00231 }
00232 
00233 uint8_t exo_is_op_read(exo_op *op)
00234 {
00235   return op->type == EXO_READ;
00236 }
00237 
00238 uint8_t exo_is_op_subscribe(exo_op *op)
00239 {
00240   return op->type == EXO_SUBSCRIBE;
00241 }
00242 
00243 uint8_t exo_is_op_write(exo_op *op)
00244 {
00245   return op->type == EXO_WRITE;
00246 }
00247 
00248 
00249 /*!
00250  * \brief Performs queued operations with the Exosite One Platform
00251  *
00252  * Queues a request to read a dataport from the Exosite One Platform. If the
00253  * request is successful the provided callback will be called with a single
00254  * parameter, a pointer to the result as a C string.
00255  *
00256  * \param[in] alias     Alias of dataport to read from
00257  * \param[in] callback  Function pointer to call on success
00258  *
00259  * \return EXO_STATE, EXO_OK on success or error code
00260  *
00261  */
00262 exo_state exo_operate(exo_op *op, uint8_t count)
00263 {
00264   int i;
00265 
00266   switch (device_state){
00267     case EXO_STATE_UNINITIALIZED:
00268       return EXO_ERROR;
00269     case EXO_STATE_INITIALIZED:
00270     case EXO_STATE_BAD_CIK:
00271       if (op[0].state == EXO_REQUEST_NULL || op[0].timeout < exopal_get_time())
00272         exo_activate(&op[0]);
00273     case EXO_STATE_GOOD:
00274       break;
00275   }
00276 
00277   exo_process_waiting_datagrams(op, count);
00278   exo_process_active_ops(op, count);
00279 
00280   for (i = 0; i < count; i++) {
00281     if (op[i].state == EXO_REQUEST_NEW)
00282       return EXO_BUSY;
00283   }
00284 
00285   for (i = 0; i < count; i++) {
00286     if (op[i].state == EXO_REQUEST_PENDING)
00287       return EXO_WAITING;
00288   }
00289 
00290   return EXO_IDLE;
00291 }
00292 
00293 // Internal Functions
00294 
00295 static void exo_process_waiting_datagrams(exo_op *op, uint8_t count)
00296 {
00297   uint8_t buf[MINIMUM_DATAGRAM_SIZE];
00298   coap_pdu pdu;
00299   coap_option opt;
00300   coap_payload payload;
00301   int i;
00302 
00303   pdu.buf = buf;
00304   pdu.max = MINIMUM_DATAGRAM_SIZE;
00305   pdu.len = 0;
00306 
00307   // receive a UDP packet if one or more waiting
00308   while (exopal_udp_recv(pdu.buf, pdu.max, &pdu.len) == 0) {
00309     if (coap_validate_pkt(&pdu) != CE_NONE)
00310       continue; //Invalid Packet, Ignore
00311 
00312     for (i = 0; i < count; i++) {
00313       if (coap_get_type(&pdu) == CT_CON || coap_get_type(&pdu) == CT_NON) {
00314         if (op[i].state == EXO_REQUEST_SUBSCRIBED && coap_get_token(&pdu) == op[i].token) {
00315           if (coap_get_code(&pdu) == CC_CONTENT) {
00316             uint32_t new_seq = 0;
00317             opt = coap_get_option_by_num(&pdu, CON_OBSERVE, 0);
00318             for (int j = 0; j < opt.len; j++) {
00319               new_seq = (new_seq << (8*j)) | opt.val[j];
00320             }
00321 
00322             payload = coap_get_payload(&pdu);
00323             if (payload.len == 0) {
00324               op[i].value[0] = '\0';
00325             } else if (payload.len+1 > op[i].value_max || op[i].value == 0) {
00326               op[i].state = EXO_REQUEST_ERROR;
00327             } else{
00328               memcpy(op[i].value, payload.val, payload.len);
00329               op[i].value[payload.len] = 0;
00330               op[i].mid = coap_get_mid(&pdu);
00331               // TODO: User proper logic to ensure it's a new value not a different, but old one.
00332               if (op[i].obs_seq != new_seq) {
00333                 op[i].state = EXO_REQUEST_SUB_ACK_NEW;
00334                 op[i].obs_seq = new_seq;
00335               } else {
00336                 op[i].state = EXO_REQUEST_SUB_ACK;
00337               }
00338 
00339               opt = coap_get_option_by_num(&pdu, CON_MAX_AGE, 0);
00340               uint8_t max_age = 120; // default, 2 minutes, see RFC4787 Sec 4.3
00341               if (opt.num !=0 && opt.len == 1){ // if has Max-Age option, use it
00342                 max_age = opt.val[0];
00343               }
00344 
00345               // Set timeout between Max-Age to Max-Age + ACK_RANDOM_FACTOR (CoAP Defined)
00346               op[i].timeout = exopal_get_time() + (max_age * 1000000)
00347                                                 + (((uint64_t)rand() % 1500000));
00348             }
00349           } else if (coap_get_code_class(&pdu) != 2) {
00350             op[i].state = EXO_REQUEST_ERROR;
00351           }
00352           break;
00353         }
00354       } else if (coap_get_type(&pdu) == CT_ACK) {
00355         if (op[i].state == EXO_REQUEST_PENDING && op[i].mid == coap_get_mid(&pdu)) {
00356           if (coap_get_code_class(&pdu) == 2) {
00357             switch (op[i].type) {
00358               case EXO_WRITE:
00359                 op[i].state = EXO_REQUEST_SUCCESS;
00360                 break;
00361               case EXO_READ:
00362                 payload = coap_get_payload(&pdu);
00363                 if (payload.len == 0) {
00364                   op[i].value[0] = '\0';
00365                 } else if (payload.len+1 > op[i].value_max || op[i].value == 0) {
00366                   op[i].state = EXO_REQUEST_ERROR;
00367                 } else{
00368                   memcpy(op[i].value, payload.val, payload.len);
00369                   op[i].value[payload.len] = 0;
00370                   op[i].state = EXO_REQUEST_SUCCESS;
00371                 }
00372                 break;
00373               case EXO_SUBSCRIBE:
00374                 payload = coap_get_payload(&pdu);
00375                 if (payload.len == 0) {
00376                   op[i].value[0] = '\0';
00377                 } else if (payload.len+1 > op[i].value_max || op[i].value == 0) {
00378                   op[i].state = EXO_REQUEST_ERROR;
00379                 } else{
00380                   memcpy(op[i].value, payload.val, payload.len);
00381                   op[i].value[payload.len] = 0;
00382                   op[i].state = EXO_REQUEST_SUCCESS;
00383 
00384                   opt = coap_get_option_by_num(&pdu, CON_MAX_AGE, 0);
00385                   uint8_t max_age = 120; // default, 2 minutes, see RFC4787 Sec 4.3
00386                   if (opt.num !=0 && opt.len == 1){ // if has Max-Age option, use it
00387                     max_age = opt.val[0];
00388                   }
00389 
00390                   opt = coap_get_option_by_num(&pdu, CON_OBSERVE, 0);
00391                   for (int j = 0; j < opt.len; j++) {
00392                     op[i].obs_seq = (op[i].obs_seq << (8*j)) | opt.val[j];
00393                   }
00394 
00395                   // Set timeout between Max-Age to Max-Age + ACK_RANDOM_FACTOR (CoAP Defined)
00396                   op[i].timeout = exopal_get_time() + (max_age * 1000000)
00397                                                     + (((uint64_t)rand() % 1500000));
00398                 }
00399                 break;
00400               case EXO_ACTIVATE:
00401                 payload = coap_get_payload(&pdu);
00402                 if (payload.len == CIK_LENGTH) {
00403                   memcpy(cik, payload.val, CIK_LENGTH);
00404                   cik[CIK_LENGTH] = 0;
00405                   op[i].state = EXO_REQUEST_SUCCESS;
00406                   exopal_store_cik(cik);
00407                   device_state = EXO_STATE_GOOD;
00408                 } else {
00409                   op[i].state = EXO_REQUEST_ERROR;
00410                 }
00411 
00412                 // We're done with this op now.
00413                 exo_op_init(&op[i]);
00414                 break;
00415               case EXO_NULL: // pending null request? shouldn't be possible
00416                 continue;
00417             }
00418           } else {
00419             op[i].state = EXO_REQUEST_ERROR;
00420 
00421             if (coap_get_code(&pdu) == CC_UNAUTHORIZED){
00422               //device_state = EXO_STATE_BAD_CIK;
00423 
00424               if (op[0].type == EXO_NULL || op[0].timeout < exopal_get_time())
00425                 exo_activate(&op[0]);
00426             } else if (coap_get_code(&pdu) == CC_NOT_FOUND) {
00427               device_state = EXO_STATE_GOOD;
00428             }
00429           }
00430 
00431           break;
00432         }
00433 
00434       } else if (coap_get_type(&pdu) == CT_RST) {
00435         if ((op[i].state == EXO_REQUEST_PENDING || op[i].state == EXO_REQUEST_SUBSCRIBED) &&
00436             (op[i].mid == coap_get_mid(&pdu) && op[i].token == coap_get_token(&pdu))){
00437           op[i].state = EXO_REQUEST_ERROR;
00438           break;
00439         }
00440       }
00441     }
00442 
00443     // if the above loop ends normally we don't recognize message, reply RST
00444     if (i == count){
00445       if (coap_get_type(&pdu) == CT_CON) {
00446         // this can't fail
00447         exo_build_msg_rst(&pdu, coap_get_mid(&pdu), coap_get_token(&pdu), coap_get_tkl(&pdu));
00448 
00449         // best effort, don't bother checking if it failed, nothing we can do it
00450         // it did anyway
00451         exopal_udp_send(pdu.buf, pdu.len);
00452       }
00453 
00454       break;
00455     }
00456   }
00457 }
00458 
00459 // process all ops that are in an active state
00460 static void exo_process_active_ops(exo_op *op, uint8_t count)
00461 {
00462   uint8_t buf[MINIMUM_DATAGRAM_SIZE];
00463   coap_pdu pdu;
00464   int i;
00465   uint64_t now = exopal_get_time();
00466 
00467   pdu.buf = buf;
00468   pdu.max = MINIMUM_DATAGRAM_SIZE;
00469   pdu.len = 0;
00470 
00471   for (i = 0; i < count; i++) {
00472     switch (op[i].state) {
00473       case EXO_REQUEST_NEW:
00474         // Build and Send Request
00475         switch (op[i].type) {
00476           case EXO_READ:
00477             exo_build_msg_read(&pdu, op[i].alias);
00478             break;
00479           case EXO_SUBSCRIBE:
00480             exo_build_msg_observe(&pdu, op[i].alias);
00481             break;
00482           case EXO_WRITE:
00483             exo_build_msg_write(&pdu, op[i].alias, op[i].value);
00484             break;
00485           case EXO_ACTIVATE:
00486             exo_build_msg_activate(&pdu, vendor, model, serial);
00487             break;
00488           default:
00489             op[i].type = EXO_NULL;
00490             continue;
00491         }
00492 
00493         if (exopal_udp_send(pdu.buf, pdu.len) == 0) {
00494           op[i].state = EXO_REQUEST_PENDING;
00495           op[i].timeout = exopal_get_time() + 4000000;
00496           op[i].mid = coap_get_mid(&pdu);
00497           op[i].token = coap_get_token(&pdu);
00498         }
00499 
00500         break;
00501       case EXO_REQUEST_SUBSCRIBED:
00502       case EXO_REQUEST_PENDING:
00503         // check if pending requests have reached timeout
00504         if (op[i].timeout <= now){
00505           switch (op[i].type) {
00506             case EXO_READ:
00507             case EXO_WRITE:
00508             case EXO_ACTIVATE:
00509               if (op[i].retries < COAP_MAX_RETRANSMIT){
00510                 switch (op[i].type) {
00511                   case EXO_READ:
00512                     exo_build_msg_read(&pdu, op[i].alias);
00513                     break;
00514                   case EXO_WRITE:
00515                     exo_build_msg_write(&pdu, op[i].alias, op[i].value);
00516                     break;
00517                   case EXO_ACTIVATE:
00518                     exo_build_msg_activate(&pdu, vendor, model, serial);
00519                     break;
00520                   default:
00521                     break;
00522                 }
00523 
00524                 // reuse old mid and token
00525                 coap_set_mid(&pdu, op[i].mid);
00526                 coap_set_token(&pdu, op[i].token, op[i].tkl);
00527 
00528                 if (exopal_udp_send(pdu.buf, pdu.len) == 0) {
00529                   op[i].retries++;
00530                   op[i].timeout = exopal_get_time() + (op[i].retries * COAP_PROBING_RATE * 1000000)
00531                                                     + (((uint64_t)rand() % 1500000));
00532                 }
00533               } else {
00534                 op[i].state = EXO_REQUEST_ERROR;
00535               }
00536               break;
00537             case EXO_SUBSCRIBE:
00538               // force a new observe request
00539               op[i].state = EXO_REQUEST_NEW;
00540               break;
00541             default:
00542               break;
00543           }
00544         }
00545         break;
00546       case EXO_REQUEST_SUB_ACK_NEW:
00547       case EXO_REQUEST_SUB_ACK:
00548         // send ack for observe notification
00549         exo_build_msg_ack(&pdu, coap_get_mid(&pdu));
00550 
00551         if (exopal_udp_send(pdu.buf, pdu.len) == 0) {
00552           if (op[i].state == EXO_REQUEST_SUB_ACK)
00553             op[i].state = EXO_REQUEST_SUBSCRIBED;
00554           else if (op[i].state == EXO_REQUEST_SUB_ACK_NEW)
00555             op[i].state = EXO_REQUEST_SUCCESS;
00556         }
00557         break;
00558       default:
00559         break;
00560     }
00561   }
00562 }
00563 
00564 
00565 exo_error exo_build_msg_activate(coap_pdu *pdu, const char *vendor, const char *model, const char *serial_number)
00566 {
00567     coap_error ret;
00568     coap_init_pdu(pdu);
00569     ret = coap_set_version(pdu, COAP_V1);
00570     ret |= coap_set_type(pdu, CT_CON);
00571     ret |= coap_set_code(pdu, CC_POST);
00572     ret |= coap_set_mid(pdu, message_id_counter++);
00573     ret |= coap_set_token(pdu, rand(), 2);
00574     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)"provision", 9);
00575     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)"activate", 8);
00576     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)vendor, strlen(vendor));
00577     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)model, strlen(model));
00578     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)serial_number, strlen(serial_number));
00579 
00580     if (ret != CE_NONE)
00581       return EXO_GENERAL_ERROR;
00582 
00583     return EXO_OK;
00584 }
00585 
00586 exo_error exo_build_msg_read(coap_pdu *pdu, const char *alias)
00587 {
00588     coap_error ret;
00589     coap_init_pdu(pdu);
00590     ret = coap_set_version(pdu, COAP_V1);
00591     ret |= coap_set_type(pdu, CT_CON);
00592     ret |= coap_set_code(pdu, CC_GET);
00593     ret |= coap_set_mid(pdu, message_id_counter++);
00594     ret |= coap_set_token(pdu, rand(), 2);
00595     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)"1a", 2);
00596     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)alias, strlen(alias));
00597     ret |= coap_add_option(pdu, CON_URI_QUERY, (uint8_t*)cik, 40);
00598 
00599     if (ret != CE_NONE)
00600       return EXO_GENERAL_ERROR;
00601 
00602     return EXO_OK;
00603 }
00604 
00605 exo_error exo_build_msg_observe(coap_pdu *pdu, const char *alias)
00606 {
00607     uint8_t obs_opt = 0;
00608     coap_error ret;
00609     coap_init_pdu(pdu);
00610     ret = coap_set_version(pdu, COAP_V1);
00611     ret |= coap_set_type(pdu, CT_CON);
00612     ret |= coap_set_code(pdu, CC_GET);
00613     ret |= coap_set_mid(pdu, message_id_counter++);
00614     ret |= coap_set_token(pdu, rand(), 2);
00615     ret |= coap_add_option(pdu, CON_OBSERVE, &obs_opt, 1);
00616     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)"1a", 2);
00617     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)alias, strlen(alias));
00618     ret |= coap_add_option(pdu, CON_URI_QUERY, (uint8_t*)cik, 40);
00619 
00620     if (ret != CE_NONE)
00621       return EXO_GENERAL_ERROR;
00622 
00623     return EXO_OK;
00624 }
00625 
00626 exo_error exo_build_msg_write(coap_pdu *pdu, const char *alias, const char *value)
00627 {
00628     coap_error ret;
00629     coap_init_pdu(pdu);
00630     ret = coap_set_version(pdu, COAP_V1);
00631     ret |= coap_set_type(pdu, CT_CON);
00632     ret |= coap_set_code(pdu, CC_POST);
00633     ret |= coap_set_mid(pdu, message_id_counter++);
00634     ret |= coap_set_token(pdu, rand(), 2);
00635     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)"1a", 2);
00636     ret |= coap_add_option(pdu, CON_URI_PATH, (uint8_t*)alias, strlen(alias));
00637     ret |= coap_add_option(pdu, CON_URI_QUERY, (uint8_t*)cik, 40);
00638     ret |= coap_set_payload(pdu, (uint8_t *)value, strlen(value));
00639 
00640     if (ret != CE_NONE)
00641       return EXO_GENERAL_ERROR;
00642 
00643     return EXO_OK;
00644 }
00645 
00646 exo_error exo_build_msg_rst(coap_pdu *pdu, const uint16_t mid, const uint64_t token, const uint8_t tkl)
00647 {
00648     coap_error ret;
00649     coap_init_pdu(pdu);
00650     ret = coap_set_version(pdu, COAP_V1);
00651     ret |= coap_set_type(pdu, CT_RST);
00652     ret |= coap_set_code(pdu, CC_EMPTY);
00653     ret |= coap_set_mid(pdu, mid);
00654     ret |= coap_set_token(pdu, token, tkl);
00655 
00656     if (ret != CE_NONE)
00657       return EXO_GENERAL_ERROR;
00658 
00659     return EXO_OK;
00660 }
00661 
00662 exo_error exo_build_msg_ack(coap_pdu *pdu, const uint16_t mid)
00663 {
00664     coap_error ret;
00665     coap_init_pdu(pdu);
00666     ret = coap_set_version(pdu, COAP_V1);
00667     ret |= coap_set_type(pdu, CT_ACK);
00668     ret |= coap_set_code(pdu, CC_EMPTY);
00669     ret |= coap_set_mid(pdu, mid);
00670 
00671     if (ret != CE_NONE)
00672       return EXO_GENERAL_ERROR;
00673 
00674     return EXO_OK;
00675 }
00676 
00677 exo_error exo_do_activate()
00678 {
00679   exo_op op;
00680 
00681   exo_op_init(&op);
00682 
00683 
00684   return EXO_OK;
00685 }
00686 
00687 uint8_t exo_util_is_ascii_hex(const char *str, size_t len)
00688 {
00689     size_t i;
00690 
00691     for (i = 0; i < len; i++) {
00692         if (!((str[i] >= 'a' && str[i] <= 'f') ||
00693               (str[i] >= '0' && str[i] <= '9'))) {
00694             return 1;
00695         }
00696     }
00697 
00698     return 0;
00699 }
00700