From 6b1c04e1de8a47e882bbce82895c173215b10574 Mon Sep 17 00:00:00 2001 From: Lewis Jackson <> Date: Wed, 31 May 2023 04:04:25 +0300 Subject: [PATCH] Experimental timer-based RTC updates --- src/WatchFace.cpp | 2 +- src/Watchy.cpp | 15 ++++-- src/WatchyRTC.cpp | 128 +++++++++++++++++++--------------------------- src/WatchyRTC.h | 13 +++-- src/config.h | 4 +- 5 files changed, 72 insertions(+), 90 deletions(-) diff --git a/src/WatchFace.cpp b/src/WatchFace.cpp index db7bba0..46f840b 100644 --- a/src/WatchFace.cpp +++ b/src/WatchFace.cpp @@ -92,7 +92,7 @@ void WatchFace::DrawWatchFace(bool partialRefresh) DrawBatteryIcon(); tmElements_t currentTime; - m_RTC.read(currentTime, m_tzOffset); + m_RTC.Get(currentTime, m_tzOffset); SevenSegment sevenSegment(30, 60, 6, 5, 5); if (currentTime.Hour < 10) { diff --git a/src/Watchy.cpp b/src/Watchy.cpp index 0442586..183e6ff 100644 --- a/src/Watchy.cpp +++ b/src/Watchy.cpp @@ -17,9 +17,13 @@ void Watchy::Init() esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); - Wire.begin(SDA, SCL); - m_RTC.init(); + if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) { + if(!m_RTC.CheckWakeup()) { + DeepSleep(); + } + } + Wire.begin(SDA, SCL); m_display.epd2.selectSPI(SPI, SPISettings(20000000, MSBFIRST, SPI_MODE0)); m_display.init(0, g_displayFullInit, 10, true); SetBusyCallback(); @@ -63,6 +67,7 @@ void Watchy::Init() default: { BmaConfig(); + m_RTC.Init(); ConnectWiFi(); SyncNTPTime(); DisconnectWiFi(); @@ -83,7 +88,6 @@ void Watchy::DeepSleep() } g_displayFullInit = false; // Notify not to init it again - m_RTC.clearAlarm(); // resets the alarm flag in the RTC // Set GPIOs 0-39 to input to avoid power leaking out const uint64_t ignore = 0b11110001000000110000100111000010; // Ignore some GPIOs due to resets @@ -97,6 +101,9 @@ void Watchy::DeepSleep() esp_sleep_enable_ext1_wakeup( BTN_PIN_MASK | ACC_INT_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); + + m_RTC.SetTimer(); + esp_deep_sleep_start(); } @@ -158,7 +165,7 @@ void Watchy::SyncNTPTime() if (success) { tmElements_t tm; breakTime((time_t)timeClient.getEpochTime(), tm); - m_RTC.set(tm); + m_RTC.Set(tm); } else { Serial.begin(9600); Serial.println("Failed to get NTP time"); diff --git a/src/WatchyRTC.cpp b/src/WatchyRTC.cpp index 5eed0ab..55d25a4 100644 --- a/src/WatchyRTC.cpp +++ b/src/WatchyRTC.cpp @@ -1,58 +1,53 @@ #include "WatchyRTC.h" +#if (UPDATE_INTERVAL > 255) +#error "UPDATE_INTERVAL must be either a multiple of 60, or less than 256 seconds" +#endif + +RTC_DATA_ATTR bool WatchyRTC::m_timerSet = false; +RTC_DATA_ATTR bool WatchyRTC::m_initialTimer = true; + WatchyRTC::WatchyRTC() { } -void WatchyRTC::init() { - byte error; - Wire.beginTransmission(RTC_PCF_ADDR); - error = Wire.endTransmission(); -} - -void WatchyRTC::config(String datetime) { // String datetime format is YYYY:MM:DD:HH:MM:SS - _PCFConfig(datetime); -} - -void WatchyRTC::clearAlarm() { - int nextAlarmMinute = 0; - rtc_pcf.clearAlarm(); // resets the alarm flag in the RTC - - int second = rtc_pcf.getSecond(); - int minute = rtc_pcf.getMinute(); - int hour = rtc_pcf.getHour(); - - minute += UPDATE_INTERVAL; - - if (minute >= 60) { - hour += minute / 60; - minute = minute % 60; - } - - rtc_pcf.setAlarm(minute, hour, 99, 99); -} - -void WatchyRTC::read(tmElements_t & tm, int offsetInSeconds) +void WatchyRTC::Init() { - rtc_pcf.getDate(); - tm.Year = y2kYearToTm(rtc_pcf.getYear()); +} + +void WatchyRTC::Get(tmElements_t & tm, int offsetInSeconds) +{ + 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 & DS3231 has Wday range of 1-7, but PCF8563 stores day of week in 0-6 range - tm.Hour = rtc_pcf.getHour(); + 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(); - OffsetTime(tm, offsetInSeconds); } -void WatchyRTC::set(tmElements_t tm) { +void WatchyRTC::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.setDate(tm.Day, tm.Wday - 1, tm.Month, 0, tmYearToY2k(tm.Year)); - rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second); - clearAlarm(); + rtc_pcf.setDateTime(tm.Day, tm.Wday - 1, tm.Month, 0, tmYearToY2k(tm.Year), tm.Hour, tm.Minute, tm.Second); +} + +void WatchyRTC::SetTimer() +{ + if (!m_timerSet) { + 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); + + // Non repeating + rtc_pcf.setTimer(seconds, TMR_1Hz, false); + m_timerSet = true; + m_initialTimer = true; + } } void WatchyRTC::OffsetTime(tmElements_t & tm, int offsetInSeconds) @@ -119,44 +114,25 @@ void WatchyRTC::OffsetTime(tmElements_t & tm, int offsetInSeconds) tm.Second = second; } -void WatchyRTC::_PCFConfig(String datetime) { // String datetime is YYYY:MM:DD:HH:MM:SS - if (datetime != "") { - tmElements_t tm; - tm.Year = CalendarYrToTm(_getValue(datetime, ':', 0).toInt()); // YYYY - - // 1970 - tm.Month = _getValue(datetime, ':', 1).toInt(); - tm.Day = _getValue(datetime, ':', 2).toInt(); - tm.Hour = _getValue(datetime, ':', 3).toInt(); - tm.Minute = _getValue(datetime, ':', 4).toInt(); - tm.Second = _getValue(datetime, ':', 5).toInt(); - 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.setDate( - tm.Day, tm.Wday - 1, tm.Month, 0, - tmYearToY2k(tm.Year)); // TimeLib & DS3231 has Wday range of 1-7, but - // PCF8563 stores day of week in 0-6 range - // hr, min, sec - rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second); - } +// TODO: implement more advanced wakeup logic, i.e. > 255 seconds that are not a multiple of 60 +bool WatchyRTC::CheckWakeup() +{ + if(m_initialTimer) { + m_initialTimer = false; - // on POR event, PCF8563 sets month to 0, which will give an error since - // months are 1-12 - clearAlarm(); -} - -String WatchyRTC::_getValue(String data, char separator, int index) { - int found = 0; - int strIndex[] = {0, -1}; - int maxIndex = data.length() - 1; - - for (int i = 0; i <= maxIndex && found <= index; i++) { - if (data.charAt(i) == separator || i == maxIndex) { - found++; - strIndex[0] = strIndex[1] + 1; - strIndex[1] = (i == maxIndex) ? i + 1 : i; + 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; } + + rtc_pcf.setTimer(interval, frequency, true); + + return true; } - return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; -} + return true; +} \ No newline at end of file diff --git a/src/WatchyRTC.h b/src/WatchyRTC.h index 7f3ede7..59f6be3 100644 --- a/src/WatchyRTC.h +++ b/src/WatchyRTC.h @@ -15,17 +15,16 @@ public: public: WatchyRTC(); - void init(); - void config(String datetime); // String datetime format is YYYY:MM:DD:HH:MM:SS - void clearAlarm(); - void read(tmElements_t & tm, int offsetInSeconds = 0); - void set(tmElements_t tm); + void Init(); + void Get(tmElements_t & tm, int offsetInSeconds = 0); + void Set(tmElements_t tm); + void SetTimer(); + bool CheckWakeup(); // Checks to really wake up or not, also resets the timer after the initial sleep static void OffsetTime(tmElements_t & tm, int offsetInSeconds); private: - void _PCFConfig(String datetime); - String _getValue(String data, char separator, int index); + static RTC_DATA_ATTR bool m_timerSet, m_initialTimer; }; #endif \ No newline at end of file diff --git a/src/config.h b/src/config.h index e07c817..98847c1 100644 --- a/src/config.h +++ b/src/config.h @@ -30,5 +30,5 @@ #define NTP_SERVER "pool.ntp.org" -#define UPDATE_INTERVAL 1 -#define WAKE_ON_ACCEL_EVENTS false \ No newline at end of file +#define UPDATE_INTERVAL 60 // seconds +#define WAKE_ON_ACCEL_EVENTS false // useful if saving battery by not updating every minute \ No newline at end of file