From 94c962247e94e63869b1e59f34f51efc6fa7b0b1 Mon Sep 17 00:00:00 2001 From: Michael-Paul Moore Date: Wed, 13 Apr 2022 09:43:59 -0700 Subject: [PATCH] Great build. have multiple faces! --- src/DateTimeWatchFace.cpp | 20 ---- src/DateTimeWatchFace.h | 17 ---- src/DateWatchFace.cpp | 39 ++++++++ src/DateWatchFace.h | 17 ++++ src/SyncNTP.cpp | 68 +++++++++++++ src/SyncNTP.h | 16 ++++ src/TimeWatchFace.cpp | 14 ++- src/TimeWatchFace.h | 5 +- src/WatchFace.h | 3 +- src/WatchyApp.cpp | 5 + src/WatchyApp.h | 10 +- src/WatchyExpanded.cpp | 106 ++++++++++++++++++--- src/WatchyExpanded.h | 24 ++++- src/WatchyRTC.cpp | 196 +++++++++++++++++++------------------- src/watchy_config.h | 21 +++- 15 files changed, 403 insertions(+), 158 deletions(-) delete mode 100644 src/DateTimeWatchFace.cpp delete mode 100644 src/DateTimeWatchFace.h create mode 100644 src/DateWatchFace.cpp create mode 100644 src/DateWatchFace.h create mode 100644 src/SyncNTP.cpp create mode 100644 src/SyncNTP.h create mode 100644 src/WatchyApp.cpp diff --git a/src/DateTimeWatchFace.cpp b/src/DateTimeWatchFace.cpp deleted file mode 100644 index 0534632..0000000 --- a/src/DateTimeWatchFace.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Self -#include "DateTimeWatchFace.h" - -// Fonts -#include - -void CDateTimeWatchFace::Draw(CWatchyExpanded::ADisplay& display, const tmElements_t& time) -{ - CTimeWatchFace::Draw(display, time); - - m_currentLocalTime.tm_wday = time.Wday - 1; - m_currentLocalTime.tm_year = time.Year + 1970 - 1900; - m_currentLocalTime.tm_mon = time.Month - 1; - m_currentLocalTime.tm_mday = time.Day; - - char buffer[32]; - strftime(buffer, sizeof(buffer), "%a %b %d, %Y", &m_currentLocalTime); - display.print(buffer); - display.println(); -}; diff --git a/src/DateTimeWatchFace.h b/src/DateTimeWatchFace.h deleted file mode 100644 index 9e84a87..0000000 --- a/src/DateTimeWatchFace.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// Time -#include - -// Expanded -#include "WatchFace.h" -#include "WatchyExpanded.h" - -// Faces -#include "TimeWatchFace.h" - -class CDateTimeWatchFace : public CTimeWatchFace -{ - public: - void Draw(CWatchyExpanded::ADisplay& display, const tmElements_t& time) override; -}; diff --git a/src/DateWatchFace.cpp b/src/DateWatchFace.cpp new file mode 100644 index 0000000..287868c --- /dev/null +++ b/src/DateWatchFace.cpp @@ -0,0 +1,39 @@ +// Self +#include "DateWatchFace.h" + +// Fonts +#include + +// Time +#include + +void CDateWatchFace::Draw(CWatchyExpanded& expanded) +{ + StartDraw(expanded.Display()); + CTimeWatchFace::DrawInternal(expanded); + DrawInternal(expanded); +}; + +void CDateWatchFace::StartDraw(CWatchyExpanded::ADisplay& display) +{ + display.setFullWindow(); + display.fillScreen(GxEPD_BLACK); + display.setFont(&FreeMonoBold9pt7b); + display.setCursor(0, 15); +}; + +void CDateWatchFace::DrawInternal(CWatchyExpanded& expanded) +{ + CWatchyExpanded::ADisplay& display = expanded.Display(); + tmElements_t& time = expanded.Time(); + + m_currentLocalTime.tm_wday = time.Wday - 1; + m_currentLocalTime.tm_year = time.Year + 1970 - 1900; + m_currentLocalTime.tm_mon = time.Month - 1; + m_currentLocalTime.tm_mday = time.Day; + + char buffer[32]; + strftime(buffer, sizeof(buffer), "%a %b %d, %Y", &m_currentLocalTime); + display.print(buffer); + display.println(); +}; diff --git a/src/DateWatchFace.h b/src/DateWatchFace.h new file mode 100644 index 0000000..568a80c --- /dev/null +++ b/src/DateWatchFace.h @@ -0,0 +1,17 @@ +#pragma once + +// Expanded +#include "WatchFace.h" +#include "WatchyExpanded.h" + +// Faces +#include "TimeWatchFace.h" + +class CDateWatchFace : public CTimeWatchFace +{ + public: + void Draw(CWatchyExpanded& expanded) override; + + void StartDraw(CWatchyExpanded::ADisplay& display); + void DrawInternal(CWatchyExpanded& expanded); +}; diff --git a/src/SyncNTP.cpp b/src/SyncNTP.cpp new file mode 100644 index 0000000..94e4668 --- /dev/null +++ b/src/SyncNTP.cpp @@ -0,0 +1,68 @@ +// Self +#include "SyncNTP.h" + +// GxEPD2 +#include + +// Fonts +#include + +// WiFi +#include + +// Watchy +#include "WatchyRTC.h" + +// NTP +#include + +CSyncNTP::CSyncNTP(CWatchyExpanded& expanded) : CWatchyApp(expanded) {} + +const char* CSyncNTP::Name() const +{ + return "SyncNTP"; +} + +void CSyncNTP::Work() +{ + CWatchyExpanded::ADisplay& display = m_expanded.Display(); + display.setFullWindow(); + display.fillScreen(GxEPD_BLACK); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_WHITE); + display.setCursor(0, 10); + display.println("Syncing NTP..."); + display.display(false); //full refresh + + if(m_expanded.ConnectWiFi()) + { + if (!SyncNTP(3600 * -7, 3600, "pool.ntp.org")) + display.println("Failed to Sync NTP!"); + else + display.println("Synced to NTP!"); + + WiFi.mode(WIFI_OFF); + btStop(); + } + else + { + display.println("WiFi Not Configured."); + } + + display.display(true); //full refresh + delay(3000); +} + +//NTP sync - call after connecting to WiFi and remember to turn it back off +bool CSyncNTP::SyncNTP(long gmt, int dst, String ntpServer) +{ + WiFiUDP ntpUDP; + NTPClient timeClient(ntpUDP, ntpServer.c_str(), gmt); + timeClient.begin(); + if(!timeClient.forceUpdate()) + return false; //NTP sync failed + tmElements_t tm; + breakTime((time_t)timeClient.getEpochTime(), tm); + m_expanded.RTC().set(tm); + return true; +} diff --git a/src/SyncNTP.h b/src/SyncNTP.h new file mode 100644 index 0000000..5c15054 --- /dev/null +++ b/src/SyncNTP.h @@ -0,0 +1,16 @@ +#pragma once + +// Epanded +#include "WatchyApp.h" + +class CSyncNTP : public CWatchyApp +{ + public: + CSyncNTP(CWatchyExpanded& expanded); + const char* Name() const override; + void Work() override; + + private: + bool SyncNTP(long gmt, int dst, String ntpServer); +}; + diff --git a/src/TimeWatchFace.cpp b/src/TimeWatchFace.cpp index af00a4f..0756ac9 100644 --- a/src/TimeWatchFace.cpp +++ b/src/TimeWatchFace.cpp @@ -4,13 +4,25 @@ // Fonts #include -void CTimeWatchFace::Draw(CWatchyExpanded::ADisplay& display, const tmElements_t& time) +void CTimeWatchFace::Draw(CWatchyExpanded& expanded) +{ + CWatchyExpanded::ADisplay& display = expanded.Display(); + StartDraw(display); + DrawInternal(expanded); +}; + +void CTimeWatchFace::StartDraw(CWatchyExpanded::ADisplay& display) { display.setFullWindow(); display.fillScreen(GxEPD_BLACK); display.setFont(&FreeMonoBold9pt7b); display.setCursor(0, 15); +}; +void CTimeWatchFace::DrawInternal(CWatchyExpanded& expanded) +{ + CWatchyExpanded::ADisplay& display = expanded.Display(); + tmElements_t& time = expanded.Time(); m_currentLocalTime.tm_hour = time.Hour; m_currentLocalTime.tm_min = time.Minute; m_currentLocalTime.tm_sec = time.Second; diff --git a/src/TimeWatchFace.h b/src/TimeWatchFace.h index 9f17385..9b6444a 100644 --- a/src/TimeWatchFace.h +++ b/src/TimeWatchFace.h @@ -10,7 +10,10 @@ class CTimeWatchFace : public CWatchFace { public: - void Draw(CWatchyExpanded::ADisplay& display, const tmElements_t& time) override; + virtual void Draw(CWatchyExpanded& expanded) override; + + void StartDraw(CWatchyExpanded::ADisplay& display); + void DrawInternal(CWatchyExpanded& expanded); protected: tm m_currentLocalTime; diff --git a/src/WatchFace.h b/src/WatchFace.h index 68d1a7c..d42297e 100644 --- a/src/WatchFace.h +++ b/src/WatchFace.h @@ -10,6 +10,5 @@ class CWatchFace { public: CWatchFace() = default; - //override this method for different watch faces - virtual void Draw(CWatchyExpanded::ADisplay& display, const tmElements_t& time) = 0; + virtual void Draw(CWatchyExpanded& expanded) = 0; //override this method for different watch faces }; diff --git a/src/WatchyApp.cpp b/src/WatchyApp.cpp new file mode 100644 index 0000000..23435cf --- /dev/null +++ b/src/WatchyApp.cpp @@ -0,0 +1,5 @@ +// Self +#include "WatchyApp.h" + + +CWatchyApp::CWatchyApp(CWatchyExpanded& expanded) : m_expanded(expanded) {} diff --git a/src/WatchyApp.h b/src/WatchyApp.h index 3bf4591..b81ce64 100644 --- a/src/WatchyApp.h +++ b/src/WatchyApp.h @@ -1,7 +1,15 @@ #pragma once +// Expanded +#include "WatchyExpanded.h" + class CWatchyApp { + public: + CWatchyApp(CWatchyExpanded& expanded); + virtual const char* Name() const = 0; + virtual void Work() = 0; + protected: + CWatchyExpanded& m_expanded; }; - diff --git a/src/WatchyExpanded.cpp b/src/WatchyExpanded.cpp index f435799..6dc1781 100644 --- a/src/WatchyExpanded.cpp +++ b/src/WatchyExpanded.cpp @@ -8,14 +8,24 @@ // Faces #include "TimeWatchFace.h" -#include "DateTimeWatchFace.h" +#include "DateWatchFace.h" + +// Apps +#include "SyncNTP.h" + +// Fonts +#include + +// WiFi +#include RTC_DATA_ATTR SExpandedData g_data; CWatchyExpanded::CWatchyExpanded() : m_display(GxEPD2_154_D67(wcd::cs, wcd::dc, wcd::reset, wcd::busy)), m_data(g_data) { AddWatchFace(new CTimeWatchFace); - AddWatchFace(new CDateTimeWatchFace); + AddWatchFace(new CDateWatchFace); + AddApp(new CSyncNTP(*this)); } void CWatchyExpanded::AddWatchFace(CWatchFace* pFace) @@ -23,6 +33,11 @@ void CWatchyExpanded::AddWatchFace(CWatchFace* pFace) m_faces.push_back(pFace); } +void CWatchyExpanded::AddApp(CWatchyApp* pApp) +{ + m_apps.push_back(pApp); +} + void CWatchyExpanded::Run() { const esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); //get wake up reason @@ -37,7 +52,7 @@ void CWatchyExpanded::Run() switch (wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0: //RTC Alarm - if(m_guiState == wc::kWatchFace_State) + if(m_data.m_guiState == SExpandedData::guiState::face) m_UpdateWatchFace = true; break; case ESP_SLEEP_WAKEUP_EXT1: //button Press @@ -50,11 +65,37 @@ void CWatchyExpanded::Run() if (m_UpdateWatchFace) { m_rtc.read(m_currentTime); - UpdateScreen(false); // full update + UpdateScreen(true); // full update } DeepSleep(); } +CWatchyExpanded::ADisplay& CWatchyExpanded::Display() +{ + return m_display; +} + +WatchyRTC& CWatchyExpanded::RTC() +{ + return m_rtc; +} + +tmElements_t& CWatchyExpanded::Time() +{ + return m_currentTime; +} + +bool CWatchyExpanded::ConnectWiFi() +{ + //WiFi not setup, you can also use hard coded credentials with WiFi.begin(SSID,PASS); + if(wl_status_t::WL_CONNECT_FAILED == WiFi.begin()) + return false; + + WiFi.waitForConnectResult(); + + return true; +} + void CWatchyExpanded::Init() { if (!m_data.m_init) @@ -73,33 +114,62 @@ void CWatchyExpanded::DisplayBusyCallback(const void*) void CWatchyExpanded::UpdateScreen(const bool partial_update) { m_display.setFullWindow(); - m_currentTime.Month = 4; - m_faces[m_data.m_face % m_faces.size()]->Draw(m_display, m_currentTime); + m_faces[m_data.m_face % m_faces.size()]->Draw(*this); m_display.display(partial_update); //partial refresh - m_guiState = wc::kWatchFace_State; + m_data.m_guiState = SExpandedData::guiState::face; } void CWatchyExpanded::DeepSleep() { m_display.hibernate(); m_data.m_init = false; - m_rtc.clearAlarm(); //resets the alarm flag in the RTC + m_rtc.clearAlarm(); // resets the alarm flag in the RTC for(int i = 0; i < 40; ++i) // Set pins 0-39 to input to avoid power leaking out pinMode(i, INPUT); - esp_sleep_enable_ext0_wakeup(wc::rtc_pin, 0); //enable deep sleep wake on RTC interrupt - esp_sleep_enable_ext1_wakeup(wc::btn_pin_mask, ESP_EXT1_WAKEUP_ANY_HIGH); //enable deep sleep wake on button press + esp_sleep_enable_ext0_wakeup(wcp::rtc_pin, 0); //enable deep sleep wake on RTC interrupt + esp_sleep_enable_ext1_wakeup(wcp::btn_pin_mask, ESP_EXT1_WAKEUP_ANY_HIGH); //enable deep sleep wake on button press esp_deep_sleep_start(); } void CWatchyExpanded::HandleButtonPress() { const uint64_t kWakeupBit = esp_sleep_get_ext1_wakeup_status(); - if (kWakeupBit & wc::up_btn_mask) - BackFace(); - else if (kWakeupBit & wc::down_btn_mask) - ForwardFace(); + if (m_data.m_guiState == SExpandedData::guiState::face) + { + if (kWakeupBit & wcp::up_btn_mask) + BackFace(); + else if (kWakeupBit & wcp::down_btn_mask) + ForwardFace(); + else if (kWakeupBit & wcp::menu_btn_mask) + Menu(); + } + else if (m_data.m_guiState == SExpandedData::guiState::menu) + { + if (kWakeupBit & wcp::back_btn_mask) + { + m_data.m_guiState = SExpandedData::guiState::face; + m_UpdateWatchFace = true; + } + else if (kWakeupBit & wcp::menu_btn_mask) + { + m_apps[m_data.menu % m_apps.size()]->Work(); + } + } +} + +void CWatchyExpanded::Menu() +{ + m_display.setFullWindow(); + m_display.fillScreen(GxEPD_BLACK); + m_display.setFont(&FreeMonoBold9pt7b); + m_display.setCursor(0, 15); + + for (const CWatchyApp* pApp : m_apps) + m_display.println(pApp->Name()); + m_data.m_guiState = SExpandedData::guiState::menu; + m_display.display(true); } void CWatchyExpanded::BackFace() @@ -131,3 +201,11 @@ uint16_t CWatchyExpanded::_readRegister(uint8_t address, uint8_t reg, uint8_t *d data[++i] = Wire.read(); return 0; } + +float CWatchyExpanded::BatteryVoltage() +{ + if(m_rtc.rtcType == DS3231) + return analogReadMilliVolts(wcp::batt_adc_pin) / 1000.0f * 2.0f; // Battery voltage goes through a 1/2 divider. + else + return analogReadMilliVolts(wcp::batt_adc_pin) / 1000.0f * 2.0f; +} diff --git a/src/WatchyExpanded.h b/src/WatchyExpanded.h index be0ce72..f3d44f9 100644 --- a/src/WatchyExpanded.h +++ b/src/WatchyExpanded.h @@ -23,28 +23,48 @@ struct SExpandedData { bool m_init = true; std::uint8_t m_face = 0; + + enum guiState : std::uint8_t + { + face, + menu + } m_guiState = guiState::face; + + std::uint8_t m_menuItem = 0; }; class CWatchyExpanded { public: + using ADisplay = GxEPD2_BW; + CWatchyExpanded(); void AddWatchFace(CWatchFace* pFace); + void AddApp(CWatchyApp* pApp); void Init(); void Run(); - using ADisplay = GxEPD2_BW; + bool ConnectWiFi(); + + ADisplay& Display(); + WatchyRTC& RTC(); + tmElements_t& Time(); + float BatteryVoltage(); private: static void DisplayBusyCallback(const void*); void UpdateScreen(const bool fullUpdate); void DeepSleep(); + void HandleButtonPress(); + void BackFace(); void ForwardFace(); + void Menu(); + void _bmaConfig(); static uint16_t _readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len); @@ -53,7 +73,7 @@ class CWatchyExpanded ADisplay m_display; tmElements_t m_currentTime; - std::int8_t m_guiState = 0; + WatchyRTC m_rtc; SExpandedData& m_data; bool m_UpdateWatchFace = false; diff --git a/src/WatchyRTC.cpp b/src/WatchyRTC.cpp index 4a65bc5..392112e 100644 --- a/src/WatchyRTC.cpp +++ b/src/WatchyRTC.cpp @@ -1,118 +1,122 @@ #include "WatchyRTC.h" WatchyRTC::WatchyRTC() - : rtc_ds(false) {} + : 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::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; + } } void WatchyRTC::config(String datetime){ //String datetime format is YYYY:MM:DD:HH:MM:SS - if(rtcType == DS3231){ - _DSConfig(datetime); - }else{ - _PCFConfig(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::clearAlarm() +{ + if(rtcType == DS3231) + { + rtc_ds.alarm(ALARM_2); + } + else + { + rtc_pcf.clearAlarm(); //resets the alarm flag in the RTC + int 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); - }else{ - 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.Minute = rtc_pcf.getMinute(); - tm.Second = rtc_pcf.getSecond(); - } + if(rtcType == DS3231){ + rtc_ds.read(tm); + }else{ + 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.Minute = rtc_pcf.getMinute(); + tm.Second = rtc_pcf.getSecond(); + } } void WatchyRTC::set(tmElements_t tm){ - if(rtcType == DS3231){ - time_t t = makeTime(tm); - rtc_ds.set(t); - }else{ - 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); - clearAlarm(); - } + if(rtcType == DS3231){ + time_t t = makeTime(tm); + rtc_ds.set(t); + }else{ + 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); + clearAlarm(); + } } uint8_t WatchyRTC::temperature(){ - if(rtcType == DS3231){ - return rtc_ds.temperature(); - }else{ - return 255; //error - } + if(rtcType == DS3231){ + return rtc_ds.temperature(); + }else{ + return 255; //error + } } void WatchyRTC::_DSConfig(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); - 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 + 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); + 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){ //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); - } - //on POR event, PCF8563 sets month to 0, which will give an error since months are 1-12 - clearAlarm(); + 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); + } + //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) @@ -122,11 +126,11 @@ String WatchyRTC::_getValue(String data, char separator, int index) 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; - } + 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]) : ""; diff --git a/src/watchy_config.h b/src/watchy_config.h index 7ee851f..6bfd3a1 100644 --- a/src/watchy_config.h +++ b/src/watchy_config.h @@ -30,9 +30,6 @@ namespace watchy_config { -// Menu -constexpr std::int8_t kWatchFace_State{-1}; - namespace display { // Display @@ -46,16 +43,32 @@ constexpr std::uint8_t reset{9}; constexpr std::uint8_t busy{19}; }; +namespace pins +{ + // RTC pins constexpr gpio_num_t rtc_pin{GPIO_NUM_27}; +#define ARDUINO_WATCHY_V20 1 + +#if defined (ARDUINO_WATCHY_V10) + constexpr std::uint64_t up_btn_mask{GPIO_SEL_32}; +#elif defined (ARDUINO_WATCHY_V15) + constexpr std::uint64_t up_btn_mask{GPIO_SEL_32}; +#elif defined (ARDUINO_WATCHY_V20) + constexpr std::uint64_t up_btn_mask{GPIO_SEL_35}; + constexpr std:: uint8_t batt_adc_pin{34}; +#endif + // btn pins & masks constexpr std::uint64_t menu_btn_mask{GPIO_SEL_26}; constexpr std::uint64_t back_btn_mask{GPIO_SEL_25}; -constexpr std::uint64_t up_btn_mask{GPIO_SEL_32}; constexpr std::uint64_t down_btn_mask{GPIO_SEL_4}; constexpr std::uint64_t btn_pin_mask{menu_btn_mask|back_btn_mask|up_btn_mask|down_btn_mask}; + +}; }; namespace wc = watchy_config; namespace wcd = watchy_config::display; +namespace wcp = watchy_config::pins;