mirror of https://github.com/jeelabs/esp-link.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
6.4 KiB
274 lines
6.4 KiB
9 years ago
|
#include "Time.h"
|
||
|
|
||
|
static tmElements_t tm; // a cache of time elements
|
||
|
static time_t cacheTime; // the time the cache was updated
|
||
|
static time_t syncInterval = 300; // time sync will be attempted after this many seconds
|
||
|
|
||
|
static os_timer_t micros_overflow_timer;
|
||
|
static uint32_t micros_at_last_overflow_tick = 0;
|
||
|
static uint32_t micros_overflow_count = 0;
|
||
|
|
||
|
static time_t sysTime = 0;
|
||
|
static time_t prevMillis = 0;
|
||
|
static time_t nextSyncTime = 0;
|
||
|
static timeStatus_t Status = timeNotSet;
|
||
|
|
||
|
getExternalTime getTimePtr;
|
||
|
|
||
|
int16_t ICACHE_FLASH_ATTR
|
||
|
totalMinutes(int16_t hours, int8_t minutes)
|
||
|
{
|
||
|
return (hours * 60) + minutes;
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
micros_overflow_tick(void* arg) {
|
||
|
uint32_t m = system_get_time();
|
||
|
if (m < micros_at_last_overflow_tick)
|
||
|
++micros_overflow_count;
|
||
|
micros_at_last_overflow_tick = m;
|
||
|
}
|
||
|
|
||
|
unsigned long ICACHE_FLASH_ATTR
|
||
|
millis() {
|
||
|
uint32_t m = system_get_time();
|
||
|
uint32_t c = micros_overflow_count + ((m < micros_at_last_overflow_tick) ? 1 : 0);
|
||
|
return c * 4294967 + m / 1000;
|
||
|
}
|
||
|
|
||
|
unsigned long ICACHE_FLASH_ATTR
|
||
|
micros() {
|
||
|
return system_get_time();
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
time_init() {
|
||
|
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*)µs_overflow_tick, 0);
|
||
|
os_timer_arm(µs_overflow_timer, 60000, 1);
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
breakTime(time_t time, tmElements_t *tm){
|
||
|
|
||
|
uint8_t year;
|
||
|
uint8_t month, monthLength;
|
||
|
unsigned long days;
|
||
|
|
||
|
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
|
||
|
tm->Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
||
|
|
||
|
year = 0;
|
||
|
days = 0;
|
||
|
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
||
|
year++;
|
||
|
}
|
||
|
tm->Year = year; // year is offset from 1970
|
||
|
|
||
|
days -= LEAP_YEAR(year) ? 366 : 365;
|
||
|
time -= days; // now it is days in this year, starting at 0
|
||
|
|
||
|
days = 0;
|
||
|
month = 0;
|
||
|
monthLength = 0;
|
||
|
for (month = 0; month<12; month++) {
|
||
|
if (month == 1) { // february
|
||
|
if (LEAP_YEAR(year)) {
|
||
|
monthLength = 29;
|
||
|
}
|
||
|
else {
|
||
|
monthLength = 28;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
monthLength = monthDays[month];
|
||
|
}
|
||
|
|
||
|
if (time >= monthLength) {
|
||
|
time -= monthLength;
|
||
|
}
|
||
|
else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
tm->Month = month + 1; // jan is month 1
|
||
|
tm->Day = time + 1; // day of month
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Convert the "timeInput" time_t count into "struct tm" time components.
|
||
|
* This is a more compact version of the C library localtime function.
|
||
|
* Note that year is offset from 1970 !!!
|
||
|
*/
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
timet_to_tm(time_t timeInput, struct tmElements *tmel){
|
||
|
|
||
|
uint8_t year;
|
||
|
uint8_t month, monthLength;
|
||
|
uint32_t time;
|
||
|
unsigned long days;
|
||
|
|
||
|
time = (uint32_t)timeInput;
|
||
|
tmel->Second = time % 60;
|
||
|
time /= 60; // Now it is minutes.
|
||
|
tmel->Minute = time % 60;
|
||
|
time /= 60; // Now it is hours.
|
||
|
tmel->Hour = time % 24;
|
||
|
time /= 24; // Now it is days.
|
||
|
tmel->Wday = ((time + 4) % 7) + 1; // Sunday is day 1.
|
||
|
|
||
|
year = 0;
|
||
|
days = 0;
|
||
|
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
||
|
year++;
|
||
|
}
|
||
|
tmel->Year = year; // The year is offset from 1970.
|
||
|
|
||
|
days -= LEAP_YEAR(year) ? 366 : 365;
|
||
|
time -= days; // Now it is days in this year, starting at 0.
|
||
|
|
||
|
days = 0;
|
||
|
month = 0;
|
||
|
monthLength = 0;
|
||
|
for (month = 0; month<12; month++) {
|
||
|
if (month == 1) { // February.
|
||
|
if (LEAP_YEAR(year)) {
|
||
|
monthLength = 29;
|
||
|
}
|
||
|
else {
|
||
|
monthLength = 28;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
monthLength = monthDays[month];
|
||
|
}
|
||
|
|
||
|
if (time >= monthLength) {
|
||
|
time -= monthLength;
|
||
|
}
|
||
|
else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
tmel->Month = month + 1; // Jan is month 1.
|
||
|
tmel->Day = time + 1; // Day of month.
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Reconstitute "struct tm" elements into a time_t count value.
|
||
|
* Note that the year argument is offset from 1970.
|
||
|
*/
|
||
|
time_t ICACHE_FLASH_ATTR
|
||
|
tm_to_timet(struct tmElements *tmel){
|
||
|
|
||
|
int i;
|
||
|
uint32_t seconds;
|
||
|
|
||
|
// Seconds from 1970 till 1st Jan 00:00:00 of the given year.
|
||
|
seconds = tmel->Year*(SECS_PER_DAY * 365);
|
||
|
for (i = 0; i < tmel->Year; i++) {
|
||
|
if (LEAP_YEAR(i)) {
|
||
|
seconds += SECS_PER_DAY; // Add extra days for leap years.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add the number of elapsed days for the given year. Months start from 1.
|
||
|
for (i = 1; i < tmel->Month; i++) {
|
||
|
if ((i == 2) && LEAP_YEAR(tmel->Year)) {
|
||
|
seconds += SECS_PER_DAY * 29;
|
||
|
}
|
||
|
else {
|
||
|
seconds += SECS_PER_DAY * monthDays[i - 1]; // "monthDay" array starts from 0.
|
||
|
}
|
||
|
}
|
||
|
seconds += (tmel->Day - 1) * SECS_PER_DAY; // Days...
|
||
|
seconds += tmel->Hour * SECS_PER_HOUR; // Hours...
|
||
|
seconds += tmel->Minute * SECS_PER_MIN; // Minutes...
|
||
|
seconds += tmel->Second; // ...and finally, Seconds.
|
||
|
return (time_t)seconds;
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
refreshCache(time_t t){
|
||
|
if (t != cacheTime)
|
||
|
{
|
||
|
breakTime(t, &tm);
|
||
|
cacheTime = t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ICACHE_FLASH_ATTR
|
||
|
hour() { // the hour now
|
||
|
time_t t = now();
|
||
|
refreshCache(t);
|
||
|
return tm.Hour;
|
||
|
}
|
||
|
|
||
|
int ICACHE_FLASH_ATTR
|
||
|
minute() { // the minute now
|
||
|
time_t t = now();
|
||
|
refreshCache(t);
|
||
|
return tm.Minute;
|
||
|
}
|
||
|
|
||
|
int ICACHE_FLASH_ATTR
|
||
|
second() { // the second now
|
||
|
time_t t = now();
|
||
|
refreshCache(t);
|
||
|
return tm.Second;
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
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 + syncInterval;
|
||
|
Status = timeSet;
|
||
|
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||
|
}
|
||
|
|
||
|
time_t ICACHE_FLASH_ATTR
|
||
|
now(){
|
||
|
while (millis() - prevMillis >= 1000){
|
||
|
sysTime++;
|
||
|
prevMillis += 1000;
|
||
|
#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
|
||
|
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
|
||
|
}
|
||
|
}
|
||
|
return sysTime;
|
||
|
}
|
||
|
|
||
|
timeStatus_t ICACHE_FLASH_ATTR
|
||
|
timeStatus(){ // indicates if time has been set and recently synchronized
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
setSyncProvider(getExternalTime getTimeFunction){
|
||
|
getTimePtr = getTimeFunction;
|
||
|
nextSyncTime = sysTime;
|
||
|
now(); // this will sync the clock
|
||
|
}
|
||
|
|
||
|
void ICACHE_FLASH_ATTR
|
||
|
setSyncInterval(time_t interval){ // set the number of seconds between re-sync
|
||
|
syncInterval = interval;
|
||
|
}
|