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
Diff: TimeInterface.cpp
- Revision:
- 0:61112ca9193b
- Child:
- 1:2ee90f546f54
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TimeInterface.cpp Sun Jun 08 00:18:43 2014 +0000 @@ -0,0 +1,221 @@ + +#include "TimeInterface.h" + +#include "rtc_api.h" + +#ifdef WIN32 +// Fake it out for Win32 development and testing +struct LPC { + unsigned long CCR; // Clock Control register + unsigned long GPREG0; // General Purpose Register #0 - 32-bit Battery backed + unsigned long GPREG1; // General Purpose Register #1 - 32-bit Battery backed + unsigned long CALIBRATION; // Calibration Register +}; +struct LPC X; +struct LPC * LPC_RTC = &X; +#define set_time(x) (void)x +#endif + + +TimeInterface::TimeInterface() +{ +} + +TimeInterface::~TimeInterface() +{ +} + +clock_t TimeInterface::clock(void) +{ + return std::clock(); +} + +time_t TimeInterface::time(time_t* timer) +{ + return std::time(timer); +} + +char * TimeInterface::ctime(const time_t * timer) +{ + char * p = std::ctime(timer); + + if (strlen(p) < sizeof(result)) { + strcpy(result, p); + p = strchr(result, '\n'); + if (p) + *p = '\0'; + } else { + result[0] = '\0'; + } + return result; +} + +char * TimeInterface::asctime(const struct tm_ex *timeptr) +{ + static const char wday_name[][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d", + wday_name[timeptr->tm_wday % 7], + mon_name[timeptr->tm_mon % 12], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + 1900 + timeptr->tm_year); + return result; +} + +struct tm_ex * TimeInterface::gmtime(const time_t * timer) +{ + time_t priv = *timer + (get_tzo_min() * 60); + struct tm * tmp = std::localtime(&priv); + + tm_ext.tm_sec = tmp->tm_sec; + tm_ext.tm_min = tmp->tm_min; + tm_ext.tm_hour = tmp->tm_hour; + tm_ext.tm_mday = tmp->tm_mday; + tm_ext.tm_mon = tmp->tm_mon; + tm_ext.tm_year = tmp->tm_year; + tm_ext.tm_wday = tmp->tm_wday; + tm_ext.tm_yday = tmp->tm_yday; + tm_ext.tm_isdst = tmp->tm_isdst; + tm_ext.tm_tzo_min = get_tzo_min(); + return &tm_ext; +} + +struct tm_ex * TimeInterface::localtime(const time_t * timer) +{ + struct tm * tmp = std::localtime(timer); + + tm_ext.tm_sec = tmp->tm_sec; + tm_ext.tm_min = tmp->tm_min; + tm_ext.tm_hour = tmp->tm_hour; + tm_ext.tm_mday = tmp->tm_mday; + tm_ext.tm_mon = tmp->tm_mon; + tm_ext.tm_year = tmp->tm_year; + tm_ext.tm_wday = tmp->tm_wday; + tm_ext.tm_yday = tmp->tm_yday; + tm_ext.tm_isdst = tmp->tm_isdst; + tm_ext.tm_tzo_min = get_tzo_min(); + return &tm_ext; +} + +time_t TimeInterface::mktime(struct tm_ex * timeptr) +{ + return std::mktime((struct tm *)timeptr); +} + +size_t TimeInterface::strftime(char * ptr, size_t maxsize, const char * format, const struct tm_ex * timeptr) +{ + return std::strftime(ptr, maxsize, format, (struct tm *)timeptr); +} + +double TimeInterface::difftime(time_t end, time_t beginning) +{ + return std::difftime(end, beginning); +} + + + +// time zone functions + +void TimeInterface::set_time(time_t t, int16_t tzo_min) +{ + time_t tval = t - tzo_min; + rtc_init(); + rtc_write(tval); + LPC_RTC->GPREG1 = tval; +} + +void TimeInterface::set_tzo_min(int16_t tzo_min) +{ + uint16_t th; + uint32_t treg; + + if (tzo_min >= -720 && tzo_min <= 720) { + th = (uint16_t)(-tzo_min); + treg = (th << 16) | (uint16_t)tzo_min; + LPC_RTC->GPREG0 = treg; + //printf("set_tzo(%d) %d is %08X\r\n", tzo, th, LPC_RTC->GPREG0); + } +} + +int16_t TimeInterface::get_tzo_min(void) +{ + uint16_t th, tl; + + th = LPC_RTC->GPREG0 >> 16; + tl = LPC_RTC->GPREG0; + //printf("get_tzo() is %04X %04X\r\n", th, tl); + if ((uint16_t)(th + tl) == 0) { + return tl; + } else { + return 0; + } +} + +time_t TimeInterface::get_timelastset(void) +{ + return LPC_RTC->GPREG1; +} + +int32_t TimeInterface::get_cal() { + int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF; + + if (calvalue & 0x20000) { + calvalue = -(calvalue & 0x1FFFF); + } + return calvalue; +} + +void TimeInterface::set_cal(int32_t calibration) { + if (calibration) { + if (calibration < 0) { + calibration = (-calibration & 0x1FFFF) | 0x20000; + } + LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it + } else { + LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it + } + LPC_RTC->CALIBRATION = calibration; +} + +bool TimeInterface::adjust_sec(int32_t adjustSeconds) +{ + time_t lastSet = get_timelastset(); + + if (lastSet != 0) { + time_t seconds = time(NULL); // get "now" according to the rtc + int32_t delta = seconds - lastSet; + int32_t curCal = get_cal(); + int32_t calMAX = 131071; + int32_t secPerDay = 86400; + float errSecPerDay; + + // Convert the current calibration and the adjustment into + // the new calibration value + // assume it is +10sec and it has been 2days, then the adjustment + // needs to be +5 sec per day, or one adjustment every 1/5th + // of a day, or 1 adjustment every 86400/5 counts. + // delta = now - then (number of elapsed seconds) + if (adjustSeconds != 0 && delta != 0) { + int32_t calFactor; + + // Make the clock correct + seconds = seconds + adjustSeconds; + set_time(seconds); + // Compute the calibration factor + errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay); + calFactor = (int32_t)((float)secPerDay/errSecPerDay); + if (abs(calFactor) < calMAX) + set_cal(calFactor); + } + return true; + } else { + return false; + } +}