Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of kpn_senml by
senml_pack.cpp
00001 /* _ __ ____ _ _ 00002 * | |/ / | _ \ | \ | | 00003 * | ' / | |_) | | \| | 00004 * | . \ | __/ | |\ | 00005 * |_|\_\ |_| |_| \_| 00006 * 00007 * (c) 2018 KPN 00008 * License: MIT License. 00009 * Author: Jan Bogaerts 00010 * 00011 * pack (document) without base values 00012 */ 00013 00014 #include <senml_pack.h> 00015 #include <senml_base.h> 00016 #include <senml_helpers.h> 00017 #include <senml_json_parser.h> 00018 #include <senml_cbor_parser.h> 00019 #include <senml_JsonStreamingParser.h> 00020 #include <math.h> 00021 #include <cbor.h> 00022 #include <senml_logging.h> 00023 00024 00025 00026 //todo: inline these: 00027 void SenMLPack::setBaseName(const char* name) 00028 { 00029 this->_bn = name; 00030 } 00031 00032 const char* SenMLPack::getBaseName() 00033 { 00034 return this->_bn.c_str(); 00035 } 00036 00037 void SenMLPack::setBaseUnit(SenMLUnit unit) 00038 { 00039 this->_bu = unit; 00040 } 00041 00042 00043 void SenMLPack::setBaseTime(double time) 00044 { 00045 double prev = this->_bt; 00046 this->_bt = time; //set before asking children -> could be better to do it afterwards? 00047 SenMLBase *item = this->_start; 00048 while(item){ 00049 item->adjustToBaseTime(prev, time); 00050 item = item->getNext(); 00051 } 00052 } 00053 00054 00055 void SenMLPack::setLast(SenMLBase* value) 00056 { 00057 if(value == this) //if we become the last item in the list, then the list is empty. 00058 this->_end = NULL; 00059 else 00060 this->_end = value; 00061 } 00062 00063 00064 bool SenMLPack::add(SenMLBase* item) 00065 { 00066 if(item->getNext() != NULL){ 00067 log_debug("already in list"); 00068 return false; 00069 } 00070 00071 SenMLBase* last = this->_end; 00072 if(last){ 00073 last->setNext(item); 00074 item->setPrev(last); 00075 } 00076 else{ 00077 this->_start = item; 00078 item->setPrev(this); 00079 } 00080 this->_end = item; 00081 return true; 00082 } 00083 00084 bool SenMLPack::clear() 00085 { 00086 SenMLBase *item = this->_start; 00087 while(item){ 00088 if(item->isPack()) //if it's a pack element, it also needs to clear out it's children. 00089 ((SenMLPack*)item)->clear(); 00090 item->setPrev(NULL); 00091 SenMLBase *next = item->getNext(); 00092 item->setNext(NULL); 00093 item = next; 00094 } 00095 this->setNext(NULL); 00096 this->setPrev(NULL); 00097 this->_end = NULL; 00098 this->_start = NULL; 00099 return true; 00100 } 00101 00102 void SenMLPack::fromJson(Stream *source, SenMLStreamMethod format) 00103 { 00104 JsonStreamingParser parser; 00105 SenMLJsonListener listener(this); 00106 00107 parser.setListener(&listener); 00108 char data; 00109 if(format == SENML_RAW) { 00110 #ifdef __MBED__ 00111 data = source->getc(); 00112 #else 00113 data = source->read(); 00114 #endif 00115 } 00116 else{ 00117 data = readHexChar(source); 00118 } 00119 00120 while(data != -1){ 00121 parser.parse(data); 00122 if(format == SENML_RAW){ 00123 #ifdef __MBED__ 00124 data = source->getc(); 00125 #else 00126 data = source->read(); 00127 #endif 00128 } 00129 else 00130 data = readHexChar(source); 00131 } 00132 // when we get here, all the data is stored in the document and callbacks have been called. 00133 } 00134 00135 void SenMLPack::fromJson(const char *source) 00136 { 00137 JsonStreamingParser parser; 00138 SenMLJsonListener listener(this); 00139 00140 parser.setListener(&listener); 00141 for(int i = 0; source[i] != 0; i++){ 00142 parser.parse(source[i]); 00143 } 00144 // when we get here, all the data is stored in the document and callbacks have been called. 00145 } 00146 00147 void SenMLPack::fromCbor(Stream* source, SenMLStreamMethod format) 00148 { 00149 SenMLCborParser parser(this, format); 00150 parser.parse(source); 00151 } 00152 00153 void SenMLPack::fromCbor(char* source, int length, SenMLStreamMethod format) 00154 { 00155 SenMLCborParser parser(this, format); 00156 parser.parse(source, length); 00157 } 00158 00159 00160 void SenMLPack::toJson(Stream *dest, SenMLStreamMethod format) 00161 { 00162 StreamContext renderTo; //set up the global record that configures the rendering. This saves us some bytes on the stack and in code by not having to pass along the values as function arguments. 00163 _streamCtx = &renderTo; 00164 this->setupStreamCtx(dest, format); 00165 this->internalToJson(); 00166 } 00167 00168 void SenMLPack::toJson(char *dest, int length, SenMLStreamMethod format) 00169 { 00170 StreamContext renderTo; //set up the global record that configures the rendering. This saves us some bytes on the stack and in code by not having to pass along the values as function arguments. 00171 _streamCtx = &renderTo; 00172 this->setupStreamCtx(dest, length, format); 00173 this->internalToJson(); 00174 } 00175 00176 //render the content of the current object to json data (string) 00177 void SenMLPack::internalToJson() 00178 { 00179 printText("[", 1); 00180 this->contentToJson(); 00181 printText("]", 1); 00182 } 00183 00184 00185 void SenMLPack::fieldsToJson() 00186 { 00187 int bnLength = this->_bn.length(); 00188 if(bnLength > 0){ 00189 printText("\"bn\":\"", 6); 00190 printText(this->_bn.c_str(), bnLength); 00191 printText("\"", 1); 00192 } 00193 if(this->_bu){ 00194 printText(",\"bu\":\"", 7); 00195 printUnit(this->_bu); 00196 printText("\"", 1); 00197 } 00198 if(!isnan(this->_bt)){ 00199 printText(",\"bt\":", 6); 00200 printDouble(this->_bt, SENML_MAX_DOUBLE_PRECISION); 00201 } 00202 } 00203 00204 void SenMLPack::contentToJson() 00205 { 00206 printText("{", 1); 00207 this->fieldsToJson(); 00208 SenMLBase *next = this->_start; 00209 if(next && next->isPack() == false){ //we can only inline the first record. If the first item is a Pack (child device), then don't inline it. 00210 printText(",", 1); 00211 next->fieldsToJson(); 00212 next = next->getNext(); 00213 } 00214 printText("}", 1); 00215 while(next){ 00216 printText(",", 1); 00217 next->contentToJson(); 00218 next = next->getNext(); 00219 } 00220 } 00221 00222 00223 00224 void SenMLPack::setupStreamCtx(char *dest, int length, SenMLStreamMethod format) 00225 { 00226 _streamCtx->data.blob.data = dest; 00227 _streamCtx->data.blob.length = length; 00228 _streamCtx->data.blob.curPos = 0; 00229 _streamCtx->dataAsBlob = true; 00230 _streamCtx->format = format; 00231 _streamCtx->baseValue.baseUint = 0; //by default, there is no base value or sum 00232 _streamCtx->baseSum.baseUint = 0; 00233 _streamCtx->baseDataType = CBOR_TYPE_DATA; //data never adjusts for basevalue, so this is safe. 00234 } 00235 00236 void SenMLPack::setupStreamCtx(Stream *dest, SenMLStreamMethod format) 00237 { 00238 _streamCtx->data.stream = dest; 00239 _streamCtx->format = format; 00240 _streamCtx->dataAsBlob = false; 00241 _streamCtx->baseValue.baseUint = 0; //by default, there is no base value or sum 00242 _streamCtx->baseSum.baseUint = 0; 00243 _streamCtx->baseDataType = CBOR_TYPE_DATA; //data never adjusts for basevalue, so this is safe. 00244 } 00245 00246 int SenMLPack::toCbor(Stream *dest, SenMLStreamMethod format) 00247 { 00248 StreamContext renderTo; //set up the global record that configures the rendering. This saves us some bytes on the stack and in code by not having to pass along the values as function arguments. 00249 _streamCtx = &renderTo; 00250 this->setupStreamCtx(dest, format); 00251 int res = cbor_serialize_array(this->getArrayLength()); 00252 res += this->contentToCbor(); 00253 return res; 00254 } 00255 00256 int SenMLPack::toCbor(char *dest, int length, SenMLStreamMethod format) 00257 { 00258 StreamContext renderTo; //set up the global record that configures the rendering. This saves us some bytes on the stack and in code by not having to pass along the values as function arguments. 00259 _streamCtx = &renderTo; 00260 this->setupStreamCtx(dest, length, format); 00261 int res = cbor_serialize_array(this->getArrayLength()); 00262 res += this->contentToCbor(); 00263 return res; 00264 } 00265 00266 int SenMLPack::contentToCbor() 00267 { 00268 int length = cbor_serialize_map(this->getFieldLength()); 00269 00270 int res = this->fieldsToCbor(); 00271 SenMLBase *next = this->_start; 00272 if(next && next->isPack() == false){ //we can only inline the first record. If the first item is a Pack (child device), then don't inline it. 00273 res += next->fieldsToCbor(); 00274 next = next->getNext(); 00275 } 00276 00277 while(next){ 00278 if(next->isPack() == false) 00279 res += next->contentToCbor(); 00280 else 00281 res += ((SenMLPack*)next)->contentToCbor(); 00282 next = next->getNext(); 00283 } 00284 return res; 00285 } 00286 00287 int SenMLPack::getArrayLength() 00288 { 00289 int result = 0; //init to 0 cause if there is a record, the first will become part of the first element in the array, if we were to init to 1, we would have 1 record too many. 00290 SenMLBase *next = this->_start; 00291 while(next){ //we can only inline the first record. If the first item is a Pack (child device), then don't inline it. 00292 result += next->getArrayLength(); //custom record implementations may wrap multiple records. 00293 next = next->getNext(); 00294 } 00295 if(result == 0) //if there are no items in this pack, then we still render 1 array element, that of the pack itself. 00296 result = 1; 00297 return result; 00298 } 00299 00300 00301 int SenMLPack::getFieldLength() 00302 { 00303 int result = 0; 00304 if(this->_bn.length() > 0 ) result++; 00305 if(this->_bu) result++; 00306 if(!isnan(this->_bt)) result++; 00307 00308 SenMLBase *next = this->_start; 00309 if(next && next->isPack() == false){ //we can only inline the first record. If the first item is a Pack (child device), then don't inline it. 00310 result += next->getFieldLength(); 00311 next = next->getNext(); 00312 } 00313 return result; 00314 } 00315 00316 int SenMLPack::fieldsToCbor() 00317 { 00318 int res = 0 ; 00319 if(this->_bn.length() > 0 ){ 00320 res += cbor_serialize_int(SENML_CBOR_BN_LABEL); 00321 res += cbor_serialize_unicode_string(this->_bn.c_str()); 00322 } 00323 if(this->_bu){ 00324 res += cbor_serialize_int(SENML_CBOR_BU_LABEL); 00325 res += cbor_serialize_unicode_string(senml_units_names[this->_bu]); 00326 } 00327 if(!isnan(this->_bt)){ 00328 res += cbor_serialize_int(SENML_CBOR_BT_LABEL); 00329 res += cbor_serialize_double(this->_bt); 00330 } 00331 return res; 00332 } 00333 00334 00335 00336 00337 00338 00339
Generated on Tue Jul 12 2022 23:07:22 by
