branch with improvemnts

Fork of M2XStreamClient by AT&T M2X Team

Committer:
citrusbyte
Date:
Thu Oct 24 12:22:33 2013 +0000
Revision:
5:ea68c8980ad8
Child:
6:e6d66d99dd6f
Initial commit for M2X mbed client library

Who changed what in which revision?

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