commit
49fd795ade
@ -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 <Arduino.h>
|
|
||||||
#else
|
|
||||||
#include <WProgram.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
@ -27,11 +27,7 @@
|
|||||||
1.4 5 Sep 2014 - compatibility with Arduino 1.5.7
|
1.4 5 Sep 2014 - compatibility with Arduino 1.5.7
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if ARDUINO >= 100
|
#include <Arduino.h>
|
||||||
#include <Arduino.h>
|
|
||||||
#else
|
|
||||||
#include <WProgram.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TIMELIB_ENABLE_MILLIS
|
#define TIMELIB_ENABLE_MILLIS
|
||||||
#define usePPS
|
#define usePPS
|
||||||
@ -41,9 +37,10 @@
|
|||||||
// Convert days since epoch to week day. Sunday is day 1.
|
// Convert days since epoch to week day. Sunday is day 1.
|
||||||
#define DAYS_TO_WDAY(x) (((x) + 4) % 7) + 1
|
#define DAYS_TO_WDAY(x) (((x) + 4) % 7) + 1
|
||||||
|
|
||||||
static tmElements_t cacheElements; // a cache of time elements
|
static tmElements_t cacheElements; // a cache of time elements
|
||||||
static time_t cacheTime; // the time the cache was updated
|
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 uint32_t syncInterval =
|
||||||
|
300; // time sync will be attempted after this many seconds
|
||||||
|
|
||||||
void refreshCache(time_t t) {
|
void refreshCache(time_t t) {
|
||||||
if (t != cacheTime) {
|
if (t != cacheTime) {
|
||||||
@ -52,8 +49,8 @@ void refreshCache(time_t t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int hour() { // the hour now
|
int hour() { // the hour now
|
||||||
return hour(now());
|
return hour(now());
|
||||||
}
|
}
|
||||||
|
|
||||||
int hour(time_t t) { // the hour for the given time
|
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
|
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
|
int hourFormat12(time_t t) { // the hour for the given time in 12 hour format
|
||||||
refreshCache(t);
|
refreshCache(t);
|
||||||
if( cacheElements.Hour == 0 )
|
if (cacheElements.Hour == 0)
|
||||||
return 12; // 12 midnight
|
return 12; // 12 midnight
|
||||||
else if( cacheElements.Hour > 12)
|
else if (cacheElements.Hour > 12)
|
||||||
return cacheElements.Hour - 12 ;
|
return cacheElements.Hour - 12;
|
||||||
else
|
else
|
||||||
return cacheElements.Hour ;
|
return cacheElements.Hour;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t isAM() { // returns true if time now is AM
|
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
|
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
|
uint8_t isPM() { // returns true if PM
|
||||||
return isPM(now());
|
return isPM(now());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t isPM(time_t t) { // returns true if PM
|
uint8_t isPM(time_t t) { // returns true if PM
|
||||||
return (hour(t) >= 12);
|
return (hour(t) >= 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
int minute() {
|
int minute() { return minute(now()); }
|
||||||
return minute(now());
|
|
||||||
}
|
|
||||||
|
|
||||||
int minute(time_t t) { // the minute for the given time
|
int minute(time_t t) { // the minute for the given time
|
||||||
refreshCache(t);
|
refreshCache(t);
|
||||||
return cacheElements.Minute;
|
return cacheElements.Minute;
|
||||||
}
|
}
|
||||||
|
|
||||||
int second() {
|
int second() { return second(now()); }
|
||||||
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);
|
refreshCache(t);
|
||||||
return cacheElements.Second;
|
return cacheElements.Second;
|
||||||
}
|
}
|
||||||
@ -122,35 +115,31 @@ int microsecond() {
|
|||||||
return (int)us;
|
return (int)us;
|
||||||
}
|
}
|
||||||
|
|
||||||
int day(){
|
int day() { return (day(now())); }
|
||||||
return(day(now()));
|
|
||||||
}
|
|
||||||
|
|
||||||
int day(time_t t) { // the day for the given time (0-6)
|
int day(time_t t) { // the day for the given time (0-6)
|
||||||
refreshCache(t);
|
refreshCache(t);
|
||||||
return cacheElements.Day;
|
return cacheElements.Day;
|
||||||
}
|
}
|
||||||
|
|
||||||
int weekday() { // Sunday is day 1
|
int weekday() { // Sunday is day 1
|
||||||
return weekday(now());
|
return weekday(now());
|
||||||
}
|
}
|
||||||
|
|
||||||
int weekday(time_t t) {
|
int weekday(time_t t) {
|
||||||
refreshCache(t);
|
refreshCache(t);
|
||||||
return cacheElements.Wday;
|
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);
|
refreshCache(t);
|
||||||
return cacheElements.Month;
|
return cacheElements.Month;
|
||||||
}
|
}
|
||||||
|
|
||||||
int year() { // as in Processing, the full four digit year: (2009, 2010 etc)
|
int year() { // as in Processing, the full four digit year: (2009, 2010 etc)
|
||||||
return year(now());
|
return year(now());
|
||||||
}
|
}
|
||||||
|
|
||||||
int year(time_t t) { // the year for the given time
|
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);
|
return tmYearToCalendar(cacheElements.Year);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
/* functions to convert to and from system time */
|
/* 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
|
// 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 LEAP_YEAR(Y) \
|
||||||
#define daysInYear(year) ((time_t) (LEAP_YEAR(year) ? 366 : 365))
|
(((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){
|
void breakTime(time_t time, tmElements_t &tm) {
|
||||||
// break the given time_t into time components
|
// break the given time_t into time components
|
||||||
// this is a more compact version of the C library localtime function
|
// this is a more compact version of the C library localtime function
|
||||||
// note that year is offset from 1970 !!!
|
// note that year is offset from 1970 !!!
|
||||||
|
|
||||||
uint8_t period;
|
uint8_t period;
|
||||||
time_t length;
|
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
|
// if the number of days since epoch matches cacheTime, then can take date
|
||||||
// elements from cacheElements and avoid expensive calculation.
|
// elements from cacheElements and avoid expensive calculation.
|
||||||
if (time == (cacheTime / SECS_PER_DAY)) {
|
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.Wday = cacheElements.Wday;
|
||||||
tm.Day = cacheElements.Day;
|
tm.Day = cacheElements.Day;
|
||||||
tm.Month = cacheElements.Month;
|
tm.Month = cacheElements.Month;
|
||||||
@ -196,34 +190,34 @@ void breakTime(time_t time, tmElements_t &tm){
|
|||||||
}
|
}
|
||||||
|
|
||||||
tm.Wday = DAYS_TO_WDAY(time);
|
tm.Wday = DAYS_TO_WDAY(time);
|
||||||
|
|
||||||
period = 0;
|
period = 0;
|
||||||
while (time >= (length = daysInYear(period)))
|
while (time >= (length = daysInYear(period))) {
|
||||||
{
|
|
||||||
time -= length;
|
time -= length;
|
||||||
period++;
|
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
|
// time is now days since 1 Jan of the year
|
||||||
|
|
||||||
bool leap_year = LEAP_YEAR(period);
|
bool leap_year = LEAP_YEAR(period);
|
||||||
period = 0;
|
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;
|
time -= length;
|
||||||
period++;
|
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
|
// 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){
|
time_t makeTime(const tmElements_t &tm) {
|
||||||
// assemble time elements into time_t
|
// assemble time elements into time_t
|
||||||
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
|
// note year argument is offset from 1970 (see macros in time.h to convert to
|
||||||
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
|
// other formats) previous version used full four digit year (or digits since
|
||||||
|
// 2000),i.e. 2009 was 2009 or 9
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
uint32_t seconds;
|
uint32_t seconds;
|
||||||
|
|
||||||
@ -231,25 +225,26 @@ time_t makeTime(const tmElements_t &tm){
|
|||||||
seconds = SECS_PER_DAY * (365 * tm.Year);
|
seconds = SECS_PER_DAY * (365 * tm.Year);
|
||||||
for (i = 0; i < tm.Year; i++) {
|
for (i = 0; i < tm.Year; i++) {
|
||||||
if (LEAP_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
|
// add days for this year, months start from 1
|
||||||
for (i = 1; i < tm.Month; i++) {
|
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;
|
seconds += SECS_PER_DAY * 29;
|
||||||
} else {
|
} 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.Day - 1) * SECS_PER_DAY;
|
||||||
seconds+= tm.Hour * SECS_PER_HOUR;
|
seconds += tm.Hour * SECS_PER_HOUR;
|
||||||
seconds+= tm.Minute * SECS_PER_MIN;
|
seconds += tm.Minute * SECS_PER_MIN;
|
||||||
seconds+= tm.Second;
|
seconds += tm.Second;
|
||||||
return (time_t)seconds;
|
return (time_t)seconds;
|
||||||
}
|
}
|
||||||
/*=====================================================*/
|
/*=====================================================*/
|
||||||
/* Low level system time functions */
|
/* Low level system time functions */
|
||||||
|
|
||||||
static time_t sysTime = 0;
|
static time_t sysTime = 0;
|
||||||
@ -257,19 +252,18 @@ static uint32_t prevMicros = 0;
|
|||||||
static time_t nextSyncTime = 0;
|
static time_t nextSyncTime = 0;
|
||||||
static timeStatus_t Status = timeNotSet;
|
static timeStatus_t Status = timeNotSet;
|
||||||
|
|
||||||
getExternalTime getTimePtr; // pointer to external sync function
|
getExternalTime getTimePtr; // pointer to external sync function
|
||||||
//setExternalTime setTimePtr; // not used in this version
|
// setExternalTime setTimePtr; // not used in this version
|
||||||
|
|
||||||
#ifdef TIME_DRIFT_INFO // define this to get drift data
|
#ifdef TIME_DRIFT_INFO // define this to get drift data
|
||||||
time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
|
time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef usePPS
|
#ifdef usePPS
|
||||||
void SyncToPPS()
|
time_t SyncToPPS() {
|
||||||
{
|
|
||||||
sysTime++;
|
sysTime++;
|
||||||
prevMicros = micros();
|
prevMicros = micros();
|
||||||
//Serial.println(prevMicros);
|
return sysTime;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -278,54 +272,56 @@ time_t now() {
|
|||||||
return now(sysTimeMicros);
|
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()
|
// 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
|
// micros() and prevMicros are both unsigned ints thus the subtraction will
|
||||||
// always result in a positive difference. This is OK since it corrects for
|
// always result in a positive difference. This is OK since it corrects for
|
||||||
// wrap-around and micros() is monotonic.
|
// wrap-around and micros() is monotonic.
|
||||||
sysTime++;
|
sysTime++;
|
||||||
prevMicros += 1000000;
|
prevMicros += 1000000;
|
||||||
#ifdef TIME_DRIFT_INFO
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
if (nextSyncTime <= sysTime) {
|
if (nextSyncTime <= sysTime) {
|
||||||
if (getTimePtr != 0) {
|
if (getTimePtr != 0) {
|
||||||
time_t t = getTimePtr();
|
time_t t = getTimePtr();
|
||||||
|
|
||||||
if (t != 0) {
|
if (t != 0) {
|
||||||
setTime(t);
|
setTime(t);
|
||||||
} else {
|
} else {
|
||||||
nextSyncTime = sysTime + syncInterval;
|
nextSyncTime = sysTime + syncInterval;
|
||||||
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
|
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sysTime;
|
return sysTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTime(time_t t) {
|
void setTime(time_t t) {
|
||||||
#ifdef TIME_DRIFT_INFO
|
#ifdef TIME_DRIFT_INFO
|
||||||
if(sysUnsyncedTime == 0)
|
if (sysUnsyncedTime == 0)
|
||||||
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
|
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sysTime = t;
|
sysTime = t;
|
||||||
nextSyncTime = t + (time_t) syncInterval;
|
nextSyncTime = t + (time_t)syncInterval;
|
||||||
Status = timeSet;
|
Status = timeSet;
|
||||||
#ifndef usePPS
|
#ifndef usePPS
|
||||||
prevMicros = micros(); // restart counting from now (thanks to Korman for this fix)
|
prevMicros =
|
||||||
#endif
|
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) {
|
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);
|
// year can be given as full four digit year or two digts (2010 or 10 for
|
||||||
// it is converted to years since 1970
|
// 2010); it is converted to years since 1970
|
||||||
if (yr > 99)
|
if (yr > 99)
|
||||||
yr = CalendarYrToTm(yr);
|
yr = CalendarYrToTm(yr);
|
||||||
else
|
else
|
||||||
yr = tmYearToY2k(yr);
|
yr = tmYearToY2k(yr);
|
||||||
cacheElements.Year = yr;
|
cacheElements.Year = yr;
|
||||||
cacheElements.Month = mnth;
|
cacheElements.Month = mnth;
|
||||||
cacheElements.Day = dy;
|
cacheElements.Day = dy;
|
||||||
@ -337,9 +333,7 @@ void setTime(int hr, int min, int sec, int dy, int mnth, int yr) {
|
|||||||
setTime(cacheTime);
|
setTime(cacheTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjustTime(long adjustment) {
|
void adjustTime(long adjustment) { sysTime += adjustment; }
|
||||||
sysTime += adjustment;
|
|
||||||
}
|
|
||||||
|
|
||||||
// indicates if time has been set and recently synchronized
|
// indicates if time has been set and recently synchronized
|
||||||
timeStatus_t timeStatus() {
|
timeStatus_t timeStatus() {
|
||||||
@ -347,13 +341,14 @@ timeStatus_t timeStatus() {
|
|||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSyncProvider(getExternalTime getTimeFunction){
|
void setSyncProvider(getExternalTime getTimeFunction) {
|
||||||
getTimePtr = getTimeFunction;
|
getTimePtr = getTimeFunction;
|
||||||
nextSyncTime = sysTime;
|
nextSyncTime = sysTime;
|
||||||
now(); // this will sync the clock
|
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;
|
syncInterval = (uint32_t)interval;
|
||||||
nextSyncTime = sysTime + syncInterval;
|
nextSyncTime = sysTime + syncInterval;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/*
|
/*
|
||||||
July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this)
|
July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this)
|
||||||
- fixed daysToTime_t macro (thanks maniacbug)
|
- fixed daysToTime_t macro (thanks maniacbug)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _Time_h
|
#ifndef _Time_h
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -16,7 +16,6 @@
|
|||||||
#include <sys/types.h> // for __time_t_defined, but avr libc lacks sys/types.h
|
#include <sys/types.h> // for __time_t_defined, but avr libc lacks sys/types.h
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc
|
#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc
|
||||||
typedef unsigned long time_t;
|
typedef unsigned long time_t;
|
||||||
#endif
|
#endif
|
||||||
@ -33,126 +32,154 @@ typedef unsigned long time_t;
|
|||||||
// but at least this hack lets us define C++ functions as intended. Hopefully
|
// but at least this hack lets us define C++ functions as intended. Hopefully
|
||||||
// nothing too terrible will result from overriding the C library header?!
|
// nothing too terrible will result from overriding the C library header?!
|
||||||
extern "C++" {
|
extern "C++" {
|
||||||
typedef enum {timeNotSet, timeNeedsSync, timeSet
|
typedef enum { timeNotSet, timeNeedsSync, timeSet } timeStatus_t;
|
||||||
} timeStatus_t ;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
|
dowInvalid,
|
||||||
|
dowSunday,
|
||||||
|
dowMonday,
|
||||||
|
dowTuesday,
|
||||||
|
dowWednesday,
|
||||||
|
dowThursday,
|
||||||
|
dowFriday,
|
||||||
|
dowSaturday
|
||||||
} timeDayOfWeek_t;
|
} timeDayOfWeek_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields
|
tmSecond,
|
||||||
} tmByteFields;
|
tmMinute,
|
||||||
|
tmHour,
|
||||||
|
tmWday,
|
||||||
|
tmDay,
|
||||||
|
tmMonth,
|
||||||
|
tmYear,
|
||||||
|
tmNbrFields
|
||||||
|
} tmByteFields;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t Second;
|
uint8_t Second;
|
||||||
uint8_t Minute;
|
uint8_t Minute;
|
||||||
uint8_t Hour;
|
uint8_t Hour;
|
||||||
uint8_t Wday; // day of week, sunday is day 1
|
uint8_t Wday; // day of week, sunday is day 1
|
||||||
uint8_t Day;
|
uint8_t Day;
|
||||||
uint8_t Month;
|
uint8_t Month;
|
||||||
uint8_t Year; // offset from 1970;
|
uint8_t Year; // offset from 1970;
|
||||||
} tmElements_t, TimeElements, *tmElementsPtr_t;
|
} tmElements_t, TimeElements, *tmElementsPtr_t;
|
||||||
|
|
||||||
//convenience macros to convert to and from tm years
|
// convenience macros to convert to and from tm years
|
||||||
#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year
|
#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year
|
||||||
#define CalendarYrToTm(Y) ((Y) - 1970)
|
#define CalendarYrToTm(Y) ((Y)-1970)
|
||||||
#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000
|
#define tmYearToY2k(Y) ((Y)-30) // offset is from 2000
|
||||||
#define y2kYearToTm(Y) ((Y) + 30)
|
#define y2kYearToTm(Y) ((Y) + 30)
|
||||||
|
|
||||||
typedef time_t(*getExternalTime)();
|
|
||||||
//typedef void (*setExternalTime)(const time_t); // not used in this version
|
|
||||||
|
|
||||||
|
typedef time_t (*getExternalTime)();
|
||||||
|
// typedef void (*setExternalTime)(const time_t); // not used in this version
|
||||||
|
|
||||||
/*==============================================================================*/
|
/*==============================================================================*/
|
||||||
/* Useful Constants */
|
/* 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_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 DAYS_PER_WEEK ((time_t)(7UL))
|
||||||
#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK))
|
#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_PER_YEAR \
|
||||||
#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k
|
((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 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 */
|
/* Useful Macros for converting elapsed time to a time_t */
|
||||||
#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN)
|
#define minutesToTime_t ((M))((M)*SECS_PER_MIN)
|
||||||
#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR)
|
#define hoursToTime_t ((H))((H)*SECS_PER_HOUR)
|
||||||
#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011
|
#define daysToTime_t ((D))((D)*SECS_PER_DAY) // fixed on Jul 22 2011
|
||||||
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK)
|
#define weeksToTime_t ((W))((W)*SECS_PER_WEEK)
|
||||||
|
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
/* time and date functions */
|
/* time and date functions */
|
||||||
int hour(); // the hour now
|
int hour(); // the hour now
|
||||||
int hour(time_t t); // the hour for the given time
|
int hour(time_t t); // the hour for the given time
|
||||||
int hourFormat12(); // the hour now in 12 hour format
|
int hourFormat12(); // the hour now in 12 hour format
|
||||||
int hourFormat12(time_t t); // the hour for the given time 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(); // returns true if time now is AM
|
||||||
uint8_t isAM(time_t t); // returns true the given time 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(); // returns true if time now is PM
|
||||||
uint8_t isPM(time_t t); // returns true the given time is PM
|
uint8_t isPM(time_t t); // returns true the given time is PM
|
||||||
int minute(); // the minute now
|
int minute(); // the minute now
|
||||||
int minute(time_t t); // the minute for the given time
|
int minute(time_t t); // the minute for the given time
|
||||||
int second(); // the second now
|
int second(); // the second now
|
||||||
int second(time_t t); // the second for the given time
|
int second(time_t t); // the second for the given time
|
||||||
#ifdef TIMELIB_ENABLE_MILLIS
|
#ifdef TIMELIB_ENABLE_MILLIS
|
||||||
int millisecond(); // the millisecond now
|
int millisecond(); // the millisecond now
|
||||||
int microsecond();
|
int microsecond();
|
||||||
#endif
|
#endif
|
||||||
int day(); // the day now
|
int day(); // the day now
|
||||||
int day(time_t t); // the day for the given time
|
int day(time_t t); // the day for the given time
|
||||||
int weekday(); // the weekday now (Sunday is day 1)
|
int weekday(); // the weekday now (Sunday is day 1)
|
||||||
int weekday(time_t t); // the weekday for the given time
|
int weekday(time_t t); // the weekday for the given time
|
||||||
int month(); // the month now (Jan is month 1)
|
int month(); // the month now (Jan is month 1)
|
||||||
int month(time_t t); // the month for the given time
|
int month(time_t t); // the month for the given time
|
||||||
int year(); // the full four digit year: (2009, 2010 etc)
|
int year(); // the full four digit year: (2009, 2010 etc)
|
||||||
int year(time_t t); // the year for the given time
|
int year(time_t t); // the year for the given time
|
||||||
|
|
||||||
time_t now(); // return the current time as seconds since Jan 1 1970
|
time_t now(); // return the current time as seconds since Jan 1 1970
|
||||||
#ifdef TIMELIB_ENABLE_MILLIS
|
#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(uint32_t &sysTimeMicros); // return the current time as seconds and
|
||||||
|
// microseconds since Jan 1 1970
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef usePPS
|
#ifdef usePPS
|
||||||
void SyncToPPS();
|
time_t SyncToPPS();
|
||||||
#endif
|
#endif
|
||||||
void setTime(time_t t);
|
void setTime(time_t t);
|
||||||
void setTime(int hr,int min,int sec,int day, int month, int yr);
|
void setTime(int hr, int min, int sec, int day, int month, int yr);
|
||||||
void adjustTime(long adjustment);
|
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 */
|
/* time sync functions */
|
||||||
timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized
|
timeStatus_t
|
||||||
void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider
|
timeStatus(); // indicates if time has been set and recently synchronized
|
||||||
void setSyncInterval(time_t interval); // set the number of seconds between re-sync
|
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 */
|
/* low level functions to convert to and from system time */
|
||||||
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
|
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
|
time_t makeTime(const tmElements_t &tm); // convert time elements into time_t
|
||||||
|
|
||||||
} // extern "C++"
|
} // extern "C++"
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
#endif /* _Time_h */
|
#endif /* _Time_h */
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ void refreshtheDisplay() {
|
|||||||
|
|
||||||
uint8_t msgWaiting;
|
uint8_t msgWaiting;
|
||||||
char timeState, buff[16];
|
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
|
// block i2c bus access
|
||||||
if (I2C_MUTEX_LOCK()) {
|
if (I2C_MUTEX_LOCK()) {
|
||||||
|
@ -358,10 +358,13 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// start pps timepulse and timekeepr
|
// start pps timepulse
|
||||||
ESP_LOGI(TAG, "Starting Timekeeper...");
|
ESP_LOGI(TAG, "Starting Timekeeper...");
|
||||||
assert(timepulse_init()); // setup timepulse
|
assert(timepulse_init()); // setup timepulse
|
||||||
timepulse_start();
|
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
|
// start wifi in monitor mode and start channel rotation timer
|
||||||
ESP_LOGI(TAG, "Starting Wifi...");
|
ESP_LOGI(TAG, "Starting Wifi...");
|
||||||
@ -414,10 +417,6 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
|
|
||||||
// set time source
|
|
||||||
setSyncInterval(TIME_SYNC_INTERVAL * 60);
|
|
||||||
setSyncProvider(&timeProvider);
|
|
||||||
|
|
||||||
#if defined HAS_IF482 || defined HAS_DCF77
|
#if defined HAS_IF482 || defined HAS_DCF77
|
||||||
ESP_LOGI(TAG, "Starting Clock Controller...");
|
ESP_LOGI(TAG, "Starting Clock Controller...");
|
||||||
clock_init();
|
clock_init();
|
||||||
|
@ -15,10 +15,8 @@ time_t timeProvider(void) {
|
|||||||
time_t t = 0;
|
time_t t = 0;
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
// xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1100)); // wait for pps
|
|
||||||
t = get_gpstime(); // fetch recent time from last NEMA record
|
t = get_gpstime(); // fetch recent time from last NEMA record
|
||||||
if (t) {
|
if (t) {
|
||||||
// t++; // last NMEA record concerns past second, so we add one
|
|
||||||
#ifdef HAS_RTC
|
#ifdef HAS_RTC
|
||||||
set_rtctime(t); // calibrate RTC
|
set_rtctime(t); // calibrate RTC
|
||||||
#endif
|
#endif
|
||||||
@ -102,10 +100,10 @@ void timepulse_start(void) {
|
|||||||
// interrupt service routine triggered by either pps or esp32 hardware timer
|
// interrupt service routine triggered by either pps or esp32 hardware timer
|
||||||
void IRAM_ATTR CLOCKIRQ(void) {
|
void IRAM_ATTR CLOCKIRQ(void) {
|
||||||
|
|
||||||
SyncToPPS(); // calibrate systime from Time.h
|
time_t t = SyncToPPS(); // calibrates UTC systime, see Time.h
|
||||||
|
|
||||||
if (ClockTask != NULL)
|
if (ClockTask != NULL)
|
||||||
xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, NULL);
|
xTaskNotifyFromISR(ClockTask, uint32_t(t), eSetBits, NULL);
|
||||||
|
|
||||||
#if defined GPS_INT || defined RTC_INT
|
#if defined GPS_INT || defined RTC_INT
|
||||||
xSemaphoreGiveFromISR(TimePulse, NULL);
|
xSemaphoreGiveFromISR(TimePulse, NULL);
|
||||||
@ -167,61 +165,61 @@ void clock_init(void) {
|
|||||||
pinMode(HAS_DCF77, OUTPUT);
|
pinMode(HAS_DCF77, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(clock_loop, // task function
|
userUTCTime = now();
|
||||||
"clockloop", // name of task
|
|
||||||
2048, // stack size of task
|
xTaskCreatePinnedToCore(clock_loop, // task function
|
||||||
(void *)1, // task parameter
|
"clockloop", // name of task
|
||||||
4, // priority of the task
|
2048, // stack size of task
|
||||||
&ClockTask, // task handle
|
(void *)&userUTCTime, // start time as task parameter
|
||||||
1); // CPU core
|
4, // priority of the task
|
||||||
|
&ClockTask, // task handle
|
||||||
|
1); // CPU core
|
||||||
|
|
||||||
assert(ClockTask); // has clock task started?
|
assert(ClockTask); // has clock task started?
|
||||||
} // clock_init
|
} // 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;
|
uint32_t printtime;
|
||||||
time_t t;
|
time_t t = *((time_t *)taskparameter); // UTC time seconds
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
// preload first DCF frame before start
|
// preload first DCF frame before start
|
||||||
#ifdef HAS_DCF77
|
#ifdef HAS_DCF77
|
||||||
uint8_t *DCFpulse; // pointer on array with DCF pulse bits
|
uint8_t *DCFpulse; // pointer on array with DCF pulse bits
|
||||||
DCFpulse = DCF77_Frame(t1(now()));
|
DCFpulse = DCF77_Frame(nextmin(t));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// output time telegram for second following sec beginning with timepulse
|
// output the next second's pulse after timepulse arrived
|
||||||
for (;;) {
|
for (;;) {
|
||||||
xTaskNotifyWait(0x00, ULONG_MAX, &printtime,
|
xTaskNotifyWait(0x00, ULONG_MAX, &printtime,
|
||||||
portMAX_DELAY); // wait for timepulse
|
portMAX_DELAY); // wait for timepulse
|
||||||
|
|
||||||
// no confident time -> suppress clock output
|
// no confident time -> we suppress clock output
|
||||||
if (timeStatus() == timeNotSet)
|
if (timeStatus() == timeNotSet)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
t = time_t(printtime);
|
t = time_t(printtime); // UTC time seconds
|
||||||
|
|
||||||
#if defined HAS_IF482
|
#if defined HAS_IF482
|
||||||
|
|
||||||
// IF482_Pulse(t2(t)); // next second
|
IF482_Pulse(nextsec(t));
|
||||||
IF482_Pulse(t); // next second
|
|
||||||
|
|
||||||
#elif defined HAS_DCF77
|
#elif defined HAS_DCF77
|
||||||
|
|
||||||
if (second(t) == DCF77_FRAME_SIZE - 1) // is it time to load new frame?
|
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] !=
|
if (minute(nextmin(t)) == // do we still have a recent frame?
|
||||||
minute(t1(t))) // have recent frame? (timepulses could be missed!)
|
DCFpulse[DCF77_FRAME_SIZE]) // (timepulses could be missed!)
|
||||||
continue;
|
DCF77_Pulse(t, DCFpulse); // then output current second's pulse
|
||||||
else
|
else
|
||||||
// DCF77_Pulse(t2(t), DCFpulse); // then output next second of this frame
|
continue; // no recent frame -> we suppress clock output
|
||||||
DCF77_Pulse(t, DCFpulse); // then output next second of this frame
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user