mbed 5.4 with sleep mode

Dependencies:   C027_Support mbed-dev

Fork of C027_SupportTest_coap by Umar Naeem

Files at this revision

API Documentation at this revision

Comitter:
ranaumarnaeem
Date:
Thu May 25 11:53:45 2017 +0000
Parent:
38:f1bc6e867fcf
Commit message:
mbed 5.4 with sleep mode

Changed in this revision

Coap/coap_client.c Show diff for this revision Revisions of this file
Coap/coap_client.cpp Show annotated file Show diff for this revision Revisions of this file
Coap/coap_client.h Show annotated file Show diff for this revision Revisions of this file
Coap/coap_msg.c Show diff for this revision Revisions of this file
Coap/coap_msg.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r f1bc6e867fcf -r 4f3f7463e55f Coap/coap_client.c
--- a/Coap/coap_client.c	Wed May 24 07:51:33 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1021 +0,0 @@
-/*
- * Copyright (c) 2015 Keith Cullen.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- *  @file coap_client.c
- *
- *  @brief Source file for the FreeCoAP client library
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-
-#include "coap_client.h"
-#include "main.h"
-
-#define COAP_CLIENT_ACK_TIMEOUT_SEC   2                                         /**< Minimum delay to wait before retransmitting a confirmable message */
-#define COAP_CLIENT_MAX_RETRANSMIT    4                                         /**< Maximum number of times a confirmable message can be retransmitted */
-#define COAP_CLIENT_RESP_TIMEOUT_SEC  30                                        /**< Maximum amount of time to wait for a response */
-
-/****************************************************************************************************
- *                                           coap_client                                            *
- ****************************************************************************************************/
-void coap_client_destroy(coap_client_t *client)
-{
-    memset(client, 0, sizeof(coap_client_t));
-}
-
-/**
- *  @brief Send a message to the server
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Number of bytes sent or error code
- *  @retval >0 Number of bytes sent
- *  @retval <0 Error
- */
-static int coap_client_send(coap_client_t *client, coap_msg_t *msg)
-{
-    int num = 0;
-    char buf[COAP_MSG_MAX_BUF_LEN] = {0};
-
-    num = coap_msg_format(msg, buf, sizeof(buf));
-    if (num < 0)
-    {
-        return num;
-    }
-    num = send(client->sd, buf, num);
-    if (num < 0)
-    {
-        printf("send error\n");
-        return -errno;
-    }
-
-    return num;
-}
-
-/**
- *  @brief Handle a format error in a received message
- *
- *  Special handling for the case where a received
- *  message could not be parsed due to a format error.
- *  Extract enough information from the received message
- *  to form a reset message.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] buf Buffer containing the message
- *  @param[in] len length of the buffer
- */
-static void coap_client_handle_format_error(coap_client_t *client, char *buf, size_t len)
-{
-    coap_msg_t msg = {0};
-    unsigned msg_id = 0;
-    unsigned type = 0;
-    int ret = 0;
-
-    ret = coap_msg_parse_type_msg_id(buf, len, &type, &msg_id);
-    if ((ret == 0) && (type == COAP_MSG_CON))
-    {
-        coap_msg_create(&msg);
-        ret = coap_msg_set_type(&msg, COAP_MSG_RST);
-        if (ret < 0)
-        {
-            coap_msg_destroy(&msg);
-            return;
-        }
-        ret = coap_msg_set_msg_id(&msg, msg_id);
-        if (ret < 0)
-        {
-            coap_msg_destroy(&msg);
-            return;
-        }
-        coap_client_send(client, &msg);
-        coap_msg_destroy(&msg);
-    }
-}
-
-/**
- *  @brief Receive a message from the server
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Number of bytes received or error code
- *  @retval >0 Number of bytes received
- *  @retval <0 Error
- */
-static int coap_client_recv(coap_client_t *client, coap_msg_t *msg)
-{
-    int num = 0;
-    int ret = 0;
-    char buf[COAP_MSG_MAX_BUF_LEN] = {0};
-
-    num = recv(client->sd, buf, sizeof(buf));
-    if (num < 0)
-    {
-        return -errno;
-    }
-
-    ret = coap_msg_parse(msg, buf, num);
-    if (ret < 0)
-    {
-        if (ret == -EBADMSG)
-        {
-            coap_client_handle_format_error(client, buf, num);
-        }
-        return ret;
-    }
-    return num;
-}
-
-/**
- *  @brief Reject a received confirmable message
- *
- *  Send a reset message to the server.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_reject_con(coap_client_t *client, coap_msg_t *msg)
-{
-    coap_msg_t rej = {0};
-    int num = 0;
-    int ret = 0;
-
-    printf("Rejecting confirmable message from host %s and port %s\n", client->server_host, client->server_port);
-    coap_msg_create(&rej);
-    ret = coap_msg_set_type(&rej, COAP_MSG_RST);
-    if (ret < 0)
-    {
-        coap_msg_destroy(&rej);
-        return ret;
-    }
-    ret = coap_msg_set_msg_id(&rej, coap_msg_get_msg_id(msg));
-    if (ret < 0)
-    {
-        coap_msg_destroy(&rej);
-        return ret;
-    }
-    num = coap_client_send(client, &rej);
-    coap_msg_destroy(&rej);
-    if (num < 0)
-    {
-        return num;
-    }
-    return 0;
-}
-
-/**
- *  @brief Reject a received non-confirmable message
- *
- *  @param[in] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Operation status
- *  @retval 0 Success
- */
-static int coap_client_reject_non(coap_client_t *client, coap_msg_t *msg)
-{
-    printf("Rejecting non-confirmable message from host %s and port %s\n", client->server_host, client->server_port);
-    return 0;
-}
-
-/**
- *  @brief Reject a received acknowledgement message
- *
- *  @param[in] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Operation status
- *  @retval 0 Success
- */
-static int coap_client_reject_ack(coap_client_t *client, coap_msg_t *msg)
-{
-    printf("Rejecting acknowledgement message from host %s and port %s\n", client->server_host, client->server_port);
-    return 0;
-}
-
-/**
- *  @brief Reject a received reset message
- *
- *  @param[in] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Operation status
- *  @retval 0 Success
- */
-static int coap_client_reject_reset(coap_client_t *client, coap_msg_t *msg)
-{
-    printf("Rejecting reset message from host %s and port %s\n", client->server_host, client->server_port);
-    return 0;
-}
-
-/**
- *  @brief Reject a received message
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_reject(coap_client_t *client, coap_msg_t *msg)
-{
-    if (coap_msg_get_type(msg) == COAP_MSG_CON)
-    {
-        return coap_client_reject_con(client, msg);
-    }
-    else if (coap_msg_get_type(msg) == COAP_MSG_NON)
-    {
-        return coap_client_reject_non(client, msg);
-    }
-    else if (coap_msg_get_type(msg) == COAP_MSG_ACK)
-    {
-        return coap_client_reject_ack(client, msg);
-    }
-    else if (coap_msg_get_type(msg) == COAP_MSG_RST)
-    {
-        return coap_client_reject_reset(client, msg);
-    }
-    return 0;  /* should never arrive here */
-}
-
-/**
- *  @brief Send an acknowledgement message to the server
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] msg Pointer to a message structure
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_send_ack(coap_client_t *client, coap_msg_t *msg)
-{
-    coap_msg_t ack = {0};
-    int num = 0;
-    int ret = 0;
-
-    printf("Acknowledging confirmable message from host %s and port %s\n", client->server_host, client->server_port);
-    coap_msg_create(&ack);
-    ret = coap_msg_set_type(&ack, COAP_MSG_ACK);
-    if (ret < 0)
-    {
-        coap_msg_destroy(&ack);
-        return ret;
-    }
-    ret = coap_msg_set_msg_id(&ack, coap_msg_get_msg_id(msg));
-    if (ret < 0)
-    {
-        coap_msg_destroy(&ack);
-        return ret;
-    }
-    num = coap_client_send(client, &ack);
-    coap_msg_destroy(&ack);
-    if (num < 0)
-    {
-        return num;
-    }
-    return 0;
-}
-
-/**
- *  @brief Compare the token values in a request message and a response message
- *
- *  @param[in] req Pointer to the request message
- *  @param[in] resp Pointer to the response message
- *
- *  @returns Comparison value
- *  @retval 0 the tokens are not equal
- *  @retval 1 the tokens are equal
- */
-static int coap_client_match_token(coap_msg_t *req, coap_msg_t *resp)
-{
-    return ((coap_msg_get_token_len(resp) == coap_msg_get_token_len(req))
-         && (memcmp(coap_msg_get_token(resp), coap_msg_get_token(req), coap_msg_get_token_len(req)) == 0));
-}
-
-/**
- *  @brief Check that all of the options in a message are acceptable
- *
- *  For a proxy, options are acceptable if they are safe to forward or recognized or both.
- *  For a server, options are acceptable if they are elective or recognized or both.
- *
- *  @param[in] msg Pointer to message structure
- *
- *  @returns Operation status or bad option number
- *  @retval 0 Success
- *  @retval >0 Bad option number
- */
-static unsigned coap_client_check_options(coap_msg_t *msg)
-{
-#ifdef COAP_PROXY
-    return coap_msg_check_unsafe_ops(msg);
-#else  /* !COAP_PROXY */
-    return coap_msg_check_critical_ops(msg);
-#endif  /* COAP_PROXY */
-}
-
-/**
- *  @brief Handle a received piggy-backed response message
- *
- *  An acknowledgement has been received that contains
- *  the same token as the request. Check the response
- *  contained within it.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] resp Pointer to the response message
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_handle_piggybacked_response(coap_client_t *client, coap_msg_t *resp)
-{
-    unsigned op_num = 0;
-
-    op_num = coap_client_check_options(resp);
-    if (op_num != 0)
-    {
-        printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port);
-        coap_client_reject(client, resp);
-        return -EBADMSG;
-    }
-    printf("Received acknowledgement and response from Server\n");
-    return 0;
-}
-
-/**
- *  @brief Handle a received separate response message
- *
- *  A separate response has been received that contains
- *  the same token as the request. Check the response
- *  and send an acknowledgement if necessary.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] resp Pointer to the response message
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_handle_sep_response(coap_client_t *client, coap_msg_t *resp)
-{
-    unsigned op_num = 0;
-
-    if (coap_msg_get_type(resp) == COAP_MSG_CON)
-    {
-        printf("Received confirmable response from host %s and port %s\n", client->server_host, client->server_port);
-        op_num = coap_client_check_options(resp);
-        if (op_num != 0)
-        {
-            printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port);
-            coap_client_reject(client, resp);
-            return -EBADMSG;
-        }
-        return coap_client_send_ack(client, resp);
-    }
-    else if (coap_msg_get_type(resp) == COAP_MSG_NON)
-    {
-        printf("Received non-confirmable response from host %s and port %s\n", client->server_host, client->server_port);
-        op_num = coap_client_check_options(resp);
-        if (op_num != 0)
-        {
-            printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port);
-            coap_client_reject(client, resp);
-            return -EBADMSG;
-        }
-        return 0;
-    }
-    coap_client_reject(client, resp);
-    return -EBADMSG;
-}
-
-/**
- *  @brief Handle a separate response to a confirmable request
- *
- *  An acknowledgement has been received. Receive the
- *  response and send an acknowledgement back to the server.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] req Pointer to the request message
- *  @param[out] resp Pointer to the response message
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_exchange_sep(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
-{
-    int num = 0;
-    int ret = 0;
-    int starttimeout,endtimeout;
-
-    /* wait for a separate response to a confirmable request */
-    printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port);
-    while (1)
-    {
-        starttimeout = readseconds();
-        while(1)
-        {
-            num = coap_client_recv(client, resp);
-            if (num < 0)
-            {
-                return num;
-            }
-            else if(num > 0)
-            {
-                break;    
-            }
-            endtimeout = readseconds();
-            if((endtimeout - starttimeout) > COAP_CLIENT_RESP_TIMEOUT_SEC)
-            {
-                printf("Timeout no data received\n");  
-                return -1;  
-            }
-        }
-        
-        if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req))
-        {
-            if (coap_msg_get_type(resp) == COAP_MSG_ACK)
-            {
-                /* message deduplication */
-                printf("Received duplicate acknowledgement from host %s and port %s\n", client->server_host, client->server_port);
-                continue;
-            }
-            else if (coap_msg_get_type(resp) == COAP_MSG_RST)
-            {
-                return -ECONNRESET;
-            }
-            coap_client_reject(client, resp);
-            return -EBADMSG;
-        }
-        if (coap_client_match_token(req, resp))
-        {
-             return coap_client_handle_sep_response(client, resp);
-        }
-        /* message deduplication */
-        /* we might have received a duplicate message that was already received from the same server */
-        /* reject the message and continue listening */
-        ret = coap_client_reject(client, resp);
-        if (ret < 0 )
-        {
-            return ret;
-        }
-    }
-    return 0;
-}
-
-/**
- *  @brief Handle the response to a confirmable request
- *
- *  A confirmable request has been sent to the server.
- *  Receive the acknowledgement and response. Send an
- *  acknowledgement if necessary.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] req Pointer to the request message
- *  @param[out] resp Pointer to the response message
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_client_exchange_con(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
-{
-    int num = 0;
-    int ret = 0;
-    int starttimeout,endtimeout;
-    /*  wait for piggy-backed response in ack message
-     *  or ack message and separate response message
-     */
-    //printf("Expecting acknowledgement from server\r\n");
-    client->num_retrans = 0;
-    while (1)
-    {
-        int doubletimeout = COAP_CLIENT_ACK_TIMEOUT_SEC;
-        starttimeout = readseconds();
-        while(1)
-        {
-            num = coap_client_recv(client, resp);
-            if (num < 0)
-            {
-                //return num;
-            }
-            else if(num > 0)
-            {
-                break;    
-            }
-            endtimeout = readseconds();
-            if((endtimeout - starttimeout) > doubletimeout)
-            {
-                printf("Timeout no data received after %d seconds\n",endtimeout - starttimeout);
-
-                if (client->num_retrans >= COAP_CLIENT_MAX_RETRANSMIT)
-                {
-                    printf("Maximum retries reached no ack from server!\r\n");
-                    return -ETIMEDOUT;
-                }
-                
-                doubletimeout = 2 * doubletimeout;
-                starttimeout = readseconds();
-                client->num_retrans++;
-
-                printf("Retransmitting to server...\r\n");
-                num = coap_client_send(client, req);
-                if (num < 0)
-                {
-                    printf("Resending Failed to server...\r\n");
-                    return num;
-                } 
-            }
-        }
-         
-        if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req))
-        {
-            if (coap_msg_get_type(resp) == COAP_MSG_ACK)
-            {
-                if (coap_msg_is_empty(resp))
-                {
-                    /* received ack message, wait for separate response message */
-                    printf("Received acknowledgement from host %s and port %s\n", client->server_host, client->server_port);
-                    return coap_client_exchange_sep(client, req, resp);
-                }
-                else if (coap_client_match_token(req, resp))
-                {
-                    return coap_client_handle_piggybacked_response(client, resp);
-                }
-            }
-            else if (coap_msg_get_type(resp) == COAP_MSG_RST)
-            {
-                return -ECONNRESET;
-            }
-            coap_client_reject(client, resp);
-            return -EBADMSG;
-        }
-        else if (coap_client_match_token(req, resp))
-        {
-            /* RFC7252
-             * as the underlying datagram transport may not be sequence-preserving,
-             * the Confirmable message carrying the response may actually arrive
-             * before or after the Acknowledgement message for the request; for
-             * the purposes of terminating the retransmission sequence, this also
-             * serves as an acknowledgement.
-             */
-             return coap_client_handle_sep_response(client, resp);
-        }
-        /* message deduplication */
-        /* we might have received a duplicate message that was already received from the same server */
-        /* reject the message and continue listening */
-        ret = coap_client_reject(client, resp);
-        if (ret < 0 )
-        {
-            return ret;
-        }
-    }
-    return 0;
-}
-
-/**
- *  @brief Handle the response to a non-confirmable request
- *
- *  A non-confirmable request has been sent to the server.
- *  Receive the response.
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] req Pointer to the request message
- *  @param[out] resp Pointer to the response message
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- **/
-static int coap_client_exchange_non(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
-{
-    int num = 0;
-    int ret = 0;
-    int starttimeout,endtimeout;
-
-    printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port);
-    while (1)
-    {
-        starttimeout = readseconds();
-        while(1)
-        {
-            num = coap_client_recv(client, resp);
-            if (num < 0)
-            {
-                return num;
-            }
-            else if(num > 0)
-            {
-                break;    
-            }
-            endtimeout = readseconds();
-            if((endtimeout - starttimeout) > COAP_CLIENT_RESP_TIMEOUT_SEC)
-            {
-                printf("Timeout no data received\n");    
-                return -1;
-            }
-        }
- 
-        if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req))
-        {
-            if (coap_msg_get_type(resp) == COAP_MSG_RST)
-            {
-                return -ECONNRESET;
-            }
-            coap_client_reject(client, resp);
-            return -EBADMSG;
-        }
-        if (coap_client_match_token(req, resp))
-        {
-             return coap_client_handle_sep_response(client, resp);
-        }
-        /* message deduplication */
-        /* we might have received a duplicate message that was already received from the same server */
-        /* reject the message and continue listening */
-        ret = coap_client_reject(client, resp);
-        if (ret < 0 )
-        {
-            return ret;
-        }
-    }
-    return 0;
-}
-
-int coap_client_exchange(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
-{
-    unsigned char msg_id_buf[2] = {0};
-    unsigned msg_id = 0;
-    int num = 0;
-    char token[4] = {0};
-    int ret = 0;
-
-    /* check for a valid request */
-    if ((coap_msg_get_type(req) == COAP_MSG_ACK)
-     || (coap_msg_get_type(req) == COAP_MSG_RST)
-     || (coap_msg_get_code_class(req) != COAP_MSG_REQ))
-    {
-        return -EINVAL;
-    }
-
-    /* generate the message ID */
-    coap_msg_gen_rand_str((char *)msg_id_buf, sizeof(msg_id_buf));
-    msg_id = (((unsigned)msg_id_buf[1]) << 8) | (unsigned)msg_id_buf[0];
-    ret = coap_msg_set_msg_id(req, msg_id);
-    if (ret < 0)
-    {
-        return ret;
-    }
-
-    /* generate the token */
-    coap_msg_gen_rand_str(token, sizeof(token));
-    ret = coap_msg_set_token(req, token, sizeof(token));
-    if (ret < 0)
-    {
-        return ret;
-    }
-
-    num = coap_client_send(client, req);
-    if (num < 0)
-    {
-        return num;
-    }
-
-    if (coap_msg_get_type(req) == COAP_MSG_CON)
-    {
-        return coap_client_exchange_con(client, req, resp);
-    }
-    else if (coap_msg_get_type(req) == COAP_MSG_NON)
-    {
-        return coap_client_exchange_non(client, req, resp);
-    }
-    return -EINVAL;
-}
-//----------------------------------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------------------------------
-/**
- *  @brief Test an exchange with the server
- *
- *  @param[in] data Pointer to a client test data structure
- *
- *  @returns Test result
- */
-test_result_t test_exchange_func(char* buf,int buf_len)
-{
-    printf("----------------------------------------\n");
-    test_result_t result = PASS;
-    coap_client_t client = {0};
-    coap_msg_t resp = {0};
-    coap_msg_t req = {0};
-    int ret = 0;
-
-    test_coap_client_msg_op_t req_ops;
-        req_ops.num = COAP_MSG_URI_PATH;
-        req_ops.len = 8;
-        req_ops.val = (char*)"resource";
-        
-    test_coap_client_msg_op_t resp_ops;
-        resp_ops.num = 0;
-        resp_ops.len = 0;
-        resp_ops.val = 0;
-
-    test_coap_client_msg_t test1_req;
-        test1_req.type = COAP_MSG_CON;
-        test1_req.code_class = COAP_MSG_REQ;
-        test1_req.code_detail = COAP_MSG_GET;
-        test1_req.ops = req_ops;
-        test1_req.num_ops = 1;
-        test1_req.payload = buf;
-        test1_req.payload_len = buf_len;
-
-    test_coap_client_msg_t test1_resp;
-        test1_resp.type = COAP_MSG_ACK;
-        test1_resp.code_class = COAP_MSG_SUCCESS;
-        test1_resp.code_detail = COAP_MSG_CONTENT;
-        test1_resp.ops = resp_ops;
-        test1_resp.num_ops = 0;
-        test1_resp.payload = (char*)"Hello Client!";
-        test1_resp.payload_len = 13;
-
-    test_coap_client_data_t test1_data; 
-        test1_data.desc = "Send a confirmable request to server and expect a piggy-backed response";
-        test1_data.host = HOST;
-        test1_data.port = PORT;
-        test1_data.common_name = (char*)"dummy/server";
-        test1_data.test_req = test1_req;
-        test1_data.test_resp = test1_resp;
-        test1_data.num_msg = 1;
-
-    //printf("%s\n", test1_data.desc);
-
-    if (ret < 0)
-    {
-        printf("Error  : %s\n",strerror(-ret));
-        return FAIL;
-    }
-
-        coap_msg_create(&req);
-        coap_msg_create(&resp);
-        
-        ret = exchange(&client, &test1_data.test_req, &req, &resp);
-        //printf("exchange function\n");
-        if (ret != PASS)
-        {
-            printf("exchange function fail\n");
-            coap_msg_destroy(&resp);
-            coap_msg_destroy(&req);
-            coap_client_destroy(&client);
-            return FAIL;
-        }
-
-        ret = compare_ver_token(&req, &resp);
-        if (ret != PASS)
-        {
-            coap_msg_destroy(&resp);
-            coap_msg_destroy(&req);
-            coap_client_destroy(&client);
-            return FAIL;
-        }
-
-        ret = check_resp(&test1_data.test_resp, &resp);
-        if (ret != PASS)
-        {
-            coap_msg_destroy(&resp);
-            coap_msg_destroy(&req);
-            coap_client_destroy(&client);
-            return FAIL;
-        }
-
-    coap_msg_destroy(&resp);
-    coap_msg_destroy(&req);
-    coap_client_destroy(&client);
-
-    return result;
-}
-//----------------------------------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------------------------------
-/**
- *  @brief Print a CoAP message
- *
- *  @param[in] str String to be printed before the message
- *  @param[in] msg Pointer to a message structure
- */
-void print_coap_msg(const char *str, coap_msg_t *msg)
-{
-    //coap_msg_op_t *op = NULL;
-    //unsigned num = 0;
-    //unsigned len = 0;
-    unsigned i = 0;
-    //unsigned j = 0;
-    char *payload = NULL;
-    char *token = NULL;
-    //char *val = NULL;
-
-    printf("%s\n", str);
-    printf("ver:         0x%02x\n", coap_msg_get_ver(msg));
-    printf("type:        0x%02x\n", coap_msg_get_type(msg));
-    printf("token_len:   %d\n", coap_msg_get_token_len(msg));
-    printf("code_class:  %d\n", coap_msg_get_code_class(msg));
-    printf("code_detail: %d\n", coap_msg_get_code_detail(msg));
-    printf("msg_id:      0x%04x\n", coap_msg_get_msg_id(msg));
-    printf("token:      ");
-    token = coap_msg_get_token(msg);
-    for (i = 0; i < coap_msg_get_token_len(msg); i++)
-    {
-        printf(" 0x%02x", (unsigned char)token[i]);
-    }
-    printf("\n");
-    /*op = coap_msg_get_first_op(msg);
-    while (op != NULL)
-    {
-        num = coap_msg_op_get_num(op);
-        len = coap_msg_op_get_len(op);
-        val = coap_msg_op_get_val(op);
-        printf("op[%u].num:   %u\n", j, num);
-        printf("op[%u].len:   %u\n", j, len);
-        printf("op[%u].val:  ", j);
-        for (i = 0; i < len; i++)
-        {
-            printf(" 0x%02x", (unsigned char)val[i]);
-        }
-        printf("\n");
-        op = coap_msg_op_get_next(op);
-        j++;
-    }*/
-    printf("payload:     ");
-    payload = coap_msg_get_payload(msg);
-    for (i = 0; i < coap_msg_get_payload_len(msg); i++)
-    {
-        printf("%c", payload[i]);
-    //ucReturnCode[i] = payload[i];
-    }
-    //ucReturnCode[i] = '\0';
-    printf("\n");
-    printf("payload_len: %zu\n", coap_msg_get_payload_len(msg));
-}
-//----------------------------------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------------------------------
-/**
- *  @brief Populate a request message with details from a test request message structure
- *
- *  @param[in] test_req Pointer to a test request message structure
- *  @param[out] req Pointer to a request message structure
- *
- *  @returns Test result
- */
-test_result_t populate_req(test_coap_client_msg_t *test_req, coap_msg_t *req)
-{
-    int ret = 0;
-
-    ret = coap_msg_set_type(req, test_req->type);
-    if (ret < 0)
-    {
-        printf("Error  : %s\n",strerror(-ret));
-        return FAIL;
-    }
-    ret = coap_msg_set_code(req, test_req->code_class, test_req->code_detail);
-    if (ret < 0)
-    {
-        printf("Error  : %s\n",strerror(-ret));
-        return FAIL;
-    }
-    ret = coap_msg_add_op(req, test_req->ops.num, test_req->ops.len, test_req->ops.val);
-    if (ret < 0)
-    {
-        printf("Error  : %s\n",strerror(-ret));
-        return FAIL;
-    }
-    if (test_req->payload)
-    {
-        ret = coap_msg_set_payload(req, test_req->payload, test_req->payload_len);
-        if (ret < 0)
-        {
-            printf("Error  : %s\n",strerror(-ret));
-            return FAIL;
-        }
-    }
-    return PASS;
-}
-//----------------------------------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------------------------------
-/**
- *  @brief Send a request to the server and receive the response
- *
- *  @param[in,out] client Pointer to a client structure
- *  @param[in] test_req Pointer to a test request message structure
- *  @param[out] req Pointer to a request message structure
- *  @param[out] resp Pointer to a response message structure
- *
- *  @returns Test result
- */
-test_result_t exchange(coap_client_t *client, test_coap_client_msg_t *test_req, coap_msg_t *req, coap_msg_t *resp)
-{
-    test_result_t result = PASS;
-    int ret = 0;
-
-    result = populate_req(test_req, req);
-    if (result != PASS)
-    {
-        printf("populate_req FAIL\n");
-        return result;
-    }
-    ret = coap_client_exchange(client, req, resp);
-    if (ret < 0)
-    {
-        printf("coap_client_exchange FAIL\n");
-        printf("Error  : %s\n",strerror(-ret));
-        return FAIL;
-    }
-    //printf("coap_client_exchange PASS\n");
-    print_coap_msg("Sent:", req);
-    print_coap_msg("Received:", resp);
-
-    return PASS;
-}
-//----------------------------------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------------------------------
-/**
- *  @brief Compare the version and token fields in a request message and a response message
- *
- *  @param[out] req Pointer to a request message structure
- *  @param[out] resp Pointer to a response message structure
- *
- *  @returns Test result
- */
-test_result_t compare_ver_token(coap_msg_t *req, coap_msg_t *resp)
-{
-    if (coap_msg_get_ver(req) != coap_msg_get_ver(resp))
-    {
-        return FAIL;
-    }
-    if (coap_msg_get_token_len(req) != coap_msg_get_token_len(resp))
-    {
-        return FAIL;
-    }
-    else if (memcmp(coap_msg_get_token(req), coap_msg_get_token(resp), coap_msg_get_token_len(req)) != 0)
-    {
-        return FAIL;
-    }
-    return PASS;
-}
-//----------------------------------------------------------------------------------------------------------------------
-//----------------------------------------------------------------------------------------------------------------------
-/**
- *  @brief Check the fields in a response message against the expected values
- *
- *  @param[out] test_resp Pointer to a test response message structure
- *  @param[out] resp Pointer to a response message structure
- *
- *  @returns Test result
- */
-test_result_t check_resp(test_coap_client_msg_t *test_resp, coap_msg_t *resp)
-{
-    if (test_resp->type != coap_msg_get_type(resp))
-    {
-        return FAIL;
-    }
-    if (test_resp->code_class != coap_msg_get_code_class(resp))
-    {
-        return FAIL;
-    }
-    if (test_resp->code_detail != coap_msg_get_code_detail(resp))
-    {
-        return FAIL;
-    }
-    return PASS;
-}
diff -r f1bc6e867fcf -r 4f3f7463e55f Coap/coap_client.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Coap/coap_client.cpp	Thu May 25 11:53:45 2017 +0000
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2015 Keith Cullen.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ *  @file coap_client.c
+ *
+ *  @brief Source file for the FreeCoAP client library
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "coap_client.h"
+#include "main.h"
+
+#define COAP_CLIENT_ACK_TIMEOUT_SEC   2                                         /**< Minimum delay to wait before retransmitting a confirmable message */
+#define COAP_CLIENT_MAX_RETRANSMIT    4                                         /**< Maximum number of times a confirmable message can be retransmitted */
+#define COAP_CLIENT_RESP_TIMEOUT_SEC  30                                        /**< Maximum amount of time to wait for a response */
+
+/****************************************************************************************************
+ *                                           coap_client                                            *
+ ****************************************************************************************************/
+void coap_client_destroy(coap_client_t *client)
+{
+    memset(client, 0, sizeof(coap_client_t));
+}
+
+/**
+ *  @brief Send a message to the server
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Number of bytes sent or error code
+ *  @retval >0 Number of bytes sent
+ *  @retval <0 Error
+ */
+static int coap_client_send(coap_client_t *client, coap_msg_t *msg)
+{
+    int num = 0;
+    char buf[COAP_MSG_MAX_BUF_LEN] = {0};
+
+    num = coap_msg_format(msg, buf, sizeof(buf));
+    if (num < 0)
+    {
+        return num;
+    }
+    num = send(client->sd, buf, num);
+    if (num < 0)
+    {
+        printf("send error\n");
+        return -errno;
+    }
+
+    return num;
+}
+
+/**
+ *  @brief Handle a format error in a received message
+ *
+ *  Special handling for the case where a received
+ *  message could not be parsed due to a format error.
+ *  Extract enough information from the received message
+ *  to form a reset message.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] buf Buffer containing the message
+ *  @param[in] len length of the buffer
+ */
+static void coap_client_handle_format_error(coap_client_t *client, char *buf, size_t len)
+{
+    coap_msg_t msg = {0};
+    unsigned msg_id = 0;
+    unsigned type = 0;
+    int ret = 0;
+
+    ret = coap_msg_parse_type_msg_id(buf, len, &type, &msg_id);
+    if ((ret == 0) && (type == COAP_MSG_CON))
+    {
+        coap_msg_create(&msg);
+        ret = coap_msg_set_type(&msg, COAP_MSG_RST);
+        if (ret < 0)
+        {
+            coap_msg_destroy(&msg);
+            return;
+        }
+        ret = coap_msg_set_msg_id(&msg, msg_id);
+        if (ret < 0)
+        {
+            coap_msg_destroy(&msg);
+            return;
+        }
+        coap_client_send(client, &msg);
+        coap_msg_destroy(&msg);
+    }
+}
+
+/**
+ *  @brief Receive a message from the server
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Number of bytes received or error code
+ *  @retval >0 Number of bytes received
+ *  @retval <0 Error
+ */
+static int coap_client_recv(coap_client_t *client, coap_msg_t *msg)
+{
+    int num = 0;
+    int ret = 0;
+    char buf[COAP_MSG_MAX_BUF_LEN] = {0};
+
+    num = recv(client->sd, buf, sizeof(buf));
+    if (num < 0)
+    {
+        return -errno;
+    }
+
+    ret = coap_msg_parse(msg, buf, num);
+    if (ret < 0)
+    {
+        if (ret == -EBADMSG)
+        {
+            coap_client_handle_format_error(client, buf, num);
+        }
+        return ret;
+    }
+    return num;
+}
+
+/**
+ *  @brief Reject a received confirmable message
+ *
+ *  Send a reset message to the server.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_reject_con(coap_client_t *client, coap_msg_t *msg)
+{
+    coap_msg_t rej = {0};
+    int num = 0;
+    int ret = 0;
+
+    printf("Rejecting confirmable message from host %s and port %s\n", client->server_host, client->server_port);
+    coap_msg_create(&rej);
+    ret = coap_msg_set_type(&rej, COAP_MSG_RST);
+    if (ret < 0)
+    {
+        coap_msg_destroy(&rej);
+        return ret;
+    }
+    ret = coap_msg_set_msg_id(&rej, coap_msg_get_msg_id(msg));
+    if (ret < 0)
+    {
+        coap_msg_destroy(&rej);
+        return ret;
+    }
+    num = coap_client_send(client, &rej);
+    coap_msg_destroy(&rej);
+    if (num < 0)
+    {
+        return num;
+    }
+    return 0;
+}
+
+/**
+ *  @brief Reject a received non-confirmable message
+ *
+ *  @param[in] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ */
+static int coap_client_reject_non(coap_client_t *client, coap_msg_t *msg)
+{
+    printf("Rejecting non-confirmable message from host %s and port %s\n", client->server_host, client->server_port);
+    return 0;
+}
+
+/**
+ *  @brief Reject a received acknowledgement message
+ *
+ *  @param[in] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ */
+static int coap_client_reject_ack(coap_client_t *client, coap_msg_t *msg)
+{
+    printf("Rejecting acknowledgement message from host %s and port %s\n", client->server_host, client->server_port);
+    return 0;
+}
+
+/**
+ *  @brief Reject a received reset message
+ *
+ *  @param[in] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ */
+static int coap_client_reject_reset(coap_client_t *client, coap_msg_t *msg)
+{
+    printf("Rejecting reset message from host %s and port %s\n", client->server_host, client->server_port);
+    return 0;
+}
+
+/**
+ *  @brief Reject a received message
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_reject(coap_client_t *client, coap_msg_t *msg)
+{
+    if (coap_msg_get_type(msg) == COAP_MSG_CON)
+    {
+        return coap_client_reject_con(client, msg);
+    }
+    else if (coap_msg_get_type(msg) == COAP_MSG_NON)
+    {
+        return coap_client_reject_non(client, msg);
+    }
+    else if (coap_msg_get_type(msg) == COAP_MSG_ACK)
+    {
+        return coap_client_reject_ack(client, msg);
+    }
+    else if (coap_msg_get_type(msg) == COAP_MSG_RST)
+    {
+        return coap_client_reject_reset(client, msg);
+    }
+    return 0;  /* should never arrive here */
+}
+
+/**
+ *  @brief Send an acknowledgement message to the server
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] msg Pointer to a message structure
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_send_ack(coap_client_t *client, coap_msg_t *msg)
+{
+    coap_msg_t ack = {0};
+    int num = 0;
+    int ret = 0;
+
+    printf("Acknowledging confirmable message from host %s and port %s\n", client->server_host, client->server_port);
+    coap_msg_create(&ack);
+    ret = coap_msg_set_type(&ack, COAP_MSG_ACK);
+    if (ret < 0)
+    {
+        coap_msg_destroy(&ack);
+        return ret;
+    }
+    ret = coap_msg_set_msg_id(&ack, coap_msg_get_msg_id(msg));
+    if (ret < 0)
+    {
+        coap_msg_destroy(&ack);
+        return ret;
+    }
+    num = coap_client_send(client, &ack);
+    coap_msg_destroy(&ack);
+    if (num < 0)
+    {
+        return num;
+    }
+    return 0;
+}
+
+/**
+ *  @brief Compare the token values in a request message and a response message
+ *
+ *  @param[in] req Pointer to the request message
+ *  @param[in] resp Pointer to the response message
+ *
+ *  @returns Comparison value
+ *  @retval 0 the tokens are not equal
+ *  @retval 1 the tokens are equal
+ */
+static int coap_client_match_token(coap_msg_t *req, coap_msg_t *resp)
+{
+    return ((coap_msg_get_token_len(resp) == coap_msg_get_token_len(req))
+         && (memcmp(coap_msg_get_token(resp), coap_msg_get_token(req), coap_msg_get_token_len(req)) == 0));
+}
+
+/**
+ *  @brief Check that all of the options in a message are acceptable
+ *
+ *  For a proxy, options are acceptable if they are safe to forward or recognized or both.
+ *  For a server, options are acceptable if they are elective or recognized or both.
+ *
+ *  @param[in] msg Pointer to message structure
+ *
+ *  @returns Operation status or bad option number
+ *  @retval 0 Success
+ *  @retval >0 Bad option number
+ */
+static unsigned coap_client_check_options(coap_msg_t *msg)
+{
+#ifdef COAP_PROXY
+    return coap_msg_check_unsafe_ops(msg);
+#else  /* !COAP_PROXY */
+    return coap_msg_check_critical_ops(msg);
+#endif  /* COAP_PROXY */
+}
+
+/**
+ *  @brief Handle a received piggy-backed response message
+ *
+ *  An acknowledgement has been received that contains
+ *  the same token as the request. Check the response
+ *  contained within it.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] resp Pointer to the response message
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_handle_piggybacked_response(coap_client_t *client, coap_msg_t *resp)
+{
+    unsigned op_num = 0;
+
+    op_num = coap_client_check_options(resp);
+    if (op_num != 0)
+    {
+        printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port);
+        coap_client_reject(client, resp);
+        return -EBADMSG;
+    }
+    printf("Received acknowledgement and response from Server\n");
+    return 0;
+}
+
+/**
+ *  @brief Handle a received separate response message
+ *
+ *  A separate response has been received that contains
+ *  the same token as the request. Check the response
+ *  and send an acknowledgement if necessary.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] resp Pointer to the response message
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_handle_sep_response(coap_client_t *client, coap_msg_t *resp)
+{
+    unsigned op_num = 0;
+
+    if (coap_msg_get_type(resp) == COAP_MSG_CON)
+    {
+        printf("Received confirmable response from host %s and port %s\n", client->server_host, client->server_port);
+        op_num = coap_client_check_options(resp);
+        if (op_num != 0)
+        {
+            printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port);
+            coap_client_reject(client, resp);
+            return -EBADMSG;
+        }
+        return coap_client_send_ack(client, resp);
+    }
+    else if (coap_msg_get_type(resp) == COAP_MSG_NON)
+    {
+        printf("Received non-confirmable response from host %s and port %s\n", client->server_host, client->server_port);
+        op_num = coap_client_check_options(resp);
+        if (op_num != 0)
+        {
+            printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port);
+            coap_client_reject(client, resp);
+            return -EBADMSG;
+        }
+        return 0;
+    }
+    coap_client_reject(client, resp);
+    return -EBADMSG;
+}
+
+/**
+ *  @brief Handle a separate response to a confirmable request
+ *
+ *  An acknowledgement has been received. Receive the
+ *  response and send an acknowledgement back to the server.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] req Pointer to the request message
+ *  @param[out] resp Pointer to the response message
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_exchange_sep(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
+{
+    int num = 0;
+    int ret = 0;
+    int starttimeout,endtimeout;
+
+    /* wait for a separate response to a confirmable request */
+    printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port);
+    while (1)
+    {
+        starttimeout = readseconds();
+        while(1)
+        {
+            num = coap_client_recv(client, resp);
+            if (num < 0)
+            {
+                return num;
+            }
+            else if(num > 0)
+            {
+                break;    
+            }
+            endtimeout = readseconds();
+            if((endtimeout - starttimeout) > COAP_CLIENT_RESP_TIMEOUT_SEC)
+            {
+                printf("Timeout no data received\n");  
+                return -1;  
+            }
+        }
+        
+        if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req))
+        {
+            if (coap_msg_get_type(resp) == COAP_MSG_ACK)
+            {
+                /* message deduplication */
+                printf("Received duplicate acknowledgement from host %s and port %s\n", client->server_host, client->server_port);
+                continue;
+            }
+            else if (coap_msg_get_type(resp) == COAP_MSG_RST)
+            {
+                return -ECONNRESET;
+            }
+            coap_client_reject(client, resp);
+            return -EBADMSG;
+        }
+        if (coap_client_match_token(req, resp))
+        {
+             return coap_client_handle_sep_response(client, resp);
+        }
+        /* message deduplication */
+        /* we might have received a duplicate message that was already received from the same server */
+        /* reject the message and continue listening */
+        ret = coap_client_reject(client, resp);
+        if (ret < 0 )
+        {
+            return ret;
+        }
+    }
+    return 0;
+}
+
+/**
+ *  @brief Handle the response to a confirmable request
+ *
+ *  A confirmable request has been sent to the server.
+ *  Receive the acknowledgement and response. Send an
+ *  acknowledgement if necessary.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] req Pointer to the request message
+ *  @param[out] resp Pointer to the response message
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_client_exchange_con(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
+{
+    int num = 0;
+    int ret = 0;
+    int starttimeout,endtimeout;
+    /*  wait for piggy-backed response in ack message
+     *  or ack message and separate response message
+     */
+    //printf("Expecting acknowledgement from server\r\n");
+    client->num_retrans = 0;
+    while (1)
+    {
+        int doubletimeout = COAP_CLIENT_ACK_TIMEOUT_SEC;
+        starttimeout = readseconds();
+        while(1)
+        {
+            num = coap_client_recv(client, resp);
+            if (num < 0)
+            {
+                //return num;
+            }
+            else if(num > 0)
+            {
+                break;    
+            }
+            endtimeout = readseconds();
+            if((endtimeout - starttimeout) > doubletimeout)
+            {
+                printf("Timeout no data received after %d seconds\n",endtimeout - starttimeout);
+
+                if (client->num_retrans >= COAP_CLIENT_MAX_RETRANSMIT)
+                {
+                    printf("Maximum retries reached no ack from server!\r\n");
+                    return -ETIMEDOUT;
+                }
+                
+                doubletimeout = 2 * doubletimeout;
+                starttimeout = readseconds();
+                client->num_retrans++;
+
+                printf("Retransmitting to server...\r\n");
+                num = coap_client_send(client, req);
+                if (num < 0)
+                {
+                    printf("Resending Failed to server...\r\n");
+                    return num;
+                } 
+            }
+        }
+         
+        if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req))
+        {
+            if (coap_msg_get_type(resp) == COAP_MSG_ACK)
+            {
+                if (coap_msg_is_empty(resp))
+                {
+                    /* received ack message, wait for separate response message */
+                    printf("Received acknowledgement from host %s and port %s\n", client->server_host, client->server_port);
+                    return coap_client_exchange_sep(client, req, resp);
+                }
+                else if (coap_client_match_token(req, resp))
+                {
+                    return coap_client_handle_piggybacked_response(client, resp);
+                }
+            }
+            else if (coap_msg_get_type(resp) == COAP_MSG_RST)
+            {
+                return -ECONNRESET;
+            }
+            coap_client_reject(client, resp);
+            return -EBADMSG;
+        }
+        else if (coap_client_match_token(req, resp))
+        {
+            /* RFC7252
+             * as the underlying datagram transport may not be sequence-preserving,
+             * the Confirmable message carrying the response may actually arrive
+             * before or after the Acknowledgement message for the request; for
+             * the purposes of terminating the retransmission sequence, this also
+             * serves as an acknowledgement.
+             */
+             return coap_client_handle_sep_response(client, resp);
+        }
+        /* message deduplication */
+        /* we might have received a duplicate message that was already received from the same server */
+        /* reject the message and continue listening */
+        ret = coap_client_reject(client, resp);
+        if (ret < 0 )
+        {
+            return ret;
+        }
+    }
+    return 0;
+}
+
+/**
+ *  @brief Handle the response to a non-confirmable request
+ *
+ *  A non-confirmable request has been sent to the server.
+ *  Receive the response.
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] req Pointer to the request message
+ *  @param[out] resp Pointer to the response message
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ **/
+static int coap_client_exchange_non(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
+{
+    int num = 0;
+    int ret = 0;
+    int starttimeout,endtimeout;
+
+    printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port);
+    while (1)
+    {
+        starttimeout = readseconds();
+        while(1)
+        {
+            num = coap_client_recv(client, resp);
+            if (num < 0)
+            {
+                return num;
+            }
+            else if(num > 0)
+            {
+                break;    
+            }
+            endtimeout = readseconds();
+            if((endtimeout - starttimeout) > COAP_CLIENT_RESP_TIMEOUT_SEC)
+            {
+                printf("Timeout no data received\n");    
+                return -1;
+            }
+        }
+ 
+        if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req))
+        {
+            if (coap_msg_get_type(resp) == COAP_MSG_RST)
+            {
+                return -ECONNRESET;
+            }
+            coap_client_reject(client, resp);
+            return -EBADMSG;
+        }
+        if (coap_client_match_token(req, resp))
+        {
+             return coap_client_handle_sep_response(client, resp);
+        }
+        /* message deduplication */
+        /* we might have received a duplicate message that was already received from the same server */
+        /* reject the message and continue listening */
+        ret = coap_client_reject(client, resp);
+        if (ret < 0 )
+        {
+            return ret;
+        }
+    }
+    return 0;
+}
+
+int coap_client_exchange(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp)
+{
+    unsigned char msg_id_buf[2] = {0};
+    unsigned msg_id = 0;
+    int num = 0;
+    char token[4] = {0};
+    int ret = 0;
+
+    /* check for a valid request */
+    if ((coap_msg_get_type(req) == COAP_MSG_ACK)
+     || (coap_msg_get_type(req) == COAP_MSG_RST)
+     || (coap_msg_get_code_class(req) != COAP_MSG_REQ))
+    {
+        return -EINVAL;
+    }
+
+    /* generate the message ID */
+    coap_msg_gen_rand_str((char *)msg_id_buf, sizeof(msg_id_buf));
+    msg_id = (((unsigned)msg_id_buf[1]) << 8) | (unsigned)msg_id_buf[0];
+    ret = coap_msg_set_msg_id(req, msg_id);
+    if (ret < 0)
+    {
+        return ret;
+    }
+
+    /* generate the token */
+    coap_msg_gen_rand_str(token, sizeof(token));
+    ret = coap_msg_set_token(req, token, sizeof(token));
+    if (ret < 0)
+    {
+        return ret;
+    }
+
+    num = coap_client_send(client, req);
+    if (num < 0)
+    {
+        return num;
+    }
+
+    if (coap_msg_get_type(req) == COAP_MSG_CON)
+    {
+        return coap_client_exchange_con(client, req, resp);
+    }
+    else if (coap_msg_get_type(req) == COAP_MSG_NON)
+    {
+        return coap_client_exchange_non(client, req, resp);
+    }
+    return -EINVAL;
+}
+//----------------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------------
+/**
+ *  @brief Test an exchange with the server
+ *
+ *  @param[in] data Pointer to a client test data structure
+ *
+ *  @returns Test result
+ */
+test_result_t test_exchange_func(char* buf,int buf_len,char* returncode)
+{
+    printf("----------------------------------------\n");
+    test_result_t result = PASS;
+    coap_client_t client = {0};
+    coap_msg_t resp = {0};
+    coap_msg_t req = {0};
+    int ret = 0;
+
+    test_coap_client_msg_op_t req_ops;
+        req_ops.num = COAP_MSG_URI_PATH;
+        req_ops.len = 8;
+        req_ops.val = (char*)"resource";
+        
+    test_coap_client_msg_op_t resp_ops;
+        resp_ops.num = 0;
+        resp_ops.len = 0;
+        resp_ops.val = 0;
+
+    test_coap_client_msg_t test1_req;
+        test1_req.type = COAP_MSG_CON;
+        test1_req.code_class = COAP_MSG_REQ;
+        test1_req.code_detail = COAP_MSG_GET;
+        test1_req.ops = req_ops;
+        test1_req.num_ops = 1;
+        test1_req.payload = buf;
+        test1_req.payload_len = buf_len;
+
+    test_coap_client_msg_t test1_resp;
+        test1_resp.type = COAP_MSG_ACK;
+        test1_resp.code_class = COAP_MSG_SUCCESS;
+        test1_resp.code_detail = COAP_MSG_CONTENT;
+        test1_resp.ops = resp_ops;
+        test1_resp.num_ops = 0;
+        test1_resp.payload = (char*)"Hello Client!";
+        test1_resp.payload_len = 13;
+
+    test_coap_client_data_t test1_data; 
+        test1_data.desc = "Send a confirmable request to server and expect a piggy-backed response";
+        test1_data.host = HOST;
+        test1_data.port = PORT;
+        test1_data.common_name = (char*)"dummy/server";
+        test1_data.test_req = test1_req;
+        test1_data.test_resp = test1_resp;
+        test1_data.num_msg = 1;
+
+    //printf("%s\n", test1_data.desc);
+
+    if (ret < 0)
+    {
+        printf("Error  : %s\n",strerror(-ret));
+        return FAIL;
+    }
+
+        coap_msg_create(&req);
+        coap_msg_create(&resp);
+        
+        ret = exchange(&client, &test1_data.test_req, &req, &resp,returncode);
+        //printf("exchange function\n");
+        if (ret != PASS)
+        {
+            printf("exchange function fail\n");
+            coap_msg_destroy(&resp);
+            coap_msg_destroy(&req);
+            coap_client_destroy(&client);
+            return FAIL;
+        }
+
+        ret = compare_ver_token(&req, &resp);
+        if (ret != PASS)
+        {
+            coap_msg_destroy(&resp);
+            coap_msg_destroy(&req);
+            coap_client_destroy(&client);
+            return FAIL;
+        }
+
+        ret = check_resp(&test1_data.test_resp, &resp);
+        if (ret != PASS)
+        {
+            coap_msg_destroy(&resp);
+            coap_msg_destroy(&req);
+            coap_client_destroy(&client);
+            return FAIL;
+        }
+
+    coap_msg_destroy(&resp);
+    coap_msg_destroy(&req);
+    coap_client_destroy(&client);
+
+    return result;
+}
+//----------------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------------
+/**
+ *  @brief Print a CoAP message
+ *
+ *  @param[in] str String to be printed before the message
+ *  @param[in] msg Pointer to a message structure
+ */
+void print_coap_msg(const char *str, coap_msg_t *msg,char* returncode)
+{
+    //coap_msg_op_t *op = NULL;
+    //unsigned num = 0;
+    //unsigned len = 0;
+    unsigned i = 0;
+    //unsigned j = 0;
+    char *payload = NULL;
+    char *token = NULL;
+    //char *val = NULL;
+
+    printf("%s\n", str);
+    printf("ver:         0x%02x\n", coap_msg_get_ver(msg));
+    printf("type:        0x%02x\n", coap_msg_get_type(msg));
+    printf("token_len:   %d\n", coap_msg_get_token_len(msg));
+    printf("code_class:  %d\n", coap_msg_get_code_class(msg));
+    printf("code_detail: %d\n", coap_msg_get_code_detail(msg));
+    printf("msg_id:      0x%04x\n", coap_msg_get_msg_id(msg));
+    printf("token:      ");
+    token = coap_msg_get_token(msg);
+    for (i = 0; i < coap_msg_get_token_len(msg); i++)
+    {
+        printf(" 0x%02x", (unsigned char)token[i]);
+    }
+    printf("\n");
+    /*op = coap_msg_get_first_op(msg);
+    while (op != NULL)
+    {
+        num = coap_msg_op_get_num(op);
+        len = coap_msg_op_get_len(op);
+        val = coap_msg_op_get_val(op);
+        printf("op[%u].num:   %u\n", j, num);
+        printf("op[%u].len:   %u\n", j, len);
+        printf("op[%u].val:  ", j);
+        for (i = 0; i < len; i++)
+        {
+            printf(" 0x%02x", (unsigned char)val[i]);
+        }
+        printf("\n");
+        op = coap_msg_op_get_next(op);
+        j++;
+    }*/
+    printf("payload:     ");
+    payload = coap_msg_get_payload(msg);
+    
+    if(strcmp(str,"Received:") == 0)
+    {
+        for (i = 0; i < coap_msg_get_payload_len(msg); i++)
+        {
+            printf("%c", payload[i]);
+            returncode[i] = payload[i];
+        }
+        returncode[i] = '\0';
+    }
+    printf("\n");
+    
+    printf("payload_len: %zu\n", coap_msg_get_payload_len(msg));
+}
+//----------------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------------
+/**
+ *  @brief Populate a request message with details from a test request message structure
+ *
+ *  @param[in] test_req Pointer to a test request message structure
+ *  @param[out] req Pointer to a request message structure
+ *
+ *  @returns Test result
+ */
+test_result_t populate_req(test_coap_client_msg_t *test_req, coap_msg_t *req)
+{
+    int ret = 0;
+
+    ret = coap_msg_set_type(req, test_req->type);
+    if (ret < 0)
+    {
+        printf("Error  : %s\n",strerror(-ret));
+        return FAIL;
+    }
+    ret = coap_msg_set_code(req, test_req->code_class, test_req->code_detail);
+    if (ret < 0)
+    {
+        printf("Error  : %s\n",strerror(-ret));
+        return FAIL;
+    }
+    ret = coap_msg_add_op(req, test_req->ops.num, test_req->ops.len, test_req->ops.val);
+    if (ret < 0)
+    {
+        printf("Error  : %s\n",strerror(-ret));
+        return FAIL;
+    }
+    if (test_req->payload)
+    {
+        ret = coap_msg_set_payload(req, test_req->payload, test_req->payload_len);
+        if (ret < 0)
+        {
+            printf("Error  : %s\n",strerror(-ret));
+            return FAIL;
+        }
+    }
+    return PASS;
+}
+//----------------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------------
+/**
+ *  @brief Send a request to the server and receive the response
+ *
+ *  @param[in,out] client Pointer to a client structure
+ *  @param[in] test_req Pointer to a test request message structure
+ *  @param[out] req Pointer to a request message structure
+ *  @param[out] resp Pointer to a response message structure
+ *
+ *  @returns Test result
+ */
+test_result_t exchange(coap_client_t *client, test_coap_client_msg_t *test_req, coap_msg_t *req, coap_msg_t *resp,char* returncode)
+{
+    test_result_t result = PASS;
+    int ret = 0;
+
+    result = populate_req(test_req, req);
+    if (result != PASS)
+    {
+        printf("populate_req FAIL\n");
+        return result;
+    }
+    ret = coap_client_exchange(client, req, resp);
+    if (ret < 0)
+    {
+        printf("coap_client_exchange FAIL\n");
+        printf("Error  : %s\n",strerror(-ret));
+        return FAIL;
+    }
+    //printf("coap_client_exchange PASS\n");
+    print_coap_msg("Sent:", req,returncode);
+    print_coap_msg("Received:", resp,returncode);
+
+    return PASS;
+}
+//----------------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------------
+/**
+ *  @brief Compare the version and token fields in a request message and a response message
+ *
+ *  @param[out] req Pointer to a request message structure
+ *  @param[out] resp Pointer to a response message structure
+ *
+ *  @returns Test result
+ */
+test_result_t compare_ver_token(coap_msg_t *req, coap_msg_t *resp)
+{
+    if (coap_msg_get_ver(req) != coap_msg_get_ver(resp))
+    {
+        return FAIL;
+    }
+    if (coap_msg_get_token_len(req) != coap_msg_get_token_len(resp))
+    {
+        return FAIL;
+    }
+    else if (memcmp(coap_msg_get_token(req), coap_msg_get_token(resp), coap_msg_get_token_len(req)) != 0)
+    {
+        return FAIL;
+    }
+    return PASS;
+}
+//----------------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------------
+/**
+ *  @brief Check the fields in a response message against the expected values
+ *
+ *  @param[out] test_resp Pointer to a test response message structure
+ *  @param[out] resp Pointer to a response message structure
+ *
+ *  @returns Test result
+ */
+test_result_t check_resp(test_coap_client_msg_t *test_resp, coap_msg_t *resp)
+{
+    if (test_resp->type != coap_msg_get_type(resp))
+    {
+        return FAIL;
+    }
+    if (test_resp->code_class != coap_msg_get_code_class(resp))
+    {
+        return FAIL;
+    }
+    if (test_resp->code_detail != coap_msg_get_code_detail(resp))
+    {
+        return FAIL;
+    }
+    return PASS;
+}
diff -r f1bc6e867fcf -r 4f3f7463e55f Coap/coap_client.h
--- a/Coap/coap_client.h	Wed May 24 07:51:33 2017 +0000
+++ b/Coap/coap_client.h	Thu May 25 11:53:45 2017 +0000
@@ -45,8 +45,6 @@
 #define COAP_CLIENT_HOST_BUF_LEN    128             /* Buffer length for host addresses */
 #define COAP_CLIENT_PORT_BUF_LEN    8               /* Buffer length for port numbers */
 
-//unsigned char ucReturnCode[10];     //Return code array
-
 /**
  *  @brief Test result enumeration
  */
@@ -158,12 +156,12 @@
  **/
 int coap_client_exchange(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp);
 
-test_result_t test_exchange_func(char* buf,int buf_len);
+test_result_t test_exchange_func(char* buf,int buf_len,char* returncode);
 test_result_t check_resp(test_coap_client_msg_t *test_resp, coap_msg_t *resp);
 test_result_t compare_ver_token(coap_msg_t *req, coap_msg_t *resp);
-test_result_t exchange(coap_client_t *client, test_coap_client_msg_t *test_req, coap_msg_t *req, coap_msg_t *resp);
+test_result_t exchange(coap_client_t *client, test_coap_client_msg_t *test_req, coap_msg_t *req, coap_msg_t *resp,char* returncode);
 test_result_t populate_req(test_coap_client_msg_t *test_req, coap_msg_t *req);
-void print_coap_msg(const char *str, coap_msg_t *msg);
+void print_coap_msg(const char *str, coap_msg_t *msg,char* returncode);
 
 
 
diff -r f1bc6e867fcf -r 4f3f7463e55f Coap/coap_msg.c
--- a/Coap/coap_msg.c	Wed May 24 07:51:33 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1024 +0,0 @@
-/*
- * Copyright (c) 2015 Keith Cullen.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- *  @file coap_msg.c
- *
- *  @brief Source file for the FreeCoAP message parser/formatter library
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <time.h>
-#include <errno.h>
-#include "coap_msg.h"
-#include "coap_client.h"
-
-#define coap_msg_op_list_get_first(list)       ((list)->first)                  /**< Get the first option from an option linked-list */
-#define coap_msg_op_list_get_last(list)        ((list)->last)                   /**< Get the last option in an option linked-list */
-#define coap_msg_op_list_is_empty(list)        ((list)->first == NULL)          /**< Indicate whether or not an option linked-list is empty */
-
-static int coap_msg_rand_init = 0;                                              /**< Indicates whether or not the random number generator has been initialised */
-
-void coap_msg_gen_rand_str(char *buf, size_t len)
-{
-    size_t i = 0;
-
-    if (!coap_msg_rand_init)
-    {
-        srand(time(NULL));
-        coap_msg_rand_init = 1;
-    }
-    for (i = 0; i < len; i++)
-    {
-        buf[i] = rand() & 0x000000ff;
-    }
-}
-
-int coap_msg_op_num_is_recognized(unsigned num)
-{
-    switch (num)
-    {
-    case COAP_MSG_IF_MATCH:
-    case COAP_MSG_URI_HOST:
-    case COAP_MSG_ETAG:
-    case COAP_MSG_IF_NONE_MATCH:
-    case COAP_MSG_URI_PORT:
-    case COAP_MSG_LOCATION_PATH:
-    case COAP_MSG_URI_PATH:
-    case COAP_MSG_CONTENT_FORMAT:
-    case COAP_MSG_MAX_AGE:
-    case COAP_MSG_URI_QUERY:
-    case COAP_MSG_ACCEPT:
-    case COAP_MSG_LOCATION_QUERY:
-    case COAP_MSG_PROXY_URI:
-    case COAP_MSG_PROXY_SCHEME:
-    case COAP_MSG_SIZE1:
-        return 1;
-    }
-    return 0;
-}
-
-/**
- *  @brief Allocate an option structure
- *
- *  @param[in] num Option number
- *  @param[in] len Option length
- *  @param[in] val Pointer to the option value
- *
- *  @returns Pointer to the option structure
- *  @retval NULL Out-of-memory
- */
-static coap_msg_op_t *coap_msg_op_new(unsigned num, unsigned len, const char *val)
-{
-    coap_msg_op_t *op = NULL;
-
-    op = (coap_msg_op_t *)malloc(sizeof(coap_msg_op_t));
-    if (op == NULL)
-    {
-        return NULL;
-    }
-    op->num = num;
-    op->len = len;
-    op->val = (char *)malloc(len);
-    if (op->val == NULL)
-    {
-        free(op);
-        return NULL;
-    }
-    memcpy(op->val, val, len);
-    op->next = NULL;
-    return op;
-}
-
-/**
- *  @brief Free an option structure that was allocated by coap_msg_op_new
- *
- *  @param[in,out] op Pointer to the option structure
- */
-static void coap_msg_op_delete(coap_msg_op_t *op)
-{
-    free(op->val);
-    free(op);
-}
-
-/**
- *  @brief Initialise an option linked-list structure
- *
- *  @param[out] list Pointer to an option linked-list structure
- */
-static void coap_msg_op_list_create(coap_msg_op_list_t *list)
-{
-    memset(list, 0, sizeof(coap_msg_op_list_t));
-}
-
-/**
- *  @brief Deinitialise an option linked-list structure
- *
- *  @param[in,out] list Pointer to an option linked-list structure
- */
-static void coap_msg_op_list_destroy(coap_msg_op_list_t *list)
-{
-    coap_msg_op_t *prev = NULL;
-    coap_msg_op_t *op = NULL;
-
-    op = list->first;
-    while (op != NULL)
-    {
-        prev = op;
-        op = op->next;
-        coap_msg_op_delete(prev);
-    }
-    memset(list, 0, sizeof(coap_msg_op_list_t));
-}
-
-/**
- *  @brief Allocate an option structure and add it to the end of an option linked-list structure
- *
- *  @param[in,out] list Pointer to an option linked-list structure
- *  @param[in] num Option number
- *  @param[in] len Option length
- *  @param[in] val Pointer to a buffer containing the option value
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_msg_op_list_add_last(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val)
-{
-    coap_msg_op_t *op = NULL;
-
-    op = coap_msg_op_new(num, len, val);
-    if (op == NULL)
-    {
-        return -ENOMEM;
-    }
-    if (list->first == NULL)
-    {
-        list->first = op;
-        list->last = op;
-    }
-    else
-    {
-        list->last->next = op;
-        list->last = op;
-    }
-    return 0;
-}
-
-/**
- *  @brief Allocate an option structure and add it to an option linked-list structure
- *
- *  The option is added to the list at a position determined by the option number.
- *
- *  @param[in,out] list Pointer to an option linked-list structure
- *  @param[in] num Option number
- *  @param[in] len Option length
- *  @param[in] val Pointer to a buffer containing the option value
- *
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_msg_op_list_add(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val)
-{
-    coap_msg_op_t *prev = NULL;
-    coap_msg_op_t *op = NULL;
-
-    op = coap_msg_op_new(num, len, val);
-    if (op == NULL)
-    {
-        return -ENOMEM;
-    }
-    if (list->first == NULL)
-    {
-        /* empty list */
-        list->first = op;
-        list->last = op;
-        return 0;
-    }
-    if (op->num < list->first->num)
-    {
-        /* start of the list */
-        op->next = list->first;
-        list->first = op;
-        return 0;
-    }
-    prev = list->first;
-    while (prev != list->last)
-    {
-        /* middle of the list */
-        if ((prev->num <= op->num) && (op->num < prev->next->num))
-        {
-            op->next = prev->next;
-            prev->next = op;
-            return 0;
-        }
-        prev = prev->next;
-    }
-    /* end of the list */
-    list->last->next = op;
-    list->last = op;
-    return 0;
-}
-
-void coap_msg_create(coap_msg_t *msg)
-{
-    memset(msg, 0, sizeof(coap_msg_t));
-    msg->ver = COAP_MSG_VER;
-    coap_msg_op_list_create(&msg->op_list);
-}
-
-void coap_msg_destroy(coap_msg_t *msg)
-{
-    coap_msg_op_list_destroy(&msg->op_list);
-    if (msg->payload != NULL)
-    {
-        free(msg->payload);
-    }
-    memset(msg, 0, sizeof(coap_msg_t));
-}
-
-void coap_msg_reset(coap_msg_t *msg)
-{
-    coap_msg_destroy(msg);
-    coap_msg_create(msg);
-}
-
-/**
- *  @brief Check a message for correctness
- *
- *  The following checks from RFC7252 are performed:
- *
- *  An Empty message has the Code field set to 0.00. The Token Length
- *  field MUST be set to 0 and bytes of data MUST NOT be present after
- *  the Message ID field.  If there are any bytes, they MUST be processed
- *  as a message format error.
- *
- *  The Reset message MUST echo the Message ID of the Confirmable message
- *  and MUST be Empty.
- *
- *  A Non-confirmable message always carries either a request or response
- *  and MUST NOT be Empty.
- *
- *  @param[in] msg Pointer to a message structure
- *  @returns Operation status
- *  @retval 0 Success
- *  @retval <0 Error
- */
-static int coap_msg_check(coap_msg_t *msg)
-{
-    if ((msg->code_class == 0) && (msg->code_detail == 0))
-    {
-        /* empty message */
-        if ((msg->type == COAP_MSG_NON)
-         || (msg->token_len != 0)
-         || (!coap_msg_op_list_is_empty(&msg->op_list))
-         || (msg->payload_len != 0))
-        {
-            return -EBADMSG;
-        }
-    }
-    else
-    {
-        /* non-empty message */
-        if (msg->type == COAP_MSG_RST)
-        {
-            return -EBADMSG;
-        }
-    }
-    return 0;
-}
-
-unsigned coap_msg_check_critical_ops(coap_msg_t *msg)
-{
-    coap_msg_op_t *op = NULL;
-    unsigned num = 0;
-
-    op = coap_msg_get_first_op(msg);
-    while (op != NULL)
-    {
-        num = coap_msg_op_get_num(op);
-        if ((coap_msg_op_num_is_critical(num))
-         && (!coap_msg_op_num_is_recognized(num)))
-        {
-            return num;  /* fail */
-        }
-        op = coap_msg_op_get_next(op);
-    }
-    return 0;  /* pass */
-}
-
-unsigned coap_msg_check_unsafe_ops(coap_msg_t *msg)
-{
-    coap_msg_op_t *op = NULL;
-    unsigned num = 0;
-
-    op = coap_msg_get_first_op(msg);
-    while (op != NULL)
-    {
-        num = coap_msg_op_get_num(op);
-        if ((coap_msg_op_num_is_unsafe(num))
-         && (!coap_msg_op_num_is_recognized(num)))
-        {
-            return num;  /* fail */
-        }
-        op = coap_msg_op_get_next(op);
-    }
-    return 0;  /* pass */
-}
-
-int coap_msg_parse_type_msg_id(char *buf, size_t len, unsigned *type, unsigned *msg_id)
-{
-    if (len < 4)
-    {
-        return -EBADMSG;
-    }
-    *type = (buf[0] >> 4) & 0x03;
-    *msg_id = ntohs(*((uint16_t *)(&buf[2])));
-    return 0;
-}
-
-/**
- *  @brief Parse the header in a message
- *
- *  @param[out] msg Pointer to a message structure
- *  @param[in] buf Pointer to a buffer containing the message
- *  @param[in] len Length of the buffer
- *
- *  @returns Number of bytes parsed or error code
- *  @retval >0 Number of bytes parsed
- *  @retval <0 Error
- */
-static int coap_msg_parse_hdr(coap_msg_t *msg, char *buf, size_t len)
-{
-    char *p = buf;
-
-    if (len < 4)
-    {
-        return -EBADMSG;
-    }
-    msg->ver = (p[0] >> 6) & 0x03;
-    if (msg->ver != COAP_MSG_VER)
-    {
-        return -EINVAL;
-    }
-    msg->type = (p[0] >> 4) & 0x03;
-    msg->token_len = p[0] & 0x0f;
-    if (msg->token_len > sizeof(msg->token))
-    {
-        return -EBADMSG;
-    }
-    msg->code_detail = p[1] & 0x1f;
-    msg->code_class = (p[1] >> 5) & 0x07;
-    if ((msg->code_class != COAP_MSG_REQ)
-     && (msg->code_class != COAP_MSG_SUCCESS)
-     && (msg->code_class != COAP_MSG_CLIENT_ERR)
-     && (msg->code_class != COAP_MSG_SERVER_ERR))
-    {
-        return -EBADMSG;
-    }
-    msg->msg_id = ntohs(*((uint16_t *)(&p[2])));
-    p += 4;
-    len -= 4;
-    return p - buf;
-}
-
-/**
- *  @brief Parse the token in a message
- *
- *  @param[out] msg Pointer to a message structure
- *  @param[in] buf Pointer to a buffer containing the message
- *  @param[in] len Length of the buffer
- *
- *  @returns Number of bytes parsed or error code
- *  @retval >0 Number of bytes parsed
- *  @retval <0 Error
- */
-static int coap_msg_parse_token(coap_msg_t *msg, char *buf, size_t len)
-{
-    if (len < msg->token_len)
-    {
-        return -EBADMSG;
-    }
-    memcpy(msg->token, buf, msg->token_len);
-    return msg->token_len;
-}
-
-/**
- *  @brief Parse an option in a message
- *
- *  @param[in,out] msg Pointer to a message structure
- *  @param[in] buf Pointer to a buffer containing the message
- *  @param[in] len Length of the buffer
- *
- *  @returns Number of bytes parsed or error code
- *  @retval >0 Number of bytes parsed
- *  @retval <0 Error
- */
-static int coap_msg_parse_op(coap_msg_t *msg, char *buf, size_t len)
-{
-    coap_msg_op_t *prev = NULL;
-    unsigned op_delta = 0;
-    unsigned op_len = 0;
-    unsigned op_num = 0;
-    char *p = buf;
-    int ret = 0;
-
-    if (len < 1)
-    {
-        return -EBADMSG;
-    }
-    op_delta = (p[0] >> 4) & 0x0f;
-    op_len = p[0] & 0x0f;
-    if ((op_delta == 15) || (op_len == 15))
-    {
-        return -EBADMSG;
-    }
-    p++;
-    len--;
-    if (op_delta == 13)
-    {
-        if (len < 1)
-        {
-            return -EBADMSG;
-        }
-        op_delta += p[0];
-        p++;
-        len--;
-    }
-    else if (op_delta == 14)
-    {
-        if (len < 2)
-        {
-            return -EBADMSG;
-        }
-        op_delta = 269 + ntohs(*((uint16_t *)(&p[0])));
-        p += 2;
-        len -= 2;
-    }
-    if (op_len == 13)
-    {
-        if (len < 1)
-        {
-            return -EBADMSG;
-        }
-        op_len += p[0];
-        p++;
-        len--;
-    }
-    else if (op_len == 14)
-    {
-        if (len < 2)
-        {
-            return -EBADMSG;
-        }
-        op_len = 269 + ntohs(*((uint16_t *)(&p[0])));
-        p += 2;
-        len -= 2;
-    }
-    if (len < op_len)
-    {
-        return -EBADMSG;
-    }
-    prev = coap_msg_op_list_get_last(&msg->op_list);
-    if (prev == NULL)
-    {
-        op_num = op_delta;
-    }
-    else
-    {
-        op_num = coap_msg_op_get_num(prev) + op_delta;
-    }
-    ret = coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p);
-    if (ret < 0)
-    {
-        return ret;
-    }
-    p += op_len;
-    return p - buf;
-}
-
-/**
- *  @brief Parse the options in a message
- *
- *  @param[in,out] msg Pointer to a message structure
- *  @param[in] buf Pointer to a buffer containing the message
- *  @param[in] len Length of the buffer
- *
- *  @returns Number of bytes parsed or error code
- *  @retval >0 Number of bytes parsed
- *  @retval <0 Error
- */
-static int coap_msg_parse_ops(coap_msg_t *msg, char *buf, size_t len)
-{
-    int num = 0;
-    char *p = buf;
-
-    while (1)
-    {
-        if (((p[0] & 0xff) == 0xff) || (len == 0))
-        {
-            break;
-        }
-        num = coap_msg_parse_op(msg, p, len);
-        if (num < 0)
-        {
-            return num;
-        }
-        p += num;
-        len -= num;
-    }
-    return p - buf;
-}
-
-/**
- *  @brief Parse the payload in a message
- *
- *  @param[out] msg Pointer to a message structure
- *  @param[in] buf Pointer to a buffer containing the message
- *  @param[in] len Length of the buffer
- *
- *  @returns Number of bytes parsed or error code
- *  @retval >0 Number of bytes parsed
- *  @retval <0 Error
- */
-static int coap_msg_parse_payload(coap_msg_t *msg, char *buf, size_t len)
-{
-    char *p = buf;
-
-    if (len == 0)
-    {
-        return 0;
-    }
-    if ((p[0] & 0xff) != 0xff)
-    {
-        return -EBADMSG;
-    }
-    p++;
-    len--;
-    if (len == 0)
-    {
-        return -EBADMSG;
-    }
-    msg->payload = (char *)malloc(len);
-    if (msg->payload == NULL)
-    {
-        return -ENOMEM;
-    }
-    memcpy(msg->payload, p, len);
-    msg->payload_len = len;
-    p += len;
-    return p - buf;
-}
-
-int coap_msg_parse(coap_msg_t *msg, char *buf, size_t len)
-{
-    int num = 0;
-    char *p = buf;
-
-    coap_msg_reset(msg);
-    num = coap_msg_parse_hdr(msg, p, len);
-    if (num < 0)
-    {
-        coap_msg_destroy(msg);
-        return num;
-    }
-    p += num;
-    len -= num;
-    num = coap_msg_parse_token(msg, p, len);
-    if (num < 0)
-    {
-        coap_msg_destroy(msg);
-        return num;
-    }
-    p += num;
-    len -= num;
-    num = coap_msg_parse_ops(msg, p, len);
-    if (num < 0)
-    {
-        coap_msg_destroy(msg);
-        return num;
-    }
-    p += num;
-    len -= num;
-    num = coap_msg_parse_payload(msg, p, len);
-    if (num < 0)
-    {
-        coap_msg_destroy(msg);
-        return num;
-    }
-    return coap_msg_check(msg);
-}
-
-int coap_msg_set_type(coap_msg_t *msg, unsigned type)
-{
-    if ((type != COAP_MSG_CON)
-     && (type != COAP_MSG_NON)
-     && (type != COAP_MSG_ACK)
-     && (type != COAP_MSG_RST))
-    {
-        return -EINVAL;
-    }
-    msg->type = type;
-    return 0;
-}
-
-int coap_msg_set_code(coap_msg_t *msg, unsigned code_class, unsigned code_detail)
-{
-    if (code_class > COAP_MSG_MAX_CODE_CLASS)
-    {
-        return -EINVAL;
-    }
-    if (code_detail > COAP_MSG_MAX_CODE_DETAIL)
-    {
-        return -EINVAL;
-    }
-    msg->code_class = code_class;
-    msg->code_detail = code_detail;
-    return 0;
-}
-
-int coap_msg_set_msg_id(coap_msg_t *msg, unsigned msg_id)
-{
-    if (msg_id > COAP_MSG_MAX_MSG_ID)
-    {
-        return -EINVAL;
-    }
-    msg->msg_id = msg_id;
-    return 0;
-}
-
-int coap_msg_set_token(coap_msg_t *msg, char *buf, size_t len)
-{
-    if (len > COAP_MSG_MAX_TOKEN_LEN)
-    {
-        return -EINVAL;
-    }
-    memcpy(msg->token, buf, len);
-    msg->token_len = len;
-    return 0;
-}
-
-int coap_msg_add_op(coap_msg_t *msg, unsigned num, unsigned len, const char *val)
-{
-    return coap_msg_op_list_add(&msg->op_list, num, len, val);
-}
-
-int coap_msg_set_payload(coap_msg_t *msg, char *buf, size_t len)
-{
-    msg->payload_len = 0;
-    if (msg->payload != NULL)
-    {
-        free(msg->payload);
-        msg->payload = NULL;
-    }
-    if (len > 0)
-    {
-        msg->payload = (char *)malloc(len);
-        if (msg->payload == NULL)
-        {
-            return -ENOMEM;
-        }
-        memcpy(msg->payload, buf, len);
-        msg->payload_len = len;
-    }
-    return 0;
-}
-
-/**
- *  @brief Format the header in a message
- *
- *  @param[in] msg Pointer to a message structure
- *  @param[out] buf Pointer to a buffer to contain the formatted message
- *  @param[in] len Length of the buffer
- *
- *  @returns Length of the formatted message or error code
- *  @retval >0 Length of the formatted message
- *  @retval <0 Error
- */
-static int coap_msg_format_hdr(coap_msg_t *msg, char *buf, size_t len)
-{
-    uint16_t msg_id = 0;
-
-    if (len < 4)
-    {
-        return -ENOSPC;
-    }
-    buf[0] = (char)((COAP_MSG_VER << 6)
-                  | ((msg->type & 0x03) << 4)
-                  | (msg->token_len & 0x0f));
-    buf[1] = (char)(((msg->code_class & 0x07) << 5)
-                  | (msg->code_detail & 0x1f));
-    msg_id = htons(msg->msg_id);
-    memcpy(&buf[2], &msg_id, 2);
-    return 4;
-}
-
-/**
- *  @brief Format the token in a message
- *
- *  @param[in] msg Pointer to a message structure
- *  @param[out] buf Pointer to a buffer to contain the formatted message
- *  @param[in] len Length of the buffer
- *
- *  @returns Length of the formatted message or error code
- *  @retval >0 Length of the formatted message
- *  @retval <0 Error
- */
-static int coap_msg_format_token(coap_msg_t *msg, char *buf, size_t len)
-{
-    if (len < msg->token_len)
-    {
-        return -ENOSPC;
-    }
-    memcpy(buf, msg->token, msg->token_len);
-    return msg->token_len;
-}
-
-/**
- *  @brief Format an option in a message
- *
- *  @param[in] op Pointer to an option structure
- *  @param[in] prev_num option number of the previous option
- *  @param[out] buf Pointer to a buffer to contain the formatted message
- *  @param[in] len Length of the buffer
- *
- *  @returns Length of the formatted message or error code
- *  @retval >0 Length of the formatted message
- *  @retval <0 Error
- */
-static int coap_msg_format_op(coap_msg_op_t *op, unsigned prev_num, char *buf, size_t len)
-{
-    unsigned op_delta = 0;
-    unsigned num = 0;
-    uint16_t val = 0;
-    char *p = buf;
-
-    op_delta = op->num - prev_num;
-    num++;
-
-    /* option delta */
-    if (op_delta >= 269)
-    {
-        num += 2;
-    }
-    else if (op_delta >= 13)
-    {
-        num += 1;
-    }
-
-    /* option length */
-    if (op->len >= 269)
-    {
-        num += 2;
-    }
-    else if (op->num >= 13)
-    {
-        num += 1;
-    }
-
-    /* option value */
-    num += op->len;
-    if (num > len)
-    {
-        return -ENOSPC;
-    }
-
-    /* option delta */
-    if (op_delta >= 269)
-    {
-        p[0] = 14 << 4;
-    }
-    else if (op_delta >= 13)
-    {
-        p[0] = 13 << 4;
-    }
-    else
-    {
-        p[0] = op_delta << 4;
-    }
-
-    /* option length */
-    if (op->len >= 269)
-    {
-        p[0] |= 14;
-    }
-    else if (op->len >= 13)
-    {
-        p[0] |= 13;
-    }
-    else
-    {
-        p[0] |= op->len;
-    }
-    p++;
-    len--;
-
-    /* option delta extended */
-    if (op_delta >= 269)
-    {
-        val = htons(op_delta - 269);
-        memcpy(p, &val, 2);
-        p += 2;
-        len -= 2;
-    }
-    else if (op_delta >= 13)
-    {
-        p[0] = op_delta - 13;
-        p++;
-        len--;
-    }
-
-    /* option length extended */
-    if (op->len >= 269)
-    {
-        val = htons(op->len - 269);
-        memcpy(p, &val, 2);
-        p += 2;
-        len -= 2;
-    }
-    else if (op->len >= 13)
-    {
-        p[0] = op->len - 13;
-        p++;
-        len--;
-    }
-
-    /* option value */
-    memcpy(p, op->val, op->len);
-    p += op->len;
-
-    return p - buf;
-}
-
-/**
- *  @brief Format the options in a message
- *
- *  @param[in] msg Pointer to a message structure
- *  @param[out] buf Pointer to a buffer to contain the formatted message
- *  @param[in] len Length of the buffer
- *
- *  @returns Length of the formatted message or error code
- *  @retval >0 Length of the formatted message
- *  @retval <0 Error
- */
-static int coap_msg_format_ops(coap_msg_t *msg, char *buf, size_t len)
-{
-    coap_msg_op_t *op = NULL;
-    unsigned prev_num = 0;
-    int num = 0;
-    char *p = buf;
-
-    op = coap_msg_op_list_get_first(&msg->op_list);
-    while (op != NULL)
-    {
-        num = coap_msg_format_op(op, prev_num, p, len);
-        if (num < 0)
-        {
-            return num;
-        }
-        p += num;
-        len -= num;
-        prev_num = coap_msg_op_get_num(op);
-        op = coap_msg_op_get_next(op);
-    }
-    return p - buf;
-}
-
-/**
- *  @brief Format the payload in a message
- *
- *  @param[in] msg Pointer to a message structure
- *  @param[out] buf Pointer to a buffer to contain the formatted message
- *  @param[in] len Length of the buffer
- *
- *  @returns Length of the formatted message or error code
- *  @retval >0 Length of the formatted message
- *  @retval <0 Error
- */
-static int coap_msg_format_payload(coap_msg_t *msg, char *buf, size_t len)
-{
-    if (msg->payload_len == 0)
-    {
-        return 0;
-    }
-    if (msg->payload_len + 1 > len)
-    {
-        return -ENOSPC;
-    }
-    buf[0] = 0xff;
-    memcpy(&buf[1], msg->payload, msg->payload_len);
-    return msg->payload_len + 1;
-}
-
-int coap_msg_format(coap_msg_t *msg, char *buf, size_t len)
-{
-    int num = 0;
-    char *p = buf;
-    int ret = 0;
-
-    ret = coap_msg_check(msg);
-    if (ret != 0)
-    {
-        return ret;
-    }
-    num = coap_msg_format_hdr(msg, p, len);
-    if (num < 0)
-    {
-        return num;
-    }
-    p += num;
-    len -= num;
-    num = coap_msg_format_token(msg, p, len);
-    if (num < 0)
-    {
-        return num;
-    }
-    p += num;
-    len -= num;
-    num = coap_msg_format_ops(msg, p, len);
-    if (num < 0)
-    {
-        return num;
-    }
-    p += num;
-    len -= num;
-    num = coap_msg_format_payload(msg, p, len);
-    if (num < 0)
-    {
-        return num;
-    }
-    p += num;
-    return p - buf;
-}
-
-int coap_msg_copy(coap_msg_t *dst, coap_msg_t *src)
-{
-    coap_msg_op_t *op = NULL;
-    int ret = 0;
-
-    dst->ver = src->ver;
-    ret = coap_msg_set_type(dst, coap_msg_get_type(src));
-    if (ret < 0)
-    {
-        return ret;
-    }
-    ret = coap_msg_set_code(dst, coap_msg_get_code_class(src), coap_msg_get_code_detail(src));
-    if (ret < 0)
-    {
-        return ret;
-    }
-    ret = coap_msg_set_msg_id(dst, coap_msg_get_msg_id(src));
-    if (ret < 0)
-    {
-        return ret;
-    }
-    ret = coap_msg_set_token(dst, coap_msg_get_token(src), coap_msg_get_token_len(src));
-    if (ret < 0)
-    {
-        return ret;
-    }
-    op = coap_msg_get_first_op(src);
-    while (op != NULL)
-    {
-        ret = coap_msg_add_op(dst, coap_msg_op_get_num(op), coap_msg_op_get_len(op), coap_msg_op_get_val(op));
-        if (ret < 0)
-        {
-            return ret;
-        }
-        op = coap_msg_op_get_next(op);
-    }
-    ret = coap_msg_set_payload(dst, coap_msg_get_payload(src), coap_msg_get_payload_len(src));
-    if (ret < 0)
-    {
-        return ret;
-    }
-    return 0;
-}
-
diff -r f1bc6e867fcf -r 4f3f7463e55f Coap/coap_msg.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Coap/coap_msg.cpp	Thu May 25 11:53:45 2017 +0000
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (c) 2015 Keith Cullen.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ *  @file coap_msg.c
+ *
+ *  @brief Source file for the FreeCoAP message parser/formatter library
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <errno.h>
+#include "coap_msg.h"
+#include "coap_client.h"
+
+#define coap_msg_op_list_get_first(list)       ((list)->first)                  /**< Get the first option from an option linked-list */
+#define coap_msg_op_list_get_last(list)        ((list)->last)                   /**< Get the last option in an option linked-list */
+#define coap_msg_op_list_is_empty(list)        ((list)->first == NULL)          /**< Indicate whether or not an option linked-list is empty */
+
+static int coap_msg_rand_init = 0;                                              /**< Indicates whether or not the random number generator has been initialised */
+
+void coap_msg_gen_rand_str(char *buf, size_t len)
+{
+    size_t i = 0;
+
+    if (!coap_msg_rand_init)
+    {
+        srand(time(NULL));
+        coap_msg_rand_init = 1;
+    }
+    for (i = 0; i < len; i++)
+    {
+        buf[i] = rand() & 0x000000ff;
+    }
+}
+
+int coap_msg_op_num_is_recognized(unsigned num)
+{
+    switch (num)
+    {
+    case COAP_MSG_IF_MATCH:
+    case COAP_MSG_URI_HOST:
+    case COAP_MSG_ETAG:
+    case COAP_MSG_IF_NONE_MATCH:
+    case COAP_MSG_URI_PORT:
+    case COAP_MSG_LOCATION_PATH:
+    case COAP_MSG_URI_PATH:
+    case COAP_MSG_CONTENT_FORMAT:
+    case COAP_MSG_MAX_AGE:
+    case COAP_MSG_URI_QUERY:
+    case COAP_MSG_ACCEPT:
+    case COAP_MSG_LOCATION_QUERY:
+    case COAP_MSG_PROXY_URI:
+    case COAP_MSG_PROXY_SCHEME:
+    case COAP_MSG_SIZE1:
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ *  @brief Allocate an option structure
+ *
+ *  @param[in] num Option number
+ *  @param[in] len Option length
+ *  @param[in] val Pointer to the option value
+ *
+ *  @returns Pointer to the option structure
+ *  @retval NULL Out-of-memory
+ */
+static coap_msg_op_t *coap_msg_op_new(unsigned num, unsigned len, const char *val)
+{
+    coap_msg_op_t *op = NULL;
+
+    op = (coap_msg_op_t *)malloc(sizeof(coap_msg_op_t));
+    if (op == NULL)
+    {
+        return NULL;
+    }
+    op->num = num;
+    op->len = len;
+    op->val = (char *)malloc(len);
+    if (op->val == NULL)
+    {
+        free(op);
+        return NULL;
+    }
+    memcpy(op->val, val, len);
+    op->next = NULL;
+    return op;
+}
+
+/**
+ *  @brief Free an option structure that was allocated by coap_msg_op_new
+ *
+ *  @param[in,out] op Pointer to the option structure
+ */
+static void coap_msg_op_delete(coap_msg_op_t *op)
+{
+    free(op->val);
+    free(op);
+}
+
+/**
+ *  @brief Initialise an option linked-list structure
+ *
+ *  @param[out] list Pointer to an option linked-list structure
+ */
+static void coap_msg_op_list_create(coap_msg_op_list_t *list)
+{
+    memset(list, 0, sizeof(coap_msg_op_list_t));
+}
+
+/**
+ *  @brief Deinitialise an option linked-list structure
+ *
+ *  @param[in,out] list Pointer to an option linked-list structure
+ */
+static void coap_msg_op_list_destroy(coap_msg_op_list_t *list)
+{
+    coap_msg_op_t *prev = NULL;
+    coap_msg_op_t *op = NULL;
+
+    op = list->first;
+    while (op != NULL)
+    {
+        prev = op;
+        op = op->next;
+        coap_msg_op_delete(prev);
+    }
+    memset(list, 0, sizeof(coap_msg_op_list_t));
+}
+
+/**
+ *  @brief Allocate an option structure and add it to the end of an option linked-list structure
+ *
+ *  @param[in,out] list Pointer to an option linked-list structure
+ *  @param[in] num Option number
+ *  @param[in] len Option length
+ *  @param[in] val Pointer to a buffer containing the option value
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_msg_op_list_add_last(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val)
+{
+    coap_msg_op_t *op = NULL;
+
+    op = coap_msg_op_new(num, len, val);
+    if (op == NULL)
+    {
+        return -ENOMEM;
+    }
+    if (list->first == NULL)
+    {
+        list->first = op;
+        list->last = op;
+    }
+    else
+    {
+        list->last->next = op;
+        list->last = op;
+    }
+    return 0;
+}
+
+/**
+ *  @brief Allocate an option structure and add it to an option linked-list structure
+ *
+ *  The option is added to the list at a position determined by the option number.
+ *
+ *  @param[in,out] list Pointer to an option linked-list structure
+ *  @param[in] num Option number
+ *  @param[in] len Option length
+ *  @param[in] val Pointer to a buffer containing the option value
+ *
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_msg_op_list_add(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val)
+{
+    coap_msg_op_t *prev = NULL;
+    coap_msg_op_t *op = NULL;
+
+    op = coap_msg_op_new(num, len, val);
+    if (op == NULL)
+    {
+        return -ENOMEM;
+    }
+    if (list->first == NULL)
+    {
+        /* empty list */
+        list->first = op;
+        list->last = op;
+        return 0;
+    }
+    if (op->num < list->first->num)
+    {
+        /* start of the list */
+        op->next = list->first;
+        list->first = op;
+        return 0;
+    }
+    prev = list->first;
+    while (prev != list->last)
+    {
+        /* middle of the list */
+        if ((prev->num <= op->num) && (op->num < prev->next->num))
+        {
+            op->next = prev->next;
+            prev->next = op;
+            return 0;
+        }
+        prev = prev->next;
+    }
+    /* end of the list */
+    list->last->next = op;
+    list->last = op;
+    return 0;
+}
+
+void coap_msg_create(coap_msg_t *msg)
+{
+    memset(msg, 0, sizeof(coap_msg_t));
+    msg->ver = COAP_MSG_VER;
+    coap_msg_op_list_create(&msg->op_list);
+}
+
+void coap_msg_destroy(coap_msg_t *msg)
+{
+    coap_msg_op_list_destroy(&msg->op_list);
+    if (msg->payload != NULL)
+    {
+        free(msg->payload);
+    }
+    memset(msg, 0, sizeof(coap_msg_t));
+}
+
+void coap_msg_reset(coap_msg_t *msg)
+{
+    coap_msg_destroy(msg);
+    coap_msg_create(msg);
+}
+
+/**
+ *  @brief Check a message for correctness
+ *
+ *  The following checks from RFC7252 are performed:
+ *
+ *  An Empty message has the Code field set to 0.00. The Token Length
+ *  field MUST be set to 0 and bytes of data MUST NOT be present after
+ *  the Message ID field.  If there are any bytes, they MUST be processed
+ *  as a message format error.
+ *
+ *  The Reset message MUST echo the Message ID of the Confirmable message
+ *  and MUST be Empty.
+ *
+ *  A Non-confirmable message always carries either a request or response
+ *  and MUST NOT be Empty.
+ *
+ *  @param[in] msg Pointer to a message structure
+ *  @returns Operation status
+ *  @retval 0 Success
+ *  @retval <0 Error
+ */
+static int coap_msg_check(coap_msg_t *msg)
+{
+    if ((msg->code_class == 0) && (msg->code_detail == 0))
+    {
+        /* empty message */
+        if ((msg->type == COAP_MSG_NON)
+         || (msg->token_len != 0)
+         || (!coap_msg_op_list_is_empty(&msg->op_list))
+         || (msg->payload_len != 0))
+        {
+            return -EBADMSG;
+        }
+    }
+    else
+    {
+        /* non-empty message */
+        if (msg->type == COAP_MSG_RST)
+        {
+            return -EBADMSG;
+        }
+    }
+    return 0;
+}
+
+unsigned coap_msg_check_critical_ops(coap_msg_t *msg)
+{
+    coap_msg_op_t *op = NULL;
+    unsigned num = 0;
+
+    op = coap_msg_get_first_op(msg);
+    while (op != NULL)
+    {
+        num = coap_msg_op_get_num(op);
+        if ((coap_msg_op_num_is_critical(num))
+         && (!coap_msg_op_num_is_recognized(num)))
+        {
+            return num;  /* fail */
+        }
+        op = coap_msg_op_get_next(op);
+    }
+    return 0;  /* pass */
+}
+
+unsigned coap_msg_check_unsafe_ops(coap_msg_t *msg)
+{
+    coap_msg_op_t *op = NULL;
+    unsigned num = 0;
+
+    op = coap_msg_get_first_op(msg);
+    while (op != NULL)
+    {
+        num = coap_msg_op_get_num(op);
+        if ((coap_msg_op_num_is_unsafe(num))
+         && (!coap_msg_op_num_is_recognized(num)))
+        {
+            return num;  /* fail */
+        }
+        op = coap_msg_op_get_next(op);
+    }
+    return 0;  /* pass */
+}
+
+int coap_msg_parse_type_msg_id(char *buf, size_t len, unsigned *type, unsigned *msg_id)
+{
+    if (len < 4)
+    {
+        return -EBADMSG;
+    }
+    *type = (buf[0] >> 4) & 0x03;
+    *msg_id = ntohs(*((uint16_t *)(&buf[2])));
+    return 0;
+}
+
+/**
+ *  @brief Parse the header in a message
+ *
+ *  @param[out] msg Pointer to a message structure
+ *  @param[in] buf Pointer to a buffer containing the message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Number of bytes parsed or error code
+ *  @retval >0 Number of bytes parsed
+ *  @retval <0 Error
+ */
+static int coap_msg_parse_hdr(coap_msg_t *msg, char *buf, size_t len)
+{
+    char *p = buf;
+
+    if (len < 4)
+    {
+        return -EBADMSG;
+    }
+    msg->ver = (p[0] >> 6) & 0x03;
+    if (msg->ver != COAP_MSG_VER)
+    {
+        return -EINVAL;
+    }
+    msg->type = (coap_msg_type_t)((p[0] >> 4) & 0x03);
+    msg->token_len = p[0] & 0x0f;
+    if (msg->token_len > sizeof(msg->token))
+    {
+        return -EBADMSG;
+    }
+    msg->code_detail = p[1] & 0x1f;
+    msg->code_class = (p[1] >> 5) & 0x07;
+    if ((msg->code_class != COAP_MSG_REQ)
+     && (msg->code_class != COAP_MSG_SUCCESS)
+     && (msg->code_class != COAP_MSG_CLIENT_ERR)
+     && (msg->code_class != COAP_MSG_SERVER_ERR))
+    {
+        return -EBADMSG;
+    }
+    msg->msg_id = ntohs(*((uint16_t *)(&p[2])));
+    p += 4;
+    len -= 4;
+    return p - buf;
+}
+
+/**
+ *  @brief Parse the token in a message
+ *
+ *  @param[out] msg Pointer to a message structure
+ *  @param[in] buf Pointer to a buffer containing the message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Number of bytes parsed or error code
+ *  @retval >0 Number of bytes parsed
+ *  @retval <0 Error
+ */
+static int coap_msg_parse_token(coap_msg_t *msg, char *buf, size_t len)
+{
+    if (len < msg->token_len)
+    {
+        return -EBADMSG;
+    }
+    memcpy(msg->token, buf, msg->token_len);
+    return msg->token_len;
+}
+
+/**
+ *  @brief Parse an option in a message
+ *
+ *  @param[in,out] msg Pointer to a message structure
+ *  @param[in] buf Pointer to a buffer containing the message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Number of bytes parsed or error code
+ *  @retval >0 Number of bytes parsed
+ *  @retval <0 Error
+ */
+static int coap_msg_parse_op(coap_msg_t *msg, char *buf, size_t len)
+{
+    coap_msg_op_t *prev = NULL;
+    unsigned op_delta = 0;
+    unsigned op_len = 0;
+    unsigned op_num = 0;
+    char *p = buf;
+    int ret = 0;
+
+    if (len < 1)
+    {
+        return -EBADMSG;
+    }
+    op_delta = (p[0] >> 4) & 0x0f;
+    op_len = p[0] & 0x0f;
+    if ((op_delta == 15) || (op_len == 15))
+    {
+        return -EBADMSG;
+    }
+    p++;
+    len--;
+    if (op_delta == 13)
+    {
+        if (len < 1)
+        {
+            return -EBADMSG;
+        }
+        op_delta += p[0];
+        p++;
+        len--;
+    }
+    else if (op_delta == 14)
+    {
+        if (len < 2)
+        {
+            return -EBADMSG;
+        }
+        op_delta = 269 + ntohs(*((uint16_t *)(&p[0])));
+        p += 2;
+        len -= 2;
+    }
+    if (op_len == 13)
+    {
+        if (len < 1)
+        {
+            return -EBADMSG;
+        }
+        op_len += p[0];
+        p++;
+        len--;
+    }
+    else if (op_len == 14)
+    {
+        if (len < 2)
+        {
+            return -EBADMSG;
+        }
+        op_len = 269 + ntohs(*((uint16_t *)(&p[0])));
+        p += 2;
+        len -= 2;
+    }
+    if (len < op_len)
+    {
+        return -EBADMSG;
+    }
+    prev = coap_msg_op_list_get_last(&msg->op_list);
+    if (prev == NULL)
+    {
+        op_num = op_delta;
+    }
+    else
+    {
+        op_num = coap_msg_op_get_num(prev) + op_delta;
+    }
+    ret = coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p);
+    if (ret < 0)
+    {
+        return ret;
+    }
+    p += op_len;
+    return p - buf;
+}
+
+/**
+ *  @brief Parse the options in a message
+ *
+ *  @param[in,out] msg Pointer to a message structure
+ *  @param[in] buf Pointer to a buffer containing the message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Number of bytes parsed or error code
+ *  @retval >0 Number of bytes parsed
+ *  @retval <0 Error
+ */
+static int coap_msg_parse_ops(coap_msg_t *msg, char *buf, size_t len)
+{
+    int num = 0;
+    char *p = buf;
+
+    while (1)
+    {
+        if (((p[0] & 0xff) == 0xff) || (len == 0))
+        {
+            break;
+        }
+        num = coap_msg_parse_op(msg, p, len);
+        if (num < 0)
+        {
+            return num;
+        }
+        p += num;
+        len -= num;
+    }
+    return p - buf;
+}
+
+/**
+ *  @brief Parse the payload in a message
+ *
+ *  @param[out] msg Pointer to a message structure
+ *  @param[in] buf Pointer to a buffer containing the message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Number of bytes parsed or error code
+ *  @retval >0 Number of bytes parsed
+ *  @retval <0 Error
+ */
+static int coap_msg_parse_payload(coap_msg_t *msg, char *buf, size_t len)
+{
+    char *p = buf;
+
+    if (len == 0)
+    {
+        return 0;
+    }
+    if ((p[0] & 0xff) != 0xff)
+    {
+        return -EBADMSG;
+    }
+    p++;
+    len--;
+    if (len == 0)
+    {
+        return -EBADMSG;
+    }
+    msg->payload = (char *)malloc(len);
+    if (msg->payload == NULL)
+    {
+        return -ENOMEM;
+    }
+    memcpy(msg->payload, p, len);
+    msg->payload_len = len;
+    p += len;
+    return p - buf;
+}
+
+int coap_msg_parse(coap_msg_t *msg, char *buf, size_t len)
+{
+    int num = 0;
+    char *p = buf;
+
+    coap_msg_reset(msg);
+    num = coap_msg_parse_hdr(msg, p, len);
+    if (num < 0)
+    {
+        coap_msg_destroy(msg);
+        return num;
+    }
+    p += num;
+    len -= num;
+    num = coap_msg_parse_token(msg, p, len);
+    if (num < 0)
+    {
+        coap_msg_destroy(msg);
+        return num;
+    }
+    p += num;
+    len -= num;
+    num = coap_msg_parse_ops(msg, p, len);
+    if (num < 0)
+    {
+        coap_msg_destroy(msg);
+        return num;
+    }
+    p += num;
+    len -= num;
+    num = coap_msg_parse_payload(msg, p, len);
+    if (num < 0)
+    {
+        coap_msg_destroy(msg);
+        return num;
+    }
+    return coap_msg_check(msg);
+}
+
+int coap_msg_set_type(coap_msg_t *msg, unsigned type)
+{
+    if ((type != COAP_MSG_CON)
+     && (type != COAP_MSG_NON)
+     && (type != COAP_MSG_ACK)
+     && (type != COAP_MSG_RST))
+    {
+        return -EINVAL;
+    }
+    msg->type = (coap_msg_type_t)type;
+    return 0;
+}
+
+int coap_msg_set_code(coap_msg_t *msg, unsigned code_class, unsigned code_detail)
+{
+    if (code_class > COAP_MSG_MAX_CODE_CLASS)
+    {
+        return -EINVAL;
+    }
+    if (code_detail > COAP_MSG_MAX_CODE_DETAIL)
+    {
+        return -EINVAL;
+    }
+    msg->code_class = code_class;
+    msg->code_detail = code_detail;
+    return 0;
+}
+
+int coap_msg_set_msg_id(coap_msg_t *msg, unsigned msg_id)
+{
+    if (msg_id > COAP_MSG_MAX_MSG_ID)
+    {
+        return -EINVAL;
+    }
+    msg->msg_id = msg_id;
+    return 0;
+}
+
+int coap_msg_set_token(coap_msg_t *msg, char *buf, size_t len)
+{
+    if (len > COAP_MSG_MAX_TOKEN_LEN)
+    {
+        return -EINVAL;
+    }
+    memcpy(msg->token, buf, len);
+    msg->token_len = len;
+    return 0;
+}
+
+int coap_msg_add_op(coap_msg_t *msg, unsigned num, unsigned len, const char *val)
+{
+    return coap_msg_op_list_add(&msg->op_list, num, len, val);
+}
+
+int coap_msg_set_payload(coap_msg_t *msg, char *buf, size_t len)
+{
+    msg->payload_len = 0;
+    if (msg->payload != NULL)
+    {
+        free(msg->payload);
+        msg->payload = NULL;
+    }
+    if (len > 0)
+    {
+        msg->payload = (char *)malloc(len);
+        if (msg->payload == NULL)
+        {
+            return -ENOMEM;
+        }
+        memcpy(msg->payload, buf, len);
+        msg->payload_len = len;
+    }
+    return 0;
+}
+
+/**
+ *  @brief Format the header in a message
+ *
+ *  @param[in] msg Pointer to a message structure
+ *  @param[out] buf Pointer to a buffer to contain the formatted message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Length of the formatted message or error code
+ *  @retval >0 Length of the formatted message
+ *  @retval <0 Error
+ */
+static int coap_msg_format_hdr(coap_msg_t *msg, char *buf, size_t len)
+{
+    uint16_t msg_id = 0;
+
+    if (len < 4)
+    {
+        return -ENOSPC;
+    }
+    buf[0] = (char)((COAP_MSG_VER << 6)
+                  | ((msg->type & 0x03) << 4)
+                  | (msg->token_len & 0x0f));
+    buf[1] = (char)(((msg->code_class & 0x07) << 5)
+                  | (msg->code_detail & 0x1f));
+    msg_id = htons(msg->msg_id);
+    memcpy(&buf[2], &msg_id, 2);
+    return 4;
+}
+
+/**
+ *  @brief Format the token in a message
+ *
+ *  @param[in] msg Pointer to a message structure
+ *  @param[out] buf Pointer to a buffer to contain the formatted message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Length of the formatted message or error code
+ *  @retval >0 Length of the formatted message
+ *  @retval <0 Error
+ */
+static int coap_msg_format_token(coap_msg_t *msg, char *buf, size_t len)
+{
+    if (len < msg->token_len)
+    {
+        return -ENOSPC;
+    }
+    memcpy(buf, msg->token, msg->token_len);
+    return msg->token_len;
+}
+
+/**
+ *  @brief Format an option in a message
+ *
+ *  @param[in] op Pointer to an option structure
+ *  @param[in] prev_num option number of the previous option
+ *  @param[out] buf Pointer to a buffer to contain the formatted message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Length of the formatted message or error code
+ *  @retval >0 Length of the formatted message
+ *  @retval <0 Error
+ */
+static int coap_msg_format_op(coap_msg_op_t *op, unsigned prev_num, char *buf, size_t len)
+{
+    unsigned op_delta = 0;
+    unsigned num = 0;
+    uint16_t val = 0;
+    char *p = buf;
+
+    op_delta = op->num - prev_num;
+    num++;
+
+    /* option delta */
+    if (op_delta >= 269)
+    {
+        num += 2;
+    }
+    else if (op_delta >= 13)
+    {
+        num += 1;
+    }
+
+    /* option length */
+    if (op->len >= 269)
+    {
+        num += 2;
+    }
+    else if (op->num >= 13)
+    {
+        num += 1;
+    }
+
+    /* option value */
+    num += op->len;
+    if (num > len)
+    {
+        return -ENOSPC;
+    }
+
+    /* option delta */
+    if (op_delta >= 269)
+    {
+        p[0] = 14 << 4;
+    }
+    else if (op_delta >= 13)
+    {
+        p[0] = 13 << 4;
+    }
+    else
+    {
+        p[0] = op_delta << 4;
+    }
+
+    /* option length */
+    if (op->len >= 269)
+    {
+        p[0] |= 14;
+    }
+    else if (op->len >= 13)
+    {
+        p[0] |= 13;
+    }
+    else
+    {
+        p[0] |= op->len;
+    }
+    p++;
+    len--;
+
+    /* option delta extended */
+    if (op_delta >= 269)
+    {
+        val = htons(op_delta - 269);
+        memcpy(p, &val, 2);
+        p += 2;
+        len -= 2;
+    }
+    else if (op_delta >= 13)
+    {
+        p[0] = op_delta - 13;
+        p++;
+        len--;
+    }
+
+    /* option length extended */
+    if (op->len >= 269)
+    {
+        val = htons(op->len - 269);
+        memcpy(p, &val, 2);
+        p += 2;
+        len -= 2;
+    }
+    else if (op->len >= 13)
+    {
+        p[0] = op->len - 13;
+        p++;
+        len--;
+    }
+
+    /* option value */
+    memcpy(p, op->val, op->len);
+    p += op->len;
+
+    return p - buf;
+}
+
+/**
+ *  @brief Format the options in a message
+ *
+ *  @param[in] msg Pointer to a message structure
+ *  @param[out] buf Pointer to a buffer to contain the formatted message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Length of the formatted message or error code
+ *  @retval >0 Length of the formatted message
+ *  @retval <0 Error
+ */
+static int coap_msg_format_ops(coap_msg_t *msg, char *buf, size_t len)
+{
+    coap_msg_op_t *op = NULL;
+    unsigned prev_num = 0;
+    int num = 0;
+    char *p = buf;
+
+    op = coap_msg_op_list_get_first(&msg->op_list);
+    while (op != NULL)
+    {
+        num = coap_msg_format_op(op, prev_num, p, len);
+        if (num < 0)
+        {
+            return num;
+        }
+        p += num;
+        len -= num;
+        prev_num = coap_msg_op_get_num(op);
+        op = coap_msg_op_get_next(op);
+    }
+    return p - buf;
+}
+
+/**
+ *  @brief Format the payload in a message
+ *
+ *  @param[in] msg Pointer to a message structure
+ *  @param[out] buf Pointer to a buffer to contain the formatted message
+ *  @param[in] len Length of the buffer
+ *
+ *  @returns Length of the formatted message or error code
+ *  @retval >0 Length of the formatted message
+ *  @retval <0 Error
+ */
+static int coap_msg_format_payload(coap_msg_t *msg, char *buf, size_t len)
+{
+    if (msg->payload_len == 0)
+    {
+        return 0;
+    }
+    if (msg->payload_len + 1 > len)
+    {
+        return -ENOSPC;
+    }
+    buf[0] = 0xff;
+    memcpy(&buf[1], msg->payload, msg->payload_len);
+    return msg->payload_len + 1;
+}
+
+int coap_msg_format(coap_msg_t *msg, char *buf, size_t len)
+{
+    int num = 0;
+    char *p = buf;
+    int ret = 0;
+
+    ret = coap_msg_check(msg);
+    if (ret != 0)
+    {
+        return ret;
+    }
+    num = coap_msg_format_hdr(msg, p, len);
+    if (num < 0)
+    {
+        return num;
+    }
+    p += num;
+    len -= num;
+    num = coap_msg_format_token(msg, p, len);
+    if (num < 0)
+    {
+        return num;
+    }
+    p += num;
+    len -= num;
+    num = coap_msg_format_ops(msg, p, len);
+    if (num < 0)
+    {
+        return num;
+    }
+    p += num;
+    len -= num;
+    num = coap_msg_format_payload(msg, p, len);
+    if (num < 0)
+    {
+        return num;
+    }
+    p += num;
+    return p - buf;
+}
+
+int coap_msg_copy(coap_msg_t *dst, coap_msg_t *src)
+{
+    coap_msg_op_t *op = NULL;
+    int ret = 0;
+
+    dst->ver = src->ver;
+    ret = coap_msg_set_type(dst, coap_msg_get_type(src));
+    if (ret < 0)
+    {
+        return ret;
+    }
+    ret = coap_msg_set_code(dst, coap_msg_get_code_class(src), coap_msg_get_code_detail(src));
+    if (ret < 0)
+    {
+        return ret;
+    }
+    ret = coap_msg_set_msg_id(dst, coap_msg_get_msg_id(src));
+    if (ret < 0)
+    {
+        return ret;
+    }
+    ret = coap_msg_set_token(dst, coap_msg_get_token(src), coap_msg_get_token_len(src));
+    if (ret < 0)
+    {
+        return ret;
+    }
+    op = coap_msg_get_first_op(src);
+    while (op != NULL)
+    {
+        ret = coap_msg_add_op(dst, coap_msg_op_get_num(op), coap_msg_op_get_len(op), coap_msg_op_get_val(op));
+        if (ret < 0)
+        {
+            return ret;
+        }
+        op = coap_msg_op_get_next(op);
+    }
+    ret = coap_msg_set_payload(dst, coap_msg_get_payload(src), coap_msg_get_payload_len(src));
+    if (ret < 0)
+    {
+        return ret;
+    }
+    return 0;
+}
+
diff -r f1bc6e867fcf -r 4f3f7463e55f main.cpp
--- a/main.cpp	Wed May 24 07:51:33 2017 +0000
+++ b/main.cpp	Thu May 25 11:53:45 2017 +0000
@@ -7,10 +7,11 @@
 #include "GPS.h"
 #include "MDM.h"
 #include "main.h"
-
+#include "coap_msg.h"
+#include "coap_client.h"
+    
 extern "C" {
-    #include "coap_msg.h"
-    #include "coap_client.h"
+    
     #include "rtc_api.h"
 }
 //
@@ -31,7 +32,7 @@
 unsigned long           ulGSMRxCntr=0, ulGSMTxCntr=0 ;      //-- Asset
 unsigned long           ulTotalRxCntr=0,ulTotalTxCntr=0;    //-- Asset
 char                    caLssFinalAssetMsg[150];
-double                  dLatitude=0,dLongitude=0;
+double                  dLatitude=31.47691,dLongitude=74.34259;
 static unsigned int     uiWakeupCounter=0,uiWatchdogCounter=0;
 unsigned char           ucBtteryLevel=0;
 MDMParser::DevStatus    devStatus={};
@@ -43,6 +44,9 @@
 
 //unsigned int          uiAlarmIntervalCounter = 0;
 //unsigned int          uiHeartBeatCounter = 0;
+
+char ucReturnCode[10];     //Return code array
+int alarmtime = 1495698480;//2017-3-29-11:56:7
 //----------------------------------------------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------------------------------------------
 /*
@@ -50,7 +54,7 @@
 {
     LPC_SC->PCONP |=1<1;            //timer0 power on
     LPC_TIM0->MR0 = sec * 23980000; //1sec * sec
-    LPC_TIM0->MCR = 3;              //interrupt and reset control
+    LPC_TIM0->MCR = 1;              //interrupt and reset control
                                     //3 = Interrupt & reset timer0 on match
                                     //1 = Interrupt only, no reset of timer0
     NVIC_EnableIRQ(TIMER0_IRQn);    //enable timer0 interrupt
@@ -63,33 +67,34 @@
     if((LPC_TIM0->IR & 0x01) == 0x01)   // if MR0 interrupt, proceed
     {
         LPC_TIM0->IR |= 1 << 0;         // Clear MR0 interrupt flag
-        
-        uiAlarmIntervalCounter++;
-        if(uiAlarmIntervalCounter >= 10)//20 sec
-        {
-            bAlarmIntervalFlag = true;
-            uiAlarmIntervalCounter = 0;
-            printf("Alarm Packet time...\r\n");
-        }
-        
-        uiHeartBeatCounter++;
-        if(uiHeartBeatCounter >= 60)//2 min
-        {
-            bHeartBeatFlag = true;
-            uiHeartBeatCounter = 0;
-            printf("Heartbeat Packet time...\r\n");
-        } 
+        printf("Timer 0 interrupt generated 10 sec\r\n");
+        LPC_TIM0->TCR = 0; 
     }
 }
 */
 //----------------------------------------------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------------------------------------------
 
-void rtc_setup(void)
+void rtc_setup(time_t t, unsigned int sec)
 {
+    struct tm *timeinfo = localtime(&t);
+    unsigned int min;
+    
     rtc_init();
 
-    rtc_write(1490788567);//2017-3-29-11:56:7
+    rtc_write(alarmtime);//2017-3-29-11:56:7
+    
+    //min = sec/60;
+    //sec = sec%60;
+     //set alarm time
+    LPC_RTC->ALSEC = timeinfo->tm_sec+sec;//10 sec
+    //LPC_RTC->ALMIN = timeinfo->tm_min+min;//10 sec
+
+    LPC_RTC->AMR &= (~(1 << 0)) & 0xFF;
+
+    LPC_RTC->ILR = (1 << 0) | (1 << 1);
+    
+    printf("RTC Alarm Time Set\r\n");
 
     NVIC_EnableIRQ(RTC_IRQn);
 
@@ -130,7 +135,7 @@
     MDMSerial mdm;            
     gmdm = &mdm;
     us_ticker_init();
-    //timer0_init(2);
+    
 
 while(1)
 {
@@ -142,10 +147,8 @@
             if(bSendingDataFlag)//&& bAlarmIntervalFlag)
             {
                 //bAlarmIntervalFlag = false;
-                unsigned int counter = 50;
-                while( (ret = gps.getMessage(buf, sizeof(buf))) > 0 || counter > 0)
+                while( (ret = gps.getMessage(buf, sizeof(buf))) > 0)
                 {
-                    counter--;
                     int len = LENGTH(ret);
                     ulGPSRxCntr = len;
                     if( (PROTOCOL(ret)==GPSParser::NMEA) && (len > 6) )
@@ -200,13 +203,13 @@
                 sprintf( caLssFinalAssetMsg, "$AQLSS,02,%s,%s*xx",devStatus.imei,devStatus.imsi);
                 printf( "HeartBeat: %s\r\n", caLssFinalAssetMsg );
             }
-                
+            
             ssocket = mdm.socketSocket(MDMParser::IPPROTO_UDP, pport);
             if( ssocket >= 0 ) 
             {
                 mdm.socketSetBlocking(ssocket, 10);
                 ipp = 0x97092263;//0x052753CE;
-                if (PASS == test_exchange_func(caLssFinalAssetMsg,strlen(caLssFinalAssetMsg)))
+                if (PASS == test_exchange_func(caLssFinalAssetMsg,strlen(caLssFinalAssetMsg),ucReturnCode))
                 {
                     printf("\r\n-----------------<pass>-----------------\n");           
                 }                
@@ -215,22 +218,26 @@
 
                 mdm.socketFree(ssocket);
                 responce_checker(); 
-            }   
+            }
 
             mdm.disconnect();
-            mdm.powerOff();
+            /*mdm.powerOff();*/
+        
             if(bSleepModeFlag)
             {
-                rtc_setup();
-                hal_deepsleep();
-                //sleep_mode();
-                //uiWakeupCounter++;
+                 rtc_setup(alarmtime,10);
+                printf("Enter Sleep Mode\r\n");
+                hal_sleep();
+                printf("Exit Sleep Mode\r\n");
+                myled = !myled;
+                uiWakeupCounter++;
             }
-            if(bSendingDataFlag)
+            
+            /*if(bSendingDataFlag)
                 wait( 10 );
             else
                 wait( 60 );
-            myled = !myled;
+            myled = !myled;*/
         }
     //}
 }
@@ -295,17 +302,9 @@
        printf("Ussd Got Answer: \"%s\"\r\n", buffer);
 }
 */
-void sleep_mode(void)
-{
-    /* Deep-Sleep Mode, set SLEEPDEEP bit */
-    //SCB->SCR |= 0x4;
-    LPC_SC->PCON = 0x9;
-    __WFI();
-    //SystemInit();
-} 
 
 void responce_checker(void)
-{/*
+{    
     if(!strcmp((const char*)ucReturnCode,"RC 000"))
     {
         printf("Acknowledged RC 000\r\n");
@@ -350,5 +349,5 @@
     else if(!strcmp((const char*)ucReturnCode,"EC 002"))
     {
         printf("Error Code 002 Received Payload is corrupted\r\n");
-    }*/
+    }
 }