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 13:06:27 2015 +0000
Revision:
17:9db4a86b876a
Parent:
16:7903152de19f
Child:
19:4dfa28d37b8f
Update comments to TimeService

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jb8414 0:f479e4f4db0e 1 #include "M2XStreamClient.h"
jb8414 0:f479e4f4db0e 2
citrusbyte 17:9db4a86b876a 3 static int fill_iso8601_timestamp(int32_t seconds, int32_t milli,
citrusbyte 17:9db4a86b876a 4 char* buffer, int* length);
jb8414 0:f479e4f4db0e 5
citrusbyte 17:9db4a86b876a 6 TimeService::TimeService(M2XStreamClient* client) : _client(client) {
jb8414 0:f479e4f4db0e 7 }
jb8414 0:f479e4f4db0e 8
citrusbyte 17:9db4a86b876a 9 int TimeService::init() {
citrusbyte 17:9db4a86b876a 10 _timer.start();
citrusbyte 17:9db4a86b876a 11 return reset();
citrusbyte 10:4ce9eba38dbe 12 }
citrusbyte 10:4ce9eba38dbe 13
citrusbyte 17:9db4a86b876a 14 int TimeService::reset() {
citrusbyte 17:9db4a86b876a 15 int32_t ts;
citrusbyte 17:9db4a86b876a 16 int status = _client->getTimestamp32(&ts);
citrusbyte 16:7903152de19f 17
citrusbyte 17:9db4a86b876a 18 if (m2x_status_is_success(status)) {
citrusbyte 17:9db4a86b876a 19 _server_timestamp = ts;
citrusbyte 17:9db4a86b876a 20 _local_last_milli = _timer.read_ms();
citrusbyte 16:7903152de19f 21 }
citrusbyte 16:7903152de19f 22
citrusbyte 16:7903152de19f 23 return status;
citrusbyte 16:7903152de19f 24 }
citrusbyte 16:7903152de19f 25
citrusbyte 17:9db4a86b876a 26 int TimeService::getTimestamp(char* buffer, int* length) {
citrusbyte 17:9db4a86b876a 27 uint32_t now = _timer.read_ms();
citrusbyte 17:9db4a86b876a 28 if (now < _local_last_milli) {
citrusbyte 17:9db4a86b876a 29 // In case of a timestamp overflow, we reset the server timestamp recorded.
citrusbyte 17:9db4a86b876a 30 // Notice that unlike Arduino, mbed would overflow every 30 minutes,
citrusbyte 17:9db4a86b876a 31 // so if 2 calls to this API are more than 30 minutes apart, we are
citrusbyte 17:9db4a86b876a 32 // likely to run into troubles. This is a limitation of the current
citrusbyte 17:9db4a86b876a 33 // mbed platform. However, we argue that it might be a rare case that
citrusbyte 17:9db4a86b876a 34 // 2 calls to this are 30 minutes apart. In most cases, we would call
citrusbyte 17:9db4a86b876a 35 // this API every few seconds or minutes, this won't be a huge problem.
citrusbyte 17:9db4a86b876a 36 // However, if you have a use case that would require 2 intervening
citrusbyte 17:9db4a86b876a 37 // calls to this be 30 minutes apart, you might want to leverage a RTC
citrusbyte 17:9db4a86b876a 38 // clock instead of the simple ticker here.
citrusbyte 17:9db4a86b876a 39 int status = reset();
citrusbyte 17:9db4a86b876a 40 if (!m2x_status_is_success(status)) { return status; }
citrusbyte 17:9db4a86b876a 41 now = _timer.read_ms();
jb8414 0:f479e4f4db0e 42 }
citrusbyte 17:9db4a86b876a 43 if (now < _local_last_milli) {
citrusbyte 17:9db4a86b876a 44 // We have already reseted the timestamp, so this cannot happen,
citrusbyte 17:9db4a86b876a 45 // an HTTP request cannot last 30 minutes, something else must be wrong
citrusbyte 17:9db4a86b876a 46 // here.
citrusbyte 17:9db4a86b876a 47 return E_TIMESTAMP_ERROR;
jb8414 0:f479e4f4db0e 48 }
citrusbyte 17:9db4a86b876a 49 uint32_t diff = now - _local_last_milli;
citrusbyte 17:9db4a86b876a 50 _local_last_milli = now;
citrusbyte 17:9db4a86b876a 51 _server_timestamp += (int32_t) (diff / 1000); // Milliseconds to seconds
citrusbyte 17:9db4a86b876a 52 return fill_iso8601_timestamp(_server_timestamp, (int32_t) (diff % 1000),
citrusbyte 17:9db4a86b876a 53 buffer, length);
jb8414 0:f479e4f4db0e 54 }
jb8414 0:f479e4f4db0e 55
citrusbyte 17:9db4a86b876a 56 #define SIZE_ISO_8601 25
citrusbyte 17:9db4a86b876a 57 static inline bool is_leap_year(int16_t y) {
citrusbyte 17:9db4a86b876a 58 return ((1970 + y) > 0) &&
citrusbyte 17:9db4a86b876a 59 !((1970 + y) % 4) &&
citrusbyte 17:9db4a86b876a 60 (((1970 + y) % 100) || !((1970 + y) % 400));
citrusbyte 17:9db4a86b876a 61 }
citrusbyte 17:9db4a86b876a 62 static inline int32_t days_in_year(int16_t y) {
citrusbyte 17:9db4a86b876a 63 return is_leap_year(y) ? 366 : 365;
citrusbyte 17:9db4a86b876a 64 }
citrusbyte 17:9db4a86b876a 65 static const uint8_t MONTH_DAYS[]={31,28,31,30,31,30,31,31,30,31,30,31};
jb8414 0:f479e4f4db0e 66
citrusbyte 17:9db4a86b876a 67 static int fill_iso8601_timestamp(int32_t timestamp, int32_t milli,
citrusbyte 17:9db4a86b876a 68 char* buffer, int* length) {
citrusbyte 17:9db4a86b876a 69 int16_t year;
citrusbyte 17:9db4a86b876a 70 int8_t month, month_length;
citrusbyte 17:9db4a86b876a 71 int32_t day;
citrusbyte 17:9db4a86b876a 72 int8_t hour, minute, second;
jb8414 0:f479e4f4db0e 73
citrusbyte 17:9db4a86b876a 74 if (*length < SIZE_ISO_8601) {
citrusbyte 17:9db4a86b876a 75 *length = SIZE_ISO_8601;
citrusbyte 17:9db4a86b876a 76 return E_BUFFER_TOO_SMALL;
jb8414 0:f479e4f4db0e 77 }
jb8414 0:f479e4f4db0e 78
citrusbyte 17:9db4a86b876a 79 second = timestamp % 60;
citrusbyte 17:9db4a86b876a 80 timestamp /= 60; // now it is minutes
jb8414 0:f479e4f4db0e 81
citrusbyte 17:9db4a86b876a 82 minute = timestamp % 60;
citrusbyte 17:9db4a86b876a 83 timestamp /= 60; // now it is hours
jb8414 0:f479e4f4db0e 84
citrusbyte 17:9db4a86b876a 85 hour = timestamp % 24;
citrusbyte 17:9db4a86b876a 86 timestamp /= 24; // now it is days
jb8414 0:f479e4f4db0e 87
citrusbyte 17:9db4a86b876a 88 year = 0;
citrusbyte 17:9db4a86b876a 89 day = 0;
citrusbyte 17:9db4a86b876a 90 while ((day += days_in_year(year)) <= timestamp) {
citrusbyte 17:9db4a86b876a 91 year++;
citrusbyte 17:9db4a86b876a 92 }
citrusbyte 17:9db4a86b876a 93 day -= days_in_year(year);
citrusbyte 17:9db4a86b876a 94 timestamp -= day; // now it is days in this year, starting at 0
jb8414 0:f479e4f4db0e 95
citrusbyte 17:9db4a86b876a 96 day = 0;
citrusbyte 17:9db4a86b876a 97 month_length = 0;
citrusbyte 17:9db4a86b876a 98 for (month = 0; month < 12; month++) {
citrusbyte 17:9db4a86b876a 99 if (month == 1) {
citrusbyte 17:9db4a86b876a 100 // February
citrusbyte 17:9db4a86b876a 101 month_length = is_leap_year(year) ? 29 : 28;
citrusbyte 17:9db4a86b876a 102 } else {
citrusbyte 17:9db4a86b876a 103 month_length = MONTH_DAYS[month];
jb8414 0:f479e4f4db0e 104 }
citrusbyte 10:4ce9eba38dbe 105
citrusbyte 17:9db4a86b876a 106 if (timestamp >= month_length) {
citrusbyte 17:9db4a86b876a 107 timestamp -= month_length;
citrusbyte 17:9db4a86b876a 108 } else {
citrusbyte 17:9db4a86b876a 109 break;
citrusbyte 17:9db4a86b876a 110 }
jb8414 0:f479e4f4db0e 111 }
citrusbyte 17:9db4a86b876a 112 year = 1970 + year;
citrusbyte 17:9db4a86b876a 113 month++; // offset by 1
citrusbyte 17:9db4a86b876a 114 day = timestamp + 1;
jb8414 0:f479e4f4db0e 115
citrusbyte 17:9db4a86b876a 116 int i = 0, j = 0;
jb8414 0:f479e4f4db0e 117
citrusbyte 17:9db4a86b876a 118 // NOTE: It seems the snprintf implementation in Arduino has bugs,
citrusbyte 17:9db4a86b876a 119 // we have to manually piece the string together here.
citrusbyte 17:9db4a86b876a 120 #define INT_TO_STR(v_, width_) \
citrusbyte 17:9db4a86b876a 121 for (j = 0; j < (width_); j++) { \
citrusbyte 17:9db4a86b876a 122 buffer[i + (width_) - 1 - j] = '0' + ((v_) % 10); \
citrusbyte 17:9db4a86b876a 123 (v_) /= 10; \
citrusbyte 17:9db4a86b876a 124 } \
citrusbyte 17:9db4a86b876a 125 i += (width_)
jb8414 0:f479e4f4db0e 126
citrusbyte 17:9db4a86b876a 127 INT_TO_STR(year, 4);
citrusbyte 17:9db4a86b876a 128 buffer[i++] = '-';
citrusbyte 17:9db4a86b876a 129 INT_TO_STR(month, 2);
citrusbyte 17:9db4a86b876a 130 buffer[i++] = '-';
citrusbyte 17:9db4a86b876a 131 INT_TO_STR(day, 2);
citrusbyte 17:9db4a86b876a 132 buffer[i++] = 'T';
citrusbyte 17:9db4a86b876a 133 INT_TO_STR(hour, 2);
citrusbyte 17:9db4a86b876a 134 buffer[i++] = ':';
citrusbyte 17:9db4a86b876a 135 INT_TO_STR(minute, 2);
citrusbyte 17:9db4a86b876a 136 buffer[i++] = ':';
citrusbyte 17:9db4a86b876a 137 INT_TO_STR(second, 2);
citrusbyte 17:9db4a86b876a 138 buffer[i++] = '.';
citrusbyte 17:9db4a86b876a 139 INT_TO_STR(milli, 3);
citrusbyte 17:9db4a86b876a 140 buffer[i++] = 'Z';
citrusbyte 17:9db4a86b876a 141 buffer[i++] = '\0';
jb8414 0:f479e4f4db0e 142
citrusbyte 17:9db4a86b876a 143 #undef INT_TO_STR
jb8414 0:f479e4f4db0e 144
citrusbyte 17:9db4a86b876a 145 *length = i;
citrusbyte 17:9db4a86b876a 146 return E_OK;
jb8414 0:f479e4f4db0e 147 }