Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: WNCInterface_M2Xdemo ATT_WNCInterface_Info WNCInterface_HTTP_example Public_IoT_M2X_Cellular_Demo
Fork of M2XStreamClient by
Revision 6:e6d66d99dd6f, committed 2013-11-14
- Comitter:
- citrusbyte
- Date:
- Thu Nov 14 15:12:51 2013 +0000
- Parent:
- 5:ea68c8980ad8
- Child:
- 7:e64d9e1a800a
- Commit message:
- Update m2x client library
Changed in this revision
--- a/M2XStreamClient.cpp Thu Oct 24 12:22:33 2013 +0000
+++ b/M2XStreamClient.cpp Thu Nov 14 15:12:51 2013 +0000
@@ -5,13 +5,10 @@
#include "StreamParseFunctions.h"
#include "LocationParseFunctions.h"
-#define HEX(t_) ((char) (((t_) > 9) ? ((t_) - 10 + 'A') : ((t_) + '0')))
-#define MAX_DOUBLE_DIGITS 7
-
const char* M2XStreamClient::kDefaultM2XHost = "api-m2x.att.com";
const char* kUserAgentLine = "User-Agent: M2X Arduino Client/0.1";
-static int print_encoded_string(Print* print, const char* str);
+int print_encoded_string(Print* print, const char* str);
M2XStreamClient::M2XStreamClient(Client* client,
const char* key,
@@ -23,117 +20,41 @@
_null_print() {
}
-int M2XStreamClient::send(const char* feedId,
- const char* streamName,
- double value) {
- if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
- writeSendHeader(feedId, streamName,
- // 6 for "value="
- _null_print.print(value) + 6);
- _client->print("value=");
- // value is a double, does not need encoding
- _client->print(value);
- } else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
- return E_NOCONNECTION;
- }
-
- return readStatusCode(true);
-}
-
-int M2XStreamClient::send(const char* feedId,
- const char* streamName,
- long value) {
- if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
- writeSendHeader(feedId, streamName,
- // 6 for "value="
- _null_print.print(value) + 6);
-
- _client->print("value=");
- // value is a long, does not need encoding
- _client->print(value);
- } else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
- return E_NOCONNECTION;
+#define WRITE_QUERY_PART(client_, started_, name_, str_) { \
+ if (str_) { \
+ if (started_) { \
+ (client_)->print("&"); \
+ } else { \
+ (client_)->print("?"); \
+ started_ = true; \
+ } \
+ (client_)->print(name_ "="); \
+ (client_)->print(str_); \
+ } \
}
- return readStatusCode(true);
-}
-
-int M2XStreamClient::send(const char* feedId,
- const char* streamName,
- int value) {
+int M2XStreamClient::fetchValues(const char* feedId, const char* streamName,
+ stream_value_read_callback callback, void* context,
+ const char* startTime, const char* endTime,
+ const char* limit) {
if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
- writeSendHeader(feedId, streamName,
- // 6 for "value="
- _null_print.print(value) + 6);
-
- _client->print("value=");
- // value is an int, does not need encoding
- _client->print(value);
- } else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
- return E_NOCONNECTION;
- }
-
- return readStatusCode(true);
-}
+ bool query_started = false;
-int M2XStreamClient::send(const char* feedId,
- const char* streamName,
- const char* value) {
- if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
- writeSendHeader(feedId, streamName,
- // 6 for "value="
- _null_print.print(value) + 6);
-
- _client->print("value=");
- print_encoded_string(_client, value);
- } else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
- return E_NOCONNECTION;
- }
-
- return readStatusCode(true);
-}
-
-int M2XStreamClient::receive(const char* feedId, const char* streamName,
- stream_value_read_callback callback, void* context) {
- if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
+ DBGLN("%s", "Connected to M2X server!");
_client->print("GET /v1/feeds/");
print_encoded_string(_client, feedId);
_client->print("/streams/");
print_encoded_string(_client, streamName);
- _client->println("/values HTTP/1.0");
+ _client->print("/values");
+ WRITE_QUERY_PART(_client, query_started, "start", startTime);
+ WRITE_QUERY_PART(_client, query_started, "end", endTime);
+ WRITE_QUERY_PART(_client, query_started, "limit", limit);
+
+ _client->println(" HTTP/1.0");
writeHttpHeader(-1);
} else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
+ DBGLN("%s", "ERROR: Cannot connect to M2X server!");
return E_NOCONNECTION;
}
int status = readStatusCode(false);
@@ -149,18 +70,14 @@
location_read_callback callback,
void* context) {
if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
+ DBGLN("%s", "Connected to M2X server!");
_client->print("GET /v1/feeds/");
print_encoded_string(_client, feedId);
_client->println("/location HTTP/1.0");
writeHttpHeader(-1);
} else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
+ DBGLN("%s", "ERROR: Cannot connect to M2X server!");
return E_NOCONNECTION;
}
int status = readStatusCode(false);
@@ -174,7 +91,7 @@
// Encodes and prints string using Percent-encoding specified
// in RFC 1738, Section 2.2
-static int print_encoded_string(Print* print, const char* str) {
+int print_encoded_string(Print* print, const char* str) {
int bytes = 0;
for (int i = 0; str[i] != 0; i++) {
if (((str[i] >= 'A') && (str[i] <= 'Z')) ||
@@ -193,91 +110,7 @@
return bytes;
}
-static int write_location_data(Print* print, const char* name,
- double latitude, double longitude,
- double elevation) {
- int bytes = 0;
- bytes += print->print("name=");
- bytes += print_encoded_string(print, name);
- bytes += print->print("&latitude=");
- bytes += print->print(latitude, MAX_DOUBLE_DIGITS);
- bytes += print->print("&longitude=");
- bytes += print->print(longitude, MAX_DOUBLE_DIGITS);
- bytes += print->print("&elevation=");
- bytes += print->print(elevation);
- return bytes;
-}
-
-static int write_location_data(Print* print, const char* name,
- const char* latitude, const char* longitude,
- const char* elevation) {
- int bytes = 0;
- bytes += print->print("name=");
- bytes += print_encoded_string(print, name);
- bytes += print->print("&latitude=");
- bytes += print_encoded_string(print, latitude);
- bytes += print->print("&longitude=");
- bytes += print_encoded_string(print, longitude);
- bytes += print->print("&elevation=");
- bytes += print_encoded_string(print, elevation);
- return bytes;
-}
-
-int M2XStreamClient::updateLocation(const char* feedId,
- const char* name,
- double latitude,
- double longitude,
- double elevation) {
- if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
-
- int length = write_location_data(&_null_print, name, latitude, longitude,
- elevation);
- _client->print("PUT /v1/feeds/");
- print_encoded_string(_client, feedId);
- _client->println("/location HTTP/1.0");
-
- writeHttpHeader(length);
- write_location_data(_client, name, latitude, longitude, elevation);
- } else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
- return E_NOCONNECTION;
- }
- return readStatusCode(true);
-}
-
-int M2XStreamClient::updateLocation(const char* feedId,
- const char* name,
- const char* latitude,
- const char* longitude,
- const char* elevation) {
- if (_client->connect(_host, _port)) {
-#ifdef DEBUG
- printf("Connected to M2X server!\n");
-#endif
-
- int length = write_location_data(&_null_print, name, latitude, longitude,
- elevation);
- _client->print("PUT /v1/feeds/");
- print_encoded_string(_client, feedId);
- _client->println("/location HTTP/1.0");
-
- writeHttpHeader(length);
- write_location_data(_client, name, latitude, longitude, elevation);
- } else {
-#ifdef DEBUG
- printf("ERROR: Cannot connect to M2X server!\n");
-#endif
- return E_NOCONNECTION;
- }
- return readStatusCode(true);
-}
-
-void M2XStreamClient::writeSendHeader(const char* feedId,
+void M2XStreamClient::writePostHeader(const char* feedId,
const char* streamName,
int contentLength) {
_client->print("PUT /v1/feeds/");
@@ -285,7 +118,7 @@
_client->print("/streams/");
print_encoded_string(_client, streamName);
_client->println(" HTTP/1.0");
-
+
writeHttpHeader(contentLength);
}
@@ -293,7 +126,7 @@
_client->println(kUserAgentLine);
_client->print("X-M2X-KEY: ");
_client->println(_key);
-
+
_client->print("Host: ");
print_encoded_string(_client, _host);
if (_port != kDefaultM2XPort) {
@@ -304,10 +137,10 @@
_client->println();
if (contentLength > 0) {
- _client->println("Content-Type: application/x-www-form-urlencoded");
-#ifdef DEBUG
- printf("Content Length: %d\n", contentLength);
-#endif
+ _client->println("Content-Type: application/json");
+ DBG("%s", "Content Length: ");
+ DBGLN("%d", contentLength);
+
_client->print("Content-Length: ");
_client->println(contentLength);
}
@@ -321,9 +154,7 @@
while (true) {
while (_client->available()) {
char c = _client->read();
-#ifdef DEBUG
- printf("%c", c);
-#endif
+ DBG("%c", c);
if ((str[currentIndex] == '*') ||
(c == str[currentIndex])) {
@@ -338,9 +169,8 @@
}
if (!_client->connected()) {
-#ifdef DEBUG
- printf("ERROR: The client is disconnected from the server!\n");
-#endif
+ DBGLN("%s", "ERROR: The client is disconnected from the server!");
+
close();
return E_DISCONNECTED;
}
@@ -365,9 +195,8 @@
while (true) {
while (_client->available()) {
char c = _client->read();
-#ifdef DEBUG
- printf("%c", c);
-#endif
+ DBG("%c", c);
+
responseCode = responseCode * 10 + (c - '0');
ret++;
if (ret == 3) {
@@ -377,9 +206,8 @@
}
if (!_client->connected()) {
-#ifdef DEBUG
- printf("ERROR: The client is disconnected from the server!\n");
-#endif
+ DBGLN("%s", "ERROR: The client is disconnected from the server!");
+
if (closeClient) close();
return E_DISCONNECTED;
}
@@ -403,9 +231,8 @@
while (true) {
while (_client->available()) {
char c = _client->read();
-#ifdef DEBUG
- printf("%c", c);
-#endif
+ DBG("%c", c);
+
if ((c == '\r') || (c == '\n')) {
return (ret == 0) ? (E_INVALID) : (ret);
} else {
@@ -414,9 +241,8 @@
}
if (!_client->connected()) {
-#ifdef DEBUG
- printf("ERROR: The client is disconnected from the server!\n");
-#endif
+ DBGLN("%s", "ERROR: The client is disconnected from the server!");
+
return E_DISCONNECTED;
}
@@ -472,18 +298,12 @@
while (index < length) {
int i = 0;
-#ifdef DEBUG
- printf("Received Data: ");
-#endif
+ DBG("%s", "Received Data: ");
while ((i < BUF_LEN) && _client->available()) {
buf[i++] = _client->read();
-#ifdef DEBUG
- printf("%c", buf[i - 1]);
-#endif
+ DBG("%c", buf[i - 1]);
}
-#ifdef DEBUG
- printf("\n");
-#endif
+ DBGLNEND;
if ((!_client->connected()) &&
(!_client->available()) &&
@@ -544,18 +364,12 @@
while (index < length) {
int i = 0;
-#ifdef DEBUG
- printf("Received Data: ");
-#endif
+ DBG("%s", "Received Data: ");
while ((i < BUF_LEN) && _client->available()) {
buf[i++] = _client->read();
-#ifdef DEBUG
- printf("%c", buf[i - 1]);
-#endif
+ DBG("%c", buf[i - 1]);
}
-#ifdef DEBUG
- printf("\n");
-#endif
+ DBGLNEND;
if ((!_client->connected()) &&
(!_client->available()) &&
@@ -581,4 +395,3 @@
return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
}
-
--- a/M2XStreamClient.h Thu Oct 24 12:22:33 2013 +0000
+++ b/M2XStreamClient.h Thu Nov 14 15:12:51 2013 +0000
@@ -3,11 +3,39 @@
#define MIN(a, b) (((a) > (b))?(b):(a))
+#define MBED_PLATFORM
+
+#ifdef ARDUINO_PLATFORM
+#include "Arduino.h"
+#endif
+
+#ifdef MBED_PLATFORM
#include "mbed.h"
+#endif
+
#include "Client.h"
-#include "Utility.h"
+#include "NullPrint.h"
+
+#ifdef DEBUG
+#ifdef ARDUINO_PLATFORM
+#define DBG(fmt_, data_) Serial.print(data_)
+#define DBGLN(fmt_, data_) Serial.println(data_)
+#define DBGLNEND Serial.println()
+#endif // ARDUINO_PLATFORM
-#include "NullPrint.h"
+#ifdef MBED_PLATFORM
+#define DBG(fmt_, data_) printf((fmt_), (data_))
+#define DBGLN(fmt_, data_) printf((fmt_), (data_)); printf("\n")
+#define DBGLNEND printf("\n")
+#endif // MBED_PLATFORM
+#else
+#define DBG(fmt_, data_)
+#define DBGLN(fmt_, data_)
+#define DBGLNEND
+#endif // DEBUG
+
+#define HEX(t_) ((char) (((t_) > 9) ? ((t_) - 10 + 'A') : ((t_) + '0')))
+#define MAX_DOUBLE_DIGITS 7
static const int E_OK = 0;
static const int E_NOCONNECTION = -1;
@@ -39,13 +67,35 @@
const char* host = kDefaultM2XHost,
int port = kDefaultM2XPort);
- // Update data stream, returns the HTTP status code
- int send(const char* feedId, const char* streamName, double value);
- int send(const char* feedId, const char* streamName, long value);
- int send(const char* feedId, const char* streamName, int value);
- int send(const char* feedId, const char* streamName, const char* value);
+ // Post data stream value, returns the HTTP status code
+ template <class T>
+ int post(const char* feedId, const char* streamName, T value);
- // Receive values for a particular data stream. Since memory is
+ // Post multiple values to M2X all at once.
+ // +feedId+ - id of the feed to post values
+ // +streamNum+ - Number of streams to post
+ // +names+ - Array of stream names, the length of the array should
+ // be exactly +streamNum+
+ // +counts+ - Array of +streamNum+ length, each item in this array
+ // containing the number of values we want to post for each stream
+ // +ats+ - Timestamps for each value, the length of this array should
+ // be the some of all values in +counts+, for the first +counts[0]+
+ // items, the values belong to the first stream, for the following
+ // +counts[1]+ number of items, the values belong to the second stream,
+ // etc. Note timestamps are optional, if a value does not havee timestamp,
+ // we can simply put NULL here, or we can put NULl for +ats+, meaning
+ // none of the values has a timestamp
+ // +values+ - Values to post. This works the same way as +ats+, the
+ // first +counts[0]+ number of items contain values to post to the first
+ // stream, the succeeding +counts[1]+ number of items contain values
+ // for the second stream, etc. The length of this array should be
+ // the sum of all values in +counts+ array.
+ template <class T>
+ int postMultiple(const char* feedId, int streamNum,
+ const char* names[], const int counts[],
+ const char* ats[], T values[]);
+
+ // Fetch values for a particular data stream. Since memory is
// very limited on an Arduino, we cannot parse and get all the
// data points in memory. Instead, we use callbacks here: whenever
// a new data point is parsed, we call the callback using the values,
@@ -57,8 +107,10 @@
// For each data point, the callback will be called once. The HTTP
// status code will be returned. And the content is only parsed when
// the status code is 200.
- int receive(const char* feedId, const char* streamName,
- stream_value_read_callback callback, void* context);
+ int fetchValues(const char* feedId, const char* streamName,
+ stream_value_read_callback callback, void* context,
+ const char* startTime = NULL, const char* endTime = NULL,
+ const char* limit = NULL);
// Update datasource location
// NOTE: On an Arduino Uno and other ATMEGA based boards, double has
@@ -74,11 +126,9 @@
// precision, which means you are free to use the double-version only
// without any precision problems.
// Returned value is the http status code.
- int updateLocation(const char* feedId, const char* name,
- double latitude, double longitude, double elevation);
+ template <class T>
int updateLocation(const char* feedId, const char* name,
- const char* latitude, const char* longitude,
- const char* elevation);
+ T latitude, T longitude, T elevation);
// Read location information for a feed. Also used callback to process
// data points for memory reasons. The HTTP status code is returned,
@@ -93,10 +143,10 @@
NullPrint _null_print;
// Writes the HTTP header part for updating a stream value
- void writeSendHeader(const char* feedId,
+ void writePostHeader(const char* feedId,
const char* streamName,
int contentLength);
- // Writes HTTP header lines including M2X key, host, content
+ // Writes HTTP header lines including M2X API Key, host, content
// type and content length(if the body exists)
void writeHttpHeader(int contentLength);
// Parses HTTP response header and return the content length.
@@ -123,6 +173,7 @@
int readLocation(location_read_callback callback, void* context);
};
+#include "M2XStreamClient_template.h"
+
#endif /* M2XStreamClient_h */
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/M2XStreamClient_template.h Thu Nov 14 15:12:51 2013 +0000
@@ -0,0 +1,134 @@
+#ifndef M2XStreamClient_template_h
+#define M2XStreamClient_template_h
+
+// Implementations of template functions
+
+int print_encoded_string(Print* print, const char* str);
+
+template <class T>
+int M2XStreamClient::post(const char* feedId, const char* streamName, T value) {
+ if (_client->connect(_host, _port)) {
+ DBGLN("%s", "Connected to M2X server!");
+ writePostHeader(feedId, streamName,
+ // for {"value": and }
+ _null_print.print(value) + 10);
+ _client->print("{\"value\":");
+ _client->print(value);
+ _client->print("}");
+ } else {
+ DBGLN("%s", "ERROR: Cannot connect to M2X server!");
+ return E_NOCONNECTION;
+ }
+
+ return readStatusCode(true);
+}
+
+template <class T>
+inline int write_multiple_values(Print* print, int streamNum,
+ const char* names[], const int counts[],
+ const char* ats[], T values[]) {
+ int bytes = 0, value_index = 0;
+ bytes += print->print("{\"values\":{");
+ for (int i = 0; i < streamNum; i++) {
+ bytes += print->print("\"");
+ bytes += print->print(names[i]);
+ bytes += print->print("\":[");
+ for (int j = 0; j < counts[i]; j++) {
+ bytes += print->print("{");
+ if (ats && ats[value_index]) {
+ bytes += print->print("\"at\": \"");
+ bytes += print->print(ats[value_index]);
+ bytes += print->print("\",");
+ }
+ bytes += print->print("\"value\": \"");
+ bytes += print->print(values[value_index]);
+ bytes += print->print("\"}");
+ if (j < counts[i] - 1) { bytes += print->print(","); }
+ value_index++;
+ }
+ bytes += print->print("]");
+ if (i < streamNum - 1) { bytes += print->print(","); }
+ }
+ bytes += print->print("}}");
+ return bytes;
+}
+
+template <class T>
+int M2XStreamClient::postMultiple(const char* feedId, int streamNum,
+ const char* names[], const int counts[],
+ const char* ats[], T values[]) {
+ if (_client->connect(_host, _port)) {
+ DBGLN("%s", "Connected to M2X server!");
+ int length = write_multiple_values(&_null_print, streamNum, names,
+ counts, ats, values);
+ _client->print("POST /v1/feeds/");
+ print_encoded_string(_client, feedId);
+ _client->println(" HTTP/1.0");
+ writeHttpHeader(length);
+ write_multiple_values(_client, streamNum, names, counts, ats, values);
+ } else {
+ DBGLN("%s", "ERROR: Cannot connect to M2X server!");
+ return E_NOCONNECTION;
+ }
+ return readStatusCode(true);
+}
+
+template <class T>
+static int write_location_data(Print* print, const char* name,
+ T latitude, T longitude,
+ T elevation) {
+ int bytes = 0;
+ bytes += print->print("{\"name\":\"");
+ bytes += print->print(name);
+ bytes += print->print("\",\"latitude\":\"");
+ bytes += print->print(latitude);
+ bytes += print->print("\",\"longitude\":\"");
+ bytes += print->print(longitude);
+ bytes += print->print("\",\"elevation\":\"");
+ bytes += print->print(elevation);
+ bytes += print->print("\"}");
+ return bytes;
+}
+
+static int write_location_data(Print* print, const char* name,
+ double latitude, double longitude,
+ double elevation) {
+ int bytes = 0;
+ bytes += print->print("{\"name\":\"");
+ bytes += print->print(name);
+ bytes += print->print("\",\"latitude\":\"");
+ bytes += print->print(latitude, MAX_DOUBLE_DIGITS);
+ bytes += print->print("\",\"longitude\":\"");
+ bytes += print->print(longitude, MAX_DOUBLE_DIGITS);
+ bytes += print->print("\",\"elevation\":\"");
+ bytes += print->print(elevation);
+ bytes += print->print("\"}");
+ return bytes;
+}
+
+template <class T>
+int M2XStreamClient::updateLocation(const char* feedId,
+ const char* name,
+ T latitude,
+ T longitude,
+ T elevation) {
+ if (_client->connect(_host, _port)) {
+ DBGLN("%s", "Connected to M2X server!");
+
+ int length = write_location_data(&_null_print, name, latitude, longitude,
+ elevation);
+ _client->print("PUT /v1/feeds/");
+ print_encoded_string(_client, feedId);
+ _client->println("/location HTTP/1.0");
+
+ writeHttpHeader(length);
+ write_location_data(_client, name, latitude, longitude, elevation);
+ } else {
+ DBGLN("%s", "ERROR: Cannot connect to M2X server!");
+ return E_NOCONNECTION;
+ }
+ return readStatusCode(true);
+}
+
+#endif
+
