Browse Source

default build with coap, reduce coap module mem usage

funshine 9 years ago
parent
commit
0b95ae08a2
10 changed files with 109 additions and 55 deletions
  1. 26 0
      README.md
  2. 14 14
      app/coap/coap.c
  3. 37 28
      app/coap/coap.h
  4. 2 0
      app/coap/coap_client.c
  5. 12 1
      app/coap/coap_server.c
  6. 12 7
      app/coap/endpoints.c
  7. 2 0
      app/coap/pdu.c
  8. 1 1
      app/include/user_modules.h
  9. 1 1
      app/include/user_version.h
  10. 2 3
      app/modules/coap.c

+ 26 - 0
README.md

@@ -34,6 +34,10 @@ Tencent QQ group: 309957875<br />
 - cross compiler (done)
 
 # Change log
+2015-03-15<br />
+bugs fixed: #239, #273.<br />
+reduce coap module memory usage, add coap module to default built.
+
 2015-03-11<br />
 fix bugs of spiffs.<br />
 build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).<br />
@@ -414,3 +418,25 @@ They'll be available as `u8g.<font_name>` in Lua.
 	-- first LED green, second LED white
 	ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255))
 ```
+
+####coap client and server
+```lua
+-- use copper addon for firefox
+cs=coap.Server()
+cs:listen(5683)
+
+myvar=1
+cs:var("myvar") -- get coap://192.168.18.103:5683/v1/v/myvar will return the value of myvar: 1
+
+-- function should tack one string, return one string.
+function myfun(payload)
+  print("myfun called")
+  respond = "hello"
+  return respond
+end
+cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun
+
+cc = coap.Client()
+cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
+cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")
+```

+ 14 - 14
app/coap/coap.c

@@ -76,7 +76,7 @@ int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8
     else
     if (hdr->tkl <= 8)
     {
-        if (4 + hdr->tkl > buflen)
+        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;
@@ -93,7 +93,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
 {
     // inject token
     uint8_t *p;
-    if (buflen < 4 + hdr->tkl)
+    if (buflen < (4U + hdr->tkl))
         return COAP_ERR_BUFFER_TOO_SMALL;
     p = buf + 4;
     if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len))
@@ -102,7 +102,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
     if (hdr->tkl > 0)
         c_memcpy(p, tokbuf->p, hdr->tkl);
 
-    // http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3.1
+    // http://tools.ietf.org/html/rfc7252#section-3.1
     // inject options
     return hdr->tkl;
 }
@@ -111,8 +111,8 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8
 int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)
 {
     const uint8_t *p = *buf;
-    uint16_t len, delta;
     uint8_t headlen = 1;
+    uint16_t len, delta;
 
     if (buflen < headlen) // too small
         return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
@@ -179,14 +179,14 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8
     return 0;
 }
 
-// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3.1
+// 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;
-    uint16_t delta = 0;
     if (p > end)
         return COAP_ERR_OPTION_OVERRUNS_PACKET;   // out of bounds
 
@@ -215,7 +215,7 @@ int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coa
     return 0;
 }
 
-int coap_buildOptionHeader(unsigned short optDelta, size_t length, uint8_t *buf, size_t buflen)
+int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen)
 {
     int n = 0;
     uint8_t *p = buf;
@@ -298,7 +298,7 @@ int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)
 }
 
 // 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)
+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;
@@ -352,7 +352,7 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
         uint16_t optDelta = 0;
         int rc = 0;
 
-        if (p-buf > *buflen)
+        if (((size_t)(p-buf)) > *buflen)
              return COAP_ERR_BUFFER_TOO_SMALL;
         optDelta = pkt->opts[i].num - running_delta;
 
@@ -381,17 +381,17 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
     return 0;
 }
 
-void coap_option_nibble(uint16_t value, uint8_t *nibble)
+void coap_option_nibble(uint32_t value, uint8_t *nibble)
 {
     if (value<13)
     {
         *nibble = (0xFF & value);
     }
     else
-    if (((uint32_t)value)<=0xFF+13)
+    if (value<=0xFF+13)
     {
         *nibble = 13;
-    } else if (((uint32_t)value) -269 <=0xFFFF)
+    } else if (value<=0xFFFF+269)
     {
         *nibble = 14;
     }
@@ -405,7 +405,7 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint
     pkt->hdr.code = rspcode;
     pkt->hdr.id[0] = msgid_hi;
     pkt->hdr.id[1] = msgid_lo;
-    pkt->numopts = 0;
+    pkt->numopts = 1;
 
     // need token in response
     if (tok) {
@@ -442,7 +442,7 @@ unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val) {
   return n;
 }
 
-static uint8_t _token_data[4]={'n','o','d','e'};
+static uint8_t _token_data[4] = {'n','o','d','e'};
 coap_buffer_t the_token = { _token_data, 4 };
 static unsigned short message_id;
 

+ 37 - 28
app/coap/coap.h

@@ -18,13 +18,15 @@ extern "C" {
 
 #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF)
 
-// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3
+//http://tools.ietf.org/html/rfc7252#section-3
 typedef struct
 {
-    uint8_t ver;
-    uint8_t t;
-    uint8_t tkl;
-    uint8_t code;
+    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;
 
@@ -42,23 +44,24 @@ typedef struct
 
 typedef struct
 {
-    uint8_t num;
-    coap_buffer_t buf;
+    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;
-    coap_buffer_t tok;
-    uint8_t numopts;
-    coap_option_t opts[MAXOPT];
-    coap_buffer_t payload;
-    coap_rw_buffer_t scratch;       // scratch->p = malloc(...) , and free it when done.
+    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_rw_buffer_t content;       // content->p = malloc(...) , and free it when done.
 } coap_packet_t;
 
 /////////////////////////////////////////
 
-//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.2
+//http://tools.ietf.org/html/rfc7252#section-12.2
 typedef enum
 {
     COAP_OPTION_IF_MATCH = 1,
@@ -78,7 +81,7 @@ typedef enum
     COAP_OPTION_PROXY_SCHEME = 39
 } coap_option_num_t;
 
-//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.1
+//http://tools.ietf.org/html/rfc7252#section-12.1.1
 typedef enum
 {
     COAP_METHOD_GET = 1,
@@ -87,7 +90,7 @@ typedef enum
     COAP_METHOD_DELETE = 4
 } coap_method_t;
 
-//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.1
+//http://tools.ietf.org/html/rfc7252#section-12.1.1
 typedef enum
 {
     COAP_TYPE_CON = 0,
@@ -96,8 +99,8 @@ typedef enum
     COAP_TYPE_RESET = 3
 } coap_msgtype_t;
 
-//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-5.2
-//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.2
+//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
 {
@@ -107,7 +110,7 @@ typedef enum
     COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4)
 } coap_responsecode_t;
 
-//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.3
+//http://tools.ietf.org/html/rfc7252#section-12.3
 typedef enum
 {
     COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block
@@ -155,15 +158,21 @@ struct coap_luser_entry{
     coap_luser_entry *next;
 };
 
-struct coap_endpoint_t
-{
-    coap_method_t method;
-    coap_endpoint_func handler;
-    const coap_endpoint_path_t *path;
-    const char *core_attr;
-    coap_luser_entry *user_entry;
+struct coap_endpoint_t{
+    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_luser_entry *user_entry;
 };
 
+
 ///////////////////////
 void coap_dumpPacket(coap_packet_t *pkt);
 int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen);
@@ -173,11 +182,11 @@ 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(uint16_t value, uint8_t *nibble);
+void coap_option_nibble(uint32_t value, uint8_t *nibble);
 void coap_setup(void);
 void endpoint_setup(void);
 
-int coap_buildOptionHeader(unsigned short optDelta, size_t length, uint8_t *buf, size_t buflen);
+int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen);
 
 #ifdef __cplusplus
 }

+ 2 - 0
app/coap/coap_client.c

@@ -11,6 +11,8 @@ void coap_client_response_handler(char *data, unsigned short len, unsigned short
 {
   NODE_DBG("coap_client_response_handler is called.\n");
   coap_packet_t pkt;
+  pkt.content.p = NULL;
+  pkt.content.len = 0;
   int rc;
 
   if (0 != (rc = coap_parse(&pkt, data, len))){

+ 12 - 1
app/coap/coap_server.c

@@ -1,5 +1,6 @@
 #include "user_config.h"
 #include "c_types.h"
+#include "c_stdlib.h"
 
 #include "coap.h"
 
@@ -8,6 +9,8 @@ size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned
   NODE_DBG("coap_server_respond is called.\n");
   size_t rlen = rsplen;
   coap_packet_t pkt;
+  pkt.content.p = NULL;
+  pkt.content.len = 0;
   uint8_t scratch_raw[4];
   coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};
   int rc;
@@ -25,13 +28,16 @@ size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned
   else
   {
     coap_packet_t rsppkt;
+    rsppkt.content.p = NULL;
+    rsppkt.content.len = 0;
 #ifdef COAP_DEBUG
     coap_dumpPacket(&pkt);
 #endif
     coap_handle_req(&scratch_buf, &pkt, &rsppkt);
     if (0 != (rc = coap_build(rsp, &rlen, &rsppkt))){
       NODE_DBG("coap_build failed rc=%d\n", rc);
-      return 0;
+      // return 0;
+      rlen = 0;
     }
     else
     {
@@ -44,6 +50,11 @@ size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned
       coap_dumpPacket(&rsppkt);
 #endif
     }
+    if(rsppkt.content.p){
+      c_free(rsppkt.content.p);
+      rsppkt.content.p = NULL;
+      rsppkt.content.len = 0;
+    }
     return rlen;
   }
 }

+ 12 - 7
app/coap/endpoints.c

@@ -1,5 +1,6 @@
 #include "c_stdio.h"
 #include "c_string.h"
+#include "c_stdlib.h"
 #include "coap.h"
 
 #include "lua.h"
@@ -8,20 +9,24 @@
 
 #include "os_type.h"
 
-static char rsp[512] = "";
-const uint16_t rsplen = 512;
-void build_well_known_rsp(void);
+void build_well_known_rsp(char *rsp, uint16_t rsplen);
 
 void endpoint_setup(void)
 {
     coap_setup();
-    build_well_known_rsp();
 }
 
 static const coap_endpoint_path_t path_well_known_core = {2, {".well-known", "core"}};
 static int handle_get_well_known_core(const coap_endpoint_t *ep, 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, c_strlen(rsp), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT);
+    outpkt->content.p = (uint8_t *)c_zalloc(MAX_PAYLOAD_SIZE);      // this should be free-ed when outpkt is built in coap_server_respond()
+    if(outpkt->content.p == NULL){
+        NODE_DBG("not enough memory\n");
+        return COAP_ERR_BUFFER_TOO_SMALL;
+    }
+    outpkt->content.len = MAX_PAYLOAD_SIZE;
+    build_well_known_rsp(outpkt->content.p, outpkt->content.len);
+    return coap_make_response(scratch, outpkt, (const uint8_t *)outpkt->content.p, c_strlen(outpkt->content.p), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT);
 }
 
 static const coap_endpoint_path_t path_variable = {2, {"v1", "v"}};
@@ -211,13 +216,13 @@ const coap_endpoint_t endpoints[] =
     {(coap_method_t)0, NULL, NULL, NULL, NULL}
 };
 
-void build_well_known_rsp(void)
+void build_well_known_rsp(char *rsp, uint16_t rsplen)
 {
     const coap_endpoint_t *ep = endpoints;
     int i;
     uint16_t len = rsplen;
 
-    c_memset(rsp, 0, sizeof(rsp));
+    c_memset(rsp, 0, len);
 
     len--; // Null-terminated string
 

+ 2 - 0
app/coap/pdu.c

@@ -24,6 +24,8 @@ coap_pdu_t * coap_new_pdu(void) {
     c_free(pdu);
     return NULL;
   }
+  pdu->pkt->content.p = NULL;
+  pdu->pkt->content.len = 0;
 
   pdu->msg.p = (uint8_t *)c_zalloc(MAX_REQUEST_SIZE+1); // +1 for string '\0'
   if(!pdu->msg.p){

+ 1 - 1
app/include/user_modules.h

@@ -27,7 +27,7 @@
 #define LUA_USE_MODULES_OW
 #define LUA_USE_MODULES_BIT
 #define LUA_USE_MODULES_MQTT
-// #define LUA_USE_MODULES_COAP			// need about 1k more ram for now
+#define LUA_USE_MODULES_COAP
 #define LUA_USE_MODULES_U8G
 #define LUA_USE_MODULES_WS2812
 #endif /* LUA_USE_MODULES */

+ 1 - 1
app/include/user_version.h

@@ -7,6 +7,6 @@
 #define NODE_VERSION_INTERNAL   0U
 
 #define NODE_VERSION	"NodeMCU 0.9.5"
-#define BUILD_DATE	    "build 20150311"
+#define BUILD_DATE	    "build 20150315"
 
 #endif	/* __USER_VERSION_H__ */

+ 2 - 3
app/modules/coap.c

@@ -227,6 +227,8 @@ static void coap_response_handler(void *arg, char *pdata, unsigned short len)
   struct espconn *pesp_conn = arg;
 
   coap_packet_t pkt;
+  pkt.content.p = NULL;
+  pkt.content.len = 0;
   // static uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0'
   uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0'
   c_memset(buf, 0, sizeof(buf)); // wipe prev data
@@ -421,7 +423,6 @@ static int coap_request( lua_State* L, coap_method_t m )
 
 extern coap_luser_entry *variable_entry;
 extern coap_luser_entry *function_entry;
-extern void build_well_known_rsp(void);
 // Lua: coap:var/func( string )
 static int coap_regist( lua_State* L, const char* mt, int isvar )
 {
@@ -456,8 +457,6 @@ static int coap_regist( lua_State* L, const char* mt, int isvar )
   h->L = L;
   h->name = name;
 
-  build_well_known_rsp(); // rebuild .well-known
-
   NODE_DBG("coap_regist is called.\n");
   return 0;  
 }