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 * parse cbor
kpniot 0:a9259748d982 12 */
kpniot 0:a9259748d982 13
kpniot 0:a9259748d982 14
kpniot 0:a9259748d982 15 #include <senml_cbor_parser.h>
kpniot 0:a9259748d982 16 #include <senml_helpers.h>
kpniot 0:a9259748d982 17 #include <senml_binary_actuator.h>
kpniot 0:a9259748d982 18
kpniot 0:a9259748d982 19 void SenMLCborParser::parse(Stream* source)
kpniot 0:a9259748d982 20 {
kpniot 0:a9259748d982 21 this->ctx.data.stream = source;
kpniot 0:a9259748d982 22 this->ctx.dataAsBlob = false;
kpniot 0:a9259748d982 23 this->internalParse();
kpniot 0:a9259748d982 24 }
kpniot 0:a9259748d982 25
kpniot 0:a9259748d982 26
kpniot 0:a9259748d982 27 void SenMLCborParser::parse(char* source, int length)
kpniot 0:a9259748d982 28 {
kpniot 0:a9259748d982 29 this->ctx.data.blob.data = source;
kpniot 0:a9259748d982 30 this->ctx.data.blob.curPos = 0;
kpniot 0:a9259748d982 31 this->ctx.data.blob.length = length;
kpniot 0:a9259748d982 32 this->ctx.dataAsBlob = true;
kpniot 0:a9259748d982 33 this->internalParse();
kpniot 0:a9259748d982 34 }
kpniot 0:a9259748d982 35
kpniot 0:a9259748d982 36 void SenMLCborParser::internalParse()
kpniot 0:a9259748d982 37 {
kpniot 0:a9259748d982 38 unsigned int read_bytes = this->processArray(); //the root element of senml input is always an array. We do this cause the readable() function on mbed doesn't work as expected, so we can't read until there is no more data, we need to read until we have valid input.
kpniot 0:a9259748d982 39
kpniot 0:a9259748d982 40 if (read_bytes == 0) {
kpniot 0:a9259748d982 41 log_debug("invalid input");
kpniot 0:a9259748d982 42 }
kpniot 0:a9259748d982 43 flush(); //make certain that the input streams are empty when done. This also resets any internally stored data. If we don't do this, we can only handle 1 bad input stream, ten it breaks.
kpniot 0:a9259748d982 44 }
kpniot 0:a9259748d982 45
kpniot 0:a9259748d982 46
kpniot 0:a9259748d982 47 void SenMLCborParser::processDouble(double value){
kpniot 0:a9259748d982 48 switch (this->curLabel)
kpniot 0:a9259748d982 49 {
kpniot 0:a9259748d982 50 //case SENML_CBOR_S_LABEL:
kpniot 0:a9259748d982 51 case SENML_CBOR_BV_LABEL: this->ctx.baseValue.baseDouble = value; break;
kpniot 0:a9259748d982 52 case SENML_CBOR_V_LABEL:
kpniot 0:a9259748d982 53 double calculated = this->ctx.baseValue.baseDouble + value;
kpniot 0:a9259748d982 54 this->setValue(&calculated, sizeof(double), CBOR_TYPE_DOUBLE);
kpniot 0:a9259748d982 55 break;
kpniot 0:a9259748d982 56 }
kpniot 0:a9259748d982 57 }
kpniot 0:a9259748d982 58
kpniot 0:a9259748d982 59 unsigned int SenMLCborParser::parseNext()
kpniot 0:a9259748d982 60 {
kpniot 0:a9259748d982 61 switch (CBOR_TYPE) {
kpniot 0:a9259748d982 62 case CBOR_UINT: return this->processUnsignedInt();
kpniot 0:a9259748d982 63 case CBOR_NEGINT: return this->processInt();
kpniot 0:a9259748d982 64 case CBOR_BYTES: return this->processBytes(CBOR_TYPE_DATA);
kpniot 0:a9259748d982 65 case CBOR_TEXT: return this->processBytes(CBOR_TYPE_STRING);
kpniot 0:a9259748d982 66 case CBOR_ARRAY: return this->processArray();
kpniot 0:a9259748d982 67 case CBOR_MAP: return this->processMap();
kpniot 0:a9259748d982 68 case CBOR_7: {
kpniot 0:a9259748d982 69 bool boolRes;
kpniot 0:a9259748d982 70 float floatVal;
kpniot 0:a9259748d982 71 double doubleVal;
kpniot 0:a9259748d982 72 size_t read_bytes;
kpniot 0:a9259748d982 73 switch ((int)peekChar()) {
kpniot 0:a9259748d982 74 case CBOR_FALSE:
kpniot 0:a9259748d982 75 readChar(); //need to remove the char from the stream.
kpniot 0:a9259748d982 76 boolRes = false;
kpniot 0:a9259748d982 77 this->setValue((void*)&boolRes, sizeof(boolRes), CBOR_TYPE_BOOL);
kpniot 0:a9259748d982 78 return 1;
kpniot 0:a9259748d982 79 case CBOR_TRUE:
kpniot 0:a9259748d982 80 readChar(); //need to remove the char from the stream.
kpniot 0:a9259748d982 81 boolRes = true;
kpniot 0:a9259748d982 82 this->setValue((void*)&boolRes, sizeof(boolRes), CBOR_TYPE_BOOL);
kpniot 0:a9259748d982 83 return 1;
kpniot 0:a9259748d982 84 case CBOR_FLOAT16:
kpniot 0:a9259748d982 85 read_bytes = cbor_deserialize_float_half(&floatVal);
kpniot 0:a9259748d982 86 this->processDouble(floatVal);
kpniot 0:a9259748d982 87 return read_bytes;
kpniot 0:a9259748d982 88 case CBOR_FLOAT32:
kpniot 0:a9259748d982 89 read_bytes = cbor_deserialize_float(&floatVal);
kpniot 0:a9259748d982 90 this->processDouble(floatVal);
kpniot 0:a9259748d982 91 return read_bytes;
kpniot 0:a9259748d982 92 case CBOR_FLOAT64:
kpniot 0:a9259748d982 93 read_bytes = cbor_deserialize_double(&doubleVal);
kpniot 0:a9259748d982 94 this->processDouble(doubleVal);
kpniot 0:a9259748d982 95 return read_bytes;
kpniot 0:a9259748d982 96 }
kpniot 0:a9259748d982 97 }
kpniot 0:a9259748d982 98 }
kpniot 0:a9259748d982 99 return 0; //if we get here, something went wrong
kpniot 0:a9259748d982 100 }
kpniot 0:a9259748d982 101
kpniot 0:a9259748d982 102 void SenMLCborParser::setValue(void* value, int length, SenMLDataType type)
kpniot 0:a9259748d982 103 {
kpniot 0:a9259748d982 104 if(this->curRec){
kpniot 0:a9259748d982 105 this->curRec->actuate(value, length, type);
kpniot 0:a9259748d982 106 }
kpniot 0:a9259748d982 107 else {
kpniot 0:a9259748d982 108 SenMLPack* pack = this->curPack;
kpniot 0:a9259748d982 109 if(!pack)
kpniot 0:a9259748d982 110 pack = this->root;
kpniot 0:a9259748d982 111 if(pack)
kpniot 0:a9259748d982 112 pack->actuate(this->curPackName.c_str(), this->curRecName.c_str(), value, length, type);
kpniot 0:a9259748d982 113 }
kpniot 0:a9259748d982 114 }
kpniot 0:a9259748d982 115
kpniot 0:a9259748d982 116 void SenMLCborParser::setBinaryValue(const char* value, int length)
kpniot 0:a9259748d982 117 {
kpniot 0:a9259748d982 118 if(this->curRec){
kpniot 0:a9259748d982 119 ((SenMLBinaryActuator*)this->curRec)->actuate(value, length);
kpniot 0:a9259748d982 120 }
kpniot 0:a9259748d982 121 else {
kpniot 0:a9259748d982 122 SenMLPack* pack = this->curPack;
kpniot 0:a9259748d982 123 if(!pack)
kpniot 0:a9259748d982 124 pack = this->root;
kpniot 0:a9259748d982 125 if(pack)
kpniot 0:a9259748d982 126 pack->actuate(this->curPackName.c_str(), this->curRecName.c_str(), value, length, CBOR_TYPE_DATA);
kpniot 0:a9259748d982 127 }
kpniot 0:a9259748d982 128 }
kpniot 0:a9259748d982 129
kpniot 0:a9259748d982 130
kpniot 0:a9259748d982 131 unsigned int SenMLCborParser::processBytes(SenMLDataType type)
kpniot 0:a9259748d982 132 {
kpniot 0:a9259748d982 133 uint64_t bytes_length; //needs to be this big for decode_int
kpniot 0:a9259748d982 134 size_t bytes_read = decode_int(&bytes_length);
kpniot 0:a9259748d982 135
kpniot 0:a9259748d982 136 if(bytes_read == 0) return 0;
kpniot 0:a9259748d982 137 char buffer[bytes_length + 1]; //need a null
kpniot 0:a9259748d982 138 for(int i = 0; i < (int)bytes_length; i++)
kpniot 0:a9259748d982 139 buffer[i] = readChar();
kpniot 0:a9259748d982 140 buffer[bytes_length] = 0; //close it, just to be save. not always needed, but it is for strings
kpniot 0:a9259748d982 141
kpniot 0:a9259748d982 142 if(type == CBOR_TYPE_DATA){ //we are expecting binary data, so it has to be for a binary data value.
kpniot 0:a9259748d982 143 if(this->curLabel == SENML_CBOR_VD_LABEL)
kpniot 0:a9259748d982 144 this->setBinaryValue(buffer, bytes_length);
kpniot 0:a9259748d982 145 else
kpniot 0:a9259748d982 146 log_debug("invalid input");
kpniot 0:a9259748d982 147 }else{ //its text
kpniot 0:a9259748d982 148 String value;
kpniot 0:a9259748d982 149 switch (this->curLabel)
kpniot 0:a9259748d982 150 {
kpniot 0:a9259748d982 151 case SENML_CBOR_BN_LABEL:
kpniot 0:a9259748d982 152 value = buffer;
kpniot 0:a9259748d982 153 this->setCurrentPack(value);
kpniot 0:a9259748d982 154 break;
kpniot 0:a9259748d982 155 case SENML_CBOR_BU_LABEL:
kpniot 0:a9259748d982 156 value = buffer;
kpniot 0:a9259748d982 157 this->checkBaseUnit(value);
kpniot 0:a9259748d982 158 break;
kpniot 0:a9259748d982 159 case SENML_CBOR_N_LABEL:
kpniot 0:a9259748d982 160 value = buffer;
kpniot 0:a9259748d982 161 this->setCurrentRecord(value);
kpniot 0:a9259748d982 162 break;
kpniot 0:a9259748d982 163 case SENML_CBOR_VS_LABEL:
kpniot 0:a9259748d982 164 this->setValue((void*)buffer, bytes_length, CBOR_TYPE_STRING);
kpniot 0:a9259748d982 165 break;
kpniot 0:a9259748d982 166 }
kpniot 0:a9259748d982 167 }
kpniot 0:a9259748d982 168 return bytes_read + bytes_length;
kpniot 0:a9259748d982 169 }
kpniot 0:a9259748d982 170
kpniot 0:a9259748d982 171 unsigned int SenMLCborParser::processArray()
kpniot 0:a9259748d982 172 {
kpniot 0:a9259748d982 173 const bool is_indefinite = (peekChar() == (CBOR_ARRAY | CBOR_VAR_FOLLOWS));
kpniot 0:a9259748d982 174 uint64_t array_length = 0;
kpniot 0:a9259748d982 175 size_t read_bytes;
kpniot 0:a9259748d982 176
kpniot 0:a9259748d982 177 if (is_indefinite){
kpniot 0:a9259748d982 178 log_debug("not supported");
kpniot 0:a9259748d982 179 }
kpniot 0:a9259748d982 180 else
kpniot 0:a9259748d982 181 read_bytes = decode_int(&array_length);
kpniot 0:a9259748d982 182
kpniot 0:a9259748d982 183 size_t i = 0;
kpniot 0:a9259748d982 184
kpniot 0:a9259748d982 185 while (i < array_length) {
kpniot 0:a9259748d982 186 size_t inner_read_bytes = this->parseNext();
kpniot 0:a9259748d982 187 if (inner_read_bytes == 0) {
kpniot 0:a9259748d982 188 log_debug("invalid input");
kpniot 0:a9259748d982 189 break;
kpniot 0:a9259748d982 190 }
kpniot 0:a9259748d982 191 read_bytes += inner_read_bytes;
kpniot 0:a9259748d982 192 ++i;
kpniot 0:a9259748d982 193 }
kpniot 0:a9259748d982 194
kpniot 0:a9259748d982 195 return read_bytes;
kpniot 0:a9259748d982 196 }
kpniot 0:a9259748d982 197
kpniot 0:a9259748d982 198
kpniot 0:a9259748d982 199
kpniot 0:a9259748d982 200
kpniot 0:a9259748d982 201
kpniot 0:a9259748d982 202
kpniot 0:a9259748d982 203