KPN IoT / senml

Fork of kpn_senml by KPN IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers senml_helpers.cpp Source File

senml_helpers.cpp

00001 /*  _  __  ____    _   _ 
00002  * | |/ / |  _ \  | \ | |
00003  * | ' /  | |_) | |  \| |
00004  * | . \  |  __/  | |\  |
00005  * |_|\_\ |_|     |_| \_|
00006  * 
00007  * (c) 2018 KPN
00008  * License: MIT License.
00009  * Author: Jan Bogaerts
00010  * 
00011  * felper functions
00012  */
00013 
00014 #include <senml_helpers.h>
00015 
00016 #ifdef ESP32
00017     #include <base64.h>
00018     #include <arduino.h>                        //needed for sprintf
00019 #elif __MBED__
00020     #include <base64.h>
00021     int base64_enc_len(int plainLen) {
00022         int n = plainLen;
00023         return (n + 2 - ((n + 2) % 3)) / 3 * 4;
00024     }
00025 #else
00026     #include <Base64.h>
00027 #endif
00028 
00029 
00030 
00031 //global reference to the stream and stream configuration. This should save us memory
00032 //by not having to pass these values continuously on the stack.
00033 StreamContext* _streamCtx = NULL;
00034 
00035 void printDouble(double f, unsigned int digits) 
00036 {
00037     #ifdef __MBED__
00038         char s[30];
00039         sprintf(s, "%f", f);
00040         printText(s, strlen(s));
00041     #else
00042         String temp(f, digits);
00043         const char* s = temp.c_str();
00044         int length = temp.length();
00045 
00046         for(int i = length -1; i >0; i--){                              //remove unwanted trailing 0
00047             if(s[i] != '0'){
00048                 length = i;
00049                 if(s[i] == '.')                                         //if we end on something like x.  then add a last 0, so that it becomes x.0
00050                     length++;
00051                 break;
00052             }
00053         }
00054         printText(s, length + 1);
00055     #endif
00056 } 
00057 
00058 
00059 
00060 void printBinaryAsBase64(const unsigned char* data, unsigned int length)
00061 {
00062     #ifdef ESP32
00063         String encoded = base64::encode((uint8_t*)data, length);
00064         printText(encoded.c_str(), encoded.length());
00065     #else
00066         int encodedLen = base64_enc_len(length);
00067         char encoded[encodedLen];
00068         
00069         #ifdef __MBED__
00070             // todo: check result of function
00071             size_t olen;
00072             mbedtls_base64_encode((unsigned char*)encoded, encodedLen, &olen, data, length);
00073         #else
00074             // note input is consumed in this step: it will be empty afterwards
00075             base64_encode(encoded, (char*)data, length); 
00076         #endif
00077         printText(encoded, encodedLen);
00078     #endif
00079 }
00080 
00081 void printUnit(SenMLUnit unit)
00082 {
00083     if(unit != SENML_UNIT_NONE)
00084         printText(senml_units_names[unit], strlen(senml_units_names[unit]));
00085 }
00086 
00087 void printText(const char* value, int len)
00088 {
00089     char hexTable[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00090 
00091     if(_streamCtx->dataAsBlob){
00092         if(_streamCtx->format == SENML_RAW){
00093             for(int i = 0; i < len; i++){
00094                 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.
00095                 _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++] = value[i];
00096             }
00097         }
00098         else{
00099             for(int i = 0; i < len; i++){
00100                 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.
00101                 _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++] = hexTable[value[i] / 16];
00102                 _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++] = hexTable[value[i] % 16];
00103             }
00104         }
00105     }
00106     else{
00107         if(_streamCtx->format == SENML_RAW){
00108             #ifdef __MBED__
00109                 for(int i = 0; i < len; i++)
00110                     _streamCtx->data.stream->putc(value[i]);
00111             #else
00112                 _streamCtx->data.stream->write(value, len);
00113             #endif
00114         }
00115         else if (_streamCtx->format == SENML_HEX){
00116             for(int i = 0; i< len; i++){
00117                 #ifdef __MBED__
00118                     _streamCtx->data.stream->putc(hexTable[value[i] / 16]);
00119                     _streamCtx->data.stream->putc(hexTable[value[i] % 16]);
00120                 #else
00121                     _streamCtx->data.stream->print(hexTable[value[i] / 16]);
00122                     _streamCtx->data.stream->print(hexTable[value[i] % 16]);
00123                 #endif
00124             }
00125         }
00126     }
00127 }
00128 
00129 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.
00130 static int peekVal = 0;                        //these values are removed by the compiler if no cbor is used.
00131 
00132 int readChar(){
00133     if(peeked == true){
00134         peeked = false;
00135         return peekVal;
00136     }
00137     int res;
00138     if(_streamCtx->dataAsBlob){
00139         if(_streamCtx->data.blob.curPos < _streamCtx->data.blob.length)         //peekchar has to return -1 if there is no more data, so check for this.
00140             res = _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++];
00141         else
00142             return -1;
00143         if(_streamCtx->format == SENML_HEX){
00144             int resB = _streamCtx->data.blob.data[_streamCtx->data.blob.curPos++];
00145             res = (res > '9')? (res &~ 0x20) - 'A' + 10: (res - '0');
00146             resB = (resB > '9')? (resB &~ 0x20) - 'A' + 10: (resB - '0');
00147             res = (res * 16) + resB;
00148         }
00149     } 
00150     else {                                                                      //data is comming from the stream, this already returns -1 if there is no data.
00151         if(_streamCtx->format == SENML_RAW){
00152             #ifdef __MBED__
00153                 res = _streamCtx->data.stream->getc();
00154             #else
00155                 res = _streamCtx->data.stream->available() ? _streamCtx->data.stream->read() : -1;                          //arduino stream, check if something is available, if not, we can't read anymore.
00156             #endif
00157         }
00158         else{
00159             int resB;
00160             #ifdef __MBED__
00161                 res = _streamCtx->data.stream->getc();
00162                 resB = _streamCtx->data.stream->getc();
00163             #else
00164               
00165                 if(_streamCtx->data.stream->available())
00166                     res = _streamCtx->data.stream->read();
00167                 else
00168                     return -1;
00169                 if(_streamCtx->data.stream->available())
00170                     resB = _streamCtx->data.stream->read();
00171                 else
00172                     return -1;
00173             #endif
00174             res = (res > '9')? (res &~ 0x20) - 'A' + 10: (res - '0');
00175             resB = (resB > '9')? (resB &~ 0x20) - 'A' + 10: (resB - '0');
00176             res = (res * 16) + resB;
00177         }
00178     }
00179     return res;
00180 };
00181 
00182 int peekChar(){
00183     if(peeked == true)                                                              //if already peeked, return the currently buffered value.
00184         return peekVal;
00185     peekVal = readChar();
00186     if(peekVal != -1)                                                               //if no more data, don't try to buffer it, some new data might arrive later on
00187         peeked = true;
00188     return peekVal;
00189 };
00190 
00191 void flush(){
00192     peeked = false;
00193 }
00194 
00195 
00196