Perform as little work as possible in the interrupt callbacks
This commit is contained in:
+81
-30
@@ -84,6 +84,7 @@ typedef struct {
|
|||||||
volatile bool minute_alarm_fired;
|
volatile bool minute_alarm_fired;
|
||||||
volatile bool is_buzzing;
|
volatile bool is_buzzing;
|
||||||
volatile uint8_t pending_sequence_priority;
|
volatile uint8_t pending_sequence_priority;
|
||||||
|
volatile bool schedule_next_comp;
|
||||||
|
|
||||||
// button tracking for long press
|
// button tracking for long press
|
||||||
movement_button_t mode_button;
|
movement_button_t mode_button;
|
||||||
@@ -184,7 +185,8 @@ static void _movement_set_top_of_minute_alarm() {
|
|||||||
|
|
||||||
movement_volatile_state.minute_counter = next_minute_counter;
|
movement_volatile_state.minute_counter = next_minute_counter;
|
||||||
|
|
||||||
watch_rtc_register_comp_callback(cb_minute_alarm_fired, next_minute_counter, MINUTE_TIMEOUT);
|
watch_rtc_register_comp_callback_no_schedule(cb_minute_alarm_fired, next_minute_counter, MINUTE_TIMEOUT);
|
||||||
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _movement_update_dst_offset_cache(void) {
|
static bool _movement_update_dst_offset_cache(void) {
|
||||||
@@ -234,13 +236,66 @@ static inline void _movement_reset_inactivity_countdown(void) {
|
|||||||
SLEEP_TIMEOUT
|
SLEEP_TIMEOUT
|
||||||
);
|
);
|
||||||
|
|
||||||
watch_rtc_schedule_next_comp();
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _movement_disable_inactivity_countdown(void) {
|
static inline void _movement_disable_inactivity_countdown(void) {
|
||||||
watch_rtc_disable_comp_callback_no_schedule(RESIGN_TIMEOUT);
|
watch_rtc_disable_comp_callback_no_schedule(RESIGN_TIMEOUT);
|
||||||
watch_rtc_disable_comp_callback_no_schedule(SLEEP_TIMEOUT);
|
watch_rtc_disable_comp_callback_no_schedule(SLEEP_TIMEOUT);
|
||||||
watch_rtc_schedule_next_comp();
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _movement_renew_top_of_minute_alarm(void) {
|
||||||
|
// Renew the alarm for a minute from the previous one (ensures no drift)
|
||||||
|
movement_volatile_state.minute_counter += watch_rtc_get_ticks_per_minute();
|
||||||
|
watch_rtc_register_comp_callback_no_schedule(cb_minute_alarm_fired, movement_volatile_state.minute_counter, MINUTE_TIMEOUT);
|
||||||
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _movement_handle_button_presses(uint32_t pending_events) {
|
||||||
|
bool any_up = false;
|
||||||
|
bool any_down = false;
|
||||||
|
|
||||||
|
movement_button_t* buttons[3] = {
|
||||||
|
&movement_volatile_state.mode_button,
|
||||||
|
&movement_volatile_state.light_button,
|
||||||
|
&movement_volatile_state.alarm_button
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
movement_button_t* button = buttons[i];
|
||||||
|
|
||||||
|
// If a button down occurred
|
||||||
|
if (pending_events & (1 << button->down_event)) {
|
||||||
|
watch_rtc_register_comp_callback_no_schedule(button->cb_longpress, button->down_timestamp + MOVEMENT_LONG_PRESS_TICKS, button->timeout_index);
|
||||||
|
any_down = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a button up or button long up occurred
|
||||||
|
if (pending_events & (
|
||||||
|
(1 << (button->down_event + 1)) |
|
||||||
|
(1 << (button->down_event + 3))
|
||||||
|
)) {
|
||||||
|
// We cancel the timeout if it hasn't fired yet
|
||||||
|
watch_rtc_disable_comp_callback_no_schedule(button->timeout_index);
|
||||||
|
any_up = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any_down) {
|
||||||
|
// force alarm off if the user pressed a button.
|
||||||
|
watch_buzzer_abort_sequence();
|
||||||
|
|
||||||
|
// Delay auto light off if the user is still interacting with the watch.
|
||||||
|
if (movement_state.light_on) {
|
||||||
|
movement_illuminate_led();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any_down || any_up) {
|
||||||
|
_movement_reset_inactivity_countdown();
|
||||||
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _movement_handle_top_of_minute(void) {
|
static void _movement_handle_top_of_minute(void) {
|
||||||
@@ -328,11 +383,12 @@ void movement_illuminate_led(void) {
|
|||||||
// Set a timeout to turn off the light
|
// Set a timeout to turn off the light
|
||||||
rtc_counter_t counter = watch_rtc_get_counter();
|
rtc_counter_t counter = watch_rtc_get_counter();
|
||||||
uint32_t freq = watch_rtc_get_frequency();
|
uint32_t freq = watch_rtc_get_frequency();
|
||||||
watch_rtc_register_comp_callback(
|
watch_rtc_register_comp_callback_no_schedule(
|
||||||
cb_led_timeout_interrupt,
|
cb_led_timeout_interrupt,
|
||||||
counter + (movement_state.settings.bit.led_duration * 2 - 1) * freq,
|
counter + (movement_state.settings.bit.led_duration * 2 - 1) * freq,
|
||||||
LED_TIMEOUT
|
LED_TIMEOUT
|
||||||
);
|
);
|
||||||
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,13 +398,15 @@ void movement_force_led_on(uint8_t red, uint8_t green, uint8_t blue) {
|
|||||||
movement_state.light_on = true;
|
movement_state.light_on = true;
|
||||||
watch_set_led_color_rgb(red, green, blue);
|
watch_set_led_color_rgb(red, green, blue);
|
||||||
rtc_counter_t counter = watch_rtc_get_counter();
|
rtc_counter_t counter = watch_rtc_get_counter();
|
||||||
watch_rtc_register_comp_callback(cb_led_timeout_interrupt, counter + 32767, LED_TIMEOUT);
|
watch_rtc_register_comp_callback_no_schedule(cb_led_timeout_interrupt, counter + 32767, LED_TIMEOUT);
|
||||||
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void movement_force_led_off(void) {
|
void movement_force_led_off(void) {
|
||||||
movement_state.light_on = false;
|
movement_state.light_on = false;
|
||||||
// The led timeout probably already triggered, but still disable just in case we are switching off the light by other means
|
// The led timeout probably already triggered, but still disable just in case we are switching off the light by other means
|
||||||
watch_rtc_disable_comp_callback(LED_TIMEOUT);
|
watch_rtc_disable_comp_callback_no_schedule(LED_TIMEOUT);
|
||||||
|
movement_volatile_state.schedule_next_comp = true;
|
||||||
watch_set_led_off();
|
watch_set_led_off();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,6 +1076,7 @@ static void _sleep_mode_app_loop(void) {
|
|||||||
// we also have to handle top-of-the-minute tasks here in the mini-runloop
|
// we also have to handle top-of-the-minute tasks here in the mini-runloop
|
||||||
if (movement_volatile_state.minute_alarm_fired) {
|
if (movement_volatile_state.minute_alarm_fired) {
|
||||||
movement_volatile_state.minute_alarm_fired = false;
|
movement_volatile_state.minute_alarm_fired = false;
|
||||||
|
_movement_renew_top_of_minute_alarm();
|
||||||
_movement_handle_top_of_minute();
|
_movement_handle_top_of_minute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1034,6 +1093,12 @@ static void _sleep_mode_app_loop(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have made changes to any of the RTC comp timers, schedule the next one in the queue
|
||||||
|
if (movement_volatile_state.schedule_next_comp) {
|
||||||
|
movement_volatile_state.schedule_next_comp = false;
|
||||||
|
watch_rtc_schedule_next_comp();
|
||||||
|
}
|
||||||
|
|
||||||
// otherwise enter sleep mode, until either the top of the minute interrupt or extwake wakes us up.
|
// otherwise enter sleep mode, until either the top of the minute interrupt or extwake wakes us up.
|
||||||
watch_enter_sleep_mode();
|
watch_enter_sleep_mode();
|
||||||
}
|
}
|
||||||
@@ -1093,6 +1158,9 @@ bool app_loop(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle any button up/down events that occurred, e.g. schedule longpress timeouts, reset inactivity, etc.
|
||||||
|
_movement_handle_button_presses(pending_events);
|
||||||
|
|
||||||
// if we have a scheduled background task, handle that here:
|
// if we have a scheduled background task, handle that here:
|
||||||
if (
|
if (
|
||||||
(pending_events & (1 << EVENT_TICK))
|
(pending_events & (1 << EVENT_TICK))
|
||||||
@@ -1102,17 +1170,6 @@ bool app_loop(void) {
|
|||||||
_movement_handle_scheduled_tasks();
|
_movement_handle_scheduled_tasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay auto light off if the user is still interacting with the watch.
|
|
||||||
if (movement_state.light_on) {
|
|
||||||
if (pending_events & (
|
|
||||||
(1 << EVENT_LIGHT_BUTTON_DOWN) |
|
|
||||||
(1 << EVENT_MODE_BUTTON_DOWN) |
|
|
||||||
(1 << EVENT_ALARM_BUTTON_DOWN)
|
|
||||||
)) {
|
|
||||||
movement_illuminate_led();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop the EVENT_TIMEOUT out of the pending_events so it can be handled separately
|
// Pop the EVENT_TIMEOUT out of the pending_events so it can be handled separately
|
||||||
bool resign_timeout = (pending_events & (1 << EVENT_TIMEOUT)) != 0;
|
bool resign_timeout = (pending_events & (1 << EVENT_TIMEOUT)) != 0;
|
||||||
if (resign_timeout) {
|
if (resign_timeout) {
|
||||||
@@ -1133,6 +1190,7 @@ bool app_loop(void) {
|
|||||||
// handle top-of-minute tasks, if the alarm handler told us we need to
|
// handle top-of-minute tasks, if the alarm handler told us we need to
|
||||||
if (movement_volatile_state.minute_alarm_fired) {
|
if (movement_volatile_state.minute_alarm_fired) {
|
||||||
movement_volatile_state.minute_alarm_fired = false;
|
movement_volatile_state.minute_alarm_fired = false;
|
||||||
|
_movement_renew_top_of_minute_alarm();
|
||||||
_movement_handle_top_of_minute();
|
_movement_handle_top_of_minute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1178,6 +1236,12 @@ bool app_loop(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// If we have made changes to any of the RTC comp timers, schedule the next one in the queue
|
||||||
|
if (movement_volatile_state.schedule_next_comp) {
|
||||||
|
movement_volatile_state.schedule_next_comp = false;
|
||||||
|
watch_rtc_schedule_next_comp();
|
||||||
|
}
|
||||||
|
|
||||||
#if __EMSCRIPTEN__
|
#if __EMSCRIPTEN__
|
||||||
shell_task();
|
shell_task();
|
||||||
#else
|
#else
|
||||||
@@ -1209,15 +1273,9 @@ static movement_event_type_t _process_button_event(bool pin_level, movement_butt
|
|||||||
button->is_down = pin_level;
|
button->is_down = pin_level;
|
||||||
|
|
||||||
if (pin_level) {
|
if (pin_level) {
|
||||||
// We schedule a timeout to fire the longpress event
|
|
||||||
button->down_timestamp = counter;
|
button->down_timestamp = counter;
|
||||||
watch_rtc_register_comp_callback_no_schedule(button->cb_longpress, counter + MOVEMENT_LONG_PRESS_TICKS, button->timeout_index);
|
|
||||||
// force alarm off if the user pressed a button.
|
|
||||||
watch_buzzer_abort_sequence();
|
|
||||||
event_type = button->down_event;
|
event_type = button->down_event;
|
||||||
} else {
|
} else {
|
||||||
// We cancel the timeout if it hasn't fired yet
|
|
||||||
watch_rtc_disable_comp_callback_no_schedule(button->timeout_index);
|
|
||||||
if ((counter - button->down_timestamp) >= MOVEMENT_LONG_PRESS_TICKS) {
|
if ((counter - button->down_timestamp) >= MOVEMENT_LONG_PRESS_TICKS) {
|
||||||
event_type = button->down_event + 3;
|
event_type = button->down_event + 3;
|
||||||
} else {
|
} else {
|
||||||
@@ -1225,9 +1283,6 @@ static movement_event_type_t _process_button_event(bool pin_level, movement_butt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will also schedule the comp callbacks above
|
|
||||||
_movement_reset_inactivity_countdown();
|
|
||||||
|
|
||||||
return event_type;
|
return event_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1314,10 +1369,6 @@ void cb_minute_alarm_fired(void) {
|
|||||||
#if __EMSCRIPTEN__
|
#if __EMSCRIPTEN__
|
||||||
_wake_up_simulator();
|
_wake_up_simulator();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Renew the alarm for a minute from the previous one (ensures no drift)
|
|
||||||
movement_volatile_state.minute_counter += watch_rtc_get_ticks_per_minute();
|
|
||||||
watch_rtc_register_comp_callback(cb_minute_alarm_fired, movement_volatile_state.minute_counter, MINUTE_TIMEOUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cb_tick(void) {
|
void cb_tick(void) {
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ void watch_rtc_schedule_next_comp(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Because of the hardware, the soonest we can schedule is the next tick
|
// Because of the hardware, the soonest we can schedule is the next tick
|
||||||
curr_counter +=1;
|
// curr_counter +=1;
|
||||||
|
|
||||||
bool schedule_any = false;
|
bool schedule_any = false;
|
||||||
rtc_counter_t comp_counter;
|
rtc_counter_t comp_counter;
|
||||||
@@ -278,9 +278,8 @@ void watch_rtc_disable_comp_callback_no_schedule(uint8_t index) {
|
|||||||
|
|
||||||
void watch_rtc_callback(uint16_t interrupt_cause) {
|
void watch_rtc_callback(uint16_t interrupt_cause) {
|
||||||
// First read all relevant registers, to ensure no changes occurr during the callbacks
|
// First read all relevant registers, to ensure no changes occurr during the callbacks
|
||||||
uint16_t interrupt_enabled = RTC->MODE0.INTENSET.reg;
|
|
||||||
rtc_counter_t counter = watch_rtc_get_counter();
|
rtc_counter_t counter = watch_rtc_get_counter();
|
||||||
|
uint16_t interrupt_enabled = (uint16_t)RTC->MODE0.INTENSET.reg;
|
||||||
|
|
||||||
if ((interrupt_cause & interrupt_enabled) & RTC_MODE0_INTFLAG_PER_Msk) {
|
if ((interrupt_cause & interrupt_enabled) & RTC_MODE0_INTFLAG_PER_Msk) {
|
||||||
// handle the tick callback first, it's what we do the most.
|
// handle the tick callback first, it's what we do the most.
|
||||||
@@ -309,12 +308,12 @@ void watch_rtc_callback(uint16_t interrupt_cause) {
|
|||||||
|
|
||||||
if ((interrupt_cause & interrupt_enabled) & RTC_MODE0_INTFLAG_CMP0) {
|
if ((interrupt_cause & interrupt_enabled) & RTC_MODE0_INTFLAG_CMP0) {
|
||||||
// The comp interrupt is generated one tick after the matched counter
|
// The comp interrupt is generated one tick after the matched counter
|
||||||
rtc_counter_t comp_counter = counter - 1;
|
// rtc_counter_t comp_counter = counter - 1;
|
||||||
|
|
||||||
for (uint8_t index = 0; index < WATCH_RTC_N_COMP_CB; ++index) {
|
for (uint8_t index = 0; index < WATCH_RTC_N_COMP_CB; ++index) {
|
||||||
// Give it a little bit of wiggle room, if a comp callback is enabled and is just passed
|
// Give it a little bit of wiggle room, if a comp callback is enabled and is just passed
|
||||||
if (comp_callbacks[index].enabled &&
|
if (comp_callbacks[index].enabled &&
|
||||||
(comp_counter - comp_callbacks[index].counter) <= RTC_CNT_HZ
|
(counter - comp_callbacks[index].counter) <= RTC_CNT_HZ
|
||||||
) {
|
) {
|
||||||
comp_callbacks[index].enabled = false;
|
comp_callbacks[index].enabled = false;
|
||||||
comp_callbacks[index].callback();
|
comp_callbacks[index].callback();
|
||||||
|
|||||||
Reference in New Issue
Block a user