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
TimeService.cpp@21:6878944d2ce2, 2016-01-02 (annotated)
- 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?
| User | Revision | Line number | New 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 | } |
