From 5cac2cf7fc251df8ca80c2207adab73e270ba512 Mon Sep 17 00:00:00 2001 From: Lephe Date: Thu, 16 Jul 2020 17:27:56 +0200 Subject: [PATCH] rtc: take input similar to timer_setup() in rtc_timer_start() --- include/gint/rtc.h | 51 ++++++++++++++++++++++------------------ src/rtc/rtc.c | 58 +++++++++++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 46 deletions(-) diff --git a/include/gint/rtc.h b/include/gint/rtc.h index f148722..cb7250a 100644 --- a/include/gint/rtc.h +++ b/include/gint/rtc.h @@ -6,12 +6,13 @@ #define GINT_RTC #include +#include //--- // Time management //--- -/* rtc_time_t - a point in time, representable in the RTC registers */ +/* rtc_time_t: A point in time, representable in the RTC registers */ typedef struct { uint16_t year; /* Years (exact value, e.g. 2018) */ @@ -24,15 +25,15 @@ typedef struct } rtc_time_t; -/* rtc_get_time() - read the current time from the RTC +/* rtc_get_time(): Read the current time from the RTC @time Pointer to rtc_time_t structure (needs not be initialized) */ void rtc_get_time(rtc_time_t *time); -/* rtc_set_time() - write a new current time to the RTC +/* rtc_set_time(): Set current time in the RTC If [time->week_day] is not in the valid range, it is set to 0. Other fields are not checked. @time Pointer to new time */ -void rtc_set_time(const rtc_time_t *time); +void rtc_set_time(rtc_time_t const *time); //--- // RTC timer @@ -42,8 +43,8 @@ void rtc_set_time(const rtc_time_t *time); // comparing the detected frequencies with the RTC. //--- -/* rtc_frequency_t - possible frequency settings for the RTC's interrupt */ -typedef enum +/* Possible frequency settings for the RTC's interrupt */ +enum { RTC_500mHz = 7, RTC_1Hz = 6, @@ -53,30 +54,36 @@ typedef enum RTC_64Hz = 2, RTC_256Hz = 1, RTC_NONE = 0, +}; -} rtc_frequency_t; - -/* rtc_start_timer() - configure the RTC timer +/* rtc_start_timer(): Configure the RTC timer This function sets up the RTC timer to invoke the provided callback function - with its argument regularly. This works like normal timers (); - [callback] is passed [arg] as argument and the RTC timer is stopped if it - returns non-zero. + with its argument regularly. This works like standard timers. The callback + is a function, the allowed types are listed in . It may have + zero or one argument, and must return either TIMER_CONTINUE or TIMER_STOP. - This function will replace any existing callback! + Do not confuse this "RTC timer" with Casio's added timers that run at + 32768 Hz (which are called "RTC timers" in CPU73050.dll). These timers are + called Extra TMU in gint and are handled by . - Note that, as opposed to timers, it is not possible to know how much time - will elapse before the callback will first be called. For instance, setting - up a 1 Hz-callback when the current time ends in 950 ms will result in the - callback being called after 50 ms, then every second. This is not a problem - for most uses. */ -void rtc_start_timer(rtc_frequency_t freq, - int (*callback)(volatile void *arg), volatile void *arg); + Note that the timing of the first callback is always uncertain. A 1 Hz timer + set up when half of the current second is already elapsed will be called for + the first time after only 500 ms, for instance. -/* rtc_stop_timer() - stop the RTC timer + @freq Timer frequency + @callback Function to call back at the specified frequency + @... Up to one 4-byte argument for the callback + Fails and returns non-zero if the RTC timer is already in use. */ +int rtc_start_timer(int freq, timer_callback_t callback, ...); + +/* Makes sure an argument is always provided, for va_arg() */ +#define rtc_start_timer(...) rtc_start_timer(__VA_ARGS__, 0) + +/* rtc_stop_timer(): Stop the RTC timer This function stops the RTC timer that was set up with rtc_start_timer(). If the decision of stopping the timer comes from the callback, it is preferable - to return non-zero. */ + to return TIMER_STOP. */ void rtc_stop_timer(void); #endif /* GINT_RTC */ diff --git a/src/rtc/rtc.c b/src/rtc/rtc.c index 4944490..47231aa 100644 --- a/src/rtc/rtc.c +++ b/src/rtc/rtc.c @@ -11,6 +11,10 @@ #include #include +#include + +#undef rtc_start_timer + //--- // Real-Time Clock peripheral registers //--- @@ -18,17 +22,17 @@ /* RTC address on SH7305, adjusted at startup on SH7337 and SH7355 */ static rtc_t *RTC = &SH7305_RTC; /* Address of interrupt handler parameters */ -GBSS struct { - int (*callback)(volatile void *arg); - volatile void *arg; +GBSS static struct { + void *function; + uint32_t arg; volatile uint8_t *RCR2; -} GPACKED(4) *params; +} GPACKED(4) *timer_params; //--- // Time management //--- -/* int8(), int16() - convert BCD to integer */ +/* int8(), int16(): Convert BCD to integer */ static int int8(uint8_t bcd) { return (bcd & 0x0f) + 10 * (bcd >> 4); @@ -39,7 +43,7 @@ static int int16(uint16_t bcd) + 1000 * (bcd >> 12); } -/* bcd8(), bcd16() - convert integer to BCD +/* bcd8(), bcd16(): Convert integer to BCD TODO: Use some kind of qdiv() for bcd8() and bcd16() */ static uint8_t bcd8(int integer) { @@ -52,11 +56,9 @@ static uint16_t bcd16(int integer) return (bcd8(integer / 100) << 8) | bcd8(integer % 100); } -/* rtc_get_time() - read the current time from the RTC */ +/* rtc_get_time(): Read the current time from the RTC */ void rtc_get_time(rtc_time_t *time) { - if(!time) return; - do { RTC->RCR1.CF = 0; @@ -71,11 +73,11 @@ void rtc_get_time(rtc_time_t *time) } while(RTC->RCR1.CF != 0); } -/* rtc_set_time() - write a new current time to the RTC */ -void rtc_set_time(const rtc_time_t *time) +/* rtc_set_time(): Set current time in the RTC */ +void rtc_set_time(rtc_time_t const *time) { - if(!time) return; - int wday = (time->week_day < 7) ? (time->week_day) : (0); + int wday = time->week_day; + if(wday >= 7) wday = 0; do { RTC->RCR1.CF = 0; @@ -95,16 +97,23 @@ void rtc_set_time(const rtc_time_t *time) // RTC timer //--- -/* rtc_start_timer() - configure the RTC timer */ -void rtc_start_timer(rtc_frequency_t freq, - int (*callback)(volatile void *arg), volatile void *arg) +/* rtc_start_timer(): Configure the RTC timer */ +int rtc_start_timer(int freq, timer_callback_t f, ...) { - /* Temporarily disable the interrupt */ - RTC->RCR2.PES = RTC_NONE; + /* Refuse to override an existing callback */ + if(RTC->RCR2.PES != RTC_NONE) return 1; + if(freq == RTC_NONE) return 1; - /* Set up the callback */ - params->callback = callback; - params->arg = arg; + /* Get the argument */ + va_list args; + va_start(args, f); + uint32_t arg = va_arg(args, uint32_t); + va_end(args); + + /* Temporarily disable the interrupt and set up the callback */ + RTC->RCR2.PES = RTC_NONE; + timer_params->function = f.v; + timer_params->arg = arg; /* Clear the interrupt flag */ do RTC->RCR2.PEF = 0; @@ -112,9 +121,10 @@ void rtc_start_timer(rtc_frequency_t freq, /* Enable the interrupt */ RTC->RCR2.PES = freq; + return 0; } -/* rtc_stop_timer() - stop the RTC timer */ +/* rtc_stop_timer(): Stop the RTC timer */ void rtc_stop_timer(void) { RTC->RCR2.PES = RTC_NONE; @@ -143,8 +153,8 @@ static void init(void) h0 = gint_inthandler(0xaa0, inth_rtc_pri, 32); h1 = gint_inthandler(0xae0, inth_rtc_pri_helper, 32); - params = h0 + 20; - params->RCR2 = &RTC->RCR2.byte; + timer_params = h0 + 20; + timer_params->RCR2 = &RTC->RCR2.byte; /* Disable the periodic interrupt for now, but give it priority 5 */ RTC->RCR2.PES = RTC_NONE;