CoAP server ported from Arduino microcoap

Dependencies:   EthernetInterface Socket mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
rfrenken
Date:
Thu Mar 23 16:29:41 2017 +0000
Commit message:
Coap Server ported from Arduino microcoap

Changed in this revision

EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
Socket.lib Show annotated file Show diff for this revision Revisions of this file
coap.h Show annotated file Show diff for this revision Revisions of this file
endpoints.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
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 64df7fc091da EthernetInterface.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/rfrenken/code/EthernetInterface/#99407e48004d
diff -r 000000000000 -r 64df7fc091da Socket.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.lib	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/mbed_official/code/Socket/#434906b5b977
diff -r 000000000000 -r 64df7fc091da coap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/coap.h	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,179 @@
+#ifndef COAP_H
+#define COAP_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#define MAXOPT 16
+
+//http://tools.ietf.org/html/rfc7252#section-3
+typedef struct
+{
+    uint8_t ver;                /* CoAP version number */
+    uint8_t t;                  /* CoAP Message Type */
+    uint8_t tkl;                /* Token length: indicates length of the Token field */
+    uint8_t code;               /* CoAP status code. Can be request (0.xx), success reponse (2.xx), 
+                                 * client error response (4.xx), or rever error response (5.xx) 
+                                 * For possible values, see http://tools.ietf.org/html/rfc7252#section-12.1 */
+    uint8_t id[2];
+} coap_header_t;
+
+typedef struct
+{
+    const uint8_t *p;
+    size_t len;
+} coap_buffer_t;
+
+typedef struct
+{
+    uint8_t *p;
+    size_t len;
+} coap_rw_buffer_t;
+
+typedef struct
+{
+    uint8_t num;                /* Option number. See http://tools.ietf.org/html/rfc7252#section-5.10 */
+    coap_buffer_t buf;          /* Option value */
+} coap_option_t;
+
+typedef struct
+{
+    coap_header_t hdr;          /* Header of the packet */
+    coap_buffer_t tok;          /* Token value, size as specified by hdr.tkl */
+    uint8_t numopts;            /* Number of options */
+    coap_option_t opts[MAXOPT]; /* Options of the packet. For possible entries see
+                                 * http://tools.ietf.org/html/rfc7252#section-5.10 */
+    coap_buffer_t payload;      /* Payload carried by the packet */
+} coap_packet_t;
+
+/////////////////////////////////////////
+
+//http://tools.ietf.org/html/rfc7252#section-12.2
+typedef enum
+{
+    COAP_OPTION_IF_MATCH = 1,
+    COAP_OPTION_URI_HOST = 3,
+    COAP_OPTION_ETAG = 4,
+    COAP_OPTION_IF_NONE_MATCH = 5,
+    COAP_OPTION_OBSERVE = 6,
+    COAP_OPTION_URI_PORT = 7,
+    COAP_OPTION_LOCATION_PATH = 8,
+    COAP_OPTION_URI_PATH = 11,
+    COAP_OPTION_CONTENT_FORMAT = 12,
+    COAP_OPTION_MAX_AGE = 14,
+    COAP_OPTION_URI_QUERY = 15,
+    COAP_OPTION_ACCEPT = 17,
+    COAP_OPTION_LOCATION_QUERY = 20,
+    COAP_OPTION_PROXY_URI = 35,
+    COAP_OPTION_PROXY_SCHEME = 39
+} coap_option_num_t;
+
+//http://tools.ietf.org/html/rfc7252#section-12.1.1
+typedef enum
+{
+    COAP_METHOD_GET = 1,
+    COAP_METHOD_POST = 2,
+    COAP_METHOD_PUT = 3,
+    COAP_METHOD_DELETE = 4
+} coap_method_t;
+
+//http://tools.ietf.org/html/rfc7252#section-12.1.1
+typedef enum
+{
+    COAP_TYPE_CON = 0,
+    COAP_TYPE_NONCON = 1,
+    COAP_TYPE_ACK = 2,
+    COAP_TYPE_RESET = 3
+} coap_msgtype_t;
+
+//http://tools.ietf.org/html/rfc7252#section-5.2
+//http://tools.ietf.org/html/rfc7252#section-12.1.2
+#define MAKE_RSPCODE(clas, det) ((clas << 5) | (det))
+typedef enum
+{
+    COAP_RSPCODE_CONTENT = MAKE_RSPCODE(2, 5),
+    COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4),
+    COAP_RSPCODE_BAD_REQUEST = MAKE_RSPCODE(4, 0),
+    COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4)
+} coap_responsecode_t;
+
+//http://tools.ietf.org/html/rfc7252#section-12.3
+typedef enum
+{
+    COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block
+    COAP_CONTENTTYPE_TEXT_PLAIN = 0,
+    COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40,
+    COAP_CONTENTTYPE_APPLICATION_XML = 41,
+    COAP_CONTENTTYPE_APPLICATION_OCTECT_STREAM = 42,
+    COAP_CONTENTTYPE_APPLICATION_EXI = 47,
+    COAP_CONTENTTYPE_APPLICATION_JSON = 50,
+} coap_content_type_t;
+
+///////////////////////
+
+typedef enum
+{
+    COAP_ERR_NONE = 0,
+    COAP_ERR_HEADER_TOO_SHORT = 1,
+    COAP_ERR_VERSION_NOT_1 = 2,
+    COAP_ERR_TOKEN_TOO_SHORT = 3,
+    COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER = 4,
+    COAP_ERR_OPTION_TOO_SHORT = 5,
+    COAP_ERR_OPTION_OVERRUNS_PACKET = 6,
+    COAP_ERR_OPTION_TOO_BIG = 7,
+    COAP_ERR_OPTION_LEN_INVALID = 8,
+    COAP_ERR_BUFFER_TOO_SMALL = 9,
+    COAP_ERR_UNSUPPORTED = 10,
+    COAP_ERR_OPTION_DELTA_INVALID = 11,
+} coap_error_t;
+
+///////////////////////
+
+typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo);
+#define MAX_SEGMENTS 2  // 2 = /foo/bar, 3 = /foo/bar/baz
+typedef struct
+{
+    int count;
+    const char *elems[MAX_SEGMENTS];
+} coap_endpoint_path_t;
+
+typedef struct
+{
+    coap_method_t method;               /* (i.e. POST, PUT or GET) */
+    coap_endpoint_func handler;         /* callback function which handles this 
+                                         * type of endpoint (and calls 
+                                         * coap_make_response() at some point) */
+    const coap_endpoint_path_t *path;   /* path towards a resource (i.e. foo/bar/) */ 
+    const char *core_attr;              /* the 'ct' attribute, as defined in RFC7252, section 7.2.1.:
+                                         * "The Content-Format code "ct" attribute 
+                                         * provides a hint about the 
+                                         * Content-Formats this resource returns." 
+                                         * (Section 12.3. lists possible ct values.) */
+} coap_endpoint_t;
+
+
+///////////////////////
+void coap_dumpPacket(coap_packet_t *pkt);
+int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen);
+int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf);
+const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count);
+int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt);
+void coap_dump(const uint8_t *buf, size_t buflen, bool bare);
+int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type);
+int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt);
+void coap_option_nibble(uint32_t value, uint8_t *nibble);
+void coap_setup(void);
+void endpoint_setup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+extern const coap_endpoint_t endpoints[];
\ No newline at end of file
diff -r 000000000000 -r 64df7fc091da endpoints.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/endpoints.cpp	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,234 @@
+#include "mbed.h"
+#include <stdbool.h>
+#include <string.h>
+
+#include "coap.h"
+
+static char light = '0';
+static char led0 = '0';
+static char led1 = '0';
+static char led2 = '0';
+static char led3 = '0';
+DigitalOut myled(LED1);
+DigitalOut myled1(LED2);
+DigitalOut myled2(LED3);
+DigitalOut myled3(LED4);
+
+const uint16_t rsplen = 1500;
+static char rsp[1500] = "";
+void build_rsp(void);
+
+#include <stdio.h>
+void endpoint_setup(void)
+{
+    build_rsp();
+}
+
+static const coap_endpoint_path_t path_well_known_core = {2, {".well-known", "core"}};
+static int handle_get_well_known_core(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    return coap_make_response(scratch, outpkt, (const uint8_t *)rsp, strlen(rsp), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT);
+}
+
+static const coap_endpoint_path_t path_light = {1, {"light"}};
+
+static const coap_endpoint_path_t path_led0 = {2, {"led", "0"}};
+
+static const coap_endpoint_path_t path_led1 = {2, {"led", "1"}};
+
+static const coap_endpoint_path_t path_led2 = {2, {"led", "2"}};
+
+static const coap_endpoint_path_t path_led3 = {2, {"led", "3"}};
+
+static int handle_get_light(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
+}
+
+static int handle_get_led0(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    return coap_make_response(scratch, outpkt, (const uint8_t *)&led0, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
+}
+
+static int handle_get_led1(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    return coap_make_response(scratch, outpkt, (const uint8_t *)&led1, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
+}
+
+static int handle_get_led2(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    return coap_make_response(scratch, outpkt, (const uint8_t *)&led2, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
+}
+
+static int handle_get_led3(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    return coap_make_response(scratch, outpkt, (const uint8_t *)&led3, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
+}
+
+static int handle_put_light(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    if (inpkt->payload.len == 0)
+        return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
+    if (inpkt->payload.p[0] == '1')
+    {
+        light = '1';
+#ifdef ARDUINO
+        digitalWrite(led, HIGH);
+#else
+        myled = 1;
+        printf("ON\n");
+#endif
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+    else
+    {
+        light = '0';
+#ifdef ARDUINO
+        digitalWrite(led, LOW);
+#else
+        myled = 0;
+        printf("OFF\n");
+#endif
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+}
+
+static int handle_put_led0(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    if (inpkt->payload.len == 0)
+        return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
+    if (inpkt->payload.p[0] == '1')
+    {
+        led0 = '1';
+        myled = 1;
+        printf("ON\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led0, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+    else
+    {
+        led0 = '0';
+        myled = 0;
+        printf("OFF\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led0, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+}
+
+static int handle_put_led1(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    if (inpkt->payload.len == 0)
+        return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
+    if (inpkt->payload.p[0] == '1')
+    {
+        led1 = '1';
+        myled1 = 1;
+        printf("ON\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led1, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+    else
+    {
+        led1 = '0';
+        myled1 = 0;
+        printf("OFF\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led1, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+}
+
+static int handle_put_led2(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    if (inpkt->payload.len == 0)
+        return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
+    if (inpkt->payload.p[0] == '1')
+    {
+        led2 = '1';
+        myled2 = 1;
+        printf("ON\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led2, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+    else
+    {
+        led2 = '0';
+        myled2 = 0;
+        printf("OFF\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led2, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+}
+
+static int handle_put_led3(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
+{
+    if (inpkt->payload.len == 0)
+        return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
+    if (inpkt->payload.p[0] == '1')
+    {
+        led3 = '1';
+        myled3 = 1;
+        printf("ON\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led3, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+    else
+    {
+        led3 = '0';
+        myled3 = 0;
+        printf("OFF\n");
+        return coap_make_response(scratch, outpkt, (const uint8_t *)&led3, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);
+    }
+}
+
+
+
+const coap_endpoint_t endpoints[] =
+{
+    {COAP_METHOD_GET, handle_get_well_known_core, &path_well_known_core, "ct=40"},
+    {COAP_METHOD_GET, handle_get_light, &path_light, "ct=0"},
+    {COAP_METHOD_PUT, handle_put_light, &path_light, NULL},
+    {COAP_METHOD_GET, handle_get_led0, &path_led0, "ct=0"},
+    {COAP_METHOD_PUT, handle_put_led0, &path_led0, NULL},
+    {COAP_METHOD_GET, handle_get_led1, &path_led1, "ct=0"},
+    {COAP_METHOD_PUT, handle_put_led1, &path_led1, NULL},
+    {COAP_METHOD_GET, handle_get_led2, &path_led2, "ct=0"},
+    {COAP_METHOD_PUT, handle_put_led2, &path_led2, NULL},
+    {COAP_METHOD_GET, handle_get_led3, &path_led3, "ct=0"},
+    {COAP_METHOD_PUT, handle_put_led3, &path_led3, NULL},
+    {(coap_method_t)0, NULL, NULL, NULL}
+};
+
+void build_rsp(void)
+{
+    uint16_t len = rsplen;
+    const coap_endpoint_t *ep = endpoints;
+    int i;
+
+    len--; // Null-terminated string
+
+    while(NULL != ep->handler)
+    {
+        if (NULL == ep->core_attr) {
+            ep++;
+            continue;
+        }
+
+        if (0 < strlen(rsp)) {
+            strncat(rsp, ",", len);
+            len--;
+        }
+
+        strncat(rsp, "<", len);
+        len--;
+
+        for (i = 0; i < ep->path->count; i++) {
+            strncat(rsp, "/", len);
+            len--;
+
+            strncat(rsp, ep->path->elems[i], len);
+            len -= strlen(ep->path->elems[i]);
+        }
+
+        strncat(rsp, ">;", len);
+        len -= 2;
+
+        strncat(rsp, ep->core_attr, len);
+        len -= strlen(ep->core_attr);
+
+        ep++;
+    }
+}
+ 
\ No newline at end of file
diff -r 000000000000 -r 64df7fc091da main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,520 @@
+#include "mbed.h"
+#include "EthernetInterface.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stddef.h>
+#include "coap.h"
+
+#define PORT 5683
+
+extern void endpoint_setup(void);
+extern const coap_endpoint_t endpoints[];
+#define UDP_TX_PACKET_MAX_SIZE 256
+
+
+
+#ifdef DEBUG
+void coap_dumpHeader(coap_header_t *hdr)
+{
+    printf("Header:\n");
+    printf("  ver  0x%02X\n", hdr->ver);
+    printf("  t    0x%02X\n", hdr->t);
+    printf("  tkl  0x%02X\n", hdr->tkl);
+    printf("  code 0x%02X\n", hdr->code);
+    printf("  id   0x%02X%02X\n", hdr->id[0], hdr->id[1]);
+}
+#endif
+
+#ifdef DEBUG
+void coap_dump(const uint8_t *buf, size_t buflen, bool bare)
+{
+    if (bare)
+    {
+        while(buflen--)
+            printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
+    }
+    else
+    {
+        printf("Dump: ");
+        while(buflen--)
+            printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
+        printf("\n");
+    }
+}
+#endif
+
+int coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen)
+{
+    if (buflen < 4)
+        return COAP_ERR_HEADER_TOO_SHORT;
+    hdr->ver = (buf[0] & 0xC0) >> 6;
+    if (hdr->ver != 1)
+    {
+        printf("hdr versions is %d\n", hdr->ver);
+        return COAP_ERR_VERSION_NOT_1;
+    }
+    hdr->t = (buf[0] & 0x30) >> 4;
+    hdr->tkl = buf[0] & 0x0F;
+    hdr->code = buf[1];
+    hdr->id[0] = buf[2];
+    hdr->id[1] = buf[3];
+    return 0;
+}
+
+int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
+{
+    if (hdr->tkl == 0)
+    {
+        tokbuf->p = NULL;
+        tokbuf->len = 0;
+        return 0;
+    }
+    else
+    if (hdr->tkl <= 8)
+    {
+        if (4U + hdr->tkl > buflen)
+            return COAP_ERR_TOKEN_TOO_SHORT;   // tok bigger than packet
+        tokbuf->p = buf+4;  // past header
+        tokbuf->len = hdr->tkl;
+        return 0;
+    }
+    else
+    {
+        // invalid size
+        return COAP_ERR_TOKEN_TOO_SHORT;
+    }
+}
+
+// advances p
+int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)
+{
+    const uint8_t *p = *buf;
+    uint8_t headlen = 1;
+    uint16_t len, delta;
+
+    if (buflen < headlen) // too small
+        return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
+
+    delta = (p[0] & 0xF0) >> 4;
+    len = p[0] & 0x0F;
+
+    // These are untested and may be buggy
+    if (delta == 13)
+    {
+        headlen++;
+        if (buflen < headlen)
+            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
+        delta = p[1] + 13;
+        p++;
+    }
+    else
+    if (delta == 14)
+    {
+        headlen += 2;
+        if (buflen < headlen)
+            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
+        delta = ((p[1] << 8) | p[2]) + 269;
+        p+=2;
+    }
+    else
+    if (delta == 15)
+        return COAP_ERR_OPTION_DELTA_INVALID;
+
+    if (len == 13)
+    {
+        headlen++;
+        if (buflen < headlen)
+            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
+        len = p[1] + 13;
+        p++;
+    }
+    else
+    if (len == 14)
+    {
+        headlen += 2;
+        if (buflen < headlen)
+            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
+        len = ((p[1] << 8) | p[2]) + 269;
+        p+=2;
+    }
+    else
+    if (len == 15)
+        return COAP_ERR_OPTION_LEN_INVALID;
+
+    if ((p + 1 + len) > (*buf + buflen))
+        return COAP_ERR_OPTION_TOO_BIG;
+
+    //printf("option num=%d\n", delta + *running_delta);
+    option->num = delta + *running_delta;
+    option->buf.p = p+1;
+    option->buf.len = len;
+    //coap_dump(p+1, len, false);
+
+    // advance buf
+    *buf = p + 1 + len;
+    *running_delta += delta;
+
+    return 0;
+}
+
+// http://tools.ietf.org/html/rfc7252#section-3.1
+int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coap_buffer_t *payload, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
+{
+    size_t optionIndex = 0;
+    uint16_t delta = 0;
+    const uint8_t *p = buf + 4 + hdr->tkl;
+    const uint8_t *end = buf + buflen;
+    int rc;
+    if (p > end)
+        return COAP_ERR_OPTION_OVERRUNS_PACKET;   // out of bounds
+
+    //coap_dump(p, end - p);
+
+    // 0xFF is payload marker
+    while((optionIndex < *numOptions) && (p < end) && (*p != 0xFF))
+    {
+        if (0 != (rc = coap_parseOption(&options[optionIndex], &delta, &p, end-p)))
+            return rc;
+        optionIndex++;
+    }
+    *numOptions = optionIndex;
+
+    if (p+1 < end && *p == 0xFF)  // payload marker
+    {
+        payload->p = p+1;
+        payload->len = end-(p+1);
+    }
+    else
+    {
+        payload->p = NULL;
+        payload->len = 0;
+    }
+
+    return 0;
+}
+
+#ifdef DEBUG
+void coap_dumpOptions(coap_option_t *opts, size_t numopt)
+{
+    size_t i;
+    printf(" Options:\n");
+    for (i=0;i<numopt;i++)
+    {
+        printf("  0x%02X [ ", opts[i].num);
+        coap_dump(opts[i].buf.p, opts[i].buf.len, true);
+        printf(" ]\n");
+    }
+}
+#endif
+
+#ifdef DEBUG
+void coap_dumpPacket(coap_packet_t *pkt)
+{
+    coap_dumpHeader(&pkt->hdr);
+    coap_dumpOptions(pkt->opts, pkt->numopts);
+    printf("Payload: ");
+    coap_dump(pkt->payload.p, pkt->payload.len, true);
+    printf("\n");
+}
+#endif
+
+int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)
+{
+    int rc;
+
+    // coap_dump(buf, buflen, false);
+
+    if (0 != (rc = coap_parseHeader(&pkt->hdr, buf, buflen)))
+        return rc;
+//    coap_dumpHeader(&hdr);
+    if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen)))
+        return rc;
+    pkt->numopts = MAXOPT;
+    if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen)))
+        return rc;
+//    coap_dumpOptions(opts, numopt);
+    return 0;
+}
+
+// options are always stored consecutively, so can return a block with same option num
+const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count)
+{
+    // FIXME, options is always sorted, can find faster than this
+    size_t i;
+    const coap_option_t *first = NULL;
+    *count = 0;
+    for (i=0;i<pkt->numopts;i++)
+    {
+        if (pkt->opts[i].num == num)
+        {
+            if (NULL == first)
+                first = &pkt->opts[i];
+            (*count)++;
+        }
+        else
+        {
+            if (NULL != first)
+                break;
+        }
+    }
+    return first;
+}
+
+int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf)
+{
+    if (buf->len+1 > strbuflen)
+        return COAP_ERR_BUFFER_TOO_SMALL;
+    memcpy(strbuf, buf->p, buf->len);
+    strbuf[buf->len] = 0;
+    return 0;
+}
+
+int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
+{
+    size_t opts_len = 0;
+    size_t i;
+    uint8_t *p;
+    uint16_t running_delta = 0;
+
+    // build header
+    if (*buflen < (4U + pkt->hdr.tkl))
+        return COAP_ERR_BUFFER_TOO_SMALL;
+
+    buf[0] = (pkt->hdr.ver & 0x03) << 6;
+    buf[0] |= (pkt->hdr.t & 0x03) << 4;
+    buf[0] |= (pkt->hdr.tkl & 0x0F);
+    buf[1] = pkt->hdr.code;
+    buf[2] = pkt->hdr.id[0];
+    buf[3] = pkt->hdr.id[1];
+
+    // inject token
+    p = buf + 4;
+    if ((pkt->hdr.tkl > 0) && (pkt->hdr.tkl != pkt->tok.len))
+        return COAP_ERR_UNSUPPORTED;
+    
+    if (pkt->hdr.tkl > 0)
+        memcpy(p, pkt->tok.p, pkt->hdr.tkl);
+
+    // // http://tools.ietf.org/html/rfc7252#section-3.1
+    // inject options
+    p += pkt->hdr.tkl;
+
+    for (i=0;i<pkt->numopts;i++)
+    {
+        uint32_t optDelta;
+        uint8_t len, delta = 0;
+
+        if (((size_t)(p-buf)) > *buflen)
+             return COAP_ERR_BUFFER_TOO_SMALL;
+        optDelta = pkt->opts[i].num - running_delta;
+        coap_option_nibble(optDelta, &delta);
+        coap_option_nibble((uint32_t)pkt->opts[i].buf.len, &len);
+
+        *p++ = (0xFF & (delta << 4 | len));
+        if (delta == 13)
+        {
+            *p++ = (optDelta - 13);
+        }
+        else
+        if (delta == 14)
+        {
+            *p++ = ((optDelta-269) >> 8);
+            *p++ = (0xFF & (optDelta-269));
+        }
+        if (len == 13)
+        {
+            *p++ = (pkt->opts[i].buf.len - 13);
+        }
+        else
+        if (len == 14)
+        {
+            *p++ = (pkt->opts[i].buf.len >> 8);
+            *p++ = (0xFF & (pkt->opts[i].buf.len-269));
+        }
+
+        memcpy(p, pkt->opts[i].buf.p, pkt->opts[i].buf.len);
+        p += pkt->opts[i].buf.len;
+        running_delta = pkt->opts[i].num;
+    }
+
+    opts_len = (p - buf) - 4;   // number of bytes used by options
+
+    if (pkt->payload.len > 0)
+    {
+        if (*buflen < 4 + 1 + pkt->payload.len + opts_len)
+            return COAP_ERR_BUFFER_TOO_SMALL;
+        buf[4 + opts_len] = 0xFF;  // payload marker
+        memcpy(buf+5 + opts_len, pkt->payload.p, pkt->payload.len);
+        *buflen = opts_len + 5 + pkt->payload.len;
+    }
+    else
+        *buflen = opts_len + 4;
+    return 0;
+}
+
+void coap_option_nibble(uint32_t value, uint8_t *nibble)
+{
+    if (value<13)
+    {
+        *nibble = (0xFF & value);
+    }
+    else
+    if (value<=0xFF+13)
+    {
+        *nibble = 13;
+    } else if (value<=0xFFFF+269)
+    {
+        *nibble = 14;
+    }
+}
+
+int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type)
+{
+    pkt->hdr.ver = 0x01;
+    pkt->hdr.t = COAP_TYPE_ACK;
+    pkt->hdr.tkl = 0;
+    pkt->hdr.code = rspcode;
+    pkt->hdr.id[0] = msgid_hi;
+    pkt->hdr.id[1] = msgid_lo;
+    pkt->numopts = 1;
+
+    // need token in response
+    if (tok) {
+        pkt->hdr.tkl = tok->len;
+        pkt->tok = *tok;
+    }
+
+    // safe because 1 < MAXOPT
+    pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT;
+    pkt->opts[0].buf.p = scratch->p;
+    if (scratch->len < 2)
+        return COAP_ERR_BUFFER_TOO_SMALL;
+    scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8;
+    scratch->p[1] = ((uint16_t)content_type & 0x00FF);
+    pkt->opts[0].buf.len = 2;
+    pkt->payload.p = content;
+    pkt->payload.len = content_len;
+    return 0;
+}
+
+// FIXME, if this looked in the table at the path before the method then
+// it could more easily return 405 errors
+int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt)
+{
+    const coap_option_t *opt;
+    uint8_t count;
+    int i;
+    const coap_endpoint_t *ep = endpoints;
+
+    while(NULL != ep->handler)
+    {
+        if (ep->method != inpkt->hdr.code)
+            goto next;
+        if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
+        {
+            if (count != ep->path->count)
+                goto next;
+            for (i=0;i<count;i++)
+            {
+                if (opt[i].buf.len != strlen(ep->path->elems[i]))
+                    goto next;
+                if (0 != memcmp(ep->path->elems[i], opt[i].buf.p, opt[i].buf.len))
+                    goto next;
+            }
+            // match!
+            return ep->handler(scratch, inpkt, outpkt, inpkt->hdr.id[0], inpkt->hdr.id[1]);
+        }
+next:
+        ep++;
+    }
+
+    coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
+
+    return 0;
+}
+
+void coap_setup(void)
+{
+}
+
+Serial pc(USBTX, USBRX);
+static uint8_t scratch_raw[32];
+static coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};
+
+int main(void) {
+
+    
+    EthernetInterface eth;
+    eth.init(); //Use DHCP
+    eth.connect();
+    printf("IP Address is %s\n", eth.getIPAddress());
+    
+    UDPSocket coapServer;
+    coapServer.bind(PORT);
+    
+    coap_setup();
+    endpoint_setup();
+    Endpoint client;
+    char buffer[256];
+    uint8_t packetbuf[256];
+    coap_packet_t pkt;
+    
+    while (true) {
+            printf("\nWaiting for UDP packet...\n");
+        int sz = coapServer.receiveFrom(client,  buffer, sizeof(buffer));
+        buffer[sz] = '\0';
+        
+        printf("Received packet from: %s\n", client.get_address());
+        
+        printf("Packet contents : '%s'\n",buffer);
+
+#ifdef DEBUG
+        for (int i=0;i<sz;i++)
+        {
+            printf("%x",buffer[i]);
+            printf(" ");
+        }
+        printf("\n");
+#endif
+        int rc;
+
+        if (0 != (rc = coap_parse(&pkt, (uint8_t *)buffer, sz)))
+        {
+            printf("Bad packet rc=%d\n", rc);
+        }
+        else
+        {
+            size_t rsplen = sizeof(buffer);
+            coap_packet_t rsppkt;
+            coap_handle_req(&scratch_buf, &pkt, &rsppkt);
+
+            memset(buffer, 0, UDP_TX_PACKET_MAX_SIZE);
+            if (0 != (rc = coap_build((uint8_t *)buffer, &rsplen, &rsppkt)))
+            {
+                printf("coap_build failed rc=%d\n", rc);
+            }
+            else
+            {
+                coapServer.sendTo(client, (char *) buffer, rsplen);
+            }
+        }
+    }
+}
+
+
+    //coap_setup();
+    //endpoint_setup();
+// override the default weak function to provide a specific mac address
+/*extern "C" void mbed_mac_address(char *mac)
+{
+    mac[0] = 0x01;
+    mac[1] = 0x23;
+    mac[2] = 0x45;
+    mac[3] = 0x67;
+    mac[4] = 0x89;
+    mac[5] = 0xAB;
+};*/
+
diff -r 000000000000 -r 64df7fc091da mbed-rtos.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#58563e6cba1e
diff -r 000000000000 -r 64df7fc091da mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Mar 23 16:29:41 2017 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/mbed_official/code/mbed/builds/093f2bd7b9eb
\ No newline at end of file