Adapted to LoRa Semtech + Nucleo

Dependents:   LoRaWAN-lmic-app LoRaWAN-lmic-app LoRaWAN-test-10secs LoRaPersonalizedDeviceForEverynet ... more

Fork of cantcoap by Ashley Mills

Revision:
2:d0d57af6c9df
Parent:
1:5eec2844ad47
--- a/cantcoap.cpp	Thu Jan 30 14:07:56 2014 +0000
+++ b/cantcoap.cpp	Fri Nov 20 12:30:26 2015 +0000
@@ -35,29 +35,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+//#include <unistd.h>
 #include <string.h>
-#include <inet.h>
 #include "cantcoap.h"
-
-// for debugging output you need https://mbed.org/users/donatien/code/DebugLib/
-#define __DEBUG__ 3 // INFO
-#ifndef __MODULE__
-   #define __MODULE__ "cantcoap.cpp"
-#endif
-#include "dbg.h"
-// some extra debug stuff
-#if __DEBUG__ > 0
-   #define INFOX(...)  do { fprintf(stderr,__VA_ARGS__); } while(0)
-   #define INFOLX(...) do { fprintf(stderr,"[INFO] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0) 
-   #define DBGLX(...)  do { fprintf(stderr,"[DBG] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0)
-   #define DBG_PDU()   do { printBin(); } while(0)
-#else
-   #define INFOX(...)  do{} while(0)
-   #define INFOLX(...) do{} while(0)
-   #define DBGLX(...)  do{} while(0)
-   #define DBG_PDU()   do{} while(0)
-#endif
-
+#include "lwip/inet.h"
+#include "mbed.h"
+//#include <iostream>
 
 /// Memory-managed constructor. Buffer for PDU is dynamically sized and allocated by the object.
 /**
@@ -122,34 +105,8 @@
  * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
  */
 CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) {
-    int bufferLength = pduLength;
-    // sanity
-	if(pduLength<4&&pduLength!=0) {
-		DBG("PDU cannot have a length less than 4");
-	}
-
-	// pdu
-	_pdu = pdu;
-	_bufferLength = bufferLength;
-	if(pduLength==0) {
-		// this is actually a fresh pdu, header always exists
-		_pduLength = 4;
-		// make sure header is zeroed
-		_pdu[0] = 0x00; _pdu[1] = 0x00; _pdu[2] = 0x00; _pdu[3] = 0x00;
-		setVersion(1);
-	} else {
-		_pduLength = pduLength;
-	}
-
-	_constructedFromBuffer = 1;
-
-	// options
-	_numOptions = 0;
-	_maxAddedOptionNumber = 0;
-
-	// payload
-	_payloadPointer = NULL;
-	_payloadLength = 0;
+	CoapPDU(pdu,pduLength,pduLength);
+	// delegated to CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
 }
 
 /// Construct object from external buffer that may be larger than actual PDU.
@@ -298,7 +255,7 @@
 		(code>COAP_UNSUPPORTED_CONTENT_FORMAT&&code<COAP_INTERNAL_SERVER_ERROR) ||
 		(code>COAP_PROXYING_NOT_SUPPORTED) ) {
 		DBG("Invalid CoAP code: %d",code);
-		return 0;
+		//return 0;
 	}
 	DBG("CoAP code: %d",code);
 
@@ -452,28 +409,35 @@
  * Calls CoapPDU::setURI(uri,strlen(uri).
  */
 int CoapPDU::setURI(char *uri) {
-	return setURI(uri,strlen(uri));
+	return setURI(uri,(int)strlen(uri));
 }
 
 /// Shorthand function for setting a resource URI.
 /**
- * This will parse the supplied \b uri and construct enough URI_PATH CoAP options to encode it.
+ * This will parse the supplied \b uri and construct enough URI_PATH and URI_QUERY options to encode it.
  * The options are added to the PDU.
  * 
- * At present queries are not handled. TODO Implement queries.
+ * At present only simple URI formatting is handled, only '/','?', and '&' separators, and no port or protocol specificaiton.
+ *
+ * The function will split on '/' and create URI_PATH elements until it either reaches the end of the string
+ * in which case it will stop or if it reaches '?' it will start splitting on '&' and create URI_QUERY elements
+ * until it reaches the end of the string.
  *
- * \note This uses an internal buffer of 16 bytes to manipulate strings. The internal buffer will be
- * expanded dynamically if necessary (path component longer than 16 bytes). The internal buffer will
- * be freed before the function returns.
- * 
+ * Here is an example:
+ *
+ * /a/b/c/d?x=1&y=2&z=3
+ *
+ * Will be broken into four URI_PATH elements "a", "b", "c", "d", and three URI_QUERY elements "x=1", "y=2", "z=3"
+ *
+ * TODO: Add protocol extraction, port extraction, and some malformity checking.
+ *
  * \param uri The uri to parse.
  * \param urilen The length of the uri to parse.
  *
  * \return 1 on success, 0 on failure.
  */
 int CoapPDU::setURI(char *uri, int urilen) {
-	// only '/' and alphabetic chars allowed
-	// very simple splitting done
+	// only '/', '?', '&' and ascii chars allowed
 
 	// sanitation
 	if(urilen<=0||uri==NULL) {
@@ -487,67 +451,73 @@
 		return 0;
 	}
 
+	// TODO, queries
+	// extract ? to mark where to stop processing path components
+	// and then process the query params
+
 	// local vars
 	char *startP=uri,*endP=NULL;
-	int oLen = 0;
-	int bufSpace = 16;
-	char *uriBuf = (char*)malloc(bufSpace*sizeof(char));
-	if(uriBuf==NULL) {
-		DBG("Error allocating temporary memory.");
-		return 1;
-	}
-
+	long oLen = 0;
+	char splitChar = '/';
+	int queryStageTriggered = 0;
+	uint16_t optionType = COAP_OPTION_URI_PATH;
 	while(1) {
-		// stop at end of string
+		// stop at end of string or query
 		if(*startP==0x00||*(startP+1)==0x00) {
 			break;
 		}
 
 		// ignore leading slash
-		if(*startP=='/') {
+		if(*startP==splitChar) {
 			DBG("Skipping leading slash");
 			startP++;
 		}
 
 		// find next split point
-		endP = strchr(startP,'/');
+		endP = strchr(startP,splitChar);
 
 		// might not be another slash
 		if(endP==NULL) {
 			DBG("Ending out of slash");
-			endP = uri+urilen;
+			// check if there is a ?
+			endP = strchr(startP,'?');
+			// done if no queries
+			if(endP==NULL) {
+				endP = uri+urilen;
+			} else {
+				queryStageTriggered = 1;
+			}
 		}
 
 		// get length of segment
 		oLen = endP-startP;
 
-		// copy sequence, make space if necessary
-		if((oLen+1)>bufSpace) {
-			char *newBuf = (char*)realloc(uriBuf,oLen+1);
-			if(newBuf==NULL) {
-				DBG("Error making space for temporary buffer");
-				free(uriBuf);
-				return 1;
-			}
-			uriBuf = newBuf;
-		}
+		#ifdef DEBUG
+		char *b = (char*)malloc(oLen+1);
+		memcpy(b,startP,oLen);
+		b[oLen] = 0x00;
+		DBG("Adding URI_PATH %s",b);
+		free(b);
+		#endif
 
-		// copy into temporary buffer
-		memcpy(uriBuf,startP,oLen);
-		uriBuf[oLen] = 0x00;
-		DBG("Adding URI_PATH %s",uriBuf);
 		// add option
-		if(addOption(COAP_OPTION_URI_PATH,oLen,(uint8_t*)uriBuf)!=0) {
+		if(addOption(optionType,oLen,(uint8_t*)startP)!=0) {
 			DBG("Error adding option");
 			return 1;
 		}
 		startP = endP;
+
+		if(queryStageTriggered) {
+			splitChar = '&';
+			optionType = COAP_OPTION_URI_QUERY;
+			startP++;
+			queryStageTriggered = false;
+		}
 	}
 
-	// clean up
-	free(uriBuf);
 	return 0;
 }
+
 /// Shorthand for adding a URI QUERY to the option list.
 /**
  * Adds a new option to the CoAP PDU that encodes a URI_QUERY.
@@ -559,10 +529,12 @@
 	return addOption(COAP_OPTION_URI_QUERY,strlen(query),(uint8_t*)query);
 }
 
-/// Concatenates any URI_PATH elements into a single string.
+/// Concatenates any URI_PATH elements and URI_QUERY elements into a single string.
 /**
- * Parses the PDU options and extracts all URI_PATH elements, concatenating them into a single string with slash separators.
- * The produced string will be null terminated.
+ * Parses the PDU options and extracts all URI_PATH and URI_QUERY elements, 
+ * concatenating them into a single string with slash and amphersand separators accordingly.
+ * 
+ * The produced string will be NULL terminated.
  * 
  * \param dst Buffer into which to copy the concatenated path elements.
  * \param dstlen Length of buffer.
@@ -615,10 +587,24 @@
 		DBG("No space for initial slash needed 1, got %d",bytesLeft);
 		return 1;
 	}
+
+	char separator = '/';
+	int firstQuery = 1;
+
 	for(int i=0; i<_numOptions; i++) {
 		o = &options[i];
 		oLen = o->optionValueLength;
-		if(o->optionNumber==COAP_OPTION_URI_PATH) {
+		if(o->optionNumber==COAP_OPTION_URI_PATH||o->optionNumber==COAP_OPTION_URI_QUERY) {
+			// if the option is a query, change the separator to &
+			if(o->optionNumber==COAP_OPTION_URI_QUERY) {
+				if(firstQuery) {
+					// change previous '/' to a '?'
+					*(dst-1) = '?';
+					firstQuery = 0;
+				}
+				separator = '&';
+			}
+
 			// check space
 			if(oLen>bytesLeft) {
 				DBG("Destination buffer too small, needed %d, got %d",oLen,bytesLeft);
@@ -632,16 +618,16 @@
 				return 0;
 			}
 
-			// copy URI path component
+			// copy URI path or query component
 			memcpy(dst,o->optionValuePointer,oLen);
 
 			// adjust counters
 			dst += oLen;
 			bytesLeft -= oLen;
 
-			// add slash following (don't know at this point if another option is coming)
+			// add separator following (don't know at this point if another option is coming)
 			if(bytesLeft>=1) {
-				*dst = '/';
+				*dst = separator;
 				dst++;
 				bytesLeft--;
 			} else {
@@ -651,7 +637,7 @@
 		}
 	}
 
-	// remove terminating slash
+	// remove terminating separator
 	dst--;
 	bytesLeft++;
 	// add null terminating byte (always space since reserved)
@@ -821,6 +807,16 @@
 	return 0;
 }
 
+long CoapPDU::getLongToken(){
+
+    long token=0;
+    
+    for (int i=0; i<getTokenLength(); ++i) {
+        token+= getTokenPointer()[i]<<8*i;
+    }
+    return ntohl(token);
+}
+
 /// Sets the CoAP response code
 void CoapPDU::setCode(CoapPDU::Code code) {
 	_pdu[1] = code;
@@ -1211,6 +1207,7 @@
  * \param len Length of payload byte sequence.
  * \return 0 on success, 1 on failure.
  */
+
 int CoapPDU::setPayload(uint8_t *payload, int len) {
 	if(payload==NULL) {
 		DBG("NULL payload pointer.");
@@ -1229,6 +1226,8 @@
 	return 0;
 }
 
+
+
 /// Returns a pointer to the payload buffer.
 uint8_t* CoapPDU::getPayloadPointer() {
 	return _payloadPointer;
@@ -1563,205 +1562,203 @@
 
 /// Prints the PDU in human-readable format.
 void CoapPDU::printHuman() {
-	INFOX("__________________\r\n");
+	INFO("__________________");
 	if(_constructedFromBuffer) {
-		INFOX("PDU was constructed from buffer of %d bytes\r\n",_bufferLength);
+		INFO("PDU was constructed from buffer of %d bytes",_bufferLength);
 	}
-	INFOX("PDU is %d bytes long\r\n",_pduLength);
-	INFOX("CoAP Version: %d\r\n",getVersion());
+	INFO("PDU is %d bytes long",_pduLength);
+	INFO("CoAP Version: %d",getVersion());
 	INFOX("Message Type: ");
 	switch(getType()) {
 		case COAP_CONFIRMABLE:
-			INFOX("Confirmable\r\n");
+			INFO("Confirmable");
 		break;
 
 		case COAP_NON_CONFIRMABLE:
-			INFOX("Non-Confirmable\r\n");
+			INFO("Non-Confirmable");
 		break;
 
 		case COAP_ACKNOWLEDGEMENT:
-			INFOX("Acknowledgement\r\n");
+			INFO("Acknowledgement");
 		break;
 
 		case COAP_RESET:
-			INFOX("Reset\r\n");
+			INFO("Reset");
 		break;
 	}
-	INFOX("Token length: %d\r\n",getTokenLength());
+	INFO("Token length: %d",getTokenLength());
 	INFOX("Code: ");
 	switch(getCode()) {
 		case COAP_EMPTY:
-			INFOX("0.00 Empty");
+			INFO("0.00 Empty");
 		break;
 		case COAP_GET:
-			INFOX("0.01 GET");
+			INFO("0.01 GET");
 		break;
 		case COAP_POST:
-			INFOX("0.02 POST");
+			INFO("0.02 POST");
 		break;
 		case COAP_PUT:
-			INFOX("0.03 PUT");
+			INFO("0.03 PUT");
 		break;
 		case COAP_DELETE:
-			INFOX("0.04 DELETE");
+			INFO("0.04 DELETE");
 		break;
 		case COAP_CREATED:
-			INFOX("2.01 Created");
+			INFO("2.01 Created");
 		break;
 		case COAP_DELETED:
-			INFOX("2.02 Deleted");
+			INFO("2.02 Deleted");
 		break;
 		case COAP_VALID:
-			INFOX("2.03 Valid");
+			INFO("2.03 Valid");
 		break;
 		case COAP_CHANGED:
-			INFOX("2.04 Changed");
+			INFO("2.04 Changed");
 		break;
 		case COAP_CONTENT:
-			INFOX("2.05 Content");
+			INFO("2.05 Content");
 		break;
 		case COAP_BAD_REQUEST:
-			INFOX("4.00 Bad Request");
+			INFO("4.00 Bad Request");
 		break;
 		case COAP_UNAUTHORIZED:
-			INFOX("4.01 Unauthorized");
+			INFO("4.01 Unauthorized");
 		break;
 		case COAP_BAD_OPTION:
-			INFOX("4.02 Bad Option");
+			INFO("4.02 Bad Option");
 		break;
 		case COAP_FORBIDDEN:
-			INFOX("4.03 Forbidden");
+			INFO("4.03 Forbidden");
 		break;
 		case COAP_NOT_FOUND:
-			INFOX("4.04 Not Found");
+			INFO("4.04 Not Found");
 		break;
 		case COAP_METHOD_NOT_ALLOWED:
-			INFOX("4.05 Method Not Allowed");
+			INFO("4.05 Method Not Allowed");
 		break;
 		case COAP_NOT_ACCEPTABLE:
-			INFOX("4.06 Not Acceptable");
+			INFO("4.06 Not Acceptable");
 		break;
 		case COAP_PRECONDITION_FAILED:
-			INFOX("4.12 Precondition Failed");
+			INFO("4.12 Precondition Failed");
 		break;
 		case COAP_REQUEST_ENTITY_TOO_LARGE:
-			INFOX("4.13 Request Entity Too Large");
+			INFO("4.13 Request Entity Too Large");
 		break;
 		case COAP_UNSUPPORTED_CONTENT_FORMAT:
-			INFOX("4.15 Unsupported Content-Format");
+			INFO("4.15 Unsupported Content-Format");
 		break;
 		case COAP_INTERNAL_SERVER_ERROR:
-			INFOX("5.00 Internal Server Error");
+			INFO("5.00 Internal Server Error");
 		break;
 		case COAP_NOT_IMPLEMENTED:
-			INFOX("5.01 Not Implemented");
+			INFO("5.01 Not Implemented");
 		break;
 		case COAP_BAD_GATEWAY:
-			INFOX("5.02 Bad Gateway");
+			INFO("5.02 Bad Gateway");
 		break;
 		case COAP_SERVICE_UNAVAILABLE:
-			INFOX("5.03 Service Unavailable");
+			INFO("5.03 Service Unavailable");
 		break;
 		case COAP_GATEWAY_TIMEOUT:
-			INFOX("5.04 Gateway Timeout");
+			INFO("5.04 Gateway Timeout");
 		break;
 		case COAP_PROXYING_NOT_SUPPORTED:
-			INFOX("5.05 Proxying Not Supported");
+			INFO("5.05 Proxying Not Supported");
 		break;
 		case COAP_UNDEFINED_CODE:
-			INFOX("Undefined Code");
+			INFO("Undefined Code");
 		break;
 	}
-	INFOX("\r\n");
 
 	// print message ID
-	INFOX("Message ID: %u\r\n",getMessageID());
+	INFO("Message ID: %u",getMessageID());
 
 	// print token value
 	int tokenLength = getTokenLength();
 	uint8_t *tokenPointer = getPDUPointer()+COAP_HDR_SIZE;
 	if(tokenLength==0) {
-		INFOX("No token.\r\n");
+		INFO("No token.");
 	} else {
-		INFOX("Token of %d bytes.\r\n",tokenLength);
+		INFO("Token of %d bytes.",tokenLength);
 		INFOX("   Value: 0x");
 		for(int j=0; j<tokenLength; j++) {
 			INFOX("%.2x",tokenPointer[j]);
 		}
-		INFOX("\r\n");
+		INFO(" ");
 	}
 
 	// print options
 	CoapPDU::CoapOption* options = getOptions();
-	INFOX("%d options:\r\n",_numOptions);
+	INFO("%d options:",_numOptions);
 	for(int i=0; i<_numOptions; i++) {
-		INFOX("OPTION (%d/%d)\r\n",i,_numOptions);
-		INFOX("   Option number (delta): %hu (%hu)\r\n",options[i].optionNumber,options[i].optionDelta);
+		INFO("OPTION (%d/%d)",i + 1,_numOptions);
+		INFO("   Option number (delta): %hu (%hu)",options[i].optionNumber,options[i].optionDelta);
 		INFOX("   Name: ");
 		switch(options[i].optionNumber) {
 			case COAP_OPTION_IF_MATCH:
-				INFOX("IF_MATCH");
+				INFO("IF_MATCH");
 			break;
 			case COAP_OPTION_URI_HOST:
-				INFOX("URI_HOST");
+				INFO("URI_HOST");
 			break;
 			case COAP_OPTION_ETAG:
-				INFOX("ETAG");
+				INFO("ETAG");
 			break;
 			case COAP_OPTION_IF_NONE_MATCH:
-				INFOX("IF_NONE_MATCH");
+				INFO("IF_NONE_MATCH");
 			break;
 			case COAP_OPTION_OBSERVE:
-				INFOX("OBSERVE");
+				INFO("OBSERVE");
 			break;
 			case COAP_OPTION_URI_PORT:
-				INFOX("URI_PORT");
+				INFO("URI_PORT");
 			break;
 			case COAP_OPTION_LOCATION_PATH:
-				INFOX("LOCATION_PATH");
+				INFO("LOCATION_PATH");
 			break;
 			case COAP_OPTION_URI_PATH:
-				INFOX("URI_PATH");
+				INFO("URI_PATH");
 			break;
 			case COAP_OPTION_CONTENT_FORMAT:
-				INFOX("CONTENT_FORMAT");
+				INFO("CONTENT_FORMAT");
 			break;
 			case COAP_OPTION_MAX_AGE:
-				INFOX("MAX_AGE");
+				INFO("MAX_AGE");
 			break;
 			case COAP_OPTION_URI_QUERY:
-				INFOX("URI_QUERY");
+				INFO("URI_QUERY");
 			break;
 			case COAP_OPTION_ACCEPT:
-				INFOX("ACCEPT");
+				INFO("ACCEPT");
 			break;
 			case COAP_OPTION_LOCATION_QUERY:
-				INFOX("LOCATION_QUERY");
+				INFO("LOCATION_QUERY");
 			break;
 			case COAP_OPTION_PROXY_URI:
-				INFOX("PROXY_URI");
+				INFO("PROXY_URI");
 			break;
 			case COAP_OPTION_PROXY_SCHEME:
-				INFOX("PROXY_SCHEME");
+				INFO("PROXY_SCHEME");
 			break;
 			case COAP_OPTION_BLOCK1:
-				INFOX("BLOCK1");
+				INFO("BLOCK1");
 			break;
 			case COAP_OPTION_BLOCK2:
-				INFOX("BLOCK2");
+				INFO("BLOCK2");
 			break;
 			case COAP_OPTION_SIZE1:
-				INFOX("SIZE1");
+				INFO("SIZE1");
 			break;
 			case COAP_OPTION_SIZE2:
-				INFOX("SIZE2");
+				INFO("SIZE2");
 			break;
 			default:
-				INFOX("Unknown option");
+				INFO("Unknown option");
 			break;
 		}
-		INFOX("\r\n");
-		INFOX("   Value length: %u\r\n",options[i].optionValueLength);
+		INFO("   Value length: %u",options[i].optionValueLength);
 		INFOX("   Value: \"");
 		for(int j=0; j<options[i].optionValueLength; j++) {
 			char c = options[i].optionValuePointer[j];
@@ -1771,14 +1768,14 @@
 				INFOX("\\%.2d",c);
 			}
 		}
-		INFOX("\"\r\n");
+		INFO("\"");
 	}
 	
 	// print payload
 	if(_payloadLength==0) {
-		INFOX("No payload.\r\n");
+		INFO("No payload.");
 	} else {
-		INFOX("Payload of %d bytes\r\n",_payloadLength);
+		INFO("Payload of %d bytes",_payloadLength);
 		INFOX("   Value: \"");
 		for(int j=0; j<_payloadLength; j++) {
 			char c = _payloadPointer[j];
@@ -1788,9 +1785,9 @@
 				INFOX("\\%.2x",c);
 			}
 		}
-		INFO("\"\r\n");
+		INFO("\"");
 	}
-	INFOX("__________________\r\n");
+	INFO("__________________");
 }
 
 /// Prints the PDU as a c array (useful for debugging or hardcoding PDUs)
@@ -1812,7 +1809,7 @@
 	uint16_t optionValueLength = getOptionValueLength(option);
 	int extraDeltaBytes = computeExtraBytes(optionDelta);
 	int extraValueLengthBytes = computeExtraBytes(optionValueLength);
-	int totalLength = 1+extraDeltaBytes+extraValueLengthBytes+optionValueLength;
+	long totalLength = 1+extraDeltaBytes+extraValueLengthBytes+optionValueLength;
 
 	if(totalLength>_pduLength) {
 		totalLength = &_pdu[_pduLength-1]-option;
@@ -1911,4 +1908,4 @@
 /// Dumps the PDU as a byte sequence to stdout.
 void CoapPDU::print() {
 	fwrite(_pdu,1,_pduLength,stdout);
-}
\ No newline at end of file
+}