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.

Dependencies:   CalendarPage

Dependents:   CI-data-logger-server WattEye X10Svr SSDP_Server

Committer:
WiredHome
Date:
Sun Jun 22 21:00:01 2014 +0000
Revision:
2:65e0a25c7551
Parent:
1:2ee90f546f54
Child:
3:49f36b489b64
Revised the TimeInterface class to use NTP as is, not to modify it.

Who changed what in which revision?

UserRevisionLine numberNew 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 2:65e0a25c7551 6 #define DEBUG "Time"
WiredHome 2:65e0a25c7551 7 #include <cstdio>
WiredHome 2:65e0a25c7551 8 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 2:65e0a25c7551 9 #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:65e0a25c7551 10 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:65e0a25c7551 11 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:65e0a25c7551 12 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:65e0a25c7551 13 #else
WiredHome 2:65e0a25c7551 14 #define DBG(x, ...)
WiredHome 2:65e0a25c7551 15 #define WARN(x, ...)
WiredHome 2:65e0a25c7551 16 #define ERR(x, ...)
WiredHome 2:65e0a25c7551 17 #define INFO(x, ...)
WiredHome 2:65e0a25c7551 18 #endif
WiredHome 2:65e0a25c7551 19
WiredHome 0:61112ca9193b 20 #ifdef WIN32
WiredHome 0:61112ca9193b 21 // Fake it out for Win32 development and testing
WiredHome 0:61112ca9193b 22 struct LPC {
WiredHome 0:61112ca9193b 23 unsigned long CCR; // Clock Control register
WiredHome 0:61112ca9193b 24 unsigned long GPREG0; // General Purpose Register #0 - 32-bit Battery backed
WiredHome 0:61112ca9193b 25 unsigned long GPREG1; // General Purpose Register #1 - 32-bit Battery backed
WiredHome 0:61112ca9193b 26 unsigned long CALIBRATION; // Calibration Register
WiredHome 0:61112ca9193b 27 };
WiredHome 0:61112ca9193b 28 struct LPC X;
WiredHome 0:61112ca9193b 29 struct LPC * LPC_RTC = &X;
WiredHome 0:61112ca9193b 30 #define set_time(x) (void)x
WiredHome 0:61112ca9193b 31 #endif
WiredHome 0:61112ca9193b 32
WiredHome 0:61112ca9193b 33
WiredHome 0:61112ca9193b 34 TimeInterface::TimeInterface()
WiredHome 0:61112ca9193b 35 {
WiredHome 0:61112ca9193b 36 }
WiredHome 0:61112ca9193b 37
WiredHome 0:61112ca9193b 38 TimeInterface::~TimeInterface()
WiredHome 0:61112ca9193b 39 {
WiredHome 0:61112ca9193b 40 }
WiredHome 0:61112ca9193b 41
WiredHome 2:65e0a25c7551 42 NTPResult TimeInterface::setTime(const char* host, uint16_t port, uint32_t timeout)
WiredHome 2:65e0a25c7551 43 {
WiredHome 2:65e0a25c7551 44 NTPClient ntp;
WiredHome 2:65e0a25c7551 45 NTPResult res;
WiredHome 2:65e0a25c7551 46 int16_t tzomin = get_tzo_min();
WiredHome 2:65e0a25c7551 47 INFO("setTime(%s, %d, %d) %d\r\n", host, port, timeout, tzomin);
WiredHome 2:65e0a25c7551 48 res = ntp.setTime(host, port, timeout);
WiredHome 2:65e0a25c7551 49 INFO(" ret: %d\r\n", res);
WiredHome 2:65e0a25c7551 50 if (res == NTP_OK) {
WiredHome 2:65e0a25c7551 51 // if the time was fetched successfully, then
WiredHome 2:65e0a25c7551 52 // let's save the time last set with the local tzo applied
WiredHome 2:65e0a25c7551 53 // and this saves the last time set for later precision
WiredHome 2:65e0a25c7551 54 // tuning.
WiredHome 2:65e0a25c7551 55 set_time(std::time(NULL));
WiredHome 2:65e0a25c7551 56 }
WiredHome 2:65e0a25c7551 57 return res;
WiredHome 2:65e0a25c7551 58 }
WiredHome 2:65e0a25c7551 59
WiredHome 0:61112ca9193b 60 clock_t TimeInterface::clock(void)
WiredHome 0:61112ca9193b 61 {
WiredHome 0:61112ca9193b 62 return std::clock();
WiredHome 0:61112ca9193b 63 }
WiredHome 0:61112ca9193b 64
WiredHome 0:61112ca9193b 65 time_t TimeInterface::time(time_t* timer)
WiredHome 0:61112ca9193b 66 {
WiredHome 0:61112ca9193b 67 return std::time(timer);
WiredHome 0:61112ca9193b 68 }
WiredHome 0:61112ca9193b 69
WiredHome 1:2ee90f546f54 70 time_t TimeInterface::timelocal(time_t* timer)
WiredHome 1:2ee90f546f54 71 {
WiredHome 1:2ee90f546f54 72 return std::time(timer) + 60 * get_tzo_min();
WiredHome 1:2ee90f546f54 73 }
WiredHome 1:2ee90f546f54 74
WiredHome 0:61112ca9193b 75 char * TimeInterface::ctime(const time_t * timer)
WiredHome 0:61112ca9193b 76 {
WiredHome 0:61112ca9193b 77 char * p = std::ctime(timer);
WiredHome 0:61112ca9193b 78
WiredHome 0:61112ca9193b 79 if (strlen(p) < sizeof(result)) {
WiredHome 0:61112ca9193b 80 strcpy(result, p);
WiredHome 0:61112ca9193b 81 p = strchr(result, '\n');
WiredHome 0:61112ca9193b 82 if (p)
WiredHome 0:61112ca9193b 83 *p = '\0';
WiredHome 0:61112ca9193b 84 } else {
WiredHome 0:61112ca9193b 85 result[0] = '\0';
WiredHome 0:61112ca9193b 86 }
WiredHome 0:61112ca9193b 87 return result;
WiredHome 0:61112ca9193b 88 }
WiredHome 0:61112ca9193b 89
WiredHome 2:65e0a25c7551 90 char * TimeInterface::asctime(const struct tm_ex * timeptr)
WiredHome 0:61112ca9193b 91 {
WiredHome 0:61112ca9193b 92 static const char wday_name[][4] = {
WiredHome 0:61112ca9193b 93 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
WiredHome 0:61112ca9193b 94 };
WiredHome 0:61112ca9193b 95 static const char mon_name[][4] = {
WiredHome 0:61112ca9193b 96 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
WiredHome 0:61112ca9193b 97 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
WiredHome 0:61112ca9193b 98 };
WiredHome 0:61112ca9193b 99
WiredHome 0:61112ca9193b 100 sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
WiredHome 0:61112ca9193b 101 wday_name[timeptr->tm_wday % 7],
WiredHome 0:61112ca9193b 102 mon_name[timeptr->tm_mon % 12],
WiredHome 0:61112ca9193b 103 timeptr->tm_mday, timeptr->tm_hour,
WiredHome 0:61112ca9193b 104 timeptr->tm_min, timeptr->tm_sec,
WiredHome 0:61112ca9193b 105 1900 + timeptr->tm_year);
WiredHome 0:61112ca9193b 106 return result;
WiredHome 0:61112ca9193b 107 }
WiredHome 0:61112ca9193b 108
WiredHome 0:61112ca9193b 109 struct tm_ex * TimeInterface::gmtime(const time_t * timer)
WiredHome 0:61112ca9193b 110 {
WiredHome 0:61112ca9193b 111 time_t priv = *timer + (get_tzo_min() * 60);
WiredHome 0:61112ca9193b 112 struct tm * tmp = std::localtime(&priv);
WiredHome 0:61112ca9193b 113
WiredHome 0:61112ca9193b 114 tm_ext.tm_sec = tmp->tm_sec;
WiredHome 0:61112ca9193b 115 tm_ext.tm_min = tmp->tm_min;
WiredHome 0:61112ca9193b 116 tm_ext.tm_hour = tmp->tm_hour;
WiredHome 0:61112ca9193b 117 tm_ext.tm_mday = tmp->tm_mday;
WiredHome 0:61112ca9193b 118 tm_ext.tm_mon = tmp->tm_mon;
WiredHome 0:61112ca9193b 119 tm_ext.tm_year = tmp->tm_year;
WiredHome 0:61112ca9193b 120 tm_ext.tm_wday = tmp->tm_wday;
WiredHome 0:61112ca9193b 121 tm_ext.tm_yday = tmp->tm_yday;
WiredHome 0:61112ca9193b 122 tm_ext.tm_isdst = tmp->tm_isdst;
WiredHome 0:61112ca9193b 123 tm_ext.tm_tzo_min = get_tzo_min();
WiredHome 0:61112ca9193b 124 return &tm_ext;
WiredHome 0:61112ca9193b 125 }
WiredHome 0:61112ca9193b 126
WiredHome 0:61112ca9193b 127 struct tm_ex * TimeInterface::localtime(const time_t * timer)
WiredHome 0:61112ca9193b 128 {
WiredHome 0:61112ca9193b 129 struct tm * tmp = std::localtime(timer);
WiredHome 0:61112ca9193b 130
WiredHome 0:61112ca9193b 131 tm_ext.tm_sec = tmp->tm_sec;
WiredHome 0:61112ca9193b 132 tm_ext.tm_min = tmp->tm_min;
WiredHome 0:61112ca9193b 133 tm_ext.tm_hour = tmp->tm_hour;
WiredHome 0:61112ca9193b 134 tm_ext.tm_mday = tmp->tm_mday;
WiredHome 0:61112ca9193b 135 tm_ext.tm_mon = tmp->tm_mon;
WiredHome 0:61112ca9193b 136 tm_ext.tm_year = tmp->tm_year;
WiredHome 0:61112ca9193b 137 tm_ext.tm_wday = tmp->tm_wday;
WiredHome 0:61112ca9193b 138 tm_ext.tm_yday = tmp->tm_yday;
WiredHome 0:61112ca9193b 139 tm_ext.tm_isdst = tmp->tm_isdst;
WiredHome 0:61112ca9193b 140 tm_ext.tm_tzo_min = get_tzo_min();
WiredHome 0:61112ca9193b 141 return &tm_ext;
WiredHome 0:61112ca9193b 142 }
WiredHome 0:61112ca9193b 143
WiredHome 0:61112ca9193b 144 time_t TimeInterface::mktime(struct tm_ex * timeptr)
WiredHome 0:61112ca9193b 145 {
WiredHome 0:61112ca9193b 146 return std::mktime((struct tm *)timeptr);
WiredHome 0:61112ca9193b 147 }
WiredHome 0:61112ca9193b 148
WiredHome 0:61112ca9193b 149 size_t TimeInterface::strftime(char * ptr, size_t maxsize, const char * format, const struct tm_ex * timeptr)
WiredHome 0:61112ca9193b 150 {
WiredHome 0:61112ca9193b 151 return std::strftime(ptr, maxsize, format, (struct tm *)timeptr);
WiredHome 0:61112ca9193b 152 }
WiredHome 0:61112ca9193b 153
WiredHome 0:61112ca9193b 154 double TimeInterface::difftime(time_t end, time_t beginning)
WiredHome 0:61112ca9193b 155 {
WiredHome 0:61112ca9193b 156 return std::difftime(end, beginning);
WiredHome 0:61112ca9193b 157 }
WiredHome 0:61112ca9193b 158
WiredHome 0:61112ca9193b 159
WiredHome 0:61112ca9193b 160
WiredHome 0:61112ca9193b 161 // time zone functions
WiredHome 0:61112ca9193b 162
WiredHome 0:61112ca9193b 163 void TimeInterface::set_time(time_t t, int16_t tzo_min)
WiredHome 0:61112ca9193b 164 {
WiredHome 2:65e0a25c7551 165 time_t tval = t - (tzo_min * 60);
WiredHome 0:61112ca9193b 166 rtc_init();
WiredHome 0:61112ca9193b 167 rtc_write(tval);
WiredHome 0:61112ca9193b 168 LPC_RTC->GPREG1 = tval;
WiredHome 2:65e0a25c7551 169 INFO("set_time(%s)", ctime(&tval));
WiredHome 0:61112ca9193b 170 }
WiredHome 0:61112ca9193b 171
WiredHome 0:61112ca9193b 172 void TimeInterface::set_tzo_min(int16_t tzo_min)
WiredHome 0:61112ca9193b 173 {
WiredHome 0:61112ca9193b 174 uint16_t th;
WiredHome 0:61112ca9193b 175 uint32_t treg;
WiredHome 0:61112ca9193b 176
WiredHome 0:61112ca9193b 177 if (tzo_min >= -720 && tzo_min <= 720) {
WiredHome 0:61112ca9193b 178 th = (uint16_t)(-tzo_min);
WiredHome 0:61112ca9193b 179 treg = (th << 16) | (uint16_t)tzo_min;
WiredHome 0:61112ca9193b 180 LPC_RTC->GPREG0 = treg;
WiredHome 0:61112ca9193b 181 //printf("set_tzo(%d) %d is %08X\r\n", tzo, th, LPC_RTC->GPREG0);
WiredHome 0:61112ca9193b 182 }
WiredHome 0:61112ca9193b 183 }
WiredHome 0:61112ca9193b 184
WiredHome 0:61112ca9193b 185 int16_t TimeInterface::get_tzo_min(void)
WiredHome 0:61112ca9193b 186 {
WiredHome 0:61112ca9193b 187 uint16_t th, tl;
WiredHome 0:61112ca9193b 188
WiredHome 0:61112ca9193b 189 th = LPC_RTC->GPREG0 >> 16;
WiredHome 0:61112ca9193b 190 tl = LPC_RTC->GPREG0;
WiredHome 0:61112ca9193b 191 //printf("get_tzo() is %04X %04X\r\n", th, tl);
WiredHome 0:61112ca9193b 192 if ((uint16_t)(th + tl) == 0) {
WiredHome 0:61112ca9193b 193 return tl;
WiredHome 0:61112ca9193b 194 } else {
WiredHome 0:61112ca9193b 195 return 0;
WiredHome 0:61112ca9193b 196 }
WiredHome 0:61112ca9193b 197 }
WiredHome 0:61112ca9193b 198
WiredHome 0:61112ca9193b 199 time_t TimeInterface::get_timelastset(void)
WiredHome 0:61112ca9193b 200 {
WiredHome 0:61112ca9193b 201 return LPC_RTC->GPREG1;
WiredHome 0:61112ca9193b 202 }
WiredHome 0:61112ca9193b 203
WiredHome 0:61112ca9193b 204 int32_t TimeInterface::get_cal() {
WiredHome 0:61112ca9193b 205 int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF;
WiredHome 0:61112ca9193b 206
WiredHome 0:61112ca9193b 207 if (calvalue & 0x20000) {
WiredHome 0:61112ca9193b 208 calvalue = -(calvalue & 0x1FFFF);
WiredHome 0:61112ca9193b 209 }
WiredHome 0:61112ca9193b 210 return calvalue;
WiredHome 0:61112ca9193b 211 }
WiredHome 0:61112ca9193b 212
WiredHome 0:61112ca9193b 213 void TimeInterface::set_cal(int32_t calibration) {
WiredHome 0:61112ca9193b 214 if (calibration) {
WiredHome 0:61112ca9193b 215 if (calibration < 0) {
WiredHome 0:61112ca9193b 216 calibration = (-calibration & 0x1FFFF) | 0x20000;
WiredHome 0:61112ca9193b 217 }
WiredHome 0:61112ca9193b 218 LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it
WiredHome 0:61112ca9193b 219 } else {
WiredHome 0:61112ca9193b 220 LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it
WiredHome 0:61112ca9193b 221 }
WiredHome 0:61112ca9193b 222 LPC_RTC->CALIBRATION = calibration;
WiredHome 0:61112ca9193b 223 }
WiredHome 0:61112ca9193b 224
WiredHome 0:61112ca9193b 225 bool TimeInterface::adjust_sec(int32_t adjustSeconds)
WiredHome 0:61112ca9193b 226 {
WiredHome 0:61112ca9193b 227 time_t lastSet = get_timelastset();
WiredHome 0:61112ca9193b 228
WiredHome 0:61112ca9193b 229 if (lastSet != 0) {
WiredHome 0:61112ca9193b 230 time_t seconds = time(NULL); // get "now" according to the rtc
WiredHome 0:61112ca9193b 231 int32_t delta = seconds - lastSet;
WiredHome 0:61112ca9193b 232 int32_t curCal = get_cal();
WiredHome 0:61112ca9193b 233 int32_t calMAX = 131071;
WiredHome 0:61112ca9193b 234 int32_t secPerDay = 86400;
WiredHome 0:61112ca9193b 235 float errSecPerDay;
WiredHome 0:61112ca9193b 236
WiredHome 0:61112ca9193b 237 // Convert the current calibration and the adjustment into
WiredHome 0:61112ca9193b 238 // the new calibration value
WiredHome 0:61112ca9193b 239 // assume it is +10sec and it has been 2days, then the adjustment
WiredHome 0:61112ca9193b 240 // needs to be +5 sec per day, or one adjustment every 1/5th
WiredHome 0:61112ca9193b 241 // of a day, or 1 adjustment every 86400/5 counts.
WiredHome 0:61112ca9193b 242 // delta = now - then (number of elapsed seconds)
WiredHome 0:61112ca9193b 243 if (adjustSeconds != 0 && delta != 0) {
WiredHome 0:61112ca9193b 244 int32_t calFactor;
WiredHome 0:61112ca9193b 245
WiredHome 0:61112ca9193b 246 // Make the clock correct
WiredHome 0:61112ca9193b 247 seconds = seconds + adjustSeconds;
WiredHome 0:61112ca9193b 248 set_time(seconds);
WiredHome 0:61112ca9193b 249 // Compute the calibration factor
WiredHome 0:61112ca9193b 250 errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay);
WiredHome 0:61112ca9193b 251 calFactor = (int32_t)((float)secPerDay/errSecPerDay);
WiredHome 0:61112ca9193b 252 if (abs(calFactor) < calMAX)
WiredHome 0:61112ca9193b 253 set_cal(calFactor);
WiredHome 0:61112ca9193b 254 }
WiredHome 0:61112ca9193b 255 return true;
WiredHome 0:61112ca9193b 256 } else {
WiredHome 0:61112ca9193b 257 return false;
WiredHome 0:61112ca9193b 258 }
WiredHome 0:61112ca9193b 259 }