diff --git a/src/RTCZero.cpp b/src/RTCZero.cpp index f2727f1..e5f8ee0 100644 --- a/src/RTCZero.cpp +++ b/src/RTCZero.cpp @@ -19,6 +19,10 @@ #include "RTCZero.h" +#define EPOCH_TIME_OFF 946684800 // This is 1st January 2000, 00:00:00 in epoch time + +static const uint8_t daysInMonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; + voidFuncPtr RTC_callBack = NULL; void RTCZero::begin() @@ -46,7 +50,9 @@ void RTCZero::begin() tmp_reg |= RTC_MODE2_CTRL_MODE_CLOCK; // set clock operating mode tmp_reg |= RTC_MODE2_CTRL_PRESCALER_DIV1024; // set prescaler to 1024 for MODE2 tmp_reg &= ~RTC_MODE2_CTRL_MATCHCLR; // disable clear on match - tmp_reg |= RTC_MODE2_CTRL_CLKREP; // 24h time representation + + //According to the datasheet RTC_MODE2_CTRL_CLKREP = 0 for 24h + tmp_reg &= ~RTC_MODE2_CTRL_CLKREP; // 24h time representation RTC->MODE2.READREQ.reg &= ~RTC_READREQ_RCONT; // disable continuously mode @@ -102,7 +108,9 @@ void RTCZero::detachInterrupt() void RTCZero::standbyMode() { - SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + // Entering standby mode when connected + // via the native USB port causes issues. + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; __WFI(); } @@ -286,6 +294,82 @@ void RTCZero::setAlarmDate(uint8_t day, uint8_t month, uint8_t year) setAlarmYear(year); } +uint32_t RTCZero::getEpoch() +{ + return getY2kEpoch() + EPOCH_TIME_OFF; +} + +uint32_t RTCZero::getY2kEpoch() +{ + uint16_t days = RTC->MODE2.CLOCK.bit.DAY; + days = days > 0 ? days : 1; + uint8_t months = RTC->MODE2.CLOCK.bit.MONTH; + uint16_t years = RTC->MODE2.CLOCK.bit.YEAR; + + for (uint8_t i = 1; i < months; ++i) { + days += daysInMonth[i - 1]; + } + + if ((months > 2) && (years % 4 == 0)) { + ++days; + } + days += 365 * years + (years + 3) / 4 - 1; + + uint8_t hours = RTC->MODE2.CLOCK.bit.HOUR; + + return ((days * 24 + hours) * 60 + + RTC->MODE2.CLOCK.bit.MINUTE) * 60 + RTC->MODE2.CLOCK.bit.SECOND; +} + +void RTCZero::setEpoch(uint32_t ts) +{ + if (ts < EPOCH_TIME_OFF) { + setY2kEpoch(0); + } + else { + setY2kEpoch(ts - EPOCH_TIME_OFF); + } +} + +void RTCZero::setY2kEpoch(uint32_t ts) +{ + RTC->MODE2.CLOCK.bit.SECOND = ts % 60; + ts /= 60; + RTC->MODE2.CLOCK.bit.MINUTE = ts % 60; + ts /= 60; + RTC->MODE2.CLOCK.bit.HOUR = ts % 24; + + uint16_t days = ts / 24; + uint8_t months; + uint8_t years; + + uint8_t leap; + + // Calculate years + for (years = 0; ; ++years) { + leap = years % 4 == 0; + if (days < 365 + leap) + break; + days -= 365 + leap; + } + + // Calculate months + for (months = 1; ; ++months) { + uint8_t daysPerMonth = daysInMonth[months - 1]; + if (leap && months == 2) + ++daysPerMonth; + if (days < daysPerMonth) + break; + days -= daysPerMonth; + } + + RTC->MODE2.CLOCK.bit.YEAR = years; + RTC->MODE2.CLOCK.bit.MONTH = months; + RTC->MODE2.CLOCK.bit.DAY = days + 1; + while (RTCisSyncing()) + ; +} + /* * Private Utility Functions */ diff --git a/src/RTCZero.h b/src/RTCZero.h index d8f5cc5..d3bebdf 100644 --- a/src/RTCZero.h +++ b/src/RTCZero.h @@ -17,10 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#pragma once - -#define H24 1 -#define H12 0 +#ifndef RTC_ZERO_H +#define RTC_ZERO_H #include "Arduino.h" @@ -31,13 +29,13 @@ class RTCZero { enum Alarm_Match: uint8_t // Should we have this enum or just use the identifiers from /component/rtc.h ? { - MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, - MATCH_SS = RTC_MODE2_MASK_SEL_SS_Val, - MATCH_MMSS = RTC_MODE2_MASK_SEL_MMSS_Val, - MATCH_HHMMSS = RTC_MODE2_MASK_SEL_HHMMSS_Val, - MATCH_DHHMMSS = RTC_MODE2_MASK_SEL_DDHHMMSS_Val, - MATCH_MMDDHHMMSS = RTC_MODE2_MASK_SEL_MMDDHHMMSS_Val, - MATCH_YYMMDDHHMMSS = RTC_MODE2_MASK_SEL_YYMMDDHHMMSS_Val + MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, // Never + MATCH_SS = RTC_MODE2_MASK_SEL_SS_Val, // Every Minute + MATCH_MMSS = RTC_MODE2_MASK_SEL_MMSS_Val, // Every Hour + MATCH_HHMMSS = RTC_MODE2_MASK_SEL_HHMMSS_Val, // Every Day + MATCH_DHHMMSS = RTC_MODE2_MASK_SEL_DDHHMMSS_Val, // Every Month + MATCH_MMDDHHMMSS = RTC_MODE2_MASK_SEL_MMDDHHMMSS_Val, // Every Year + MATCH_YYMMDDHHMMSS = RTC_MODE2_MASK_SEL_YYMMDDHHMMSS_Val // Once, on a specific date and a specific time }; RTCZero() {}; @@ -56,14 +54,16 @@ class RTCZero { uint8_t getSeconds(); uint8_t getMinutes(); uint8_t getHours(); + uint8_t getAM_PM(); uint8_t getDay(); uint8_t getMonth(); uint8_t getYear(); - + uint8_t getAlarmSeconds(); uint8_t getAlarmMinutes(); uint8_t getAlarmHours(); + uint8_t getAlarmAM_PM(); uint8_t getAlarmDay(); uint8_t getAlarmMonth(); @@ -91,6 +91,13 @@ class RTCZero { void setAlarmYear(uint8_t year); void setAlarmDate(uint8_t day, uint8_t month, uint8_t year); + /* Epoch Functions */ + + uint32_t getEpoch(); + uint32_t getY2kEpoch(); + void setEpoch(uint32_t ts); + void setY2kEpoch(uint32_t ts); + private: void config32kOSC(void); bool RTCisSyncing(void); @@ -99,3 +106,5 @@ class RTCZero { void RTCreset(); void RTCresetRemove(); }; + +#endif // RTC_ZERO_H