From 182f850d23e26d6738aab23913693d90c1cb3ff4 Mon Sep 17 00:00:00 2001 From: cyberman54 Date: Sat, 2 Mar 2019 20:01:27 +0100 Subject: [PATCH] timekeeper fixes --- lib/microTime/microTime.cpp | 359 ------------------------------------ lib/microTime/src/Time.cpp | 203 ++++++++++---------- lib/microTime/src/TimeLib.h | 203 +++++++++++--------- src/display.cpp | 2 +- src/main.cpp | 9 +- src/timekeeper.cpp | 58 +++--- 6 files changed, 247 insertions(+), 587 deletions(-) delete mode 100644 lib/microTime/microTime.cpp diff --git a/lib/microTime/microTime.cpp b/lib/microTime/microTime.cpp deleted file mode 100644 index 00e806e2..00000000 --- a/lib/microTime/microTime.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* - time.c - low level time and date functions - Copyright (c) Michael Margolis 2009-2014 - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - 1.0 6 Jan 2010 - initial release - 1.1 12 Feb 2010 - fixed leap year calculation error - 1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this) - 1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update - status, updated examples for Arduino 1.0, fixed ARM - compatibility issues, added TimeArduinoDue and TimeTeensy3 - examples, add error checking and messages to RTC examples, - add examples to DS1307RTC library. - 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 -*/ - -#if ARDUINO >= 100 -#include -#else -#include -#endif - -#define TIMELIB_ENABLE_MILLIS -#define usePPS - -#include "microTimeLib.h" - -// Convert days since epoch to week day. Sunday is day 1. -#define DAYS_TO_WDAY(x) (((x) + 4) % 7) + 1 - -static tmElements_t cacheElements; // a cache of time elements -static time_t cacheTime; // the time the cache was updated -static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds - -void refreshCache(time_t t) { - if (t != cacheTime) { - breakTime(t, cacheElements); - cacheTime = t; - } -} - -int hour() { // the hour now - return hour(now()); -} - -int hour(time_t t) { // the hour for the given time - refreshCache(t); - return cacheElements.Hour; -} - -int hourFormat12() { // the hour now in 12 hour format - return hourFormat12(now()); -} - -int hourFormat12(time_t t) { // the hour for the given time in 12 hour format - refreshCache(t); - if( cacheElements.Hour == 0 ) - return 12; // 12 midnight - else if( cacheElements.Hour > 12) - return cacheElements.Hour - 12 ; - else - return cacheElements.Hour ; -} - -uint8_t isAM() { // returns true if time now is AM - return !isPM(now()); -} - -uint8_t isAM(time_t t) { // returns true if given time is AM - return !isPM(t); -} - -uint8_t isPM() { // returns true if PM - return isPM(now()); -} - -uint8_t isPM(time_t t) { // returns true if PM - return (hour(t) >= 12); -} - -int minute() { - return minute(now()); -} - -int minute(time_t t) { // the minute for the given time - refreshCache(t); - return cacheElements.Minute; -} - -int second() { - return second(now()); -} - -int second(time_t t) { // the second for the given time - refreshCache(t); - return cacheElements.Second; -} - -int millisecond() { - uint32_t ms; - now(ms); - ms = ms / 1000; - return (int)ms; -} - -int microsecond() { - uint32_t us; - now(us); - return (int)us; -} - -int day(){ - return(day(now())); -} - -int day(time_t t) { // the day for the given time (0-6) - refreshCache(t); - return cacheElements.Day; -} - -int weekday() { // Sunday is day 1 - return weekday(now()); -} - -int weekday(time_t t) { - refreshCache(t); - return cacheElements.Wday; -} - -int month(){ - return month(now()); -} - -int month(time_t t) { // the month for the given time - refreshCache(t); - return cacheElements.Month; -} - -int year() { // as in Processing, the full four digit year: (2009, 2010 etc) - return year(now()); -} - -int year(time_t t) { // the year for the given time - refreshCache(t); - return tmYearToCalendar(cacheElements.Year); -} - -/*============================================================================*/ -/* functions to convert to and from system time */ -/* These are for interfacing with time serivces and are not normally needed in a sketch */ - -// leap year calulator expects year argument as years offset from 1970 -#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) ) -#define daysInYear(year) ((time_t) (LEAP_YEAR(year) ? 366 : 365)) - -static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 - -void breakTime(time_t time, tmElements_t &tm){ -// break the given time_t into time components -// this is a more compact version of the C library localtime function -// note that year is offset from 1970 !!! - - uint8_t period; - time_t length; - - tm.Second = time % 60; - time /= 60; // now it is minutes - tm.Minute = time % 60; - time /= 60; // now it is hours - tm.Hour = time % 24; - time /= 24; // now it is days since 1 Jan 1970 - - // if the number of days since epoch matches cacheTime, then can take date - // elements from cacheElements and avoid expensive calculation. - if (time == (cacheTime / SECS_PER_DAY)) { - if (&tm != &cacheElements) { // check whether tm is actually cacheElements - tm.Wday = cacheElements.Wday; - tm.Day = cacheElements.Day; - tm.Month = cacheElements.Month; - tm.Year = cacheElements.Year; - } - return; - } - - tm.Wday = DAYS_TO_WDAY(time); - - period = 0; - while (time >= (length = daysInYear(period))) - { - time -= length; - period++; - } - tm.Year = period; // year is offset from 1970 - // time is now days since 1 Jan of the year - - bool leap_year = LEAP_YEAR(period); - period = 0; - while (period < 12 && time >= (length = monthDays[period] + (leap_year && period==1))) - { - time -= length; - period++; - } - tm.Month = period + 1; // jan is month 1 - // time is now days since the 1st day of the month - - tm.Day = time + 1; // day of month -} - -time_t makeTime(const tmElements_t &tm){ -// assemble time elements into time_t -// note year argument is offset from 1970 (see macros in time.h to convert to other formats) -// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 - - int i; - uint32_t seconds; - - // seconds from 1970 till 1 jan 00:00:00 of the given year - seconds = SECS_PER_DAY * (365 * tm.Year); - for (i = 0; i < tm.Year; i++) { - if (LEAP_YEAR(i)) { - seconds += SECS_PER_DAY; // add extra days for leap years - } - } - - // add days for this year, months start from 1 - for (i = 1; i < tm.Month; i++) { - if ( (i == 2) && LEAP_YEAR(tm.Year)) { - seconds += SECS_PER_DAY * 29; - } else { - seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 - } - } - seconds+= (tm.Day-1) * SECS_PER_DAY; - seconds+= tm.Hour * SECS_PER_HOUR; - seconds+= tm.Minute * SECS_PER_MIN; - seconds+= tm.Second; - return (time_t)seconds; -} -/*=====================================================*/ -/* Low level system time functions */ - -static time_t sysTime = 0; -static uint32_t prevMicros = 0; -static time_t nextSyncTime = 0; -static timeStatus_t Status = timeNotSet; - -getExternalTime getTimePtr; // pointer to external sync function -//setExternalTime setTimePtr; // not used in this version - -#ifdef TIME_DRIFT_INFO // define this to get drift data -time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync -#endif - -#ifdef usePPS -void SyncToPPS() -{ - sysTime++; - prevMicros = micros(); - //Serial.println(prevMicros); -} -#endif - -time_t now() { - uint32_t sysTimeMicros; - return now(sysTimeMicros); -} - -time_t now(uint32_t& sysTimeMicros) { - // calculate number of seconds passed since last call to now() - while ((sysTimeMicros = micros() - prevMicros) >= 1000000) { - // micros() and prevMicros are both unsigned ints thus the subtraction will - // always result in a positive difference. This is OK since it corrects for - // wrap-around and micros() is monotonic. - sysTime++; - prevMicros += 1000000; -#ifdef TIME_DRIFT_INFO - sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift -#endif - } - if (nextSyncTime <= sysTime) { - if (getTimePtr != 0) { - time_t t = getTimePtr(); - - if (t != 0) { - setTime(t); - } else { - nextSyncTime = sysTime + syncInterval; - Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; - } - } - } - return sysTime; -} - -void setTime(time_t t) { -#ifdef TIME_DRIFT_INFO - if(sysUnsyncedTime == 0) - sysUnsyncedTime = t; // store the time of the first call to set a valid Time -#endif - - sysTime = t; - nextSyncTime = t + (time_t) syncInterval; - Status = timeSet; - #ifndef usePPS - prevMicros = micros(); // restart counting from now (thanks to Korman for this fix) - #endif -} - -void setTime(int hr, int min, int sec, int dy, int mnth, int yr) { - // year can be given as full four digit year or two digts (2010 or 10 for 2010); - // it is converted to years since 1970 - if (yr > 99) - yr = CalendarYrToTm(yr); - else - yr = tmYearToY2k(yr); - cacheElements.Year = yr; - cacheElements.Month = mnth; - cacheElements.Day = dy; - cacheElements.Hour = hr; - cacheElements.Minute = min; - cacheElements.Second = sec; - cacheTime = makeTime(cacheElements); - cacheElements.Wday = DAYS_TO_WDAY(cacheTime / SECS_PER_DAY); - setTime(cacheTime); -} - -void adjustTime(long adjustment) { - sysTime += adjustment; -} - -// indicates if time has been set and recently synchronized -timeStatus_t timeStatus() { - now(); // required to actually update the status - return Status; -} - -void setSyncProvider(getExternalTime getTimeFunction){ - getTimePtr = getTimeFunction; - nextSyncTime = sysTime; - now(); // this will sync the clock -} - -void setSyncInterval(time_t interval){ // set the number of seconds between re-sync - syncInterval = (uint32_t)interval; - nextSyncTime = sysTime + syncInterval; -} diff --git a/lib/microTime/src/Time.cpp b/lib/microTime/src/Time.cpp index e8fd886e..a4cd2d3a 100644 --- a/lib/microTime/src/Time.cpp +++ b/lib/microTime/src/Time.cpp @@ -27,11 +27,7 @@ 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 */ -#if ARDUINO >= 100 -#include -#else -#include -#endif +#include #define TIMELIB_ENABLE_MILLIS #define usePPS @@ -41,9 +37,10 @@ // Convert days since epoch to week day. Sunday is day 1. #define DAYS_TO_WDAY(x) (((x) + 4) % 7) + 1 -static tmElements_t cacheElements; // a cache of time elements -static time_t cacheTime; // the time the cache was updated -static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds +static tmElements_t cacheElements; // a cache of time elements +static time_t cacheTime; // the time the cache was updated +static uint32_t syncInterval = + 300; // time sync will be attempted after this many seconds void refreshCache(time_t t) { if (t != cacheTime) { @@ -52,8 +49,8 @@ void refreshCache(time_t t) { } } -int hour() { // the hour now - return hour(now()); +int hour() { // the hour now + return hour(now()); } int hour(time_t t) { // the hour for the given time @@ -62,49 +59,45 @@ int hour(time_t t) { // the hour for the given time } int hourFormat12() { // the hour now in 12 hour format - return hourFormat12(now()); + return hourFormat12(now()); } int hourFormat12(time_t t) { // the hour for the given time in 12 hour format refreshCache(t); - if( cacheElements.Hour == 0 ) + if (cacheElements.Hour == 0) return 12; // 12 midnight - else if( cacheElements.Hour > 12) - return cacheElements.Hour - 12 ; + else if (cacheElements.Hour > 12) + return cacheElements.Hour - 12; else - return cacheElements.Hour ; + return cacheElements.Hour; } uint8_t isAM() { // returns true if time now is AM - return !isPM(now()); + return !isPM(now()); } uint8_t isAM(time_t t) { // returns true if given time is AM - return !isPM(t); + return !isPM(t); } uint8_t isPM() { // returns true if PM - return isPM(now()); + return isPM(now()); } uint8_t isPM(time_t t) { // returns true if PM - return (hour(t) >= 12); + return (hour(t) >= 12); } -int minute() { - return minute(now()); -} +int minute() { return minute(now()); } int minute(time_t t) { // the minute for the given time refreshCache(t); return cacheElements.Minute; } -int second() { - return second(now()); -} +int second() { return second(now()); } -int second(time_t t) { // the second for the given time +int second(time_t t) { // the second for the given time refreshCache(t); return cacheElements.Second; } @@ -122,35 +115,31 @@ int microsecond() { return (int)us; } -int day(){ - return(day(now())); -} +int day() { return (day(now())); } int day(time_t t) { // the day for the given time (0-6) refreshCache(t); return cacheElements.Day; } -int weekday() { // Sunday is day 1 - return weekday(now()); +int weekday() { // Sunday is day 1 + return weekday(now()); } int weekday(time_t t) { refreshCache(t); return cacheElements.Wday; } - -int month(){ - return month(now()); -} -int month(time_t t) { // the month for the given time +int month() { return month(now()); } + +int month(time_t t) { // the month for the given time refreshCache(t); return cacheElements.Month; } -int year() { // as in Processing, the full four digit year: (2009, 2010 etc) - return year(now()); +int year() { // as in Processing, the full four digit year: (2009, 2010 etc) + return year(now()); } int year(time_t t) { // the year for the given time @@ -158,20 +147,25 @@ int year(time_t t) { // the year for the given time return tmYearToCalendar(cacheElements.Year); } -/*============================================================================*/ +/*============================================================================*/ /* functions to convert to and from system time */ -/* These are for interfacing with time serivces and are not normally needed in a sketch */ +/* These are for interfacing with time serivces and are not normally needed in a + * sketch */ // leap year calulator expects year argument as years offset from 1970 -#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) ) -#define daysInYear(year) ((time_t) (LEAP_YEAR(year) ? 366 : 365)) +#define LEAP_YEAR(Y) \ + (((1970 + (Y)) > 0) && !((1970 + (Y)) % 4) && \ + (((1970 + (Y)) % 100) || !((1970 + (Y)) % 400))) +#define daysInYear(year) ((time_t)(LEAP_YEAR(year) ? 366 : 365)) -static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 +static const uint8_t monthDays[] = { + 31, 28, 31, 30, 31, 30, 31, + 31, 30, 31, 30, 31}; // API starts months from 1, this array starts from 0 -void breakTime(time_t time, tmElements_t &tm){ -// break the given time_t into time components -// this is a more compact version of the C library localtime function -// note that year is offset from 1970 !!! +void breakTime(time_t time, tmElements_t &tm) { + // break the given time_t into time components + // this is a more compact version of the C library localtime function + // note that year is offset from 1970 !!! uint8_t period; time_t length; @@ -186,7 +180,7 @@ void breakTime(time_t time, tmElements_t &tm){ // if the number of days since epoch matches cacheTime, then can take date // elements from cacheElements and avoid expensive calculation. if (time == (cacheTime / SECS_PER_DAY)) { - if (&tm != &cacheElements) { // check whether tm is actually cacheElements + if (&tm != &cacheElements) { // check whether tm is actually cacheElements tm.Wday = cacheElements.Wday; tm.Day = cacheElements.Day; tm.Month = cacheElements.Month; @@ -196,34 +190,34 @@ void breakTime(time_t time, tmElements_t &tm){ } tm.Wday = DAYS_TO_WDAY(time); - + period = 0; - while (time >= (length = daysInYear(period))) - { + while (time >= (length = daysInYear(period))) { time -= length; period++; } - tm.Year = period; // year is offset from 1970 + tm.Year = period; // year is offset from 1970 // time is now days since 1 Jan of the year bool leap_year = LEAP_YEAR(period); period = 0; - while (period < 12 && time >= (length = monthDays[period] + (leap_year && period==1))) - { + while (period < 12 && + time >= (length = monthDays[period] + (leap_year && period == 1))) { time -= length; period++; } - tm.Month = period + 1; // jan is month 1 + tm.Month = period + 1; // jan is month 1 // time is now days since the 1st day of the month - tm.Day = time + 1; // day of month + tm.Day = time + 1; // day of month } -time_t makeTime(const tmElements_t &tm){ -// assemble time elements into time_t -// note year argument is offset from 1970 (see macros in time.h to convert to other formats) -// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 - +time_t makeTime(const tmElements_t &tm) { + // assemble time elements into time_t + // note year argument is offset from 1970 (see macros in time.h to convert to + // other formats) previous version used full four digit year (or digits since + // 2000),i.e. 2009 was 2009 or 9 + int i; uint32_t seconds; @@ -231,25 +225,26 @@ time_t makeTime(const tmElements_t &tm){ seconds = SECS_PER_DAY * (365 * tm.Year); for (i = 0; i < tm.Year; i++) { if (LEAP_YEAR(i)) { - seconds += SECS_PER_DAY; // add extra days for leap years + seconds += SECS_PER_DAY; // add extra days for leap years } } - + // add days for this year, months start from 1 for (i = 1; i < tm.Month; i++) { - if ( (i == 2) && LEAP_YEAR(tm.Year)) { + if ((i == 2) && LEAP_YEAR(tm.Year)) { seconds += SECS_PER_DAY * 29; } else { - seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + seconds += SECS_PER_DAY * monthDays[i - 1]; // monthDay array starts from + // 0 } } - seconds+= (tm.Day-1) * SECS_PER_DAY; - seconds+= tm.Hour * SECS_PER_HOUR; - seconds+= tm.Minute * SECS_PER_MIN; - seconds+= tm.Second; - return (time_t)seconds; + seconds += (tm.Day - 1) * SECS_PER_DAY; + seconds += tm.Hour * SECS_PER_HOUR; + seconds += tm.Minute * SECS_PER_MIN; + seconds += tm.Second; + return (time_t)seconds; } -/*=====================================================*/ +/*=====================================================*/ /* Low level system time functions */ static time_t sysTime = 0; @@ -257,19 +252,18 @@ static uint32_t prevMicros = 0; static time_t nextSyncTime = 0; static timeStatus_t Status = timeNotSet; -getExternalTime getTimePtr; // pointer to external sync function -//setExternalTime setTimePtr; // not used in this version +getExternalTime getTimePtr; // pointer to external sync function +// setExternalTime setTimePtr; // not used in this version -#ifdef TIME_DRIFT_INFO // define this to get drift data -time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync +#ifdef TIME_DRIFT_INFO // define this to get drift data +time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync #endif #ifdef usePPS -void SyncToPPS() -{ +time_t SyncToPPS() { sysTime++; prevMicros = micros(); - //Serial.println(prevMicros); + return sysTime; } #endif @@ -278,54 +272,56 @@ time_t now() { return now(sysTimeMicros); } -time_t now(uint32_t& sysTimeMicros) { +time_t now(uint32_t &sysTimeMicros) { // calculate number of seconds passed since last call to now() - while ((sysTimeMicros = micros() - prevMicros) >= 1000000) { + while ((sysTimeMicros = micros() - prevMicros) >= 1000000) { // micros() and prevMicros are both unsigned ints thus the subtraction will // always result in a positive difference. This is OK since it corrects for // wrap-around and micros() is monotonic. sysTime++; - prevMicros += 1000000; + prevMicros += 1000000; #ifdef TIME_DRIFT_INFO - sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift + sysUnsyncedTime++; // this can be compared to the synced time to measure + // long term drift #endif } if (nextSyncTime <= sysTime) { if (getTimePtr != 0) { time_t t = getTimePtr(); - + if (t != 0) { setTime(t); } else { nextSyncTime = sysTime + syncInterval; - Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; + Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; } } - } + } return sysTime; } -void setTime(time_t t) { +void setTime(time_t t) { #ifdef TIME_DRIFT_INFO - if(sysUnsyncedTime == 0) - sysUnsyncedTime = t; // store the time of the first call to set a valid Time + if (sysUnsyncedTime == 0) + sysUnsyncedTime = t; // store the time of the first call to set a valid Time #endif - sysTime = t; - nextSyncTime = t + (time_t) syncInterval; + sysTime = t; + nextSyncTime = t + (time_t)syncInterval; Status = timeSet; - #ifndef usePPS - prevMicros = micros(); // restart counting from now (thanks to Korman for this fix) - #endif -} +#ifndef usePPS + prevMicros = + micros(); // restart counting from now (thanks to Korman for this fix) +#endif +} void setTime(int hr, int min, int sec, int dy, int mnth, int yr) { - // year can be given as full four digit year or two digts (2010 or 10 for 2010); - // it is converted to years since 1970 + // year can be given as full four digit year or two digts (2010 or 10 for + // 2010); it is converted to years since 1970 if (yr > 99) - yr = CalendarYrToTm(yr); + yr = CalendarYrToTm(yr); else - yr = tmYearToY2k(yr); + yr = tmYearToY2k(yr); cacheElements.Year = yr; cacheElements.Month = mnth; cacheElements.Day = dy; @@ -337,9 +333,7 @@ void setTime(int hr, int min, int sec, int dy, int mnth, int yr) { setTime(cacheTime); } -void adjustTime(long adjustment) { - sysTime += adjustment; -} +void adjustTime(long adjustment) { sysTime += adjustment; } // indicates if time has been set and recently synchronized timeStatus_t timeStatus() { @@ -347,13 +341,14 @@ timeStatus_t timeStatus() { return Status; } -void setSyncProvider(getExternalTime getTimeFunction){ - getTimePtr = getTimeFunction; +void setSyncProvider(getExternalTime getTimeFunction) { + getTimePtr = getTimeFunction; nextSyncTime = sysTime; now(); // this will sync the clock } -void setSyncInterval(time_t interval){ // set the number of seconds between re-sync +void setSyncInterval( + time_t interval) { // set the number of seconds between re-sync syncInterval = (uint32_t)interval; nextSyncTime = sysTime + syncInterval; } diff --git a/lib/microTime/src/TimeLib.h b/lib/microTime/src/TimeLib.h index 713097f9..6ed36bc3 100644 --- a/lib/microTime/src/TimeLib.h +++ b/lib/microTime/src/TimeLib.h @@ -5,7 +5,7 @@ /* July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this) - fixed daysToTime_t macro (thanks maniacbug) -*/ +*/ #ifndef _Time_h #ifdef __cplusplus @@ -16,7 +16,6 @@ #include // for __time_t_defined, but avr libc lacks sys/types.h #endif - #if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc typedef unsigned long time_t; #endif @@ -33,126 +32,154 @@ typedef unsigned long time_t; // but at least this hack lets us define C++ functions as intended. Hopefully // nothing too terrible will result from overriding the C library header?! extern "C++" { -typedef enum {timeNotSet, timeNeedsSync, timeSet -} timeStatus_t ; +typedef enum { timeNotSet, timeNeedsSync, timeSet } timeStatus_t; typedef enum { - dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday + dowInvalid, + dowSunday, + dowMonday, + dowTuesday, + dowWednesday, + dowThursday, + dowFriday, + dowSaturday } timeDayOfWeek_t; typedef enum { - tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields -} tmByteFields; + tmSecond, + tmMinute, + tmHour, + tmWday, + tmDay, + tmMonth, + tmYear, + tmNbrFields +} tmByteFields; -typedef struct { - uint8_t Second; - uint8_t Minute; - uint8_t Hour; - uint8_t Wday; // day of week, sunday is day 1 +typedef struct { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // day of week, sunday is day 1 uint8_t Day; - uint8_t Month; - uint8_t Year; // offset from 1970; -} tmElements_t, TimeElements, *tmElementsPtr_t; + uint8_t Month; + uint8_t Year; // offset from 1970; +} tmElements_t, TimeElements, *tmElementsPtr_t; -//convenience macros to convert to and from tm years -#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year -#define CalendarYrToTm(Y) ((Y) - 1970) -#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 -#define y2kYearToTm(Y) ((Y) + 30) - -typedef time_t(*getExternalTime)(); -//typedef void (*setExternalTime)(const time_t); // not used in this version +// convenience macros to convert to and from tm years +#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year +#define CalendarYrToTm(Y) ((Y)-1970) +#define tmYearToY2k(Y) ((Y)-30) // offset is from 2000 +#define y2kYearToTm(Y) ((Y) + 30) +typedef time_t (*getExternalTime)(); +// typedef void (*setExternalTime)(const time_t); // not used in this version /*==============================================================================*/ /* Useful Constants */ -#define SECS_PER_MIN ((time_t)(60UL)) +#define SECS_PER_MIN ((time_t)(60UL)) #define SECS_PER_HOUR ((time_t)(3600UL)) -#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL)) +#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL)) #define DAYS_PER_WEEK ((time_t)(7UL)) #define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK)) -#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years -#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k - -/* Useful Macros for getting elapsed time */ -#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN) -#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN) -#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR) -#define dayOfWeek(_time_) ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday -#define elapsedDays(_time_) ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970 -#define elapsedSecsToday(_time_) ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight -// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 -// Always set the correct time before settting alarms -#define previousMidnight(_time_) (((_time_) / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day -#define nextMidnight(_time_) (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day -#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY)) // note that week starts on day 1 -#define previousSunday(_time_) ((_time_) - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time -#define nextSunday(_time_) (previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time +#define SECS_PER_YEAR \ + ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years +#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k +/* Useful Macros for getting elapsed time */ +#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN) +#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR) +#define dayOfWeek(_time_) \ + ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK) + 1) // 1 = Sunday +#define elapsedDays(_time_) \ + ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970 +#define elapsedSecsToday(_time_) \ + ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight +// The following macros are used in calculating alarms and assume the clock is +// set to a date later than Jan 1 1971 Always set the correct time before +// settting alarms +#define previousMidnight(_time_) \ + (((_time_) / SECS_PER_DAY) * \ + SECS_PER_DAY) // time at the start of the given day +#define nextMidnight(_time_) \ + (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day +#define elapsedSecsThisWeek(_time_) \ + (elapsedSecsToday(_time_) + \ + ((dayOfWeek(_time_) - 1) * SECS_PER_DAY)) // note that week starts on day 1 +#define previousSunday(_time_) \ + ((_time_)-elapsedSecsThisWeek( \ + _time_)) // time at the start of the week for the given time +#define nextSunday(_time_) \ + (previousSunday(_time_) + \ + SECS_PER_WEEK) // time at the end of the week for the given time /* Useful Macros for converting elapsed time to a time_t */ -#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) -#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) -#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 -#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) +#define minutesToTime_t ((M))((M)*SECS_PER_MIN) +#define hoursToTime_t ((H))((H)*SECS_PER_HOUR) +#define daysToTime_t ((D))((D)*SECS_PER_DAY) // fixed on Jul 22 2011 +#define weeksToTime_t ((W))((W)*SECS_PER_WEEK) /*============================================================================*/ /* time and date functions */ -int hour(); // the hour now -int hour(time_t t); // the hour for the given time -int hourFormat12(); // the hour now in 12 hour format -int hourFormat12(time_t t); // the hour for the given time in 12 hour format -uint8_t isAM(); // returns true if time now is AM -uint8_t isAM(time_t t); // returns true the given time is AM -uint8_t isPM(); // returns true if time now is PM -uint8_t isPM(time_t t); // returns true the given time is PM -int minute(); // the minute now -int minute(time_t t); // the minute for the given time -int second(); // the second now -int second(time_t t); // the second for the given time +int hour(); // the hour now +int hour(time_t t); // the hour for the given time +int hourFormat12(); // the hour now in 12 hour format +int hourFormat12(time_t t); // the hour for the given time in 12 hour format +uint8_t isAM(); // returns true if time now is AM +uint8_t isAM(time_t t); // returns true the given time is AM +uint8_t isPM(); // returns true if time now is PM +uint8_t isPM(time_t t); // returns true the given time is PM +int minute(); // the minute now +int minute(time_t t); // the minute for the given time +int second(); // the second now +int second(time_t t); // the second for the given time #ifdef TIMELIB_ENABLE_MILLIS -int millisecond(); // the millisecond now -int microsecond(); +int millisecond(); // the millisecond now +int microsecond(); #endif -int day(); // the day now -int day(time_t t); // the day for the given time -int weekday(); // the weekday now (Sunday is day 1) -int weekday(time_t t); // the weekday for the given time -int month(); // the month now (Jan is month 1) -int month(time_t t); // the month for the given time -int year(); // the full four digit year: (2009, 2010 etc) -int year(time_t t); // the year for the given time +int day(); // the day now +int day(time_t t); // the day for the given time +int weekday(); // the weekday now (Sunday is day 1) +int weekday(time_t t); // the weekday for the given time +int month(); // the month now (Jan is month 1) +int month(time_t t); // the month for the given time +int year(); // the full four digit year: (2009, 2010 etc) +int year(time_t t); // the year for the given time -time_t now(); // return the current time as seconds since Jan 1 1970 -#ifdef TIMELIB_ENABLE_MILLIS -time_t now(uint32_t& sysTimeMicros); // return the current time as seconds and microseconds since Jan 1 1970 +time_t now(); // return the current time as seconds since Jan 1 1970 +#ifdef TIMELIB_ENABLE_MILLIS +time_t now(uint32_t &sysTimeMicros); // return the current time as seconds and + // microseconds since Jan 1 1970 #endif #ifdef usePPS -void SyncToPPS(); +time_t SyncToPPS(); #endif -void setTime(time_t t); -void setTime(int hr,int min,int sec,int day, int month, int yr); -void adjustTime(long adjustment); +void setTime(time_t t); +void setTime(int hr, int min, int sec, int day, int month, int yr); +void adjustTime(long adjustment); +/* date strings */ +#define dt_MAX_STRING_LEN \ + 9 // length of longest date string (excluding terminating null) +char *monthStr(uint8_t month); +char *dayStr(uint8_t day); +char *monthShortStr(uint8_t month); +char *dayShortStr(uint8_t day); -/* date strings */ -#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) -char* monthStr(uint8_t month); -char* dayStr(uint8_t day); -char* monthShortStr(uint8_t month); -char* dayShortStr(uint8_t day); - /* time sync functions */ -timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized -void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider -void setSyncInterval(time_t interval); // set the number of seconds between re-sync +timeStatus_t +timeStatus(); // indicates if time has been set and recently synchronized +void setSyncProvider( + getExternalTime getTimeFunction); // identify the external time provider +void setSyncInterval( + time_t interval); // set the number of seconds between re-sync /* low level functions to convert to and from system time */ -void breakTime(time_t time, tmElements_t &tm); // break time_t into elements -time_t makeTime(const tmElements_t &tm); // convert time elements into time_t +void breakTime(time_t time, tmElements_t &tm); // break time_t into elements +time_t makeTime(const tmElements_t &tm); // convert time elements into time_t } // extern "C++" #endif // __cplusplus #endif /* _Time_h */ - diff --git a/src/display.cpp b/src/display.cpp index 047c233e..4abed281 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -131,7 +131,7 @@ void refreshtheDisplay() { uint8_t msgWaiting; char timeState, buff[16]; - time_t t = myTZ.toLocal(now()); // note: call now() here *before* locking mutex! + const time_t t = myTZ.toLocal(now()); // note: call now() here *before* locking mutex! // block i2c bus access if (I2C_MUTEX_LOCK()) { diff --git a/src/main.cpp b/src/main.cpp index 2fa91e8b..bf32e01d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -358,10 +358,13 @@ void setup() { #endif #endif - // start pps timepulse and timekeepr + // start pps timepulse ESP_LOGI(TAG, "Starting Timekeeper..."); assert(timepulse_init()); // setup timepulse timepulse_start(); + // set time source and sync time + setSyncInterval(TIME_SYNC_INTERVAL * 60); + setSyncProvider(&timeProvider); // start wifi in monitor mode and start channel rotation timer ESP_LOGI(TAG, "Starting Wifi..."); @@ -414,10 +417,6 @@ void setup() { #endif #endif // HAS_BUTTON - // set time source - setSyncInterval(TIME_SYNC_INTERVAL * 60); - setSyncProvider(&timeProvider); - #if defined HAS_IF482 || defined HAS_DCF77 ESP_LOGI(TAG, "Starting Clock Controller..."); clock_init(); diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 5b75b637..9fd671c6 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -15,10 +15,8 @@ time_t timeProvider(void) { time_t t = 0; #ifdef HAS_GPS - // xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1100)); // wait for pps t = get_gpstime(); // fetch recent time from last NEMA record if (t) { - // t++; // last NMEA record concerns past second, so we add one #ifdef HAS_RTC set_rtctime(t); // calibrate RTC #endif @@ -102,10 +100,10 @@ void timepulse_start(void) { // interrupt service routine triggered by either pps or esp32 hardware timer void IRAM_ATTR CLOCKIRQ(void) { - SyncToPPS(); // calibrate systime from Time.h + time_t t = SyncToPPS(); // calibrates UTC systime, see Time.h if (ClockTask != NULL) - xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, NULL); + xTaskNotifyFromISR(ClockTask, uint32_t(t), eSetBits, NULL); #if defined GPS_INT || defined RTC_INT xSemaphoreGiveFromISR(TimePulse, NULL); @@ -167,61 +165,61 @@ void clock_init(void) { pinMode(HAS_DCF77, OUTPUT); #endif - xTaskCreatePinnedToCore(clock_loop, // task function - "clockloop", // name of task - 2048, // stack size of task - (void *)1, // task parameter - 4, // priority of the task - &ClockTask, // task handle - 1); // CPU core + userUTCTime = now(); + + xTaskCreatePinnedToCore(clock_loop, // task function + "clockloop", // name of task + 2048, // stack size of task + (void *)&userUTCTime, // start time as task parameter + 4, // priority of the task + &ClockTask, // task handle + 1); // CPU core assert(ClockTask); // has clock task started? } // clock_init -void clock_loop(void *pvParameters) { // ClockTask +void clock_loop(void *taskparameter) { // ClockTask - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check + // caveat: don't use now() in this task, it will cause a race condition + // due to concurrent access to i2c bus for setting rtc via SyncProvider! + +#define nextsec(t) (t + 1) // next second +#define nextmin(t) (t + SECS_PER_MIN + 1) // next minute - TickType_t wakeTime; uint32_t printtime; - time_t t; - -#define t1(t) (t + DCF77_FRAME_SIZE + 1) // future minute for next DCF77 frame -#define t2(t) (t + 1) // future second after sync with 1pps trigger + time_t t = *((time_t *)taskparameter); // UTC time seconds // preload first DCF frame before start #ifdef HAS_DCF77 uint8_t *DCFpulse; // pointer on array with DCF pulse bits - DCFpulse = DCF77_Frame(t1(now())); + DCFpulse = DCF77_Frame(nextmin(t)); #endif - // output time telegram for second following sec beginning with timepulse + // output the next second's pulse after timepulse arrived for (;;) { xTaskNotifyWait(0x00, ULONG_MAX, &printtime, portMAX_DELAY); // wait for timepulse - // no confident time -> suppress clock output + // no confident time -> we suppress clock output if (timeStatus() == timeNotSet) continue; - t = time_t(printtime); + t = time_t(printtime); // UTC time seconds #if defined HAS_IF482 - // IF482_Pulse(t2(t)); // next second - IF482_Pulse(t); // next second + IF482_Pulse(nextsec(t)); #elif defined HAS_DCF77 if (second(t) == DCF77_FRAME_SIZE - 1) // is it time to load new frame? - DCFpulse = DCF77_Frame(t1(t)); // generate next frame + DCFpulse = DCF77_Frame(nextmin(t)); // generate frame for next minute - if (DCFpulse[DCF77_FRAME_SIZE] != - minute(t1(t))) // have recent frame? (timepulses could be missed!) - continue; + if (minute(nextmin(t)) == // do we still have a recent frame? + DCFpulse[DCF77_FRAME_SIZE]) // (timepulses could be missed!) + DCF77_Pulse(t, DCFpulse); // then output current second's pulse else - // DCF77_Pulse(t2(t), DCFpulse); // then output next second of this frame - DCF77_Pulse(t, DCFpulse); // then output next second of this frame + continue; // no recent frame -> we suppress clock output #endif