summaryrefslogtreecommitdiffstats
path: root/movement/movement.c
diff options
context:
space:
mode:
authorJoey Castillo <joeycastillo@utexas.edu>2021-11-28 18:15:21 -0500
committerJoey Castillo <joeycastillo@utexas.edu>2021-11-29 10:33:42 -0500
commit03fb09f5b47a5d2da079e58a74d6285139a3f974 (patch)
treebb2309221974f1f78628e29832d4e0b7d64fd7ac /movement/movement.c
parent812c6c2612c6aa89c9e2bd356f1b8c2a829d5f6a (diff)
downloadSensor-Watch-03fb09f5b47a5d2da079e58a74d6285139a3f974.tar.gz
Sensor-Watch-03fb09f5b47a5d2da079e58a74d6285139a3f974.tar.bz2
Sensor-Watch-03fb09f5b47a5d2da079e58a74d6285139a3f974.zip
movement: more granular button and LED timing via fast tick
Diffstat (limited to 'movement/movement.c')
-rw-r--r--movement/movement.c84
1 files changed, 59 insertions, 25 deletions
diff --git a/movement/movement.c b/movement/movement.c
index ac165094..76cd2252 100644
--- a/movement/movement.c
+++ b/movement/movement.c
@@ -63,6 +63,7 @@ void cb_light_btn_interrupt();
void cb_alarm_btn_interrupt();
void cb_alarm_btn_extwake();
void cb_alarm_fired();
+void cb_fast_tick();
void cb_tick();
static inline void _movement_reset_inactivity_countdown() {
@@ -70,6 +71,20 @@ static inline void _movement_reset_inactivity_countdown() {
movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_interval];
}
+static inline void _movement_enable_fast_tick_if_needed() {
+ if (!movement_state.fast_tick_enabled) {
+ movement_state.fast_ticks = 0;
+ watch_rtc_register_periodic_callback(cb_fast_tick, 128);
+ }
+}
+
+static inline void _movement_disable_fast_tick_if_possible() {
+ if ((movement_state.light_ticks == -1) && ((movement_state.light_down_timestamp + movement_state.mode_down_timestamp + movement_state.alarm_down_timestamp) == 0)) {
+ movement_state.fast_tick_enabled = false;
+ watch_rtc_disable_periodic_callback(128);
+ }
+}
+
void _movement_handle_background_tasks() {
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
// For each face, if the watch face wants a background task...
@@ -83,17 +98,20 @@ void _movement_handle_background_tasks() {
}
void movement_request_tick_frequency(uint8_t freq) {
- watch_rtc_disable_all_periodic_callbacks();
+ if (freq == 128) return; // Movement uses the 128 Hz tick internally
+ RTC->MODE2.INTENCLR.reg = 0xFE; // disable all callbacks except the 128 Hz one
movement_state.subsecond = 0;
movement_state.tick_frequency = freq;
watch_rtc_register_periodic_callback(cb_tick, freq);
}
void movement_illuminate_led() {
- watch_set_led_color(movement_state.settings.bit.led_red_color ? (0xF | movement_state.settings.bit.led_red_color << 4) : 0,
- movement_state.settings.bit.led_green_color ? (0xF | movement_state.settings.bit.led_green_color << 4) : 0);
- movement_state.led_on = true;
- movement_state.light_ticks = movement_state.settings.bit.led_duration * 2;
+ if (movement_state.settings.bit.led_duration) {
+ watch_set_led_color(movement_state.settings.bit.led_red_color ? (0xF | movement_state.settings.bit.led_red_color << 4) : 0,
+ movement_state.settings.bit.led_green_color ? (0xF | movement_state.settings.bit.led_green_color << 4) : 0);
+ movement_state.light_ticks = (movement_state.settings.bit.led_duration * 2 - 1) * 128;
+ _movement_enable_fast_tick_if_needed();
+ }
}
void movement_move_to_face(uint8_t watch_face_index) {
@@ -113,6 +131,7 @@ void app_init() {
movement_state.settings.bit.le_interval = 1;
movement_state.settings.bit.led_duration = 1;
movement_state.settings.bit.time_zone = 16; // default to GMT
+ movement_state.light_ticks = -1;
_movement_reset_inactivity_countdown();
}
@@ -182,14 +201,15 @@ bool app_loop() {
movement_state.watch_face_changed = false;
}
- // if the LED is on and should be off, turn it off
- if (movement_state.led_on && movement_state.light_ticks == 0) {
+ // if the LED should be off, turn it off
+ if (movement_state.light_ticks == 0) {
// unless the user is holding down the LIGHT button, in which case, give them more time.
if (watch_get_pin_level(BTN_LIGHT)) {
- movement_state.light_ticks = 3;
+ movement_state.light_ticks = 1;
} else {
watch_set_led_off();
- movement_state.led_on = false;
+ movement_state.light_ticks = -1;
+ _movement_disable_fast_tick_if_possible();
}
}
@@ -238,35 +258,45 @@ bool app_loop() {
event.subsecond = 0;
- return can_sleep && !movement_state.led_on;
+ return can_sleep && (movement_state.light_ticks == 0);
}
-movement_event_type_t _figure_out_button_event(movement_event_type_t button_down_event_type, uint8_t *down_timestamp) {
- watch_date_time date_time = watch_rtc_get_date_time();
- if (*down_timestamp) {
- uint8_t diff = ((61 + date_time.unit.second) - *down_timestamp) % 60;
+movement_event_type_t _figure_out_button_event(bool pin_level, movement_event_type_t button_down_event_type, uint8_t *down_timestamp) {
+ if (pin_level) {
+ // handle rising edge
+ _movement_enable_fast_tick_if_needed();
+ *down_timestamp = movement_state.fast_ticks + 1;
+ return button_down_event_type;
+ } else {
+ // this line is hack but it handles the situation where the light button was held for more than 10 seconds.
+ // fast tick is disabled by then, and the LED would get stuck on since there's no one left decrementing light_ticks.
+ if (movement_state.light_ticks == 1) movement_state.light_ticks = 0;
+ // now that that's out of the way, handle falling edge
+ uint16_t diff = movement_state.fast_ticks - *down_timestamp;
*down_timestamp = 0;
- if (diff > 1) return button_down_event_type + 2;
+ _movement_disable_fast_tick_if_possible();
+ // any press over a half second is considered a long press.
+ if (diff > 64) return button_down_event_type + 2;
else return button_down_event_type + 1;
- } else {
- *down_timestamp = date_time.unit.second + 1;
- return button_down_event_type;
}
}
void cb_light_btn_interrupt() {
+ bool pin_level = watch_get_pin_level(BTN_LIGHT);
_movement_reset_inactivity_countdown();
- event.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp);
+ event.event_type = _figure_out_button_event(pin_level, EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp);
}
void cb_mode_btn_interrupt() {
+ bool pin_level = watch_get_pin_level(BTN_MODE);
_movement_reset_inactivity_countdown();
- event.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp);
+ event.event_type = _figure_out_button_event(pin_level, EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp);
}
void cb_alarm_btn_interrupt() {
+ bool pin_level = watch_get_pin_level(BTN_ALARM);
_movement_reset_inactivity_countdown();
- event.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &movement_state.alarm_down_timestamp);
+ event.event_type = _figure_out_button_event(pin_level, EVENT_ALARM_BUTTON_DOWN, &movement_state.alarm_down_timestamp);
}
void cb_alarm_btn_extwake() {
@@ -278,14 +308,18 @@ void cb_alarm_fired() {
movement_state.needs_background_tasks_handled = true;
}
+void cb_fast_tick() {
+ movement_state.fast_ticks++;
+ if (movement_state.light_ticks > 0) movement_state.light_ticks--;
+ // this is just a fail-safe; fast tick should be disabled as soon as the button is up and/or the LED times out.
+ // but if for whatever reason it isn't, this forces the fast tick off after 10 seconds.
+ if (movement_state.fast_ticks >= 1280) watch_rtc_disable_periodic_callback(128);
+}
+
void cb_tick() {
event.event_type = EVENT_TICK;
watch_date_time date_time = watch_rtc_get_date_time();
if (date_time.unit.second != movement_state.last_second) {
- // TODO: since we time the LED with the 1 Hz tick, the actual time lit can vary depending on whether the
- // user hit it just before or just after a tick. If we time this with the system tick we can do better.
- if (movement_state.light_ticks) movement_state.light_ticks--;
-
// TODO: can we consolidate these two ticks?
if (movement_state.settings.bit.le_interval && movement_state.le_mode_ticks > 0) movement_state.le_mode_ticks--;
if (movement_state.timeout_ticks > 0) movement_state.timeout_ticks--;