From 241f568e713cf8b8d2014f85ce35cfada5ba405a Mon Sep 17 00:00:00 2001 From: sqfmi Date: Mon, 29 Nov 2021 02:34:21 -0500 Subject: [PATCH] Fix RTC - Added RTC scan - Support for both RTCs in abstraction lib --- library.json | 3 +- library.properties | 4 +- src/Watchy.cpp | 99 +++++-------------------------- src/Watchy.h | 7 +-- src/WatchyRTC.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++++ src/WatchyRTC.h | 34 +++++++++++ src/config.h | 7 ++- 7 files changed, 203 insertions(+), 93 deletions(-) create mode 100644 src/WatchyRTC.cpp create mode 100644 src/WatchyRTC.h diff --git a/library.json b/library.json index d56ce5e..0ad88ae 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Watchy", - "version": "1.2.7", + "version": "1.2.8", "description": "Watchy - An Open Source E-Paper Watch by SQFMI", "authors": [ { @@ -19,6 +19,7 @@ { "name": "Adafruit GFX Library" }, { "name": "Arduino_JSON" }, { "name": "DS3232RTC" }, + { "name": "Rtc_Pcf8563" }, { "name": "GxEPD2" }, { "name": "WiFiManager", diff --git a/library.properties b/library.properties index a17a113..f79eccb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Watchy -version=1.2.7 +version=1.2.8 author=SQFMI maintainer=SQFMI sentence=Watchy - An Open Source E-Paper Watch by SQFMI @@ -7,4 +7,4 @@ paragraph=This library contains drivers and code samples for Watchy category=Other url=https://watchy.sqfmi.com architectures=esp32 -depends=Adafruit GFX Library,Arduino_JSON,DS3232RTC,GxEPD2,WiFiManager +depends=Adafruit GFX Library,Arduino_JSON,DS3232RTC,Rtc_Pcf8563,GxEPD2,WiFiManager diff --git a/src/Watchy.cpp b/src/Watchy.cpp index 8f6eef4..9fcf837 100644 --- a/src/Watchy.cpp +++ b/src/Watchy.cpp @@ -1,6 +1,6 @@ #include "Watchy.h" -DS3232RTC Watchy::RTC(false); +WatchyRTC Watchy::RTC; GxEPD2_BW Watchy::display(GxEPD2_154_D67(CS, DC, RESET, BUSY)); RTC_DATA_ATTR int guiState; @@ -11,53 +11,17 @@ RTC_DATA_ATTR bool BLE_CONFIGURED; RTC_DATA_ATTR weatherData currentWeather; RTC_DATA_ATTR int weatherIntervalCounter = WEATHER_UPDATE_INTERVAL; -String 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; - } - } - - return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; -} - Watchy::Watchy(){} //constructor void Watchy::init(String datetime){ esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); //get wake up reason Wire.begin(SDA, SCL); //init i2c - + RTC.init(); switch (wakeup_reason) { - #ifdef ESP_RTC - case ESP_SLEEP_WAKEUP_TIMER: //ESP Internal RTC - if(guiState == WATCHFACE_STATE){ - RTC.read(currentTime); - currentTime.Minute++; - tmElements_t tm; - tm.Month = currentTime.Month; - tm.Day = currentTime.Day; - tm.Year = currentTime.Year; - tm.Hour = currentTime.Hour; - tm.Minute = currentTime.Minute; - tm.Second = 0; - time_t t = makeTime(tm); - RTC.set(t); - RTC.read(currentTime); - showWatchFace(true); //partial updates on tick - } - break; - #endif case ESP_SLEEP_WAKEUP_EXT0: //RTC Alarm - RTC.alarm(ALARM_2); //resets the alarm flag in the RTC + RTC.clearAlarm(); //resets the alarm flag in the RTC if(guiState == WATCHFACE_STATE){ RTC.read(currentTime); showWatchFace(true); //partial updates on tick @@ -67,10 +31,9 @@ void Watchy::init(String datetime){ handleButtonPress(); break; default: //reset - #ifndef ESP_RTC - _rtcConfig(datetime); - #endif + RTC.config(datetime); _bmaConfig(); + RTC.read(currentTime); showWatchFace(false); //full update on reset break; } @@ -78,39 +41,11 @@ void Watchy::init(String datetime){ } void Watchy::deepSleep(){ - #ifndef ESP_RTC esp_sleep_enable_ext0_wakeup(RTC_PIN, 0); //enable deep sleep wake on RTC interrupt - #endif - #ifdef ESP_RTC - esp_sleep_enable_timer_wakeup(60000000); - #endif esp_sleep_enable_ext1_wakeup(BTN_PIN_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); //enable deep sleep wake on button press esp_deep_sleep_start(); } -void Watchy::_rtcConfig(String datetime){ - if(datetime != NULL){ - const time_t FUDGE(30);//fudge factor to allow for upload time, etc. (seconds, YMMV) - tmElements_t tm; - tm.Year = getValue(datetime, ':', 0).toInt() - YEAR_OFFSET;//offset from 1970, since year is stored in uint8_t - 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) + FUDGE; - RTC.set(t); - - } - //https://github.com/JChristensen/DS3232RTC - RTC.squareWave(SQWAVE_NONE); //disable square wave output - //RTC.set(compileTime()); //set RTC time to compile time - RTC.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 0); //alarm wakes up Watchy every minute - RTC.alarmInterrupt(ALARM_2, true); //enable alarm interrupt - RTC.read(currentTime); -} - void Watchy::handleButtonPress(){ uint64_t wakeupBit = esp_sleep_get_ext1_wakeup_status(); //Menu Button @@ -148,13 +83,13 @@ void Watchy::handleButtonPress(){ //Back Button else if (wakeupBit & BACK_BTN_MASK){ if(guiState == MAIN_MENU_STATE){//exit to watch face if already in menu - RTC.alarm(ALARM_2); //resets the alarm flag in the RTC - RTC.read(currentTime); - showWatchFace(false); + RTC.clearAlarm(); //resets the alarm flag in the RTC + RTC.read(currentTime); + showWatchFace(false); }else if(guiState == APP_STATE){ - showMenu(menuIndex, false);//exit to menu if already in app + showMenu(menuIndex, false);//exit to menu if already in app }else if(guiState == FW_UPDATE_STATE){ - showMenu(menuIndex, false);//exit to menu if already in app + showMenu(menuIndex, false);//exit to menu if already in app } } //Up Button @@ -221,7 +156,7 @@ void Watchy::handleButtonPress(){ }else if(digitalRead(BACK_BTN_PIN) == 1){ lastTimeout = millis(); if(guiState == MAIN_MENU_STATE){//exit to watch face if already in menu - RTC.alarm(ALARM_2); //resets the alarm flag in the RTC + RTC.clearAlarm(); //resets the alarm flag in the RTC RTC.read(currentTime); showWatchFace(false); break; //leave loop @@ -366,7 +301,7 @@ void Watchy::setTime(){ int8_t hour = currentTime.Hour; int8_t day = currentTime.Day; int8_t month = currentTime.Month; - int8_t year = currentTime.Year + YEAR_OFFSET - 2000; + int8_t year = currentTime.Year; int8_t setIndex = SET_HOUR; @@ -406,7 +341,7 @@ void Watchy::setTime(){ minute == 59 ? (minute = 0) : minute++; break; case SET_YEAR: - year == 99 ? (year = 20) : year++; + year == 99 ? (year = 21) : year++; break; case SET_MONTH: month == 12 ? (month = 1) : month++; @@ -429,7 +364,7 @@ void Watchy::setTime(){ minute == 0 ? (minute = 59) : minute--; break; case SET_YEAR: - year == 20 ? (year = 99) : year--; + year == 21 ? (year = 99) : year--; break; case SET_MONTH: month == 1 ? (month = 12) : month--; @@ -502,17 +437,15 @@ void Watchy::setTime(){ display.hibernate(); - const time_t FUDGE(10);//fudge factor to allow for upload time, etc. (seconds, YMMV) tmElements_t tm; tm.Month = month; tm.Day = day; - tm.Year = year + 2000 - YEAR_OFFSET;//offset from 1970, since year is stored in uint8_t + tm.Year = year; tm.Hour = hour; tm.Minute = minute; tm.Second = 0; - time_t t = makeTime(tm) + FUDGE; - RTC.set(t); + RTC.set(tm); showMenu(menuIndex, false); diff --git a/src/Watchy.h b/src/Watchy.h index 887d58e..473e7b1 100644 --- a/src/Watchy.h +++ b/src/Watchy.h @@ -5,14 +5,14 @@ #include #include #include -#include #include #include #include #include "DSEG7_Classic_Bold_53.h" +#include "WatchyRTC.h" #include "BLE.h" #include "bma.h" -#include "config.h" +#include "config.h" typedef struct weatherData{ int8_t temperature; @@ -21,7 +21,7 @@ typedef struct weatherData{ class Watchy { public: - static DS3232RTC RTC; + static WatchyRTC RTC; static GxEPD2_BW display; tmElements_t currentTime; public: @@ -48,7 +48,6 @@ class Watchy { virtual void drawWatchFace(); //override this method for different watch faces private: - void _rtcConfig(String datetime); void _bmaConfig(); static void _configModeCallback(WiFiManager *myWiFiManager); static uint16_t _readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len); diff --git a/src/WatchyRTC.cpp b/src/WatchyRTC.cpp new file mode 100644 index 0000000..a03bd8a --- /dev/null +++ b/src/WatchyRTC.cpp @@ -0,0 +1,142 @@ +#include "WatchyRTC.h" + +WatchyRTC::WatchyRTC() + : rtc_ds(false) {} + +void WatchyRTC::init(){ + byte error; + Wire.beginTransmission(RTC_DS_ADDR); + error = Wire.endTransmission(); + if(error == 0){ + rtcType = DS3231; + }else{ + Wire.beginTransmission(RTC_PCF_ADDR); + error = Wire.endTransmission(); + if(error == 0){ + rtcType = PCF8563; + }else{ + //RTC Error + } + } +} + +void WatchyRTC::config(String datetime){ + if(rtcType == DS3231){ + _DSConfig(datetime); + }else{ + _PCFConfig(datetime); + } +} + +void WatchyRTC::clearAlarm(){ + if(rtcType == DS3231){ + rtc_ds.alarm(ALARM_2); + }else{ + int nextAlarmMinute = 0; + rtc_pcf.clearAlarm(); //resets the alarm flag in the RTC + nextAlarmMinute = rtc_pcf.getMinute(); + nextAlarmMinute = (nextAlarmMinute == 59) ? 0 : (nextAlarmMinute + 1); //set alarm to trigger 1 minute from now + rtc_pcf.setAlarm(nextAlarmMinute, 99, 99, 99); + } +} + +void WatchyRTC::read(tmElements_t &tm){ + if(rtcType == DS3231){ + rtc_ds.read(tm); + tm.Year = tm.Year - 30; //reset to offset from 2000 + }else{ + tm.Month = rtc_pcf.getMonth(); + tm.Day = rtc_pcf.getDay(); + tm.Year = rtc_pcf.getYear(); + tm.Hour = rtc_pcf.getHour(); + tm.Minute = rtc_pcf.getMinute(); + tm.Second = rtc_pcf.getSecond(); + tm.Wday = rtc_pcf.getWeekday() + 1; + } +} + +void WatchyRTC::set(tmElements_t tm){ + if(rtcType == DS3231){ + tm.Year = tm.Year + 2000 - YEAR_OFFSET_DS; + time_t t = makeTime(tm); + rtc_ds.set(t); + }else{ + rtc_pcf.setDate(tm.Day, _getDayOfWeek(tm.Day, tm.Month, tm.Year+YEAR_OFFSET_PCF), tm.Month, 0, tm.Year); + rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second); + } +} + +uint8_t WatchyRTC::temperature(){ + if(rtcType == DS3231){ + return rtc_ds.temperature(); + }else{ + return 25; + } +} + +void WatchyRTC::_DSConfig(String datetime){ + if(datetime != NULL){ + tmElements_t tm; + tm.Year = _getValue(datetime, ':', 0).toInt() - YEAR_OFFSET_DS;//offset from 1970, since year is stored in uint8_t + 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); + rtc_ds.set(t); + } + //https://github.com/JChristensen/DS3232RTC + rtc_ds.squareWave(SQWAVE_NONE); //disable square wave output + rtc_ds.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 0); //alarm wakes up Watchy every minute + rtc_ds.alarmInterrupt(ALARM_2, true); //enable alarm interrupt +} + +void WatchyRTC::_PCFConfig(String datetime){ + if(datetime != NULL){ + tmElements_t tm; + tm.Year = _getValue(datetime, ':', 0).toInt(); + 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(); + + rtc_pcf.initClock(); + //day, weekday, month, century(1=1900, 0=2000), year(0-99) + rtc_pcf.setDate(tm.Day, _getDayOfWeek(tm.Day, tm.Month, tm.Year), tm.Month, 0, tm.Year - YEAR_OFFSET_PCF);//offset from 2000, since year is stored in uint8_t + //hr, min, sec + rtc_pcf.setTime(tm.Hour, tm.Minute, tm.Second); + + } + rtc_pcf.clearAlarm(); + int nextAlarmMinute = rtc_pcf.getMinute(); + nextAlarmMinute = (nextAlarmMinute == 59) ? 0 : (nextAlarmMinute + 1); + rtc_pcf.setAlarm(nextAlarmMinute, 99, 99, 99); +} + +int WatchyRTC::_getDayOfWeek(int d, int m, int y) +{ + static int t[] = { 0, 3, 2, 5, 0, 3, + 5, 1, 4, 6, 2, 4 }; + y -= m < 3; + return ( y + y / 4 - y / 100 + + y / 400 + t[m - 1] + d) % 7; +} + +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; + } + } + + return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; +} \ No newline at end of file diff --git a/src/WatchyRTC.h b/src/WatchyRTC.h new file mode 100644 index 0000000..ea5350b --- /dev/null +++ b/src/WatchyRTC.h @@ -0,0 +1,34 @@ +#ifndef WATCHY_RTC_H +#define WATCHY_RTC_H + +#include +#include + +#define DS3231 0 +#define PCF8563 1 +#define RTC_DS_ADDR 0x68 +#define RTC_PCF_ADDR 0x51 +#define YEAR_OFFSET_DS 1970 +#define YEAR_OFFSET_PCF 2000 + +class WatchyRTC { + public: + DS3232RTC rtc_ds; + Rtc_Pcf8563 rtc_pcf; + uint8_t rtcType; + public: + WatchyRTC(); + void init(); + void config(String datetime); + void clearAlarm(); + void read(tmElements_t &tm); + void set(tmElements_t tm); + uint8_t temperature(); + private: + void _DSConfig(String datetime); + void _PCFConfig(String datetime); + int _getDayOfWeek(int d, int m, int y); + String _getValue(String data, char separator, int index); +}; + +#endif \ No newline at end of file diff --git a/src/config.h b/src/config.h index 757c90e..716a57c 100644 --- a/src/config.h +++ b/src/config.h @@ -4,7 +4,8 @@ //pins #define SDA 21 #define SCL 22 -#define ADC_PIN 33 +//#define ADC_PIN 33 +#define ADC_PIN 35 #define RTC_PIN GPIO_NUM_27 #define CS 5 #define DC 10 @@ -47,7 +48,7 @@ #define SET_YEAR 2 #define SET_MONTH 3 #define SET_DAY 4 -#define YEAR_OFFSET 1970 +#define YEAR_OFFSET 2000 #define HOUR_12_24 24 //BLE OTA #define BLE_DEVICE_NAME "Watchy BLE OTA" @@ -58,4 +59,4 @@ #define HARDWARE_VERSION_MAJOR 1 #define HARDWARE_VERSION_MINOR 0 -#endif +#endif \ No newline at end of file