#include "RTC.h" #include #if (UPDATE_INTERVAL > 255) #error "UPDATE_INTERVAL must be either a multiple of 60, or less than 256 seconds" #endif RTC_DATA_ATTR bool WatchFeatures::RTC::m_timerSet = false; RTC_DATA_ATTR bool WatchFeatures::RTC::m_initialTimer = true; void WatchFeatures::RTC::Get(tmElements_t & tm) { rtc_pcf.getDateTime(); tm.Year = y2kYearToTm(rtc_pcf.getYear()); tm.Month = rtc_pcf.getMonth(); tm.Day = rtc_pcf.getDay(); tm.Wday = rtc_pcf.getWeekday() + 1; // TimeLib has Wday range of 1-7, but PCF8563 stores day of week in 0-6 range tm.Hour = rtc_pcf.getHour(); tm.Minute = rtc_pcf.getMinute(); tm.Second = rtc_pcf.getSecond(); } void WatchFeatures::RTC::Set(tmElements_t tm) { time_t t = makeTime(tm); // make and break to calculate tm.Wday breakTime(t, tm); // day, weekday, month, century(1=1900, 0=2000), year(0-99) rtc_pcf.setDateTime(tm.Day, tm.Wday - 1, tm.Month, 0, tmYearToY2k(tm.Year), tm.Hour, tm.Minute, tm.Second); } void WatchFeatures::RTC::SetTimer() { if (!m_timerSet) { Resync(); } } void WatchFeatures::RTC::OffsetTime(tmElements_t & tm, int offsetInSeconds) { int year = tm.Year; int month = tm.Month; int day = tm.Day; int hour = tm.Hour; int minute = tm.Minute; int second = tm.Second; // adjust for offset second += offsetInSeconds; if (second >= 60 || second < 0) { minute += second / 60; second = second % 60; } if (minute >= 60 || minute < 0) { hour += minute / 60; minute = minute % 60; } if (hour >= 24 || hour < 0) { day += hour / 24; hour = hour % 24; } bool leapYear = year % 4 == 0; if (leapYear) { if (month == 2 && day > 29) { month++; day = day % 29; } } else { if (month == 2 && day > 28) { month++; day = day % 28; } } if (month == 4 || month == 6 || month == 9 || month == 11) { if (day > 30) { month++; day = day % 30; } } else { if (day > 31) { month++; day = day % 31; } } if (month > 12 || month < 0) { year++; month = month % 12; } tm.Year = year; tm.Month = month; tm.Day = day; tm.Hour = hour; tm.Minute = minute; tm.Second = second; } // TODO: implement more advanced wakeup logic, i.e. > 255 seconds that are not a multiple of 60 bool WatchFeatures::RTC::CheckWakeup() { if(m_initialTimer) { m_initialTimer = false; byte frequency, interval; if (UPDATE_INTERVAL % 60 == 0) { frequency = TMR_1MIN; // 1 minute interval = UPDATE_INTERVAL / 60; } else { frequency = TMR_1Hz; // 1 second interval = UPDATE_INTERVAL; } // Timer doesn't work reliably unless it's cleared first rtc_pcf.clearTimer(); rtc_pcf.setTimer(interval, frequency, true); return true; } return true; } void WatchFeatures::RTC::Resync() { rtc_pcf.getDateTime(); // Sleep just long enough to get to a multiple of the update interval, makes updates happen on exact turn of the minute int seconds = UPDATE_INTERVAL - (rtc_pcf.getSecond() % UPDATE_INTERVAL); if (seconds < 0) { seconds = 0; } // Timer doesn't work reliably unless it's cleared first rtc_pcf.clearTimer(); if (seconds == 0) { // If there's no time to wait, just call CheckWakeup() immediately and it'll set the repeating timer m_timerSet = true; m_initialTimer = true; CheckWakeup(); } else { rtc_pcf.setTimer(seconds, TMR_1Hz, false); m_timerSet = true; m_initialTimer = true; } seconds = 0; }