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.
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
+
