The KPN SenML library helps you create and parse senml documents in both json and cbor format. The library can be used for sending sensor data and receiving actuator commands.

Committer:
kpniot
Date:
Sat May 19 17:35:20 2018 +0000
Revision:
0:a9259748d982
first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kpniot 0:a9259748d982 1 /* _ __ ____ _ _
kpniot 0:a9259748d982 2 * | |/ / | _ \ | \ | |
kpniot 0:a9259748d982 3 * | ' / | |_) | | \| |
kpniot 0:a9259748d982 4 * | . \ | __/ | |\ |
kpniot 0:a9259748d982 5 * |_|\_\ |_| |_| \_|
kpniot 0:a9259748d982 6 *
kpniot 0:a9259748d982 7 * (c) 2018 KPN
kpniot 0:a9259748d982 8 * License: MIT License.
kpniot 0:a9259748d982 9 * Author: Jan Bogaerts
kpniot 0:a9259748d982 10 *
kpniot 0:a9259748d982 11 * felper functions
kpniot 0:a9259748d982 12 */
kpniot 0:a9259748d982 13
kpniot 0:a9259748d982 14 #include <senml_helpers.h>
kpniot 0:a9259748d982 15
kpniot 0:a9259748d982 16 #ifdef ESP32
kpniot 0:a9259748d982 17 #include <base64.h>
kpniot 0:a9259748d982 18 #include <arduino.h> //needed for sprintf
kpniot 0:a9259748d982 19 #elif __MBED__
kpniot 0:a9259748d982 20 #include <base64.h>
kpniot 0:a9259748d982 21 int base64_enc_len(int plainLen) {
kpniot 0:a9259748d982 22 int n = plainLen;
kpniot 0:a9259748d982 23 return (n + 2 - ((n + 2) % 3)) / 3 * 4;
kpniot 0:a9259748d982 24 }
kpniot 0:a9259748d982 25 #else
kpniot 0:a9259748d982 26 #include <Base64.h>
kpniot 0:a9259748d982 27 #endif
kpniot 0:a9259748d982 28
kpniot 0:a9259748d982 29
kpniot 0:a9259748d982 30
kpniot 0:a9259748d982 31 //global reference to the stream and stream configuration. This should save us memory
kpniot 0:a9259748d982 32 //by not having to pass these values continuously on the stack.
kpniot 0:a9259748d982 33 StreamContext* _streamCtx = NULL;
kpniot 0:a9259748d982 34
kpniot 0:a9259748d982 35 void printDouble(double f, unsigned int digits)
kpniot 0:a9259748d982 36 {
kpniot 0:a9259748d982 37 #ifdef __MBED__
kpniot 0:a9259748d982 38 char s[30];
kpniot 0:a9259748d982 39 sprintf(s, "%f", f);
kpniot 0:a9259748d982 40 printText(s, strlen(s));
kpniot 0:a9259748d982 41 #else
kpniot 0:a9259748d982 42 String temp(f, digits);
kpniot 0:a9259748d982 43 const char* s = temp.c_str();
kpniot 0:a9259748d982 44 int length = temp.length();
kpniot 0:a9259748d982 45
kpniot 0:a9259748d982 46 for(int i = length -1; i >0; i--){ //remove unwanted trailing 0
kpniot 0:a9259748d982 47 if(s[i] != '0'){
kpniot 0:a9259748d982 48 length = i;
kpniot 0:a9259748d982 49 if(s[i] == '.') //if we end on something like x. then add a last 0, so that it becomes x.0
kpniot 0:a9259748d982 50 length++;
kpniot 0:a9259748d982 51 break;
kpniot 0:a9259748d982 52 }
kpniot 0:a9259748d982 53 }
kpniot 0:a9259748d982 54 printText(s, length + 1);
kpniot 0:a9259748d982 55 #endif
kpniot 0:a9259748d982 56 }
kpniot 0:a9259748d982 57
kpniot 0:a9259748d982 58
kpniot 0:a9259748d982 59
kpniot 0:a9259748d982 60 void printBinaryAsBase64(const unsigned char* data, unsigned int length)
kpniot 0:a9259748d982 61 {
kpniot 0:a9259748d982 62 #ifdef ESP32
kpniot 0:a9259748d982 63 String encoded = base64::encode((uint8_t*)data, length);
kpniot 0:a9259748d982 64 printText(encoded.c_str(), encoded.length());
kpniot 0:a9259748d982 65 #else
kpniot 0:a9259748d982 66 int encodedLen = base64_enc_len(length);
kpniot 0:a9259748d982 67 char encoded[encodedLen];
kpniot 0:a9259748d982 68
kpniot 0:a9259748d982 69 #ifdef __MBED__
kpniot 0:a9259748d982 70 // todo: check result of function
kpniot 0:a9259748d982 71 size_t olen;
kpniot 0:a9259748d982 72 mbedtls_base64_encode((unsigned char*)encoded, encodedLen, &olen, data, length);
kpniot 0:a9259748d982 73 #else
kpniot 0:a9259748d982 74 // note input is consumed in this step: it will be empty afterwards
kpniot 0:a9259748d982 75 base64_encode(encoded, (char*)data, length);
kpniot 0:a9259748d982 76 #endif
kpniot 0:a9259748d982 77 printText(encoded, encodedLen);
kpniot 0:a9259748d982 78 #endif
kpniot 0:a9259748d982 79 }
kpniot 0:a9259748d982 80
kpniot 0:a9259748d982 81 void printUnit(SenMLUnit unit)
kpniot 0:a9259748d982 82 {
kpniot 0:a9259748d982 83 if(unit != SENML_UNIT_NONE)
kpniot 0:a9259748d982 84 printText(senml_units_names[unit], strlen(senml_units_names[unit]));
kpniot 0:a9259748d982 85 }
kpniot 0:a9259748d982 86
kpniot 0:a9259748d982 87 void printText(const char* value, int len)
kpniot 0:a9259748d982 88 {
kpniot 0:a9259748d982 89 char hexTable[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
kpniot 0:a9259748d982 90
kpniot 0:a9259748d982 91 if(_streamCtx->dataAsBlob){
kpniot 0:a9259748d982 92 if(_streamCtx->format == SENML_RAW){
kpniot 0:a9259748d982 93 for(int i = 0; i < len; i++){
kpniot 0:a9259748d982 94 if(_streamCtx->data.blob.curPos >= _streamCtx->data.blob.length) return; //if we reached the end of the buffer, stop rendering otherwise we overwrite some other mem which is not good.
kpniot 0:a9259748d982 95 _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++] = value[i];
kpniot 0:a9259748d982 96 }
kpniot 0:a9259748d982 97 }
kpniot 0:a9259748d982 98 else{
kpniot 0:a9259748d982 99 for(int i = 0; i < len; i++){
kpniot 0:a9259748d982 100 if(_streamCtx->data.blob.curPos >= _streamCtx->data.blob.length) return; //if we reached the end of the buffer, stop rendering otherwise we overwrite some other mem which is not good.
kpniot 0:a9259748d982 101 _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++] = hexTable[value[i] / 16];
kpniot 0:a9259748d982 102 _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++] = hexTable[value[i] % 16];
kpniot 0:a9259748d982 103 }
kpniot 0:a9259748d982 104 }
kpniot 0:a9259748d982 105 }
kpniot 0:a9259748d982 106 else{
kpniot 0:a9259748d982 107 if(_streamCtx->format == SENML_RAW){
kpniot 0:a9259748d982 108 #ifdef __MBED__
kpniot 0:a9259748d982 109 for(int i = 0; i < len; i++)
kpniot 0:a9259748d982 110 _streamCtx->data.stream->putc(value[i]);
kpniot 0:a9259748d982 111 #else
kpniot 0:a9259748d982 112 _streamCtx->data.stream->write(value, len);
kpniot 0:a9259748d982 113 #endif
kpniot 0:a9259748d982 114 }
kpniot 0:a9259748d982 115 else if (_streamCtx->format == SENML_HEX){
kpniot 0:a9259748d982 116 for(int i = 0; i< len; i++){
kpniot 0:a9259748d982 117 #ifdef __MBED__
kpniot 0:a9259748d982 118 _streamCtx->data.stream->putc(hexTable[value[i] / 16]);
kpniot 0:a9259748d982 119 _streamCtx->data.stream->putc(hexTable[value[i] % 16]);
kpniot 0:a9259748d982 120 #else
kpniot 0:a9259748d982 121 _streamCtx->data.stream->print(hexTable[value[i] / 16]);
kpniot 0:a9259748d982 122 _streamCtx->data.stream->print(hexTable[value[i] % 16]);
kpniot 0:a9259748d982 123 #endif
kpniot 0:a9259748d982 124 }
kpniot 0:a9259748d982 125 }
kpniot 0:a9259748d982 126 }
kpniot 0:a9259748d982 127 }
kpniot 0:a9259748d982 128
kpniot 0:a9259748d982 129 static bool peeked = false; //if we peek the stream in HEX format, we actually need to read 2 bytes, so the peek doesn't work, but we need to read the actual value.
kpniot 0:a9259748d982 130 static int peekVal = 0; //these values are removed by the compiler if no cbor is used.
kpniot 0:a9259748d982 131
kpniot 0:a9259748d982 132 int readChar(){
kpniot 0:a9259748d982 133 if(peeked == true){
kpniot 0:a9259748d982 134 peeked = false;
kpniot 0:a9259748d982 135 return peekVal;
kpniot 0:a9259748d982 136 }
kpniot 0:a9259748d982 137 int res;
kpniot 0:a9259748d982 138 if(_streamCtx->dataAsBlob){
kpniot 0:a9259748d982 139 if(_streamCtx->data.blob.curPos < _streamCtx->data.blob.length) //peekchar has to return -1 if there is no more data, so check for this.
kpniot 0:a9259748d982 140 res = _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++];
kpniot 0:a9259748d982 141 else
kpniot 0:a9259748d982 142 return -1;
kpniot 0:a9259748d982 143 if(_streamCtx->format == SENML_HEX){
kpniot 0:a9259748d982 144 int resB = _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++];
kpniot 0:a9259748d982 145 res = (res > '9')? (res &~ 0x20) - 'A' + 10: (res - '0');
kpniot 0:a9259748d982 146 resB = (resB > '9')? (resB &~ 0x20) - 'A' + 10: (resB - '0');
kpniot 0:a9259748d982 147 res = (res * 16) + resB;
kpniot 0:a9259748d982 148 }
kpniot 0:a9259748d982 149 }
kpniot 0:a9259748d982 150 else { //data is comming from the stream, this already returns -1 if there is no data.
kpniot 0:a9259748d982 151 if(_streamCtx->format == SENML_RAW){
kpniot 0:a9259748d982 152 #ifdef __MBED__
kpniot 0:a9259748d982 153 res = _streamCtx->data.stream->getc();
kpniot 0:a9259748d982 154 #else
kpniot 0:a9259748d982 155 res = _streamCtx->data.stream->available() ? _streamCtx->data.stream->read() : -1; //arduino stream, check if something is available, if not, we can't read anymore.
kpniot 0:a9259748d982 156 #endif
kpniot 0:a9259748d982 157 }
kpniot 0:a9259748d982 158 else{
kpniot 0:a9259748d982 159 int resB;
kpniot 0:a9259748d982 160 #ifdef __MBED__
kpniot 0:a9259748d982 161 res = _streamCtx->data.stream->getc();
kpniot 0:a9259748d982 162 resB = _streamCtx->data.stream->getc();
kpniot 0:a9259748d982 163 #else
kpniot 0:a9259748d982 164
kpniot 0:a9259748d982 165 if(_streamCtx->data.stream->available())
kpniot 0:a9259748d982 166 res = _streamCtx->data.stream->read();
kpniot 0:a9259748d982 167 else
kpniot 0:a9259748d982 168 return -1;
kpniot 0:a9259748d982 169 if(_streamCtx->data.stream->available())
kpniot 0:a9259748d982 170 resB = _streamCtx->data.stream->read();
kpniot 0:a9259748d982 171 else
kpniot 0:a9259748d982 172 return -1;
kpniot 0:a9259748d982 173 #endif
kpniot 0:a9259748d982 174 res = (res > '9')? (res &~ 0x20) - 'A' + 10: (res - '0');
kpniot 0:a9259748d982 175 resB = (resB > '9')? (resB &~ 0x20) - 'A' + 10: (resB - '0');
kpniot 0:a9259748d982 176 res = (res * 16) + resB;
kpniot 0:a9259748d982 177 }
kpniot 0:a9259748d982 178 }
kpniot 0:a9259748d982 179 return res;
kpniot 0:a9259748d982 180 };
kpniot 0:a9259748d982 181
kpniot 0:a9259748d982 182 int peekChar(){
kpniot 0:a9259748d982 183 if(peeked == true) //if already peeked, return the currently buffered value.
kpniot 0:a9259748d982 184 return peekVal;
kpniot 0:a9259748d982 185 peekVal = readChar();
kpniot 0:a9259748d982 186 if(peekVal != -1) //if no more data, don't try to buffer it, some new data might arrive later on
kpniot 0:a9259748d982 187 peeked = true;
kpniot 0:a9259748d982 188 return peekVal;
kpniot 0:a9259748d982 189 };
kpniot 0:a9259748d982 190
kpniot 0:a9259748d982 191 void flush(){
kpniot 0:a9259748d982 192 peeked = false;
kpniot 0:a9259748d982 193 }
kpniot 0:a9259748d982 194
kpniot 0:a9259748d982 195
kpniot 0:a9259748d982 196