Jim Flynn / M2XStreamClient-JMF

Dependents:   WNCInterface_M2Xdemo ATT_WNCInterface_Info WNCInterface_HTTP_example Public_IoT_M2X_Cellular_Demo

Fork of M2XStreamClient by AT&T M2X Team

Committer:
citrusbyte
Date:
Sat Jan 02 02:29:43 2016 +0000
Revision:
21:6878944d2ce2
Parent:
16:7903152de19f
Update library version

Who changed what in which revision?

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