summaryrefslogtreecommitdiffstats
path: root/watch-library/watch/watch_rtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'watch-library/watch/watch_rtc.c')
-rw-r--r--watch-library/watch/watch_rtc.c150
1 files changed, 142 insertions, 8 deletions
diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c
index 2d6d598f..3d2104f3 100644
--- a/watch-library/watch/watch_rtc.c
+++ b/watch-library/watch/watch_rtc.c
@@ -22,19 +22,153 @@
* SOFTWARE.
*/
- bool _watch_rtc_is_enabled() {
- return RTC->MODE0.CTRLA.bit.ENABLE;
+ext_irq_cb_t tick_callback;
+ext_irq_cb_t alarm_callback;
+ext_irq_cb_t btn_alarm_callback;
+ext_irq_cb_t a2_callback;
+ext_irq_cb_t a4_callback;
+
+bool _watch_rtc_is_enabled() {
+ return RTC->MODE2.CTRLA.bit.ENABLE;
}
-void watch_set_date_time(struct calendar_date_time date_time) {
- calendar_set_date(&CALENDAR_0, &date_time.date);
- calendar_set_time(&CALENDAR_0, &date_time.time);
+void _sync_rtc() {
+ while (RTC->MODE2.SYNCBUSY.reg);
}
-void watch_get_date_time(struct calendar_date_time *date_time) {
- calendar_get_date_time(&CALENDAR_0, date_time);
+void _watch_rtc_init() {
+ MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC;
+
+ if (_watch_rtc_is_enabled()) return; // don't reset the RTC if it's already set up.
+
+ RTC->MODE2.CTRLA.bit.ENABLE = 0;
+ _sync_rtc();
+
+ RTC->MODE2.CTRLA.bit.SWRST = 1;
+ _sync_rtc();
+
+ RTC->MODE2.CTRLA.bit.MODE = RTC_MODE2_CTRLA_MODE_CLOCK_Val;
+ RTC->MODE2.CTRLA.bit.PRESCALER = RTC_MODE2_CTRLA_PRESCALER_DIV1024_Val;
+ RTC->MODE2.CTRLA.bit.CLOCKSYNC = 1;
+ RTC->MODE2.CTRLA.bit.ENABLE = 1;
+ _sync_rtc();
+}
+
+void watch_rtc_set_date_time(watch_date_time date_time) {
+ RTC_MODE2_CLOCK_Type val;
+
+ val.bit.SECOND = date_time.second;
+ val.bit.MINUTE = date_time.minute;
+ val.bit.HOUR = date_time.hour;
+ val.bit.DAY = date_time.day;
+ val.bit.MONTH = date_time.month;
+ val.bit.YEAR = (uint8_t)(date_time.year - WATCH_RTC_REFERENCE_YEAR);
+
+ RTC->MODE2.CLOCK.reg = val.reg;
+ _sync_rtc();
+}
+
+watch_date_time watch_rtc_get_date_time() {
+ watch_date_time retval;
+
+ _sync_rtc();
+ RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK;
+
+ retval.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
+ retval.month = val.bit.MONTH;
+ retval.day = val.bit.DAY;
+ retval.hour = val.bit.HOUR;
+ retval.minute = val.bit.MINUTE;
+ retval.second = val.bit.SECOND;
+
+ return retval;
}
void watch_register_tick_callback(ext_irq_cb_t callback) {
- _prescaler_register_callback(&CALENDAR_0.device, callback);
+ tick_callback = callback;
+ NVIC_ClearPendingIRQ(RTC_IRQn);
+ NVIC_EnableIRQ(RTC_IRQn);
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7;
+}
+
+void watch_disable_tick_callback() {
+ RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_PER7;
+}
+
+void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) {
+ RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND = alarm_time.second;
+ RTC->MODE2.Mode2Alarm[0].ALARM.bit.MINUTE = alarm_time.minute;
+ RTC->MODE2.Mode2Alarm[0].ALARM.bit.HOUR = alarm_time.hour;
+ RTC->MODE2.Mode2Alarm[0].ALARM.bit.DAY = alarm_time.day;
+ RTC->MODE2.Mode2Alarm[0].ALARM.bit.MONTH = alarm_time.month;
+ RTC->MODE2.Mode2Alarm[0].ALARM.bit.YEAR = (uint8_t)(alarm_time.year - WATCH_RTC_REFERENCE_YEAR);
+ RTC->MODE2.Mode2Alarm[0].MASK.reg = mask;
+
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0;
+ alarm_callback = callback;
+ NVIC_ClearPendingIRQ(RTC_IRQn);
+ NVIC_EnableIRQ(RTC_IRQn);
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0;
+}
+
+void watch_rtc_disable_alarm_callback() {
+ RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_ALARM0;
+}
+
+void RTC_Handler(void) {
+ uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg;
+ uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg;
+
+ if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
+ if (alarm_callback != NULL) {
+ alarm_callback();
+ }
+ RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0;
+ } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) {
+ if (tick_callback != NULL) {
+ tick_callback();
+ }
+ RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_PER7;
+ } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
+ uint8_t reason = RTC->MODE2.TAMPID.reg;
+ if (reason & RTC_TAMPID_TAMPID2) {
+ if (btn_alarm_callback != NULL) btn_alarm_callback();
+ } else if (reason & RTC_TAMPID_TAMPID1) {
+ if (a2_callback != NULL) a2_callback();
+ } else if (reason & RTC_TAMPID_TAMPID0) {
+ if (a4_callback != NULL) a4_callback();
+ }
+ RTC->MODE2.TAMPID.reg = reason;
+ RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_TAMPER;
+ }
+}
+
+///////////////////////
+// Deprecated functions
+
+void watch_set_date_time(struct calendar_date_time date_time) {
+ RTC_MODE2_CLOCK_Type val;
+
+ val.bit.SECOND = date_time.time.sec;
+ val.bit.MINUTE = date_time.time.min;
+ val.bit.HOUR = date_time.time.hour;
+ val.bit.DAY = date_time.date.day;
+ val.bit.MONTH = date_time.date.month;
+ val.bit.YEAR = (uint8_t)(date_time.date.year - WATCH_RTC_REFERENCE_YEAR);
+
+ RTC->MODE2.CLOCK.reg = val.reg;
+
+ _sync_rtc();
+}
+
+void watch_get_date_time(struct calendar_date_time *date_time) {
+ _sync_rtc();
+ RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK;
+
+ date_time->time.sec = val.bit.SECOND;
+ date_time->time.min = val.bit.MINUTE;
+ date_time->time.hour = val.bit.HOUR;
+ date_time->date.day = val.bit.DAY;
+ date_time->date.month = val.bit.MONTH;
+ date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
}