A time interface class. This class replicates the normal time functions, but goes a couple of steps further. mbed library 82 and prior has a defective gmtime function. Also, this class enables access to setting the time, and adjusting the accuracy of the RTC.
Dependents: CI-data-logger-server WattEye X10Svr SSDP_Server
TimeInterface.cpp@1:2ee90f546f54, 2014-06-14 (annotated)
- Committer:
- WiredHome
- Date:
- Sat Jun 14 12:34:53 2014 +0000
- Revision:
- 1:2ee90f546f54
- Parent:
- 0:61112ca9193b
- Child:
- 2:65e0a25c7551
Add timelocal() method so local time offset does not have to be added in every use of time().
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:61112ca9193b | 1 | |
WiredHome | 0:61112ca9193b | 2 | #include "TimeInterface.h" |
WiredHome | 0:61112ca9193b | 3 | |
WiredHome | 0:61112ca9193b | 4 | #include "rtc_api.h" |
WiredHome | 0:61112ca9193b | 5 | |
WiredHome | 0:61112ca9193b | 6 | #ifdef WIN32 |
WiredHome | 0:61112ca9193b | 7 | // Fake it out for Win32 development and testing |
WiredHome | 0:61112ca9193b | 8 | struct LPC { |
WiredHome | 0:61112ca9193b | 9 | unsigned long CCR; // Clock Control register |
WiredHome | 0:61112ca9193b | 10 | unsigned long GPREG0; // General Purpose Register #0 - 32-bit Battery backed |
WiredHome | 0:61112ca9193b | 11 | unsigned long GPREG1; // General Purpose Register #1 - 32-bit Battery backed |
WiredHome | 0:61112ca9193b | 12 | unsigned long CALIBRATION; // Calibration Register |
WiredHome | 0:61112ca9193b | 13 | }; |
WiredHome | 0:61112ca9193b | 14 | struct LPC X; |
WiredHome | 0:61112ca9193b | 15 | struct LPC * LPC_RTC = &X; |
WiredHome | 0:61112ca9193b | 16 | #define set_time(x) (void)x |
WiredHome | 0:61112ca9193b | 17 | #endif |
WiredHome | 0:61112ca9193b | 18 | |
WiredHome | 0:61112ca9193b | 19 | |
WiredHome | 0:61112ca9193b | 20 | TimeInterface::TimeInterface() |
WiredHome | 0:61112ca9193b | 21 | { |
WiredHome | 0:61112ca9193b | 22 | } |
WiredHome | 0:61112ca9193b | 23 | |
WiredHome | 0:61112ca9193b | 24 | TimeInterface::~TimeInterface() |
WiredHome | 0:61112ca9193b | 25 | { |
WiredHome | 0:61112ca9193b | 26 | } |
WiredHome | 0:61112ca9193b | 27 | |
WiredHome | 0:61112ca9193b | 28 | clock_t TimeInterface::clock(void) |
WiredHome | 0:61112ca9193b | 29 | { |
WiredHome | 0:61112ca9193b | 30 | return std::clock(); |
WiredHome | 0:61112ca9193b | 31 | } |
WiredHome | 0:61112ca9193b | 32 | |
WiredHome | 0:61112ca9193b | 33 | time_t TimeInterface::time(time_t* timer) |
WiredHome | 0:61112ca9193b | 34 | { |
WiredHome | 0:61112ca9193b | 35 | return std::time(timer); |
WiredHome | 0:61112ca9193b | 36 | } |
WiredHome | 0:61112ca9193b | 37 | |
WiredHome | 1:2ee90f546f54 | 38 | time_t TimeInterface::timelocal(time_t* timer) |
WiredHome | 1:2ee90f546f54 | 39 | { |
WiredHome | 1:2ee90f546f54 | 40 | return std::time(timer) + 60 * get_tzo_min(); |
WiredHome | 1:2ee90f546f54 | 41 | } |
WiredHome | 1:2ee90f546f54 | 42 | |
WiredHome | 0:61112ca9193b | 43 | char * TimeInterface::ctime(const time_t * timer) |
WiredHome | 0:61112ca9193b | 44 | { |
WiredHome | 0:61112ca9193b | 45 | char * p = std::ctime(timer); |
WiredHome | 0:61112ca9193b | 46 | |
WiredHome | 0:61112ca9193b | 47 | if (strlen(p) < sizeof(result)) { |
WiredHome | 0:61112ca9193b | 48 | strcpy(result, p); |
WiredHome | 0:61112ca9193b | 49 | p = strchr(result, '\n'); |
WiredHome | 0:61112ca9193b | 50 | if (p) |
WiredHome | 0:61112ca9193b | 51 | *p = '\0'; |
WiredHome | 0:61112ca9193b | 52 | } else { |
WiredHome | 0:61112ca9193b | 53 | result[0] = '\0'; |
WiredHome | 0:61112ca9193b | 54 | } |
WiredHome | 0:61112ca9193b | 55 | return result; |
WiredHome | 0:61112ca9193b | 56 | } |
WiredHome | 0:61112ca9193b | 57 | |
WiredHome | 0:61112ca9193b | 58 | char * TimeInterface::asctime(const struct tm_ex *timeptr) |
WiredHome | 0:61112ca9193b | 59 | { |
WiredHome | 0:61112ca9193b | 60 | static const char wday_name[][4] = { |
WiredHome | 0:61112ca9193b | 61 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
WiredHome | 0:61112ca9193b | 62 | }; |
WiredHome | 0:61112ca9193b | 63 | static const char mon_name[][4] = { |
WiredHome | 0:61112ca9193b | 64 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
WiredHome | 0:61112ca9193b | 65 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
WiredHome | 0:61112ca9193b | 66 | }; |
WiredHome | 0:61112ca9193b | 67 | |
WiredHome | 0:61112ca9193b | 68 | sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d", |
WiredHome | 0:61112ca9193b | 69 | wday_name[timeptr->tm_wday % 7], |
WiredHome | 0:61112ca9193b | 70 | mon_name[timeptr->tm_mon % 12], |
WiredHome | 0:61112ca9193b | 71 | timeptr->tm_mday, timeptr->tm_hour, |
WiredHome | 0:61112ca9193b | 72 | timeptr->tm_min, timeptr->tm_sec, |
WiredHome | 0:61112ca9193b | 73 | 1900 + timeptr->tm_year); |
WiredHome | 0:61112ca9193b | 74 | return result; |
WiredHome | 0:61112ca9193b | 75 | } |
WiredHome | 0:61112ca9193b | 76 | |
WiredHome | 0:61112ca9193b | 77 | struct tm_ex * TimeInterface::gmtime(const time_t * timer) |
WiredHome | 0:61112ca9193b | 78 | { |
WiredHome | 0:61112ca9193b | 79 | time_t priv = *timer + (get_tzo_min() * 60); |
WiredHome | 0:61112ca9193b | 80 | struct tm * tmp = std::localtime(&priv); |
WiredHome | 0:61112ca9193b | 81 | |
WiredHome | 0:61112ca9193b | 82 | tm_ext.tm_sec = tmp->tm_sec; |
WiredHome | 0:61112ca9193b | 83 | tm_ext.tm_min = tmp->tm_min; |
WiredHome | 0:61112ca9193b | 84 | tm_ext.tm_hour = tmp->tm_hour; |
WiredHome | 0:61112ca9193b | 85 | tm_ext.tm_mday = tmp->tm_mday; |
WiredHome | 0:61112ca9193b | 86 | tm_ext.tm_mon = tmp->tm_mon; |
WiredHome | 0:61112ca9193b | 87 | tm_ext.tm_year = tmp->tm_year; |
WiredHome | 0:61112ca9193b | 88 | tm_ext.tm_wday = tmp->tm_wday; |
WiredHome | 0:61112ca9193b | 89 | tm_ext.tm_yday = tmp->tm_yday; |
WiredHome | 0:61112ca9193b | 90 | tm_ext.tm_isdst = tmp->tm_isdst; |
WiredHome | 0:61112ca9193b | 91 | tm_ext.tm_tzo_min = get_tzo_min(); |
WiredHome | 0:61112ca9193b | 92 | return &tm_ext; |
WiredHome | 0:61112ca9193b | 93 | } |
WiredHome | 0:61112ca9193b | 94 | |
WiredHome | 0:61112ca9193b | 95 | struct tm_ex * TimeInterface::localtime(const time_t * timer) |
WiredHome | 0:61112ca9193b | 96 | { |
WiredHome | 0:61112ca9193b | 97 | struct tm * tmp = std::localtime(timer); |
WiredHome | 0:61112ca9193b | 98 | |
WiredHome | 0:61112ca9193b | 99 | tm_ext.tm_sec = tmp->tm_sec; |
WiredHome | 0:61112ca9193b | 100 | tm_ext.tm_min = tmp->tm_min; |
WiredHome | 0:61112ca9193b | 101 | tm_ext.tm_hour = tmp->tm_hour; |
WiredHome | 0:61112ca9193b | 102 | tm_ext.tm_mday = tmp->tm_mday; |
WiredHome | 0:61112ca9193b | 103 | tm_ext.tm_mon = tmp->tm_mon; |
WiredHome | 0:61112ca9193b | 104 | tm_ext.tm_year = tmp->tm_year; |
WiredHome | 0:61112ca9193b | 105 | tm_ext.tm_wday = tmp->tm_wday; |
WiredHome | 0:61112ca9193b | 106 | tm_ext.tm_yday = tmp->tm_yday; |
WiredHome | 0:61112ca9193b | 107 | tm_ext.tm_isdst = tmp->tm_isdst; |
WiredHome | 0:61112ca9193b | 108 | tm_ext.tm_tzo_min = get_tzo_min(); |
WiredHome | 0:61112ca9193b | 109 | return &tm_ext; |
WiredHome | 0:61112ca9193b | 110 | } |
WiredHome | 0:61112ca9193b | 111 | |
WiredHome | 0:61112ca9193b | 112 | time_t TimeInterface::mktime(struct tm_ex * timeptr) |
WiredHome | 0:61112ca9193b | 113 | { |
WiredHome | 0:61112ca9193b | 114 | return std::mktime((struct tm *)timeptr); |
WiredHome | 0:61112ca9193b | 115 | } |
WiredHome | 0:61112ca9193b | 116 | |
WiredHome | 0:61112ca9193b | 117 | size_t TimeInterface::strftime(char * ptr, size_t maxsize, const char * format, const struct tm_ex * timeptr) |
WiredHome | 0:61112ca9193b | 118 | { |
WiredHome | 0:61112ca9193b | 119 | return std::strftime(ptr, maxsize, format, (struct tm *)timeptr); |
WiredHome | 0:61112ca9193b | 120 | } |
WiredHome | 0:61112ca9193b | 121 | |
WiredHome | 0:61112ca9193b | 122 | double TimeInterface::difftime(time_t end, time_t beginning) |
WiredHome | 0:61112ca9193b | 123 | { |
WiredHome | 0:61112ca9193b | 124 | return std::difftime(end, beginning); |
WiredHome | 0:61112ca9193b | 125 | } |
WiredHome | 0:61112ca9193b | 126 | |
WiredHome | 0:61112ca9193b | 127 | |
WiredHome | 0:61112ca9193b | 128 | |
WiredHome | 0:61112ca9193b | 129 | // time zone functions |
WiredHome | 0:61112ca9193b | 130 | |
WiredHome | 0:61112ca9193b | 131 | void TimeInterface::set_time(time_t t, int16_t tzo_min) |
WiredHome | 0:61112ca9193b | 132 | { |
WiredHome | 0:61112ca9193b | 133 | time_t tval = t - tzo_min; |
WiredHome | 0:61112ca9193b | 134 | rtc_init(); |
WiredHome | 0:61112ca9193b | 135 | rtc_write(tval); |
WiredHome | 0:61112ca9193b | 136 | LPC_RTC->GPREG1 = tval; |
WiredHome | 0:61112ca9193b | 137 | } |
WiredHome | 0:61112ca9193b | 138 | |
WiredHome | 0:61112ca9193b | 139 | void TimeInterface::set_tzo_min(int16_t tzo_min) |
WiredHome | 0:61112ca9193b | 140 | { |
WiredHome | 0:61112ca9193b | 141 | uint16_t th; |
WiredHome | 0:61112ca9193b | 142 | uint32_t treg; |
WiredHome | 0:61112ca9193b | 143 | |
WiredHome | 0:61112ca9193b | 144 | if (tzo_min >= -720 && tzo_min <= 720) { |
WiredHome | 0:61112ca9193b | 145 | th = (uint16_t)(-tzo_min); |
WiredHome | 0:61112ca9193b | 146 | treg = (th << 16) | (uint16_t)tzo_min; |
WiredHome | 0:61112ca9193b | 147 | LPC_RTC->GPREG0 = treg; |
WiredHome | 0:61112ca9193b | 148 | //printf("set_tzo(%d) %d is %08X\r\n", tzo, th, LPC_RTC->GPREG0); |
WiredHome | 0:61112ca9193b | 149 | } |
WiredHome | 0:61112ca9193b | 150 | } |
WiredHome | 0:61112ca9193b | 151 | |
WiredHome | 0:61112ca9193b | 152 | int16_t TimeInterface::get_tzo_min(void) |
WiredHome | 0:61112ca9193b | 153 | { |
WiredHome | 0:61112ca9193b | 154 | uint16_t th, tl; |
WiredHome | 0:61112ca9193b | 155 | |
WiredHome | 0:61112ca9193b | 156 | th = LPC_RTC->GPREG0 >> 16; |
WiredHome | 0:61112ca9193b | 157 | tl = LPC_RTC->GPREG0; |
WiredHome | 0:61112ca9193b | 158 | //printf("get_tzo() is %04X %04X\r\n", th, tl); |
WiredHome | 0:61112ca9193b | 159 | if ((uint16_t)(th + tl) == 0) { |
WiredHome | 0:61112ca9193b | 160 | return tl; |
WiredHome | 0:61112ca9193b | 161 | } else { |
WiredHome | 0:61112ca9193b | 162 | return 0; |
WiredHome | 0:61112ca9193b | 163 | } |
WiredHome | 0:61112ca9193b | 164 | } |
WiredHome | 0:61112ca9193b | 165 | |
WiredHome | 0:61112ca9193b | 166 | time_t TimeInterface::get_timelastset(void) |
WiredHome | 0:61112ca9193b | 167 | { |
WiredHome | 0:61112ca9193b | 168 | return LPC_RTC->GPREG1; |
WiredHome | 0:61112ca9193b | 169 | } |
WiredHome | 0:61112ca9193b | 170 | |
WiredHome | 0:61112ca9193b | 171 | int32_t TimeInterface::get_cal() { |
WiredHome | 0:61112ca9193b | 172 | int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF; |
WiredHome | 0:61112ca9193b | 173 | |
WiredHome | 0:61112ca9193b | 174 | if (calvalue & 0x20000) { |
WiredHome | 0:61112ca9193b | 175 | calvalue = -(calvalue & 0x1FFFF); |
WiredHome | 0:61112ca9193b | 176 | } |
WiredHome | 0:61112ca9193b | 177 | return calvalue; |
WiredHome | 0:61112ca9193b | 178 | } |
WiredHome | 0:61112ca9193b | 179 | |
WiredHome | 0:61112ca9193b | 180 | void TimeInterface::set_cal(int32_t calibration) { |
WiredHome | 0:61112ca9193b | 181 | if (calibration) { |
WiredHome | 0:61112ca9193b | 182 | if (calibration < 0) { |
WiredHome | 0:61112ca9193b | 183 | calibration = (-calibration & 0x1FFFF) | 0x20000; |
WiredHome | 0:61112ca9193b | 184 | } |
WiredHome | 0:61112ca9193b | 185 | LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it |
WiredHome | 0:61112ca9193b | 186 | } else { |
WiredHome | 0:61112ca9193b | 187 | LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it |
WiredHome | 0:61112ca9193b | 188 | } |
WiredHome | 0:61112ca9193b | 189 | LPC_RTC->CALIBRATION = calibration; |
WiredHome | 0:61112ca9193b | 190 | } |
WiredHome | 0:61112ca9193b | 191 | |
WiredHome | 0:61112ca9193b | 192 | bool TimeInterface::adjust_sec(int32_t adjustSeconds) |
WiredHome | 0:61112ca9193b | 193 | { |
WiredHome | 0:61112ca9193b | 194 | time_t lastSet = get_timelastset(); |
WiredHome | 0:61112ca9193b | 195 | |
WiredHome | 0:61112ca9193b | 196 | if (lastSet != 0) { |
WiredHome | 0:61112ca9193b | 197 | time_t seconds = time(NULL); // get "now" according to the rtc |
WiredHome | 0:61112ca9193b | 198 | int32_t delta = seconds - lastSet; |
WiredHome | 0:61112ca9193b | 199 | int32_t curCal = get_cal(); |
WiredHome | 0:61112ca9193b | 200 | int32_t calMAX = 131071; |
WiredHome | 0:61112ca9193b | 201 | int32_t secPerDay = 86400; |
WiredHome | 0:61112ca9193b | 202 | float errSecPerDay; |
WiredHome | 0:61112ca9193b | 203 | |
WiredHome | 0:61112ca9193b | 204 | // Convert the current calibration and the adjustment into |
WiredHome | 0:61112ca9193b | 205 | // the new calibration value |
WiredHome | 0:61112ca9193b | 206 | // assume it is +10sec and it has been 2days, then the adjustment |
WiredHome | 0:61112ca9193b | 207 | // needs to be +5 sec per day, or one adjustment every 1/5th |
WiredHome | 0:61112ca9193b | 208 | // of a day, or 1 adjustment every 86400/5 counts. |
WiredHome | 0:61112ca9193b | 209 | // delta = now - then (number of elapsed seconds) |
WiredHome | 0:61112ca9193b | 210 | if (adjustSeconds != 0 && delta != 0) { |
WiredHome | 0:61112ca9193b | 211 | int32_t calFactor; |
WiredHome | 0:61112ca9193b | 212 | |
WiredHome | 0:61112ca9193b | 213 | // Make the clock correct |
WiredHome | 0:61112ca9193b | 214 | seconds = seconds + adjustSeconds; |
WiredHome | 0:61112ca9193b | 215 | set_time(seconds); |
WiredHome | 0:61112ca9193b | 216 | // Compute the calibration factor |
WiredHome | 0:61112ca9193b | 217 | errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay); |
WiredHome | 0:61112ca9193b | 218 | calFactor = (int32_t)((float)secPerDay/errSecPerDay); |
WiredHome | 0:61112ca9193b | 219 | if (abs(calFactor) < calMAX) |
WiredHome | 0:61112ca9193b | 220 | set_cal(calFactor); |
WiredHome | 0:61112ca9193b | 221 | } |
WiredHome | 0:61112ca9193b | 222 | return true; |
WiredHome | 0:61112ca9193b | 223 | } else { |
WiredHome | 0:61112ca9193b | 224 | return false; |
WiredHome | 0:61112ca9193b | 225 | } |
WiredHome | 0:61112ca9193b | 226 | } |