test
Fork of mbed-libxively-6eca970 by
src/libxively/csv_data.c@0:82702e998d3f, 2013-06-26 (annotated)
- Committer:
- xively
- Date:
- Wed Jun 26 10:40:43 2013 +0000
- Revision:
- 0:82702e998d3f
libxively v0.1.1-rc0 (34c8b32)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
xively | 0:82702e998d3f | 1 | // Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved. |
xively | 0:82702e998d3f | 2 | // This is part of Xively C library, it is under the BSD 3-Clause license. |
xively | 0:82702e998d3f | 3 | |
xively | 0:82702e998d3f | 4 | /** |
xively | 0:82702e998d3f | 5 | * \file csv_data.c |
xively | 0:82702e998d3f | 6 | * \author Olgierd Humenczuk |
xively | 0:82702e998d3f | 7 | * \brief Implements CSV _data layer_ encoders and decoders specific to Xively CSV data format [see csv_data.h] |
xively | 0:82702e998d3f | 8 | */ |
xively | 0:82702e998d3f | 9 | |
xively | 0:82702e998d3f | 10 | #include <assert.h> |
xively | 0:82702e998d3f | 11 | #include <stdio.h> |
xively | 0:82702e998d3f | 12 | #include <time.h> |
xively | 0:82702e998d3f | 13 | |
xively | 0:82702e998d3f | 14 | #include "csv_data.h" |
xively | 0:82702e998d3f | 15 | #include "xi_macros.h" |
xively | 0:82702e998d3f | 16 | #include "xi_helpers.h" |
xively | 0:82702e998d3f | 17 | #include "xi_err.h" |
xively | 0:82702e998d3f | 18 | #include "xi_consts.h" |
xively | 0:82702e998d3f | 19 | |
xively | 0:82702e998d3f | 20 | static char XI_CSV_LOCAL_BUFFER[ XI_CSV_BUFFER_SIZE ]; |
xively | 0:82702e998d3f | 21 | |
xively | 0:82702e998d3f | 22 | inline static int csv_encode_value( |
xively | 0:82702e998d3f | 23 | char* buffer |
xively | 0:82702e998d3f | 24 | , size_t buffer_size |
xively | 0:82702e998d3f | 25 | , const xi_datapoint_t* p ) |
xively | 0:82702e998d3f | 26 | { |
xively | 0:82702e998d3f | 27 | // PRECONDITION |
xively | 0:82702e998d3f | 28 | assert( buffer != 0 ); |
xively | 0:82702e998d3f | 29 | assert( buffer_size != 0 ); |
xively | 0:82702e998d3f | 30 | assert( p != 0 ); |
xively | 0:82702e998d3f | 31 | |
xively | 0:82702e998d3f | 32 | switch( p->value_type ) |
xively | 0:82702e998d3f | 33 | { |
xively | 0:82702e998d3f | 34 | case XI_VALUE_TYPE_I32: |
xively | 0:82702e998d3f | 35 | return snprintf( buffer, buffer_size, "%d", p->value.i32_value ); |
xively | 0:82702e998d3f | 36 | case XI_VALUE_TYPE_F32: |
xively | 0:82702e998d3f | 37 | return snprintf( buffer, buffer_size, "%f", p->value.f32_value ); |
xively | 0:82702e998d3f | 38 | case XI_VALUE_TYPE_STR: |
xively | 0:82702e998d3f | 39 | return snprintf( buffer, buffer_size, "%s", p->value.str_value ); |
xively | 0:82702e998d3f | 40 | default: |
xively | 0:82702e998d3f | 41 | return -1; |
xively | 0:82702e998d3f | 42 | } |
xively | 0:82702e998d3f | 43 | } |
xively | 0:82702e998d3f | 44 | |
xively | 0:82702e998d3f | 45 | typedef enum |
xively | 0:82702e998d3f | 46 | { |
xively | 0:82702e998d3f | 47 | XI_CHAR_UNKNOWN = 0, |
xively | 0:82702e998d3f | 48 | XI_CHAR_NUMBER, |
xively | 0:82702e998d3f | 49 | XI_CHAR_LETTER, |
xively | 0:82702e998d3f | 50 | XI_CHAR_DOT, |
xively | 0:82702e998d3f | 51 | XI_CHAR_SPACE, |
xively | 0:82702e998d3f | 52 | XI_CHAR_NEWLINE, |
xively | 0:82702e998d3f | 53 | XI_CHAR_TAB, |
xively | 0:82702e998d3f | 54 | XI_CHAR_MINUS |
xively | 0:82702e998d3f | 55 | } xi_char_type_t; |
xively | 0:82702e998d3f | 56 | |
xively | 0:82702e998d3f | 57 | inline static xi_char_type_t csv_classify_char( char c ) |
xively | 0:82702e998d3f | 58 | { |
xively | 0:82702e998d3f | 59 | switch( c ) |
xively | 0:82702e998d3f | 60 | { |
xively | 0:82702e998d3f | 61 | case 13: |
xively | 0:82702e998d3f | 62 | case 11: |
xively | 0:82702e998d3f | 63 | return XI_CHAR_NEWLINE; |
xively | 0:82702e998d3f | 64 | case 9: |
xively | 0:82702e998d3f | 65 | return XI_CHAR_TAB; |
xively | 0:82702e998d3f | 66 | case 32: |
xively | 0:82702e998d3f | 67 | return XI_CHAR_SPACE; |
xively | 0:82702e998d3f | 68 | case 33: case 34: case 35: case 36: case 37: case 38: case 39: |
xively | 0:82702e998d3f | 69 | case 40: case 41: case 42: case 43: case 44: |
xively | 0:82702e998d3f | 70 | return XI_CHAR_UNKNOWN; |
xively | 0:82702e998d3f | 71 | case 45: |
xively | 0:82702e998d3f | 72 | return XI_CHAR_MINUS; |
xively | 0:82702e998d3f | 73 | case 46: |
xively | 0:82702e998d3f | 74 | return XI_CHAR_DOT; |
xively | 0:82702e998d3f | 75 | case 47: |
xively | 0:82702e998d3f | 76 | return XI_CHAR_UNKNOWN; |
xively | 0:82702e998d3f | 77 | case 48: case 49: case 50: case 51: case 52: case 53: case 54: |
xively | 0:82702e998d3f | 78 | case 55: case 56: |
xively | 0:82702e998d3f | 79 | case 57: |
xively | 0:82702e998d3f | 80 | return XI_CHAR_NUMBER; |
xively | 0:82702e998d3f | 81 | case 58: case 59: case 60: case 61: case 62: case 63: |
xively | 0:82702e998d3f | 82 | case 64: |
xively | 0:82702e998d3f | 83 | return XI_CHAR_UNKNOWN; |
xively | 0:82702e998d3f | 84 | case 65: case 66: case 67: case 68: case 69: case 70: case 71: |
xively | 0:82702e998d3f | 85 | case 72: case 73: case 74: case 75: case 76: case 77: case 78: |
xively | 0:82702e998d3f | 86 | case 79: case 80: case 81: case 82: case 83: case 84: case 85: |
xively | 0:82702e998d3f | 87 | case 86: case 87: case 88: case 89: |
xively | 0:82702e998d3f | 88 | case 90: |
xively | 0:82702e998d3f | 89 | return XI_CHAR_LETTER; |
xively | 0:82702e998d3f | 90 | case 91: case 92: case 93: case 94: case 95: |
xively | 0:82702e998d3f | 91 | case 96: |
xively | 0:82702e998d3f | 92 | return XI_CHAR_UNKNOWN; |
xively | 0:82702e998d3f | 93 | case 97: case 98: case 99: case 100: case 101: case 102: case 103: |
xively | 0:82702e998d3f | 94 | case 104: case 105: case 106: case 107: case 108: case 109: case 110: |
xively | 0:82702e998d3f | 95 | case 111: case 112: case 113: case 114: case 115: case 116: case 117: |
xively | 0:82702e998d3f | 96 | case 118: case 119: case 120: case 121: |
xively | 0:82702e998d3f | 97 | case 122: |
xively | 0:82702e998d3f | 98 | return XI_CHAR_LETTER; |
xively | 0:82702e998d3f | 99 | case 123: |
xively | 0:82702e998d3f | 100 | case 124: |
xively | 0:82702e998d3f | 101 | case 125: |
xively | 0:82702e998d3f | 102 | return XI_CHAR_UNKNOWN; |
xively | 0:82702e998d3f | 103 | default: |
xively | 0:82702e998d3f | 104 | return XI_CHAR_UNKNOWN; |
xively | 0:82702e998d3f | 105 | } |
xively | 0:82702e998d3f | 106 | } |
xively | 0:82702e998d3f | 107 | |
xively | 0:82702e998d3f | 108 | typedef enum |
xively | 0:82702e998d3f | 109 | { |
xively | 0:82702e998d3f | 110 | XI_STATE_INITIAL = 0, |
xively | 0:82702e998d3f | 111 | XI_STATE_MINUS, |
xively | 0:82702e998d3f | 112 | XI_STATE_NUMBER, |
xively | 0:82702e998d3f | 113 | XI_STATE_FLOAT, |
xively | 0:82702e998d3f | 114 | XI_STATE_DOT, |
xively | 0:82702e998d3f | 115 | XI_STATE_STRING |
xively | 0:82702e998d3f | 116 | } xi_dfa_state_t; |
xively | 0:82702e998d3f | 117 | |
xively | 0:82702e998d3f | 118 | xi_datapoint_t* csv_decode_value( |
xively | 0:82702e998d3f | 119 | const char* buffer, xi_datapoint_t* p ) |
xively | 0:82702e998d3f | 120 | { |
xively | 0:82702e998d3f | 121 | // PRECONDITION |
xively | 0:82702e998d3f | 122 | assert( buffer != 0 ); |
xively | 0:82702e998d3f | 123 | assert( p != 0 ); |
xively | 0:82702e998d3f | 124 | |
xively | 0:82702e998d3f | 125 | // secure the output buffer |
xively | 0:82702e998d3f | 126 | XI_GUARD_EOS( p->value.str_value, XI_VALUE_STRING_MAX_SIZE ); |
xively | 0:82702e998d3f | 127 | |
xively | 0:82702e998d3f | 128 | // clean the counter |
xively | 0:82702e998d3f | 129 | size_t counter = 0; |
xively | 0:82702e998d3f | 130 | |
xively | 0:82702e998d3f | 131 | // the transition function |
xively | 0:82702e998d3f | 132 | static const short states[][6][2] = |
xively | 0:82702e998d3f | 133 | { |
xively | 0:82702e998d3f | 134 | // state initial // state minus // state number // state float // state dot // string |
xively | 0:82702e998d3f | 135 | { { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING } }, |
xively | 0:82702e998d3f | 136 | { { XI_CHAR_NUMBER , XI_STATE_NUMBER }, { XI_CHAR_NUMBER , XI_STATE_NUMBER }, { XI_CHAR_NUMBER , XI_STATE_NUMBER }, { XI_CHAR_NUMBER , XI_STATE_FLOAT }, { XI_CHAR_NUMBER , XI_STATE_FLOAT }, { XI_CHAR_NUMBER , XI_STATE_STRING } }, |
xively | 0:82702e998d3f | 137 | { { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING } }, |
xively | 0:82702e998d3f | 138 | { { XI_CHAR_DOT , XI_STATE_DOT }, { XI_CHAR_DOT , XI_STATE_DOT }, { XI_CHAR_DOT , XI_STATE_DOT }, { XI_CHAR_DOT , XI_STATE_STRING }, { XI_CHAR_DOT , XI_STATE_STRING }, { XI_CHAR_DOT , XI_STATE_STRING } }, |
xively | 0:82702e998d3f | 139 | { { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING } }, |
xively | 0:82702e998d3f | 140 | { { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL } }, |
xively | 0:82702e998d3f | 141 | { { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING } }, |
xively | 0:82702e998d3f | 142 | { { XI_CHAR_MINUS , XI_STATE_MINUS }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING } } |
xively | 0:82702e998d3f | 143 | }; |
xively | 0:82702e998d3f | 144 | |
xively | 0:82702e998d3f | 145 | char c = *buffer; |
xively | 0:82702e998d3f | 146 | short s = XI_STATE_INITIAL; |
xively | 0:82702e998d3f | 147 | |
xively | 0:82702e998d3f | 148 | while( c != '\n' && c !='\0' && c!='\r' ) |
xively | 0:82702e998d3f | 149 | { |
xively | 0:82702e998d3f | 150 | if( counter >= XI_VALUE_STRING_MAX_SIZE - 1 ) |
xively | 0:82702e998d3f | 151 | { |
xively | 0:82702e998d3f | 152 | xi_set_err( XI_DATAPOINT_VALUE_BUFFER_OVERFLOW ); |
xively | 0:82702e998d3f | 153 | return 0; |
xively | 0:82702e998d3f | 154 | } |
xively | 0:82702e998d3f | 155 | |
xively | 0:82702e998d3f | 156 | xi_char_type_t ct = csv_classify_char( c ); |
xively | 0:82702e998d3f | 157 | s = states[ ct ][ s ][ 1 ]; |
xively | 0:82702e998d3f | 158 | |
xively | 0:82702e998d3f | 159 | switch( s ) |
xively | 0:82702e998d3f | 160 | { |
xively | 0:82702e998d3f | 161 | case XI_STATE_MINUS: |
xively | 0:82702e998d3f | 162 | case XI_STATE_NUMBER: |
xively | 0:82702e998d3f | 163 | case XI_STATE_FLOAT: |
xively | 0:82702e998d3f | 164 | case XI_STATE_DOT: |
xively | 0:82702e998d3f | 165 | case XI_STATE_STRING: |
xively | 0:82702e998d3f | 166 | p->value.str_value[ counter ] = c; |
xively | 0:82702e998d3f | 167 | break; |
xively | 0:82702e998d3f | 168 | } |
xively | 0:82702e998d3f | 169 | |
xively | 0:82702e998d3f | 170 | c = *( ++buffer ); |
xively | 0:82702e998d3f | 171 | ++counter; |
xively | 0:82702e998d3f | 172 | } |
xively | 0:82702e998d3f | 173 | |
xively | 0:82702e998d3f | 174 | // set the guard |
xively | 0:82702e998d3f | 175 | p->value.str_value[ counter ] = '\0'; |
xively | 0:82702e998d3f | 176 | |
xively | 0:82702e998d3f | 177 | // update of the state for loose states... |
xively | 0:82702e998d3f | 178 | switch( s ) |
xively | 0:82702e998d3f | 179 | { |
xively | 0:82702e998d3f | 180 | case XI_STATE_MINUS: |
xively | 0:82702e998d3f | 181 | case XI_STATE_DOT: |
xively | 0:82702e998d3f | 182 | case XI_STATE_INITIAL: |
xively | 0:82702e998d3f | 183 | s = XI_STATE_STRING; |
xively | 0:82702e998d3f | 184 | break; |
xively | 0:82702e998d3f | 185 | } |
xively | 0:82702e998d3f | 186 | |
xively | 0:82702e998d3f | 187 | switch( s ) |
xively | 0:82702e998d3f | 188 | { |
xively | 0:82702e998d3f | 189 | case XI_STATE_NUMBER: |
xively | 0:82702e998d3f | 190 | p->value.i32_value = atoi( p->value.str_value ); |
xively | 0:82702e998d3f | 191 | p->value_type = XI_VALUE_TYPE_I32; |
xively | 0:82702e998d3f | 192 | break; |
xively | 0:82702e998d3f | 193 | case XI_STATE_FLOAT: |
xively | 0:82702e998d3f | 194 | p->value.f32_value = atof( p->value.str_value ); |
xively | 0:82702e998d3f | 195 | p->value_type = XI_VALUE_TYPE_F32; |
xively | 0:82702e998d3f | 196 | break; |
xively | 0:82702e998d3f | 197 | case XI_STATE_STRING: |
xively | 0:82702e998d3f | 198 | default: |
xively | 0:82702e998d3f | 199 | p->value_type = XI_VALUE_TYPE_STR; |
xively | 0:82702e998d3f | 200 | } |
xively | 0:82702e998d3f | 201 | |
xively | 0:82702e998d3f | 202 | return p; |
xively | 0:82702e998d3f | 203 | } |
xively | 0:82702e998d3f | 204 | |
xively | 0:82702e998d3f | 205 | const char* csv_encode_datapoint( const xi_datapoint_t* data ) |
xively | 0:82702e998d3f | 206 | { |
xively | 0:82702e998d3f | 207 | |
xively | 0:82702e998d3f | 208 | // PRECONDITIONS |
xively | 0:82702e998d3f | 209 | assert( data != 0 ); |
xively | 0:82702e998d3f | 210 | |
xively | 0:82702e998d3f | 211 | return csv_encode_datapoint_in_place( XI_CSV_LOCAL_BUFFER, sizeof( XI_CSV_LOCAL_BUFFER ), data ) == -1 ? 0 : XI_CSV_LOCAL_BUFFER; |
xively | 0:82702e998d3f | 212 | } |
xively | 0:82702e998d3f | 213 | |
xively | 0:82702e998d3f | 214 | int csv_encode_datapoint_in_place( |
xively | 0:82702e998d3f | 215 | char* in, size_t in_size |
xively | 0:82702e998d3f | 216 | , const xi_datapoint_t* datapoint ) |
xively | 0:82702e998d3f | 217 | { |
xively | 0:82702e998d3f | 218 | // PRECONDITIONS |
xively | 0:82702e998d3f | 219 | assert( in != 0 ); |
xively | 0:82702e998d3f | 220 | assert( datapoint != 0 ); |
xively | 0:82702e998d3f | 221 | |
xively | 0:82702e998d3f | 222 | int s = 0; |
xively | 0:82702e998d3f | 223 | int size = in_size; |
xively | 0:82702e998d3f | 224 | int offset = 0; |
xively | 0:82702e998d3f | 225 | |
xively | 0:82702e998d3f | 226 | if( datapoint->timestamp.timestamp != 0 ) |
xively | 0:82702e998d3f | 227 | { |
xively | 0:82702e998d3f | 228 | time_t stamp = datapoint->timestamp.timestamp; |
xively | 0:82702e998d3f | 229 | struct tm* gmtinfo = xi_gmtime( &stamp ); |
xively | 0:82702e998d3f | 230 | |
xively | 0:82702e998d3f | 231 | s = snprintf( in, size |
xively | 0:82702e998d3f | 232 | , "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ," |
xively | 0:82702e998d3f | 233 | , gmtinfo->tm_year + 1900 |
xively | 0:82702e998d3f | 234 | , gmtinfo->tm_mon + 1 |
xively | 0:82702e998d3f | 235 | , gmtinfo->tm_mday |
xively | 0:82702e998d3f | 236 | , gmtinfo->tm_hour |
xively | 0:82702e998d3f | 237 | , gmtinfo->tm_min |
xively | 0:82702e998d3f | 238 | , gmtinfo->tm_sec |
xively | 0:82702e998d3f | 239 | , ( int ) datapoint->timestamp.micro ); |
xively | 0:82702e998d3f | 240 | |
xively | 0:82702e998d3f | 241 | XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN ); |
xively | 0:82702e998d3f | 242 | } |
xively | 0:82702e998d3f | 243 | |
xively | 0:82702e998d3f | 244 | s = csv_encode_value( in + offset, size - offset, datapoint ); |
xively | 0:82702e998d3f | 245 | XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN ); |
xively | 0:82702e998d3f | 246 | |
xively | 0:82702e998d3f | 247 | s = snprintf( in + offset, size - offset, "%s", "\n" ); |
xively | 0:82702e998d3f | 248 | XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN ); |
xively | 0:82702e998d3f | 249 | |
xively | 0:82702e998d3f | 250 | return offset; |
xively | 0:82702e998d3f | 251 | |
xively | 0:82702e998d3f | 252 | err_handling: |
xively | 0:82702e998d3f | 253 | return -1; |
xively | 0:82702e998d3f | 254 | } |
xively | 0:82702e998d3f | 255 | |
xively | 0:82702e998d3f | 256 | const char* csv_encode_create_datastream( |
xively | 0:82702e998d3f | 257 | const char* datastream_id |
xively | 0:82702e998d3f | 258 | , const xi_datapoint_t* data ) |
xively | 0:82702e998d3f | 259 | { |
xively | 0:82702e998d3f | 260 | // PRECONDITIONS |
xively | 0:82702e998d3f | 261 | assert( data != 0 ); |
xively | 0:82702e998d3f | 262 | |
xively | 0:82702e998d3f | 263 | int s = 0; |
xively | 0:82702e998d3f | 264 | int size = sizeof( XI_CSV_LOCAL_BUFFER ); |
xively | 0:82702e998d3f | 265 | int offset = 0; |
xively | 0:82702e998d3f | 266 | |
xively | 0:82702e998d3f | 267 | s = snprintf( XI_CSV_LOCAL_BUFFER + offset, size - offset |
xively | 0:82702e998d3f | 268 | , "%s,", datastream_id ); |
xively | 0:82702e998d3f | 269 | XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN ); |
xively | 0:82702e998d3f | 270 | |
xively | 0:82702e998d3f | 271 | s = csv_encode_value( XI_CSV_LOCAL_BUFFER + offset, size - offset, data ); |
xively | 0:82702e998d3f | 272 | XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN ); |
xively | 0:82702e998d3f | 273 | |
xively | 0:82702e998d3f | 274 | s = snprintf( XI_CSV_LOCAL_BUFFER + offset, size - offset, "\n" ); |
xively | 0:82702e998d3f | 275 | XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN ); |
xively | 0:82702e998d3f | 276 | |
xively | 0:82702e998d3f | 277 | return XI_CSV_LOCAL_BUFFER; |
xively | 0:82702e998d3f | 278 | |
xively | 0:82702e998d3f | 279 | err_handling: |
xively | 0:82702e998d3f | 280 | return 0; |
xively | 0:82702e998d3f | 281 | } |
xively | 0:82702e998d3f | 282 | |
xively | 0:82702e998d3f | 283 | xi_feed_t* csv_decode_feed( |
xively | 0:82702e998d3f | 284 | const char* buffer |
xively | 0:82702e998d3f | 285 | , xi_feed_t* feed ) |
xively | 0:82702e998d3f | 286 | { |
xively | 0:82702e998d3f | 287 | const char* current = buffer; |
xively | 0:82702e998d3f | 288 | int32_t counter = 0; |
xively | 0:82702e998d3f | 289 | |
xively | 0:82702e998d3f | 290 | // find occurence of newline |
xively | 0:82702e998d3f | 291 | char* end_of_line = ( char* ) 1; |
xively | 0:82702e998d3f | 292 | |
xively | 0:82702e998d3f | 293 | // while we didn't jump out of the buffer |
xively | 0:82702e998d3f | 294 | while( end_of_line ) |
xively | 0:82702e998d3f | 295 | { |
xively | 0:82702e998d3f | 296 | // get current datapoint |
xively | 0:82702e998d3f | 297 | xi_datastream_t* d = &feed->datastreams[ counter ]; |
xively | 0:82702e998d3f | 298 | d->datapoint_count = 0; |
xively | 0:82702e998d3f | 299 | xi_datapoint_t* p = &d->datapoints[ 0 ]; |
xively | 0:82702e998d3f | 300 | memset( p, 0, sizeof( xi_datapoint_t ) ); |
xively | 0:82702e998d3f | 301 | |
xively | 0:82702e998d3f | 302 | end_of_line = strstr( current, "\n" ); |
xively | 0:82702e998d3f | 303 | |
xively | 0:82702e998d3f | 304 | const char* end_of_datastream_id = strstr( current, "," ); |
xively | 0:82702e998d3f | 305 | const char* beg_of_datapoint = end_of_datastream_id + 1; |
xively | 0:82702e998d3f | 306 | |
xively | 0:82702e998d3f | 307 | XI_CHECK_ZERO( beg_of_datapoint, XI_CSV_DECODE_FEED_PARSER_ERROR ); |
xively | 0:82702e998d3f | 308 | XI_CHECK_ZERO( end_of_datastream_id, XI_CSV_DECODE_FEED_PARSER_ERROR ); |
xively | 0:82702e998d3f | 309 | |
xively | 0:82702e998d3f | 310 | int size = sizeof( d->datastream_id ); |
xively | 0:82702e998d3f | 311 | |
xively | 0:82702e998d3f | 312 | int s = xi_str_copy_untiln( d->datastream_id, size |
xively | 0:82702e998d3f | 313 | , current, ',' ); |
xively | 0:82702e998d3f | 314 | XI_CHECK_SIZE( s, size, XI_CSV_DECODE_FEED_PARSER_ERROR ); |
xively | 0:82702e998d3f | 315 | |
xively | 0:82702e998d3f | 316 | xi_datapoint_t* ret = csv_decode_datapoint( beg_of_datapoint, p ); |
xively | 0:82702e998d3f | 317 | XI_CHECK_ZERO( ret, XI_CSV_DECODE_FEED_PARSER_ERROR ) |
xively | 0:82702e998d3f | 318 | |
xively | 0:82702e998d3f | 319 | d->datapoint_count = 1; |
xively | 0:82702e998d3f | 320 | current = end_of_line + 1; |
xively | 0:82702e998d3f | 321 | |
xively | 0:82702e998d3f | 322 | XI_CHECK_CND( ++counter == XI_MAX_DATASTREAMS |
xively | 0:82702e998d3f | 323 | , XI_CSV_DECODE_FEED_PARSER_ERROR ); |
xively | 0:82702e998d3f | 324 | } |
xively | 0:82702e998d3f | 325 | |
xively | 0:82702e998d3f | 326 | feed->datastream_count = counter; |
xively | 0:82702e998d3f | 327 | return feed; |
xively | 0:82702e998d3f | 328 | |
xively | 0:82702e998d3f | 329 | err_handling: |
xively | 0:82702e998d3f | 330 | return 0; |
xively | 0:82702e998d3f | 331 | } |
xively | 0:82702e998d3f | 332 | |
xively | 0:82702e998d3f | 333 | xi_datapoint_t* csv_decode_datapoint( |
xively | 0:82702e998d3f | 334 | const char* buffer |
xively | 0:82702e998d3f | 335 | , xi_datapoint_t* datapoint ) |
xively | 0:82702e998d3f | 336 | { |
xively | 0:82702e998d3f | 337 | // PRECONDITIONS |
xively | 0:82702e998d3f | 338 | assert( buffer != 0 ); |
xively | 0:82702e998d3f | 339 | assert( datapoint != 0 ); |
xively | 0:82702e998d3f | 340 | |
xively | 0:82702e998d3f | 341 | int ye, mo, da, h, m, s, ms; |
xively | 0:82702e998d3f | 342 | |
xively | 0:82702e998d3f | 343 | const char* beg_of_value = strstr( buffer, "," ); |
xively | 0:82702e998d3f | 344 | |
xively | 0:82702e998d3f | 345 | // check continuation condition |
xively | 0:82702e998d3f | 346 | XI_CHECK_ZERO( beg_of_value, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR ); |
xively | 0:82702e998d3f | 347 | |
xively | 0:82702e998d3f | 348 | // move to pointer to the proper position |
xively | 0:82702e998d3f | 349 | beg_of_value += 1; |
xively | 0:82702e998d3f | 350 | |
xively | 0:82702e998d3f | 351 | { |
xively | 0:82702e998d3f | 352 | int n = sscanf( buffer |
xively | 0:82702e998d3f | 353 | , "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ" |
xively | 0:82702e998d3f | 354 | , &ye, &mo, &da, &h, &m, &s, &ms ); |
xively | 0:82702e998d3f | 355 | |
xively | 0:82702e998d3f | 356 | // check if the parser worked correctly |
xively | 0:82702e998d3f | 357 | XI_CHECK_CND( n != 7, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR ); |
xively | 0:82702e998d3f | 358 | |
xively | 0:82702e998d3f | 359 | // copy parsed data |
xively | 0:82702e998d3f | 360 | { |
xively | 0:82702e998d3f | 361 | struct tm timeinfo; |
xively | 0:82702e998d3f | 362 | |
xively | 0:82702e998d3f | 363 | timeinfo.tm_year = ye - 1900; |
xively | 0:82702e998d3f | 364 | timeinfo.tm_mon = mo - 1; |
xively | 0:82702e998d3f | 365 | timeinfo.tm_mday = da; |
xively | 0:82702e998d3f | 366 | timeinfo.tm_hour = h; |
xively | 0:82702e998d3f | 367 | timeinfo.tm_min = m; |
xively | 0:82702e998d3f | 368 | timeinfo.tm_sec = s; |
xively | 0:82702e998d3f | 369 | |
xively | 0:82702e998d3f | 370 | time_t timestamp = xi_mktime( &timeinfo ); |
xively | 0:82702e998d3f | 371 | |
xively | 0:82702e998d3f | 372 | XI_CHECK_CND( ( int )timestamp == -1, XI_CSV_TIME_CONVERTION_ERROR ); |
xively | 0:82702e998d3f | 373 | |
xively | 0:82702e998d3f | 374 | datapoint->timestamp.timestamp = timestamp; |
xively | 0:82702e998d3f | 375 | datapoint->timestamp.micro = ms; |
xively | 0:82702e998d3f | 376 | } |
xively | 0:82702e998d3f | 377 | } |
xively | 0:82702e998d3f | 378 | |
xively | 0:82702e998d3f | 379 | xi_datapoint_t* r = csv_decode_value( beg_of_value |
xively | 0:82702e998d3f | 380 | , datapoint ); |
xively | 0:82702e998d3f | 381 | |
xively | 0:82702e998d3f | 382 | |
xively | 0:82702e998d3f | 383 | XI_CHECK_ZERO( r, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR ); |
xively | 0:82702e998d3f | 384 | |
xively | 0:82702e998d3f | 385 | return datapoint; |
xively | 0:82702e998d3f | 386 | |
xively | 0:82702e998d3f | 387 | err_handling: |
xively | 0:82702e998d3f | 388 | return 0; |
xively | 0:82702e998d3f | 389 | } |