Skip to content

Added Epoch Support #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 30, 2015
88 changes: 86 additions & 2 deletions src/RTCZero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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
*/
Expand Down
33 changes: 21 additions & 12 deletions src/RTCZero.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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() {};
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand All @@ -99,3 +106,5 @@ class RTCZero {
void RTCreset();
void RTCresetRemove();
};

#endif // RTC_ZERO_H