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:
- 10:5734dbc2f5cc
- Parent:
- 7:1de342fa7840
- Child:
- 11:1d880a50da8a
--- a/TimeInterface.cpp Sat Mar 26 20:36:02 2016 +0000 +++ b/TimeInterface.cpp Sun Jan 22 04:06:16 2017 +0000 @@ -50,7 +50,7 @@ res = ntp.setTime(host, port, timeout); INFO(" ret: %d\r\n", res); if (res == NTP_OK) { - // if the time was fetched successfully, then + // 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. @@ -63,7 +63,7 @@ { int x; dst_event_t test_dst; - + x = atoi(dstr); if (x >= 1 && x <= 12) { test_dst.MM = x; @@ -99,9 +99,9 @@ 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)) { + && 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; @@ -118,7 +118,7 @@ bool TimeInterface::get_dst(void) { - return dst; + return dst; } clock_t TimeInterface::clock(void) @@ -140,15 +140,15 @@ { 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); @@ -164,7 +164,7 @@ char * TimeInterface::ctime(const time_t * timer) { char * p = std::ctime(timer); - + if (strlen(p) < sizeof(result)) { strcpy(result, p); p = strchr(result, '\n'); @@ -185,21 +185,40 @@ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + struct tm_ex tmp = *timeptr; + tmp.tm_min += tmp.tm_tzo_min; + 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[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); + 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) -{ +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; @@ -213,10 +232,9 @@ return &tm_ext; } -struct tm_ex * TimeInterface::localtime(const time_t * timer) -{ +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; @@ -262,7 +280,7 @@ { 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; @@ -274,7 +292,7 @@ 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); @@ -290,16 +308,18 @@ return LPC_RTC->GPREG1; } -int32_t TimeInterface::get_cal() { +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) { +void TimeInterface::set_cal(int32_t calibration) +{ if (calibration) { if (calibration < 0) { calibration = (-calibration & 0x1FFFF) | 0x20000; @@ -314,7 +334,7 @@ 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; @@ -322,11 +342,11 @@ 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 + // 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) { @@ -346,3 +366,381 @@ 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[9]; + int8_t zone_offsets[9]; +}; + +static 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" }, + { 0, -5, -6, -7, -8 }, +}; + +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_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; + + 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; + + 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; +printf("z: %s => %d\r\n", En_US.zone_names[i], En_US.zone_offsets[i]); + tm->tm_tzo_min = En_US.zone_offsets[i] * 60; + buf += len; + break; + } + } + + return buf; +} +