Simple time management w/o the Network interface

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Fri Oct 11 20:53:30 2019 +0000
Child:
1:b78c91e34eda
Commit message:
Simplify as a library

Changed in this revision

TimeInterface.cpp Show annotated file Show diff for this revision Revisions of this file
TimeInterface.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TimeInterface.cpp	Fri Oct 11 20:53:30 2019 +0000
@@ -0,0 +1,763 @@
+
+#include "TimeInterface.h"
+
+#include "rtc_api.h"
+
+//#define DEBUG "Time"
+#include <cstdio>
+#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
+#define DBG(x, ...)  std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#else
+#define DBG(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define INFO(x, ...)
+#endif
+
+#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(void *net)
+{
+    m_net = net;
+    dst = false;
+    memset(&dst_pair, 0, sizeof(dst_pair));  // that's enough to keep it from running
+}
+
+TimeInterface::~TimeInterface()
+{
+}
+
+#if 0
+NTPResult TimeInterface::setTime(const char* host, uint16_t port, uint32_t timeout)
+{
+    NTPResult res;
+    
+    if (m_net) {
+        NTPClient ntp(m_net);
+        // int16_t tzomin = get_tzo_min();
+        INFO("setTime(%s, %d, %d)\r\n", host, port, timeout);
+        res = ntp.setTime(host, port, timeout);
+        INFO("  ret: %d\r\n", res);
+        if (res == NTP_OK) {
+            // if the time was fetched successfully, then
+            // let's save the time last set with the local tzo applied
+            // and this saves the last time set for later precision
+            // tuning.
+            set_time(std::time(NULL));
+        }
+    } else {
+        ERR("No connection");
+        res = NTP_CONN;
+    }
+    return res;
+}
+#endif
+
+bool TimeInterface::parseDSTstring(TimeInterface::dst_event_t * result, const char * dstr)
+{
+    int x;
+    dst_event_t test_dst;
+
+    x = atoi(dstr);
+    if (x >= 1 && x <= 12) {
+        test_dst.MM = x;
+        dstr = strchr(dstr, '/');
+        if (dstr++) {
+            x = atoi(dstr);
+            if (x >= 1 && x <= 31) {
+                test_dst.DD = x;
+                dstr = strchr(dstr, ',');
+                if (dstr++) {
+                    x = atoi(dstr);
+                    if (x >= 0 && x <= 23) {
+                        test_dst.hh = x;
+                        dstr = strchr(dstr, ':');
+                        if (dstr++) {
+                            x = atoi(dstr);
+                            if (x >= 0 && x <= 59) {
+                                test_dst.mm = x;
+                                memcpy(result, &test_dst, sizeof(dst_event_t));
+                                INFO("parsed: %d/%d %d:%02d", test_dst.MM, test_dst.DD, test_dst.hh, test_dst.mm);
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
+// parse MM/DD,hh:mm
+bool TimeInterface::set_dst(const char * dstStart, const char * dstStop)
+{
+    dst_event_pair_t test_pair;
+
+    if (parseDSTstring(&test_pair.dst_start, dstStart)
+    && parseDSTstring(&test_pair.dst_stop, dstStop)) {
+        memcpy(&dst_pair, &test_pair, sizeof(dst_event_pair_t));
+        INFO("set_dst from (%s,%s)", dstStart, dstStop);
+        return true;
+    }
+    WARN("failed to set_dst from (%s,%s)", dstStart, dstStop);
+    return false;
+}
+
+bool TimeInterface::set_dst(bool isdst)
+{
+    dst = isdst;
+    return true;
+}
+
+bool TimeInterface::get_dst(void)
+{
+    return dst;
+}
+
+clock_t TimeInterface::clock(void)
+{
+    return std::clock();
+}
+
+time_t TimeInterface::time(time_t * timer)
+{
+    return std::time(timer);
+}
+
+uint32_t TimeInterface::minutesSinceJan(int mon, int day, int hr, int min)
+{
+    return (mon * 60 * 24 * 31) + (day * 60 * 24) + (hr * 60) + min;
+}
+
+time_t TimeInterface::timelocal(time_t * timer)
+{
+    time_t privTime;
+    struct tm * tminfo;
+
+    if (dst_pair.dst_start.MM) {    // may have to change the dst
+        std::time(&privTime);
+        tminfo = std::localtime(&privTime);
+
+        uint32_t min_since_jan = minutesSinceJan(tminfo->tm_mon + 1, tminfo->tm_mday, tminfo->tm_hour, tminfo->tm_min);
+        uint32_t min_dst_start = minutesSinceJan(dst_pair.dst_start.MM, dst_pair.dst_start.DD, dst_pair.dst_start.hh, dst_pair.dst_start.mm) + get_tzo_min();
+        uint32_t min_dst_stop  = minutesSinceJan(dst_pair.dst_stop.MM, dst_pair.dst_stop.DD, dst_pair.dst_stop.hh, dst_pair.dst_stop.mm) + get_tzo_min();
+
+        if (min_since_jan >= min_dst_start && min_since_jan < min_dst_stop) {
+            dst = 1;
+            //INFO(" is dst: %u - %u - %u", min_since_jan, min_dst_start, min_dst_stop);
+        } else {
+            dst = 0;
+            //INFO("not dst: %u - %u - %u", min_since_jan, min_dst_start, min_dst_stop);
+        }
+    }
+    INFO(" timelocal: %u, %d, %d", std::time(timer), get_tzo_min(), dst);
+    return std::time(timer) + get_tzo_min() * 60 + dst * 3600;
+}
+
+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"
+    };
+    struct tm_ex tmp = *timeptr;
+    
+    tmp.tm_min += tmp.tm_tzo_min;
+    if (tmp.tm_isdst)
+        tmp.tm_min += 60;
+    while (tmp.tm_min >= 60) {
+        tmp.tm_min -= 60;
+        tmp.tm_hour++;
+    }
+    while (tmp.tm_min < 0) {
+        tmp.tm_min += 60;
+        tmp.tm_hour--;
+    }
+    while (tmp.tm_hour >= 24) {
+        tmp.tm_wday = (tmp.tm_wday + 1) % 7;
+        tmp.tm_mday++;
+        tmp.tm_hour -= 24;
+    }
+    while (tmp.tm_hour < 0) {
+        tmp.tm_wday = (tmp.tm_wday + 6) % 7;
+        tmp.tm_mday--;
+        tmp.tm_hour += 24;
+    }
+    sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
+            wday_name[tmp.tm_wday % 7],
+            mon_name[tmp.tm_mon % 12],
+            tmp.tm_mday, tmp.tm_hour,
+            tmp.tm_min, tmp.tm_sec,
+            1900 + tmp.tm_year);
+    return result;
+}
+
+struct tm_ex * TimeInterface::gmtime(const time_t * timer)
+{
+    time_t priv = *timer + get_tzo_min() * 60 + dst * 3600;
+    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)
+{
+    timeptr->tm_tzo_min = get_tzo_min();
+    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 * 60);
+    rtc_init();
+    rtc_write(tval);
+    LPC_RTC->GPREG1 = tval;
+    INFO("set_time(%s)", ctime(&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();   // calibration might want to leverage the current cal factor.
+        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;
+    }
+}
+
+
+// #############################################################################
+/*
+ * Enhancement to use a custom tm_ex struct and the time zone by D. Smart
+ *  %Z
+ *
+ * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgement:
+ *      This product includes software developed by Powerdog Industries.
+ * 4. The name of Powerdog Industries may not be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
+
+struct dtconv {
+    char    *abbrev_month_names[12];
+    char    *month_names[12];
+    char    *abbrev_weekday_names[7];
+    char    *weekday_names[7];
+    char    *time_format;
+    char    *sdate_format;
+    char    *dtime_format;
+    char    *am_string;
+    char    *pm_string;
+    char    *ldate_format;
+    char    *zone_names[10];
+    int8_t  zone_offsets[10];
+};
+
+static const struct dtconv    En_US = {
+    {
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+    },
+    {
+        "January", "February", "March", "April",
+        "May", "June", "July", "August",
+        "September", "October", "November", "December"
+    },
+    { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
+    {
+        "Sunday", "Monday", "Tuesday", "Wednesday",
+        "Thursday", "Friday", "Saturday"
+    },
+    "%H:%M:%S",
+    "%m/%d/%y",
+    "%a %b %e %T %Z %Y",
+    "AM",
+    "PM",
+    "%A, %B, %e, %Y",
+    { "UTC", "EST", "CST", "MST", "PST", "YST", "CAT", "HST", "CET", "EET", },
+    {     0,    -5,    -6,    -7,    -8,    -9,   -10,   -10,    +1,    +2, },
+};
+
+
+#ifndef isprint
+#define in_range(c, lo, up)  ((uint8_t)c >= lo && (uint8_t)c <= up)
+#define isprint(c)           in_range(c, 0x20, 0x7f)
+#define isdigit(c)           in_range(c, '0', '9')
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c)           in_range(c, 'a', 'z')
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#endif
+
+
+const char * TimeInterface::strptime(const char *buf, char *fmt, struct tm_ex *tm)
+{
+    char c, *ptr;
+    int i, len;
+    bool fSet_wday = false;     // so we can notice if the wday was set
+    
+    ptr = fmt;
+    while (*ptr != 0) {
+        if (*buf == 0)
+            break;
+
+        c = *ptr++;
+
+        if (c != '%') {
+            if (isspace(c))
+                while (*buf != 0 && isspace(*buf))
+                    buf++;
+            else if (c != *buf++)
+                return 0;
+            continue;
+        }
+
+        c = *ptr++;
+        switch (c) {
+            case 0:
+            case '%':
+                if (*buf++ != '%')
+                    return 0;
+                break;
+
+            case 'C':
+                buf = strptime(buf, En_US.ldate_format, tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'c':
+                buf = strptime(buf, "%x %X", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'D':
+                buf = strptime(buf, "%m/%d/%y", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'R':
+                buf = strptime(buf, "%H:%M", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'r':
+                buf = strptime(buf, "%I:%M:%S %p", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'T':
+                buf = strptime(buf, "%H:%M:%S", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'X':
+                buf = strptime(buf, En_US.time_format, tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'x':
+                buf = strptime(buf, En_US.sdate_format, tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'j':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i > 365)
+                    return 0;
+
+                tm->tm_yday = i;
+                break;
+
+            case 'M':
+            case 'S':
+                if (*buf == 0 || isspace(*buf))
+                    break;
+
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i > 59)
+                    return 0;
+
+                if (c == 'M')
+                    tm->tm_min = i;
+                else
+                    tm->tm_sec = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'H':
+            case 'I':
+            case 'k':
+            case 'l':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (c == 'H' || c == 'k') {
+                    if (i > 23)
+                        return 0;
+                } else if (i > 11)
+                    return 0;
+
+                tm->tm_hour = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'p':
+                len = strlen(En_US.am_string);
+                if (strncasecmp(buf, En_US.am_string, len) == 0) {
+                    if (tm->tm_hour > 12)
+                        return 0;
+                    if (tm->tm_hour == 12)
+                        tm->tm_hour = 0;
+                    buf += len;
+                    break;
+                }
+
+                len = strlen(En_US.pm_string);
+                if (strncasecmp(buf, En_US.pm_string, len) == 0) {
+                    if (tm->tm_hour > 12)
+                        return 0;
+                    if (tm->tm_hour != 12)
+                        tm->tm_hour += 12;
+                    buf += len;
+                    break;
+                }
+
+                return 0;
+
+            case 'A':
+            case 'a':
+                for (i = 0; i < asizeof(En_US.weekday_names); i++) {
+                    len = strlen(En_US.weekday_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.weekday_names[i],
+                                    len) == 0)
+                        break;
+
+                    len = strlen(En_US.abbrev_weekday_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.abbrev_weekday_names[i],
+                                    len) == 0)
+                        break;
+                }
+                if (i == asizeof(En_US.weekday_names))
+                    return 0;
+                fSet_wday = true;
+                tm->tm_wday = i;
+                buf += len;
+                break;
+
+            case 'd':
+            case 'e':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i > 31)
+                    return 0;
+
+                tm->tm_mday = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'B':
+            case 'b':
+            case 'h':
+                for (i = 0; i < asizeof(En_US.month_names); i++) {
+                    len = strlen(En_US.month_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.month_names[i],
+                                    len) == 0)
+                        break;
+
+                    len = strlen(En_US.abbrev_month_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.abbrev_month_names[i],
+                                    len) == 0)
+                        break;
+                }
+                if (i == asizeof(En_US.month_names))
+                    return 0;
+
+                tm->tm_mon = i;
+                buf += len;
+                break;
+
+            case 'm':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i < 1 || i > 12)
+                    return 0;
+
+                tm->tm_mon = i - 1;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'Y':
+            case 'y':
+                if (*buf == 0 || isspace(*buf))
+                    break;
+
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (c == 'Y')
+                    i -= 1900;
+                if (i < 0)
+                    return 0;
+
+                tm->tm_year = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+            case 'Z':
+                for (i = 0; i < asizeof(En_US.zone_names); i++) {
+                    len = strlen(En_US.zone_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.zone_names[i],
+                                    len) == 0)
+                        break;
+                }
+                if (i == asizeof(En_US.zone_names))
+                    return 0;
+                tm->tm_tzo_min = En_US.zone_offsets[i] * 60;
+                buf += len;
+                break;
+        }
+    }
+    if (!fSet_wday) {
+        if (mktime(tm) == (time_t)-1)
+            tm->tm_wday = 7;
+    }
+    return buf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TimeInterface.h	Fri Oct 11 20:53:30 2019 +0000
@@ -0,0 +1,594 @@
+
+#ifndef TIMEINTERFACE_H
+#define TIMEINTERFACE_H
+#include "mbed.h"
+#include <ctime>
+
+//#include "NTPClient.h"
+
+// Special Registers and their usage:
+// GPREG0: 32 bits
+//      low word: time zone offset (-720 to +720)
+//      high word: 2's complement of low word for integrity checking
+// GPREG1: 32 bits
+//      time_t value when the clock was last set
+
+
+extern "C" {
+#include "time.h"       // uses some std::time-functions
+}
+
+/// The tm_ex structure is patterned after the traditional tm struct, however
+/// it adds an element - the time zone offset in minutes. From this, it is then
+/// readily able to create a "local time" instead of simply a UTC time.
+///
+struct tm_ex
+{
+    int   tm_sec;       ///<! seconds, 0 to 59.
+    int   tm_min;       ///<! minutes, 0 to 59.
+    int   tm_hour;      ///<! hours,   0 to 23.
+    int   tm_mday;      ///<! monthday 1 to 31.
+    int   tm_mon;       ///<! month    0 to 11.
+    int   tm_year;      ///<! years since 1900.
+    int   tm_wday;      ///<! days since sunday 0 to 6.
+    int   tm_yday;      ///<! days since 1 Jan 0 to 365.
+    int   tm_isdst;     ///<! is daylight savings time.
+    int   tm_tzo_min;   ///<! localtime zone offset in minutes (_ex element)
+};
+
+/// TimeInterface class is much like the normal c-style time.h interface, but
+/// is extended with time-zone support, and clock-adjustment support (which 
+/// permits tuning the clock) for more accuracy. 
+///
+/// Additionally, strptime was integrated, which can extract the time from
+/// a text string. A formatter is used, so it cannot parse an arbitrary string.
+///
+/// Within this class are the normal time.h methods, simply
+/// exposed here for one consistent interface.
+///
+/// @note This class uses the special battery backed registers
+///     GPREG0 and GPREG1 for TimeInterface data.
+///
+/// @note In mbed library ver 84, the gmtime method is defective,
+///     and calls to this function return junk data. The 
+///     gmtime method in this library actually uses localtime,
+///     but manages the time-zone offset as it does so.
+///
+/// @code
+/// // TimeInterface Architecture and APIs
+/// //
+/// // +--------+
+/// // | clock  |----> clock_t clock()
+/// // +--------+
+/// // 
+/// // +--------+
+/// // |        |<------------ setTime(char * server, uint16_t port, uint32_t timeout)
+/// // | NTP    |<-----------> Ethernet
+/// // |        |----+
+/// // +--------+    |
+/// //               |
+/// // +--------+    |
+/// // | RTC    |<---+-------- set_time(time_t t, int16_t tzo)
+/// // |        |<------------ adjust_sec(int32_t)
+/// // |        |<------------ set_cal(int32_t)
+/// // |        |------------> int32_t get_cal()
+/// // |        |------------> time_t time(time_t *)
+/// // |        |------+
+/// // +--------+      |
+/// //                 |  
+/// // +--------+      |
+/// // |        |<---- | <---- set_dst(bool dst)
+/// // |        |<---- | <---- set_dst(char * start_dst, char * end_dst)
+/// // |        |----- | ----> bool get_dst()
+/// // |dst_pair|---+  |  +----------+
+/// // +--------+   |  |  |          |
+/// //              |  +->|          |
+/// // +--------+   +---->|time_local|--------> time_t timelocal(time_t *)     
+/// // | tzo    |<--------|          |
+/// // |        |         +----------+
+/// // |        |<------------ set_tzo_min(int16_t)
+/// // |        |------------> int16_t get_tzo_min()
+/// // +--------+                                
+/// //                                           
+/// // +--------+                                   +--------------------------+
+/// // | time_t | ---> char * ctime(time_t *) ----> | buffer                   |
+/// // | value  |                                   | Www Mmm dd hh:mm:ss yyyy |
+/// // +--------+     +- char * asctime(tm_ex *) -> +--------------------------+
+/// //      ^  |      |
+/// //      |  |      |                                 +-----------------+   
+/// //      |  |      +-------------------------------- | tm_ex           |   
+/// //      |  |                                        |   .tm_sec       |   
+/// //      |  +- tm_ex * gmtime(const time_t *) -----> |   .tm_min       |   
+/// //      |  |                                        |   .tm_hour      |   
+/// //      |  +- tm_ex * localtime(const time_t *) --> |   .tm_mday      |   
+/// //      |                                           |   .tm_mon       |   
+/// //      +---- time_t mktime(struct tm_ex *) ------- |   .tm_year      |   
+/// //                                                  |   .tm_wday      |   
+/// //                                                  |   .tm_yday      |   
+/// //  +---------------------------------------------> |   .tm_isdst     |   
+/// //  | +-------------------------------------------- |   .tm_tzo_min   |               
+/// //  | |                                             +-----------------+               
+/// //  | |                                         +--------------------------+
+/// //  | +- strftime(char * ptr, ..., tm_ex *) --> | buffer                   |
+/// //  +----strptime(char * buf, ..., tm_ex *) --- | Www Mmm dd hh:mm:ss yyyy |
+/// //                                              +--------------------------+
+/// //      double difftime(time_t end, time_t)
+/// //
+/// @endcode
+///
+class TimeInterface
+    {
+public:
+    /// Constructor for the TimeInterface class, which does minimal initialization.
+    ///
+    /// @param[in] net is optional and provides the EthernetInterface which is
+    ///             used if you want to sync to an NTP server
+    ///
+    /// @code
+    /// EthernetInterface net;
+    /// TimeInterface ntp(&net);
+    /// ...
+    ///     ntp.set_tzo_min(-6 * 60);
+    ///     if (NTP_OK == ntp.setTime("time.nist.gov", 123, 10)) {
+    ///         time_t tNow = ntp.timelocal();
+    ///         printf("time is %s\r\n", ntp.ctime(&tNow));
+    ///     }
+    /// ...
+    /// @endcode
+    ///
+    TimeInterface(void *m_net = NULL);
+    
+    /// Destructor, normally not used, because it is typically kept for the life
+    /// of the program.
+    ///
+    ~TimeInterface();
+    
+    /// Gets the system elapsed time in CLOCKS_PER_SEC tics.
+    ///
+    /// Divide the returned value by CLOCKS_PER_SEC to get time in seconds.
+    ///
+    /// @code
+    /// clock_t tstart, tend;
+    /// ...
+    ///     tstart = clock();
+    ///     // do something long
+    ///     tend = clock();
+    ///     printf("Elapsed time is %5.3f\r\n", (float)(tend - tstart)/CLOCKS_PER_SEC);
+    /// ...
+    /// @endcode
+    ///
+    /// @returns elapsed tics.
+    ///
+    clock_t clock(void);
+    
+    /// Gets the current time as a UTC time value, optionally writing it
+    /// to a provided buffer.
+    ///
+    /// This reads the real time clock and returns the current UTC time.
+    ///
+    /// @code
+    /// time_t t_ref1, t_ref2, t_ref3;
+    /// t_ref1 = time(NULL); 
+    /// t_ref2 = t.time(); 
+    /// (void)t.time(&t_ref3);
+    /// @endcode
+    ///
+    /// @param[out] timer is an optional pointer to a time_t value that will 
+    ///             be written with the current time. This pointer is ignored 
+    ///             when NULL.
+    /// @returns the UTC time value.
+    ///
+    time_t time(time_t * timer = NULL);
+
+    /// Gets the current time as a LOCAL time value, optionally writing it
+    /// to a provided buffer.
+    ///
+    /// This reads the real time clock and returns the current time, adjusted
+    /// for the local time zone and daylight savings time.
+    ///
+    /// @code
+    /// time_t t_ref2, t_ref3;
+    /// t_ref2 = t.time(); 
+    /// t.timelocal(&t_ref3);
+    /// @endcode
+    ///
+    /// @param[out] timer is an optional pointer to a time_t value that will 
+    ///     be written. This pointer is ignored when NULL.
+    /// @returns the LOCAL time value (UTC adjusted for the LOCAL time zone and dst).
+    ///
+    time_t timelocal(time_t * timer = NULL);
+
+    /// Convert a time value structure into an ASCII printable time "Www Mmm dd hh:mm:ss yyyy"
+    ///
+    /// @note Watch out for race conditions as this returns a pointer to a
+    ///         shared buffer.
+    /// @note Unlike the standard ctime function, this version DOES NOT append 
+    ///         a newline character to the buffer.
+    ///
+    /// @code
+    /// time_t tNow = timelocal();
+    /// printf("time is %s\r\n", ctime(tNow));
+    /// @endcode
+    ///
+    /// @param[in] timer is a pointer to a time_t value containing the time to convert.
+    /// @returns a pointer to a buffer containing the string.
+    ///
+    char * ctime(const time_t * timer);
+
+    /// Convert a tm_ex structure into an ASCII printable "time Www Mmm dd hh:mm:ss yyyy"
+    ///
+    /// @note Unlike the standard asctime, this takes a pointer to a tm_ex, which 
+    ///         has daylight savings time flag and a time zone offset element.
+    ///
+    /// @note Watch out for race conditions as this returns a pointer to a
+    ///     shared buffer.
+    ///
+    /// @note Unlike the standard ctime function, this version DOES NOT append 
+    ///     a newline character to the buffer.
+    ///
+    /// @code
+    /// time_t tNow = timelocal();
+    /// tm_ex * tEx = localtime(&tNow);
+    /// printf("Time is %s\r\n", asctime(tEx));
+    /// @endcode
+    ///
+    /// @param[in] timeptr is a pointer to a tm_ex structure containing the time to convert.
+    /// @returns a pointer to a private buffer containing the string.
+    ///
+    char * asctime(const struct tm_ex *timeptr);
+
+    /// Compute the difference in seconds between two time values.
+    ///
+    /// @code
+    /// time_t tstart, tend;
+    /// ...
+    ///     tstart = time();
+    ///     // do some long process now
+    ///     tend = time();
+    ///     printf("Elapsed time is %5.3f\r\n", tend - tstart);
+    /// ...
+    /// @endcode
+    ///
+    /// @param[in] end is the end time to compare to the beginning time.
+    /// @param[in] beginning time is compared to the end time.
+    /// @return the difference in seconds, as a double.
+    ///
+    double difftime(time_t end, time_t beginning);
+    
+    /// Convert the referenced time_t value to a tm_ex structure in UTC/GMT format.
+    ///
+    /// @note Unlike the standard asctime, this return a pointer to a tm_ex, which 
+    ///         has a time zone offset element.
+    ///
+    /// @note Watch out for race conditions as this returns a pointer to a
+    ///     shared buffer.
+    ///
+    /// @param[in] timer is a pointer to a time_t structure to convert.
+    /// @returns pointer to a tm_ex structure.
+    ///
+    struct tm_ex * gmtime(const time_t * timer);
+    
+    
+    /// Convert the referenced time_t value to a tm structure in local format.
+    ///
+    /// This method leverages the time zone offset applied with @see set_tzo()
+    /// and the daylight savings time flag applied with @see set_dst().
+    ///
+    /// @note Watch out for race conditions as this returns a pointer to a
+    ///     shared buffer.
+    ///
+    /// @code
+    /// time_t tNow = timelocal();
+    /// tm_ex * tEx = localtime(&tNow);
+    /// @endcode
+    ///
+    /// @param[in] timer is a pointer to a time_t structure to convert.
+    /// @returns pointer to a tm structure.
+    ///
+    struct tm_ex * localtime(const time_t * timer);
+    
+    /// Convert a tm_ex structure (an extended time structure) to a time_t
+    /// value.
+    ///
+    /// This function also sets the tzo_min element of the tm_ex structure
+    /// from the previously set tzo_min.
+    /// 
+    /// @param[in] timeptr is a pointer to a tm_ex structure.
+    /// @returns the computed time_t value.
+    ///
+    time_t mktime(struct tm_ex * timeptr);
+    
+    /// Presents a time value in a user specified format, into a user specified buffer.
+    ///
+    /// @param[out] ptr is a pointer to the user buffer.
+    /// @param[in] maxsize is the size of the user buffer.
+    /// @param[in] format is a pointer to the special strftime format specification.
+    ///             see format options.
+    /// @param[in] timeptr is a pointer to the tm_ex structure.
+    /// @returns the total number of characters copied into the buffer.
+    ///
+    /// format options:
+    ///     - %%a  Abbreviated weekday name e.g. Thu
+    ///     - %%A  Full weekday name e.g. Thursday
+    ///     - %%b  Abbreviated month name e.g. Aug
+    ///     - %%B  Full month name e.g. August
+    ///     - %%c  Date and time representation e.g. Thu Aug 23 14:55:02 2001
+    ///     - %%C  Year divided by 100 and truncated to integer (00-99) e.g. 20
+    ///     - %%d  Day of the month, zero-padded (01-31) e.g. 23
+    ///     - %%D  Short MM/DD/YY date, equivalent to %%m/%%d/%%y e.g. 08/23/01
+    ///     - %%e  Day of the month, space-padded ( 1-31) e.g. 23
+    ///     - %%F  Short YYYY-MM-DD date, equivalent to %%Y-%%m-%%d e.g. 2001-08-23
+    ///     - %%g  Week-based year, last two digits (00-99) e.g. 01
+    ///     - %%G  Week-based year e.g. 2001
+    ///     - %%h  Abbreviated month name * (same as %%b) e.g. Aug
+    ///     - %%H  Hour in 24h format (00-23) e.g. 14
+    ///     - %%I  Hour in 12h format (01-12) e.g. 02
+    ///     - %%j  Day of the year (001-366)  e.g. 235
+    ///     - %%m  Month as a decimal number (01-12) e.g. 08
+    ///     - %%M  Minute (00-59) e.g. 55
+    ///     - %%n  New-line character ('\\n')   
+    ///     - %%p  AM or PM designation e.g. PM
+    ///     - %%r  12-hour clock time e.g. 02:55:02 pm
+    ///     - %%R  24-hour HH:MM time, equivalent to %%H:%%M e.g. 14:55
+    ///     - %%S  Second (00-61) e.g. 02
+    ///     - %%t  Horizontal-tab character ('\t') 
+    ///     - %%T  ISO 8601 time format (HH:MM:SS), equivalent to %%H:%%M:%%S e.g. 14:55:02
+    ///     - %%u  ISO 8601 weekday as number with Monday as 1 (1-7) e.g. 4
+    ///     - %%U  Week number with the first Sunday as the first day of week one (00-53) e.g. 33
+    ///     - %%V  ISO 8601 week number (00-53) e.g. 34
+    ///     - %%w  Weekday as a decimal number with Sunday as 0 (0-6) e.g. 4
+    ///     - %%W  Week number with the first Monday as the first day of week one (00-53) e.g. 34
+    ///     - %%x  Date representation e.g. 08/23/01
+    ///     - %%X  Time representation e.g. 14:55:02
+    ///     - %%y  Year, last two digits (00-99) e.g. 01
+    ///     - %%Y  Year e.g. 2001
+    ///     - %%z  ISO 8601 offset from UTC in timezone (1 minute=1, 1 hour=100) (e.g. +100)
+    ///           If timezone cannot be determined, no characters 
+    ///     - %%Z  Timezone name or abbreviation (e.g. CDT)
+    ///           If timezone cannot be determined, no characters 
+    ///     - %  A % sign
+    ///
+    size_t strftime(char * ptr, size_t maxsize, const char * format, const struct tm_ex * timeptr);
+    
+
+    /// Convert a string, in a defined format, to a time value in a tm_ex structure.
+    ///
+    /// Most format details leveraged from The Open Group Base Specifications Issue 6
+    /// IEEE Std 1003.1, 2004 Edition
+    /// Copyright © 2001-2004 The IEEE and The Open Group, All Rights reserved.
+    ///
+    /// Modifications for mbed, and addition of the timezone format option by D. Smart
+    ///
+    /// @code
+    ///     char timesample[] = "Jan 22 2017 01:32:48 UTC";
+    ///     tm_ex tm;
+    ///     strptime(timesample, "%b %d %Y %H:%M:%S %Z", &tm);
+    /// @endcode
+    /// 
+    /// @param[in] buf is a pointer to the string to be parsed.
+    /// @param[in] format is a pointer to a format string. See the format options.
+    /// @param[out] tm is a pointer to a tm_ex struct.
+    /// @returns a pointer to the character following the last one parsed, or null on failure
+    ///
+    /// format options:
+    ///     - %%a The day of the week, using the locale's weekday names; either the abbreviated or 
+    ///         full name may be specified.
+    ///     - %%A Equivalent to %%a.
+    ///     - %%b The month, using the locale's month names; either the abbreviated or full name 
+    ///         may be specified.
+    ///     - %%B Equivalent to %%b.
+    ///     - %%c Replaced by the locale's appropriate date and time representation.
+    ///     - %%C The century number [00,99]; leading zeros are permitted but not required.
+    ///     - %%d The day of the month [01,31]; leading zeros are permitted but not required.
+    ///     - %%D The date as %%m / %%d / %%y.
+    ///     - %%e Equivalent to %%d.
+    ///     - %%h Equivalent to %%b.
+    ///     - %%H The hour (24-hour clock) [00,23]; leading zeros are permitted but not required.
+    ///     - %%I The hour (12-hour clock) [01,12]; leading zeros are permitted but not required.
+    ///     - %%j The day number of the year [001,366]; leading zeros are permitted but not required.
+    ///     - %%m The month number [01,12]; leading zeros are permitted but not required.
+    ///     - %%M The minute [00,59]; leading zeros are permitted but not required.
+    ///     - %%n Any white space.
+    ///     - %%p The locale's equivalent of a.m or p.m.
+    ///     - %%r 12-hour clock time using the AM/PM notation if t_fmt_ampm is not an empty string 
+    ///         in the LC_TIME portion of the current locale; in the POSIX locale, this shall be 
+    ///         equivalent to %%I : %%M : %%S %%p.
+    ///     - %%R The time as %%H : %%M.
+    ///     - %%S The seconds [00,60]; leading zeros are permitted but not required.
+    ///     - %%t Any white space.
+    ///     - %%T The time as %%H : %%M : %%S.
+    ///     - %%U The week number of the year (Sunday as the first day of the week) as a decimal 
+    ///         number [00,53]; leading zeros are permitted but not required.
+    ///     - %%w The weekday as a decimal number [0,6], with 0 representing Sunday; leading zeros 
+    ///         are permitted but not required.
+    ///     - %%W The week number of the year (Monday as the first day of the week) as a decimal 
+    ///         number [00,53]; leading zeros are permitted but not required.
+    ///     - %%x The date, using the locale's date format.
+    ///     - %%X The time, using the locale's time format.
+    ///     - %%y The year within century. When a century is not otherwise specified, values in 
+    ///         the range [69,99] shall refer to years 1969 to 1999 inclusive, and values in the 
+    ///         range [00,68] shall refer to years 2000 to 2068 inclusive; leading zeros shall be 
+    ///         permitted but shall not be required.
+    ///         Note: It is expected that in a future version of IEEE Std 1003.1-2001 
+    ///         the default century inferred from a 2-digit year will change. 
+    ///         (This would apply to all commands accepting a 2-digit year as input.)
+    ///     - %%Y The year, including the century (for example, 1988).
+    ///     - %%Z The timezone offset, as a 3-letter sequence. Only a few whole-hour offsets
+    ///         have been defined.
+    ///     - %% Replaced by %.
+    ///
+    const char * strptime(const char *buf, char *fmt, struct tm_ex *tm);
+
+
+    // time zone functions
+    
+    /// Set the internal RTC (clock) to the time value. 
+    ///
+    /// The time valueshould be UTC time along with an offset of zero,
+    /// which then permits gmtime and localtime to be used appropriately.
+    /// Alternately, the time can be in localtime, and the offset is then
+    /// used to compute UTC to set the clock.
+    ///
+    /// @param[in] t should be the UTC time value to set the clock to. If the available 
+    ///     time value is local time, the optional time zone offset can
+    ///     be provided so the system clock is UTC.
+    /// @param[in] tzo is the optional time zone offset in minutes when it is in
+    ///     the range of -720 to +720 (-12 hours to + 12 hours). Any
+    ///     other value is illegal and no change will be made.
+    ///
+    void set_time(time_t t, int16_t tzo_min = 0);
+    
+    /// Set the time zone offset in minutes.
+    ///
+    /// This API should be used before any other methods that fetch
+    /// the RTC info.
+    ///
+    /// @param[in] tzo is the time zone offset in minutes when it is in
+    ///     the range of -720 to +720 (-12 hours to + 12 hours). Any
+    ///     other value is illegal and no change will be made.
+    ///
+    void set_tzo_min(int16_t tzo_min);
+    
+    /// Get the time zone offset in minutes.
+    ///
+    /// @returns the time zone offset value in minutes. If the tzo was
+    /// never initialized, this returns zero.
+    ///
+    int16_t get_tzo_min(void);
+    
+    /// Set the clock for local time to report whether the current
+    /// mode is standard or daylight savings time.
+    ///
+    /// return values for localtime will then be adjusted not only
+    /// for the time zone offset, but for dst.
+    ///
+    /// @param[in] dst is a boolean that should be set when dst is
+    ///         the active mode.
+    /// @returns true, always.
+    ///
+    bool set_dst(bool dst);
+    
+    /// Set the clock for auto-adjust local time based on 
+    /// changing to standard or daylight savings time.
+    ///
+    /// return values for localtime will then be adjusted not only
+    /// for the time zone offset, but for dst.
+    ///
+    /// @param[in] dstStart is a string of the form "mm/dd,hh:mm"
+    ///                     representing when DST starts.
+    /// @param[in] dstStop  is a string of the form "mm/dd,hh:mm"
+    ///                     representing when DST stops.
+    /// @returns true if the start and stop pair could be successfully
+    ///               parsed.
+    ///
+    bool set_dst(const char * dstStart, const char * dstStop);
+    
+    /// Get the current clock mode for daylight savings time.
+    ///
+    /// @returns true if clock is in dst mode.
+    ///
+    bool get_dst(void);
+    
+    /// Get the time value when the clock was last set. This is most
+    /// often used in calibration of the clock.
+    ///
+    /// @returns time last set as a UTC time value.
+    ///
+    time_t get_timelastset(void);
+    
+    /// get_cal will return the calibration register value
+    ///
+    /// This is the raw register value as a signed 32-bit value (even though
+    /// it is actually a 17-bit unsigned value with an additional 'direction' flag).
+    ///
+    /// @returns calibration settings ranging from -131071 to +131071
+    ///
+    int32_t get_cal();
+
+    /// set_cal will set the calibration register value
+    ///
+    /// This accepts a signed value to be used to set the calibration
+    /// registers. Setting the calibration value to zero disables the
+    /// calibration function. 
+    ///
+    /// It is important to know the register function in order to use 
+    /// this command, and this API is normally not used by external
+    /// application code. @See AdjustBySeconds for a user-friendly
+    /// API.
+    ///
+    /// @param[in] calibration value to use ranging from -131071 to +131071
+    /// @returns nothing
+    ///
+    void set_cal(int32_t calibration);
+
+    /// adjust_sec adjusts both the time and the calibration by seconds
+    ///
+    /// This will take a signed value, which is the current adjustment in seconds
+    /// to put the clock on the correct time. So, if the clock is behind by
+    /// 3 seconds, the value should be +3 to advance the clock accordingly.
+    /// It will then adjust the time, and it will attempt to adjust the
+    /// calibration factor to make the time more accurate.
+    ///
+    /// The adjustment can only be made if it has retained when the clock was
+    /// last set, in order to know by how much to adjust it. It is also most
+    /// accurate if several days have elapsed since the time was set.
+    ///
+    /// @note The current version only works if the calibration value
+    ///       is zero when this adjustment is made.
+    /// 
+    /// @param[in] adjustSeconds is the signed value by which to adjust the time to
+    ///        correct it to the current actual time.
+    /// @returns true if the adjustment was made
+    /// @returns false if the adjustment could not be made
+    ///
+    bool adjust_sec(int32_t adjustSeconds);
+
+    /// Set the clock from an internet source (blocking)
+    ///
+    /// This function is the interface to NTPClient.
+    /// Blocks until completion
+    ///
+    /// @param[in] host NTP server IPv4 address or hostname (will be resolved via DNS)
+    /// @param[in] port port to use; defaults to 123
+    /// @param[in] timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
+    /// @returns NTP_OK on success, 
+    /// @returns NTP_CONN if no network interface
+    /// @returns other NTP error code (<0) on failure
+    ///
+    //NTPResult setTime(const char* host, uint16_t port = NTP_DEFAULT_PORT, uint32_t timeout = NTP_DEFAULT_TIMEOUT);
+
+    // ntp interface functions    
+private:
+    void * m_net;
+
+    typedef struct {
+        uint8_t MM;
+        uint8_t DD;
+        uint8_t hh;
+        uint8_t mm;
+    } dst_event_t;
+    typedef struct {
+        dst_event_t dst_start;
+        dst_event_t dst_stop;
+    } dst_event_pair_t;
+
+    bool parseDSTstring(dst_event_t * result, const char * dstr);
+    
+    /// Performs a "simple" computation of two dates into minutes.
+    ///
+    /// Does not account for leap years or which month it is. Is
+    /// useful only for comparing which date/time came first, not for
+    /// computing the difference between them.
+    ///
+    /// @return "normalized" minutes since Jan 1 00:00.
+    ///
+    uint32_t minutesSinceJan(int mon, int day, int hr, int min);
+
+    dst_event_pair_t dst_pair;
+    bool dst;           // true in dst mode
+    char result[30];    // holds the converted to text time string
+    time_t tresult;     // holds the converted time structure.
+    struct tm_ex tm_ext;
+    };
+
+#endif // TIMEINTERFACE_H