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:
Thu Aug 06 11:13:47 2015 +0000
Revision:
5:a5f50b5fb856
Parent:
3:49f36b489b64
Child:
6:c79cfe750416
no functional change

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 3:49f36b489b64 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 5:a5f50b5fb856 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 3:49f36b489b64 60 void set_dst(bool dst)
WiredHome 3:49f36b489b64 61 {
WiredHome 3:49f36b489b64 62 (void)dst;
WiredHome 3:49f36b489b64 63 }
WiredHome 3:49f36b489b64 64
WiredHome 3:49f36b489b64 65 bool get_dst(void)
WiredHome 3:49f36b489b64 66 {
WiredHome 3:49f36b489b64 67 return false;
WiredHome 3:49f36b489b64 68 }
WiredHome 3:49f36b489b64 69
WiredHome 0:61112ca9193b 70 clock_t TimeInterface::clock(void)
WiredHome 0:61112ca9193b 71 {
WiredHome 0:61112ca9193b 72 return std::clock();
WiredHome 0:61112ca9193b 73 }
WiredHome 0:61112ca9193b 74
WiredHome 0:61112ca9193b 75 time_t TimeInterface::time(time_t* timer)
WiredHome 0:61112ca9193b 76 {
WiredHome 0:61112ca9193b 77 return std::time(timer);
WiredHome 0:61112ca9193b 78 }
WiredHome 0:61112ca9193b 79
WiredHome 1:2ee90f546f54 80 time_t TimeInterface::timelocal(time_t* timer)
WiredHome 1:2ee90f546f54 81 {
WiredHome 1:2ee90f546f54 82 return std::time(timer) + 60 * get_tzo_min();
WiredHome 1:2ee90f546f54 83 }
WiredHome 1:2ee90f546f54 84
WiredHome 0:61112ca9193b 85 char * TimeInterface::ctime(const time_t * timer)
WiredHome 0:61112ca9193b 86 {
WiredHome 0:61112ca9193b 87 char * p = std::ctime(timer);
WiredHome 0:61112ca9193b 88
WiredHome 0:61112ca9193b 89 if (strlen(p) < sizeof(result)) {
WiredHome 0:61112ca9193b 90 strcpy(result, p);
WiredHome 0:61112ca9193b 91 p = strchr(result, '\n');
WiredHome 0:61112ca9193b 92 if (p)
WiredHome 0:61112ca9193b 93 *p = '\0';
WiredHome 0:61112ca9193b 94 } else {
WiredHome 0:61112ca9193b 95 result[0] = '\0';
WiredHome 0:61112ca9193b 96 }
WiredHome 0:61112ca9193b 97 return result;
WiredHome 0:61112ca9193b 98 }
WiredHome 0:61112ca9193b 99
WiredHome 2:65e0a25c7551 100 char * TimeInterface::asctime(const struct tm_ex * timeptr)
WiredHome 0:61112ca9193b 101 {
WiredHome 0:61112ca9193b 102 static const char wday_name[][4] = {
WiredHome 0:61112ca9193b 103 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
WiredHome 0:61112ca9193b 104 };
WiredHome 0:61112ca9193b 105 static const char mon_name[][4] = {
WiredHome 0:61112ca9193b 106 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
WiredHome 0:61112ca9193b 107 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
WiredHome 0:61112ca9193b 108 };
WiredHome 0:61112ca9193b 109
WiredHome 0:61112ca9193b 110 sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
WiredHome 0:61112ca9193b 111 wday_name[timeptr->tm_wday % 7],
WiredHome 0:61112ca9193b 112 mon_name[timeptr->tm_mon % 12],
WiredHome 0:61112ca9193b 113 timeptr->tm_mday, timeptr->tm_hour,
WiredHome 0:61112ca9193b 114 timeptr->tm_min, timeptr->tm_sec,
WiredHome 0:61112ca9193b 115 1900 + timeptr->tm_year);
WiredHome 0:61112ca9193b 116 return result;
WiredHome 0:61112ca9193b 117 }
WiredHome 0:61112ca9193b 118
WiredHome 0:61112ca9193b 119 struct tm_ex * TimeInterface::gmtime(const time_t * timer)
WiredHome 0:61112ca9193b 120 {
WiredHome 0:61112ca9193b 121 time_t priv = *timer + (get_tzo_min() * 60);
WiredHome 0:61112ca9193b 122 struct tm * tmp = std::localtime(&priv);
WiredHome 0:61112ca9193b 123
WiredHome 0:61112ca9193b 124 tm_ext.tm_sec = tmp->tm_sec;
WiredHome 0:61112ca9193b 125 tm_ext.tm_min = tmp->tm_min;
WiredHome 0:61112ca9193b 126 tm_ext.tm_hour = tmp->tm_hour;
WiredHome 0:61112ca9193b 127 tm_ext.tm_mday = tmp->tm_mday;
WiredHome 0:61112ca9193b 128 tm_ext.tm_mon = tmp->tm_mon;
WiredHome 0:61112ca9193b 129 tm_ext.tm_year = tmp->tm_year;
WiredHome 0:61112ca9193b 130 tm_ext.tm_wday = tmp->tm_wday;
WiredHome 0:61112ca9193b 131 tm_ext.tm_yday = tmp->tm_yday;
WiredHome 0:61112ca9193b 132 tm_ext.tm_isdst = tmp->tm_isdst;
WiredHome 0:61112ca9193b 133 tm_ext.tm_tzo_min = get_tzo_min();
WiredHome 0:61112ca9193b 134 return &tm_ext;
WiredHome 0:61112ca9193b 135 }
WiredHome 0:61112ca9193b 136
WiredHome 0:61112ca9193b 137 struct tm_ex * TimeInterface::localtime(const time_t * timer)
WiredHome 0:61112ca9193b 138 {
WiredHome 0:61112ca9193b 139 struct tm * tmp = std::localtime(timer);
WiredHome 0:61112ca9193b 140
WiredHome 0:61112ca9193b 141 tm_ext.tm_sec = tmp->tm_sec;
WiredHome 0:61112ca9193b 142 tm_ext.tm_min = tmp->tm_min;
WiredHome 0:61112ca9193b 143 tm_ext.tm_hour = tmp->tm_hour;
WiredHome 0:61112ca9193b 144 tm_ext.tm_mday = tmp->tm_mday;
WiredHome 0:61112ca9193b 145 tm_ext.tm_mon = tmp->tm_mon;
WiredHome 0:61112ca9193b 146 tm_ext.tm_year = tmp->tm_year;
WiredHome 0:61112ca9193b 147 tm_ext.tm_wday = tmp->tm_wday;
WiredHome 0:61112ca9193b 148 tm_ext.tm_yday = tmp->tm_yday;
WiredHome 0:61112ca9193b 149 tm_ext.tm_isdst = tmp->tm_isdst;
WiredHome 0:61112ca9193b 150 tm_ext.tm_tzo_min = get_tzo_min();
WiredHome 0:61112ca9193b 151 return &tm_ext;
WiredHome 0:61112ca9193b 152 }
WiredHome 0:61112ca9193b 153
WiredHome 0:61112ca9193b 154 time_t TimeInterface::mktime(struct tm_ex * timeptr)
WiredHome 0:61112ca9193b 155 {
WiredHome 0:61112ca9193b 156 return std::mktime((struct tm *)timeptr);
WiredHome 0:61112ca9193b 157 }
WiredHome 0:61112ca9193b 158
WiredHome 0:61112ca9193b 159 size_t TimeInterface::strftime(char * ptr, size_t maxsize, const char * format, const struct tm_ex * timeptr)
WiredHome 0:61112ca9193b 160 {
WiredHome 0:61112ca9193b 161 return std::strftime(ptr, maxsize, format, (struct tm *)timeptr);
WiredHome 0:61112ca9193b 162 }
WiredHome 0:61112ca9193b 163
WiredHome 0:61112ca9193b 164 double TimeInterface::difftime(time_t end, time_t beginning)
WiredHome 0:61112ca9193b 165 {
WiredHome 0:61112ca9193b 166 return std::difftime(end, beginning);
WiredHome 0:61112ca9193b 167 }
WiredHome 0:61112ca9193b 168
WiredHome 0:61112ca9193b 169
WiredHome 0:61112ca9193b 170
WiredHome 0:61112ca9193b 171 // time zone functions
WiredHome 0:61112ca9193b 172
WiredHome 0:61112ca9193b 173 void TimeInterface::set_time(time_t t, int16_t tzo_min)
WiredHome 0:61112ca9193b 174 {
WiredHome 2:65e0a25c7551 175 time_t tval = t - (tzo_min * 60);
WiredHome 0:61112ca9193b 176 rtc_init();
WiredHome 0:61112ca9193b 177 rtc_write(tval);
WiredHome 0:61112ca9193b 178 LPC_RTC->GPREG1 = tval;
WiredHome 2:65e0a25c7551 179 INFO("set_time(%s)", ctime(&tval));
WiredHome 0:61112ca9193b 180 }
WiredHome 0:61112ca9193b 181
WiredHome 0:61112ca9193b 182 void TimeInterface::set_tzo_min(int16_t tzo_min)
WiredHome 0:61112ca9193b 183 {
WiredHome 0:61112ca9193b 184 uint16_t th;
WiredHome 0:61112ca9193b 185 uint32_t treg;
WiredHome 0:61112ca9193b 186
WiredHome 0:61112ca9193b 187 if (tzo_min >= -720 && tzo_min <= 720) {
WiredHome 0:61112ca9193b 188 th = (uint16_t)(-tzo_min);
WiredHome 0:61112ca9193b 189 treg = (th << 16) | (uint16_t)tzo_min;
WiredHome 0:61112ca9193b 190 LPC_RTC->GPREG0 = treg;
WiredHome 0:61112ca9193b 191 //printf("set_tzo(%d) %d is %08X\r\n", tzo, th, LPC_RTC->GPREG0);
WiredHome 0:61112ca9193b 192 }
WiredHome 0:61112ca9193b 193 }
WiredHome 0:61112ca9193b 194
WiredHome 0:61112ca9193b 195 int16_t TimeInterface::get_tzo_min(void)
WiredHome 0:61112ca9193b 196 {
WiredHome 0:61112ca9193b 197 uint16_t th, tl;
WiredHome 0:61112ca9193b 198
WiredHome 0:61112ca9193b 199 th = LPC_RTC->GPREG0 >> 16;
WiredHome 0:61112ca9193b 200 tl = LPC_RTC->GPREG0;
WiredHome 0:61112ca9193b 201 //printf("get_tzo() is %04X %04X\r\n", th, tl);
WiredHome 0:61112ca9193b 202 if ((uint16_t)(th + tl) == 0) {
WiredHome 0:61112ca9193b 203 return tl;
WiredHome 0:61112ca9193b 204 } else {
WiredHome 0:61112ca9193b 205 return 0;
WiredHome 0:61112ca9193b 206 }
WiredHome 0:61112ca9193b 207 }
WiredHome 0:61112ca9193b 208
WiredHome 0:61112ca9193b 209 time_t TimeInterface::get_timelastset(void)
WiredHome 0:61112ca9193b 210 {
WiredHome 0:61112ca9193b 211 return LPC_RTC->GPREG1;
WiredHome 0:61112ca9193b 212 }
WiredHome 0:61112ca9193b 213
WiredHome 0:61112ca9193b 214 int32_t TimeInterface::get_cal() {
WiredHome 0:61112ca9193b 215 int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF;
WiredHome 0:61112ca9193b 216
WiredHome 0:61112ca9193b 217 if (calvalue & 0x20000) {
WiredHome 0:61112ca9193b 218 calvalue = -(calvalue & 0x1FFFF);
WiredHome 0:61112ca9193b 219 }
WiredHome 0:61112ca9193b 220 return calvalue;
WiredHome 0:61112ca9193b 221 }
WiredHome 0:61112ca9193b 222
WiredHome 0:61112ca9193b 223 void TimeInterface::set_cal(int32_t calibration) {
WiredHome 0:61112ca9193b 224 if (calibration) {
WiredHome 0:61112ca9193b 225 if (calibration < 0) {
WiredHome 0:61112ca9193b 226 calibration = (-calibration & 0x1FFFF) | 0x20000;
WiredHome 0:61112ca9193b 227 }
WiredHome 0:61112ca9193b 228 LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it
WiredHome 0:61112ca9193b 229 } else {
WiredHome 0:61112ca9193b 230 LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it
WiredHome 0:61112ca9193b 231 }
WiredHome 0:61112ca9193b 232 LPC_RTC->CALIBRATION = calibration;
WiredHome 0:61112ca9193b 233 }
WiredHome 0:61112ca9193b 234
WiredHome 0:61112ca9193b 235 bool TimeInterface::adjust_sec(int32_t adjustSeconds)
WiredHome 0:61112ca9193b 236 {
WiredHome 0:61112ca9193b 237 time_t lastSet = get_timelastset();
WiredHome 0:61112ca9193b 238
WiredHome 0:61112ca9193b 239 if (lastSet != 0) {
WiredHome 0:61112ca9193b 240 time_t seconds = time(NULL); // get "now" according to the rtc
WiredHome 0:61112ca9193b 241 int32_t delta = seconds - lastSet;
WiredHome 5:a5f50b5fb856 242 //int32_t curCal = get_cal(); // calibration might want to leverage the current cal factor.
WiredHome 0:61112ca9193b 243 int32_t calMAX = 131071;
WiredHome 0:61112ca9193b 244 int32_t secPerDay = 86400;
WiredHome 0:61112ca9193b 245 float errSecPerDay;
WiredHome 0:61112ca9193b 246
WiredHome 0:61112ca9193b 247 // Convert the current calibration and the adjustment into
WiredHome 0:61112ca9193b 248 // the new calibration value
WiredHome 0:61112ca9193b 249 // assume it is +10sec and it has been 2days, then the adjustment
WiredHome 0:61112ca9193b 250 // needs to be +5 sec per day, or one adjustment every 1/5th
WiredHome 0:61112ca9193b 251 // of a day, or 1 adjustment every 86400/5 counts.
WiredHome 0:61112ca9193b 252 // delta = now - then (number of elapsed seconds)
WiredHome 0:61112ca9193b 253 if (adjustSeconds != 0 && delta != 0) {
WiredHome 0:61112ca9193b 254 int32_t calFactor;
WiredHome 0:61112ca9193b 255
WiredHome 0:61112ca9193b 256 // Make the clock correct
WiredHome 0:61112ca9193b 257 seconds = seconds + adjustSeconds;
WiredHome 0:61112ca9193b 258 set_time(seconds);
WiredHome 0:61112ca9193b 259 // Compute the calibration factor
WiredHome 0:61112ca9193b 260 errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay);
WiredHome 0:61112ca9193b 261 calFactor = (int32_t)((float)secPerDay/errSecPerDay);
WiredHome 0:61112ca9193b 262 if (abs(calFactor) < calMAX)
WiredHome 0:61112ca9193b 263 set_cal(calFactor);
WiredHome 0:61112ca9193b 264 }
WiredHome 0:61112ca9193b 265 return true;
WiredHome 0:61112ca9193b 266 } else {
WiredHome 0:61112ca9193b 267 return false;
WiredHome 0:61112ca9193b 268 }
WiredHome 0:61112ca9193b 269 }