From: joeycastillo Date: Wed, 9 Oct 2024 02:17:30 +0000 (-0400) Subject: move accelerometer interrupt demo to Second Movement X-Git-Url: https://git.earman.xyz/?a=commitdiff_plain;h=e966131d8962bf2bce986bfd91bcbddcdcc6b480;p=sensor-watch.git move accelerometer interrupt demo to Second Movement --- diff --git a/Makefile b/Makefile index 784d51b..ec57af0 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ SRCS += \ ./shell/shell.c \ ./shell/shell_cmd_list.c \ ./movement/lib/sunriset/sunriset.c \ + ./watch-library/shared/driver/lis2dw.c \ ./watch-library/shared/driver/thermistor_driver.c \ ./watch-library/shared/watch/watch_common_buzzer.c \ ./watch-library/shared/watch/watch_common_display.c \ diff --git a/movement/watch_faces/sensor/accel_interrupt_count_face.c b/movement/watch_faces/sensor/accel_interrupt_count_face.c deleted file mode 100644 index 8d436ae..0000000 --- a/movement/watch_faces/sensor/accel_interrupt_count_face.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2022 Joey Castillo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include "accel_interrupt_count_face.h" -#include "lis2dw.h" -#include "watch.h" - -// hacky hacky! -uint32_t *ptr_to_count = 0; - -void accel_interrupt_handler(void); -void accel_interrupt_handler(void) { - (*ptr_to_count)++; -} - -static void _accel_interrupt_count_face_update_display(accel_interrupt_count_state_t *state) { - char buf[11]; - - if (state->running) { - watch_set_indicator(WATCH_INDICATOR_SIGNAL); - } else { - watch_clear_indicator(WATCH_INDICATOR_SIGNAL); - } - - // "AC"celerometer "IN"terrupts - snprintf(buf, 11, "AC1N%6ld", state->count); - watch_display_string(buf, 0); - printf("%s\n", buf); -} - -static void _accel_interrupt_count_face_configure_threshold(uint8_t threshold) { - lis2dw_configure_wakeup_int1(threshold, false, true); -} - -void accel_interrupt_count_face_setup(uint8_t watch_face_index, void ** context_ptr) { - (void) watch_face_index; - if (*context_ptr == NULL) { - *context_ptr = malloc(sizeof(accel_interrupt_count_state_t)); - memset(*context_ptr, 0, sizeof(accel_interrupt_count_state_t)); - ptr_to_count = &((accel_interrupt_count_state_t *)*context_ptr)->count; - watch_enable_i2c(); - lis2dw_begin(); - lis2dw_set_low_power_mode(LIS2DW_LP_MODE_2); // lowest power 14-bit mode, 25 Hz is 3.5 µA @ 1.8V w/ low noise, 3µA without - lis2dw_set_low_noise_mode(true); // consumes a little more power - lis2dw_set_range(LIS2DW_CTRL6_VAL_RANGE_4G); - lis2dw_set_data_rate(LIS2DW_DATA_RATE_25_HZ); // is this enough? - - // threshold is 1/64th of full scale, so for a FS of ±4G this is 1.25G - ((accel_interrupt_count_state_t *)*context_ptr)->threshold = 10; - _accel_interrupt_count_face_configure_threshold(((accel_interrupt_count_state_t *)*context_ptr)->threshold); - } -} - -void accel_interrupt_count_face_activate(void *context) { - accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)context; - - // never in settings mode at the start - state->is_setting = false; - - // force LE interval to never sleep - movement_set_low_energy_timeout(0); -} - -bool accel_interrupt_count_face_loop(movement_event_t event, void *context) { - accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)context; - - if (state->is_setting) { - switch (event.event_type) { - case EVENT_LIGHT_BUTTON_DOWN: - state->new_threshold = (state->new_threshold + 1) % 64; - // fall through - case EVENT_TICK: - { - char buf[11]; - snprintf(buf, 11, "TH %4d ", state->new_threshold); - watch_display_string(buf, 0); - printf("%s\n", buf); - } - break; - case EVENT_ALARM_BUTTON_UP: - lis2dw_configure_wakeup_int1(state->threshold, false, true); - state->threshold = state->new_threshold; - state->is_setting = false; - break; - default: - movement_default_loop_handler(event); - break; - } - } else { - switch (event.event_type) { - case EVENT_LIGHT_BUTTON_DOWN: - movement_illuminate_led(); - - // if stopped, reset the count - if (!state->running) { - state->count = 0; - } - _accel_interrupt_count_face_update_display(state); - break; - case EVENT_ALARM_BUTTON_UP: - if (state->running) { - state->running = false; - watch_register_interrupt_callback(A4, NULL, INTERRUPT_TRIGGER_RISING); - } else { - state->running = true; - watch_register_interrupt_callback(A4, accel_interrupt_handler, INTERRUPT_TRIGGER_RISING); - } - _accel_interrupt_count_face_update_display(state); - break; - case EVENT_ACTIVATE: - case EVENT_TICK: - _accel_interrupt_count_face_update_display(state); - break; - case EVENT_ALARM_LONG_PRESS: - if (!state->running) { - state->new_threshold = state->threshold; - state->is_setting = true; - } - return false; - default: - movement_default_loop_handler(event); - break; - } - } - - return true; -} - -void accel_interrupt_count_face_resign(void *context) { - (void) context; -} - -movement_watch_face_advisory_t accel_interrupt_count_face_advise(void *context) { - (void) context; - movement_watch_face_advisory_t retval = { 0 }; - - return retval; -} diff --git a/movement/watch_faces/sensor/accel_interrupt_count_face.h b/movement/watch_faces/sensor/accel_interrupt_count_face.h deleted file mode 100644 index 29d5df1..0000000 --- a/movement/watch_faces/sensor/accel_interrupt_count_face.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2022 Joey Castillo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -/* - * Accelerometer Interrupt Counter - * - * This is an experimental watch face for counting the number of interrupts that - * the Sensor Watch Motion acceleromoeter board fires. I expect it will be removed - * once we integrate accelerometer functionality more deeply into Movement. - */ - -#include "movement.h" -#include "watch.h" - -typedef struct { - uint32_t count; - uint8_t new_threshold; - uint8_t threshold; - bool running; - bool is_setting; -} accel_interrupt_count_state_t; - -void accel_interrupt_count_face_setup(uint8_t watch_face_index, void ** context_ptr); -void accel_interrupt_count_face_activate(void *context); -bool accel_interrupt_count_face_loop(movement_event_t event, void *context); -void accel_interrupt_count_face_resign(void *context); -movement_watch_face_advisory_t accel_interrupt_count_face_advise(void *context); - -#define accel_interrupt_count_face ((const watch_face_t){ \ - accel_interrupt_count_face_setup, \ - accel_interrupt_count_face_activate, \ - accel_interrupt_count_face_loop, \ - accel_interrupt_count_face_resign, \ - accel_interrupt_count_face_advise, \ -}) diff --git a/movement_faces.h b/movement_faces.h index 1f7df83..68da198 100644 --- a/movement_faces.h +++ b/movement_faces.h @@ -32,6 +32,7 @@ #include "fast_stopwatch_face.h" #include "sunrise_sunset_face.h" #include "character_set_face.h" +#include "accel_interrupt_count_face.h" #include "all_segments_face.h" #include "float_demo_face.h" #include "temperature_display_face.h" diff --git a/watch-faces.mk b/watch-faces.mk index 68798ad..98c7ef8 100644 --- a/watch-faces.mk +++ b/watch-faces.mk @@ -6,6 +6,7 @@ SRCS += \ ./watch-faces/complication/countdown_face.c \ ./watch-faces/complication/fast_stopwatch_face.c \ ./watch-faces/complication/sunrise_sunset_face.c \ + ./watch-faces/demo/accel_interrupt_count_face.c \ ./watch-faces/demo/all_segments_face.c \ ./watch-faces/demo/character_set_face.c \ ./watch-faces/demo/float_demo_face.c \ diff --git a/watch-faces/demo/accel_interrupt_count_face.c b/watch-faces/demo/accel_interrupt_count_face.c new file mode 100644 index 0000000..e7b61ff --- /dev/null +++ b/watch-faces/demo/accel_interrupt_count_face.c @@ -0,0 +1,164 @@ +/* + * MIT License + * + * Copyright (c) 2022 Joey Castillo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "accel_interrupt_count_face.h" +#include "lis2dw.h" +#include "watch.h" + +// hacky hacky! +uint32_t *ptr_to_count = 0; + +void accel_interrupt_handler(void); +void accel_interrupt_handler(void) { + (*ptr_to_count)++; +} + +static void _accel_interrupt_count_face_update_display(accel_interrupt_count_state_t *state) { + char buf[7]; + + if (state->running) { + watch_set_indicator(WATCH_INDICATOR_SIGNAL); + } else { + watch_clear_indicator(WATCH_INDICATOR_SIGNAL); + } + + // "AC"celerometer "IN"terrupts + watch_display_text(WATCH_POSITION_TOP_LEFT, "AC"); + watch_display_text(WATCH_POSITION_TOP_RIGHT, "1N"); + snprintf(buf, 7, "%6ld", state->count); + watch_display_text(WATCH_POSITION_BOTTOM, buf); + printf("%s\n", buf); +} + +static void _accel_interrupt_count_face_configure_threshold(uint8_t threshold) { + lis2dw_configure_wakeup_int1(threshold, false, true); +} + +void accel_interrupt_count_face_setup(uint8_t watch_face_index, void ** context_ptr) { + (void) watch_face_index; + if (*context_ptr == NULL) { + *context_ptr = malloc(sizeof(accel_interrupt_count_state_t)); + memset(*context_ptr, 0, sizeof(accel_interrupt_count_state_t)); + ptr_to_count = &((accel_interrupt_count_state_t *)*context_ptr)->count; + watch_enable_i2c(); + lis2dw_begin(); + lis2dw_set_low_power_mode(LIS2DW_LP_MODE_2); // lowest power 14-bit mode, 25 Hz is 3.5 µA @ 1.8V w/ low noise, 3µA without + lis2dw_set_low_noise_mode(true); // consumes a little more power + lis2dw_set_range(LIS2DW_CTRL6_VAL_RANGE_4G); + lis2dw_set_data_rate(LIS2DW_DATA_RATE_25_HZ); // is this enough? + + // threshold is 1/64th of full scale, so for a FS of ±4G this is 1.25G + ((accel_interrupt_count_state_t *)*context_ptr)->threshold = 10; + _accel_interrupt_count_face_configure_threshold(((accel_interrupt_count_state_t *)*context_ptr)->threshold); + } +} + +void accel_interrupt_count_face_activate(void *context) { + accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)context; + + // never in settings mode at the start + state->is_setting = false; + + // force LE interval to never sleep + movement_set_low_energy_timeout(0); +} + +bool accel_interrupt_count_face_loop(movement_event_t event, void *context) { + accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)context; + + if (state->is_setting) { + switch (event.event_type) { + case EVENT_LIGHT_BUTTON_DOWN: + state->new_threshold = (state->new_threshold + 1) % 64; + // fall through + case EVENT_TICK: + { + char buf[11]; + watch_display_text(WATCH_POSITION_TOP_RIGHT, " "); + watch_display_text_with_fallback(WATCH_POSITION_TOP, "W_THS", "TH"); + watch_display_float_with_best_effort(state->new_threshold * 0.125, " G"); + printf("%s\n", buf); + } + break; + case EVENT_ALARM_BUTTON_UP: + lis2dw_configure_wakeup_int1(state->threshold, false, true); + state->threshold = state->new_threshold; + state->is_setting = false; + break; + default: + movement_default_loop_handler(event); + break; + } + } else { + switch (event.event_type) { + case EVENT_LIGHT_BUTTON_DOWN: + movement_illuminate_led(); + + // if stopped, reset the count + if (!state->running) { + state->count = 0; + } + _accel_interrupt_count_face_update_display(state); + break; + case EVENT_ALARM_BUTTON_UP: + if (state->running) { + state->running = false; + watch_register_interrupt_callback(HAL_GPIO_A4_pin(), NULL, INTERRUPT_TRIGGER_RISING); + } else { + state->running = true; + watch_register_interrupt_callback(HAL_GPIO_A4_pin(), accel_interrupt_handler, INTERRUPT_TRIGGER_RISING); + } + _accel_interrupt_count_face_update_display(state); + break; + case EVENT_ACTIVATE: + case EVENT_TICK: + _accel_interrupt_count_face_update_display(state); + break; + case EVENT_ALARM_LONG_PRESS: + if (!state->running) { + state->new_threshold = state->threshold; + state->is_setting = true; + } + return false; + default: + movement_default_loop_handler(event); + break; + } + } + + return true; +} + +void accel_interrupt_count_face_resign(void *context) { + (void) context; +} + +movement_watch_face_advisory_t accel_interrupt_count_face_advise(void *context) { + (void) context; + movement_watch_face_advisory_t retval = { 0 }; + + return retval; +} diff --git a/watch-faces/demo/accel_interrupt_count_face.h b/watch-faces/demo/accel_interrupt_count_face.h new file mode 100644 index 0000000..29d5df1 --- /dev/null +++ b/watch-faces/demo/accel_interrupt_count_face.h @@ -0,0 +1,58 @@ +/* + * MIT License + * + * Copyright (c) 2022 Joey Castillo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +/* + * Accelerometer Interrupt Counter + * + * This is an experimental watch face for counting the number of interrupts that + * the Sensor Watch Motion acceleromoeter board fires. I expect it will be removed + * once we integrate accelerometer functionality more deeply into Movement. + */ + +#include "movement.h" +#include "watch.h" + +typedef struct { + uint32_t count; + uint8_t new_threshold; + uint8_t threshold; + bool running; + bool is_setting; +} accel_interrupt_count_state_t; + +void accel_interrupt_count_face_setup(uint8_t watch_face_index, void ** context_ptr); +void accel_interrupt_count_face_activate(void *context); +bool accel_interrupt_count_face_loop(movement_event_t event, void *context); +void accel_interrupt_count_face_resign(void *context); +movement_watch_face_advisory_t accel_interrupt_count_face_advise(void *context); + +#define accel_interrupt_count_face ((const watch_face_t){ \ + accel_interrupt_count_face_setup, \ + accel_interrupt_count_face_activate, \ + accel_interrupt_count_face_loop, \ + accel_interrupt_count_face_resign, \ + accel_interrupt_count_face_advise, \ +})