Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 78 additions & 33 deletions libraries/RTC/RTC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include "RTC.h"
#include <errno.h>
#include <zephyr/devicetree.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
Expand Down Expand Up @@ -159,7 +160,8 @@ int Rtc::getSeconds() {
return -1;
}

#if defined(CONFIG_RTC_STM32) || defined(CONFIG_RTC_RPI_PICO)
#if !defined(CONFIG_COUNTER_NRF_RTC) // For boards with a dedicated RTC peripheral/driver, we use
// the Zephyr RTC

#if DT_NODE_HAS_STATUS(DT_NODELABEL(rtc), okay)
#define RTC_NODE DT_NODELABEL(rtc)
Expand Down Expand Up @@ -200,6 +202,26 @@ bool Rtc::begin() {
return true;
}

/**
* @brief Checks if the RTC has been configured and is running
*
* For boards with a dedicated RTC peripheral, verifies that:
* 1. The device is ready
* 2. A valid time has been set (by attempting to read it)
*
* @return bool true if RTC is running and has a valid time, false otherwise
*/
bool Rtc::isRunning() {
if (!device_is_ready(rtc_dev)) {
return false;
}

// Try to read the current time to verify it has been set
struct rtc_time time;
int ret = rtc_get_time(rtc_dev, &time);
return ret == 0;
}

/**
* @brief Rtc library setter function
*
Expand Down Expand Up @@ -408,7 +430,9 @@ void Rtc::alarmCallbackWrapper([[maybe_unused]] const struct device *dev,
*/
int Rtc::setUpdateCallback(RtcUpdateCallback cb, void *user_data) {
#if defined(CONFIG_RTC_RPI_PICO)
return -1;
ARG_UNUSED(cb);
ARG_UNUSED(user_data);
return -ENOTSUP;
#else
userUpdateCallback = cb;
userUpdateCallbackData = user_data;
Expand Down Expand Up @@ -445,7 +469,8 @@ void Rtc::updateCallbackWrapper([[maybe_unused]] const struct device *dev, void
*/
int Rtc::setCalibration(int32_t calibration) {
#if defined(CONFIG_RTC_RPI_PICO)
return -1;
ARG_UNUSED(calibration);
return -ENOTSUP;
#else
return rtc_set_calibration(rtc_dev, calibration);
#endif
Expand All @@ -462,14 +487,16 @@ int Rtc::setCalibration(int32_t calibration) {
*/
int Rtc::getCalibration(int32_t &calibration) {
#if defined(CONFIG_RTC_RPI_PICO)
return -1;
ARG_UNUSED(calibration);
return -ENOTSUP;
#else
return rtc_get_calibration(rtc_dev, &calibration);
#endif
}

#elif defined(CONFIG_COUNTER_NRF_RTC) // For other platforms (nordic), we must use the counter API
// to implement RTC functionality
#else // For other platforms (i.e. Nordic), we must use the counter API to implement RTC
// functionality

#if DT_NODE_HAS_STATUS(DT_NODELABEL(rtc1), okay)
#define COUNTER_NODE DT_NODELABEL(rtc1)
#elif DT_NODE_HAS_STATUS(DT_NODELABEL(rtc2), okay)
Expand Down Expand Up @@ -503,8 +530,13 @@ static bool is_leap(int year) {
*/
void Rtc::alarmHandler(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data) {
Rtc *rtc = static_cast<Rtc *>(user_data);
if (rtc->user_callback) {
rtc->user_callback(dev, chan_id, ticks, rtc->user_data);
ARG_UNUSED(dev);
ARG_UNUSED(chan_id);
ARG_UNUSED(ticks);

rtc->alarmPending = false;
if (rtc->userAlarmCallback) {
rtc->userAlarmCallback(rtc->userAlarmCallbackData);
} else {
printk("Alarm triggered but no callback registered! Channel: %d, Ticks: %u\n", chan_id,
ticks);
Expand All @@ -520,8 +552,6 @@ void Rtc::alarmHandler(const struct device *dev, uint8_t chan_id, uint32_t ticks
Rtc::Rtc() {
counter_dev = DEVICE_DT_GET_OR_NULL(COUNTER_NODE);
timeOffset = 0;
user_callback = nullptr;
user_data = nullptr;
}

/**
Expand All @@ -545,6 +575,15 @@ bool Rtc::begin() {
return true;
}

/**
* @brief Checks if the RTC has been configured and is running
*
* @return bool true if RTC has been initialized with setTime(), false otherwise
*/
bool Rtc::isRunning() {
return isInitialized;
}

/**
* @brief Sets the current RTC time.
*
Expand Down Expand Up @@ -572,6 +611,7 @@ int Rtc::setTime(int year, int month, int day, int hour, int minute, int second)
}

timeOffset = target - (ticks / freq);
isInitialized = true;
return 0;
}

Expand Down Expand Up @@ -612,14 +652,12 @@ int Rtc::getTime(int &year, int &month, int &day, int &hour, int &minute, int &s
* @param hour Target alarm hour.
* @param minute Target alarm minute.
* @param second Target alarm second.
* @param callback Function pointer to the user-defined callback.
* @param cb_user_data Pointer to user data passed to the callback when triggered.
* @param cb Function pointer to the user-defined callback.
* @param user_data Pointer to user data passed to the callback when triggered.
* @return 0 if successful, or a negative error code if the target time is invalid.
*/
int Rtc::setAlarm(int year, int month, int day, int hour, int minute, int second,
void (*callback)(const struct device *dev, uint8_t chan_id, uint32_t ticks,
void *user_data),
void *cb_user_data) {
RtcAlarmCallback cb, void *user_data) {
time_t target_epoch = datetimeToEpoch(year, month, day, hour, minute, second);
uint32_t freq = counter_get_frequency(counter_dev);
uint32_t current_ticks;
Expand All @@ -639,8 +677,10 @@ int Rtc::setAlarm(int year, int month, int day, int hour, int minute, int second
uint32_t alarm_ticks = current_ticks + delta_seconds * freq;

// Save user callback
user_callback = callback;
user_data = cb_user_data;
userAlarmCallback = cb;
userAlarmCallbackData = user_data;
alarmEpoch = target_epoch;
alarmPending = true;

alarm_cfg.flags = 0; // Absolute alarm
alarm_cfg.ticks = alarm_ticks;
Expand All @@ -650,8 +690,10 @@ int Rtc::setAlarm(int year, int month, int day, int hour, int minute, int second
int ret = counter_set_channel_alarm(counter_dev, 0, &alarm_cfg);
if (ret != 0) {
printk("Failed to set alarm: %d\n", ret);
user_callback = nullptr;
user_data = nullptr;
userAlarmCallback = nullptr;
userAlarmCallbackData = nullptr;
alarmEpoch = 0;
alarmPending = false;
return ret;
}

Expand All @@ -670,31 +712,36 @@ int Rtc::cancelAlarm() {
if (ret != 0) {
printk("Failed to cancel alarm: %d\n", ret);
}
user_callback = nullptr;
user_data = nullptr;
userAlarmCallback = nullptr;
userAlarmCallbackData = nullptr;
alarmEpoch = 0;
alarmPending = false;
return ret;
}

/**
* @brief Retrieves the currently configured alarm time.
* This function is not supported and will return -1 to indicate this.
*
* @return -1 to indicate not supported.
* @return 0 on success, or a negative error code if no alarm is active.
*/
int Rtc::getAlarm([[maybe_unused]] int &year, [[maybe_unused]] int &month,
[[maybe_unused]] int &day, [[maybe_unused]] int &hour,
[[maybe_unused]] int &minute, [[maybe_unused]] int &second) {
return -1;
if (!alarmPending) {
return -ENOENT;
}

epochToDatetime(alarmEpoch, year, month, day, hour, minute, second);
return 0;
}

/**
* @brief Checks whether an alarm is currently pending.
* This function is not supported and will return false to indicate this.
*
* @return false to indicate not supported.
* @return true if an alarm is pending, false otherwise.
*/
bool Rtc::isAlarmPending() {
return false;
return alarmPending;
}

/**
Expand All @@ -705,7 +752,7 @@ bool Rtc::isAlarmPending() {
*/
int Rtc::setUpdateCallback([[maybe_unused]] RtcUpdateCallback cb,
[[maybe_unused]] void *user_data) {
return -1;
return -ENOTSUP;
}

/**
Expand All @@ -715,7 +762,7 @@ int Rtc::setUpdateCallback([[maybe_unused]] RtcUpdateCallback cb,
* @return -1 to indicate not supported.
*/
int Rtc::setCalibration([[maybe_unused]] int32_t calibration) {
return -1;
return -ENOTSUP;
}

/**
Expand All @@ -725,7 +772,7 @@ int Rtc::setCalibration([[maybe_unused]] int32_t calibration) {
* @return -1 to indicate not supported.
*/
int Rtc::getCalibration([[maybe_unused]] int32_t &calibration) {
return -1;
return -ENOTSUP;
}

/**
Expand Down Expand Up @@ -815,6 +862,4 @@ void Rtc::epochToDatetime(time_t t, int &year, int &month, int &day, int &hour,
month = m + 1;
day = days + 1;
}
#else
#error "Unsupported RTC configuration"
#endif /* CONFIG_RTC_STM32 || CONFIG_RTC_RPI_PICO */
#endif /* !defined(CONFIG_COUNTER) */
Loading
Loading