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:
citrusbyte
Date:
Mon Dec 28 12:48:19 2015 +0000
Revision:
16:7903152de19f
Parent:
14:205076b587fe
Child:
17:9db4a86b876a
Add TimeService implementation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jb8414 0:f479e4f4db0e 1 #include "M2XStreamClient.h"
jb8414 0:f479e4f4db0e 2
jb8414 0:f479e4f4db0e 3 #include <jsonlite.h>
jb8414 0:f479e4f4db0e 4
jb8414 0:f479e4f4db0e 5 #include "StreamParseFunctions.h"
jb8414 0:f479e4f4db0e 6 #include "LocationParseFunctions.h"
jb8414 0:f479e4f4db0e 7
jb8414 0:f479e4f4db0e 8 const char* M2XStreamClient::kDefaultM2XHost = "api-m2x.att.com";
jb8414 0:f479e4f4db0e 9
citrusbyte 10:4ce9eba38dbe 10 static int write_delete_values(Print* print, const char* from, const char* end);
jb8414 0:f479e4f4db0e 11 int print_encoded_string(Print* print, const char* str);
jb8414 0:f479e4f4db0e 12 int tolower(int ch);
jb8414 0:f479e4f4db0e 13
jb8414 0:f479e4f4db0e 14 #if defined(ARDUINO_PLATFORM) || defined(MBED_PLATFORM)
jb8414 0:f479e4f4db0e 15 int tolower(int ch)
jb8414 0:f479e4f4db0e 16 {
jb8414 0:f479e4f4db0e 17 // Arduino and mbed use ASCII table, so we can simplify the implementation
jb8414 0:f479e4f4db0e 18 if ((ch >= 'A') && (ch <= 'Z')) {
jb8414 0:f479e4f4db0e 19 return (ch + 32);
jb8414 0:f479e4f4db0e 20 }
jb8414 0:f479e4f4db0e 21 return ch;
jb8414 0:f479e4f4db0e 22 }
jb8414 0:f479e4f4db0e 23 #else
jb8414 0:f479e4f4db0e 24 // For other platform, we use libc's tolower by default
jb8414 0:f479e4f4db0e 25 #include <ctype.h>
jb8414 0:f479e4f4db0e 26 #endif
jb8414 0:f479e4f4db0e 27
jb8414 0:f479e4f4db0e 28 M2XStreamClient::M2XStreamClient(Client* client,
jb8414 0:f479e4f4db0e 29 const char* key,
jb8414 0:f479e4f4db0e 30 int case_insensitive,
jb8414 0:f479e4f4db0e 31 const char* host,
NetArc 14:205076b587fe 32 int port,
NetArc 14:205076b587fe 33 const char* path_prefix) : _client(client),
jb8414 0:f479e4f4db0e 34 _key(key),
jb8414 0:f479e4f4db0e 35 _case_insensitive(case_insensitive),
jb8414 0:f479e4f4db0e 36 _host(host),
jb8414 0:f479e4f4db0e 37 _port(port),
NetArc 14:205076b587fe 38 _path_prefix(path_prefix),
jb8414 0:f479e4f4db0e 39 _null_print() {
jb8414 0:f479e4f4db0e 40 }
jb8414 0:f479e4f4db0e 41
citrusbyte 13:0d574742208f 42 int M2XStreamClient::listStreamValues(const char* deviceId, const char* streamName,
citrusbyte 13:0d574742208f 43 stream_value_read_callback callback, void* context,
citrusbyte 13:0d574742208f 44 const char* query) {
jb8414 0:f479e4f4db0e 45 if (_client->connect(_host, _port)) {
jb8414 0:f479e4f4db0e 46 DBGLN("%s", "Connected to M2X server!");
NetArc 14:205076b587fe 47 _client->print("GET ");
NetArc 14:205076b587fe 48 if (_path_prefix)
NetArc 14:205076b587fe 49 _client->print(_path_prefix);
NetArc 14:205076b587fe 50 _client->print("/v2/devices/");
citrusbyte 13:0d574742208f 51 print_encoded_string(_client, deviceId);
jb8414 0:f479e4f4db0e 52 _client->print("/streams/");
jb8414 0:f479e4f4db0e 53 print_encoded_string(_client, streamName);
citrusbyte 13:0d574742208f 54 _client->print("/values.json");
jb8414 0:f479e4f4db0e 55
citrusbyte 13:0d574742208f 56 if (query) {
citrusbyte 13:0d574742208f 57 if (query[0] != '?') {
citrusbyte 13:0d574742208f 58 _client->print('?');
citrusbyte 13:0d574742208f 59 }
citrusbyte 13:0d574742208f 60 _client->print(query);
citrusbyte 13:0d574742208f 61 }
jb8414 0:f479e4f4db0e 62
jb8414 0:f479e4f4db0e 63 _client->println(" HTTP/1.0");
jb8414 0:f479e4f4db0e 64 writeHttpHeader(-1);
jb8414 0:f479e4f4db0e 65 } else {
jb8414 0:f479e4f4db0e 66 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
jb8414 0:f479e4f4db0e 67 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 68 }
jb8414 0:f479e4f4db0e 69 int status = readStatusCode(false);
jb8414 0:f479e4f4db0e 70 if (status == 200) {
jb8414 0:f479e4f4db0e 71 readStreamValue(callback, context);
jb8414 0:f479e4f4db0e 72 }
jb8414 0:f479e4f4db0e 73
jb8414 0:f479e4f4db0e 74 close();
jb8414 0:f479e4f4db0e 75 return status;
jb8414 0:f479e4f4db0e 76 }
jb8414 0:f479e4f4db0e 77
citrusbyte 13:0d574742208f 78 int M2XStreamClient::readLocation(const char* deviceId,
jb8414 0:f479e4f4db0e 79 location_read_callback callback,
jb8414 0:f479e4f4db0e 80 void* context) {
jb8414 0:f479e4f4db0e 81 if (_client->connect(_host, _port)) {
jb8414 0:f479e4f4db0e 82 DBGLN("%s", "Connected to M2X server!");
NetArc 14:205076b587fe 83 _client->print("GET ");
NetArc 14:205076b587fe 84 if (_path_prefix)
NetArc 14:205076b587fe 85 _client->print(_path_prefix);
NetArc 14:205076b587fe 86 _client->print("/v2/devices/");
citrusbyte 13:0d574742208f 87 print_encoded_string(_client, deviceId);
jb8414 0:f479e4f4db0e 88 _client->println("/location HTTP/1.0");
jb8414 0:f479e4f4db0e 89
jb8414 0:f479e4f4db0e 90 writeHttpHeader(-1);
jb8414 0:f479e4f4db0e 91 } else {
jb8414 0:f479e4f4db0e 92 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
jb8414 0:f479e4f4db0e 93 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 94 }
jb8414 0:f479e4f4db0e 95 int status = readStatusCode(false);
jb8414 0:f479e4f4db0e 96 if (status == 200) {
jb8414 0:f479e4f4db0e 97 readLocation(callback, context);
jb8414 0:f479e4f4db0e 98 }
jb8414 0:f479e4f4db0e 99
jb8414 0:f479e4f4db0e 100 close();
jb8414 0:f479e4f4db0e 101 return status;
jb8414 0:f479e4f4db0e 102 }
jb8414 0:f479e4f4db0e 103
citrusbyte 13:0d574742208f 104 int M2XStreamClient::deleteValues(const char* deviceId, const char* streamName,
citrusbyte 10:4ce9eba38dbe 105 const char* from, const char* end) {
citrusbyte 10:4ce9eba38dbe 106 if (_client->connect(_host, _port)) {
citrusbyte 10:4ce9eba38dbe 107 DBGLN("%s", "Connected to M2X server!");
citrusbyte 10:4ce9eba38dbe 108 int length = write_delete_values(&_null_print, from, end);
citrusbyte 13:0d574742208f 109 writeDeleteHeader(deviceId, streamName, length);
citrusbyte 10:4ce9eba38dbe 110 write_delete_values(_client, from, end);
citrusbyte 10:4ce9eba38dbe 111 } else {
citrusbyte 10:4ce9eba38dbe 112 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
citrusbyte 10:4ce9eba38dbe 113 return E_NOCONNECTION;
citrusbyte 10:4ce9eba38dbe 114 }
citrusbyte 10:4ce9eba38dbe 115
citrusbyte 10:4ce9eba38dbe 116 return readStatusCode(true);
citrusbyte 10:4ce9eba38dbe 117 }
citrusbyte 10:4ce9eba38dbe 118
citrusbyte 16:7903152de19f 119 int M2XStreamClient::getTimestamp32(int32_t *ts) {
citrusbyte 16:7903152de19f 120 // The maximum value of signed 64-bit integer is 0x7fffffffffffffff,
citrusbyte 16:7903152de19f 121 // which is 9223372036854775807. It consists of 19 characters, so a
citrusbyte 16:7903152de19f 122 // buffer of 20 is definitely enough here
citrusbyte 16:7903152de19f 123 int length = 20;
citrusbyte 16:7903152de19f 124 char buffer[20];
citrusbyte 16:7903152de19f 125 int status = getTimestamp(buffer, &length);
citrusbyte 16:7903152de19f 126 if (status == 200) {
citrusbyte 16:7903152de19f 127 int32_t result = 0;
citrusbyte 16:7903152de19f 128 for (int i = 0; i < length; i++) {
citrusbyte 16:7903152de19f 129 result = result * 10 + (buffer[i] - '0');
citrusbyte 16:7903152de19f 130 }
citrusbyte 16:7903152de19f 131 if (ts != NULL) { *ts = result; }
citrusbyte 16:7903152de19f 132 }
citrusbyte 16:7903152de19f 133 return status;
citrusbyte 16:7903152de19f 134 }
citrusbyte 16:7903152de19f 135
citrusbyte 16:7903152de19f 136 int M2XStreamClient::getTimestamp(char* buffer, int *bufferLength) {
citrusbyte 16:7903152de19f 137 if (bufferLength == NULL) { return E_INVALID; }
citrusbyte 16:7903152de19f 138 if (_client->connect(_host, _port)) {
citrusbyte 16:7903152de19f 139 DBGLN("%s", "Connected to M2X server!");
citrusbyte 16:7903152de19f 140 _client->println("GET /v2/time/seconds HTTP/1.0");
citrusbyte 16:7903152de19f 141
citrusbyte 16:7903152de19f 142 writeHttpHeader(-1);
citrusbyte 16:7903152de19f 143 } else {
citrusbyte 16:7903152de19f 144 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
citrusbyte 16:7903152de19f 145 return E_NOCONNECTION;
citrusbyte 16:7903152de19f 146 }
citrusbyte 16:7903152de19f 147 int status = readStatusCode(false);
citrusbyte 16:7903152de19f 148 if (status == 200) {
citrusbyte 16:7903152de19f 149 int length = readContentLength();
citrusbyte 16:7903152de19f 150 if (length < 0) {
citrusbyte 16:7903152de19f 151 close();
citrusbyte 16:7903152de19f 152 return length;
citrusbyte 16:7903152de19f 153 }
citrusbyte 16:7903152de19f 154 if (*bufferLength < length) {
citrusbyte 16:7903152de19f 155 *bufferLength = length;
citrusbyte 16:7903152de19f 156 return E_BUFFER_TOO_SMALL;
citrusbyte 16:7903152de19f 157 }
citrusbyte 16:7903152de19f 158 *bufferLength = length;
citrusbyte 16:7903152de19f 159 int index = skipHttpHeader();
citrusbyte 16:7903152de19f 160 if (index != E_OK) {
citrusbyte 16:7903152de19f 161 close();
citrusbyte 16:7903152de19f 162 return index;
citrusbyte 16:7903152de19f 163 }
citrusbyte 16:7903152de19f 164 index = 0;
citrusbyte 16:7903152de19f 165 while (index < length) {
citrusbyte 16:7903152de19f 166 DBG("%s", "Received Data: ");
citrusbyte 16:7903152de19f 167 while ((index < length) && _client->available()) {
citrusbyte 16:7903152de19f 168 buffer[index++] = _client->read();
citrusbyte 16:7903152de19f 169 DBG("%c", buffer[index - 1]);
citrusbyte 16:7903152de19f 170 }
citrusbyte 16:7903152de19f 171 DBGLNEND;
citrusbyte 16:7903152de19f 172
citrusbyte 16:7903152de19f 173 if ((!_client->connected()) &&
citrusbyte 16:7903152de19f 174 (index < length)) {
citrusbyte 16:7903152de19f 175 close();
citrusbyte 16:7903152de19f 176 return E_NOCONNECTION;
citrusbyte 16:7903152de19f 177 }
citrusbyte 16:7903152de19f 178
citrusbyte 16:7903152de19f 179 delay(200);
citrusbyte 16:7903152de19f 180 }
citrusbyte 16:7903152de19f 181 }
citrusbyte 16:7903152de19f 182 close();
citrusbyte 16:7903152de19f 183 return status;
citrusbyte 16:7903152de19f 184 }
citrusbyte 16:7903152de19f 185
citrusbyte 10:4ce9eba38dbe 186 static int write_delete_values(Print* print, const char* from,
citrusbyte 10:4ce9eba38dbe 187 const char* end) {
citrusbyte 10:4ce9eba38dbe 188 int bytes = 0;
citrusbyte 10:4ce9eba38dbe 189 bytes += print->print("{\"from\":\"");
citrusbyte 10:4ce9eba38dbe 190 bytes += print->print(from);
citrusbyte 10:4ce9eba38dbe 191 bytes += print->print("\",\"end\":\"");
citrusbyte 10:4ce9eba38dbe 192 bytes += print->print(end);
citrusbyte 10:4ce9eba38dbe 193 bytes += print->print("\"}");
citrusbyte 10:4ce9eba38dbe 194 return bytes;
citrusbyte 10:4ce9eba38dbe 195 }
citrusbyte 10:4ce9eba38dbe 196
jb8414 0:f479e4f4db0e 197 // Encodes and prints string using Percent-encoding specified
jb8414 0:f479e4f4db0e 198 // in RFC 1738, Section 2.2
jb8414 0:f479e4f4db0e 199 int print_encoded_string(Print* print, const char* str) {
jb8414 0:f479e4f4db0e 200 int bytes = 0;
jb8414 0:f479e4f4db0e 201 for (int i = 0; str[i] != 0; i++) {
jb8414 0:f479e4f4db0e 202 if (((str[i] >= 'A') && (str[i] <= 'Z')) ||
jb8414 0:f479e4f4db0e 203 ((str[i] >= 'a') && (str[i] <= 'z')) ||
jb8414 0:f479e4f4db0e 204 ((str[i] >= '0') && (str[i] <= '9')) ||
jb8414 0:f479e4f4db0e 205 (str[i] == '-') || (str[i] == '_') ||
jb8414 0:f479e4f4db0e 206 (str[i] == '.') || (str[i] == '~')) {
jb8414 0:f479e4f4db0e 207 bytes += print->print(str[i]);
jb8414 0:f479e4f4db0e 208 } else {
jb8414 0:f479e4f4db0e 209 // Encode all other characters
jb8414 0:f479e4f4db0e 210 bytes += print->print('%');
jb8414 0:f479e4f4db0e 211 bytes += print->print(HEX(str[i] / 16));
jb8414 0:f479e4f4db0e 212 bytes += print->print(HEX(str[i] % 16));
jb8414 0:f479e4f4db0e 213 }
jb8414 0:f479e4f4db0e 214 }
jb8414 0:f479e4f4db0e 215 return bytes;
jb8414 0:f479e4f4db0e 216 }
jb8414 0:f479e4f4db0e 217
citrusbyte 13:0d574742208f 218 void M2XStreamClient::writePutHeader(const char* deviceId,
citrusbyte 10:4ce9eba38dbe 219 const char* streamName,
citrusbyte 10:4ce9eba38dbe 220 int contentLength) {
NetArc 14:205076b587fe 221 _client->print("PUT ");
NetArc 14:205076b587fe 222 if (_path_prefix)
NetArc 14:205076b587fe 223 _client->print(_path_prefix);
NetArc 14:205076b587fe 224 _client->print("/v2/devices/");
citrusbyte 13:0d574742208f 225 print_encoded_string(_client, deviceId);
jb8414 0:f479e4f4db0e 226 _client->print("/streams/");
jb8414 0:f479e4f4db0e 227 print_encoded_string(_client, streamName);
citrusbyte 11:a11af0c81cfa 228 _client->println("/value HTTP/1.0");
jb8414 0:f479e4f4db0e 229
jb8414 0:f479e4f4db0e 230 writeHttpHeader(contentLength);
jb8414 0:f479e4f4db0e 231 }
jb8414 0:f479e4f4db0e 232
citrusbyte 13:0d574742208f 233 void M2XStreamClient::writeDeleteHeader(const char* deviceId,
citrusbyte 10:4ce9eba38dbe 234 const char* streamName,
citrusbyte 10:4ce9eba38dbe 235 int contentLength) {
NetArc 14:205076b587fe 236 _client->print("DELETE ");
NetArc 14:205076b587fe 237 if (_path_prefix)
NetArc 14:205076b587fe 238 _client->print(_path_prefix);
NetArc 14:205076b587fe 239 _client->print("/v2/devices/");
citrusbyte 13:0d574742208f 240 print_encoded_string(_client, deviceId);
citrusbyte 10:4ce9eba38dbe 241 _client->print("/streams/");
citrusbyte 10:4ce9eba38dbe 242 print_encoded_string(_client, streamName);
citrusbyte 10:4ce9eba38dbe 243 _client->print("/values");
citrusbyte 10:4ce9eba38dbe 244 _client->println(" HTTP/1.0");
citrusbyte 10:4ce9eba38dbe 245
citrusbyte 10:4ce9eba38dbe 246 writeHttpHeader(contentLength);
citrusbyte 10:4ce9eba38dbe 247 }
citrusbyte 10:4ce9eba38dbe 248
jb8414 0:f479e4f4db0e 249 void M2XStreamClient::writeHttpHeader(int contentLength) {
jb8414 0:f479e4f4db0e 250 _client->println(USER_AGENT);
jb8414 0:f479e4f4db0e 251 _client->print("X-M2X-KEY: ");
jb8414 0:f479e4f4db0e 252 _client->println(_key);
jb8414 0:f479e4f4db0e 253
jb8414 0:f479e4f4db0e 254 _client->print("Host: ");
jb8414 0:f479e4f4db0e 255 print_encoded_string(_client, _host);
jb8414 0:f479e4f4db0e 256 if (_port != kDefaultM2XPort) {
jb8414 0:f479e4f4db0e 257 _client->print(":");
jb8414 0:f479e4f4db0e 258 // port is an integer, does not need encoding
jb8414 0:f479e4f4db0e 259 _client->print(_port);
jb8414 0:f479e4f4db0e 260 }
jb8414 0:f479e4f4db0e 261 _client->println();
jb8414 0:f479e4f4db0e 262
jb8414 0:f479e4f4db0e 263 if (contentLength > 0) {
jb8414 0:f479e4f4db0e 264 _client->println("Content-Type: application/json");
jb8414 0:f479e4f4db0e 265 DBG("%s", "Content Length: ");
jb8414 0:f479e4f4db0e 266 DBGLN("%d", contentLength);
jb8414 0:f479e4f4db0e 267
jb8414 0:f479e4f4db0e 268 _client->print("Content-Length: ");
jb8414 0:f479e4f4db0e 269 _client->println(contentLength);
jb8414 0:f479e4f4db0e 270 }
jb8414 0:f479e4f4db0e 271 _client->println();
jb8414 0:f479e4f4db0e 272 }
jb8414 0:f479e4f4db0e 273
jb8414 0:f479e4f4db0e 274 int M2XStreamClient::waitForString(const char* str) {
jb8414 0:f479e4f4db0e 275 int currentIndex = 0;
jb8414 0:f479e4f4db0e 276 if (str[currentIndex] == '\0') return E_OK;
jb8414 0:f479e4f4db0e 277
jb8414 0:f479e4f4db0e 278 while (true) {
jb8414 0:f479e4f4db0e 279 while (_client->available()) {
jb8414 0:f479e4f4db0e 280 char c = _client->read();
jb8414 0:f479e4f4db0e 281 DBG("%c", c);
jb8414 0:f479e4f4db0e 282
jb8414 0:f479e4f4db0e 283 int cmp;
jb8414 0:f479e4f4db0e 284 if (_case_insensitive) {
jb8414 0:f479e4f4db0e 285 cmp = tolower(c) - tolower(str[currentIndex]);
jb8414 0:f479e4f4db0e 286 } else {
jb8414 0:f479e4f4db0e 287 cmp = c - str[currentIndex];
jb8414 0:f479e4f4db0e 288 }
jb8414 0:f479e4f4db0e 289
jb8414 0:f479e4f4db0e 290 if ((str[currentIndex] == '*') || (cmp == 0)) {
jb8414 0:f479e4f4db0e 291 currentIndex++;
jb8414 0:f479e4f4db0e 292 if (str[currentIndex] == '\0') {
jb8414 0:f479e4f4db0e 293 return E_OK;
jb8414 0:f479e4f4db0e 294 }
jb8414 0:f479e4f4db0e 295 } else {
jb8414 0:f479e4f4db0e 296 // start from the beginning
jb8414 0:f479e4f4db0e 297 currentIndex = 0;
jb8414 0:f479e4f4db0e 298 }
jb8414 0:f479e4f4db0e 299 }
jb8414 0:f479e4f4db0e 300
jb8414 0:f479e4f4db0e 301 if (!_client->connected()) {
jb8414 0:f479e4f4db0e 302 DBGLN("%s", "ERROR: The client is disconnected from the server!");
jb8414 0:f479e4f4db0e 303
jb8414 0:f479e4f4db0e 304 close();
jb8414 0:f479e4f4db0e 305 return E_DISCONNECTED;
jb8414 0:f479e4f4db0e 306 }
jb8414 0:f479e4f4db0e 307
jb8414 0:f479e4f4db0e 308 delay(1000);
jb8414 0:f479e4f4db0e 309 }
jb8414 0:f479e4f4db0e 310 // never reached here
jb8414 0:f479e4f4db0e 311 return E_NOTREACHABLE;
jb8414 0:f479e4f4db0e 312 }
jb8414 0:f479e4f4db0e 313
jb8414 0:f479e4f4db0e 314 int M2XStreamClient::readStatusCode(bool closeClient) {
jb8414 0:f479e4f4db0e 315 int responseCode = 0;
jb8414 0:f479e4f4db0e 316 int ret = waitForString("HTTP/*.* ");
jb8414 0:f479e4f4db0e 317 if (ret != E_OK) {
jb8414 0:f479e4f4db0e 318 if (closeClient) close();
jb8414 0:f479e4f4db0e 319 return ret;
jb8414 0:f479e4f4db0e 320 }
jb8414 0:f479e4f4db0e 321
jb8414 0:f479e4f4db0e 322 // ret is not needed from here(since it must be E_OK), so we can use it
jb8414 0:f479e4f4db0e 323 // as a regular variable now.
jb8414 0:f479e4f4db0e 324 ret = 0;
jb8414 0:f479e4f4db0e 325 while (true) {
jb8414 0:f479e4f4db0e 326 while (_client->available()) {
jb8414 0:f479e4f4db0e 327 char c = _client->read();
jb8414 0:f479e4f4db0e 328 DBG("%c", c);
jb8414 0:f479e4f4db0e 329
jb8414 0:f479e4f4db0e 330 responseCode = responseCode * 10 + (c - '0');
jb8414 0:f479e4f4db0e 331 ret++;
jb8414 0:f479e4f4db0e 332 if (ret == 3) {
jb8414 0:f479e4f4db0e 333 if (closeClient) close();
jb8414 0:f479e4f4db0e 334 return responseCode;
jb8414 0:f479e4f4db0e 335 }
jb8414 0:f479e4f4db0e 336 }
jb8414 0:f479e4f4db0e 337
jb8414 0:f479e4f4db0e 338 if (!_client->connected()) {
jb8414 0:f479e4f4db0e 339 DBGLN("%s", "ERROR: The client is disconnected from the server!");
jb8414 0:f479e4f4db0e 340
jb8414 0:f479e4f4db0e 341 if (closeClient) close();
jb8414 0:f479e4f4db0e 342 return E_DISCONNECTED;
jb8414 0:f479e4f4db0e 343 }
jb8414 0:f479e4f4db0e 344
jb8414 0:f479e4f4db0e 345 delay(1000);
jb8414 0:f479e4f4db0e 346 }
jb8414 0:f479e4f4db0e 347
jb8414 0:f479e4f4db0e 348 // never reached here
jb8414 0:f479e4f4db0e 349 return E_NOTREACHABLE;
jb8414 0:f479e4f4db0e 350 }
jb8414 0:f479e4f4db0e 351
jb8414 0:f479e4f4db0e 352 int M2XStreamClient::readContentLength() {
jb8414 0:f479e4f4db0e 353 int ret = waitForString("Content-Length: ");
jb8414 0:f479e4f4db0e 354 if (ret != E_OK) {
jb8414 0:f479e4f4db0e 355 return ret;
jb8414 0:f479e4f4db0e 356 }
jb8414 0:f479e4f4db0e 357
jb8414 0:f479e4f4db0e 358 // From now on, ret is not needed, we can use it
jb8414 0:f479e4f4db0e 359 // to keep the final result
jb8414 0:f479e4f4db0e 360 ret = 0;
jb8414 0:f479e4f4db0e 361 while (true) {
jb8414 0:f479e4f4db0e 362 while (_client->available()) {
jb8414 0:f479e4f4db0e 363 char c = _client->read();
jb8414 0:f479e4f4db0e 364 DBG("%c", c);
jb8414 0:f479e4f4db0e 365
jb8414 0:f479e4f4db0e 366 if ((c == '\r') || (c == '\n')) {
jb8414 0:f479e4f4db0e 367 return (ret == 0) ? (E_INVALID) : (ret);
jb8414 0:f479e4f4db0e 368 } else {
jb8414 0:f479e4f4db0e 369 ret = ret * 10 + (c - '0');
jb8414 0:f479e4f4db0e 370 }
jb8414 0:f479e4f4db0e 371 }
jb8414 0:f479e4f4db0e 372
jb8414 0:f479e4f4db0e 373 if (!_client->connected()) {
jb8414 0:f479e4f4db0e 374 DBGLN("%s", "ERROR: The client is disconnected from the server!");
jb8414 0:f479e4f4db0e 375
jb8414 0:f479e4f4db0e 376 return E_DISCONNECTED;
jb8414 0:f479e4f4db0e 377 }
jb8414 0:f479e4f4db0e 378
jb8414 0:f479e4f4db0e 379 delay(1000);
jb8414 0:f479e4f4db0e 380 }
jb8414 0:f479e4f4db0e 381
jb8414 0:f479e4f4db0e 382 // never reached here
jb8414 0:f479e4f4db0e 383 return E_NOTREACHABLE;
jb8414 0:f479e4f4db0e 384 }
jb8414 0:f479e4f4db0e 385
jb8414 0:f479e4f4db0e 386 int M2XStreamClient::skipHttpHeader() {
citrusbyte 16:7903152de19f 387 return waitForString("\n\r\n");
jb8414 0:f479e4f4db0e 388 }
jb8414 0:f479e4f4db0e 389
jb8414 0:f479e4f4db0e 390 void M2XStreamClient::close() {
jb8414 0:f479e4f4db0e 391 // Eats up buffered data before closing
jb8414 0:f479e4f4db0e 392 _client->flush();
jb8414 0:f479e4f4db0e 393 _client->stop();
jb8414 0:f479e4f4db0e 394 }
jb8414 0:f479e4f4db0e 395
jb8414 0:f479e4f4db0e 396 int M2XStreamClient::readStreamValue(stream_value_read_callback callback,
jb8414 0:f479e4f4db0e 397 void* context) {
NetArc 2:7ea7ab05f120 398 const int BUF_LEN = 64;
jb8414 0:f479e4f4db0e 399 char buf[BUF_LEN];
jb8414 0:f479e4f4db0e 400
jb8414 0:f479e4f4db0e 401 int length = readContentLength();
jb8414 0:f479e4f4db0e 402 if (length < 0) {
jb8414 0:f479e4f4db0e 403 close();
jb8414 0:f479e4f4db0e 404 return length;
jb8414 0:f479e4f4db0e 405 }
jb8414 0:f479e4f4db0e 406
jb8414 0:f479e4f4db0e 407 int index = skipHttpHeader();
jb8414 0:f479e4f4db0e 408 if (index != E_OK) {
jb8414 0:f479e4f4db0e 409 close();
jb8414 0:f479e4f4db0e 410 return index;
jb8414 0:f479e4f4db0e 411 }
jb8414 0:f479e4f4db0e 412 index = 0;
jb8414 0:f479e4f4db0e 413
jb8414 0:f479e4f4db0e 414 stream_parsing_context_state state;
jb8414 0:f479e4f4db0e 415 state.state = state.index = 0;
jb8414 0:f479e4f4db0e 416 state.callback = callback;
jb8414 0:f479e4f4db0e 417 state.context = context;
jb8414 0:f479e4f4db0e 418
jb8414 0:f479e4f4db0e 419 jsonlite_parser_callbacks cbs = jsonlite_default_callbacks;
jb8414 0:f479e4f4db0e 420 cbs.key_found = on_stream_key_found;
citrusbyte 10:4ce9eba38dbe 421 cbs.number_found = on_stream_number_found;
jb8414 0:f479e4f4db0e 422 cbs.string_found = on_stream_string_found;
jb8414 0:f479e4f4db0e 423 cbs.context.client_state = &state;
jb8414 0:f479e4f4db0e 424
jb8414 0:f479e4f4db0e 425 jsonlite_parser p = jsonlite_parser_init(jsonlite_parser_estimate_size(5));
jb8414 0:f479e4f4db0e 426 jsonlite_parser_set_callback(p, &cbs);
jb8414 0:f479e4f4db0e 427
jb8414 0:f479e4f4db0e 428 jsonlite_result result = jsonlite_result_unknown;
jb8414 0:f479e4f4db0e 429 while (index < length) {
jb8414 0:f479e4f4db0e 430 int i = 0;
citrusbyte 10:4ce9eba38dbe 431
jb8414 0:f479e4f4db0e 432 DBG("%s", "Received Data: ");
jb8414 0:f479e4f4db0e 433 while ((i < BUF_LEN) && _client->available()) {
jb8414 0:f479e4f4db0e 434 buf[i++] = _client->read();
jb8414 0:f479e4f4db0e 435 DBG("%c", buf[i - 1]);
jb8414 0:f479e4f4db0e 436 }
jb8414 0:f479e4f4db0e 437 DBGLNEND;
jb8414 0:f479e4f4db0e 438
jb8414 0:f479e4f4db0e 439 if ((!_client->connected()) &&
jb8414 0:f479e4f4db0e 440 (!_client->available()) &&
jb8414 0:f479e4f4db0e 441 ((index + i) < length)) {
jb8414 0:f479e4f4db0e 442 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 443 close();
jb8414 0:f479e4f4db0e 444 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 445 }
jb8414 0:f479e4f4db0e 446
jb8414 0:f479e4f4db0e 447 result = jsonlite_parser_tokenize(p, buf, i);
jb8414 0:f479e4f4db0e 448 if ((result != jsonlite_result_ok) &&
jb8414 0:f479e4f4db0e 449 (result != jsonlite_result_end_of_stream)) {
jb8414 0:f479e4f4db0e 450 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 451 close();
jb8414 0:f479e4f4db0e 452 return E_JSON_INVALID;
jb8414 0:f479e4f4db0e 453 }
citrusbyte 10:4ce9eba38dbe 454
NetArc 4:ba0d02be2835 455 index += i;
jb8414 0:f479e4f4db0e 456 }
jb8414 0:f479e4f4db0e 457
jb8414 0:f479e4f4db0e 458 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 459 close();
jb8414 0:f479e4f4db0e 460 return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
jb8414 0:f479e4f4db0e 461 }
jb8414 0:f479e4f4db0e 462
jb8414 0:f479e4f4db0e 463 int M2XStreamClient::readLocation(location_read_callback callback,
jb8414 0:f479e4f4db0e 464 void* context) {
jb8414 0:f479e4f4db0e 465 const int BUF_LEN = 40;
jb8414 0:f479e4f4db0e 466 char buf[BUF_LEN];
jb8414 0:f479e4f4db0e 467
jb8414 0:f479e4f4db0e 468 int length = readContentLength();
jb8414 0:f479e4f4db0e 469 if (length < 0) {
jb8414 0:f479e4f4db0e 470 close();
jb8414 0:f479e4f4db0e 471 return length;
jb8414 0:f479e4f4db0e 472 }
jb8414 0:f479e4f4db0e 473
jb8414 0:f479e4f4db0e 474 int index = skipHttpHeader();
jb8414 0:f479e4f4db0e 475 if (index != E_OK) {
jb8414 0:f479e4f4db0e 476 close();
jb8414 0:f479e4f4db0e 477 return index;
jb8414 0:f479e4f4db0e 478 }
jb8414 0:f479e4f4db0e 479 index = 0;
jb8414 0:f479e4f4db0e 480
jb8414 0:f479e4f4db0e 481 location_parsing_context_state state;
jb8414 0:f479e4f4db0e 482 state.state = state.index = 0;
jb8414 0:f479e4f4db0e 483 state.callback = callback;
jb8414 0:f479e4f4db0e 484 state.context = context;
jb8414 0:f479e4f4db0e 485
jb8414 0:f479e4f4db0e 486 jsonlite_parser_callbacks cbs = jsonlite_default_callbacks;
jb8414 0:f479e4f4db0e 487 cbs.key_found = on_location_key_found;
jb8414 0:f479e4f4db0e 488 cbs.string_found = on_location_string_found;
jb8414 0:f479e4f4db0e 489 cbs.context.client_state = &state;
jb8414 0:f479e4f4db0e 490
jb8414 0:f479e4f4db0e 491 jsonlite_parser p = jsonlite_parser_init(jsonlite_parser_estimate_size(5));
jb8414 0:f479e4f4db0e 492 jsonlite_parser_set_callback(p, &cbs);
jb8414 0:f479e4f4db0e 493
jb8414 0:f479e4f4db0e 494 jsonlite_result result = jsonlite_result_unknown;
jb8414 0:f479e4f4db0e 495 while (index < length) {
jb8414 0:f479e4f4db0e 496 int i = 0;
jb8414 0:f479e4f4db0e 497
jb8414 0:f479e4f4db0e 498 DBG("%s", "Received Data: ");
jb8414 0:f479e4f4db0e 499 while ((i < BUF_LEN) && _client->available()) {
jb8414 0:f479e4f4db0e 500 buf[i++] = _client->read();
jb8414 0:f479e4f4db0e 501 DBG("%c", buf[i - 1]);
jb8414 0:f479e4f4db0e 502 }
jb8414 0:f479e4f4db0e 503 DBGLNEND;
jb8414 0:f479e4f4db0e 504
jb8414 0:f479e4f4db0e 505 if ((!_client->connected()) &&
jb8414 0:f479e4f4db0e 506 (!_client->available()) &&
jb8414 0:f479e4f4db0e 507 ((index + i) < length)) {
jb8414 0:f479e4f4db0e 508 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 509 close();
jb8414 0:f479e4f4db0e 510 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 511 }
jb8414 0:f479e4f4db0e 512
jb8414 0:f479e4f4db0e 513 result = jsonlite_parser_tokenize(p, buf, i);
jb8414 0:f479e4f4db0e 514 if ((result != jsonlite_result_ok) &&
jb8414 0:f479e4f4db0e 515 (result != jsonlite_result_end_of_stream)) {
jb8414 0:f479e4f4db0e 516 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 517 close();
jb8414 0:f479e4f4db0e 518 return E_JSON_INVALID;
jb8414 0:f479e4f4db0e 519 }
jb8414 0:f479e4f4db0e 520
jb8414 0:f479e4f4db0e 521 index += i;
jb8414 0:f479e4f4db0e 522 }
jb8414 0:f479e4f4db0e 523
jb8414 0:f479e4f4db0e 524 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 525 close();
jb8414 0:f479e4f4db0e 526 return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
jb8414 0:f479e4f4db0e 527 }