ARM mbed M2X API Client: The ARM mbed client library is used to send/receive data to/from AT&T's M2X service from mbed LPC1768 microcontrollers.

Dependents:   m2x-demo-all M2X_MTS_ACCEL_DEMO M2X_MTS_Accel M2X_K64F_ACCEL ... more

Committer:
NetArc
Date:
Sun Sep 07 05:28:55 2014 +0000
Revision:
2:7ea7ab05f120
Parent:
0:f479e4f4db0e
Child:
3:2b527486e864
fix for parsing numeric stream values

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jb8414 0:f479e4f4db0e 1 #ifndef M2XStreamClient_h
jb8414 0:f479e4f4db0e 2 #define M2XStreamClient_h
jb8414 0:f479e4f4db0e 3
jb8414 0:f479e4f4db0e 4 #define MIN(a, b) (((a) > (b))?(b):(a))
jb8414 0:f479e4f4db0e 5
NetArc 2:7ea7ab05f120 6 #define DEBUG
jb8414 0:f479e4f4db0e 7 #define MBED_PLATFORM
jb8414 0:f479e4f4db0e 8
jb8414 0:f479e4f4db0e 9 #ifdef ARDUINO_PLATFORM
jb8414 0:f479e4f4db0e 10 #include "Arduino.h"
jb8414 0:f479e4f4db0e 11
jb8414 0:f479e4f4db0e 12 #define USER_AGENT "User-Agent: M2X Arduino Client/0.1"
jb8414 0:f479e4f4db0e 13 #endif
jb8414 0:f479e4f4db0e 14
jb8414 0:f479e4f4db0e 15 #ifdef MBED_PLATFORM
jb8414 0:f479e4f4db0e 16 #include "mbed.h"
jb8414 0:f479e4f4db0e 17
jb8414 0:f479e4f4db0e 18 #define USER_AGENT "User-Agent: M2X Mbed Client/0.1"
jb8414 0:f479e4f4db0e 19 #endif
jb8414 0:f479e4f4db0e 20
jb8414 0:f479e4f4db0e 21 #include "Client.h"
jb8414 0:f479e4f4db0e 22 #include "NullPrint.h"
jb8414 0:f479e4f4db0e 23
jb8414 0:f479e4f4db0e 24 #ifdef DEBUG
jb8414 0:f479e4f4db0e 25 #ifdef ARDUINO_PLATFORM
jb8414 0:f479e4f4db0e 26 #define DBG(fmt_, data_) Serial.print(data_)
jb8414 0:f479e4f4db0e 27 #define DBGLN(fmt_, data_) Serial.println(data_)
jb8414 0:f479e4f4db0e 28 #define DBGLNEND Serial.println()
jb8414 0:f479e4f4db0e 29 #endif // ARDUINO_PLATFORM
jb8414 0:f479e4f4db0e 30
jb8414 0:f479e4f4db0e 31 #ifdef MBED_PLATFORM
jb8414 0:f479e4f4db0e 32 #define DBG(fmt_, data_) printf((fmt_), (data_))
jb8414 0:f479e4f4db0e 33 #define DBGLN(fmt_, data_) printf((fmt_), (data_)); printf("\n")
jb8414 0:f479e4f4db0e 34 #define DBGLNEND printf("\n")
jb8414 0:f479e4f4db0e 35 #endif // MBED_PLATFORM
jb8414 0:f479e4f4db0e 36 #else
jb8414 0:f479e4f4db0e 37 #define DBG(fmt_, data_)
jb8414 0:f479e4f4db0e 38 #define DBGLN(fmt_, data_)
jb8414 0:f479e4f4db0e 39 #define DBGLNEND
jb8414 0:f479e4f4db0e 40 #endif // DEBUG
jb8414 0:f479e4f4db0e 41
jb8414 0:f479e4f4db0e 42 #define HEX(t_) ((char) (((t_) > 9) ? ((t_) - 10 + 'A') : ((t_) + '0')))
jb8414 0:f479e4f4db0e 43 #define MAX_DOUBLE_DIGITS 7
jb8414 0:f479e4f4db0e 44
jb8414 0:f479e4f4db0e 45 static const int E_OK = 0;
jb8414 0:f479e4f4db0e 46 static const int E_NOCONNECTION = -1;
jb8414 0:f479e4f4db0e 47 static const int E_DISCONNECTED = -2;
jb8414 0:f479e4f4db0e 48 static const int E_NOTREACHABLE = -3;
jb8414 0:f479e4f4db0e 49 static const int E_INVALID = -4;
jb8414 0:f479e4f4db0e 50 static const int E_JSON_INVALID = -5;
jb8414 0:f479e4f4db0e 51
jb8414 0:f479e4f4db0e 52 typedef void (*stream_value_read_callback)(const char* at,
jb8414 0:f479e4f4db0e 53 const char* value,
jb8414 0:f479e4f4db0e 54 int index,
jb8414 0:f479e4f4db0e 55 void* context);
jb8414 0:f479e4f4db0e 56
jb8414 0:f479e4f4db0e 57 typedef void (*location_read_callback)(const char* name,
jb8414 0:f479e4f4db0e 58 double latitude,
jb8414 0:f479e4f4db0e 59 double longitude,
jb8414 0:f479e4f4db0e 60 double elevation,
jb8414 0:f479e4f4db0e 61 const char* timestamp,
jb8414 0:f479e4f4db0e 62 int index,
jb8414 0:f479e4f4db0e 63 void* context);
jb8414 0:f479e4f4db0e 64
jb8414 0:f479e4f4db0e 65 class M2XStreamClient {
jb8414 0:f479e4f4db0e 66 public:
jb8414 0:f479e4f4db0e 67 static const char* kDefaultM2XHost;
jb8414 0:f479e4f4db0e 68 static const int kDefaultM2XPort = 80;
jb8414 0:f479e4f4db0e 69
jb8414 0:f479e4f4db0e 70 M2XStreamClient(Client* client,
jb8414 0:f479e4f4db0e 71 const char* key,
jb8414 0:f479e4f4db0e 72 int case_insensitive = 1,
jb8414 0:f479e4f4db0e 73 const char* host = kDefaultM2XHost,
jb8414 0:f479e4f4db0e 74 int port = kDefaultM2XPort);
jb8414 0:f479e4f4db0e 75
jb8414 0:f479e4f4db0e 76 // Post data stream value, returns the HTTP status code
jb8414 0:f479e4f4db0e 77 template <class T>
jb8414 0:f479e4f4db0e 78 int post(const char* feedId, const char* streamName, T value);
jb8414 0:f479e4f4db0e 79
jb8414 0:f479e4f4db0e 80 // Post multiple values to M2X all at once.
jb8414 0:f479e4f4db0e 81 // +feedId+ - id of the feed to post values
jb8414 0:f479e4f4db0e 82 // +streamNum+ - Number of streams to post
jb8414 0:f479e4f4db0e 83 // +names+ - Array of stream names, the length of the array should
jb8414 0:f479e4f4db0e 84 // be exactly +streamNum+
jb8414 0:f479e4f4db0e 85 // +counts+ - Array of +streamNum+ length, each item in this array
jb8414 0:f479e4f4db0e 86 // containing the number of values we want to post for each stream
jb8414 0:f479e4f4db0e 87 // +ats+ - Timestamps for each value, the length of this array should
jb8414 0:f479e4f4db0e 88 // be the some of all values in +counts+, for the first +counts[0]+
jb8414 0:f479e4f4db0e 89 // items, the values belong to the first stream, for the following
jb8414 0:f479e4f4db0e 90 // +counts[1]+ number of items, the values belong to the second stream,
jb8414 0:f479e4f4db0e 91 // etc. Note timestamps are optional, if a value does not havee timestamp,
jb8414 0:f479e4f4db0e 92 // we can simply put NULL here, or we can put NULl for +ats+, meaning
jb8414 0:f479e4f4db0e 93 // none of the values has a timestamp
jb8414 0:f479e4f4db0e 94 // +values+ - Values to post. This works the same way as +ats+, the
jb8414 0:f479e4f4db0e 95 // first +counts[0]+ number of items contain values to post to the first
jb8414 0:f479e4f4db0e 96 // stream, the succeeding +counts[1]+ number of items contain values
jb8414 0:f479e4f4db0e 97 // for the second stream, etc. The length of this array should be
jb8414 0:f479e4f4db0e 98 // the sum of all values in +counts+ array.
jb8414 0:f479e4f4db0e 99 template <class T>
jb8414 0:f479e4f4db0e 100 int postMultiple(const char* feedId, int streamNum,
jb8414 0:f479e4f4db0e 101 const char* names[], const int counts[],
jb8414 0:f479e4f4db0e 102 const char* ats[], T values[]);
jb8414 0:f479e4f4db0e 103
jb8414 0:f479e4f4db0e 104 // Fetch values for a particular data stream. Since memory is
jb8414 0:f479e4f4db0e 105 // very limited on an Arduino, we cannot parse and get all the
jb8414 0:f479e4f4db0e 106 // data points in memory. Instead, we use callbacks here: whenever
jb8414 0:f479e4f4db0e 107 // a new data point is parsed, we call the callback using the values,
jb8414 0:f479e4f4db0e 108 // after that, the values will be thrown away to make space for new
jb8414 0:f479e4f4db0e 109 // values.
jb8414 0:f479e4f4db0e 110 // Note that you can also pass in a user-specified context in this
jb8414 0:f479e4f4db0e 111 // function, this context will be passed to the callback function
jb8414 0:f479e4f4db0e 112 // each time we get a data point.
jb8414 0:f479e4f4db0e 113 // For each data point, the callback will be called once. The HTTP
jb8414 0:f479e4f4db0e 114 // status code will be returned. And the content is only parsed when
jb8414 0:f479e4f4db0e 115 // the status code is 200.
jb8414 0:f479e4f4db0e 116 int fetchValues(const char* feedId, const char* streamName,
jb8414 0:f479e4f4db0e 117 stream_value_read_callback callback, void* context,
jb8414 0:f479e4f4db0e 118 const char* startTime = NULL, const char* endTime = NULL,
jb8414 0:f479e4f4db0e 119 const char* limit = NULL);
jb8414 0:f479e4f4db0e 120
jb8414 0:f479e4f4db0e 121 // Update datasource location
jb8414 0:f479e4f4db0e 122 // NOTE: On an Arduino Uno and other ATMEGA based boards, double has
jb8414 0:f479e4f4db0e 123 // 4-byte (32 bits) precision, which is the same as float. So there's
jb8414 0:f479e4f4db0e 124 // no natural double-precision floating number on these boards. With
jb8414 0:f479e4f4db0e 125 // a float value, we have a precision of roughly 7 digits, that means
jb8414 0:f479e4f4db0e 126 // either 5 or 6 digits after the floating point. According to wikipedia,
jb8414 0:f479e4f4db0e 127 // a difference of 0.00001 will give us ~1.1132m distance. If this
jb8414 0:f479e4f4db0e 128 // precision is good for you, you can use the double-version we provided
jb8414 0:f479e4f4db0e 129 // here. Otherwise, you may need to use the string-version and do the
jb8414 0:f479e4f4db0e 130 // actual conversion by yourselves.
jb8414 0:f479e4f4db0e 131 // However, with an Arduino Due board, double has 8-bytes (64 bits)
jb8414 0:f479e4f4db0e 132 // precision, which means you are free to use the double-version only
jb8414 0:f479e4f4db0e 133 // without any precision problems.
jb8414 0:f479e4f4db0e 134 // Returned value is the http status code.
jb8414 0:f479e4f4db0e 135 template <class T>
jb8414 0:f479e4f4db0e 136 int updateLocation(const char* feedId, const char* name,
jb8414 0:f479e4f4db0e 137 T latitude, T longitude, T elevation);
jb8414 0:f479e4f4db0e 138
jb8414 0:f479e4f4db0e 139 // Read location information for a feed. Also used callback to process
jb8414 0:f479e4f4db0e 140 // data points for memory reasons. The HTTP status code is returned,
jb8414 0:f479e4f4db0e 141 // response is only parsed when the HTTP status code is 200
jb8414 0:f479e4f4db0e 142 int readLocation(const char* feedId, location_read_callback callback,
jb8414 0:f479e4f4db0e 143 void* context);
jb8414 0:f479e4f4db0e 144 private:
jb8414 0:f479e4f4db0e 145 Client* _client;
jb8414 0:f479e4f4db0e 146 const char* _key;
jb8414 0:f479e4f4db0e 147 int _case_insensitive;
jb8414 0:f479e4f4db0e 148 const char* _host;
jb8414 0:f479e4f4db0e 149 int _port;
jb8414 0:f479e4f4db0e 150 NullPrint _null_print;
jb8414 0:f479e4f4db0e 151
jb8414 0:f479e4f4db0e 152 // Writes the HTTP header part for updating a stream value
jb8414 0:f479e4f4db0e 153 void writePostHeader(const char* feedId,
jb8414 0:f479e4f4db0e 154 const char* streamName,
jb8414 0:f479e4f4db0e 155 int contentLength);
jb8414 0:f479e4f4db0e 156 // Writes HTTP header lines including M2X API Key, host, content
jb8414 0:f479e4f4db0e 157 // type and content length(if the body exists)
jb8414 0:f479e4f4db0e 158 void writeHttpHeader(int contentLength);
jb8414 0:f479e4f4db0e 159 // Parses HTTP response header and return the content length.
jb8414 0:f479e4f4db0e 160 // Note that this function does not parse all http headers, as long
jb8414 0:f479e4f4db0e 161 // as the content length is found, this function will return
jb8414 0:f479e4f4db0e 162 int readContentLength();
jb8414 0:f479e4f4db0e 163 // Skips all HTTP response header part. Return minus value in case
jb8414 0:f479e4f4db0e 164 // the connection is closed before we got all headers
jb8414 0:f479e4f4db0e 165 int skipHttpHeader();
jb8414 0:f479e4f4db0e 166 // Parses and returns the HTTP status code, note this function will
jb8414 0:f479e4f4db0e 167 // return immediately once it gets the status code
jb8414 0:f479e4f4db0e 168 int readStatusCode(bool closeClient);
jb8414 0:f479e4f4db0e 169 // Waits for a certain string pattern in the HTTP header, and returns
jb8414 0:f479e4f4db0e 170 // once the pattern is found. In the pattern, you can use '*' to denote
jb8414 0:f479e4f4db0e 171 // any character
jb8414 0:f479e4f4db0e 172 int waitForString(const char* str);
jb8414 0:f479e4f4db0e 173 // Closes the connection
jb8414 0:f479e4f4db0e 174 void close();
jb8414 0:f479e4f4db0e 175 // Parses JSON response of stream value API, and calls callback function
jb8414 0:f479e4f4db0e 176 // once we get a data point
jb8414 0:f479e4f4db0e 177 int readStreamValue(stream_value_read_callback callback, void* context);
jb8414 0:f479e4f4db0e 178 // Parses JSON response of location API, and calls callback function once
jb8414 0:f479e4f4db0e 179 // we get a data point
jb8414 0:f479e4f4db0e 180 int readLocation(location_read_callback callback, void* context);
jb8414 0:f479e4f4db0e 181 };
jb8414 0:f479e4f4db0e 182
jb8414 0:f479e4f4db0e 183 #include "M2XStreamClient_template.h"
jb8414 0:f479e4f4db0e 184
jb8414 0:f479e4f4db0e 185 #endif /* M2XStreamClient_h */