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

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;
+    }
+}