From fd5e8046d0b328578b209a8e51d53f62cbdfdd06 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 21 Sep 2021 15:49:02 -0400 Subject: support alternate LCD pinouts --- boards/OSO-MISC-21-013/pins.h | 36 ++++++++++++++++++++++++++++ watch-library/config/hpl_slcd_config.h | 44 +++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/boards/OSO-MISC-21-013/pins.h b/boards/OSO-MISC-21-013/pins.h index 66e4bdc2..a4e936a4 100644 --- a/boards/OSO-MISC-21-013/pins.h +++ b/boards/OSO-MISC-21-013/pins.h @@ -62,6 +62,42 @@ #define SLCD24 GPIO(GPIO_PORTA, 21) #define SLCD25 GPIO(GPIO_PORTA, 22) #define SLCD26 GPIO(GPIO_PORTA, 23) +// This board uses a slightly different pin mapping from the standard watch, and it's not enough to +// just declare the pins. We also have to set the LCD Pin Enable register with the SLCD pins we're +// using. These numbers are not port/pin numbers, but the "SLCD/LP[x]" numbers in the pinmux table. +// If not defined in pins.h, the LCD drover will fall back to the pin mapping in hpl_slcd_config.h. +// LPENL is for pins SLCD/LP[0..31]. +#define CONF_SLCD_LPENL (\ + (uint32_t)1 << 0 | \ + (uint32_t)1 << 1 | \ + (uint32_t)1 << 2 | \ + (uint32_t)1 << 3 | \ + (uint32_t)1 << 5 | \ + (uint32_t)1 << 6 | \ + (uint32_t)1 << 11 | \ + (uint32_t)1 << 12 | \ + (uint32_t)1 << 13 | \ + (uint32_t)1 << 14 | \ + (uint32_t)1 << 21 | \ + (uint32_t)1 << 22 | \ + (uint32_t)1 << 23 | \ + (uint32_t)1 << 24 | \ + (uint32_t)1 << 25 | \ + (uint32_t)1 << 30 | \ + (uint32_t)1 << 31 | 0) +// LPENH is for pins SLCD/LP[32..51], where bit 0 represents pin 32. +#define CONF_SLCD_LPENH (\ + (uint32_t)1 << (32 - 32) | \ + (uint32_t)1 << (33 - 32) | \ + (uint32_t)1 << (34 - 32) | \ + (uint32_t)1 << (35 - 32) | \ + (uint32_t)1 << (42 - 32) | \ + (uint32_t)1 << (43 - 32) | \ + (uint32_t)1 << (48 - 32) | \ + (uint32_t)1 << (49 - 32) | \ + (uint32_t)1 << (50 - 32) | \ + (uint32_t)1 << (51 - 32) | 0) + // 9-pin connector #define A0 GPIO(GPIO_PORTB, 4) diff --git a/watch-library/config/hpl_slcd_config.h b/watch-library/config/hpl_slcd_config.h index 72213432..5e3b2ca2 100644 --- a/watch-library/config/hpl_slcd_config.h +++ b/watch-library/config/hpl_slcd_config.h @@ -6,6 +6,7 @@ #include #include +#include "pins.h" // Standard configuration @@ -2729,15 +2730,40 @@ } \ } -#define CONF_SLCD_LPENL \ - ((uint32_t)1 << 0 | (uint32_t)1 << 1 | (uint32_t)1 << 2 | (uint32_t)1 << 3 | (uint32_t)1 << 4 | (uint32_t)1 << 5 \ - | (uint32_t)1 << 6 | (uint32_t)1 << 7 | (uint32_t)1 << 11 | (uint32_t)1 << 12 | (uint32_t)1 << 13 \ - | (uint32_t)1 << 14 | (uint32_t)1 << 21 | (uint32_t)1 << 22 | (uint32_t)1 << 23 | (uint32_t)1 << 24 \ - | (uint32_t)1 << 25 | (uint32_t)1 << 28 | (uint32_t)1 << 29 | (uint32_t)1 << 30 | (uint32_t)1 << 31 | 0) - -#define CONF_SLCD_LPENH \ - ((uint32_t)1 << 0 | (uint32_t)1 << 1 | (uint32_t)1 << 2 | (uint32_t)1 << 3 | (uint32_t)1 << 10 | (uint32_t)1 << 11 \ - | 0) // +#ifndef CONF_SLCD_LPENL +#define CONF_SLCD_LPENL (\ + (uint32_t)1 << 0 | \ + (uint32_t)1 << 1 | \ + (uint32_t)1 << 2 | \ + (uint32_t)1 << 3 | \ + (uint32_t)1 << 4 | \ + (uint32_t)1 << 5 | \ + (uint32_t)1 << 6 | \ + (uint32_t)1 << 7 | \ + (uint32_t)1 << 11 | \ + (uint32_t)1 << 12 | \ + (uint32_t)1 << 13 | \ + (uint32_t)1 << 14 | \ + (uint32_t)1 << 21 | \ + (uint32_t)1 << 22 | \ + (uint32_t)1 << 23 | \ + (uint32_t)1 << 24 | \ + (uint32_t)1 << 25 | \ + (uint32_t)1 << 28 | \ + (uint32_t)1 << 29 | \ + (uint32_t)1 << 30 | \ + (uint32_t)1 << 31 | 0) +#endif // CONF_SLCD_LPENL + +#ifndef CONF_SLCD_LPENH +#define CONF_SLCD_LPENH (\ + (uint32_t)1 << (32 - 32) | \ + (uint32_t)1 << (33 - 32) | \ + (uint32_t)1 << (34 - 32) | \ + (uint32_t)1 << (35 - 32) | \ + (uint32_t)1 << (42 - 32) | \ + (uint32_t)1 << (43 - 32) | 0) +#endif // CONF_SLCD_LPENH // <<< end of configuration section >>> -- cgit v1.2.3 From a23901f8433149ae1d29167f0b59e0df954e838f Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 23 Sep 2021 14:57:30 -0400 Subject: final deep sleep refactor: retain RAM, call it shallow sleep mode --- apps/Sensor Watch Starter Project/app.c | 35 ++++++++----------- watch-library/watch/watch_deepsleep.c | 49 +++++++++++++++++++++------ watch-library/watch/watch_deepsleep.h | 59 +++++++++++++++------------------ 3 files changed, 80 insertions(+), 63 deletions(-) diff --git a/apps/Sensor Watch Starter Project/app.c b/apps/Sensor Watch Starter Project/app.c index d2ddd6a6..5c3c77af 100644 --- a/apps/Sensor Watch Starter Project/app.c +++ b/apps/Sensor Watch Starter Project/app.c @@ -21,7 +21,7 @@ typedef struct ApplicationState { LightColor color; bool light_on; uint8_t wake_count; - bool enter_deep_sleep; + bool enter_sleep_mode; } ApplicationState; ApplicationState application_state; @@ -57,13 +57,7 @@ void app_init() { * @see watch_enter_deep_sleep() */ void app_wake_from_deep_sleep() { - // retrieve our application state from the backup registers - application_state.mode = (ApplicationMode)watch_get_backup_data(0); - application_state.color = (LightColor)watch_get_backup_data(1); - application_state.wake_count = (uint8_t)watch_get_backup_data(2) + 1; - - // wait a moment for the user's finger to be off the button - delay_ms(250); + // this app only supports shallow sleep mode. } /** @@ -151,22 +145,21 @@ bool app_loop() { break; } - if (application_state.enter_deep_sleep) { - application_state.enter_deep_sleep = false; - - // stash our application state in the backup registers - watch_store_backup_data((uint32_t)application_state.mode, 0); - watch_store_backup_data((uint32_t)application_state.color, 1); - watch_store_backup_data((uint32_t)application_state.wake_count, 2); - - // turn off the LED - watch_set_led_off(); - + if (application_state.enter_sleep_mode) { // wait a moment for the user's finger to be off the button delay_ms(250); // nap time :) - watch_enter_deep_sleep(NULL); + watch_enter_shallow_sleep(NULL); + + // we just woke up; wait a moment again for the user's finger to be off the button... + delay_ms(250); + + // and prevent ourselves from going right back to sleep. + application_state.enter_sleep_mode = false; + + // finally, after sleep, return false so that our app loop runs again and updates the display. + return false; } return true; @@ -191,5 +184,5 @@ void cb_mode_pressed() { } void cb_alarm_pressed() { - application_state.enter_deep_sleep = true; + application_state.enter_sleep_mode = true; } diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index e5494e79..89d66ee7 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -89,6 +89,34 @@ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool le _extwake_register_callback(&CALENDAR_0.device, extwake_callback); } +void watch_disable_extwake_interrupt(uint8_t pin) { + hri_rtc_tampctrl_reg_t config = hri_rtc_get_TAMPCTRL_reg(RTC, 0xFFFFFFFF); + + switch (pin) { + case A4: + a4_callback = NULL; + config &= ~(3 << RTC_TAMPCTRL_IN0ACT_Pos); + break; + case A2: + a2_callback = NULL; + config &= ~(3 << RTC_TAMPCTRL_IN1ACT_Pos); + break; + case BTN_ALARM: + btn_alarm_callback = NULL; + config &= ~(3 << RTC_TAMPCTRL_IN2ACT_Pos); + break; + default: + return; + } + + if (hri_rtcmode0_get_CTRLA_ENABLE_bit(RTC)) { + hri_rtcmode0_clear_CTRLA_ENABLE_bit(RTC); + hri_rtcmode0_wait_for_sync(RTC, RTC_MODE0_SYNCBUSY_ENABLE); + } + hri_rtc_write_TAMPCTRL_reg(RTC, config); + hri_rtcmode0_set_CTRLA_ENABLE_bit(RTC); +} + void watch_store_backup_data(uint32_t data, uint8_t reg) { if (reg < 8) { RTC->MODE0.BKUP[reg].reg = data; @@ -128,10 +156,7 @@ void _watch_disable_all_peripherals_except_slcd() { MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_SERCOM3; } -void watch_enter_deep_sleep(char *message) { - // configure the ALARM interrupt (the callback doesn't matter) - watch_register_extwake_callback(BTN_ALARM, NULL, true); - +void watch_enter_shallow_sleep(char *message) { if (message != NULL) { watch_display_string(" ", 0); watch_display_string(message, 0); @@ -152,16 +177,20 @@ void watch_enter_deep_sleep(char *message) { // disable all pins _watch_disable_all_pins_except_rtc(); - // turn off RAM completely. - PM->STDBYCFG.bit.BBIASHS = 3; - - // enter standby (4); we basically hang out here until an interrupt forces us to reset. + // enter standby (4); we basically hang out here until an interrupt wakes us. sleep(4); - NVIC_SystemReset(); + // and we awake! re-enable the brownout detector + SUPC->INTENSET.bit.BOD33DET = 1; + + // call app_setup so the app can re-enable everything we disabled. + app_setup(); + + // and call app_wake_from_sleep (since main won't have a chance to do it) + app_wake_from_sleep(); } -void watch_enter_backup_mode() { +void watch_enter_deep_sleep() { // this will not work on the current silicon revision, but I said in the documentation that we do it. // so let's do it! watch_register_extwake_callback(BTN_ALARM, NULL, true); diff --git a/watch-library/watch/watch_deepsleep.h b/watch-library/watch/watch_deepsleep.h index 3dadd663..1e118929 100644 --- a/watch-library/watch/watch_deepsleep.h +++ b/watch-library/watch/watch_deepsleep.h @@ -49,15 +49,14 @@ */ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level); -/** @brief Unregisters the interrupt on one of the EXTWAKE pins. This will prevent a value change on - * one of these pins from waking the device from deep sleep or BACKUP modes. +/** @brief Unregisters the RTC interrupt on one of the EXTWAKE pins. This will prevent a value change on + * one of these pins from waking the device from shallow and deep sleep modes. * @param pin Either pin BTN_ALARM, A2, or A4. If the pin is BTN_ALARM, this function DOES NOT disable * the internal pull down on that pin. */ -void watch_disable_extwake_interrupt(uint8_t pin, ext_irq_cb_t callback, bool level); +void watch_disable_extwake_interrupt(uint8_t pin); -/** @brief Stores data in one of the RTC's backup registers, which retain their data in the deep sleep - and backup modes. +/** @brief Stores data in one of the RTC's backup registers, which retain their data in deep sleep mode. * @param data An unsigned 32 bit integer with the data you wish to store. * @param reg A register from 0-7. */ @@ -69,33 +68,29 @@ void watch_store_backup_data(uint32_t data, uint8_t reg); */ uint32_t watch_get_backup_data(uint8_t reg); -/** @brief Enters a deep sleep mode by disabling RAM retention and all peripherals except the RTC and - * (optionally) the LCD. You can wake from this mode by pressing the ALARM button. - * @param message Either NULL, or a string representing a message to display while in deep sleep mode. The - * message will be displayed at position 0, so you should pad out the beginning of the string - * with spaces if you wish for the message to appear on line 2, i.e. " SLEEP". If this - * parameter is NULL, the screen will be blanked, and this function will disable the SLCD - * peripheral for additional power savings. (also note that while the message will replace any - * text on the display, this function will not clear any indicators you have set. This is by - * design, in case you wish to leave an indicator lit in sleep mode.) - * @details This deep sleep mode is not the lowest power mode available (see watch_enter_backup_mode), but - * it has the benefit of being able to wake with a press of the ALARM button, and provides an option - * for displaying a message to the user when asleep. The only way to wake from this mode is by - * pressing the ALARM button, or receiving an interrupt on pin A2 or A4 of the nine-pin connector. - * (An alarm interrupt would also work, but this has not yet been implemented.) This function enables - * the ALARM button interrupt for you, but if you wish to wake from the A2 or A4 RTC interrupt, you - * must configure them by calling watch_register_extwake_callback. Note however that your callback - * will not be called in this case. - * Power consumption in deep sleep mode varies a bit with the battery voltage and the temperature, - * but at 3 V and ~25° C you can eoughly estimate: - * * ~12µA current draw with the LCD controller on (message != NULL) - * * ~6.5µA current draw with the LCD controller off (message == NULL) - * @note With RAM powered off, your application state will be cleared as soon as you call this function, and - * when the user wakes up the watch, your app will effectively be waking from reset. Your app's @ref - * app_wake_from_deep_sleep function will be called to give your app a chance to restore any state that - * you stored using @ref watch_store_backup_data. +/** @brief Enters a shallow sleep mode by disabling all pins and peripherals except the RTC and (optionally) + * the LCD. You can wake from this mode by pressing the ALARM button, if you have an registered an + * external wake callback on the ALARM button. When your app wakes from this shallow sleep mode, your + * app_setup method will be called, since this function will have disabled things you set up. + * @param message Either NULL, or a string representing a message to display while in shallow sleep mode. If + * this parameter is NULL, the screen will be blanked out, and this function will disable the + * SLCD peripheral for additional power savings. If the message is non-NULL, it will replace + * any text on the screen, and will be displayed at position 0 (so you should pad out the beginning + * of the string with spaces if you wish for the message to appear on line 2, i.e. " SLEEP"). + * Also note that this function will NOT clear any indicator segments that you have set. This is + * by design, in case you wish to leave an indicator lit in sleep mode. + * @details This shallow sleep mode is not the lowest power mode available (see watch_enter_deep_sleep), but + * it has the benefit of retaining your application state and being able to wake from the ALARM button. + * It also provides an option for displaying a message to the user when asleep. Note that whether you + * want to wake from the ALARM button, the A2 RTC interrupt or the A4 interrupt, you must configure + * this by calling watch_register_extwake_callback first. + * + * Power consumption in shallow sleep mode varies a bit with the battery voltage and the temperature, + * but at 3 V and 25~30° C you can roughly estimate: + * * < 12µA current draw with the LCD controller on (message != NULL) + * * < 6µA current draw with the LCD controller off (message == NULL) */ -void watch_enter_deep_sleep(char *message); +void watch_enter_shallow_sleep(char *message); /** @brief Enters the SAM L22's lowest-power mode, BACKUP. * @details This function does some housekeeping before entering BACKUP mode. It first disables all @@ -113,5 +108,5 @@ void watch_enter_deep_sleep(char *message); * this function unless you have a device on the nine-pin connector with an external interrupt * on pin A2 or A4 (i.e. an accelerometer with an interrupt pin). */ -void watch_enter_backup_mode(); +void watch_enter_deep_sleep(); /// @} -- cgit v1.2.3 From 7945f4c4a33b5fdfffe1ab8305e57df091371fbb Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 23 Sep 2021 17:27:41 -0400 Subject: add warning about external wake on old board rev --- watch-library/watch/watch_deepsleep.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index 89d66ee7..dda428f5 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -22,6 +22,13 @@ * SOFTWARE. */ +// this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying, +// but i'd rather have it warn us at build-time than fail silently at run-time. +// besides, no one but me really has any of these boards anyway. +#warning This board revision does not support external wake on BTN_ALARM, so watch_register_extwake_callback will not work with it. Use watch_register_interrupt_callback instead. +#if BTN_ALARM != GPIO(GPIO_PORTA, 2) +#endif + static void extwake_callback(uint8_t reason); ext_irq_cb_t btn_alarm_callback; ext_irq_cb_t a2_callback; -- cgit v1.2.3 From 115c555c4c0eec6f8cef787335fcefddc4472d43 Mon Sep 17 00:00:00 2001 From: joeycastillo Date: Fri, 24 Sep 2021 17:05:18 -0400 Subject: this was an odd typo --- watch-library/watch/watch_deepsleep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index dda428f5..a69ba66c 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -25,8 +25,8 @@ // this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying, // but i'd rather have it warn us at build-time than fail silently at run-time. // besides, no one but me really has any of these boards anyway. -#warning This board revision does not support external wake on BTN_ALARM, so watch_register_extwake_callback will not work with it. Use watch_register_interrupt_callback instead. #if BTN_ALARM != GPIO(GPIO_PORTA, 2) +#warning This board revision does not support external wake on BTN_ALARM, so watch_register_extwake_callback will not work with it. Use watch_register_interrupt_callback instead. #endif static void extwake_callback(uint8_t reason); -- cgit v1.2.3 From b0703ec7778f8a7e4c9d6dd964b1773f3d59ce38 Mon Sep 17 00:00:00 2001 From: Wesley Ellis Date: Tue, 14 Sep 2021 18:52:15 -0400 Subject: Beats time app + watch Use BMP280 code as a base, but stripped down to bare bones. Then added a new 'mode' for the current Swatch Internet Time (aka beats) --- apps/beats-time/app.c | 269 ++++++++++++++++++++++++++++++++++++++++ apps/beats-time/make/.gitignore | 1 + apps/beats-time/make/Makefile | 24 ++++ 3 files changed, 294 insertions(+) create mode 100644 apps/beats-time/app.c create mode 100755 apps/beats-time/make/.gitignore create mode 100755 apps/beats-time/make/Makefile diff --git a/apps/beats-time/app.c b/apps/beats-time/app.c new file mode 100644 index 00000000..c694bc5e --- /dev/null +++ b/apps/beats-time/app.c @@ -0,0 +1,269 @@ +#include +#include +#include +#include "watch.h" + +const uint8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time + +typedef enum ApplicationMode { + MODE_CLOCK = 0, // Displays month, day and current time. + MODE_BEATS, + MODE_SET, // (ST) Set time and date + NUM_MODES // Last item in the enum, it's the number of cases. +} ApplicationMode; + + +typedef struct ApplicationState { + // Internal application state + ApplicationMode mode; // Current mode + bool mode_changed; // Lets us perform one-time setup for a given mode + uint16_t mode_ticks; // Timeout for the mode (returns to clock after timeout expires) + uint8_t light_ticks; // Timeout for the light + bool led_on; // Indicates that the LED is on + uint8_t page; // Tracks the current page in log, prefs or settings. +} ApplicationState; + +void do_clock_mode(); +void do_beats_mode(); +void do_set_time_mode(); +void set_time_mode_handle_primary_button(); +void set_time_mode_handle_secondary_button(); + +uint16_t clock2beats(uint16_t, uint16_t, uint16_t, int16_t); + +void cb_light_pressed(); +void cb_mode_pressed(); +void cb_alarm_pressed(); +void cb_tick(); + +ApplicationState application_state; +char buf[16] = {0}; + +/** + * @brief Zeroes out the application state struct. + */ +void app_init() { + memset(&application_state, 0, sizeof(application_state)); +} + +void app_wake_from_deep_sleep() { + // This app does not support deep sleep mode. +} + +void app_setup() { + struct calendar_date_time date_time; + watch_get_date_time(&date_time); + if (date_time.date.year < 2020) { + date_time.date.year = 2020; + watch_set_date_time(date_time); + } + + watch_enable_external_interrupts(); + watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING); + watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING); + watch_register_extwake_callback(BTN_ALARM, cb_alarm_pressed, true); + + watch_enable_buzzer(); + watch_enable_leds(); + watch_enable_display(); + + watch_register_tick_callback(cb_tick); +} + +void app_prepare_for_sleep() { +} + +void app_wake_from_sleep() { +} + +bool app_loop() { + // play a beep if the mode has changed in response to a user's press of the MODE button + if (application_state.mode_changed) { + // low note for nonzero case, high note for return to clock + watch_buzzer_play_note(application_state.mode ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100); + application_state.mode_changed = false; + } + + // If the user is not in clock mode and the mode timeout has expired, return them to clock mode + if (application_state.mode != MODE_CLOCK && application_state.mode_ticks == 0) { + application_state.mode = MODE_CLOCK; + application_state.mode_changed = true; + } + + // If the LED is off and should be on, turn it on + if (application_state.light_ticks > 0 && !application_state.led_on) { + watch_set_led_green(); + application_state.led_on = true; + } + + // if the LED is on and should be off, turn it off + if (application_state.led_on && application_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)) { + application_state.light_ticks = 3; + } else { + watch_set_led_off(); + application_state.led_on = false; + } + } + + switch (application_state.mode) { + case MODE_CLOCK: + do_clock_mode(); + break; + case MODE_BEATS: + do_beats_mode(); + break; + case MODE_SET: + do_set_time_mode(); + break; + case NUM_MODES: + // dummy case, just silences a warning + break; + } + + application_state.mode_changed = false; + + return true; +} + +void do_clock_mode() { + struct calendar_date_time date_time; + const char months[12][3] = {"JA", "FE", "MR", "AR", "MA", "JN", "JL", "AU", "SE", "OC", "NO", "dE"}; + + watch_get_date_time(&date_time); + watch_display_string((char *)months[date_time.date.month - 1], 0); + sprintf(buf, "%2d%2d%02d%02d", date_time.date.day, date_time.time.hour, date_time.time.min, date_time.time.sec); + watch_display_string(buf, 2); + watch_set_colon(); +} + +void do_beats_mode() { + watch_clear_colon(); + + struct calendar_date_time date_time; + + watch_get_date_time(&date_time); + + uint16_t beats = clock2beats(date_time.time.hour, date_time.time.min, date_time.time.sec, UTC_OFFSET); + sprintf(buf, "bt %04d ", beats); + + watch_display_string(buf, 0); +} + +uint16_t clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, int16_t utc_offset) { + uint32_t beats = seconds; + beats += 60 * minutes; + beats += (uint32_t)hours * 60 * 60; + beats += (utc_offset + 1) * 60 * 60; // offset from utc + 1 since beats in in UTC+1 + + beats /= 86.4; // convert to beats + beats %= 1000; // truncate to 3 digits for overflow + + return (uint16_t) beats; +} + +void do_set_time_mode() { + struct calendar_date_time date_time; + + watch_get_date_time(&date_time); + watch_display_string(" ", 0); + switch (application_state.page) { + case 0: // hour + sprintf(buf, "ST t%2d", date_time.time.hour); + break; + case 1: // minute + sprintf(buf, "ST t %02d", date_time.time.min); + break; + case 2: // second + sprintf(buf, "ST t %02d", date_time.time.sec); + break; + case 3: // year + sprintf(buf, "ST d%2d", date_time.date.year - 2000); + break; + case 4: // month + sprintf(buf, "ST d %02d", date_time.date.month); + break; + case 5: // day + sprintf(buf, "ST d %02d", date_time.date.day); + break; + } + watch_display_string(buf, 0); + watch_set_pixel(1, 12); // required for T in position 1 +} + +void set_time_mode_handle_primary_button() { + application_state.page++; + if (application_state.page == 6) application_state.page = 0; +} + +void set_time_mode_handle_secondary_button() { + struct calendar_date_time date_time; + watch_get_date_time(&date_time); + const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; + + switch (application_state.page) { + case 0: // hour + date_time.time.hour = (date_time.time.hour + 1) % 24; + break; + case 1: // minute + date_time.time.min = (date_time.time.min + 1) % 60; + break; + case 2: // second + date_time.time.sec = 0; + break; + case 3: // year + // only allow 2021-2030. fix this sometime next decade + date_time.date.year = ((date_time.date.year % 10) + 1) + 2020; + break; + case 4: // month + date_time.date.month = ((date_time.date.month + 1) % 12); + break; + case 5: // day + date_time.date.day = date_time.date.day + 1; + // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. + // and it should roll over. + if (date_time.date.day > days_in_month[date_time.date.month - 1]) { + date_time.date.day = 1; + } + break; + } + watch_set_date_time(date_time); +} + +void cb_mode_pressed() { + application_state.mode = (application_state.mode + 1) % NUM_MODES; + application_state.mode_changed = true; + application_state.mode_ticks = 300; + application_state.page = 0; +} + +void cb_light_pressed() { + switch (application_state.mode) { + case MODE_SET: + set_time_mode_handle_secondary_button(); + break; + default: + application_state.light_ticks = 3; + break; + } +} + +void cb_alarm_pressed() { + switch (application_state.mode) { + case MODE_SET: + set_time_mode_handle_primary_button(); + break; + default: + break; + } +} + +void cb_tick() { + if (application_state.light_ticks > 0) { + application_state.light_ticks--; + } + if (application_state.mode_ticks > 0) { + application_state.mode_ticks--; + } +} diff --git a/apps/beats-time/make/.gitignore b/apps/beats-time/make/.gitignore new file mode 100755 index 00000000..3722ac63 --- /dev/null +++ b/apps/beats-time/make/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/apps/beats-time/make/Makefile b/apps/beats-time/make/Makefile new file mode 100755 index 00000000..112d8e50 --- /dev/null +++ b/apps/beats-time/make/Makefile @@ -0,0 +1,24 @@ +# Leave this line at the top of the file; it has all the watch library sources and includes. +TOP = ../../.. +include $(TOP)/make.mk + +# If you add any other subdirectories with header files you wish to include, add them after ../ +# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. +# INCLUDES += \ +# -I../ \ +# -I../drivers/ \ +# -I../utils/ +INCLUDES += \ + -I../ \ + +# If you add any other source files you wish to compile, add them after ../app.c +# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. +# SRCS += \ +# ../app.c \ +# ../drivers/bmp280.c \ +# ../utils/temperature.c +SRCS += \ + ../app.c \ + +# Leave this line at the bottom of the file; it has all the targets for making your project. +include $(TOP)/rules.mk -- cgit v1.2.3 From a65dcf1ec8071878988d5aa0390c5be66ba52a11 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 27 Sep 2021 17:42:27 -0400 Subject: WIP: refactor RTC to use clock mode directly --- watch-library/hpl/rtc/hpl_rtc.c | 47 ----------- watch-library/hw/driver_init.c | 11 --- watch-library/hw/driver_init.h | 20 ----- watch-library/watch/watch_deepsleep.c | 36 +++----- watch-library/watch/watch_deepsleep.h | 5 ++ watch-library/watch/watch_private.c | 3 +- watch-library/watch/watch_rtc.c | 150 ++++++++++++++++++++++++++++++++-- watch-library/watch/watch_rtc.h | 74 +++++++++++++++-- 8 files changed, 226 insertions(+), 120 deletions(-) diff --git a/watch-library/hpl/rtc/hpl_rtc.c b/watch-library/hpl/rtc/hpl_rtc.c index e580fa78..429feff7 100644 --- a/watch-library/hpl/rtc/hpl_rtc.c +++ b/watch-library/hpl/rtc/hpl_rtc.c @@ -376,55 +376,8 @@ int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv return ERR_NONE; } -/** - * \brief RTC interrupt handler - * - * \param[in] dev The pointer to calendar device struct - */ -static void _rtc_interrupt_handler(struct calendar_dev *dev) -{ - /* Read and mask interrupt flag register */ - uint16_t interrupt_status = hri_rtcmode0_read_INTFLAG_reg(dev->hw); - uint16_t interrupt_enabled = hri_rtcmode0_read_INTEN_reg(dev->hw); - - if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) { - if (dev->callback_alarm != NULL) { - dev->callback_alarm(); - } - - /* Clear interrupt flag */ - hri_rtcmode0_clear_interrupt_CMP0_bit(dev->hw); - } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) { - if (dev->callback_tick != NULL) { - dev->callback_tick(); - } - - /* Clear interrupt flag */ - hri_rtcmode0_clear_interrupt_PER7_bit(dev->hw); - } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) { - uint8_t reason = hri_rtc_get_TAMPID_reg(dev->hw, 0x1F); - if (dev->callback_tamper != NULL) { - dev->callback_tamper(reason); - } - hri_rtc_write_TAMPID_reg(dev->hw, reason); - - /* Clear interrupt flag */ - hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw); - } -} -/** - * \brief Set calendar IRQ - */ void _calendar_set_irq(struct calendar_dev *const dev) { (void)dev; NVIC_SetPendingIRQ(RTC_IRQn); } - -/** - * \brief Rtc interrupt handler - */ -void RTC_Handler(void) -{ - _rtc_interrupt_handler(_rtc_dev); -} diff --git a/watch-library/hw/driver_init.c b/watch-library/hw/driver_init.c index 2cfdced7..09723bec 100644 --- a/watch-library/hw/driver_init.c +++ b/watch-library/hw/driver_init.c @@ -13,19 +13,8 @@ struct slcd_sync_descriptor SEGMENT_LCD_0; -struct calendar_descriptor CALENDAR_0; - struct i2c_m_sync_desc I2C_0; -void CALENDAR_0_CLOCK_init(void) { - hri_mclk_set_APBAMASK_RTC_bit(MCLK); -} - -void CALENDAR_0_init(void) { - CALENDAR_0_CLOCK_init(); - calendar_init(&CALENDAR_0, RTC); -} - void I2C_0_PORT_init(void) { gpio_set_pin_pull_mode(SDA, diff --git a/watch-library/hw/driver_init.h b/watch-library/hw/driver_init.h index 019a0b56..f56f8f9e 100644 --- a/watch-library/hw/driver_init.h +++ b/watch-library/hw/driver_init.h @@ -38,36 +38,16 @@ extern "C" { extern struct adc_sync_descriptor ADC_0; -extern struct calendar_descriptor CALENDAR_0; - extern struct i2c_m_sync_desc I2C_0; -extern struct pwm_descriptor PWM_0; - -extern struct pwm_descriptor PWM_1; extern struct slcd_sync_descriptor SEGMENT_LCD_0; -void ADC_0_PORT_init(void); -void ADC_0_CLOCK_init(void); -void ADC_0_init(void); - -void CALENDAR_0_CLOCK_init(void); -void CALENDAR_0_init(void); - void I2C_0_CLOCK_init(void); void I2C_0_init(void); void I2C_0_PORT_init(void); void delay_driver_init(void); -void PWM_0_PORT_init(void); -void PWM_0_CLOCK_init(void); -void PWM_0_init(void); - -void PWM_1_PORT_init(void); -void PWM_1_CLOCK_init(void); -void PWM_1_init(void); - void EXTERNAL_IRQ_0_init(void); void SEGMENT_LCD_0_init(void); diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index a69ba66c..4294b660 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -29,24 +29,9 @@ #warning This board revision does not support external wake on BTN_ALARM, so watch_register_extwake_callback will not work with it. Use watch_register_interrupt_callback instead. #endif -static void extwake_callback(uint8_t reason); -ext_irq_cb_t btn_alarm_callback; -ext_irq_cb_t a2_callback; -ext_irq_cb_t a4_callback; - - static void extwake_callback(uint8_t reason) { - if (reason & RTC_TAMPID_TAMPID2) { - if (btn_alarm_callback != NULL) btn_alarm_callback(); - } else if (reason & RTC_TAMPID_TAMPID1) { - if (a2_callback != NULL) a2_callback(); - } else if (reason & RTC_TAMPID_TAMPID0) { - if (a4_callback != NULL) a4_callback(); - } -} - void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level) { uint32_t pinmux; - hri_rtc_tampctrl_reg_t config = hri_rtc_get_TAMPCTRL_reg(RTC, 0xFFFFFFFF); + hri_rtc_tampctrl_reg_t config = RTC->MODE2.TAMPCTRL.reg; switch (pin) { case A4: @@ -84,16 +69,17 @@ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool le gpio_set_pin_function(pin, pinmux); // disable the RTC - if (hri_rtcmode0_get_CTRLA_ENABLE_bit(RTC)) { - hri_rtcmode0_clear_CTRLA_ENABLE_bit(RTC); - hri_rtcmode0_wait_for_sync(RTC, RTC_MODE0_SYNCBUSY_ENABLE); - } + RTC->MODE2.CTRLA.bit.ENABLE = 0; + while (RTC->MODE2.SYNCBUSY.bit.ENABLE); + // update the configuration - hri_rtc_write_TAMPCTRL_reg(RTC, config); + RTC->MODE2.TAMPCTRL.reg = config; // re-enable the RTC - hri_rtcmode0_set_CTRLA_ENABLE_bit(RTC); + RTC->MODE2.CTRLA.bit.ENABLE = 1; - _extwake_register_callback(&CALENDAR_0.device, extwake_callback); + NVIC_ClearPendingIRQ(RTC_IRQn); + NVIC_EnableIRQ(RTC_IRQn); + RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_TAMPER; } void watch_disable_extwake_interrupt(uint8_t pin) { @@ -176,7 +162,7 @@ void watch_enter_shallow_sleep(char *message) { _watch_disable_all_peripherals_except_slcd(); // disable tick interrupt - watch_register_tick_callback(NULL); + watch_disable_tick_callback(); // disable brownout detector interrupt, which could inadvertently wake us up. SUPC->INTENCLR.bit.BOD33DET = 1; @@ -202,7 +188,7 @@ void watch_enter_deep_sleep() { // so let's do it! watch_register_extwake_callback(BTN_ALARM, NULL, true); - watch_register_tick_callback(NULL); + watch_disable_tick_callback(); _watch_disable_all_peripherals_except_slcd(); slcd_sync_deinit(&SEGMENT_LCD_0); hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); diff --git a/watch-library/watch/watch_deepsleep.h b/watch-library/watch/watch_deepsleep.h index 1e118929..dc8724d9 100644 --- a/watch-library/watch/watch_deepsleep.h +++ b/watch-library/watch/watch_deepsleep.h @@ -23,6 +23,11 @@ */ ////< @file watch_deepsleep.h +// These are declared in watch_rtc.c. +extern ext_irq_cb_t btn_alarm_callback; +extern ext_irq_cb_t a2_callback; +extern ext_irq_cb_t a4_callback; + /** @addtogroup deepsleep Deep Sleep Control * @brief This section covers functions related to preparing for and entering BACKUP mode, the * deepest sleep mode available on the SAM L22 diff --git a/watch-library/watch/watch_private.c b/watch-library/watch/watch_private.c index bdf6b78a..dc70f4cb 100644 --- a/watch-library/watch/watch_private.c +++ b/watch-library/watch/watch_private.c @@ -56,8 +56,7 @@ void _watch_init() { SUPC->BOD33.bit.ENABLE = 1; // External wake depends on RTC; calendar is a required module. - CALENDAR_0_init(); - calendar_enable(&CALENDAR_0); + _watch_rtc_init(); // set up state btn_alarm_callback = NULL; diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c index 2d6d598f..3d2104f3 100644 --- a/watch-library/watch/watch_rtc.c +++ b/watch-library/watch/watch_rtc.c @@ -22,19 +22,153 @@ * SOFTWARE. */ - bool _watch_rtc_is_enabled() { - return RTC->MODE0.CTRLA.bit.ENABLE; +ext_irq_cb_t tick_callback; +ext_irq_cb_t alarm_callback; +ext_irq_cb_t btn_alarm_callback; +ext_irq_cb_t a2_callback; +ext_irq_cb_t a4_callback; + +bool _watch_rtc_is_enabled() { + return RTC->MODE2.CTRLA.bit.ENABLE; } -void watch_set_date_time(struct calendar_date_time date_time) { - calendar_set_date(&CALENDAR_0, &date_time.date); - calendar_set_time(&CALENDAR_0, &date_time.time); +void _sync_rtc() { + while (RTC->MODE2.SYNCBUSY.reg); } -void watch_get_date_time(struct calendar_date_time *date_time) { - calendar_get_date_time(&CALENDAR_0, date_time); +void _watch_rtc_init() { + MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC; + + if (_watch_rtc_is_enabled()) return; // don't reset the RTC if it's already set up. + + RTC->MODE2.CTRLA.bit.ENABLE = 0; + _sync_rtc(); + + RTC->MODE2.CTRLA.bit.SWRST = 1; + _sync_rtc(); + + RTC->MODE2.CTRLA.bit.MODE = RTC_MODE2_CTRLA_MODE_CLOCK_Val; + RTC->MODE2.CTRLA.bit.PRESCALER = RTC_MODE2_CTRLA_PRESCALER_DIV1024_Val; + RTC->MODE2.CTRLA.bit.CLOCKSYNC = 1; + RTC->MODE2.CTRLA.bit.ENABLE = 1; + _sync_rtc(); +} + +void watch_rtc_set_date_time(watch_date_time date_time) { + RTC_MODE2_CLOCK_Type val; + + val.bit.SECOND = date_time.second; + val.bit.MINUTE = date_time.minute; + val.bit.HOUR = date_time.hour; + val.bit.DAY = date_time.day; + val.bit.MONTH = date_time.month; + val.bit.YEAR = (uint8_t)(date_time.year - WATCH_RTC_REFERENCE_YEAR); + + RTC->MODE2.CLOCK.reg = val.reg; + _sync_rtc(); +} + +watch_date_time watch_rtc_get_date_time() { + watch_date_time retval; + + _sync_rtc(); + RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK; + + retval.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR; + retval.month = val.bit.MONTH; + retval.day = val.bit.DAY; + retval.hour = val.bit.HOUR; + retval.minute = val.bit.MINUTE; + retval.second = val.bit.SECOND; + + return retval; } void watch_register_tick_callback(ext_irq_cb_t callback) { - _prescaler_register_callback(&CALENDAR_0.device, callback); + tick_callback = callback; + NVIC_ClearPendingIRQ(RTC_IRQn); + NVIC_EnableIRQ(RTC_IRQn); + RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7; +} + +void watch_disable_tick_callback() { + RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_PER7; +} + +void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) { + RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND = alarm_time.second; + RTC->MODE2.Mode2Alarm[0].ALARM.bit.MINUTE = alarm_time.minute; + RTC->MODE2.Mode2Alarm[0].ALARM.bit.HOUR = alarm_time.hour; + RTC->MODE2.Mode2Alarm[0].ALARM.bit.DAY = alarm_time.day; + RTC->MODE2.Mode2Alarm[0].ALARM.bit.MONTH = alarm_time.month; + RTC->MODE2.Mode2Alarm[0].ALARM.bit.YEAR = (uint8_t)(alarm_time.year - WATCH_RTC_REFERENCE_YEAR); + RTC->MODE2.Mode2Alarm[0].MASK.reg = mask; + + RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; + alarm_callback = callback; + NVIC_ClearPendingIRQ(RTC_IRQn); + NVIC_EnableIRQ(RTC_IRQn); + RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; +} + +void watch_rtc_disable_alarm_callback() { + RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_ALARM0; +} + +void RTC_Handler(void) { + uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg; + uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg; + + if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) { + if (alarm_callback != NULL) { + alarm_callback(); + } + RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; + } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) { + if (tick_callback != NULL) { + tick_callback(); + } + RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_PER7; + } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) { + uint8_t reason = RTC->MODE2.TAMPID.reg; + if (reason & RTC_TAMPID_TAMPID2) { + if (btn_alarm_callback != NULL) btn_alarm_callback(); + } else if (reason & RTC_TAMPID_TAMPID1) { + if (a2_callback != NULL) a2_callback(); + } else if (reason & RTC_TAMPID_TAMPID0) { + if (a4_callback != NULL) a4_callback(); + } + RTC->MODE2.TAMPID.reg = reason; + RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_TAMPER; + } +} + +/////////////////////// +// Deprecated functions + +void watch_set_date_time(struct calendar_date_time date_time) { + RTC_MODE2_CLOCK_Type val; + + val.bit.SECOND = date_time.time.sec; + val.bit.MINUTE = date_time.time.min; + val.bit.HOUR = date_time.time.hour; + val.bit.DAY = date_time.date.day; + val.bit.MONTH = date_time.date.month; + val.bit.YEAR = (uint8_t)(date_time.date.year - WATCH_RTC_REFERENCE_YEAR); + + RTC->MODE2.CLOCK.reg = val.reg; + + _sync_rtc(); +} + +void watch_get_date_time(struct calendar_date_time *date_time) { + _sync_rtc(); + RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK; + + date_time->time.sec = val.bit.SECOND; + date_time->time.min = val.bit.MINUTE; + date_time->time.hour = val.bit.HOUR; + date_time->date.day = val.bit.DAY; + date_time->date.month = val.bit.MONTH; + date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR; } diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h index c685ac26..a71eab42 100644 --- a/watch-library/watch/watch_rtc.h +++ b/watch-library/watch/watch_rtc.h @@ -35,24 +35,84 @@ * to wake from STANDBY mode. */ /// @{ + +#define WATCH_RTC_REFERENCE_YEAR (2020) + +typedef struct watch_date_time { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} watch_date_time; + +typedef enum watch_rtc_alarm_match { + ALARM_MATCH_DISABLED = 0, + ALARM_MATCH_SS, + ALARM_MATCH_MMSS, + ALARM_MATCH_HHMMSS, +} watch_rtc_alarm_match; + /** @brief Called by main.c to check if the RTC is enabled. - * You may call this function, but outside of app_init, it sbould always return true. + * You may call this function, but outside of app_init, it should always return true. */ bool _watch_rtc_is_enabled(); +/** @brief Sets the date and time. + * @param date_time The time you wish to set. + * @note Internally, the SAM L22 stores the year as six bits representing a value from 0 to 63. It treats this + * as a year offset from a reference year, which must be a leap year. For now, this library uses 2020 as + * the reference year, so the range of valid values is 2020 to 2083. + */ +void watch_rtc_set_date_time(watch_date_time date_time); + +/** @brief Returns the system date and time in the provided struct. + * @return A watch_date_time with the current date and time. + */ +watch_date_time watch_rtc_get_date_time(); + +/** @brief Registers an alarm callback that will be called when the RTC time matches the target time, as masked + * by the provided mask. + * @param callback The function you wish to have called when the alarm fires. If this value is NULL, the alarm + * interrupt will still be enabled, but no callback function will be called. + * @param alarm_time The time that you wish to match. The date is currently ignored. + * @param mask One of the values in watch_rtc_alarm_match indicating which values to check. + * @details The alarm interrupt is a versatile tool for scheduling events in the future, especially since it can + * wake the device from both shallow and deep sleep modes. The key to its versatility is the mask + * parameter. Suppose we set an alarm for midnight, 00:00:00. + * * if mask is ALARM_MATCH_SS, the alarm will fire every minute when the clock ticks to seconds == 0. + * * with ALARM_MATCH_MMSS, the alarm will once an hour, at the top of each hour. + * * with ALARM_MATCH_HHMMSS, the alarm will fire at midnight every day. + * In theory the SAM L22's alarm function can match on days, months and even years, but I have not had + * success with this yet; as such, I am omitting these options for now. + */ +void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask); + +/** @brief Disables the alarm callback. + */ +void watch_rtc_disable_alarm_callback(); + +/** @brief Registers a "tick" callback that will be called once per second. + * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick + * interrupt will still be enabled, but no callback function will be called. + */ +void watch_register_tick_callback(ext_irq_cb_t callback); + +/** @brief Disables the tick callback. + */ +void watch_disable_tick_callback(); + /** @brief Sets the system date and time. * @param date_time A struct representing the date and time you wish to set. */ +__attribute__((deprecated("Use watch_rtc_set_date_time function instead"))) void watch_set_date_time(struct calendar_date_time date_time); /** @brief Returns the system date and time in the provided struct. - * @param date_time A pointer to a calendar_date_time struct. - It will be populated with the correct date and time on return. + * @param date_time A pointer to a calendar_date_time struct. It will have with the correct date and time on return. */ +__attribute__((deprecated("Use the watch_rtc_get_date_time function instead"))) void watch_get_date_time(struct calendar_date_time *date_time); -/** @brief Registers a "tick" callback that will be called once per second. - * @param callback The function you wish to have called when the clock ticks. - */ -void watch_register_tick_callback(ext_irq_cb_t callback); /// @} -- cgit v1.2.3 From b353e47506be60a067c54bb30dfabe413cc1a6d2 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 27 Sep 2021 17:51:52 -0400 Subject: remove unused ASF code --- make.mk | 7 - watch-library/hal/documentation/calendar.rst | 72 --- watch-library/hal/include/hal_calendar.h | 159 ------- watch-library/hal/include/hpl_calendar.h | 251 ----------- watch-library/hal/src/hal_calendar.c | 645 --------------------------- watch-library/hpl/rtc/hpl_rtc.c | 383 ---------------- watch-library/hpl/rtc/hpl_rtc_base.h | 52 --- watch-library/hw/driver_init.h | 1 - 8 files changed, 1570 deletions(-) delete mode 100644 watch-library/hal/documentation/calendar.rst delete mode 100644 watch-library/hal/include/hal_calendar.h delete mode 100644 watch-library/hal/src/hal_calendar.c delete mode 100644 watch-library/hpl/rtc/hpl_rtc.c delete mode 100644 watch-library/hpl/rtc/hpl_rtc_base.h diff --git a/make.mk b/make.mk index 461bef79..ae32f2da 100644 --- a/make.mk +++ b/make.mk @@ -31,8 +31,6 @@ LDFLAGS += -mcpu=cortex-m0plus -mthumb LDFLAGS += -Wl,--gc-sections LDFLAGS += -Wl,--script=$(TOP)//watch-library/linker/saml22j18.ld -# If you add any additional directories with headers, add them to this list, e.g. -# ../drivers/ INCLUDES += \ -I$(TOP)/tinyusb/src \ -I$(TOP)/boards/$(BOARD) \ @@ -54,7 +52,6 @@ INCLUDES += \ -I$(TOP)/watch-library/hpl/oscctrl/ \ -I$(TOP)/watch-library/hpl/pm/ \ -I$(TOP)/watch-library/hpl/port/ \ - -I$(TOP)/watch-library/hpl/rtc/ \ -I$(TOP)/watch-library/hpl/sercom/ \ -I$(TOP)/watch-library/hpl/slcd/ \ -I$(TOP)/watch-library/hpl/systick/ \ @@ -64,8 +61,6 @@ INCLUDES += \ -I$(TOP)/watch-library/watch/ \ -I$(TOP)/watch-library -# If you add any additional C files to your project, add them each to this list, e.g. -# ../drivers/st25dv.c SRCS += \ $(TOP)/tinyusb/src/tusb.c \ $(TOP)/tinyusb/src/common/tusb_fifo.c \ @@ -78,7 +73,6 @@ SRCS += \ $(TOP)/watch-library/hw/driver_init.c \ $(TOP)/watch-library/watch/watch.c \ $(TOP)/watch-library/hal/src/hal_atomic.c \ - $(TOP)/watch-library/hal/src/hal_calendar.c \ $(TOP)/watch-library/hal/src/hal_delay.c \ $(TOP)/watch-library/hal/src/hal_ext_irq.c \ $(TOP)/watch-library/hal/src/hal_gpio.c \ @@ -100,7 +94,6 @@ SRCS += \ $(TOP)/watch-library/hpl/osc32kctrl/hpl_osc32kctrl.c \ $(TOP)/watch-library/hpl/oscctrl/hpl_oscctrl.c \ $(TOP)/watch-library/hpl/pm/hpl_pm.c \ - $(TOP)/watch-library/hpl/rtc/hpl_rtc.c \ $(TOP)/watch-library/hpl/sercom/hpl_sercom.c \ $(TOP)/watch-library/hpl/slcd/hpl_slcd.c \ $(TOP)/watch-library/hpl/systick/hpl_systick.c \ diff --git a/watch-library/hal/documentation/calendar.rst b/watch-library/hal/documentation/calendar.rst deleted file mode 100644 index 8a3de6e8..00000000 --- a/watch-library/hal/documentation/calendar.rst +++ /dev/null @@ -1,72 +0,0 @@ -=============================== -The Calendar driver (bare-bone) -=============================== - -The Calendar driver provides means to set and get current date and time. -After enabling, an instance of the driver starts counting time from the base date with -the resolution of one second. The default base date is 00:00:00 1st of January 1970. -Only the base year of the base date can be changed via the driver API. - -The current date and time is kept internally in a relative form as the difference between -current date and time and the base date and time. This means that changing the base year changes -current date. - -The base date and time defines time "zero" or the earliest possible point in time that the calender driver can describe, -this means that current time and alarms can not be set to anything earlier than this time. - -The Calendar driver provides alarm functionality. -An alarm is a software trigger which fires on particular date and time with particular periodicity. -Upon firing the given callback function is called. - -An alarm can be in single-shot mode, firing only once at matching time; or in repeating mode, meaning that it will -reschedule a new alarm automatically based on repeating mode configuration. -In single-shot mode an alarm is removed from the alarm queue before its callback is called. It allows an application to -reuse the memory of expired alarm in the callback. - -An alarm can be triggered on the following events: match on second, minute, hour, day, month or year. -Matching on second means that the alarm is triggered when the value of seconds of the current time is equal to -the alarm's value of seconds. This means repeating alarm with match on seconds is triggered with the period of a minute. -Matching on minute means that the calendars minute and seconds values has to match the alarms, the rest of the date-time -value is ignored. In repeating mode this means a new alarm every hour. -The same logic is applied to match on hour, day, month and year. - -Each instance of the Calendar driver supports infinite amount of software alarms, only limited by the amount of RAM available. - -Features --------- -* Initialization and de-initialization -* Enabling and disabling -* Date and time operations -* Software alarms - -Applications ------------- -* A source of current date and time for an embedded system. -* Periodical functionality in low-power applications since the driver is designed to use 1Hz clock. -* Periodical function calls in case if it is more convenient to operate with absolute time. - -Dependencies ------------- -* This driver expects a counter to be increased by one every second to count date and time correctly. -* Each instance of the driver requires separate hardware timer. - -Concurrency ------------ -The Calendar driver is an interrupt driven driver.This means that the interrupt that triggers an alarm may occur during -the process of adding or removing an alarm via the driver's API. In such case the interrupt processing is postponed -until the alarm adding or removing is complete. - -The alarm queue is not protected from the access by interrupts not used by the driver. Due to this -it is not recommended to add or remove an alarm from such interrupts: in case if a higher priority interrupt supersedes -the driver's interrupt, adding or removing an alarm may cause unpredictable behavior of the driver. - -Limitations ------------ -* Only years divisible by 4 are deemed a leap year, this gives a correct result between the years 1901 to 2099. -* The driver is designed to work outside of an operating system environment, the software alarm queue is therefore processed in interrupt context which may delay execution of other interrupts. -* If there are a lot of frequently called interrupts with the priority higher than the driver's one, it may cause delay in alarm's triggering. -* Changing the base year or setting current date or time does not shift alarms' date and time accordingly or expires alarms. - -Knows issues and workarounds ----------------------------- -Not applicable diff --git a/watch-library/hal/include/hal_calendar.h b/watch-library/hal/include/hal_calendar.h deleted file mode 100644 index 26949a57..00000000 --- a/watch-library/hal/include/hal_calendar.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * \file - * - * \brief Generic CALENDAR functionality declaration. - * - * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. - * - * \asf_license_start - * - * \page License - * - * Subject to your compliance with these terms, you may use Microchip - * software and any derivatives exclusively with Microchip products. - * It is your responsibility to comply with third party license terms applicable - * to your use of third party software (including open source software) that - * may accompany Microchip software. - * - * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, - * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, - * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, - * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE - * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL - * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE - * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE - * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT - * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY - * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, - * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. - * - * \asf_license_stop - * - */ - -#ifndef _HAL_CALENDER_H_INCLUDED -#define _HAL_CALENDER_H_INCLUDED - -#include "hpl_calendar.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \addtogroup doc_driver_hal_calendar_async - * - *@{ - */ - -/** \brief Prototype of callback on alarm match - * \param calendar Pointer to the HAL Calendar instance. - */ -typedef void (*calendar_cb_alarm_t)(struct calendar_descriptor *const calendar); - -/** \brief Struct for alarm time - */ -struct calendar_alarm { - struct list_element elem; - struct _calendar_alarm cal_alarm; - calendar_cb_alarm_t callback; -}; - -/** \brief Initialize the Calendar HAL instance and hardware - * - * \param calendar Pointer to the HAL Calendar instance. - * \param hw Pointer to the hardware instance. - * \return Operation status of init - * \retval 0 Completed successfully. - */ -int32_t calendar_init(struct calendar_descriptor *const calendar, const void *hw); - -/** \brief Reset the Calendar HAL instance and hardware - * - * Reset Calendar instance to hardware defaults. - * - * \param calendar Pointer to the HAL Calendar instance. - * \return Operation status of reset. - * \retval 0 Completed successfully. - */ -int32_t calendar_deinit(struct calendar_descriptor *const calendar); - -/** \brief Enable the Calendar HAL instance and hardware - * - * \param calendar Pointer to the HAL Calendar instance. - * \return Operation status of init - * \retval 0 Completed successfully. - */ -int32_t calendar_enable(struct calendar_descriptor *const calendar); - -/** \brief Disable the Calendar HAL instance and hardware - * - * Disable Calendar instance to hardware defaults. - * - * \param calendar Pointer to the HAL Calendar instance. - * \return Operation status of reset. - * \retval 0 Completed successfully. - */ -int32_t calendar_disable(struct calendar_descriptor *const calendar); - -/** \brief Configure the base year for calendar HAL instance and hardware - * - * \param calendar Pointer to the HAL Calendar instance. - * \param p_base_year The desired base year. - * \retval 0 Completed successfully. - */ -int32_t calendar_set_baseyear(struct calendar_descriptor *const calendar, const uint32_t p_base_year); - -/** \brief Configure the time for calendar HAL instance and hardware - * - * \param calendar Pointer to the HAL Calendar instance. - * \param p_calendar_time Pointer to the time configuration. - * \retval 0 Completed successfully. - */ -int32_t calendar_set_time(struct calendar_descriptor *const calendar, struct calendar_time *const p_calendar_time); - -/** \brief Configure the date for calendar HAL instance and hardware - * - * \param calendar Pointer to the HAL Calendar instance. - * \param p_calendar_date Pointer to the date configuration. - * \return Operation status of time set. - * \retval 0 Completed successfully. - */ -int32_t calendar_set_date(struct calendar_descriptor *const calendar, struct calendar_date *const p_calendar_date); - -/** \brief Get the time for calendar HAL instance and hardware - * - * \param calendar Pointer to the HAL Calendar instance. - * \param date_time Pointer to the value that will be filled with the current time. - * \return Operation status of time retrieve. - * \retval 0 Completed successfully. - */ -int32_t calendar_get_date_time(struct calendar_descriptor *const calendar, struct calendar_date_time *const date_time); - -/** \brief Config the alarm time for calendar HAL instance and hardware - * - * Set the alarm time to calendar instance. If the callback is NULL, remove - * the alarm if the alarm is already added, otherwise, ignore the alarm. - * - * \param calendar Pointer to the HAL Calendar instance. - * \param alarm Pointer to the configuration. - * \param callback Pointer to the callback function. - * \return Operation status of alarm time set. - * \retval 0 Completed successfully. - */ -int32_t calendar_set_alarm(struct calendar_descriptor *const calendar, struct calendar_alarm *const alarm, - calendar_cb_alarm_t callback); - -/** \brief Retrieve the current driver version - * \return Current driver version. - */ -uint32_t calendar_get_version(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _HAL_CALENDER_H_INCLUDED */ diff --git a/watch-library/hal/include/hpl_calendar.h b/watch-library/hal/include/hpl_calendar.h index f94249b9..0dce40fd 100644 --- a/watch-library/hal/include/hpl_calendar.h +++ b/watch-library/hal/include/hpl_calendar.h @@ -33,68 +33,10 @@ #ifndef _HPL_CALENDER_H_INCLUDED #define _HPL_CALENDER_H_INCLUDED -#include -#include -#include "hpl_irq.h" - #ifdef __cplusplus extern "C" { #endif -/** - * \brief Calendar structure - * - * The Calendar structure forward declaration. - */ -struct calendar_dev; - -/** - * \brief Available mask options for alarms. - * - * Available mask options for alarms. - */ -enum calendar_alarm_option { - /** Alarm disabled. */ - CALENDAR_ALARM_MATCH_DISABLED = 0, - /** Alarm match on second. */ - CALENDAR_ALARM_MATCH_SEC, - /** Alarm match on second and minute. */ - CALENDAR_ALARM_MATCH_MIN, - /** Alarm match on second, minute, and hour. */ - CALENDAR_ALARM_MATCH_HOUR, - /** Alarm match on second, minute, hour, and day. */ - CALENDAR_ALARM_MATCH_DAY, - /** Alarm match on second, minute, hour, day, and month. */ - CALENDAR_ALARM_MATCH_MONTH, - /** Alarm match on second, minute, hour, day, month and year. */ - CALENDAR_ALARM_MATCH_YEAR -}; - -/** - * \brief Available mode for alarms. - */ -enum calendar_alarm_mode { ONESHOT = 1, REPEAT }; -/** - * \brief Prototype of callback on alarm match - */ -typedef void (*calendar_drv_cb_t)(); -typedef void (*calendar_drv_extwake_cb_t)(uint8_t reason); - -/** - * \brief Structure of Calendar instance - */ -struct calendar_dev { - /** Pointer to the hardware base */ - void *hw; - /** Alarm match callback */ - calendar_drv_cb_t callback_alarm; - /** Tamper callback */ - calendar_drv_extwake_cb_t callback_tamper; - /** Tick callback */ - calendar_drv_cb_t callback_tick; - /** IRQ struct */ - struct _irq_descriptor irq; -}; /** * \brief Time struct for calendar */ @@ -119,17 +61,6 @@ struct calendar_date { uint16_t year; }; -/** \brief Calendar driver struct - * - */ -struct calendar_descriptor { - struct calendar_dev device; - struct list_descriptor alarms; - /*base date/time = base_year/1/1/0/0/0(year/month/day/hour/min/sec)*/ - uint32_t base_year; - uint8_t flags; -}; - /** \brief Date&Time struct for calendar */ struct calendar_date_time { @@ -137,188 +68,6 @@ struct calendar_date_time { struct calendar_date date; }; -/** \brief struct for alarm time - */ -struct _calendar_alarm { - struct calendar_date_time datetime; - uint32_t timestamp; - enum calendar_alarm_option option; - enum calendar_alarm_mode mode; -}; - -/** \enum for tamper detection mode - */ -enum tamper_detection_mode { TAMPER_MODE_OFF = 0U, TAMPER_MODE_WAKE, TAMPER_MODE_CAPTURE, TAMPER_MODE_ACTL }; - -/** \enum for tamper detection mode - */ -enum tamper_id { TAMPID0 = 0U, TAMPID1, TAMPID2, TAMPID3, TAMPID4 }; -/** - * \brief Initialize Calendar instance - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_init(struct calendar_dev *const dev); - -/** - * \brief Deinitialize Calendar instance - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_deinit(struct calendar_dev *const dev); - -/** - * \brief Enable Calendar instance - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_enable(struct calendar_dev *const dev); - -/** - * \brief Disable Calendar instance - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_disable(struct calendar_dev *const dev); -/** - * \brief Set counter for calendar - * - * \param[in] dev The pointer to calendar device struct - * \param[in] counter The counter for set - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_set_counter(struct calendar_dev *const dev, const uint32_t counter); - -/** - * \brief Get counter for calendar - * - * \param[in] dev The pointer to calendar device struct - * - * \return return current counter value - */ -uint32_t _calendar_get_counter(struct calendar_dev *const dev); - -/** - * \brief Set compare value for calendar - * - * \param[in] dev The pointer to calendar device struct - * \param[in] comp The compare value for set - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_set_comp(struct calendar_dev *const dev, const uint32_t comp); - -/** - * \brief Get compare value for calendar - * - * \param[in] dev The pointer to calendar device struct - * - * \return return current compare value - */ -uint32_t _calendar_get_comp(struct calendar_dev *const dev); - -/** - * \brief Register callback for calendar alarm - * - * \param[in] dev The pointer to calendar device struct - * \param[in] callback The pointer to callback function - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback); - -/** - * \brief Set calendar IRQ - * - * \param[in] dev The pointer to calendar device struct - */ -void _calendar_set_irq(struct calendar_dev *const dev); - -/** - * \brief Register callback for 1Hz tick from prescaler - * - * \param[in] dev The pointer to calendar device struct - * \param[in] callback The pointer to callback function - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback); - -/** - * \brief Register callback for tamper detection - * - * \param[in] dev The pointer to calendar device struct - * \param[in] callback The pointer to callback function - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_extwake_cb_t callback); - -/** - * \brief Find tamper is detected on specified pin - * - * \param[in] dev The pointer to calendar device struct - * \param[in] enum Tamper ID number - * - * \return true on detection success and false on failure. - */ -bool _is_tamper_detected(struct calendar_dev *const dev, enum tamper_id tamper_id_pin); - -/** - * \brief brief Clear the Tamper ID flag - * - * \param[in] dev The pointer to calendar device struct - * \param[in] enum Tamper ID number - * - * \return ERR_NONE - */ -int32_t _tamper_clear_tampid_flag(struct calendar_dev *const dev, enum tamper_id tamper_id_pin); - -/** - * \brief Enable Debounce Asynchronous Feature - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _tamper_enable_debounce_asynchronous(struct calendar_dev *const dev); - -/** - * \brief Disable Tamper Debounce Asynchronous Feature - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _tamper_disable_debounce_asynchronous(struct calendar_dev *const dev); - -/** - * \brief Enable Tamper Debounce Majority Feature - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _tamper_enable_debounce_majority(struct calendar_dev *const dev); - -/** - * \brief Enable Tamper Debounce Majority Feature - * - * \param[in] dev The pointer to calendar device struct - * - * \return ERR_NONE on success, or an error code on failure. - */ -int32_t _tamper_disable_debounce_majority(struct calendar_dev *const dev); - #ifdef __cplusplus } #endif diff --git a/watch-library/hal/src/hal_calendar.c b/watch-library/hal/src/hal_calendar.c deleted file mode 100644 index 68cb7286..00000000 --- a/watch-library/hal/src/hal_calendar.c +++ /dev/null @@ -1,645 +0,0 @@ -/** - * \file - * - * \brief Generic CALENDAR functionality implementation. - * - * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. - * - * \asf_license_start - * - * \page License - * - * Subject to your compliance with these terms, you may use Microchip - * software and any derivatives exclusively with Microchip products. - * It is your responsibility to comply with third party license terms applicable - * to your use of third party software (including open source software) that - * may accompany Microchip software. - * - * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, - * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, - * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, - * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE - * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL - * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE - * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE - * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT - * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY - * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, - * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. - * - * \asf_license_stop - * - */ - -#include "hal_calendar.h" -#include -#include -#include - -#define CALENDAR_VERSION 0x00000001u -#define SECS_IN_LEAP_YEAR 31622400 -#define SECS_IN_NON_LEAP_YEAR 31536000 -#define SECS_IN_31DAYS 2678400 -#define SECS_IN_30DAYS 2592000 -#define SECS_IN_29DAYS 2505600 -#define SECS_IN_28DAYS 2419200 -#define SECS_IN_DAY 86400 -#define SECS_IN_HOUR 3600 -#define SECS_IN_MINUTE 60 -#define DEFAULT_BASE_YEAR 1970 - -#define SET_ALARM_BUSY 1 -#define PROCESS_ALARM_BUSY 2 - -/** \brief leap year check - * \retval false not leap year. - * \retval true leap year. - */ -static bool leap_year(uint16_t year) -{ - if (year & 3) { - return false; - } else { - return true; - } -} - -/** \brief calculate the seconds in specified year/month - * \retval 0 month error. - */ -static uint32_t get_secs_in_month(uint32_t year, uint8_t month) -{ - uint32_t sec_in_month = 0; - - if (leap_year(year)) { - switch (month) { - case 1: - case 3: - case 5: - case 7: - case 8: - case 10: - case 12: - sec_in_month = SECS_IN_31DAYS; - break; - case 2: - sec_in_month = SECS_IN_29DAYS; - break; - case 4: - case 6: - case 9: - case 11: - sec_in_month = SECS_IN_30DAYS; - break; - default: - break; - } - } else { - switch (month) { - case 1: - case 3: - case 5: - case 7: - case 8: - case 10: - case 12: - sec_in_month = SECS_IN_31DAYS; - break; - case 2: - sec_in_month = SECS_IN_28DAYS; - break; - case 4: - case 6: - case 9: - case 11: - sec_in_month = SECS_IN_30DAYS; - break; - default: - break; - } - } - - return sec_in_month; -} - -/** \brief convert timestamp to date/time - */ -static int32_t convert_timestamp_to_datetime(struct calendar_descriptor *const calendar, uint32_t ts, - struct calendar_date_time *dt) -{ - uint32_t tmp, sec_in_year, sec_in_month; - uint32_t tmp_year = calendar->base_year; - uint8_t tmp_month = 1; - uint8_t tmp_day = 1; - uint8_t tmp_hour = 0; - uint8_t tmp_minutes = 0; - - tmp = ts; - - /* Find year */ - while (true) { - sec_in_year = leap_year(tmp_year) ? SECS_IN_LEAP_YEAR : SECS_IN_NON_LEAP_YEAR; - - if (tmp >= sec_in_year) { - tmp -= sec_in_year; - tmp_year++; - } else { - break; - } - } - /* Find month of year */ - while (true) { - sec_in_month = get_secs_in_month(tmp_year, tmp_month); - - if (tmp >= sec_in_month) { - tmp -= sec_in_month; - tmp_month++; - } else { - break; - } - } - /* Find day of month */ - while (true) { - if (tmp >= SECS_IN_DAY) { - tmp -= SECS_IN_DAY; - tmp_day++; - } else { - break; - } - } - /* Find hour of day */ - while (true) { - if (tmp >= SECS_IN_HOUR) { - tmp -= SECS_IN_HOUR; - tmp_hour++; - } else { - break; - } - } - /* Find minute in hour */ - while (true) { - if (tmp >= SECS_IN_MINUTE) { - tmp -= SECS_IN_MINUTE; - tmp_minutes++; - } else { - break; - } - } - - dt->date.year = tmp_year; - dt->date.month = tmp_month; - dt->date.day = tmp_day; - dt->time.hour = tmp_hour; - dt->time.min = tmp_minutes; - dt->time.sec = tmp; - - return ERR_NONE; -} - -/** \brief convert date/time to timestamp - * \return timestamp - */ -static uint32_t convert_datetime_to_timestamp(struct calendar_descriptor *const calendar, struct calendar_date_time *dt) -{ - uint32_t tmp = 0; - uint32_t i = 0; - uint8_t year, month, day, hour, minutes, seconds; - - year = dt->date.year - calendar->base_year; - month = dt->date.month; - day = dt->date.day; - hour = dt->time.hour; - minutes = dt->time.min; - seconds = dt->time.sec; - - /* tot up year field */ - for (i = 0; i < year; ++i) { - if (leap_year(calendar->base_year + i)) { - tmp += SECS_IN_LEAP_YEAR; - } else { - tmp += SECS_IN_NON_LEAP_YEAR; - } - } - - /* tot up month field */ - for (i = 1; i < month; ++i) { - tmp += get_secs_in_month(dt->date.year, i); - } - - /* tot up day/hour/minute/second fields */ - tmp += (day - 1) * SECS_IN_DAY; - tmp += hour * SECS_IN_HOUR; - tmp += minutes * SECS_IN_MINUTE; - tmp += seconds; - - return tmp; -} - -/** \brief calibrate timestamp to make desired timestamp ahead of current timestamp - */ -static void calibrate_timestamp(struct calendar_descriptor *const calendar, struct calendar_alarm *alarm, - struct calendar_alarm *current_dt) -{ - uint32_t alarm_ts; - uint32_t current_ts = current_dt->cal_alarm.timestamp; - - (void)calendar; - - alarm_ts = alarm->cal_alarm.timestamp; - - /* calibrate timestamp */ - switch (alarm->cal_alarm.option) { - case CALENDAR_ALARM_MATCH_SEC: - - if (alarm_ts <= current_ts) { - alarm_ts += SECS_IN_MINUTE; - } - - break; - case CALENDAR_ALARM_MATCH_MIN: - - if (alarm_ts <= current_ts) { - alarm_ts += SECS_IN_HOUR; - } - - break; - case CALENDAR_ALARM_MATCH_HOUR: - - if (alarm_ts <= current_ts) { - alarm_ts += SECS_IN_DAY; - } - - break; - case CALENDAR_ALARM_MATCH_DAY: - - if (alarm_ts <= current_ts) { - alarm_ts += get_secs_in_month(current_dt->cal_alarm.datetime.date.year, - current_dt->cal_alarm.datetime.date.month); - } - - break; - case CALENDAR_ALARM_MATCH_MONTH: - - if (alarm_ts <= current_ts) { - if (leap_year(current_dt->cal_alarm.datetime.date.year)) { - alarm_ts += SECS_IN_LEAP_YEAR; - } else { - alarm_ts += SECS_IN_NON_LEAP_YEAR; - } - } - - break; - /* do nothing for year match */ - case CALENDAR_ALARM_MATCH_YEAR: - default: - break; - } - - /* desired timestamp after calibration */ - alarm->cal_alarm.timestamp = alarm_ts; -} - -/** \brief complete alarm to absolute date/time, then fill up the timestamp - */ -static void fill_alarm(struct calendar_descriptor *const calendar, struct calendar_alarm *alarm) -{ - struct calendar_alarm current_dt; - uint32_t tmp, current_ts; - - /* get current date/time */ - current_ts = _calendar_get_counter(&calendar->device); - convert_timestamp_to_datetime(calendar, current_ts, ¤t_dt.cal_alarm.datetime); - - current_dt.cal_alarm.timestamp = current_ts; - - /* complete alarm */ - switch (alarm->cal_alarm.option) { - case CALENDAR_ALARM_MATCH_SEC: - alarm->cal_alarm.datetime.date.year = current_dt.cal_alarm.datetime.date.year; - alarm->cal_alarm.datetime.date.month = current_dt.cal_alarm.datetime.date.month; - alarm->cal_alarm.datetime.date.day = current_dt.cal_alarm.datetime.date.day; - alarm->cal_alarm.datetime.time.hour = current_dt.cal_alarm.datetime.time.hour; - alarm->cal_alarm.datetime.time.min = current_dt.cal_alarm.datetime.time.min; - break; - case CALENDAR_ALARM_MATCH_MIN: - alarm->cal_alarm.datetime.date.year = current_dt.cal_alarm.datetime.date.year; - alarm->cal_alarm.datetime.date.month = current_dt.cal_alarm.datetime.date.month; - alarm->cal_alarm.datetime.date.day = current_dt.cal_alarm.datetime.date.day; - alarm->cal_alarm.datetime.time.hour = current_dt.cal_alarm.datetime.time.hour; - break; - case CALENDAR_ALARM_MATCH_HOUR: - alarm->cal_alarm.datetime.date.year = current_dt.cal_alarm.datetime.date.year; - alarm->cal_alarm.datetime.date.month = current_dt.cal_alarm.datetime.date.month; - alarm->cal_alarm.datetime.date.day = current_dt.cal_alarm.datetime.date.day; - break; - case CALENDAR_ALARM_MATCH_DAY: - alarm->cal_alarm.datetime.date.year = current_dt.cal_alarm.datetime.date.year; - alarm->cal_alarm.datetime.date.month = current_dt.cal_alarm.datetime.date.month; - break; - case CALENDAR_ALARM_MATCH_MONTH: - alarm->cal_alarm.datetime.date.year = current_dt.cal_alarm.datetime.date.year; - break; - case CALENDAR_ALARM_MATCH_YEAR: - break; - default: - break; - } - - /* fill up the timestamp */ - tmp = convert_datetime_to_timestamp(calendar, &alarm->cal_alarm.datetime); - alarm->cal_alarm.timestamp = tmp; - - /* calibrate the timestamp */ - calibrate_timestamp(calendar, alarm, ¤t_dt); - convert_timestamp_to_datetime(calendar, alarm->cal_alarm.timestamp, &alarm->cal_alarm.datetime); -} - -/** \brief add new alarm into the list in ascending order - */ -static int32_t calendar_add_new_alarm(struct list_descriptor *list, struct calendar_alarm *alarm) -{ - struct calendar_descriptor *calendar = CONTAINER_OF(list, struct calendar_descriptor, alarms); - struct calendar_alarm * head, *it, *prev = NULL; - - /*get the head of alarms list*/ - head = (struct calendar_alarm *)list_get_head(list); - - /*if head is null, insert new alarm as head*/ - if (!head) { - list_insert_as_head(list, alarm); - _calendar_set_comp(&calendar->device, alarm->cal_alarm.timestamp); - return ERR_NONE; - } - - /*insert the new alarm in accending order, the head will be invoked firstly */ - for (it = head; it; it = (struct calendar_alarm *)list_get_next_element(it)) { - if (alarm->cal_alarm.timestamp <= it->cal_alarm.timestamp) { - break; - } - - prev = it; - } - - /*insert new alarm into the list */ - if (it == head) { - list_insert_as_head(list, alarm); - /*get the head and set it into register*/ - _calendar_set_comp(&calendar->device, alarm->cal_alarm.timestamp); - - } else { - list_insert_after(prev, alarm); - } - - return ERR_NONE; -} - -/** \brief callback for alarm - */ -static void calendar_alarm(struct calendar_dev *const dev) -{ - struct calendar_descriptor *calendar = CONTAINER_OF(dev, struct calendar_descriptor, device); - - struct calendar_alarm *head, *it, current_dt; - - if ((calendar->flags & SET_ALARM_BUSY) || (calendar->flags & PROCESS_ALARM_BUSY)) { - calendar->flags |= PROCESS_ALARM_BUSY; - return; - } - - /* get current timestamp */ - current_dt.cal_alarm.timestamp = _calendar_get_counter(dev); - - /* get the head */ - head = (struct calendar_alarm *)list_get_head(&calendar->alarms); - ASSERT(head); - - /* remove all alarms and invoke them*/ - for (it = head; it; it = (struct calendar_alarm *)list_get_head(&calendar->alarms)) { - /* check the timestamp with current timestamp*/ - if (it->cal_alarm.timestamp <= current_dt.cal_alarm.timestamp) { - list_remove_head(&calendar->alarms); - it->callback(calendar); - - if (it->cal_alarm.mode == REPEAT) { - calibrate_timestamp(calendar, it, ¤t_dt); - convert_timestamp_to_datetime(calendar, it->cal_alarm.timestamp, &it->cal_alarm.datetime); - calendar_add_new_alarm(&calendar->alarms, it); - } - } else { - break; - } - } - - /*if no alarm in the list, register null */ - if (!it) { - _calendar_register_callback(&calendar->device, NULL); - return; - } - - /*put the new head into register */ - _calendar_set_comp(&calendar->device, it->cal_alarm.timestamp); -} - -/** \brief Initialize Calendar - */ -int32_t calendar_init(struct calendar_descriptor *const calendar, const void *hw) -{ - int32_t ret = 0; - - /* Sanity check arguments */ - ASSERT(calendar); - - if (calendar->device.hw == hw) { - /* Already initialized with current configuration */ - return ERR_NONE; - } else if (calendar->device.hw != NULL) { - /* Initialized with another configuration */ - return ERR_ALREADY_INITIALIZED; - } - calendar->device.hw = (void *)hw; - ret = _calendar_init(&calendar->device); - calendar->base_year = DEFAULT_BASE_YEAR; - - return ret; -} - -/** \brief Reset the Calendar - */ -int32_t calendar_deinit(struct calendar_descriptor *const calendar) -{ - /* Sanity check arguments */ - ASSERT(calendar); - - if (calendar->device.hw == NULL) { - return ERR_NOT_INITIALIZED; - } - _calendar_deinit(&calendar->device); - calendar->device.hw = NULL; - - return ERR_NONE; -} - -/** \brief Enable the Calendar - */ -int32_t calendar_enable(struct calendar_descriptor *const calendar) -{ - /* Sanity check arguments */ - ASSERT(calendar); - - _calendar_enable(&calendar->device); - - return ERR_NONE; -} - -/** \brief Disable the Calendar - */ -int32_t calendar_disable(struct calendar_descriptor *const calendar) -{ - /* Sanity check arguments */ - ASSERT(calendar); - - _calendar_disable(&calendar->device); - - return ERR_NONE; -} - -/** \brief Set base year for calendar - */ -int32_t calendar_set_baseyear(struct calendar_descriptor *const calendar, const uint32_t p_base_year) -{ - /* Sanity check arguments */ - ASSERT(calendar); - - calendar->base_year = p_base_year; - - return ERR_NONE; -} - -/** \brief Set time for calendar - */ -int32_t calendar_set_time(struct calendar_descriptor *const calendar, struct calendar_time *const p_calendar_time) -{ - struct calendar_date_time dt; - uint32_t current_ts, new_ts; - - /* Sanity check arguments */ - ASSERT(calendar); - - /* convert time to timestamp */ - current_ts = _calendar_get_counter(&calendar->device); - convert_timestamp_to_datetime(calendar, current_ts, &dt); - dt.time.sec = p_calendar_time->sec; - dt.time.min = p_calendar_time->min; - dt.time.hour = p_calendar_time->hour; - - new_ts = convert_datetime_to_timestamp(calendar, &dt); - - _calendar_set_counter(&calendar->device, new_ts); - - return ERR_NONE; -} - -/** \brief Set date for calendar - */ -int32_t calendar_set_date(struct calendar_descriptor *const calendar, struct calendar_date *const p_calendar_date) -{ - struct calendar_date_time dt; - uint32_t current_ts, new_ts; - - /* Sanity check arguments */ - ASSERT(calendar); - - /* convert date to timestamp */ - current_ts = _calendar_get_counter(&calendar->device); - convert_timestamp_to_datetime(calendar, current_ts, &dt); - dt.date.day = p_calendar_date->day; - dt.date.month = p_calendar_date->month; - dt.date.year = p_calendar_date->year; - - new_ts = convert_datetime_to_timestamp(calendar, &dt); - - _calendar_set_counter(&calendar->device, new_ts); - - return ERR_NONE; -} - -/** \brief Get date/time for calendar - */ -int32_t calendar_get_date_time(struct calendar_descriptor *const calendar, struct calendar_date_time *const date_time) -{ - uint32_t current_ts; - - /* Sanity check arguments */ - ASSERT(calendar); - - /* convert current timestamp to date/time */ - current_ts = _calendar_get_counter(&calendar->device); - convert_timestamp_to_datetime(calendar, current_ts, date_time); - - return ERR_NONE; -} - -/** \brief Set alarm for calendar - */ -int32_t calendar_set_alarm(struct calendar_descriptor *const calendar, struct calendar_alarm *const alarm, - calendar_cb_alarm_t callback) -{ - struct calendar_alarm *head; - - /* Sanity check arguments */ - ASSERT(calendar); - ASSERT(alarm); - - alarm->callback = callback; - - fill_alarm(calendar, alarm); - - calendar->flags |= SET_ALARM_BUSY; - - head = (struct calendar_alarm *)list_get_head(&calendar->alarms); - - if (head != NULL) { - /* already added */ - if (is_list_element(&calendar->alarms, alarm)) { - if (callback == NULL) { - /* remove alarm */ - list_delete_element(&calendar->alarms, alarm); - - if (!list_get_head(&calendar->alarms)) { - _calendar_register_callback(&calendar->device, NULL); - } - } else { - /* re-add */ - list_delete_element(&calendar->alarms, alarm); - calendar_add_new_alarm(&calendar->alarms, alarm); - } - } else if (callback != NULL) { - calendar_add_new_alarm(&calendar->alarms, alarm); - } - - calendar->flags &= ~SET_ALARM_BUSY; - - if (calendar->flags & PROCESS_ALARM_BUSY) { - CRITICAL_SECTION_ENTER() - calendar->flags &= ~PROCESS_ALARM_BUSY; - _calendar_set_irq(&calendar->device); - CRITICAL_SECTION_LEAVE() - } - } else if (callback != NULL) { - /* if head is NULL, Register callback*/ - _calendar_register_callback(&calendar->device, calendar_alarm); - calendar_add_new_alarm(&calendar->alarms, alarm); - } - - calendar->flags &= ~SET_ALARM_BUSY; - - return ERR_NONE; -} - -/** \brief Retrieve driver version - * \return Current driver version - */ -uint32_t calendar_get_version(void) -{ - return CALENDAR_VERSION; -} diff --git a/watch-library/hpl/rtc/hpl_rtc.c b/watch-library/hpl/rtc/hpl_rtc.c deleted file mode 100644 index 429feff7..00000000 --- a/watch-library/hpl/rtc/hpl_rtc.c +++ /dev/null @@ -1,383 +0,0 @@ - -/** - * \file - * - * \brief RTC Driver - * - * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. - * - * \asf_license_start - * - * \page License - * - * Subject to your compliance with these terms, you may use Microchip - * software and any derivatives exclusively with Microchip products. - * It is your responsibility to comply with third party license terms applicable - * to your use of third party software (including open source software) that - * may accompany Microchip software. - * - * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, - * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, - * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, - * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE - * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL - * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE - * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE - * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT - * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY - * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, - * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. - * - * \asf_license_stop - * - */ - -#include -#include -#include - -/*!< Pointer to hpl device */ -static struct calendar_dev *_rtc_dev = NULL; - -/** - * \brief Initializes the RTC module with given configurations. - */ -int32_t _calendar_init(struct calendar_dev *const dev) -{ - ASSERT(dev && dev->hw); - - _rtc_dev = dev; - - if (hri_rtcmode0_get_CTRLA_ENABLE_bit(dev->hw)) { -#if !CONF_RTC_INIT_RESET - return ERR_DENIED; -#else - hri_rtcmode0_clear_CTRLA_ENABLE_bit(dev->hw); - hri_rtcmode0_wait_for_sync(dev->hw, RTC_MODE0_SYNCBUSY_ENABLE); -#endif - } - hri_rtcmode0_set_CTRLA_SWRST_bit(dev->hw); - hri_rtcmode0_wait_for_sync(dev->hw, RTC_MODE0_SYNCBUSY_SWRST); - -#if CONF_RTC_EVENT_CONTROL_ENABLE == 1 - hri_rtcmode0_write_EVCTRL_reg( - dev->hw, - (CONF_RTC_PEREO0 << RTC_MODE0_EVCTRL_PEREO0_Pos) | (CONF_RTC_PEREO1 << RTC_MODE0_EVCTRL_PEREO1_Pos) - | (CONF_RTC_PEREO2 << RTC_MODE0_EVCTRL_PEREO2_Pos) | (CONF_RTC_PEREO3 << RTC_MODE0_EVCTRL_PEREO3_Pos) - | (CONF_RTC_PEREO4 << RTC_MODE0_EVCTRL_PEREO4_Pos) | (CONF_RTC_PEREO5 << RTC_MODE0_EVCTRL_PEREO5_Pos) - | (CONF_RTC_PEREO6 << RTC_MODE0_EVCTRL_PEREO6_Pos) | (CONF_RTC_PEREO7 << RTC_MODE0_EVCTRL_PEREO7_Pos) - | (CONF_RTC_COMPE0 << RTC_MODE0_EVCTRL_CMPEO_Pos) | (CONF_RTC_OVFEO << RTC_MODE0_EVCTRL_OVFEO_Pos)); -#endif - - hri_rtcmode0_write_CTRLA_reg(dev->hw, RTC_MODE0_CTRLA_PRESCALER(CONF_RTC_PRESCALER) | RTC_MODE0_CTRLA_COUNTSYNC); - - hri_rtc_write_TAMPCTRL_reg( - dev->hw, - (CONF_RTC_TAMPER_INACT_0 << RTC_TAMPCTRL_IN0ACT_Pos) | (CONF_RTC_TAMPER_INACT_1 << RTC_TAMPCTRL_IN1ACT_Pos) - | (CONF_RTC_TAMPER_INACT_2 << RTC_TAMPCTRL_IN2ACT_Pos) - | (CONF_RTC_TAMPER_INACT_3 << RTC_TAMPCTRL_IN3ACT_Pos) - | (CONF_RTC_TAMPER_INACT_4 << RTC_TAMPCTRL_IN4ACT_Pos) | (CONF_RTC_TAMP_LVL_0 << RTC_TAMPCTRL_TAMLVL0_Pos) - | (CONF_RTC_TAMP_LVL_1 << RTC_TAMPCTRL_TAMLVL1_Pos) | (CONF_RTC_TAMP_LVL_2 << RTC_TAMPCTRL_TAMLVL2_Pos) - | (CONF_RTC_TAMP_LVL_3 << RTC_TAMPCTRL_TAMLVL3_Pos) | (CONF_RTC_TAMP_LVL_4 << RTC_TAMPCTRL_TAMLVL4_Pos) - | (CONF_RTC_TAMP_DEBNC_0 << RTC_TAMPCTRL_DEBNC0_Pos) | (CONF_RTC_TAMP_DEBNC_1 << RTC_TAMPCTRL_DEBNC1_Pos) - | (CONF_RTC_TAMP_DEBNC_2 << RTC_TAMPCTRL_DEBNC2_Pos) | (CONF_RTC_TAMP_DEBNC_3 << RTC_TAMPCTRL_DEBNC3_Pos) - | (CONF_RTC_TAMP_DEBNC_4 << RTC_TAMPCTRL_DEBNC4_Pos)); - - if ((CONF_RTC_TAMPER_INACT_0 == TAMPER_MODE_ACTL) | (CONF_RTC_TAMPER_INACT_1 == TAMPER_MODE_ACTL) - | (CONF_RTC_TAMPER_INACT_2 == TAMPER_MODE_ACTL) | (CONF_RTC_TAMPER_INACT_3 == TAMPER_MODE_ACTL) - | (CONF_RTC_TAMPER_INACT_4 == TAMPER_MODE_ACTL)) { - hri_rtcmode0_set_CTRLB_RTCOUT_bit(dev->hw); - } - return ERR_NONE; -} - -/** - * \brief Deinit the RTC module - */ -int32_t _calendar_deinit(struct calendar_dev *const dev) -{ - ASSERT(dev && dev->hw); - - NVIC_DisableIRQ(RTC_IRQn); - dev->callback_alarm = NULL; - dev->callback_tick = NULL; - dev->callback_tamper = NULL; - - hri_rtcmode0_clear_CTRLA_ENABLE_bit(dev->hw); - hri_rtcmode0_set_CTRLA_SWRST_bit(dev->hw); - - return ERR_NONE; -} - -/** - * \brief Enable the RTC module - */ -int32_t _calendar_enable(struct calendar_dev *const dev) -{ - ASSERT(dev && dev->hw); - - hri_rtcmode0_set_CTRLA_ENABLE_bit(dev->hw); - - return ERR_NONE; -} - -/** - * \brief Disable the RTC module - */ -int32_t _calendar_disable(struct calendar_dev *const dev) -{ - ASSERT(dev && dev->hw); - - hri_rtcmode0_clear_CTRLA_ENABLE_bit(dev->hw); - - return ERR_NONE; -} - -/** - * \brief Set the current calendar time to desired time. - */ -int32_t _calendar_set_counter(struct calendar_dev *const dev, const uint32_t counter) -{ - ASSERT(dev && dev->hw); - - hri_rtcmode0_write_COUNT_reg(dev->hw, counter); - - return ERR_NONE; -} - -/** - * \brief Get current counter - */ -uint32_t _calendar_get_counter(struct calendar_dev *const dev) -{ - ASSERT(dev && dev->hw); - - return hri_rtcmode0_read_COUNT_reg(dev->hw); -} - -/** - * \brief Set the compare for the specified value. - */ -int32_t _calendar_set_comp(struct calendar_dev *const dev, const uint32_t comp) -{ - ASSERT(dev && dev->hw); - - hri_rtcmode0_write_COMP_reg(dev->hw, 0, comp); - - return ERR_NONE; -} - -/** - * \brief Get the compare value - */ -uint32_t _calendar_get_comp(struct calendar_dev *const dev) -{ - ASSERT(dev && dev->hw); - - return hri_rtcmode0_read_COMP_reg(dev->hw, 0); -} - -/** - * \brief Find tamper is detected on specified pin - */ -bool _is_tamper_detected(struct calendar_dev *const dev, enum tamper_id tamper_id_pin) -{ - bool value; - - ASSERT(dev && dev->hw); - - value = ((hri_rtc_read_TAMPID_reg(dev->hw) >> tamper_id_pin) & 0x01); - return value; -} - -/** - * \brief Clear the Tamper ID flag - */ -int32_t _tamper_clear_tampid_flag(struct calendar_dev *const dev, enum tamper_id tamper_id_pin) -{ - ASSERT(dev && dev->hw); - - hri_rtc_write_TAMPID_reg(dev->hw, (true << tamper_id_pin)); - - return ERR_NONE; -} - -/** - * \brief Enable Tamper Debounce Asynchronous Feature - */ -int32_t _tamper_enable_debounce_asynchronous(struct calendar_dev *const dev) -{ - int32_t return_value; - - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, false); - - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - - if (hri_rtcmode0_read_CTRLA_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - return_value = ERR_FAILURE; - } else { - hri_rtcmode0_write_CTRLB_DEBASYNC_bit(dev->hw, true); - return_value = ERR_NONE; - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, true); - } - - return return_value; -} - -/** - * \brief Disable Tamper Debounce Asynchronous Feature - */ -int32_t _tamper_disable_debounce_asynchronous(struct calendar_dev *const dev) -{ - int32_t return_value; - - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, false); - - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - - if (hri_rtcmode0_read_CTRLA_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - return_value = ERR_FAILURE; - } else { - hri_rtcmode0_write_CTRLB_DEBASYNC_bit(dev->hw, false); - return_value = ERR_NONE; - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, true); - } - - return return_value; -} - -/** - * \brief Enable Tamper Debounce Majority Feature - */ -int32_t _tamper_enable_debounce_majority(struct calendar_dev *const dev) -{ - int32_t return_value; - - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, false); - - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - - if (hri_rtcmode0_read_CTRLA_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - return_value = ERR_FAILURE; - } else { - hri_rtcmode0_write_CTRLB_DEBMAJ_bit(dev->hw, true); - return_value = ERR_NONE; - - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, true); - } - - return return_value; -} - -/** - * \brief Disable Tamper Debounce Majority Feature - */ -int32_t _tamper_disable_debounce_majority(struct calendar_dev *const dev) -{ - int32_t return_value; - - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, false); - - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - - if (hri_rtcmode0_read_CTRLA_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - return_value = ERR_FAILURE; - } else { - hri_rtcmode0_write_CTRLB_DEBMAJ_bit(dev->hw, false); - return_value = ERR_NONE; - - while (hri_rtcmode0_read_SYNCBUSY_reg(dev->hw) & RTC_MODE2_CTRLA_ENABLE) { - } - hri_rtcmode0_write_CTRLA_ENABLE_bit(dev->hw, true); - } - - return return_value; -} - -int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback) -{ - ASSERT(dev && dev->hw); - - /* Check callback */ - if (callback != NULL) { - /* register the callback */ - dev->callback_tick = callback; - - /* enable RTC_IRQn */ - NVIC_ClearPendingIRQ(RTC_IRQn); - NVIC_EnableIRQ(RTC_IRQn); - - /* enable periodic interrupt */ - hri_rtcmode0_set_INTEN_PER7_bit(dev->hw); - } else { - /* disable periodic interrupt */ - hri_rtcmode0_clear_INTEN_PER7_bit(dev->hw); - } - - return ERR_NONE; -} - -int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_extwake_cb_t callback) -{ - ASSERT(dev && dev->hw); - - /* Check callback */ - if (callback != NULL) { - /* register the callback */ - dev->callback_tamper = callback; - - /* enable RTC_IRQn */ - NVIC_ClearPendingIRQ(RTC_IRQn); - NVIC_EnableIRQ(RTC_IRQn); - - hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw); - /* enable tamper interrupt */ - hri_rtcmode0_set_INTEN_TAMPER_bit(dev->hw); - } else { - /* disable tamper interrupt */ - hri_rtcmode0_clear_INTEN_TAMPER_bit(dev->hw); - } - - return ERR_NONE; -} -/** - * \brief Registers callback for the specified callback type - */ -int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback) -{ - ASSERT(dev && dev->hw); - - /* Check callback */ - if (callback != NULL) { - /* register the callback */ - dev->callback_alarm = callback; - - /* enable RTC_IRQn */ - NVIC_ClearPendingIRQ(RTC_IRQn); - NVIC_EnableIRQ(RTC_IRQn); - - /* enable cmp */ - hri_rtcmode0_set_INTEN_CMP0_bit(dev->hw); - } else { - /* disable cmp */ - hri_rtcmode0_clear_INTEN_CMP0_bit(dev->hw); - } - - return ERR_NONE; -} - -void _calendar_set_irq(struct calendar_dev *const dev) -{ - (void)dev; - NVIC_SetPendingIRQ(RTC_IRQn); -} diff --git a/watch-library/hpl/rtc/hpl_rtc_base.h b/watch-library/hpl/rtc/hpl_rtc_base.h deleted file mode 100644 index 06e3bd79..00000000 --- a/watch-library/hpl/rtc/hpl_rtc_base.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * \file - * - * \brief RTC - * - * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries. - * - * \asf_license_start - * - * \page License - * - * Subject to your compliance with these terms, you may use Microchip - * software and any derivatives exclusively with Microchip products. - * It is your responsibility to comply with third party license terms applicable - * to your use of third party software (including open source software) that - * may accompany Microchip software. - * - * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, - * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, - * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, - * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE - * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL - * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE - * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE - * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT - * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY - * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, - * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. - * - * \asf_license_stop - */ - -#ifndef _HPL_RTC2_V200_H_INCLUDED -#define _HPL_RTC2_V200_H_INCLUDED - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Retrieve timer helper functions - * - * \return A pointer to set of timer helper functions - */ -struct _timer_hpl_interface *_rtc_get_timer(void); - -#ifdef __cplusplus -} -#endif -#endif /* _HPL_RTC2_V200_H_INCLUDED */ diff --git a/watch-library/hw/driver_init.h b/watch-library/hw/driver_init.h index f56f8f9e..002f07aa 100644 --- a/watch-library/hw/driver_init.h +++ b/watch-library/hw/driver_init.h @@ -31,7 +31,6 @@ extern "C" { #include #include #include -#include #include #include #include -- cgit v1.2.3 From 152ba8aec6c4ab19a56822ddd7d77e999cb715ae Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 28 Sep 2021 11:06:27 -0400 Subject: simplification: return date/time in same format as clock register --- watch-library/watch/watch_rtc.c | 28 +++------------------------- watch-library/watch/watch_rtc.h | 32 +++++++++++++++++++------------- 2 files changed, 22 insertions(+), 38 deletions(-) diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c index 3d2104f3..43cff478 100644 --- a/watch-library/watch/watch_rtc.c +++ b/watch-library/watch/watch_rtc.c @@ -55,16 +55,7 @@ void _watch_rtc_init() { } void watch_rtc_set_date_time(watch_date_time date_time) { - RTC_MODE2_CLOCK_Type val; - - val.bit.SECOND = date_time.second; - val.bit.MINUTE = date_time.minute; - val.bit.HOUR = date_time.hour; - val.bit.DAY = date_time.day; - val.bit.MONTH = date_time.month; - val.bit.YEAR = (uint8_t)(date_time.year - WATCH_RTC_REFERENCE_YEAR); - - RTC->MODE2.CLOCK.reg = val.reg; + RTC->MODE2.CLOCK.reg = date_time.reg; _sync_rtc(); } @@ -72,14 +63,7 @@ watch_date_time watch_rtc_get_date_time() { watch_date_time retval; _sync_rtc(); - RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK; - - retval.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR; - retval.month = val.bit.MONTH; - retval.day = val.bit.DAY; - retval.hour = val.bit.HOUR; - retval.minute = val.bit.MINUTE; - retval.second = val.bit.SECOND; + retval.reg = RTC->MODE2.CLOCK.reg; return retval; } @@ -96,14 +80,8 @@ void watch_disable_tick_callback() { } void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) { - RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND = alarm_time.second; - RTC->MODE2.Mode2Alarm[0].ALARM.bit.MINUTE = alarm_time.minute; - RTC->MODE2.Mode2Alarm[0].ALARM.bit.HOUR = alarm_time.hour; - RTC->MODE2.Mode2Alarm[0].ALARM.bit.DAY = alarm_time.day; - RTC->MODE2.Mode2Alarm[0].ALARM.bit.MONTH = alarm_time.month; - RTC->MODE2.Mode2Alarm[0].ALARM.bit.YEAR = (uint8_t)(alarm_time.year - WATCH_RTC_REFERENCE_YEAR); + RTC->MODE2.Mode2Alarm[0].ALARM.reg = alarm_time.reg; RTC->MODE2.Mode2Alarm[0].MASK.reg = mask; - RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; alarm_callback = callback; NVIC_ClearPendingIRQ(RTC_IRQn); diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h index a71eab42..a2248758 100644 --- a/watch-library/watch/watch_rtc.h +++ b/watch-library/watch/watch_rtc.h @@ -38,13 +38,16 @@ #define WATCH_RTC_REFERENCE_YEAR (2020) -typedef struct watch_date_time { - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; +typedef union { + struct { + uint32_t second : 6; // 0-59 + uint32_t minute : 6; // 0-59 + uint32_t hour : 5; // 0-23 + uint32_t day : 5; // 1-31 + uint32_t month : 4; // 1-12 + uint32_t year : 6; // 0-63 (representing 2020-2083) + } unit; + uint32_t reg; // the bit-packed value as expected by the RTC peripheral's CLOCK register. } watch_date_time; typedef enum watch_rtc_alarm_match { @@ -60,15 +63,18 @@ typedef enum watch_rtc_alarm_match { bool _watch_rtc_is_enabled(); /** @brief Sets the date and time. - * @param date_time The time you wish to set. - * @note Internally, the SAM L22 stores the year as six bits representing a value from 0 to 63. It treats this - * as a year offset from a reference year, which must be a leap year. For now, this library uses 2020 as - * the reference year, so the range of valid values is 2020 to 2083. + * @param date_time The date and time you wish to set, with a year value from 0-63 representing 2020-2083. + * @note The SAM L22 stores the year as six bits representing a value from 0 to 63. It treats this as a year + * offset from a reference year, which must be a leap year. Since 2020 was a leap year, and it allows + * useful dates through 2083, it is assumed that watch apps will use 2020 as the reference year; thus + * 1 means 2021, 2 means 2022, etc. **You will be responsible for handling this offset in your code**, + * if the calendar year is needed for timestamp calculation logic or display purposes. */ void watch_rtc_set_date_time(watch_date_time date_time); -/** @brief Returns the system date and time in the provided struct. - * @return A watch_date_time with the current date and time. +/** @brief Returns the date and time. + * @return A watch_date_time with the current date and time, with a year value from 0-63 representing 2020-2083. + * @see watch_rtc_set_date_time for notes about how the year is stored. */ watch_date_time watch_rtc_get_date_time(); -- cgit v1.2.3 From 39a17c99b988086396388a942889c78b84ad6891 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 28 Sep 2021 13:42:08 -0400 Subject: overdue refactor: compile all watch modules separately --- make.mk | 11 +++++++++++ watch-library/hal/include/hal_calendar.h | 0 watch-library/hal/src/hal_calendar.c | 0 watch-library/watch/watch.c | 12 ------------ watch-library/watch/watch_adc.c | 2 ++ watch-library/watch/watch_adc.h | 5 +++++ watch-library/watch/watch_app.h | 3 +++ watch-library/watch/watch_buzzer.c | 2 ++ watch-library/watch/watch_buzzer.h | 5 +++++ watch-library/watch/watch_deepsleep.c | 2 ++ watch-library/watch/watch_deepsleep.h | 5 +++++ watch-library/watch/watch_extint.c | 2 ++ watch-library/watch/watch_extint.h | 4 ++++ watch-library/watch/watch_gpio.c | 2 ++ watch-library/watch/watch_gpio.h | 5 +++++ watch-library/watch/watch_i2c.c | 4 +++- watch-library/watch/watch_i2c.h | 5 +++++ watch-library/watch/watch_led.c | 2 ++ watch-library/watch/watch_led.h | 5 +++++ watch-library/watch/watch_private.c | 1 + watch-library/watch/watch_private.h | 8 ++++++++ watch-library/watch/watch_rtc.c | 2 ++ watch-library/watch/watch_rtc.h | 4 ++++ watch-library/watch/watch_slcd.c | 2 ++ watch-library/watch/watch_slcd.h | 5 +++++ watch-library/watch/watch_uart.c | 1 + watch-library/watch/watch_uart.h | 5 +++++ 27 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 watch-library/hal/include/hal_calendar.h create mode 100644 watch-library/hal/src/hal_calendar.c diff --git a/make.mk b/make.mk index ae32f2da..299d9d31 100644 --- a/make.mk +++ b/make.mk @@ -71,6 +71,17 @@ SRCS += \ $(TOP)/watch-library/main.c \ $(TOP)/watch-library/startup_saml22.c \ $(TOP)/watch-library/hw/driver_init.c \ + $(TOP)/watch-library/watch/watch_rtc.c \ + $(TOP)/watch-library/watch/watch_slcd.c \ + $(TOP)/watch-library/watch/watch_extint.c \ + $(TOP)/watch-library/watch/watch_led.c \ + $(TOP)/watch-library/watch/watch_buzzer.c \ + $(TOP)/watch-library/watch/watch_adc.c \ + $(TOP)/watch-library/watch/watch_gpio.c \ + $(TOP)/watch-library/watch/watch_i2c.c \ + $(TOP)/watch-library/watch/watch_uart.c \ + $(TOP)/watch-library/watch/watch_deepsleep.c \ + $(TOP)/watch-library/watch/watch_private.c \ $(TOP)/watch-library/watch/watch.c \ $(TOP)/watch-library/hal/src/hal_atomic.c \ $(TOP)/watch-library/hal/src/hal_delay.c \ diff --git a/watch-library/hal/include/hal_calendar.h b/watch-library/hal/include/hal_calendar.h new file mode 100644 index 00000000..e69de29b diff --git a/watch-library/hal/src/hal_calendar.c b/watch-library/hal/src/hal_calendar.c new file mode 100644 index 00000000..e69de29b diff --git a/watch-library/watch/watch.c b/watch-library/watch/watch.c index 6196b1f3..de7160c5 100644 --- a/watch-library/watch/watch.c +++ b/watch-library/watch/watch.c @@ -24,18 +24,6 @@ #include "watch.h" -#include "watch_rtc.c" -#include "watch_slcd.c" -#include "watch_extint.c" -#include "watch_led.c" -#include "watch_buzzer.c" -#include "watch_adc.c" -#include "watch_gpio.c" -#include "watch_i2c.c" -#include "watch_uart.c" -#include "watch_deepsleep.c" -#include "watch_private.c" - bool battery_is_low = false; // receives interrupts from MCLK, OSC32KCTRL, OSCCTRL, PAC, PM, SUPC and TAL, whatever that is. diff --git a/watch-library/watch/watch_adc.c b/watch-library/watch/watch_adc.c index 490a49b1..90980a88 100644 --- a/watch-library/watch/watch_adc.c +++ b/watch-library/watch/watch_adc.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_adc.h" + void _watch_sync_adc() { while (ADC->SYNCBUSY.reg); } diff --git a/watch-library/watch/watch_adc.h b/watch-library/watch/watch_adc.h index b49f1301..c9b6ad2a 100644 --- a/watch-library/watch/watch_adc.h +++ b/watch-library/watch/watch_adc.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_ADC_H_INCLUDED +#define _WATCH_ADC_H_INCLUDED ////< @file watch_adc.h +#include "watch.h" + /** @addtogroup adc Analog Input * @brief This section covers functions related to the SAM L22's analog-to-digital converter, * as well as configuring and reading values from the five analog-capable pins on the @@ -103,3 +107,4 @@ void watch_disable_analog_input(const uint8_t pin); void watch_disable_adc(); /// @} +#endif diff --git a/watch-library/watch/watch_app.h b/watch-library/watch/watch_app.h index fd7ea706..00a6a610 100644 --- a/watch-library/watch/watch_app.h +++ b/watch-library/watch/watch_app.h @@ -21,6 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_APP_H_INCLUDED +#define _WATCH_APP_H_INCLUDED ////< @file watch_app.h /** @addtogroup app Application Framework @@ -103,3 +105,4 @@ void app_prepare_for_sleep(); void app_wake_from_sleep(); /// @} +#endif diff --git a/watch-library/watch/watch_buzzer.c b/watch-library/watch/watch_buzzer.c index 9cb37393..007a44ca 100644 --- a/watch-library/watch/watch_buzzer.c +++ b/watch-library/watch/watch_buzzer.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_buzzer.h" + inline void watch_enable_buzzer() { if (!hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) { _watch_enable_tcc(); diff --git a/watch-library/watch/watch_buzzer.h b/watch-library/watch/watch_buzzer.h index 995e059a..e15657be 100644 --- a/watch-library/watch/watch_buzzer.h +++ b/watch-library/watch/watch_buzzer.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_BUZZER_H_INCLUDED +#define _WATCH_BUZZER_H_INCLUDED ////< @file watch_buzzer.h +#include "watch.h" + /** @addtogroup buzzer Buzzer * @brief This section covers functions related to the piezo buzzer embedded in the F-91W's back plate. */ @@ -157,3 +161,4 @@ void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms); extern const uint16_t NotePeriods[108]; /// @} +#endif diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index 4294b660..c83254e4 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_extint.h" + // this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying, // but i'd rather have it warn us at build-time than fail silently at run-time. // besides, no one but me really has any of these boards anyway. diff --git a/watch-library/watch/watch_deepsleep.h b/watch-library/watch/watch_deepsleep.h index dc8724d9..3dc428d0 100644 --- a/watch-library/watch/watch_deepsleep.h +++ b/watch-library/watch/watch_deepsleep.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_DEEPSLEEP_H_INCLUDED +#define _WATCH_DEEPSLEEP_H_INCLUDED ////< @file watch_deepsleep.h +#include "watch.h" + // These are declared in watch_rtc.c. extern ext_irq_cb_t btn_alarm_callback; extern ext_irq_cb_t a2_callback; @@ -115,3 +119,4 @@ void watch_enter_shallow_sleep(char *message); */ void watch_enter_deep_sleep(); /// @} +#endif diff --git a/watch-library/watch/watch_extint.c b/watch-library/watch/watch_extint.c index f2bad949..dcaa0d80 100644 --- a/watch-library/watch/watch_extint.c +++ b/watch-library/watch/watch_extint.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_extint.h" + void watch_enable_external_interrupts() { // Configure EIC to use GCLK3 (the 32.768 kHz crystal) hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); diff --git a/watch-library/watch/watch_extint.h b/watch-library/watch/watch_extint.h index 9c810534..758fe8bc 100644 --- a/watch-library/watch/watch_extint.h +++ b/watch-library/watch/watch_extint.h @@ -21,8 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_EXTINT_H_INCLUDED +#define _WATCH_EXTINT_H_INCLUDED ////< @file watch_extint.h +#include "watch.h" #include "hal_ext_irq.h" /** @addtogroup buttons Buttons & External Interrupts @@ -78,3 +81,4 @@ void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback); __attribute__((deprecated("Use watch_enable_external_interrupts instead"))) void watch_enable_buttons(); /// @} +#endif diff --git a/watch-library/watch/watch_gpio.c b/watch-library/watch/watch_gpio.c index a9bc139d..b37d009f 100644 --- a/watch-library/watch/watch_gpio.c +++ b/watch-library/watch/watch_gpio.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_gpio.h" + void watch_enable_digital_input(const uint8_t pin) { gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF); diff --git a/watch-library/watch/watch_gpio.h b/watch-library/watch/watch_gpio.h index 640686e0..fc43642c 100644 --- a/watch-library/watch/watch_gpio.h +++ b/watch-library/watch/watch_gpio.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_GPIO_H_INCLUDED +#define _WATCH_GPIO_H_INCLUDED ////< @file watch_gpio.h +#include "watch.h" + /** @addtogroup gpio Digital Input and Output * @brief This section covers functions related to general-purpose input and output signals. */ @@ -69,3 +73,4 @@ void watch_disable_digital_output(const uint8_t pin); */ void watch_set_pin_level(const uint8_t pin, const bool level); /// @} +#endif diff --git a/watch-library/watch/watch_i2c.c b/watch-library/watch/watch_i2c.c index 385d9d08..d2cf474b 100644 --- a/watch-library/watch/watch_i2c.c +++ b/watch-library/watch/watch_i2c.c @@ -22,7 +22,9 @@ * SOFTWARE. */ - struct io_descriptor *I2C_0_io; +#include "watch_i2c.h" + +struct io_descriptor *I2C_0_io; void watch_enable_i2c() { I2C_0_init(); diff --git a/watch-library/watch/watch_i2c.h b/watch-library/watch/watch_i2c.h index 7ac05c13..65df49b4 100644 --- a/watch-library/watch/watch_i2c.h +++ b/watch-library/watch/watch_i2c.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_I2C_H_INCLUDED +#define _WATCH_I2C_H_INCLUDED ////< @file watch_i2c.h +#include "watch.h" + /** @addtogroup i2c I2C Controller Driver * @brief This section covers functions related to the SAM L22's built-I2C driver, including * configuring the I2C bus, putting values directly on the bus and reading data from @@ -99,3 +103,4 @@ uint32_t watch_i2c_read24(int16_t addr, uint8_t reg); */ uint32_t watch_i2c_read32(int16_t addr, uint8_t reg); /// @} +#endif diff --git a/watch-library/watch/watch_led.c b/watch-library/watch/watch_led.c index 7b189452..1348c977 100644 --- a/watch-library/watch/watch_led.c +++ b/watch-library/watch/watch_led.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_led.h" + void watch_enable_leds() { if (!hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) { _watch_enable_tcc(); diff --git a/watch-library/watch/watch_led.h b/watch-library/watch/watch_led.h index 0927e716..2b9dead0 100644 --- a/watch-library/watch/watch_led.h +++ b/watch-library/watch/watch_led.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_LED_H_INCLUDED +#define _WATCH_LED_H_INCLUDED ////< @file watch_led.h +#include "watch.h" + /** @addtogroup led LED Control * @brief This section covers functions related to the bi-color red/green LED mounted behind the LCD. * @details The SAM L22 is an exceedingly power efficient chip, whereas the LED's are relatively power- @@ -86,3 +90,4 @@ void watch_enable_led(bool unused); __attribute__((deprecated("Use watch_disable_leds instead"))) void watch_disable_led(bool unused); /// @} +#endif diff --git a/watch-library/watch/watch_private.c b/watch-library/watch/watch_private.c index dc70f4cb..270208dc 100644 --- a/watch-library/watch/watch_private.c +++ b/watch-library/watch/watch_private.c @@ -22,6 +22,7 @@ * SOFTWARE. */ +#include "watch_private.h" #include "tusb.h" void _watch_init() { diff --git a/watch-library/watch/watch_private.h b/watch-library/watch/watch_private.h index abee085a..8045e438 100644 --- a/watch-library/watch/watch_private.h +++ b/watch-library/watch/watch_private.h @@ -21,10 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_PRIVATE_H_INCLUDED +#define _WATCH_PRIVATE_H_INCLUDED + +#include "watch.h" /// Called by main.c while setting up the app. You should not call this from your app. void _watch_init(); +/// Initializes the real-time clock peripheral. +void _watch_rtc_init(); + /// Called by buzzer and LED setup functions. You should not call this from your app. void _watch_enable_tcc(); @@ -33,3 +40,4 @@ void _watch_disable_tcc(); /// Called by main.c if plugged in to USB. You should not call this from your app. void _watch_enable_usb(); +#endif diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c index 43cff478..0974c796 100644 --- a/watch-library/watch/watch_rtc.c +++ b/watch-library/watch/watch_rtc.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_rtc.h" + ext_irq_cb_t tick_callback; ext_irq_cb_t alarm_callback; ext_irq_cb_t btn_alarm_callback; diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h index a2248758..71f555ab 100644 --- a/watch-library/watch/watch_rtc.h +++ b/watch-library/watch/watch_rtc.h @@ -21,8 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_RTC_H_INCLUDED +#define _WATCH_RTC_H_INCLUDED ////< @file watch_rtc.h +#include "watch.h" #include "hpl_calendar.h" /** @addtogroup rtc Real-Time Clock @@ -122,3 +125,4 @@ __attribute__((deprecated("Use the watch_rtc_get_date_time function instead"))) void watch_get_date_time(struct calendar_date_time *date_time); /// @} +#endif diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c index 7210713a..ba9d12b2 100644 --- a/watch-library/watch/watch_slcd.c +++ b/watch-library/watch/watch_slcd.c @@ -22,6 +22,8 @@ * SOFTWARE. */ +#include "watch_slcd.h" + ////////////////////////////////////////////////////////////////////////////////////////// // Segmented Display diff --git a/watch-library/watch/watch_slcd.h b/watch-library/watch/watch_slcd.h index efef99ac..4f5a617c 100644 --- a/watch-library/watch/watch_slcd.h +++ b/watch-library/watch/watch_slcd.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_SLCD_H_INCLUDED +#define _WATCH_SLCD_H_INCLUDED ////< @file watch_slcd.h +#include "watch.h" + /** @addtogroup slcd Segment LCD Display * @brief This section covers functions related to the Segment LCD display driver, which is responsible * for displaying strings of characters and indicators on the main watch display. @@ -100,3 +104,4 @@ void watch_clear_indicator(WatchIndicatorSegment indicator); void watch_clear_all_indicators(); /// @} +#endif diff --git a/watch-library/watch/watch_uart.c b/watch-library/watch/watch_uart.c index 3d97803d..d35533d0 100644 --- a/watch-library/watch/watch_uart.c +++ b/watch-library/watch/watch_uart.c @@ -50,6 +50,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "watch_uart.h" #include "peripheral_clk_config.h" void watch_enable_debug_uart(uint32_t baud) { diff --git a/watch-library/watch/watch_uart.h b/watch-library/watch/watch_uart.h index 3c4f7aef..3e98bd35 100644 --- a/watch-library/watch/watch_uart.h +++ b/watch-library/watch/watch_uart.h @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef _WATCH_UART_H_INCLUDED +#define _WATCH_UART_H_INCLUDED ////< @file watch_uart.h +#include "watch.h" + /** @addtogroup debug Debug UART * @brief This section covers functions related to the debug UART, available on * pin D1 of the 9-pin connector. @@ -51,3 +55,4 @@ void watch_debug_putc(char c); __attribute__((deprecated("Use printf to log debug messages over USB."))) void watch_debug_puts(char *s); /// @} +#endif -- cgit v1.2.3 From 9da9dfb7b2c7f43a9c45a46eca47b924396fd865 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 28 Sep 2021 15:13:09 -0400 Subject: rtc: support periodic ticks at intervals from 1 to 128 Hz --- watch-library/watch/watch_deepsleep.c | 4 +- watch-library/watch/watch_rtc.c | 71 +++++++++++++++++++++++++++-------- watch-library/watch/watch_rtc.h | 39 +++++++++++++++++-- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index c83254e4..1f3ae7fb 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -164,7 +164,7 @@ void watch_enter_shallow_sleep(char *message) { _watch_disable_all_peripherals_except_slcd(); // disable tick interrupt - watch_disable_tick_callback(); + watch_rtc_disable_all_tick_callbacks(); // disable brownout detector interrupt, which could inadvertently wake us up. SUPC->INTENCLR.bit.BOD33DET = 1; @@ -190,7 +190,7 @@ void watch_enter_deep_sleep() { // so let's do it! watch_register_extwake_callback(BTN_ALARM, NULL, true); - watch_disable_tick_callback(); + watch_rtc_disable_all_tick_callbacks(); _watch_disable_all_peripherals_except_slcd(); slcd_sync_deinit(&SEGMENT_LCD_0); hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c index 0974c796..519a1f00 100644 --- a/watch-library/watch/watch_rtc.c +++ b/watch-library/watch/watch_rtc.c @@ -24,7 +24,7 @@ #include "watch_rtc.h" -ext_irq_cb_t tick_callback; +ext_irq_cb_t tick_callbacks[8]; ext_irq_cb_t alarm_callback; ext_irq_cb_t btn_alarm_callback; ext_irq_cb_t a2_callback; @@ -70,15 +70,40 @@ watch_date_time watch_rtc_get_date_time() { return retval; } -void watch_register_tick_callback(ext_irq_cb_t callback) { - tick_callback = callback; +void watch_rtc_register_1Hz_callback(ext_irq_cb_t callback) { + watch_rtc_register_tick_callback(callback, 1); +} + +void watch_rtc_disable_1Hz_callback() { + watch_rtc_disable_tick_callback(1); +} + +void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period) { + // we told them, it has to be a power of 2. + if (__builtin_popcount(period) != 1) return; + + // this left-justifies the period in a 32-bit integer. + uint32_t tmp = period << 24; + // now we can count the leading zeroes to get the value we need. + // 0x01 (1 Hz) will have 7 leading zeros for PER7. 0xF0 (128 Hz) will have no leading zeroes for PER0. + uint8_t per_n = __builtin_clz(tmp); + + // this also maps nicely to an index for our list of tick callbacks. + tick_callbacks[per_n] = callback; + NVIC_ClearPendingIRQ(RTC_IRQn); NVIC_EnableIRQ(RTC_IRQn); - RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7; + RTC->MODE2.INTENSET.reg = 1 << per_n; +} + +void watch_rtc_disable_tick_callback(uint8_t period) { + if (__builtin_popcount(period) != 1) return; + uint8_t per_n = __builtin_clz(period << 24); + RTC->MODE2.INTENCLR.reg = 1 << per_n; } -void watch_disable_tick_callback() { - RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_PER7; +void watch_rtc_disable_all_tick_callbacks() { + RTC->MODE2.INTENCLR.reg = 0xFF; } void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) { @@ -99,17 +124,20 @@ void RTC_Handler(void) { uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg; uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg; - if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) { - if (alarm_callback != NULL) { - alarm_callback(); + if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER_Msk) { + // handle the tick callback first, it's what we do the most. + // start from PER7, the 1 Hz tick. + for(int8_t i = 7; i >= 0; i--) { + if ((interrupt_status & interrupt_enabled) & (1 << i)) { + if (tick_callbacks[i] != NULL) { + tick_callbacks[i](); + } + RTC->MODE2.INTFLAG.reg = 1 << i; + break; + } } - RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; - } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) { - if (tick_callback != NULL) { - tick_callback(); - } - RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_PER7; } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) { + // handle the extwake interrupts next. uint8_t reason = RTC->MODE2.TAMPID.reg; if (reason & RTC_TAMPID_TAMPID2) { if (btn_alarm_callback != NULL) btn_alarm_callback(); @@ -120,6 +148,12 @@ void RTC_Handler(void) { } RTC->MODE2.TAMPID.reg = reason; RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_TAMPER; + } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) { + // finally handle the alarm. + if (alarm_callback != NULL) { + alarm_callback(); + } + RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; } } @@ -152,3 +186,10 @@ void watch_get_date_time(struct calendar_date_time *date_time) { date_time->date.month = val.bit.MONTH; date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR; } + +void watch_register_tick_callback(ext_irq_cb_t callback) { + tick_callbacks[7] = callback; + NVIC_ClearPendingIRQ(RTC_IRQn); + NVIC_EnableIRQ(RTC_IRQn); + RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7; +} diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h index 71f555ab..f6b6329e 100644 --- a/watch-library/watch/watch_rtc.h +++ b/watch-library/watch/watch_rtc.h @@ -106,11 +106,37 @@ void watch_rtc_disable_alarm_callback(); * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick * interrupt will still be enabled, but no callback function will be called. */ -void watch_register_tick_callback(ext_irq_cb_t callback); +void watch_rtc_register_1Hz_callback(ext_irq_cb_t callback); + +/** @brief Disables the tick callback for the given period. + */ +void watch_rtc_disable_1Hz_callback(); + +/** @brief Registers a "tick" callback that will be called at a configurable period. + * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick + * interrupt will still be enabled, but no callback function will be called. + * @param period The frequency of the tick in Hz. **Must be a power of 2**, from 1 to 128 inclusive. + * @note A 1 Hz tick (@see watch_rtc_register_1Hz_callback) is suitable for most applications, in that it gives you a + * chance to update the display once a second — an ideal update rate for a watch! If however you are displaying + * a value (such as an accelerometer output) that updates more frequently than once per second, you may want to + * tick at 16 or 32 Hz to update the screen more quickly. Just remember that the more frequent the tick, the more + * power your app will consume. Ideally you should enable the fast tick only when the user requires it (i.e. in + * response to an input event), and move back to the slow tick after some time. + * + * Also note that the RTC peripheral does not have sub-second resolution, so even if you set a 2 or 4 Hz interval, + * the system will not have any way of telling you where you are within a given second; watch_rtc_get_date_time + * will return the exact same timestamp until the second ticks over. + */ +void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period); -/** @brief Disables the tick callback. +/** @brief Disables the tick callback for the given period. + * @param period The frequency of the tick you wish to disable, in Hz. **Must be a power of 2**, from 1 to 128. */ -void watch_disable_tick_callback(); +void watch_rtc_disable_tick_callback(uint8_t period); + +/** @brief Disables all tick callbacks. + */ +void watch_rtc_disable_all_tick_callbacks(); /** @brief Sets the system date and time. * @param date_time A struct representing the date and time you wish to set. @@ -124,5 +150,12 @@ void watch_set_date_time(struct calendar_date_time date_time); __attribute__((deprecated("Use the watch_rtc_get_date_time function instead"))) void watch_get_date_time(struct calendar_date_time *date_time); +/** @brief Registers a "tick" callback that will be called once per second. + * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick + * interrupt will still be enabled, but no callback function will be called. + */ +__attribute__((deprecated("Use the watch_rtc_register_1Hz_callback function instead"))) +void watch_register_tick_callback(ext_irq_cb_t callback); + /// @} #endif -- cgit v1.2.3 From 6334af0136a118c06b951dd041c5025aca5f1028 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 28 Sep 2021 19:18:42 -0400 Subject: tweak to API nomenclature: tick happens once a second, other interrupts are periodic --- watch-library/watch/watch_deepsleep.c | 4 ++-- watch-library/watch/watch_rtc.c | 22 +++++++++++----------- watch-library/watch/watch_rtc.h | 27 +++++++++++++++------------ 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index 1f3ae7fb..b7da82ee 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -164,7 +164,7 @@ void watch_enter_shallow_sleep(char *message) { _watch_disable_all_peripherals_except_slcd(); // disable tick interrupt - watch_rtc_disable_all_tick_callbacks(); + watch_rtc_disable_all_periodic_callbacks(); // disable brownout detector interrupt, which could inadvertently wake us up. SUPC->INTENCLR.bit.BOD33DET = 1; @@ -190,7 +190,7 @@ void watch_enter_deep_sleep() { // so let's do it! watch_register_extwake_callback(BTN_ALARM, NULL, true); - watch_rtc_disable_all_tick_callbacks(); + watch_rtc_disable_all_periodic_callbacks(); _watch_disable_all_peripherals_except_slcd(); slcd_sync_deinit(&SEGMENT_LCD_0); hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c index 519a1f00..a50da7c4 100644 --- a/watch-library/watch/watch_rtc.c +++ b/watch-library/watch/watch_rtc.c @@ -70,20 +70,20 @@ watch_date_time watch_rtc_get_date_time() { return retval; } -void watch_rtc_register_1Hz_callback(ext_irq_cb_t callback) { - watch_rtc_register_tick_callback(callback, 1); +void watch_rtc_register_tick_callback(ext_irq_cb_t callback) { + watch_rtc_register_periodic_callback(callback, 1); } -void watch_rtc_disable_1Hz_callback() { - watch_rtc_disable_tick_callback(1); +void watch_rtc_disable_tick_callback() { + watch_rtc_disable_periodic_callback(1); } -void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period) { +void watch_rtc_register_periodic_callback(ext_irq_cb_t callback, uint8_t frequency) { // we told them, it has to be a power of 2. - if (__builtin_popcount(period) != 1) return; + if (__builtin_popcount(frequency) != 1) return; // this left-justifies the period in a 32-bit integer. - uint32_t tmp = period << 24; + uint32_t tmp = frequency << 24; // now we can count the leading zeroes to get the value we need. // 0x01 (1 Hz) will have 7 leading zeros for PER7. 0xF0 (128 Hz) will have no leading zeroes for PER0. uint8_t per_n = __builtin_clz(tmp); @@ -96,13 +96,13 @@ void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period) { RTC->MODE2.INTENSET.reg = 1 << per_n; } -void watch_rtc_disable_tick_callback(uint8_t period) { - if (__builtin_popcount(period) != 1) return; - uint8_t per_n = __builtin_clz(period << 24); +void watch_rtc_disable_periodic_callback(uint8_t frequency) { + if (__builtin_popcount(frequency) != 1) return; + uint8_t per_n = __builtin_clz(frequency << 24); RTC->MODE2.INTENCLR.reg = 1 << per_n; } -void watch_rtc_disable_all_tick_callbacks() { +void watch_rtc_disable_all_periodic_callbacks() { RTC->MODE2.INTENCLR.reg = 0xFF; } diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h index f6b6329e..1776a712 100644 --- a/watch-library/watch/watch_rtc.h +++ b/watch-library/watch/watch_rtc.h @@ -105,18 +105,21 @@ void watch_rtc_disable_alarm_callback(); /** @brief Registers a "tick" callback that will be called once per second. * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick * interrupt will still be enabled, but no callback function will be called. + * @note this is equivalent to calling watch_rtc_register_periodic_callback with a frequency of 1. It can be + * disabled with either watch_rtc_disable_tick_callback() or watch_rtc_disable_periodic_callback(1), + * and will also be disabled when watch_rtc_disable_all_periodic_callbacks is called. */ -void watch_rtc_register_1Hz_callback(ext_irq_cb_t callback); +void watch_rtc_register_tick_callback(ext_irq_cb_t callback); /** @brief Disables the tick callback for the given period. */ -void watch_rtc_disable_1Hz_callback(); +void watch_rtc_disable_tick_callback(); -/** @brief Registers a "tick" callback that will be called at a configurable period. - * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick +/** @brief Registers a callback that will be called at a configurable period. + * @param callback The function you wish to have called at the specified period. If you pass in NULL, the periodic * interrupt will still be enabled, but no callback function will be called. - * @param period The frequency of the tick in Hz. **Must be a power of 2**, from 1 to 128 inclusive. - * @note A 1 Hz tick (@see watch_rtc_register_1Hz_callback) is suitable for most applications, in that it gives you a + * @param frequency The frequency of the tick in Hz. **Must be a power of 2**, from 1 to 128 inclusive. + * @note A 1 Hz tick (@see watch_rtc_register_tick_callback) is suitable for most applications, in that it gives you a * chance to update the display once a second — an ideal update rate for a watch! If however you are displaying * a value (such as an accelerometer output) that updates more frequently than once per second, you may want to * tick at 16 or 32 Hz to update the screen more quickly. Just remember that the more frequent the tick, the more @@ -127,16 +130,16 @@ void watch_rtc_disable_1Hz_callback(); * the system will not have any way of telling you where you are within a given second; watch_rtc_get_date_time * will return the exact same timestamp until the second ticks over. */ -void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period); +void watch_rtc_register_periodic_callback(ext_irq_cb_t callback, uint8_t frequency); /** @brief Disables the tick callback for the given period. - * @param period The frequency of the tick you wish to disable, in Hz. **Must be a power of 2**, from 1 to 128. + * @param frequency The frequency of the tick you wish to disable, in Hz. **Must be a power of 2**, from 1 to 128. */ -void watch_rtc_disable_tick_callback(uint8_t period); +void watch_rtc_disable_periodic_callback(uint8_t frequency); -/** @brief Disables all tick callbacks. +/** @brief Disables all periodic callbacks, including the once-per-second tick callback. */ -void watch_rtc_disable_all_tick_callbacks(); +void watch_rtc_disable_all_periodic_callbacks(); /** @brief Sets the system date and time. * @param date_time A struct representing the date and time you wish to set. @@ -154,7 +157,7 @@ void watch_get_date_time(struct calendar_date_time *date_time); * @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick * interrupt will still be enabled, but no callback function will be called. */ -__attribute__((deprecated("Use the watch_rtc_register_1Hz_callback function instead"))) +__attribute__((deprecated("Use the watch_rtc_register_tick_callback function instead"))) void watch_register_tick_callback(ext_irq_cb_t callback); /// @} -- cgit v1.2.3 From 116304162486afcdb2e9a63fb748800ed8639591 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 28 Sep 2021 19:53:29 -0400 Subject: update existing apps to use new RTC API --- apps/Sensor Watch BME280 Project/app.c | 62 ++++++++++++++-------------------- apps/beats-time/app.c | 60 +++++++++++++------------------- 2 files changed, 49 insertions(+), 73 deletions(-) diff --git a/apps/Sensor Watch BME280 Project/app.c b/apps/Sensor Watch BME280 Project/app.c index e07b35f8..366ccde9 100644 --- a/apps/Sensor Watch BME280 Project/app.c +++ b/apps/Sensor Watch BME280 Project/app.c @@ -21,13 +21,6 @@ void app_wake_from_deep_sleep() { } void app_setup() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - if (date_time.date.year < 2020) { - date_time.date.year = 2020; - watch_set_date_time(date_time); - } - watch_enable_external_interrupts(); watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING); watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING); @@ -64,7 +57,7 @@ void app_setup() { watch_enable_display(); - watch_register_tick_callback(cb_tick); + watch_rtc_register_tick_callback(cb_tick); } /** @@ -191,9 +184,8 @@ float read_humidity(int32_t t_fine) { } void log_data() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - uint8_t hour = date_time.time.hour; + watch_date_time date_time = watch_rtc_get_date_time(); + uint8_t hour = date_time.unit.hour; int8_t temperature = read_temperature(NULL); for(int i = 0; i < MAX_DATA_POINTS - 1; i++) { @@ -205,12 +197,11 @@ void log_data() { } void do_clock_mode() { - struct calendar_date_time date_time; + watch_date_time date_time = watch_rtc_get_date_time(); const char months[12][3] = {"JA", "FE", "MR", "AR", "MA", "JN", "JL", "AU", "SE", "OC", "NO", "dE"}; - watch_get_date_time(&date_time); - watch_display_string((char *)months[date_time.date.month - 1], 0); - sprintf(buf, "%2d%2d%02d%02d", date_time.date.day, date_time.time.hour, date_time.time.min, date_time.time.sec); + watch_display_string((char *)months[date_time.unit.month - 1], 0); + sprintf(buf, "%2d%2d%02d%02d", date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); watch_display_string(buf, 2); watch_set_colon(); } @@ -271,28 +262,27 @@ void prefs_mode_handle_secondary_button() { } void do_set_time_mode() { - struct calendar_date_time date_time; + watch_date_time date_time = watch_rtc_get_date_time(); - watch_get_date_time(&date_time); watch_display_string(" ", 0); switch (application_state.page) { case 0: // hour - sprintf(buf, "ST t%2d", date_time.time.hour); + sprintf(buf, "ST t%2d", date_time.unit.hour); break; case 1: // minute - sprintf(buf, "ST t %02d", date_time.time.min); + sprintf(buf, "ST t %02d", date_time.unit.minute); break; case 2: // second - sprintf(buf, "ST t %02d", date_time.time.sec); + sprintf(buf, "ST t %02d", date_time.unit.second); break; case 3: // year - sprintf(buf, "ST d%2d", date_time.date.year - 2000); + sprintf(buf, "ST d%2d", date_time.unit.year + 20); break; case 4: // month - sprintf(buf, "ST d %02d", date_time.date.month); + sprintf(buf, "ST d %02d", date_time.unit.month); break; case 5: // day - sprintf(buf, "ST d %02d", date_time.date.day); + sprintf(buf, "ST d %02d", date_time.unit.day); break; } watch_display_string(buf, 0); @@ -305,37 +295,36 @@ void set_time_mode_handle_primary_button() { } void set_time_mode_handle_secondary_button() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); + watch_date_time date_time = watch_rtc_get_date_time(); const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; switch (application_state.page) { case 0: // hour - date_time.time.hour = (date_time.time.hour + 1) % 24; + date_time.unit.hour = (date_time.unit.hour + 1) % 24; break; case 1: // minute - date_time.time.min = (date_time.time.min + 1) % 60; + date_time.unit.minute = (date_time.unit.minute + 1) % 60; break; case 2: // second - date_time.time.sec = 0; + date_time.unit.second = 0; break; case 3: // year // only allow 2021-2030. fix this sometime next decade - date_time.date.year = ((date_time.date.year % 10) + 1) + 2020; + date_time.unit.year = ((date_time.unit.year % 10) + 1); break; case 4: // month - date_time.date.month = ((date_time.date.month + 1) % 12); + date_time.unit.month = ((date_time.unit.month + 1) % 12); break; case 5: // day - date_time.date.day = date_time.date.day + 1; + date_time.unit.day = date_time.unit.day + 1; // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. // and it should roll over. - if (date_time.date.day > days_in_month[date_time.date.month - 1]) { - date_time.date.day = 1; + if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { + date_time.unit.day = 1; } break; } - watch_set_date_time(date_time); + watch_rtc_set_date_time(date_time); } void cb_mode_pressed() { @@ -377,9 +366,8 @@ void cb_alarm_pressed() { void cb_tick() { // TODO: use alarm interrupt to trigger data acquisition. - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - if (date_time.time.min == 0 && date_time.time.sec == 0) { + watch_date_time date_time = watch_rtc_get_date_time(); + if (date_time.unit.minute == 0 && date_time.unit.second == 0) { log_data(); } diff --git a/apps/beats-time/app.c b/apps/beats-time/app.c index c694bc5e..47d0add2 100644 --- a/apps/beats-time/app.c +++ b/apps/beats-time/app.c @@ -51,13 +51,6 @@ void app_wake_from_deep_sleep() { } void app_setup() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - if (date_time.date.year < 2020) { - date_time.date.year = 2020; - watch_set_date_time(date_time); - } - watch_enable_external_interrupts(); watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING); watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING); @@ -67,7 +60,7 @@ void app_setup() { watch_enable_leds(); watch_enable_display(); - watch_register_tick_callback(cb_tick); + watch_rtc_register_tick_callback(cb_tick); } void app_prepare_for_sleep() { @@ -128,24 +121,21 @@ bool app_loop() { } void do_clock_mode() { - struct calendar_date_time date_time; + watch_date_time date_time = watch_rtc_get_date_time(); const char months[12][3] = {"JA", "FE", "MR", "AR", "MA", "JN", "JL", "AU", "SE", "OC", "NO", "dE"}; - watch_get_date_time(&date_time); - watch_display_string((char *)months[date_time.date.month - 1], 0); - sprintf(buf, "%2d%2d%02d%02d", date_time.date.day, date_time.time.hour, date_time.time.min, date_time.time.sec); + watch_display_string((char *)months[date_time.unit.month - 1], 0); + sprintf(buf, "%2d%2d%02d%02d", date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); watch_display_string(buf, 2); watch_set_colon(); + } void do_beats_mode() { watch_clear_colon(); - struct calendar_date_time date_time; - - watch_get_date_time(&date_time); - - uint16_t beats = clock2beats(date_time.time.hour, date_time.time.min, date_time.time.sec, UTC_OFFSET); + watch_date_time date_time = watch_rtc_get_date_time(); + uint16_t beats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, UTC_OFFSET); sprintf(buf, "bt %04d ", beats); watch_display_string(buf, 0); @@ -164,28 +154,27 @@ uint16_t clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, int16_t } void do_set_time_mode() { - struct calendar_date_time date_time; + watch_date_time date_time = watch_rtc_get_date_time(); - watch_get_date_time(&date_time); watch_display_string(" ", 0); switch (application_state.page) { case 0: // hour - sprintf(buf, "ST t%2d", date_time.time.hour); + sprintf(buf, "ST t%2d", date_time.unit.hour); break; case 1: // minute - sprintf(buf, "ST t %02d", date_time.time.min); + sprintf(buf, "ST t %02d", date_time.unit.minute); break; case 2: // second - sprintf(buf, "ST t %02d", date_time.time.sec); + sprintf(buf, "ST t %02d", date_time.unit.second); break; case 3: // year - sprintf(buf, "ST d%2d", date_time.date.year - 2000); + sprintf(buf, "ST d%2d", date_time.unit.year + 20); break; case 4: // month - sprintf(buf, "ST d %02d", date_time.date.month); + sprintf(buf, "ST d %02d", date_time.unit.month); break; case 5: // day - sprintf(buf, "ST d %02d", date_time.date.day); + sprintf(buf, "ST d %02d", date_time.unit.day); break; } watch_display_string(buf, 0); @@ -198,37 +187,36 @@ void set_time_mode_handle_primary_button() { } void set_time_mode_handle_secondary_button() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); + watch_date_time date_time = watch_rtc_get_date_time(); const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; switch (application_state.page) { case 0: // hour - date_time.time.hour = (date_time.time.hour + 1) % 24; + date_time.unit.hour = (date_time.unit.hour + 1) % 24; break; case 1: // minute - date_time.time.min = (date_time.time.min + 1) % 60; + date_time.unit.minute = (date_time.unit.minute + 1) % 60; break; case 2: // second - date_time.time.sec = 0; + date_time.unit.second = 0; break; case 3: // year // only allow 2021-2030. fix this sometime next decade - date_time.date.year = ((date_time.date.year % 10) + 1) + 2020; + date_time.unit.year = ((date_time.unit.year % 10) + 1); break; case 4: // month - date_time.date.month = ((date_time.date.month + 1) % 12); + date_time.unit.month = ((date_time.unit.month + 1) % 12); break; case 5: // day - date_time.date.day = date_time.date.day + 1; + date_time.unit.day = date_time.unit.day + 1; // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. // and it should roll over. - if (date_time.date.day > days_in_month[date_time.date.month - 1]) { - date_time.date.day = 1; + if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { + date_time.unit.day = 1; } break; } - watch_set_date_time(date_time); + watch_rtc_set_date_time(date_time); } void cb_mode_pressed() { -- cgit v1.2.3 From 7503c86102b5f9f0378b7a959d8274c1110d7d11 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 30 Sep 2021 16:17:40 -0400 Subject: add lcd feather --- PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.brd | 7947 ++++++++++++++++++++ PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.sch | 6772 +++++++++++++++++ 2 files changed, 14719 insertions(+) create mode 100644 PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.brd create mode 100644 PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.sch diff --git a/PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.brd b/PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.brd new file mode 100644 index 00000000..60e8374a --- /dev/null +++ b/PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.brd @@ -0,0 +1,7947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VBUS +RST +ARF +3V +A6 +A5 +PA12 +SCK +MO +MI +RX +TX +VBAT +GND +EN + + +A7 +SCL +SDA + + + + + + + + + + +A0 +A8 +VBUS +SCL +PB31 +SDA +PB30 +!RESET +AREF +PA03 +3V3 +A5 +PA07 +A4/MISO: +PB00 +RX: +PB23 +TX: +PB22 +GND +A6 +PA04 +A0 +PB04 +A8 +PA02 +A1/SCK: +PB01 +A2/ +MOSI: +PB02 +PA13 +PA01 +PA00 +PA27 +SWDIO +PA31 +SWCLK +PA30 +VBAT +EN +A7 +PB05 +SAM L22 +Feather with LCD +OSO-FEAL-A1-00 +PA30 +PA31 +PA27 +PA00 +PA01 +PA13 +!RESET +SWCLK +3V3 +SWDIO +GND +SAM L22 +Feather with LCD +OSO-FEAL-A1-00 +A3 +A3 +PB03 +NC + + +LED +/ +PA12 +LCD0 +LCD1 +LCD2 +LCD3 +LCD4 +LCD5 +LCD6 +LCD7 +LCD8 +LCD9 +LCD10 +LCD11 +LCD12 +LCD13 +LCD14 +LCD15 +LCD16 +LCD17 +LCD18 +LCD19 +LCD20 +LCD21 +LCD22 +LCD23 +LCD24 +LCD25 +LCD26 + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +</p> + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE +A +C + + + + + + + + + + + + + + + + + + + +<b>Small Outline Transistor</b> - 5 Pin + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +2-Pin JST PH Series Right-Angle Connector (+/- for batteries) + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +<p>4UCon: 19735 (with cap), 15117 (without caps)</p> + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>SOD-123</b> +<p>Source: http://www.diodes.com/datasheets/ds30139.pdf</p> + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +<b>SOT23</b> - Reflow soldering + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +Generated from <b>Hiking Log FeatherWing.brd</b><p> +by exp-lbrs.ulp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>Adafruit 3.5in 480x320 FeatherWing.sch</b><p> +by exp-lbrs.ulp + + +<b>0805 MicroPitch</b> + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + +>PCB Edge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>OSH Park Design Rules</b> +<p> +Please make sure your boards conform to these design rules. +</p> +<p> +Note, that not all DRC settings must be set by the manufacturer. Several can be adjusted for the design, including those listed on our docs page here. +<a href="http://docs.oshpark.com/design-tools/eagle/design-rules-files/">Adjustable Settings</a> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + + diff --git a/PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.sch b/PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.sch new file mode 100644 index 00000000..e68cee70 --- /dev/null +++ b/PCB/Main Boards/Watch Dev Board/OSO-FEAL-A1-00.sch @@ -0,0 +1,6772 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +</p> + + +<b> 0402</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0402 MicroPitch<p> + + + + + +>NAME +>VALUE + + + + + +<b>0603</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + +<b>0805</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0805 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR 2512 (Metric 6432)</b> + + + + + + + + +>NAME +>VALUE + + + + + +0603-Mini +<p>Mini footprint for dense boards</p> + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + +3,0 + + + + + + + + + +1,0 + + + + + + + + + +2,0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +A +C + + + + + + + + + + + + + + + + + + + +<b>CHIPLED 1206</b> + + + + + + + + + + + + + + + +>NAME +>VALUE +A +C + + + + + + + + + + +<b>CHIPLED 0805</b> + + + + + + + + + + + + + + + + +>NAME +>VALUE +A +C + + + + + + + + + + + + + +<b>CHIPLED 0603</b> + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +<p>Source: http://www.cree.com/~/media/Files/Cree/LED%20Components%20and%20Modules/XLamp/Data%20and%20Binning/XLampXPE2.pdf</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + +<p>PLCC2 - Reverse Mount</p> +<p>Source: http://catalog.osram-os.com/media/_en/Graphics/00042122_0.pdf</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + +<b>Small Outline Transistor</b> - 5 Pin + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +<b>PIN HEADER</b> + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +2-Pin JST PH Series Right-Angle Connector (+/- for batteries) + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + +- ++ +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<p>2x05 1.27mm Headers SMT (2.0mm Height)</p> +4UConnector: 16846 + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +<p>4UCon: 19735 (with cap), 15117 (without caps)</p> + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p>4UCon: 20317</p> + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>SMA Surface Mount Diode</b> + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>Name +>Value + + +<b>SOT23</b> - Reflow soldering + + + + + + + + + + + + +>NAME +>VALUE + + + + + +SOD-523 (0.8x1.2mm) + +<p>Source: http://www.rohm.com/products/databook/di/pdf/rb751s-40.pdf</p> + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +<b>SOD323</b> (2.5x1.2mm) + + +>NAME +>VALUE + + + + + + + + + + + + + + + +<b>SOD-123</b> +<p>Source: http://www.diodes.com/datasheets/ds30139.pdf</p> + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +<b>SMALL OUTLINE TRANSISTOR</b><p> +TS-003 + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +Surface Mount Test Point - Compact SMT + + + + + +>NAME +>VALUE + + +Testpoint - Pad + + + + + +>NAME +>VALUE + + +Testpoint - Round 2mm + + +>NAME +>VALUE + + + +>NAME +>VALUE + + + +1.5 x 2.0mm SMT pad (no solder paste) + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + +>NAME +>VALUE + + + +>NAME +>VALUE + + + + + + +>NAME +>VALUE + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + +>VALUE + + + + + + + +>NAME +>VALUE + + + + + + + + +>VALUE + + + + + +>VALUE + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +nRESET +NC/TDI +SWO/TDO +SWDCLK/TCK +SWDIO/TMS +VCC +GND +GND +KEY +GNDDetect +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + +>VALUE +>NAME +D +S +G + + + + + + + + + + + + + + + + + + + + + + + + +MCP73831/2 +LIPO Charger +Temp: +-40-85°C +VDD: +3.75-6V + + + + + + +>NAME +>VALUE + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + +<p><b>Ceramic Capacitors</b></p> +<p>For new designs, use the packages preceded by an '_' character since they are more reliable:</p> +<p>The following footprints should be used on most boards:</p> +<ul> +<li><b>_0402</b> - Standard footprint for regular board layouts</li> +<li><b>_0603</b> - Standard footprint for regular board layouts</li> +<li><b>_0805</b> - Standard footprint for regular board layouts</li> +<li><b>_1206</b> - Standard footprint for regular board layouts</li> +</ul> +<p>For extremely tight-pitch boards where space is at a premium, the following 'micro-pitch' footprints can be used (smaller pads, no silkscreen outline, etc.):</p> +<ul> +<li><b>_0402MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0603MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0805MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_1206MP</b> - Micro-pitch footprint for very dense/compact boards</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>GND</b> + + + + + + + + + + + + +<p><b>Resistors</b></p> +<p>For new designs, use the packages preceded by an '_' character since they are more reliable:</p> +<p>The following footprints should be used on most boards:</p> +<ul> +<li><b>_0402</b> - Standard footprint for regular board layouts</li> +<li><b>_0603</b> - Standard footprint for regular board layouts</li> +<li><b>_0805</b> - Standard footprint for regular board layouts</li> +<li><b>_1206</b> - Standard footprint for regular board layouts</li> +</ul> +<p>For extremely tight-pitch boards where space is at a premium, the following 'micro-pitch' footprints can be used (smaller pads, no silkscreen outline, etc.):</p> +<ul> +<li><b>_0402MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0603MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0805MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_1206MP</b> - Micro-pitch footprint for very dense/compact boards</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Mounting Hole</b> +<p>For #2 screws (0.086"/2.18mm width, 0.094"/2.4mm hole) use 2.5mm</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p>VBUS Supply Symbole</p> + + + + + + + + + + + + +VBAT Supply Sumbol + + + + + + + + + + + + +<p><b>LED</b></p> +<b>0603</b> - 0603 Surface Mount Package +<hr> +<p><b><u>2mA:</u></b></p> +<ul> +<li>Green LED - Low Power (3.9mcd, 2ma, 1.7Vf) - Digikey: 475-2709-2-ND</li> +<li>Orange LED - Low Power (9.8mcd, 2ma, 1.8Vf) - Digikey: 475-1194-2-ND</li> +<li>Red LED - Low Power (5mcd, 2ma, 1.8Vf) - Digikey: 475-1195-2-ND</li> +<li>Yellow LED - Low Power (7mcd, 2ma, 1.8Vf) - Digikey: 475-1196-2-ND</li> +</ul> +<p><b><u>5mA:</u></b></p> +<ul> +<li>Blue LED - Low Power (17mcd, 5ma, 2.9Vf) - Digikey: LNJ937W8CRACT-ND</li> +</ul> +<b>0805</b> - 0805 Surface Mount Package +<hr> +<p><b><u>2mA:</u></b></p> +<ul> +<li>Red LED (8.8mcd, 2mA, 1.8Vf, Clear) - Low Power [Digikey: 475-2510-1-ND]</li> +<li>Green LED (5mcd, 2mA, 1.8Vf, Clear) - Low Power [Digikey: 475-2730-1-ND]</li> +<li>Yellow LED (11.3mcd, 2mA, 1.8Vf, Clear) - Low Power [Digikey: 475-2555-1-ND]</li> +</ul> +<p><b><u>20mA:</u></b></p> +<ul> +<li>Red LED (104mcd, 20mA, Diffused) - LS R976 [Digikey: 475-1278-6-ND]</li> +<li>Red LED (12mcd, 20mA, 2.0Vf, Clear) - APT2012EC [Digikey: 754-1128-1-ND]</li> +<li>Green LED (15mcd, 20mA, 2.2Vf, Clear) - APT2012GC [Digikey: 754-1131-1-ND]</li> +<li>Orange LED (160mcd, 20mA, 2.1Vf, Clear) - APT2012SECK [Digikey: 754-1130-1-ND]</li> +</ul> +<li><b>1206</b> - 1206 Surface Mount Package +<hr> +<ul> +<li>Green LED (26mcd, 20mA, Diffused) - LG N971 [Digikey: 475-1407-6-ND]</li> +<li>Red LED (15mcd, 20mA, Diffused) - LH N974 [Digikey: 475-1416-6-ND]</li> +</ul> + +<li><b>Cree</b> - Cree High-Power Surface Mount LEDs +<hr> +<ul> +<li>XPEBWT-L1-0000-00D50 - White 111lm 350mA 2.9Vf 6200K 110°</li> +<li>XTEAWT-00-0000-00000LEE3 - White 114lm 350mA 2.85Vf 5000K 115°</li> +</ul> + +<li><b>Everlight</b> - Everlight 45-21 Series Surface Mount LEDs +<hr> +<ul> +<li>45-21/QK2C-B2832AC2CB2/2T - Warm White 2000mcd 20mA 3.25Vf 3050K 120°</li> +<li>45-21/LK2C-B38452C4CB2/2T - Nuetral White 2000mcd 20mA 3.25Vf 4150K 120°</li> +<li>45-21/LK2C-B50634C6CB2/2T - Cold White 2200mcd 20mA 3.25Vf 5650K 120°</li> +</ul> + +<li><b>PLCC2 Reverse Mount</b> +<hr> +<ul> +<li>LS T77K-J1L2-1-0-2-R18-Z - Red 11.25mcd 2mA 1.8Vf 630nm 120°</li> +<li>LO T77K-L1M2-24-Z - Orange 19.6mcd 2mA 1.8Vf 606nm 120°</li> +<li>LY T77K-K2M1-26-Z - Yellow 15.7mcd 2mA 1.8Vf 587nm 120°</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +JST 2-Pin Right-Angle Connector +<ul> +<li>PH-Series - 4UConnector: 17311</li> +<li>SH-Series - 4UConnector: 07278</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p><b>Serial Wire (SW-DP) Connector</b></p> +<p>Standard 0.05" 10-pin connector is for use with the Cortex M and Cortex A SWD (serial wire debugger) interface (SW-DP)</p> +<b>Connectors</b> +<ul> +<li><b>2x05_1.27MM_SMT</b> - Inexpensive surface-mount header with bare pins, compatible with standard 10-pin SWD cables (4UCON: 16846)</li> +<li><b>2x05_1.27MM_BOX_NOPOSTS</b> - Polarised surface-mount box (4UCON with caps: 19735, without caps: 15117</li> +<li><b>2x05_1.27MM_BOX_POSTS</b> - Polarised surface-mount box with mounting holes (4UCON: 20317)</li> +</ul> +<b>Pinout:</b> +<ul> +<li>http://infocenter.arm.com/help/topic/com.arm.doc.faqs/attached/13634/cortex_debug_connectors.pdf</li> +<li>http://www.keil.com/peripherals/coresight/connectors.asp</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p><b>SOT23-5 Fixed Voltage Regulators</b></p> +<p></p> +<table width="700"> +<tr bgcolor="#EEEEEE" > +<td><b>Part</b></td> +<td><b>Current Out</b></td> +<td><b>V Out</b></td> +<td><b>V In</b></td> +<td><b>V Dropout</b></td> +<td><b>θJA (°C/W)</b></td> +<td><b>TJ (°C)</b></td> +<td><b>Digikey Part No.</b></td> +</tr> +<tr> + <td>ADP121</td> + <td>150mA</td> + <td><b>3.3V</b></td> + <td>3.4-5.5V</td> + <td>0.09V @ 150mA</td> + <td>--</td> + <td>--</td> + <td>ADP121-AUJZ33R7CT-ND</td> +</tr> +<tr> + <td>ADP121</td> + <td>150mA</td> + <td><b>3.0V</b></td> + <td>3.1-5.5V</td> + <td>0.09V @ 150mA</td> + <td>--</td> + <td>--</td> + <td>ADP121-AUJZ30R7CT-ND</td> +</tr> +<tr> + <td>ADP122</td> + <td><strong>300mA</strong></td> + <td><b>3.3V</b></td> + <td>3.4-5.5V</td> + <td>0.085V @ 300mA</td> + <td>--</td> + <td>--</td> + <td>ADP122AUJZ-3.3-R7CT-ND</td> +</tr> +<tr> + <td>ADP1712</td> + <td><strong>300mA</strong></td> + <td><b>3.3V</b></td> + <td>3.5-5.5V</td> + <td>0.17V @ 300mA</td> + <td>--</td> + <td>--</td> + <td>ADP1712AUJZ-3.3-R7TR-ND</td> +</tr> +<tr> + <td>AP7311 (<b>Low Cost</b>)</td> + <td>150mA</td> + <td><b>3.3V</b></td> + <td>3.5-6V</td> + <td>0.15V @ 150mA</td> + <td>--</td> + <td>--</td> + <td>AP7311-33WG-7DICT-ND</td> +</tr> + +<tr> + <td>LD39015M18R</td> + <td>150mA</td> + <td><b>1.8V</b></td> + <td>1.9V-5.5V</td> + <td>0.08V @ 100mA</td> + <td>--</td> + <td>--</td> + <td>497-6977-1-ND</td> +</tr> + +<tr> + <td>LP2985A-33DBVR</td> + <td>150mA</td> + <td><b>3.3V</b></td> + <td>3.3-16V</td> + <td>0.28V @ 150mA</td> + <td>206</td> + <td>150</td> + <td>296-18479-1-ND</td> +</tr> + +<tr> + <td>MCP1824T-3302E/OT</td> + <td><b>300mA</b></td> + <td><b>3.3V</b></td> + <td>3.5V-6V</td> + <td>0.2V @ 300mA</td> + <td>--</td> + <td>--</td> + <td>MCP1824T-3302E/OTCT-ND</td> +</tr> + +<tr> + <td>MIC5205-2.5YM5 TR</td> + <td>150mA</td> + <td><b>2.5V</b></td> + <td>2.7-16V</td> + <td>0.165V @ 150mA</td> + <td>--</td> + <td>--</td> + <td>576-1257-2-ND</td> +</tr> +<tr> + <td>MIC5205-3.0YM5 TR</td> + <td>150mA</td> + <td><b>3.0V</b></td> + <td>3.2V-16V</td> + <td>0.165V @ 150mA</td> + <td>--</td> + <td>--</td> + <td>576-1258-2-ND</td> +</tr> +<tr> + <td>MIC5205-3.3YM5 TR</td> + <td>150mA</td> + <td><b>3.3V</b></td> + <td>3.5V-16V</td> + <td>0.165V @ 150mA</td> + <td>--</td> + <td>--</td> + <td>576-1259-2-ND</td> +</tr> +<tr> + <td>TPS780330220</td> + <td>150mA</td> + <td><b>3.3V+2.2V</b></td> + <td>3.6-5.5V</td> + <td>250mV Max</td> + <td>--</td> + <td>--</td> + <td>296-23332-1-ND</td> +</tr> +<tr> + <td>TDA3663/N1,135</td> + <td>100mA</td> + <td><b>3.3V</b></td> + <td>3.5-<b>45V</b></td> + <td>0.18V @ 50mA</td> + <td>--</td> + <td>--</td> + <td>568-5343-1-ND</td> +</tr> +<tr> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> +</tr> + +</table> +<p>Max operating temp can be calculated using θJA, TJ (max junction temperature), and power in watts. Set the "Maximum Ambient Temperature" until it reaches TJ ("Max Junction Temperature"), which is the absolute limit for safe use of the regulator: <a href="http://www.daycounter.com/Calculators/Heat-Sink-Temperature-Calculator.phtml">Heat Sink Temperature Calculator</a></p> +<p>For example, With 12V source into a 3.3V LP2985 and a 30mA load, we are dissipating (12V-3.3V) * 0.03A = 0.261W. With a θJA of 206 °C/W, a TJ of 150°C, and 261mW we can safely use the chip without a heat sink up to 75°C (=147.1°C Junction Temperature).</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>P-Channel Mosfet</b> +<p><b>LEGEND</b></p> +<p> +<b>VDS</b>: Voltage Drain-Source<br/> +<b>ID</b>: Drain Current<br/> +<b>RDS(ON)</b>: Drain-Source On-State Resistance<br/> +<b>VGS(TH)</b>: Gate-Source Threshold Voltage<br/> +<b>CISS</b>: Drain-Source Input Capacitance +</p> +<p> +<b>SOT-23</b> +<table border="0" width="90%" cellspacing="0" cellpadding="5"> +<tr bgcolor="#DDDDDD"> +<td>Name</td> +<td>VDS</td> +<td>ID</td> +<td>RDS(ON)</td> +<td>VGS(TH)</td> +<td>CISS</td> +<td>Order Number</td> +</tr> + +<tr> +<td>IRLML5103</td> +<td>30V</td> +<td>760mA</td> +<td>600 mOhm</td> +<td>--</td> +<td>75pF @ 25V</td> +<td>Digikey: IRLML5103PBFCT-ND</td> +</tr> + +<tr> +<td>IRLML6401</td> +<td>12V</td> +<td>4.3A</td> +<td>50 mOhm</td> +<td>950mV @ 250µA</td> +<td>830pF @ 10V</td> +<td>Digikey: IRLML6401PBFTR-ND</td> +</tr> + +<tr> +<td>NTR0202PL</td> +<td>20V</td> +<td>400mA</td> +<td>800 mOhm</td> +<td>2.3V @ 250uA</td> +<td>70pF @ 5V</td> +<td>Digikey: NTR0202PLT1GOSTR-ND</td> +</tr> + +<tr> +<td>NTR4101PT1G</td> +<td>20V</td> +<td>1.8A</td> +<td>85 mOhm</td> +<td>1.2V @ 250uA</td> +<td>675pF @ 10V</td> +<td>Digikey: NTR4101PT1GOSCT-ND</td> +</tr> + +<tr> +<td>DMP2004K</td> +<td>20V</td> +<td>600mA</td> +<td>900 mOhm</td> +<td>1V @ 250uA</td> +<td>175pF @ 16V</td> +<td>Digikey: DMP2004KDICT-ND</td> +</tr> + +<tr> +<td>PMV65XP</td> +<td>20V</td> +<td>3.9A</td> +<td>76 mOhm</td> +<td>950mV @ 1mA</td> +<td>725pF @ 20V</td> +<td>Digikey: 568-2358-2-ND</td> +</tr> + +<tr> +<td></td> +<td></td> +<td></td> +<td></td> +<td></td> +<td></td> +<td></td> +</tr> + +<tr> +<td></td> +<td></td> +<td></td> +<td></td> +<td></td> +<td></td> +<td></td> +</tr> +</table> +<b>TO-252</b> +<table border="0" width="90%" cellspacing="0" cellpadding="5"> +<tr bgcolor="#DDDDDD"> +<td>Name</td> +<td>VDS</td> +<td>ID</td> +<td>RDS(ON)</td> +<td>VGS(TH)</td> +<td>CISS</td> +<td>Order Number</td> +</tr> + +<tr> +<td>AOD417</td> +<td>30V</td> +<td>25A</td> +<td>34 mOhm</td> +<td>3V @ 250µA</td> +<td>920pF @ 15V</td> +<td>Digikey: 785-1106-2-ND</td> +</tr> + +</table> + +<b>PowerPak</b> +<table border="0" width="90%" cellspacing="0" cellpadding="5"> +<tr bgcolor="#DDDDDD"> +<td>Name</td> +<td>VDS</td> +<td>ID</td> +<td>RDS(ON)</td> +<td>VGS(TH)</td> +<td>CISS</td> +<td>Order Number</td> +</tr> + + +<tr> +<td>AON7401</td> +<td>30V</td> +<td>12A</td> +<td>14 mOhm</td> +<td>3V @ 250µA</td> +<td>2600pF @ 15V</td> +<td>Digikey: 785-1302-1-ND</td> +</tr> + + +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p><b>MCP73831/2 LIPO Charger</b></p> +<p> +<ul> +<li>VDD: 3.75 - 6V</li> +<li>Temp -40 - 85°C</li> +<li>Programmable Charge Rate: 15-500mA</li> +</ul> +</p> +<p><b>NOTE:</b> STAT is a tri-state logic output on the MCP73831 and an open-drain output on the MCP73832.</p> +<p>SOT23-5 with 4.2V output and tri-state logic on STAT = MCP73831T-2ACI/OT</p> + + + + + + + + + + + + + + + + + + + +<b>Test Point</b> +<p>Various test points for characterisation and PCB testing</p> +<p> +<ul> +<li><b>TESTPOINT_SMT</b> - Compact Surface Mount Test Point [Digikey: 5016KTR-ND]</li> +</ul> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p><b>Buttons</b></p> +<b>SOFTTOUCHSMD_SJ</b> - Soft touch temporary push button (Super Junk Akihabara) +<p>Compatible with SKPMANE010 [Mouser: 688-SKPMAN]</p> +<p>C&K_KSS = Digikey: KSS221GLFS</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + +Generated from <b>Hiking Log FeatherWing.brd</b><p> +by exp-lbrs.ulp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>DRAWING_NAME +>LAST_DATE_TIME +>SHEET +Sheet: + +oddly +specific +objects +by joey castillo +cc-by-sa 4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +LCD Glass + + + + +<b>FRAME</b><p> +DIN A4, landscape with location and doc. field + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Supply Symbols</b><p> + GND, VCC, 0V, +5V, -5V, etc.<p> + Please keep in mind, that these devices are necessary for the + automatic wiring of the supply signals.<p> + The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> + In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> + <author>Created by librarian@cadsoft.de</author> + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + +Generated from <b>Adafruit 3.5in 480x320 FeatherWing.sch</b><p> +by exp-lbrs.ulp + + +Inductor - 1007 (2518 Metric) +<p>L: 2.5mm x W: 1.8mm x H: 1.8mm</p> + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + +0603 (1608 Metric) + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +>NAME +>VALUE + + +0805 (2012 Metric) + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + +<p>Source: http://www.sumida.com/products/pdf/CDRH5D28,5D28R,5D28RHP.pdf</p> + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>Source: </b> http://www.tdk.co.jp/tefe02/e531_slf6045.pdf + + + + + + + + + + + + +>NAME +>VALUE + + +<b>Source: http://www.tdk.co.jp/tefe02/e531_vlc5045.pdf</b> + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>Source: </b>http://www.tdk.co.jp/tefe02/e531_vlc6045.pdf + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b> 0402</b> + + + + + + + + + + + +>NAME +>VALUE + + +<b>0402 MicroPitch<p> + + + + + + + + +>NAME +>VALUE + + +<b>0603</b> + + + + + + + + + + + +>NAME +>VALUE + + +<b>0603 MicroPitch</b> + + + + + + + + +>NAME +>VALUE + + +<b>0805</b> + + + + + + + + + + + +>NAME +>VALUE + + +<b>0805 MicroPitch</b> + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>Inductors</b> +<p>0603:</p> +<ul> +<li>10nH Ceramic Inductor - microwire antenna/RF (Digikey: 712-1434-2-ND)</li> +</ul> +<p>0805:</p> +<ul> +<li>560nH Ceramic Inductor - RF (Digikey: 553-1047-1-ND)</li> +<li>270nH Ceramic Inductor - Q = 40@250MHz, +-5%, 1 Ohm DC Resistance (Digikey: 535-10506-2-ND)</li> +</ul> +<p>1007 (2518 Metric) SMT:</p> +<ul> +<li>10µH 10% 250mOhm 820mA 1007 Inductor (Digikey: 587-2189-1-ND)</li> +<li>22µH 10% 500mOhm 580mA 1007 Inductor (Digikey: 587-2190-1-ND)</li> +<li>47µH 10% 950mOhm 420mA 1007 Inductor (Digikey: 587-2191-1-ND)</li> +<li>47µH 5% 100mOhm 1A 1008 Inductor (Digikey: 732-1816-1-ND)</li> +</ul> +<p>5.0x5.0mm (Taiyo Yuden NR5040 Series)</p> +<ul> +<li>6.8µH 20% 2.3A 64mOhm Inductor (Digikey: 587-2374-2-ND)</li> +</ul> +<p>5.0x5.0mm (TDK VLC5045 Series)</p> +<ul> +<li>4.7µH 20% 3.3A 34mOhm Inductor (Digikey: 445-6526-1-ND)</li> +<li>6.8µH 20% 2.7A 46mOhm Inductor (Digikey: 445-6527-1-ND)</li> +</ul> +<p>6.0x6.0mm (TDK VLC6045 Series)</p> +<ul> +<li>4.7µH 20% 3.8A 27mOhm Inductor (Digikey: 445-6538-2-ND)</li> +<li>6.8µH 20% 3A 41mOhm Inductor (Digikey: 445-6540-1-ND)</li> +<li>6.2µH 30% 2.2A 45mOhm Inductor (Digikey: SRR5028-6R2YCT-ND) - Not TDK VLC6045 but footprint should match</li> +</ul> +<p>6.0x6.0mm (TDK SLF6045 Series)</p> +<ul> +<li>6.8uH 30% 2A 33mOhm Inductor (Digikey: 445-4572-1-ND, Mouser: 810-SLF645T6R8N2R0PF)</li> +</ul> +<p>6.0x6.0mm (Sumida CDRH5D28 Series)</p> +<ul> +<li>6.2uH 30% 1.8A 45mOhm Inductor (Digikey: 308-1542-1-ND)</li> +</ul> + +<p>Taiyo Yuden NR3015T2R2M - 2.2uH 20% 1.5A (Digikey: 587-1648-2-ND, Mouser: 963-NR3015T2R2M) - Used with TI TPS62172</p> +<p>CoilCraft RFID Transponder Coil - MA5532-AE (For use with AS3935 Lightning Sensor)</p> + +<p>Taiyo Yuden NRH2412T2R2MNGH - 2.2uH 20% 1AA (Digikey: 587-3443-1-ND) - Used with TI LM3671</p> + +<p> +Vishay IHLP +<ul> +<li>1.0uH Molded Inductor - 24mOhm DCR, 5A, +/-20%, -55°C-125°C (Digikey: 541-1319-1-ND)</li> +</ul> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + + + + + +2 of 2 +>Name +>Value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + +>PCB Edge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + +USB 2.0 Type C Receptacle Dip Type, PCB Top Mount + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +LIPO CHARGING +LED +RESET +POWER AND FILTERING +10K = 100mA +5.0K = 200mA +2.0K = 500mA +1.0K = 1000mA +FEATHER HEADERS + + + + + + + + +USB PORT +SAM L22 POWER +SAM L22 MICROCONTROLLER +SWD CONNECTOR +LIQUID +CRYSTAL +DISPLAY +SERCOM0: UART +SERCOM1: I2C +SERCOM2: Unavailable +SERCOM3: SPI +TCC[5] +TCC[7] +TCC[6] +TCC[0] +TCC[2] +TCC[3] +Watch A0 +Watch CS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + + -- cgit v1.2.3 From d72a2ff6a16b4bef1b10739b6351c072d4f7e1a2 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 30 Sep 2021 16:19:11 -0400 Subject: fix LED resistor values --- PCB/Main Boards/OSO-SWAT-A1-05-BLUE.brd | 6 +++--- PCB/Main Boards/OSO-SWAT-A1-05-BLUE.sch | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.brd b/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.brd index 6fc45acf..4f691500 100644 --- a/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.brd +++ b/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.brd @@ -3,7 +3,7 @@ - + @@ -3134,11 +3134,11 @@ Please make sure your boards conform to these design rules. - + - + diff --git a/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.sch b/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.sch index 8fe68647..52751cc6 100644 --- a/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.sch +++ b/PCB/Main Boards/OSO-SWAT-A1-05-BLUE.sch @@ -4223,8 +4223,8 @@ by exp-lbrs.ulp - - + + -- cgit v1.2.3 From 20db34a9c0fa3d12b2042774e541fc0bcb7fb2b6 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 30 Sep 2021 16:32:30 -0400 Subject: add fractional beats to beat time app --- apps/beats-time/app.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/apps/beats-time/app.c b/apps/beats-time/app.c index 47d0add2..611e7f16 100644 --- a/apps/beats-time/app.c +++ b/apps/beats-time/app.c @@ -4,6 +4,7 @@ #include "watch.h" const uint8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time +const uint8_t BEAT_REFRESH_FREQUENCY = 8; typedef enum ApplicationMode { MODE_CLOCK = 0, // Displays month, day and current time. @@ -21,6 +22,8 @@ typedef struct ApplicationState { uint8_t light_ticks; // Timeout for the light bool led_on; // Indicates that the LED is on uint8_t page; // Tracks the current page in log, prefs or settings. + uint8_t last_second; // lets us see when the second changed, for subsecond timing + uint8_t subsecond; // a value from 0 to (BEAT_REFRESH_FREQUENCY - 1) indicating the fractional second } ApplicationState; void do_clock_mode(); @@ -29,12 +32,13 @@ void do_set_time_mode(); void set_time_mode_handle_primary_button(); void set_time_mode_handle_secondary_button(); -uint16_t clock2beats(uint16_t, uint16_t, uint16_t, int16_t); +float clock2beats(uint16_t, uint16_t, uint16_t, int16_t); void cb_light_pressed(); void cb_mode_pressed(); void cb_alarm_pressed(); void cb_tick(); +void cb_fast_tick(); ApplicationState application_state; char buf[16] = {0}; @@ -69,11 +73,21 @@ void app_prepare_for_sleep() { void app_wake_from_sleep() { } +void update_tick_frequency() { + watch_rtc_disable_all_periodic_callbacks(); + if (application_state.mode == MODE_BEATS) { + watch_rtc_register_periodic_callback(cb_fast_tick, BEAT_REFRESH_FREQUENCY); + } else { + watch_rtc_register_tick_callback(cb_tick); + } +} + bool app_loop() { // play a beep if the mode has changed in response to a user's press of the MODE button if (application_state.mode_changed) { // low note for nonzero case, high note for return to clock watch_buzzer_play_note(application_state.mode ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100); + update_tick_frequency(); application_state.mode_changed = false; } @@ -81,6 +95,7 @@ bool app_loop() { if (application_state.mode != MODE_CLOCK && application_state.mode_ticks == 0) { application_state.mode = MODE_CLOCK; application_state.mode_changed = true; + update_tick_frequency(); } // If the LED is off and should be on, turn it on @@ -135,22 +150,22 @@ void do_beats_mode() { watch_clear_colon(); watch_date_time date_time = watch_rtc_get_date_time(); - uint16_t beats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, UTC_OFFSET); - sprintf(buf, "bt %04d ", beats); + float beats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, UTC_OFFSET); + sprintf(buf, "bt %6.0f", beats * 100); watch_display_string(buf, 0); } -uint16_t clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, int16_t utc_offset) { - uint32_t beats = seconds; +float clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, int16_t utc_offset) { + float beats = seconds + ((float)application_state.subsecond / (float)BEAT_REFRESH_FREQUENCY); beats += 60 * minutes; - beats += (uint32_t)hours * 60 * 60; + beats += (float)hours * 60 * 60; beats += (utc_offset + 1) * 60 * 60; // offset from utc + 1 since beats in in UTC+1 beats /= 86.4; // convert to beats - beats %= 1000; // truncate to 3 digits for overflow + while(beats > 1000) beats -= 1000; // beats %= 1000 but for a float - return (uint16_t) beats; + return beats; } void do_set_time_mode() { @@ -255,3 +270,13 @@ void cb_tick() { application_state.mode_ticks--; } } + +void cb_fast_tick() { + watch_date_time date_time = watch_rtc_get_date_time(); + if (date_time.unit.second != application_state.last_second) { + application_state.last_second = date_time.unit.second; + application_state.subsecond = 0; + } else { + application_state.subsecond++; + } +} -- cgit v1.2.3 From 15ae7ab84b13953ec309a5823ade6ddb60f6a68c Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 30 Sep 2021 16:32:59 -0400 Subject: add beep to starter app --- apps/Sensor Watch Starter Project/app.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/Sensor Watch Starter Project/app.c b/apps/Sensor Watch Starter Project/app.c index 5c3c77af..ff5ed53d 100644 --- a/apps/Sensor Watch Starter Project/app.c +++ b/apps/Sensor Watch Starter Project/app.c @@ -20,6 +20,7 @@ typedef struct ApplicationState { ApplicationMode mode; LightColor color; bool light_on; + bool beep; uint8_t wake_count; bool enter_sleep_mode; } ApplicationState; @@ -74,6 +75,7 @@ void app_wake_from_deep_sleep() { */ void app_setup() { watch_enable_leds(); + watch_enable_buzzer(); watch_enable_external_interrupts(); // This starter app demonstrates three different ways of using the button interrupts. @@ -113,6 +115,11 @@ void app_wake_from_sleep() { * the watch STANDBY sleep mode. */ bool app_loop() { + if (application_state.beep) { + watch_buzzer_play_note(BUZZER_NOTE_C7, 50); + application_state.beep = false; + } + // set the LED to a color if (application_state.light_on) { switch (application_state.color) { @@ -181,6 +188,7 @@ void cb_light_pressed() { void cb_mode_pressed() { application_state.mode = (application_state.mode + 1) % 2; + application_state.beep = true; } void cb_alarm_pressed() { -- cgit v1.2.3 From 84c0fbfa2a68dc3c29b989947567d111e70a037b Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Fri, 1 Oct 2021 17:09:05 -0400 Subject: slcd: add autonomous blinking and animation --- watch-library/config/hpl_slcd_config.h | 4 +-- watch-library/watch/watch_slcd.c | 49 ++++++++++++++++++++++++++++++++++ watch-library/watch/watch_slcd.h | 35 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/watch-library/config/hpl_slcd_config.h b/watch-library/config/hpl_slcd_config.h index 5e3b2ca2..33b6a817 100644 --- a/watch-library/config/hpl_slcd_config.h +++ b/watch-library/config/hpl_slcd_config.h @@ -80,7 +80,7 @@ // <3=>128 // slcd_arch_presc #ifndef CONF_SLCD_PRESC -#define CONF_SLCD_PRESC 2 +#define CONF_SLCD_PRESC 1 #endif // Clock Divider @@ -95,7 +95,7 @@ // <7=>8 // slcd_arch_ckdiv #ifndef CONF_SLCD_CKDIV -#define CONF_SLCD_CKDIV 3 +#define CONF_SLCD_CKDIV 5 #endif /* TODO add frame frequency check */ diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c index ba9d12b2..58e1da7f 100644 --- a/watch-library/watch/watch_slcd.c +++ b/watch-library/watch/watch_slcd.c @@ -23,6 +23,7 @@ */ #include "watch_slcd.h" +#include "hpl_slcd_config.h" ////////////////////////////////////////////////////////////////////////////////////////// // Segmented Display @@ -149,6 +150,10 @@ static const uint32_t IndicatorSegments[6] = { SLCD_SEGID(1, 10), // WATCH_INDICATOR_LAP }; +void _sync_slcd() { + while (SLCD->SYNCBUSY.reg); +} + void watch_enable_display() { SEGMENT_LCD_0_init(); slcd_sync_enable(&SEGMENT_LCD_0); @@ -218,3 +223,47 @@ void watch_clear_all_indicators() { slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(0, 16)); slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(1, 10)); } + +void watch_start_character_blink(char character, uint32_t duration) { + SLCD->CTRLD.bit.FC0EN = 0; + _sync_slcd(); + + if (duration <= SLCD_FC_BYPASS_MAX_MS) { + SLCD->FC0.reg = SLCD_FC0_PB | ((duration / (1000 / SLCD_FRAME_FREQUENCY)) - 1); + } else { + SLCD->FC0.reg = (((duration / (1000 / SLCD_FRAME_FREQUENCY)) / 8 - 1)); + } + SLCD->CTRLD.bit.FC0EN = 1; + + watch_display_character(character, 7); + watch_clear_pixel(2, 10); // clear segment B of position 7 since it can't blink + + SLCD->CTRLD.bit.BLINK = 0; + SLCD->CTRLA.bit.ENABLE = 0; + _sync_slcd(); + + SLCD->BCFG.bit.BSS0 = 0x07; + SLCD->BCFG.bit.BSS1 = 0x07; + + SLCD->CTRLD.bit.BLINK = 1; + _sync_slcd(); + SLCD->CTRLA.bit.ENABLE = 1; + _sync_slcd(); +} + +void watch_stop_blink() { + SLCD->CTRLD.bit.FC0EN = 0; + SLCD->CTRLD.bit.BLINK = 0; +} + +void watch_start_tick_animation(uint32_t duration) { + watch_display_character(' ', 8); + const uint32_t segs[] = { SLCD_SEGID(0, 2)}; + slcd_sync_start_animation(&SEGMENT_LCD_0, segs, 1, duration); +} + +void watch_stop_tick_animation() { + const uint32_t segs[] = { SLCD_SEGID(0, 2)}; + slcd_sync_stop_animation(&SEGMENT_LCD_0, segs, 1); + watch_display_character(' ', 8); +} diff --git a/watch-library/watch/watch_slcd.h b/watch-library/watch/watch_slcd.h index 4f5a617c..4e710936 100644 --- a/watch-library/watch/watch_slcd.h +++ b/watch-library/watch/watch_slcd.h @@ -103,5 +103,40 @@ void watch_clear_indicator(WatchIndicatorSegment indicator); */ void watch_clear_all_indicators(); +/** @brief Blinks a single character in position 7. Does not affect other positions. + * @details Six of the seven segments in position 7 (and only position 7) are capable of autonomous + * blinking. This blinking does not require any CPU resources, and will continue even in + * standby and shallow sleep mode (if the LCD remains on). + * @param character The character you wish to blink. + * @param duration The duration of the on/off cycle in milliseconds, from 50 to ~4250 ms. + * @note Segment B of position 7 cannot blink autonomously, so not all characters will work well. + * Supported characters for blinking: + * * Punctuation: underscore, apostrophe, comma, hyphen, equals sign, tilde (top segment only) + * * Numbers: 5, 6, ampersand (lowercase 7) + * * Letters: b, C, c, E, F, h, i, L, l, n, o, S, t + */ +void watch_start_character_blink(char character, uint32_t duration); + +/** @brief Stops and clears all blinking segments. + * @details This will stop all blinking in position 7, and clear all segments in that digit. + */ +void watch_stop_blink(); + +/** @brief Begins a two-segment "tick-tock" animation in position 8. + * @details Six of the seven segments in position 8 (and only position 8) are capable of autonomous + * animation. This animation is very basic, and consists of moving a bit pattern forward + * or backward in a shift register whose positions map to fixed segments on the LCD. Given + * this constraint, an animation across all six segments does not make sense; so the watch + * library offers only a simple "tick/tock" in segments D and E. This animation does not + * require any CPU resources, and will continue even in standby and shallow sleep mode + * (if the LCD remains on). + * @param duration The duration of each frame in ms. 500 milliseconds produces a classic tick/tock. + */ +void watch_start_tick_animation(uint32_t duration); + +/** @brief Stops the tick/tock animation and clears all animating segments. + * @details This will stop the animation and clear all segments in position 8. + */ +void watch_stop_tick_animation(); /// @} #endif -- cgit v1.2.3 From 624ff19580e87915575118ca5ab4f6c33d811003 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 28 Sep 2021 01:06:37 -0400 Subject: wip: late-night untested launcher app musings --- launcher/launcher.c | 142 +++++++++++++++++++++++++++++++++++++++++ launcher/launcher.h | 74 +++++++++++++++++++++ launcher/launcher_config.h | 13 ++++ launcher/make/.gitignore | 1 + launcher/make/Makefile | 26 ++++++++ launcher/widgets/fake_widget.c | 24 +++++++ launcher/widgets/fake_widget.h | 18 ++++++ 7 files changed, 298 insertions(+) create mode 100644 launcher/launcher.c create mode 100644 launcher/launcher.h create mode 100644 launcher/launcher_config.h create mode 100755 launcher/make/.gitignore create mode 100755 launcher/make/Makefile create mode 100644 launcher/widgets/fake_widget.c create mode 100644 launcher/widgets/fake_widget.h diff --git a/launcher/launcher.c b/launcher/launcher.c new file mode 100644 index 00000000..1ad0b9da --- /dev/null +++ b/launcher/launcher.c @@ -0,0 +1,142 @@ +#include +#include +#include "watch.h" +#include "launcher.h" +#include "launcher_config.h" + +LauncherState launcher_state; +void * widget_contexts[LAUNCHER_NUM_WIDGETS]; + +void app_init() { + memset(&launcher_state, 0, sizeof(launcher_state)); +} + +void app_wake_from_deep_sleep() { + // This app does not support deep sleep mode. +} + +void app_setup() { + watch_enable_external_interrupts(); + watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_BOTH); + watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_BOTH); + watch_register_interrupt_callback(BTN_ALARM, cb_alarm_pressed, INTERRUPT_TRIGGER_BOTH); + + watch_enable_buzzer(); + watch_enable_leds(); + watch_enable_display(); + + watch_register_tick_callback(cb_tick); + + for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { + widgets[i].setup(&launcher_state.launcherSettings, widget_contexts[i]); + } +} + +void app_prepare_for_sleep() { +} + +void app_wake_from_sleep() { +} + +LauncherEvent event; + +bool app_loop() { + // play a beep if the widget has changed in response to a user's press of the MODE button + if (launcher_state.widget_changed) { + // low note for nonzero case, high note for return to clock + watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100); + launcher_state.widget_changed = false; + } + + // If the LED is off and should be on, turn it on + if (launcher_state.light_ticks > 0 && !launcher_state.led_on) { + watch_set_led_green(); + launcher_state.led_on = true; + } + + // if the LED is on and should be off, turn it off + if (launcher_state.led_on && launcher_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)) { + launcher_state.light_ticks = 3; + } else { + watch_set_led_off(); + launcher_state.led_on = false; + } + } + + if (event) { + event = 0; + bool can_sleep = widgets[launcher_state.current_widget].loop(event, &launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); + if (can_sleep) return true; + + event = EVENT_LOOP; + return false; + } + + return true; +} + +void move_to_next_widget() { + launcher_state.widget_changed = true; + widgets[launcher_state.current_widget].enter_background(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); + launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS; + widgets[launcher_state.current_widget].enter_foreground(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); +} + +void move_to_first_widget() { + launcher_state.widget_changed = true; + widgets[launcher_state.current_widget].enter_background(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); + launcher_state.current_widget = 0; + widgets[0].enter_foreground(&launcher_state.launcherSettings, widget_contexts[0]); +} + +void illuminate_led() { + launcher_state.light_ticks = 3; +} + +void cb_light_pressed() { + struct calendar_date_time date_time; + watch_get_date_time(&date_time); + if (launcher_state.light_down_timestamp) { + uint8_t diff = (61 + date_time.time.sec) - launcher_state.light_down_timestamp; + if (diff > 1) event = EVENT_LIGHT_LONG_PRESS; + else event = EVENT_LIGHT_BUTTON_UP; + launcher_state.light_down_timestamp = 0; + } else { + launcher_state.light_down_timestamp = date_time.time.sec + 1; + event = EVENT_LIGHT_BUTTON_DOWN; + } +} + +void cb_mode_pressed() { + struct calendar_date_time date_time; + watch_get_date_time(&date_time); + if (launcher_state.mode_down_timestamp) { + uint8_t diff = (61 + date_time.time.sec) - launcher_state.mode_down_timestamp; + if (diff > 1) event = EVENT_MODE_LONG_PRESS; + else event = EVENT_MODE_BUTTON_UP; + launcher_state.mode_down_timestamp = 0; + } else { + launcher_state.mode_down_timestamp = date_time.time.sec + 1; + event = EVENT_MODE_BUTTON_DOWN; + } +} + +void cb_alarm_pressed() { + struct calendar_date_time date_time; + watch_get_date_time(&date_time); + if (launcher_state.alarm_down_timestamp) { + uint8_t diff = (61 + date_time.time.sec) - launcher_state.alarm_down_timestamp; + if (diff > 1) event = EVENT_ALARM_LONG_PRESS; + else event = EVENT_ALARM_BUTTON_UP; + launcher_state.alarm_down_timestamp = 0; + } else { + launcher_state.alarm_down_timestamp = date_time.time.sec + 1; + event = EVENT_ALARM_BUTTON_DOWN; + } +} + +void cb_tick() { + event = EVENT_TICK; +} diff --git a/launcher/launcher.h b/launcher/launcher.h new file mode 100644 index 00000000..888d1adb --- /dev/null +++ b/launcher/launcher.h @@ -0,0 +1,74 @@ +#ifndef LAUNCHER_H_ +#define LAUNCHER_H_ +#include +#include + +// TODO: none of this is implemented +typedef union { + struct { + uint32_t reserved : 1; + uint32_t clock_mode_24h : 1; // determines whether display should use 12 or 24 hour mode. + uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour. + uint32_t alarm_should_sound : 1; // if true, the alarm interrupt plays a song. + uint32_t note_index : 7; // the index of the tone to play, or 0x7F for no tone. + uint32_t snapback_enabled : 1; // if true, snaps back to the main screen after 5 minutes + uint32_t sleep_interval : 3; // 0 to disable sleep, or a number of days to sleep after. + uint32_t sleep_blanks_screen : 1; // blank screen or display "SLEEP" when asleep + uint32_t led_red_color : 8; // for general purpose illumination, the red LED value + uint32_t led_green_color : 8; // for general purpose illumination, the green LED value + } bit; + uint32_t value; +} LauncherSettings; + +typedef enum LauncherEvent { + EVENT_NONE = 0, // There is no event to report. + EVENT_ACTIVATE, // Your widget is entering the foreground. + EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. + EVENT_LOOP, // The app did not sleep, and is going into another invocation of the run loop. + EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. + EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. + EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. + EVENT_MODE_BUTTON_DOWN, // The mode button has been pressed, but not yet released. + EVENT_MODE_BUTTON_UP, // The mode button was pressed and released. + EVENT_MODE_LONG_PRESS, // The mode button was held for >2 seconds, and released. + EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released. + EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released. + EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released. +} LauncherEvent; + +typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); +typedef void (*launcher_widget_enter_foreground)(LauncherSettings *settings, void *context); +typedef bool (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); +typedef void (*launcher_widget_enter_background)(LauncherSettings *settings, void *context); + +typedef struct WatchWidget { + launcher_widget_setup setup; + launcher_widget_enter_foreground enter_foreground; + launcher_widget_loop loop; + launcher_widget_enter_background enter_background; +} WatchWidget; + +typedef struct LauncherState { + // properties stored in BACKUP register + LauncherSettings launcherSettings; + + // transient properties + int16_t current_widget; + bool widget_changed; + + // LED stuff + uint8_t light_ticks; + bool led_on; + + // button tracking for long press + uint8_t light_down_timestamp; + uint8_t mode_down_timestamp; + uint8_t alarm_down_timestamp; +} LauncherState; + +void cb_mode_pressed(); +void cb_light_pressed(); +void cb_alarm_pressed(); +void cb_tick(); + +#endif // LAUNCHER_H_ diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h new file mode 100644 index 00000000..cb820a7e --- /dev/null +++ b/launcher/launcher_config.h @@ -0,0 +1,13 @@ +#ifndef LAUNCHER_CONFIG_H_ +#define LAUNCHER_CONFIG_H_ + +#include "fake_widget.h" + +#define LAUNCHER_NUM_WIDGETS 1 + +WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = { + fake_widget +}; + + +#endif // LAUNCHER_CONFIG_H_ diff --git a/launcher/make/.gitignore b/launcher/make/.gitignore new file mode 100755 index 00000000..3722ac63 --- /dev/null +++ b/launcher/make/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/launcher/make/Makefile b/launcher/make/Makefile new file mode 100755 index 00000000..dce33f45 --- /dev/null +++ b/launcher/make/Makefile @@ -0,0 +1,26 @@ +# Leave this line at the top of the file; it has all the watch library sources and includes. +TOP = ../.. +include $(TOP)/make.mk + +# If you add any other subdirectories with header files you wish to include, add them after ../ +# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. +# INCLUDES += \ +# -I../ \ +# -I../drivers/ \ +# -I../utils/ +INCLUDES += \ + -I../ \ + -I../widgets/ \ + +# If you add any other source files you wish to compile, add them after ../app.c +# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. +# SRCS += \ +# ../app.c \ +# ../drivers/bmp280.c \ +# ../utils/temperature.c +SRCS += \ + ../launcher.c \ + ../widgets/fake_widget.c \ + +# Leave this line at the bottom of the file; it has all the targets for making your project. +include $(TOP)/rules.mk diff --git a/launcher/widgets/fake_widget.c b/launcher/widgets/fake_widget.c new file mode 100644 index 00000000..15e3cf2a --- /dev/null +++ b/launcher/widgets/fake_widget.c @@ -0,0 +1,24 @@ +#include "fake_widget.h" + +void fake_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + *context_ptr = NULL; +} + +void fake_widget_enter_foreground(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} + +bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + (void) event; + (void) settings; + (void) context; + + return true; +} + +void fake_widget_enter_background(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/launcher/widgets/fake_widget.h b/launcher/widgets/fake_widget.h new file mode 100644 index 00000000..5a4b33db --- /dev/null +++ b/launcher/widgets/fake_widget.h @@ -0,0 +1,18 @@ +#ifndef FAKE_WIDGET_H_ +#define FAKE_WIDGET_H_ + +#include "launcher.h" + +void fake_widget_setup(LauncherSettings *settings, void ** context_ptr); +void fake_widget_enter_foreground(LauncherSettings *settings, void *context); +bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void fake_widget_enter_background(LauncherSettings *settings, void *context); + +#define fake_widget { \ + fake_widget_setup, \ + fake_widget_enter_foreground, \ + fake_widget_loop, \ + fake_widget_enter_background, \ +} + +#endif // FAKE_WIDGET_H_ \ No newline at end of file -- cgit v1.2.3 From 399caa2582a4c139bd37ea0ce4480d06cfa53914 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 12:31:51 -0400 Subject: more wip launcher stuff --- launcher/launcher.c | 37 +++++++++++++++++++++---------------- launcher/launcher.h | 33 +++++++++++++++++---------------- launcher/widgets/fake_widget.c | 6 +++--- launcher/widgets/fake_widget.h | 12 +++++++----- 4 files changed, 48 insertions(+), 40 deletions(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 1ad0b9da..26fec93e 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -7,8 +7,19 @@ LauncherState launcher_state; void * widget_contexts[LAUNCHER_NUM_WIDGETS]; +void launcher_request_tick_frequency(uint8_t freq) { + watch_rtc_disable_all_periodic_callbacks(); + watch_rtc_register_periodic_callback(cb_tick, freq); +} + +void launcher_illuminate_led() { + launcher_state.light_ticks = 3; +} + + void app_init() { memset(&launcher_state, 0, sizeof(launcher_state)); + launcher_state.launcher_settings.bit.led_green_color = 0xF; } void app_wake_from_deep_sleep() { @@ -25,10 +36,10 @@ void app_setup() { watch_enable_leds(); watch_enable_display(); - watch_register_tick_callback(cb_tick); + launcher_request_tick_frequency(1); for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { - widgets[i].setup(&launcher_state.launcherSettings, widget_contexts[i]); + widgets[i].setup(&launcher_state.launcher_settings, widget_contexts[i]); } } @@ -50,7 +61,7 @@ bool app_loop() { // If the LED is off and should be on, turn it on if (launcher_state.light_ticks > 0 && !launcher_state.led_on) { - watch_set_led_green(); + watch_set_led_color(launcher_state.launcher_settings.bit.led_red_color, launcher_state.launcher_settings.bit.led_green_color); launcher_state.led_on = true; } @@ -67,32 +78,26 @@ bool app_loop() { if (event) { event = 0; - bool can_sleep = widgets[launcher_state.current_widget].loop(event, &launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); - if (can_sleep) return true; - - event = EVENT_LOOP; - return false; + widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); } + if (launcher_state.led_on) return false; + return true; } void move_to_next_widget() { launcher_state.widget_changed = true; - widgets[launcher_state.current_widget].enter_background(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); + widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS; - widgets[launcher_state.current_widget].enter_foreground(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); + widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); } void move_to_first_widget() { launcher_state.widget_changed = true; - widgets[launcher_state.current_widget].enter_background(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]); + widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); launcher_state.current_widget = 0; - widgets[0].enter_foreground(&launcher_state.launcherSettings, widget_contexts[0]); -} - -void illuminate_led() { - launcher_state.light_ticks = 3; + widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); } void cb_light_pressed() { diff --git a/launcher/launcher.h b/launcher/launcher.h index 888d1adb..bc8d9191 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -6,16 +6,16 @@ // TODO: none of this is implemented typedef union { struct { - uint32_t reserved : 1; - uint32_t clock_mode_24h : 1; // determines whether display should use 12 or 24 hour mode. + uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour. - uint32_t alarm_should_sound : 1; // if true, the alarm interrupt plays a song. - uint32_t note_index : 7; // the index of the tone to play, or 0x7F for no tone. - uint32_t snapback_enabled : 1; // if true, snaps back to the main screen after 5 minutes - uint32_t sleep_interval : 3; // 0 to disable sleep, or a number of days to sleep after. - uint32_t sleep_blanks_screen : 1; // blank screen or display "SLEEP" when asleep - uint32_t led_red_color : 8; // for general purpose illumination, the red LED value - uint32_t led_green_color : 8; // for general purpose illumination, the green LED value + uint32_t alarm_should_sound : 1; // if true, the alarm interrupt can match a time and play a song. + uint32_t alarm_minute : 6; // the minute of the alarm we want to match + uint32_t alarm_hour : 5; // the second of the alarm we want to match + uint32_t note_index : 4; // the index of the tone to play on button press, or 0xF for no tone. + uint32_t screensaver_interval : 3; // 0 to disable screensaver, or a screensaver activation interval. + uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. + uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) + uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) } bit; uint32_t value; } LauncherSettings; @@ -24,7 +24,6 @@ typedef enum LauncherEvent { EVENT_NONE = 0, // There is no event to report. EVENT_ACTIVATE, // Your widget is entering the foreground. EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. - EVENT_LOOP, // The app did not sleep, and is going into another invocation of the run loop. EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. @@ -37,20 +36,22 @@ typedef enum LauncherEvent { } LauncherEvent; typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); -typedef void (*launcher_widget_enter_foreground)(LauncherSettings *settings, void *context); -typedef bool (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); -typedef void (*launcher_widget_enter_background)(LauncherSettings *settings, void *context); +typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context); +typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); +typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context); typedef struct WatchWidget { + char widget_name[11]; + bool snapback_enabled; launcher_widget_setup setup; - launcher_widget_enter_foreground enter_foreground; + launcher_widget_activate activate; launcher_widget_loop loop; - launcher_widget_enter_background enter_background; + launcher_widget_resign resign; } WatchWidget; typedef struct LauncherState { // properties stored in BACKUP register - LauncherSettings launcherSettings; + LauncherSettings launcher_settings; // transient properties int16_t current_widget; diff --git a/launcher/widgets/fake_widget.c b/launcher/widgets/fake_widget.c index 15e3cf2a..70b6918c 100644 --- a/launcher/widgets/fake_widget.c +++ b/launcher/widgets/fake_widget.c @@ -5,12 +5,12 @@ void fake_widget_setup(LauncherSettings *settings, void ** context_ptr) { *context_ptr = NULL; } -void fake_widget_enter_foreground(LauncherSettings *settings, void *context) { +void fake_widget_activate(LauncherSettings *settings, void *context) { (void) settings; (void) context; } -bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +void fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { (void) event; (void) settings; (void) context; @@ -18,7 +18,7 @@ bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *con return true; } -void fake_widget_enter_background(LauncherSettings *settings, void *context) { +void fake_widget_resign(LauncherSettings *settings, void *context) { (void) settings; (void) context; } diff --git a/launcher/widgets/fake_widget.h b/launcher/widgets/fake_widget.h index 5a4b33db..470cdf99 100644 --- a/launcher/widgets/fake_widget.h +++ b/launcher/widgets/fake_widget.h @@ -4,15 +4,17 @@ #include "launcher.h" void fake_widget_setup(LauncherSettings *settings, void ** context_ptr); -void fake_widget_enter_foreground(LauncherSettings *settings, void *context); -bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void fake_widget_enter_background(LauncherSettings *settings, void *context); +void fake_widget_activate(LauncherSettings *settings, void *context); +void fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void fake_widget_resign(LauncherSettings *settings, void *context); #define fake_widget { \ + "WI dGIt01", \ + true, \ fake_widget_setup, \ - fake_widget_enter_foreground, \ + fake_widget_activate, \ fake_widget_loop, \ - fake_widget_enter_background, \ + fake_widget_resign, \ } #endif // FAKE_WIDGET_H_ \ No newline at end of file -- cgit v1.2.3 From 95ea714d61b058f2b25aea6c01021cb3b3b2c3be Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 14:26:17 -0400 Subject: basic launcher switching between two widgets --- launcher/launcher.c | 90 +++++++++++++++++++--------------------- launcher/launcher.h | 8 ++-- launcher/launcher_config.h | 8 ++-- launcher/make/Makefile | 3 +- launcher/widgets/fake_widget.c | 24 ----------- launcher/widgets/fake_widget.h | 20 --------- launcher/widgets/fake_widget_1.c | 32 ++++++++++++++ launcher/widgets/fake_widget_1.h | 19 +++++++++ launcher/widgets/fake_widget_2.c | 32 ++++++++++++++ launcher/widgets/fake_widget_2.h | 19 +++++++++ 10 files changed, 155 insertions(+), 100 deletions(-) delete mode 100644 launcher/widgets/fake_widget.c delete mode 100644 launcher/widgets/fake_widget.h create mode 100644 launcher/widgets/fake_widget_1.c create mode 100644 launcher/widgets/fake_widget_1.h create mode 100644 launcher/widgets/fake_widget_2.c create mode 100644 launcher/widgets/fake_widget_2.h diff --git a/launcher/launcher.c b/launcher/launcher.c index 26fec93e..ff10cf6e 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -7,6 +7,11 @@ LauncherState launcher_state; void * widget_contexts[LAUNCHER_NUM_WIDGETS]; +void cb_mode_pressed(); +void cb_light_pressed(); +void cb_alarm_pressed(); +void cb_tick(); + void launcher_request_tick_frequency(uint8_t freq) { watch_rtc_disable_all_periodic_callbacks(); watch_rtc_register_periodic_callback(cb_tick, freq); @@ -16,10 +21,26 @@ void launcher_illuminate_led() { launcher_state.light_ticks = 3; } +void launcher_move_to_next_widget() { + launcher_state.widget_changed = true; + widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS; + widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + watch_display_string(widgets[launcher_state.current_widget].widget_name, 0); +} + +void launcher_move_to_first_widget() { + launcher_state.widget_changed = true; + widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + launcher_state.current_widget = 0; + widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); + watch_display_string(widgets[launcher_state.current_widget].widget_name, 0); +} void app_init() { memset(&launcher_state, 0, sizeof(launcher_state)); launcher_state.launcher_settings.bit.led_green_color = 0xF; + launcher_state.launcher_settings.bit.led_red_color = 0x0; } void app_wake_from_deep_sleep() { @@ -41,6 +62,8 @@ void app_setup() { for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { widgets[i].setup(&launcher_state.launcher_settings, widget_contexts[i]); } + + launcher_move_to_first_widget(); } void app_prepare_for_sleep() { @@ -61,8 +84,10 @@ bool app_loop() { // If the LED is off and should be on, turn it on if (launcher_state.light_ticks > 0 && !launcher_state.led_on) { - watch_set_led_color(launcher_state.launcher_settings.bit.led_red_color, launcher_state.launcher_settings.bit.led_green_color); + watch_set_led_color(launcher_state.launcher_settings.bit.led_red_color ? (0xF | launcher_state.launcher_settings.bit.led_red_color << 4) : 0, + launcher_state.launcher_settings.bit.led_green_color ? (0xF | launcher_state.launcher_settings.bit.led_green_color << 4) : 0); launcher_state.led_on = true; + } // if the LED is on and should be off, turn it off @@ -77,71 +102,42 @@ bool app_loop() { } if (event) { - event = 0; widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + event = 0; } + if (launcher_state.led_on) return false; return true; } -void move_to_next_widget() { - launcher_state.widget_changed = true; - widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS; - widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); -} - -void move_to_first_widget() { - launcher_state.widget_changed = true; - widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - launcher_state.current_widget = 0; - widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); +LauncherEvent _figure_out_button_event(LauncherEvent button_down_event, 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; + *down_timestamp = 0; + if (diff > 1) return button_down_event + 2; + else return button_down_event + 1; + } else { + *down_timestamp = date_time.unit.second + 1; + return button_down_event; + } } void cb_light_pressed() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - if (launcher_state.light_down_timestamp) { - uint8_t diff = (61 + date_time.time.sec) - launcher_state.light_down_timestamp; - if (diff > 1) event = EVENT_LIGHT_LONG_PRESS; - else event = EVENT_LIGHT_BUTTON_UP; - launcher_state.light_down_timestamp = 0; - } else { - launcher_state.light_down_timestamp = date_time.time.sec + 1; - event = EVENT_LIGHT_BUTTON_DOWN; - } + event = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); } void cb_mode_pressed() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - if (launcher_state.mode_down_timestamp) { - uint8_t diff = (61 + date_time.time.sec) - launcher_state.mode_down_timestamp; - if (diff > 1) event = EVENT_MODE_LONG_PRESS; - else event = EVENT_MODE_BUTTON_UP; - launcher_state.mode_down_timestamp = 0; - } else { - launcher_state.mode_down_timestamp = date_time.time.sec + 1; - event = EVENT_MODE_BUTTON_DOWN; - } + event = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); } void cb_alarm_pressed() { - struct calendar_date_time date_time; - watch_get_date_time(&date_time); - if (launcher_state.alarm_down_timestamp) { - uint8_t diff = (61 + date_time.time.sec) - launcher_state.alarm_down_timestamp; - if (diff > 1) event = EVENT_ALARM_LONG_PRESS; - else event = EVENT_ALARM_BUTTON_UP; - launcher_state.alarm_down_timestamp = 0; - } else { - launcher_state.alarm_down_timestamp = date_time.time.sec + 1; - event = EVENT_ALARM_BUTTON_DOWN; - } + event = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); } void cb_tick() { event = EVENT_TICK; + if (launcher_state.light_ticks) launcher_state.light_ticks--; } diff --git a/launcher/launcher.h b/launcher/launcher.h index bc8d9191..7a794545 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -42,7 +42,6 @@ typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context typedef struct WatchWidget { char widget_name[11]; - bool snapback_enabled; launcher_widget_setup setup; launcher_widget_activate activate; launcher_widget_loop loop; @@ -67,9 +66,8 @@ typedef struct LauncherState { uint8_t alarm_down_timestamp; } LauncherState; -void cb_mode_pressed(); -void cb_light_pressed(); -void cb_alarm_pressed(); -void cb_tick(); +void launcher_move_to_next_widget(); +void launcher_move_to_first_widget(); +void launcher_illuminate_led(); #endif // LAUNCHER_H_ diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h index cb820a7e..db9d1be1 100644 --- a/launcher/launcher_config.h +++ b/launcher/launcher_config.h @@ -1,12 +1,14 @@ #ifndef LAUNCHER_CONFIG_H_ #define LAUNCHER_CONFIG_H_ -#include "fake_widget.h" +#include "fake_widget_1.h" +#include "fake_widget_2.h" -#define LAUNCHER_NUM_WIDGETS 1 +#define LAUNCHER_NUM_WIDGETS 2 WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = { - fake_widget + fake_widget_1, + fake_widget_2, }; diff --git a/launcher/make/Makefile b/launcher/make/Makefile index dce33f45..f02c1853 100755 --- a/launcher/make/Makefile +++ b/launcher/make/Makefile @@ -20,7 +20,8 @@ INCLUDES += \ # ../utils/temperature.c SRCS += \ ../launcher.c \ - ../widgets/fake_widget.c \ + ../widgets/fake_widget_1.c \ + ../widgets/fake_widget_2.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/launcher/widgets/fake_widget.c b/launcher/widgets/fake_widget.c deleted file mode 100644 index 70b6918c..00000000 --- a/launcher/widgets/fake_widget.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "fake_widget.h" - -void fake_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - *context_ptr = NULL; -} - -void fake_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} - -void fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - (void) event; - (void) settings; - (void) context; - - return true; -} - -void fake_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} diff --git a/launcher/widgets/fake_widget.h b/launcher/widgets/fake_widget.h deleted file mode 100644 index 470cdf99..00000000 --- a/launcher/widgets/fake_widget.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef FAKE_WIDGET_H_ -#define FAKE_WIDGET_H_ - -#include "launcher.h" - -void fake_widget_setup(LauncherSettings *settings, void ** context_ptr); -void fake_widget_activate(LauncherSettings *settings, void *context); -void fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void fake_widget_resign(LauncherSettings *settings, void *context); - -#define fake_widget { \ - "WI dGIt01", \ - true, \ - fake_widget_setup, \ - fake_widget_activate, \ - fake_widget_loop, \ - fake_widget_resign, \ -} - -#endif // FAKE_WIDGET_H_ \ No newline at end of file diff --git a/launcher/widgets/fake_widget_1.c b/launcher/widgets/fake_widget_1.c new file mode 100644 index 00000000..aa4af2c2 --- /dev/null +++ b/launcher/widgets/fake_widget_1.c @@ -0,0 +1,32 @@ +#include "fake_widget_1.h" + +void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + // *context_ptr = NULL; +} + +void fake_widget_1_activate(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} + +void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + + switch (event) { + case EVENT_MODE_BUTTON_UP: + launcher_move_to_next_widget(); + break; + case EVENT_LIGHT_BUTTON_UP: + launcher_illuminate_led(); + break; + default: + break; + } +} + +void fake_widget_1_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/launcher/widgets/fake_widget_1.h b/launcher/widgets/fake_widget_1.h new file mode 100644 index 00000000..00db80cb --- /dev/null +++ b/launcher/widgets/fake_widget_1.h @@ -0,0 +1,19 @@ +#ifndef FAKE_WIDGET_1_H_ +#define FAKE_WIDGET_1_H_ + +#include "launcher.h" + +void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr); +void fake_widget_1_activate(LauncherSettings *settings, void *context); +void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void fake_widget_1_resign(LauncherSettings *settings, void *context); + +#define fake_widget_1 { \ + "W1 d get01", \ + fake_widget_1_setup, \ + fake_widget_1_activate, \ + fake_widget_1_loop, \ + fake_widget_1_resign, \ +} + +#endif // FAKE_WIDGET_1_H_ \ No newline at end of file diff --git a/launcher/widgets/fake_widget_2.c b/launcher/widgets/fake_widget_2.c new file mode 100644 index 00000000..4ce00ce2 --- /dev/null +++ b/launcher/widgets/fake_widget_2.c @@ -0,0 +1,32 @@ +#include "fake_widget_2.h" + +void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + *context_ptr = NULL; +} + +void fake_widget_2_activate(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} + +void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + + switch (event) { + case EVENT_MODE_BUTTON_UP: + launcher_move_to_next_widget(); + break; + case EVENT_LIGHT_BUTTON_UP: + launcher_illuminate_led(); + break; + default: + break; + } +} + +void fake_widget_2_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/launcher/widgets/fake_widget_2.h b/launcher/widgets/fake_widget_2.h new file mode 100644 index 00000000..31bf30bc --- /dev/null +++ b/launcher/widgets/fake_widget_2.h @@ -0,0 +1,19 @@ +#ifndef FAKE_WIDGET_2_H_ +#define FAKE_WIDGET_2_H_ + +#include "launcher.h" + +void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr); +void fake_widget_2_activate(LauncherSettings *settings, void *context); +void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void fake_widget_2_resign(LauncherSettings *settings, void *context); + +#define fake_widget_2 { \ + "W1 d get02", \ + fake_widget_2_setup, \ + fake_widget_2_activate, \ + fake_widget_2_loop, \ + fake_widget_2_resign, \ +} + +#endif // FAKE_WIDGET_2_H_ \ No newline at end of file -- cgit v1.2.3 From 8d5280a34f1159d8af0277ba04b7e1cb9c8bd7ac Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 18:48:55 -0400 Subject: slcd: add function to blank entire screen --- watch-library/watch/watch_slcd.c | 6 ++++++ watch-library/watch/watch_slcd.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c index ba9d12b2..c1e24308 100644 --- a/watch-library/watch/watch_slcd.c +++ b/watch-library/watch/watch_slcd.c @@ -162,6 +162,12 @@ inline void watch_clear_pixel(uint8_t com, uint8_t seg) { slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(com, seg)); } +void watch_clear_display() { + SLCD->SDATAL0.reg = 0; + SLCD->SDATAL1.reg = 0; + SLCD->SDATAL2.reg = 0; +} + void watch_display_character(uint8_t character, uint8_t position) { // handle lowercase 7 if needed if (character == '7' && (position == 4 || position == 6)) character = '&'; diff --git a/watch-library/watch/watch_slcd.h b/watch-library/watch/watch_slcd.h index 4f5a617c..5a54b72e 100644 --- a/watch-library/watch/watch_slcd.h +++ b/watch-library/watch/watch_slcd.h @@ -69,6 +69,10 @@ void watch_set_pixel(uint8_t com, uint8_t seg); */ void watch_clear_pixel(uint8_t com, uint8_t seg); +/** @brief Clears all segments of the display, including incicators and the colon. + */ +void watch_clear_display(); + /** @brief Displays a string at the given position, starting from the top left. There are ten digits. A space in any position will clear that digit. * @param string A null-terminated string. -- cgit v1.2.3 From 27df51d40a29baea8c50a25ed2345b1293a5089c Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 18:49:21 -0400 Subject: launcher app with clock and preferences menu --- launcher/launcher.c | 41 +++++---- launcher/launcher.h | 14 ++- launcher/launcher_config.h | 6 +- launcher/make/Makefile | 4 + launcher/widgets/clock/simple_clock_widget.c | 86 ++++++++++++++++++ launcher/widgets/clock/simple_clock_widget.h | 20 ++++ launcher/widgets/fake_widget_1.c | 10 +- launcher/widgets/fake_widget_1.h | 3 +- launcher/widgets/fake_widget_2.c | 8 +- launcher/widgets/fake_widget_2.h | 3 +- launcher/widgets/settings/preferences_widget.c | 121 +++++++++++++++++++++++++ launcher/widgets/settings/preferences_widget.h | 18 ++++ 12 files changed, 304 insertions(+), 30 deletions(-) create mode 100644 launcher/widgets/clock/simple_clock_widget.c create mode 100644 launcher/widgets/clock/simple_clock_widget.h create mode 100644 launcher/widgets/settings/preferences_widget.c create mode 100644 launcher/widgets/settings/preferences_widget.h diff --git a/launcher/launcher.c b/launcher/launcher.c index ff10cf6e..8dc38199 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -13,7 +13,10 @@ void cb_alarm_pressed(); void cb_tick(); void launcher_request_tick_frequency(uint8_t freq) { + // FIXME: there is an issue where after changing tick frequencies on a widget switch, something glitchy happens on the next one. watch_rtc_disable_all_periodic_callbacks(); + launcher_state.subsecond = 0; + launcher_state.tick_frequency = freq; watch_rtc_register_periodic_callback(cb_tick, freq); } @@ -21,26 +24,24 @@ void launcher_illuminate_led() { launcher_state.light_ticks = 3; } -void launcher_move_to_next_widget() { +void launcher_move_to_widget(uint8_t widget_index) { launcher_state.widget_changed = true; widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS; + launcher_state.current_widget = widget_index; + watch_clear_display(); widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - watch_display_string(widgets[launcher_state.current_widget].widget_name, 0); + widgets[launcher_state.current_widget].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]); } -void launcher_move_to_first_widget() { - launcher_state.widget_changed = true; - widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - launcher_state.current_widget = 0; - widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); - watch_display_string(widgets[launcher_state.current_widget].widget_name, 0); +void launcher_move_to_next_widget() { + launcher_move_to_widget((launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS); } void app_init() { memset(&launcher_state, 0, sizeof(launcher_state)); launcher_state.launcher_settings.bit.led_green_color = 0xF; - launcher_state.launcher_settings.bit.led_red_color = 0x0; + watch_date_time date_time = watch_rtc_get_date_time(); + watch_rtc_set_date_time(date_time); } void app_wake_from_deep_sleep() { @@ -60,10 +61,10 @@ void app_setup() { launcher_request_tick_frequency(1); for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { - widgets[i].setup(&launcher_state.launcher_settings, widget_contexts[i]); + widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]); } - launcher_move_to_first_widget(); + launcher_move_to_widget(0); } void app_prepare_for_sleep() { @@ -77,8 +78,8 @@ LauncherEvent event; bool app_loop() { // play a beep if the widget has changed in response to a user's press of the MODE button if (launcher_state.widget_changed) { - // low note for nonzero case, high note for return to clock - watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100); + // low note for nonzero case, high note for return to widget 0 + watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); launcher_state.widget_changed = false; } @@ -102,7 +103,7 @@ bool app_loop() { } if (event) { - widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]); event = 0; } @@ -139,5 +140,13 @@ void cb_alarm_pressed() { void cb_tick() { event = EVENT_TICK; - if (launcher_state.light_ticks) launcher_state.light_ticks--; + watch_date_time date_time = watch_rtc_get_date_time(); + if (date_time.unit.second != launcher_state.last_second) { + if (launcher_state.light_ticks) launcher_state.light_ticks--; + + launcher_state.last_second = date_time.unit.second; + launcher_state.subsecond = 0; + } else { + launcher_state.subsecond++; + } } diff --git a/launcher/launcher.h b/launcher/launcher.h index 7a794545..e49575e7 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -6,12 +6,13 @@ // TODO: none of this is implemented typedef union { struct { + uint32_t reserved : 3; uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. + uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour. uint32_t alarm_should_sound : 1; // if true, the alarm interrupt can match a time and play a song. uint32_t alarm_minute : 6; // the minute of the alarm we want to match uint32_t alarm_hour : 5; // the second of the alarm we want to match - uint32_t note_index : 4; // the index of the tone to play on button press, or 0xF for no tone. uint32_t screensaver_interval : 3; // 0 to disable screensaver, or a screensaver activation interval. uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) @@ -37,11 +38,10 @@ typedef enum LauncherEvent { typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context); -typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); +typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context); typedef struct WatchWidget { - char widget_name[11]; launcher_widget_setup setup; launcher_widget_activate activate; launcher_widget_loop loop; @@ -64,10 +64,16 @@ typedef struct LauncherState { uint8_t light_down_timestamp; uint8_t mode_down_timestamp; uint8_t alarm_down_timestamp; + + // stuff for subsecond tracking + uint8_t tick_frequency; + uint8_t last_second; + uint8_t subsecond; } LauncherState; +void launcher_move_to_widget(uint8_t widget_index); void launcher_move_to_next_widget(); -void launcher_move_to_first_widget(); void launcher_illuminate_led(); +void launcher_request_tick_frequency(uint8_t freq); #endif // LAUNCHER_H_ diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h index db9d1be1..9bc43c47 100644 --- a/launcher/launcher_config.h +++ b/launcher/launcher_config.h @@ -1,12 +1,16 @@ #ifndef LAUNCHER_CONFIG_H_ #define LAUNCHER_CONFIG_H_ +#include "simple_clock_widget.h" +#include "preferences_widget.h" #include "fake_widget_1.h" #include "fake_widget_2.h" -#define LAUNCHER_NUM_WIDGETS 2 +#define LAUNCHER_NUM_WIDGETS 4 WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = { + simple_clock_widget, + preferences_widget, fake_widget_1, fake_widget_2, }; diff --git a/launcher/make/Makefile b/launcher/make/Makefile index f02c1853..4fba0351 100755 --- a/launcher/make/Makefile +++ b/launcher/make/Makefile @@ -11,6 +11,8 @@ include $(TOP)/make.mk INCLUDES += \ -I../ \ -I../widgets/ \ + -I../widgets/clock/ \ + -I../widgets/settings/ \ # If you add any other source files you wish to compile, add them after ../app.c # Note that you will need to add a backslash at the end of any line you wish to continue, i.e. @@ -20,6 +22,8 @@ INCLUDES += \ # ../utils/temperature.c SRCS += \ ../launcher.c \ + ../widgets/clock/simple_clock_widget.c \ + ../widgets/settings/preferences_widget.c \ ../widgets/fake_widget_1.c \ ../widgets/fake_widget_2.c \ diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c new file mode 100644 index 00000000..51c6c9c6 --- /dev/null +++ b/launcher/widgets/clock/simple_clock_widget.c @@ -0,0 +1,86 @@ +#include +#include "simple_clock_widget.h" +#include "watch.h" + +void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + // the only context we need is the timestamp of the previous tick. + *context_ptr = malloc(sizeof(uint32_t)); +} + +void simple_clock_widget_activate(LauncherSettings *settings, void *context) { + if (settings->bit.clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + } + watch_set_colon(); + // this ensures that none of the timestamp fields will match, so we can re-render them all. + *((uint32_t *)context) = 0xFFFFFFFF; +} + +void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { + printf("simple_clock_widget_loop\n"); + (void) subsecond; + const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; + char buf[11]; + uint8_t pos; + + watch_date_time date_time; + uint32_t previous_date_time; + switch (event) { + case EVENT_TICK: + case EVENT_ACTIVATE: + date_time = watch_rtc_get_date_time(); + previous_date_time = *((uint32_t *)context); + *((uint32_t *)context) = date_time.reg; + + if (date_time.reg >> 6 == previous_date_time >> 6) { + // everything before seconds is the same, don't waste cycles setting those segments. + pos = 8; + sprintf(buf, "%02d", date_time.unit.second); + } else if (date_time.reg >> 12 == previous_date_time >> 12) { + // everything before minutes is the same. + pos = 6; + sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); + } else { + // other stuff changed; let's do it all. + if (!settings->bit.clock_mode_24h) { + // if we are in 12 hour mode, do some cleanup. + if (date_time.unit.hour < 12) { + watch_clear_indicator(WATCH_INDICATOR_PM); + } else { + watch_set_indicator(WATCH_INDICATOR_PM); + } + date_time.unit.hour %= 12; + if (date_time.unit.hour == 0) date_time.unit.hour = 12; + } + pos = 0; + sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } + watch_display_string(buf, pos); + break; + case EVENT_MODE_BUTTON_UP: + launcher_move_to_next_widget(); + return; + case EVENT_LIGHT_BUTTON_UP: + launcher_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_UP: + break; + default: + break; + } +} + +void simple_clock_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} + +uint8_t simple_clock_widget_get_weekday(uint16_t year, uint16_t month, uint16_t day) { + year += 20; + if (month <= 2) { + month += 12; + year--; + } + return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7; +} diff --git a/launcher/widgets/clock/simple_clock_widget.h b/launcher/widgets/clock/simple_clock_widget.h new file mode 100644 index 00000000..459721b9 --- /dev/null +++ b/launcher/widgets/clock/simple_clock_widget.h @@ -0,0 +1,20 @@ +#ifndef SIMPLE_CLOCK_WIDGET_H_ +#define SIMPLE_CLOCK_WIDGET_H_ + +#include "launcher.h" + +void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr); +void simple_clock_widget_activate(LauncherSettings *settings, void *context); +void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +void simple_clock_widget_resign(LauncherSettings *settings, void *context); + +uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year); + +#define simple_clock_widget { \ + simple_clock_widget_setup, \ + simple_clock_widget_activate, \ + simple_clock_widget_loop, \ + simple_clock_widget_resign, \ +} + +#endif // FAKE_WIDGET_H_ \ No newline at end of file diff --git a/launcher/widgets/fake_widget_1.c b/launcher/widgets/fake_widget_1.c index aa4af2c2..15ffcbd2 100644 --- a/launcher/widgets/fake_widget_1.c +++ b/launcher/widgets/fake_widget_1.c @@ -1,8 +1,9 @@ #include "fake_widget_1.h" +#include "watch.h" void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; - // *context_ptr = NULL; + *context_ptr = NULL; } void fake_widget_1_activate(LauncherSettings *settings, void *context) { @@ -10,14 +11,17 @@ void fake_widget_1_activate(LauncherSettings *settings, void *context) { (void) context; } -void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { + printf("fake_widget_1_loop\n"); (void) settings; + (void) subsecond; (void) context; + watch_display_string("W1 d get01", 0); switch (event) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); - break; + return; case EVENT_LIGHT_BUTTON_UP: launcher_illuminate_led(); break; diff --git a/launcher/widgets/fake_widget_1.h b/launcher/widgets/fake_widget_1.h index 00db80cb..18180156 100644 --- a/launcher/widgets/fake_widget_1.h +++ b/launcher/widgets/fake_widget_1.h @@ -5,11 +5,10 @@ void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr); void fake_widget_1_activate(LauncherSettings *settings, void *context); -void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); void fake_widget_1_resign(LauncherSettings *settings, void *context); #define fake_widget_1 { \ - "W1 d get01", \ fake_widget_1_setup, \ fake_widget_1_activate, \ fake_widget_1_loop, \ diff --git a/launcher/widgets/fake_widget_2.c b/launcher/widgets/fake_widget_2.c index 4ce00ce2..f3ffc14b 100644 --- a/launcher/widgets/fake_widget_2.c +++ b/launcher/widgets/fake_widget_2.c @@ -1,4 +1,5 @@ #include "fake_widget_2.h" +#include "watch.h" void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; @@ -10,14 +11,17 @@ void fake_widget_2_activate(LauncherSettings *settings, void *context) { (void) context; } -void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { + printf("fake_widget_2_loop\n"); (void) settings; + (void) subsecond; (void) context; + watch_display_string("W1 d get02", 0); switch (event) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); - break; + return; case EVENT_LIGHT_BUTTON_UP: launcher_illuminate_led(); break; diff --git a/launcher/widgets/fake_widget_2.h b/launcher/widgets/fake_widget_2.h index 31bf30bc..1f6bd503 100644 --- a/launcher/widgets/fake_widget_2.h +++ b/launcher/widgets/fake_widget_2.h @@ -5,11 +5,10 @@ void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr); void fake_widget_2_activate(LauncherSettings *settings, void *context); -void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); void fake_widget_2_resign(LauncherSettings *settings, void *context); #define fake_widget_2 { \ - "W1 d get02", \ fake_widget_2_setup, \ fake_widget_2_activate, \ fake_widget_2_loop, \ diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c new file mode 100644 index 00000000..5877c237 --- /dev/null +++ b/launcher/widgets/settings/preferences_widget.c @@ -0,0 +1,121 @@ +#include +#include "preferences_widget.h" +#include "watch.h" + +#define PREFERENCES_WIDGET_NUM_PREFEFENCES (5) +const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL", "Bt Beep", "SC", "Lt grn", "Lt red"}; + +void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + *context_ptr = malloc(sizeof(uint8_t)); +} + +void preferences_widget_activate(LauncherSettings *settings, void *context) { + (void) settings; + *((uint8_t *)context) = 0; + launcher_request_tick_frequency(4); // we need to manually blink some pixels +} + +void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { + (void) settings; + (void) context; + printf("preferences_widget_loop\n"); + uint8_t current_page = *((uint8_t *)context); + switch (event) { + case EVENT_MODE_BUTTON_UP: + launcher_move_to_next_widget(); + return; + case EVENT_LIGHT_BUTTON_UP: + current_page = (current_page + 1) % PREFERENCES_WIDGET_NUM_PREFEFENCES; + *((uint8_t *)context) = current_page; + break; + case EVENT_ALARM_BUTTON_UP: + switch (current_page) { + case 0: + settings->bit.clock_mode_24h = !(settings->bit.clock_mode_24h); + break; + case 1: + settings->bit.button_should_sound = !(settings->bit.button_should_sound); + break; + case 2: + settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1; + break; + case 3: + settings->bit.led_green_color = settings->bit.led_green_color + 1; + break; + case 4: + settings->bit.led_red_color = settings->bit.led_red_color + 1; + break; + } + break; + default: + break; + } + + watch_clear_display(); + watch_display_string((char *)preferences_widget_titles[current_page], 0); + if (current_page > 2) { + // this is a hack, launcher should be able to illumate with a custom color. + launcher_illuminate_led(); + watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, + settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); + } else { + watch_set_led_off(); + } + + if (subsecond % 2) return; + char buf[3]; + switch (current_page) { + case 0: + if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); + else watch_display_string("12h", 4); + break; + case 1: + if (settings->bit.button_should_sound) watch_display_string("y", 9); + else watch_display_string("n", 9); + break; + case 2: + switch (settings->bit.screensaver_interval) { + case 0: + watch_display_string("never", 4); + break; + case 1: + watch_display_string("1 hour", 4); + break; + case 2: + watch_display_string("2 hour", 4); + break; + case 3: + watch_display_string("6 hour", 4); + break; + case 4: + watch_display_string("12 hr", 4); + break; + case 5: + watch_display_string(" 1 day", 4); + break; + case 6: + watch_display_string(" 2 day", 4); + break; + case 7: + watch_display_string(" 7 day", 4); + break; + } + break; + case 3: + sprintf(buf, "%2d", settings->bit.led_green_color); + watch_display_string(buf, 8); + break; + case 4: + sprintf(buf, "%2d", settings->bit.led_red_color); + watch_display_string(buf, 8); + break; + } +} + +void preferences_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + watch_set_led_off(); + launcher_request_tick_frequency(1); +} diff --git a/launcher/widgets/settings/preferences_widget.h b/launcher/widgets/settings/preferences_widget.h new file mode 100644 index 00000000..fcbcd0d6 --- /dev/null +++ b/launcher/widgets/settings/preferences_widget.h @@ -0,0 +1,18 @@ +#ifndef PREFERENCES_WIDGET_H_ +#define PREFERENCES_WIDGET_H_ + +#include "launcher.h" + +void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr); +void preferences_widget_activate(LauncherSettings *settings, void *context); +void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +void preferences_widget_resign(LauncherSettings *settings, void *context); + +#define preferences_widget { \ + preferences_widget_setup, \ + preferences_widget_activate, \ + preferences_widget_loop, \ + preferences_widget_resign, \ +} + +#endif // PREFERENCES_WIDGET_H_ \ No newline at end of file -- cgit v1.2.3 From a6d8a098507ed13537e17e51bb545dcadb579d40 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 19:15:47 -0400 Subject: avoid calling deactivate on widget 0 before it's activated --- launcher/launcher.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 8dc38199..0d4fbe86 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -64,7 +64,8 @@ void app_setup() { widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]); } - launcher_move_to_widget(0); + widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + widgets[0].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, 0, widget_contexts[launcher_state.current_widget]); } void app_prepare_for_sleep() { -- cgit v1.2.3 From 64485b4255271dca8d6d38a91fa9ace610bf7222 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 19:16:14 -0400 Subject: implement beep / silent preference --- launcher/launcher.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 0d4fbe86..77dc303c 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -40,6 +40,7 @@ void launcher_move_to_next_widget() { void app_init() { memset(&launcher_state, 0, sizeof(launcher_state)); launcher_state.launcher_settings.bit.led_green_color = 0xF; + launcher_state.launcher_settings.bit.button_should_sound = true; watch_date_time date_time = watch_rtc_get_date_time(); watch_rtc_set_date_time(date_time); } @@ -80,7 +81,9 @@ bool app_loop() { // play a beep if the widget has changed in response to a user's press of the MODE button if (launcher_state.widget_changed) { // low note for nonzero case, high note for return to widget 0 - watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); + if (launcher_state.launcher_settings.bit.button_should_sound) { + watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); + } launcher_state.widget_changed = false; } -- cgit v1.2.3 From 4300dff61631143f794f186cadb222bdf5f75a06 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 20:37:15 -0400 Subject: launcher: first crack at low power 'screensaver' mode --- apps/Sensor Watch Starter Project/app.c | 2 +- launcher/launcher.c | 85 +++++++++++++++++++++------- launcher/launcher.h | 4 ++ launcher/widgets/clock/simple_clock_widget.c | 13 +++-- watch-library/watch/watch_deepsleep.c | 7 +-- watch-library/watch/watch_deepsleep.h | 15 ++--- 6 files changed, 84 insertions(+), 42 deletions(-) diff --git a/apps/Sensor Watch Starter Project/app.c b/apps/Sensor Watch Starter Project/app.c index ff5ed53d..ae5aa6e8 100644 --- a/apps/Sensor Watch Starter Project/app.c +++ b/apps/Sensor Watch Starter Project/app.c @@ -157,7 +157,7 @@ bool app_loop() { delay_ms(250); // nap time :) - watch_enter_shallow_sleep(NULL); + watch_enter_shallow_sleep(false); // we just woke up; wait a moment again for the user's finger to be off the button... delay_ms(250); diff --git a/launcher/launcher.c b/launcher/launcher.c index 77dc303c..0f8f7ead 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -1,19 +1,27 @@ #include #include +#include #include "watch.h" #include "launcher.h" #include "launcher_config.h" LauncherState launcher_state; void * widget_contexts[LAUNCHER_NUM_WIDGETS]; +const int32_t launcher_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; -void cb_mode_pressed(); -void cb_light_pressed(); -void cb_alarm_pressed(); +void cb_mode_btn_interrupt(); +void cb_light_btn_interrupt(); +void cb_alarm_btn_interrupt(); +void cb_alarm_btn_extwake(); +void cb_alarm_fired(); void cb_tick(); +static inline void _launcher_reset_screensaver_countdown() { + // for testing, make the timeout happen 60x faster. + launcher_state.screensaver_ticks = launcher_screensaver_deadlines[launcher_state.launcher_settings.bit.screensaver_interval] / 60; +} + void launcher_request_tick_frequency(uint8_t freq) { - // FIXME: there is an issue where after changing tick frequencies on a widget switch, something glitchy happens on the next one. watch_rtc_disable_all_periodic_callbacks(); launcher_state.subsecond = 0; launcher_state.tick_frequency = freq; @@ -39,10 +47,11 @@ void launcher_move_to_next_widget() { void app_init() { memset(&launcher_state, 0, sizeof(launcher_state)); + launcher_state.launcher_settings.bit.led_green_color = 0xF; launcher_state.launcher_settings.bit.button_should_sound = true; - watch_date_time date_time = watch_rtc_get_date_time(); - watch_rtc_set_date_time(date_time); + launcher_state.launcher_settings.bit.screensaver_interval = 1; + _launcher_reset_screensaver_countdown(); } void app_wake_from_deep_sleep() { @@ -50,23 +59,27 @@ void app_wake_from_deep_sleep() { } void app_setup() { - watch_enable_external_interrupts(); - watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_BOTH); - watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_BOTH); - watch_register_interrupt_callback(BTN_ALARM, cb_alarm_pressed, INTERRUPT_TRIGGER_BOTH); + if (launcher_state.screensaver_ticks != -1) { + watch_disable_extwake_interrupt(BTN_ALARM); - watch_enable_buzzer(); - watch_enable_leds(); - watch_enable_display(); + watch_enable_external_interrupts(); + watch_register_interrupt_callback(BTN_MODE, cb_mode_btn_interrupt, INTERRUPT_TRIGGER_BOTH); + watch_register_interrupt_callback(BTN_LIGHT, cb_light_btn_interrupt, INTERRUPT_TRIGGER_BOTH); + watch_register_interrupt_callback(BTN_ALARM, cb_alarm_btn_interrupt, INTERRUPT_TRIGGER_BOTH); - launcher_request_tick_frequency(1); + watch_enable_buzzer(); + watch_enable_leds(); + watch_enable_display(); - for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { - widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]); - } + launcher_request_tick_frequency(1); + + for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { + widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]); + } - widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - widgets[0].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, 0, widget_contexts[launcher_state.current_widget]); + widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + widgets[0].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, 0, widget_contexts[launcher_state.current_widget]); + } } void app_prepare_for_sleep() { @@ -106,6 +119,19 @@ bool app_loop() { } } + // if we have timed out of our screensaver countdown, enter screensaver mode. + if (launcher_state.screensaver_ticks == 0) { + launcher_state.screensaver_ticks = -1; + watch_date_time alarm_time; + alarm_time.reg = 0; + alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 + watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); + watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); + widgets[launcher_state.current_widget].loop(EVENT_SCREENSAVER, &launcher_state.launcher_settings, 0, widget_contexts[launcher_state.current_widget]); + event = EVENT_SCREENSAVER; + watch_enter_shallow_sleep(true); + } + if (event) { widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]); event = 0; @@ -130,23 +156,38 @@ LauncherEvent _figure_out_button_event(LauncherEvent button_down_event, uint8_t } } -void cb_light_pressed() { +void cb_light_btn_interrupt() { + _launcher_reset_screensaver_countdown(); event = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); } -void cb_mode_pressed() { +void cb_mode_btn_interrupt() { + _launcher_reset_screensaver_countdown(); event = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); } -void cb_alarm_pressed() { +void cb_alarm_btn_interrupt() { + _launcher_reset_screensaver_countdown(); event = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); } +void cb_alarm_btn_extwake() { + _launcher_reset_screensaver_countdown(); + // this is a hack: waking from shallow sleep, app_setup does get called, but it happens before we reset our ticks. + // need to figure out if there's a better heuristic for determining how we woke up. + app_setup(); +} + +void cb_alarm_fired() { + event = EVENT_SCREENSAVER; +} + void cb_tick() { event = EVENT_TICK; watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.second != launcher_state.last_second) { if (launcher_state.light_ticks) launcher_state.light_ticks--; + if (launcher_state.launcher_settings.bit.screensaver_interval && launcher_state.screensaver_ticks > 0) launcher_state.screensaver_ticks--; launcher_state.last_second = date_time.unit.second; launcher_state.subsecond = 0; diff --git a/launcher/launcher.h b/launcher/launcher.h index e49575e7..09b33dbb 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -25,6 +25,7 @@ typedef enum LauncherEvent { EVENT_NONE = 0, // There is no event to report. EVENT_ACTIVATE, // Your widget is entering the foreground. EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. + EVENT_SCREENSAVER, // Your widget is being asked to display its output for screensaver mode. EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. @@ -65,6 +66,9 @@ typedef struct LauncherState { uint8_t mode_down_timestamp; uint8_t alarm_down_timestamp; + // screensaver countdown + int32_t screensaver_ticks; + // stuff for subsecond tracking uint8_t tick_frequency; uint8_t last_second; diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c index 51c6c9c6..29a53b41 100644 --- a/launcher/widgets/clock/simple_clock_widget.c +++ b/launcher/widgets/clock/simple_clock_widget.c @@ -27,17 +27,18 @@ void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, u watch_date_time date_time; uint32_t previous_date_time; switch (event) { - case EVENT_TICK: case EVENT_ACTIVATE: + case EVENT_TICK: + case EVENT_SCREENSAVER: date_time = watch_rtc_get_date_time(); previous_date_time = *((uint32_t *)context); *((uint32_t *)context) = date_time.reg; - if (date_time.reg >> 6 == previous_date_time >> 6) { + if (date_time.reg >> 6 == previous_date_time >> 6 && event != EVENT_SCREENSAVER) { // everything before seconds is the same, don't waste cycles setting those segments. pos = 8; sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12) { + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event != EVENT_SCREENSAVER) { // everything before minutes is the same. pos = 6; sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); @@ -54,7 +55,11 @@ void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, u if (date_time.unit.hour == 0) date_time.unit.hour = 12; } pos = 0; - sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + if (event == EVENT_SCREENSAVER) { + sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); + } else { + sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } } watch_display_string(buf, pos); break; diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index b7da82ee..9ca53db0 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -151,11 +151,8 @@ void _watch_disable_all_peripherals_except_slcd() { MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_SERCOM3; } -void watch_enter_shallow_sleep(char *message) { - if (message != NULL) { - watch_display_string(" ", 0); - watch_display_string(message, 0); - } else { +void watch_enter_shallow_sleep(bool display_on) { + if (!display_on) { slcd_sync_deinit(&SEGMENT_LCD_0); hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); } diff --git a/watch-library/watch/watch_deepsleep.h b/watch-library/watch/watch_deepsleep.h index 3dc428d0..84825f00 100644 --- a/watch-library/watch/watch_deepsleep.h +++ b/watch-library/watch/watch_deepsleep.h @@ -81,13 +81,8 @@ uint32_t watch_get_backup_data(uint8_t reg); * the LCD. You can wake from this mode by pressing the ALARM button, if you have an registered an * external wake callback on the ALARM button. When your app wakes from this shallow sleep mode, your * app_setup method will be called, since this function will have disabled things you set up. - * @param message Either NULL, or a string representing a message to display while in shallow sleep mode. If - * this parameter is NULL, the screen will be blanked out, and this function will disable the - * SLCD peripheral for additional power savings. If the message is non-NULL, it will replace - * any text on the screen, and will be displayed at position 0 (so you should pad out the beginning - * of the string with spaces if you wish for the message to appear on line 2, i.e. " SLEEP"). - * Also note that this function will NOT clear any indicator segments that you have set. This is - * by design, in case you wish to leave an indicator lit in sleep mode. + * @param display_on if true, leaves the LCD on to display whatever content was on-screen. If false, disables + * the segment LCD controller for additional power savings. * @details This shallow sleep mode is not the lowest power mode available (see watch_enter_deep_sleep), but * it has the benefit of retaining your application state and being able to wake from the ALARM button. * It also provides an option for displaying a message to the user when asleep. Note that whether you @@ -96,10 +91,10 @@ uint32_t watch_get_backup_data(uint8_t reg); * * Power consumption in shallow sleep mode varies a bit with the battery voltage and the temperature, * but at 3 V and 25~30° C you can roughly estimate: - * * < 12µA current draw with the LCD controller on (message != NULL) - * * < 6µA current draw with the LCD controller off (message == NULL) + * * < 12µA current draw with the LCD controller on + * * < 6µA current draw with the LCD controller off */ -void watch_enter_shallow_sleep(char *message); +void watch_enter_shallow_sleep(bool display_on); /** @brief Enters the SAM L22's lowest-power mode, BACKUP. * @details This function does some housekeeping before entering BACKUP mode. It first disables all -- cgit v1.2.3 From a6115de94d977da69a6a81f93a92706e76324a37 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 3 Oct 2021 23:39:52 -0400 Subject: disable screensaver interrupt on wake --- launcher/launcher.c | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/launcher.c b/launcher/launcher.c index 0f8f7ead..120e045b 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -61,6 +61,7 @@ void app_wake_from_deep_sleep() { void app_setup() { if (launcher_state.screensaver_ticks != -1) { watch_disable_extwake_interrupt(BTN_ALARM); + watch_rtc_disable_alarm_callback(); watch_enable_external_interrupts(); watch_register_interrupt_callback(BTN_MODE, cb_mode_btn_interrupt, INTERRUPT_TRIGGER_BOTH); -- cgit v1.2.3 From 51e2f0d77d95a6e5c3b1426fbc7874c3a59a5e00 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 00:37:58 -0400 Subject: event type / subsecond refactor --- launcher/launcher.c | 34 ++++++++++++++------------ launcher/launcher.h | 14 +++++++++-- launcher/widgets/clock/simple_clock_widget.c | 11 ++++----- launcher/widgets/clock/simple_clock_widget.h | 2 +- launcher/widgets/fake_widget_1.c | 5 ++-- launcher/widgets/fake_widget_1.h | 2 +- launcher/widgets/fake_widget_2.c | 5 ++-- launcher/widgets/fake_widget_2.h | 2 +- launcher/widgets/settings/preferences_widget.c | 6 ++--- launcher/widgets/settings/preferences_widget.h | 2 +- 10 files changed, 47 insertions(+), 36 deletions(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 120e045b..4211e1ac 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -8,6 +8,7 @@ LauncherState launcher_state; void * widget_contexts[LAUNCHER_NUM_WIDGETS]; const int32_t launcher_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; +LauncherEvent event; void cb_mode_btn_interrupt(); void cb_light_btn_interrupt(); @@ -38,7 +39,9 @@ void launcher_move_to_widget(uint8_t widget_index) { launcher_state.current_widget = widget_index; watch_clear_display(); widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - widgets[launcher_state.current_widget].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]); + event.value = 0; + event.bit.event_type = EVENT_ACTIVATE; + widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); } void launcher_move_to_next_widget() { @@ -79,7 +82,8 @@ void app_setup() { } widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - widgets[0].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, 0, widget_contexts[launcher_state.current_widget]); + event.value = 0; + event.bit.event_type = EVENT_ACTIVATE; } } @@ -89,8 +93,6 @@ void app_prepare_for_sleep() { void app_wake_from_sleep() { } -LauncherEvent event; - bool app_loop() { // play a beep if the widget has changed in response to a user's press of the MODE button if (launcher_state.widget_changed) { @@ -128,14 +130,16 @@ bool app_loop() { alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); - widgets[launcher_state.current_widget].loop(EVENT_SCREENSAVER, &launcher_state.launcher_settings, 0, widget_contexts[launcher_state.current_widget]); - event = EVENT_SCREENSAVER; + event.value = 0; + event.bit.event_type = EVENT_SCREENSAVER; + widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); watch_enter_shallow_sleep(true); } - if (event) { - widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]); - event = 0; + if (event.bit.event_type) { + event.bit.subsecond = launcher_state.subsecond; + widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + event.value = 0; } @@ -144,7 +148,7 @@ bool app_loop() { return true; } -LauncherEvent _figure_out_button_event(LauncherEvent button_down_event, uint8_t *down_timestamp) { +LauncherEventType _figure_out_button_event(LauncherEventType button_down_event, 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; @@ -159,17 +163,17 @@ LauncherEvent _figure_out_button_event(LauncherEvent button_down_event, uint8_t void cb_light_btn_interrupt() { _launcher_reset_screensaver_countdown(); - event = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); + event.bit.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); } void cb_mode_btn_interrupt() { _launcher_reset_screensaver_countdown(); - event = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); + event.bit.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); } void cb_alarm_btn_interrupt() { _launcher_reset_screensaver_countdown(); - event = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); + event.bit.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); } void cb_alarm_btn_extwake() { @@ -180,11 +184,11 @@ void cb_alarm_btn_extwake() { } void cb_alarm_fired() { - event = EVENT_SCREENSAVER; + event.bit.event_type = EVENT_SCREENSAVER; } void cb_tick() { - event = EVENT_TICK; + event.bit.event_type = EVENT_TICK; watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.second != launcher_state.last_second) { if (launcher_state.light_ticks) launcher_state.light_ticks--; diff --git a/launcher/launcher.h b/launcher/launcher.h index 09b33dbb..d6ebbc2c 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -21,7 +21,7 @@ typedef union { uint32_t value; } LauncherSettings; -typedef enum LauncherEvent { +typedef enum { EVENT_NONE = 0, // There is no event to report. EVENT_ACTIVATE, // Your widget is entering the foreground. EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. @@ -35,11 +35,21 @@ typedef enum LauncherEvent { EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released. EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released. EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released. +} LauncherEventType; + +typedef union { + struct { + uint32_t event_type : 8; + uint32_t subsecond : 8; + uint32_t reserved : 16; + } bit; + uint32_t value; } LauncherEvent; + typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context); -typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context); typedef struct WatchWidget { diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c index 29a53b41..427793f3 100644 --- a/launcher/widgets/clock/simple_clock_widget.c +++ b/launcher/widgets/clock/simple_clock_widget.c @@ -17,16 +17,15 @@ void simple_clock_widget_activate(LauncherSettings *settings, void *context) { *((uint32_t *)context) = 0xFFFFFFFF; } -void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { +void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("simple_clock_widget_loop\n"); - (void) subsecond; const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; char buf[11]; uint8_t pos; watch_date_time date_time; uint32_t previous_date_time; - switch (event) { + switch (event.bit.event_type) { case EVENT_ACTIVATE: case EVENT_TICK: case EVENT_SCREENSAVER: @@ -34,11 +33,11 @@ void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, u previous_date_time = *((uint32_t *)context); *((uint32_t *)context) = date_time.reg; - if (date_time.reg >> 6 == previous_date_time >> 6 && event != EVENT_SCREENSAVER) { + if (date_time.reg >> 6 == previous_date_time >> 6 && event.bit.event_type != EVENT_SCREENSAVER) { // everything before seconds is the same, don't waste cycles setting those segments. pos = 8; sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12 && event != EVENT_SCREENSAVER) { + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.bit.event_type != EVENT_SCREENSAVER) { // everything before minutes is the same. pos = 6; sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); @@ -55,7 +54,7 @@ void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, u if (date_time.unit.hour == 0) date_time.unit.hour = 12; } pos = 0; - if (event == EVENT_SCREENSAVER) { + if (event.bit.event_type == EVENT_SCREENSAVER) { sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); } else { sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); diff --git a/launcher/widgets/clock/simple_clock_widget.h b/launcher/widgets/clock/simple_clock_widget.h index 459721b9..42b0d3c5 100644 --- a/launcher/widgets/clock/simple_clock_widget.h +++ b/launcher/widgets/clock/simple_clock_widget.h @@ -5,7 +5,7 @@ void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr); void simple_clock_widget_activate(LauncherSettings *settings, void *context); -void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); void simple_clock_widget_resign(LauncherSettings *settings, void *context); uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year); diff --git a/launcher/widgets/fake_widget_1.c b/launcher/widgets/fake_widget_1.c index 15ffcbd2..65324095 100644 --- a/launcher/widgets/fake_widget_1.c +++ b/launcher/widgets/fake_widget_1.c @@ -11,14 +11,13 @@ void fake_widget_1_activate(LauncherSettings *settings, void *context) { (void) context; } -void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { +void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("fake_widget_1_loop\n"); (void) settings; - (void) subsecond; (void) context; watch_display_string("W1 d get01", 0); - switch (event) { + switch (event.bit.event_type) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); return; diff --git a/launcher/widgets/fake_widget_1.h b/launcher/widgets/fake_widget_1.h index 18180156..24704f23 100644 --- a/launcher/widgets/fake_widget_1.h +++ b/launcher/widgets/fake_widget_1.h @@ -5,7 +5,7 @@ void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr); void fake_widget_1_activate(LauncherSettings *settings, void *context); -void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context); void fake_widget_1_resign(LauncherSettings *settings, void *context); #define fake_widget_1 { \ diff --git a/launcher/widgets/fake_widget_2.c b/launcher/widgets/fake_widget_2.c index f3ffc14b..a6eafb7b 100644 --- a/launcher/widgets/fake_widget_2.c +++ b/launcher/widgets/fake_widget_2.c @@ -11,14 +11,13 @@ void fake_widget_2_activate(LauncherSettings *settings, void *context) { (void) context; } -void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { +void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("fake_widget_2_loop\n"); (void) settings; - (void) subsecond; (void) context; watch_display_string("W1 d get02", 0); - switch (event) { + switch (event.bit.event_type) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); return; diff --git a/launcher/widgets/fake_widget_2.h b/launcher/widgets/fake_widget_2.h index 1f6bd503..945e28fa 100644 --- a/launcher/widgets/fake_widget_2.h +++ b/launcher/widgets/fake_widget_2.h @@ -5,7 +5,7 @@ void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr); void fake_widget_2_activate(LauncherSettings *settings, void *context); -void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context); void fake_widget_2_resign(LauncherSettings *settings, void *context); #define fake_widget_2 { \ diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c index 5877c237..d4abeb8e 100644 --- a/launcher/widgets/settings/preferences_widget.c +++ b/launcher/widgets/settings/preferences_widget.c @@ -16,12 +16,12 @@ void preferences_widget_activate(LauncherSettings *settings, void *context) { launcher_request_tick_frequency(4); // we need to manually blink some pixels } -void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) { +void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { (void) settings; (void) context; printf("preferences_widget_loop\n"); uint8_t current_page = *((uint8_t *)context); - switch (event) { + switch (event.bit.event_type) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); return; @@ -63,7 +63,7 @@ void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, ui watch_set_led_off(); } - if (subsecond % 2) return; + if (event.bit.subsecond % 2) return; char buf[3]; switch (current_page) { case 0: diff --git a/launcher/widgets/settings/preferences_widget.h b/launcher/widgets/settings/preferences_widget.h index fcbcd0d6..e2e27fc7 100644 --- a/launcher/widgets/settings/preferences_widget.h +++ b/launcher/widgets/settings/preferences_widget.h @@ -5,7 +5,7 @@ void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr); void preferences_widget_activate(LauncherSettings *settings, void *context); -void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context); +void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); void preferences_widget_resign(LauncherSettings *settings, void *context); #define preferences_widget { \ -- cgit v1.2.3 From c1ec7734c910d1eef74ebc3647dc084eeb43bbcf Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 09:51:49 -0400 Subject: launcher: let widgets prevent sleep --- launcher/launcher.c | 26 ++++++++++++-------------- launcher/launcher.h | 3 ++- launcher/widgets/clock/simple_clock_widget.c | 6 ++++-- launcher/widgets/clock/simple_clock_widget.h | 2 +- launcher/widgets/fake_widget_1.c | 6 ++++-- launcher/widgets/fake_widget_1.h | 2 +- launcher/widgets/fake_widget_2.c | 6 ++++-- launcher/widgets/fake_widget_2.h | 2 +- launcher/widgets/settings/preferences_widget.c | 24 +++++++++++++----------- launcher/widgets/settings/preferences_widget.h | 2 +- 10 files changed, 43 insertions(+), 36 deletions(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 4211e1ac..20fd7e59 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -35,13 +35,7 @@ void launcher_illuminate_led() { void launcher_move_to_widget(uint8_t widget_index) { launcher_state.widget_changed = true; - widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - launcher_state.current_widget = widget_index; - watch_clear_display(); - widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - event.value = 0; - event.bit.event_type = EVENT_ACTIVATE; - widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + launcher_state.next_widget = widget_index; } void launcher_move_to_next_widget() { @@ -94,12 +88,17 @@ void app_wake_from_sleep() { } bool app_loop() { - // play a beep if the widget has changed in response to a user's press of the MODE button if (launcher_state.widget_changed) { - // low note for nonzero case, high note for return to widget 0 if (launcher_state.launcher_settings.bit.button_should_sound) { + // low note for nonzero case, high note for return to widget 0 watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); } + widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + launcher_state.current_widget = launcher_state.next_widget; + watch_clear_display(); + widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + event.value = 0; + event.bit.event_type = EVENT_ACTIVATE; launcher_state.widget_changed = false; } @@ -136,16 +135,15 @@ bool app_loop() { watch_enter_shallow_sleep(true); } + bool can_sleep = true; + if (event.bit.event_type) { event.bit.subsecond = launcher_state.subsecond; - widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + can_sleep = widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); event.value = 0; } - - if (launcher_state.led_on) return false; - - return true; + return can_sleep && !launcher_state.led_on; } LauncherEventType _figure_out_button_event(LauncherEventType button_down_event, uint8_t *down_timestamp) { diff --git a/launcher/launcher.h b/launcher/launcher.h index d6ebbc2c..97c56545 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -49,7 +49,7 @@ typedef union { typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context); -typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); +typedef bool (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context); typedef struct WatchWidget { @@ -65,6 +65,7 @@ typedef struct LauncherState { // transient properties int16_t current_widget; + int16_t next_widget; bool widget_changed; // LED stuff diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c index 427793f3..83b5a713 100644 --- a/launcher/widgets/clock/simple_clock_widget.c +++ b/launcher/widgets/clock/simple_clock_widget.c @@ -17,7 +17,7 @@ void simple_clock_widget_activate(LauncherSettings *settings, void *context) { *((uint32_t *)context) = 0xFFFFFFFF; } -void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("simple_clock_widget_loop\n"); const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; char buf[11]; @@ -64,7 +64,7 @@ void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, v break; case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); - return; + return false; case EVENT_LIGHT_BUTTON_UP: launcher_illuminate_led(); break; @@ -73,6 +73,8 @@ void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, v default: break; } + + return true; } void simple_clock_widget_resign(LauncherSettings *settings, void *context) { diff --git a/launcher/widgets/clock/simple_clock_widget.h b/launcher/widgets/clock/simple_clock_widget.h index 42b0d3c5..739c942b 100644 --- a/launcher/widgets/clock/simple_clock_widget.h +++ b/launcher/widgets/clock/simple_clock_widget.h @@ -5,7 +5,7 @@ void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr); void simple_clock_widget_activate(LauncherSettings *settings, void *context); -void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); void simple_clock_widget_resign(LauncherSettings *settings, void *context); uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year); diff --git a/launcher/widgets/fake_widget_1.c b/launcher/widgets/fake_widget_1.c index 65324095..bdc964e2 100644 --- a/launcher/widgets/fake_widget_1.c +++ b/launcher/widgets/fake_widget_1.c @@ -11,7 +11,7 @@ void fake_widget_1_activate(LauncherSettings *settings, void *context) { (void) context; } -void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("fake_widget_1_loop\n"); (void) settings; (void) context; @@ -20,13 +20,15 @@ void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *c switch (event.bit.event_type) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); - return; + return false; case EVENT_LIGHT_BUTTON_UP: launcher_illuminate_led(); break; default: break; } + + return true; } void fake_widget_1_resign(LauncherSettings *settings, void *context) { diff --git a/launcher/widgets/fake_widget_1.h b/launcher/widgets/fake_widget_1.h index 24704f23..d033b49a 100644 --- a/launcher/widgets/fake_widget_1.h +++ b/launcher/widgets/fake_widget_1.h @@ -5,7 +5,7 @@ void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr); void fake_widget_1_activate(LauncherSettings *settings, void *context); -void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context); +bool fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context); void fake_widget_1_resign(LauncherSettings *settings, void *context); #define fake_widget_1 { \ diff --git a/launcher/widgets/fake_widget_2.c b/launcher/widgets/fake_widget_2.c index a6eafb7b..46772222 100644 --- a/launcher/widgets/fake_widget_2.c +++ b/launcher/widgets/fake_widget_2.c @@ -11,7 +11,7 @@ void fake_widget_2_activate(LauncherSettings *settings, void *context) { (void) context; } -void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("fake_widget_2_loop\n"); (void) settings; (void) context; @@ -20,13 +20,15 @@ void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *c switch (event.bit.event_type) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); - return; + return false; case EVENT_LIGHT_BUTTON_UP: launcher_illuminate_led(); break; default: break; } + + return true; } void fake_widget_2_resign(LauncherSettings *settings, void *context) { diff --git a/launcher/widgets/fake_widget_2.h b/launcher/widgets/fake_widget_2.h index 945e28fa..cf01969d 100644 --- a/launcher/widgets/fake_widget_2.h +++ b/launcher/widgets/fake_widget_2.h @@ -5,7 +5,7 @@ void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr); void fake_widget_2_activate(LauncherSettings *settings, void *context); -void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context); +bool fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context); void fake_widget_2_resign(LauncherSettings *settings, void *context); #define fake_widget_2 { \ diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c index d4abeb8e..878b775b 100644 --- a/launcher/widgets/settings/preferences_widget.c +++ b/launcher/widgets/settings/preferences_widget.c @@ -16,15 +16,16 @@ void preferences_widget_activate(LauncherSettings *settings, void *context) { launcher_request_tick_frequency(4); // we need to manually blink some pixels } -void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { (void) settings; (void) context; printf("preferences_widget_loop\n"); uint8_t current_page = *((uint8_t *)context); switch (event.bit.event_type) { case EVENT_MODE_BUTTON_UP: + watch_set_led_off(); launcher_move_to_next_widget(); - return; + return false; case EVENT_LIGHT_BUTTON_UP: current_page = (current_page + 1) % PREFERENCES_WIDGET_NUM_PREFEFENCES; *((uint8_t *)context) = current_page; @@ -54,16 +55,8 @@ void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, vo watch_clear_display(); watch_display_string((char *)preferences_widget_titles[current_page], 0); - if (current_page > 2) { - // this is a hack, launcher should be able to illumate with a custom color. - launcher_illuminate_led(); - watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, - settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); - } else { - watch_set_led_off(); - } - if (event.bit.subsecond % 2) return; + if (event.bit.subsecond % 2) return current_page <= 2; char buf[3]; switch (current_page) { case 0: @@ -111,6 +104,15 @@ void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, vo watch_display_string(buf, 8); break; } + + if (current_page > 2) { + watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, + settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); + return false; + } + + watch_set_led_off(); + return true; } void preferences_widget_resign(LauncherSettings *settings, void *context) { diff --git a/launcher/widgets/settings/preferences_widget.h b/launcher/widgets/settings/preferences_widget.h index e2e27fc7..11a189f8 100644 --- a/launcher/widgets/settings/preferences_widget.h +++ b/launcher/widgets/settings/preferences_widget.h @@ -5,7 +5,7 @@ void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr); void preferences_widget_activate(LauncherSettings *settings, void *context); -void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); void preferences_widget_resign(LauncherSettings *settings, void *context); #define preferences_widget { \ -- cgit v1.2.3 From 7f8973a8cc55e37cd8e2d59f7eab2def0045d2a6 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 10:48:04 -0400 Subject: slcd: add more special cases --- watch-library/watch/watch_slcd.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c index c1e24308..fc8c255a 100644 --- a/watch-library/watch/watch_slcd.c +++ b/watch-library/watch/watch_slcd.c @@ -114,8 +114,8 @@ static const uint8_t Character_Set[] = 0b01010000, // r 0b01101101, // s 0b01111000, // t - 0b01100010, // u (appears as superscript to work in more positions) - 0b01100010, // v (appears as superscript to work in more positions) + 0b01100010, // u (appears in (u)pper half to work in more positions) + 0b00011100, // v (looks like u but in the lower half) 0b10111110, // w (only works in position 0) 0b01111110, // x 0b01101110, // y @@ -169,8 +169,16 @@ void watch_clear_display() { } void watch_display_character(uint8_t character, uint8_t position) { - // handle lowercase 7 if needed - if (character == '7' && (position == 4 || position == 6)) character = '&'; + // special cases for positions 4 and 6 + if (position == 4 || position == 6) { + if (character == '7') character = '&'; // "lowercase" 7 + if (character == 'v') character = 'u'; // bottom segment duplicated, so show in top half + if (character == 'J') character = 'j'; // same + } else if (position != 4 && position != 6) { + if (character == 'u') character = 'v'; // we can use the bottom segment; move to lower half + if (character == 'j') character = 'J'; // same but just display a normal J + } + if (position == 0) slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(0, 15)); // clear funky ninth segment uint64_t segmap = Segment_Map[position]; uint64_t segdata = Character_Set[character - 0x20]; @@ -189,7 +197,8 @@ void watch_display_character(uint8_t character, uint8_t position) { segmap = segmap >> 8; segdata = segdata >> 1; } - if (character == 'T' && position == 1) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(1, 12)); + if (character == 'T' && position == 1) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(1, 12)); // add descender + else if (position == 0 && (character == 'B' || character == 'D')) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(0, 15)); // add funky ninth segment } void watch_display_string(char *string, uint8_t position) { -- cgit v1.2.3 From 0546859073a3e57ed724e4eb1d741a438a175638 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 11:09:11 -0400 Subject: launcher: improvements to screensaver mode --- launcher/launcher.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 20fd7e59..43921106 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -130,9 +130,19 @@ bool app_loop() { watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); event.value = 0; - event.bit.event_type = EVENT_SCREENSAVER; - widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - watch_enter_shallow_sleep(true); + + // this is a little mini-runloop. + // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. + while (launcher_state.screensaver_ticks == -1) { + event.bit.event_type = EVENT_SCREENSAVER; + widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + watch_enter_shallow_sleep(true); + } + // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. + event.bit.event_type = EVENT_ACTIVATE; + // this is a hack tho: waking from shallow sleep, app_setup does get called, but it happens before we have reset our ticks. + // need to figure out if there's a better heuristic for determining how we woke up. + app_setup(); } bool can_sleep = true; @@ -175,10 +185,8 @@ void cb_alarm_btn_interrupt() { } void cb_alarm_btn_extwake() { + // wake up! _launcher_reset_screensaver_countdown(); - // this is a hack: waking from shallow sleep, app_setup does get called, but it happens before we reset our ticks. - // need to figure out if there's a better heuristic for determining how we woke up. - app_setup(); } void cb_alarm_fired() { -- cgit v1.2.3 From 0b60edb2659dfacf729a29f7aea7dab2bfa22160 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 11:57:29 -0400 Subject: launcher: fix typo --- launcher/launcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 43921106..38a13b5c 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -75,7 +75,7 @@ void app_setup() { widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]); } - widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); + widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); event.value = 0; event.bit.event_type = EVENT_ACTIVATE; } -- cgit v1.2.3 From 74e866250920cb35b4575e0cdad47f63d4ae871d Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 11:57:57 -0400 Subject: launcher: track can_sleep between runloop invocations --- launcher/launcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 38a13b5c..d6883567 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -145,7 +145,7 @@ bool app_loop() { app_setup(); } - bool can_sleep = true; + static bool can_sleep = true; if (event.bit.event_type) { event.bit.subsecond = launcher_state.subsecond; -- cgit v1.2.3 From 95e95bb980d39c57544195715d508b6ccaee054d Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 11:59:08 -0400 Subject: launcher: fix flickering in preferences widget --- launcher/widgets/settings/preferences_widget.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c index 878b775b..7e583c81 100644 --- a/launcher/widgets/settings/preferences_widget.c +++ b/launcher/widgets/settings/preferences_widget.c @@ -3,7 +3,7 @@ #include "watch.h" #define PREFERENCES_WIDGET_NUM_PREFEFENCES (5) -const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL", "Bt Beep", "SC", "Lt grn", "Lt red"}; +const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; @@ -17,8 +17,6 @@ void preferences_widget_activate(LauncherSettings *settings, void *context) { } bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - (void) settings; - (void) context; printf("preferences_widget_loop\n"); uint8_t current_page = *((uint8_t *)context); switch (event.bit.event_type) { @@ -53,7 +51,6 @@ bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, vo break; } - watch_clear_display(); watch_display_string((char *)preferences_widget_titles[current_page], 0); if (event.bit.subsecond % 2) return current_page <= 2; -- cgit v1.2.3 From 110c81cbed94340f54fa890af94523f7a6135493 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 14:11:39 -0400 Subject: preferences widget: fix alignment of 'never' --- launcher/widgets/settings/preferences_widget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c index 7e583c81..79508ab3 100644 --- a/launcher/widgets/settings/preferences_widget.c +++ b/launcher/widgets/settings/preferences_widget.c @@ -67,7 +67,7 @@ bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, vo case 2: switch (settings->bit.screensaver_interval) { case 0: - watch_display_string("never", 4); + watch_display_string(" never", 4); break; case 1: watch_display_string("1 hour", 4); -- cgit v1.2.3 From 58cf2e75856c8a3aaee9619835bff16e97026a86 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 14:12:15 -0400 Subject: launcher: add widget for setting the time --- launcher/launcher_config.h | 6 +- launcher/make/Makefile | 1 + launcher/widgets/settings/set_time_widget.c | 109 ++++++++++++++++++++++++++++ launcher/widgets/settings/set_time_widget.h | 18 +++++ 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 launcher/widgets/settings/set_time_widget.c create mode 100644 launcher/widgets/settings/set_time_widget.h diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h index 9bc43c47..ab0f6ea3 100644 --- a/launcher/launcher_config.h +++ b/launcher/launcher_config.h @@ -3,16 +3,16 @@ #include "simple_clock_widget.h" #include "preferences_widget.h" +#include "set_time_widget.h" #include "fake_widget_1.h" #include "fake_widget_2.h" -#define LAUNCHER_NUM_WIDGETS 4 +#define LAUNCHER_NUM_WIDGETS 3 WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = { simple_clock_widget, preferences_widget, - fake_widget_1, - fake_widget_2, + set_time_widget, }; diff --git a/launcher/make/Makefile b/launcher/make/Makefile index 4fba0351..2f35f58c 100755 --- a/launcher/make/Makefile +++ b/launcher/make/Makefile @@ -24,6 +24,7 @@ SRCS += \ ../launcher.c \ ../widgets/clock/simple_clock_widget.c \ ../widgets/settings/preferences_widget.c \ + ../widgets/settings/set_time_widget.c \ ../widgets/fake_widget_1.c \ ../widgets/fake_widget_2.c \ diff --git a/launcher/widgets/settings/set_time_widget.c b/launcher/widgets/settings/set_time_widget.c new file mode 100644 index 00000000..c65459ab --- /dev/null +++ b/launcher/widgets/settings/set_time_widget.c @@ -0,0 +1,109 @@ +#include +#include "set_time_widget.h" +#include "watch.h" + +#define SET_TIME_WIDGET_NUM_SETTINGS (6) +const char set_time_widget_titles[SET_TIME_WIDGET_NUM_SETTINGS][3] = {"HR", "MN", "SE", "YR", "MO", "DA"}; + +void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + *context_ptr = malloc(sizeof(uint8_t)); +} + +void set_time_widget_activate(LauncherSettings *settings, void *context) { + (void) settings; + *((uint8_t *)context) = 0; + launcher_request_tick_frequency(4); +} + +bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + uint8_t current_page = *((uint8_t *)context); + const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; + watch_date_time date_time = watch_rtc_get_date_time(); + + switch (event.bit.event_type) { + case EVENT_MODE_BUTTON_UP: + launcher_move_to_next_widget(); + return false; + case EVENT_LIGHT_BUTTON_UP: + current_page = (current_page + 1) % SET_TIME_WIDGET_NUM_SETTINGS; + *((uint8_t *)context) = current_page; + break; + case EVENT_ALARM_BUTTON_UP: + switch (current_page) { + case 0: // hour + date_time.unit.hour = (date_time.unit.hour + 1) % 24; + break; + case 1: // minute + date_time.unit.minute = (date_time.unit.minute + 1) % 60; + break; + case 2: // second + date_time.unit.second = 0; + break; + case 3: // year + // only allow 2021-2030. fix this sometime next decade + date_time.unit.year = ((date_time.unit.year % 10) + 1); + break; + case 4: // month + date_time.unit.month = (date_time.unit.month % 12) + 1; + break; + case 5: // day + date_time.unit.day = date_time.unit.day + 1; + // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. + // and it should roll over. + if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { + date_time.unit.day = 1; + } + break; + } + watch_rtc_set_date_time(date_time); + break; + default: + break; + } + + char buf[11]; + if (current_page < 3) { + watch_set_colon(); + if (settings->bit.clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } else { + sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second); + if (date_time.unit.hour > 12) watch_set_indicator(WATCH_INDICATOR_PM); + else watch_clear_indicator(WATCH_INDICATOR_PM); + } + } else { + watch_clear_colon(); + watch_clear_indicator(WATCH_INDICATOR_24H); + watch_clear_indicator(WATCH_INDICATOR_PM); + sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day); + } + if (event.bit.subsecond % 2) { + switch (current_page) { + case 0: + case 3: + buf[4] = buf[5] = ' '; + break; + case 1: + case 4: + buf[6] = buf[7] = ' '; + break; + case 2: + case 5: + buf[8] = buf[9] = ' '; + break; + } + } + + watch_display_string(buf, 0); + + return true; +} + +void set_time_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + watch_set_led_off(); + launcher_request_tick_frequency(1); +} diff --git a/launcher/widgets/settings/set_time_widget.h b/launcher/widgets/settings/set_time_widget.h new file mode 100644 index 00000000..dc492dce --- /dev/null +++ b/launcher/widgets/settings/set_time_widget.h @@ -0,0 +1,18 @@ +#ifndef SET_TIME_WIDGET_H_ +#define SET_TIME_WIDGET_H_ + +#include "launcher.h" + +void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr); +void set_time_widget_activate(LauncherSettings *settings, void *context); +bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void set_time_widget_resign(LauncherSettings *settings, void *context); + +#define set_time_widget { \ + set_time_widget_setup, \ + set_time_widget_activate, \ + set_time_widget_loop, \ + set_time_widget_resign, \ +} + +#endif // SET_TIME_WIDGET_H_ -- cgit v1.2.3 From 83192b3a580c19eb694ca7951650db87eeb582ad Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 4 Oct 2021 15:27:29 -0400 Subject: launcher: fix high beep on return to clock --- launcher/launcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index d6883567..160b8d2a 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -91,7 +91,7 @@ bool app_loop() { if (launcher_state.widget_changed) { if (launcher_state.launcher_settings.bit.button_should_sound) { // low note for nonzero case, high note for return to widget 0 - watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); + watch_buzzer_play_note(launcher_state.next_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); } widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); launcher_state.current_widget = launcher_state.next_widget; -- cgit v1.2.3 From 8372e37bea5313a131054081e84fe7e9a45f32a9 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 5 Oct 2021 15:55:34 -0400 Subject: fix memory leak when waking from screensaver mode --- launcher/launcher.c | 8 ++++++++ launcher/widgets/clock/simple_clock_widget.c | 2 +- launcher/widgets/settings/preferences_widget.c | 2 +- launcher/widgets/settings/set_time_widget.c | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 160b8d2a..7d87c58a 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -56,6 +56,14 @@ void app_wake_from_deep_sleep() { } void app_setup() { + static bool is_first_launch = true; + + if (is_first_launch) { + for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { + widget_contexts[i] = NULL; + is_first_launch = false; + } + } if (launcher_state.screensaver_ticks != -1) { watch_disable_extwake_interrupt(BTN_ALARM); watch_rtc_disable_alarm_callback(); diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c index 83b5a713..0c89cbc2 100644 --- a/launcher/widgets/clock/simple_clock_widget.c +++ b/launcher/widgets/clock/simple_clock_widget.c @@ -5,7 +5,7 @@ void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; // the only context we need is the timestamp of the previous tick. - *context_ptr = malloc(sizeof(uint32_t)); + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint32_t)); } void simple_clock_widget_activate(LauncherSettings *settings, void *context) { diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c index 79508ab3..40e0ac50 100644 --- a/launcher/widgets/settings/preferences_widget.c +++ b/launcher/widgets/settings/preferences_widget.c @@ -7,7 +7,7 @@ const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = { void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; - *context_ptr = malloc(sizeof(uint8_t)); + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); } void preferences_widget_activate(LauncherSettings *settings, void *context) { diff --git a/launcher/widgets/settings/set_time_widget.c b/launcher/widgets/settings/set_time_widget.c index c65459ab..c7949a4f 100644 --- a/launcher/widgets/settings/set_time_widget.c +++ b/launcher/widgets/settings/set_time_widget.c @@ -7,7 +7,7 @@ const char set_time_widget_titles[SET_TIME_WIDGET_NUM_SETTINGS][3] = {"HR", "MN" void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; - *context_ptr = malloc(sizeof(uint8_t)); + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); } void set_time_widget_activate(LauncherSettings *settings, void *context) { -- cgit v1.2.3 From 0f349cb52e7436303f61a3dd2dde2f40d3dc05c3 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 5 Oct 2021 17:58:49 -0400 Subject: add pulseometer widget --- launcher/launcher_config.h | 1 + launcher/make/Makefile | 2 + .../widgets/complications/pulseometer_widget.c | 83 ++++++++++++++++++++++ .../widgets/complications/pulseometer_widget.h | 24 +++++++ 4 files changed, 110 insertions(+) create mode 100644 launcher/widgets/complications/pulseometer_widget.c create mode 100644 launcher/widgets/complications/pulseometer_widget.h diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h index ab0f6ea3..5280b989 100644 --- a/launcher/launcher_config.h +++ b/launcher/launcher_config.h @@ -4,6 +4,7 @@ #include "simple_clock_widget.h" #include "preferences_widget.h" #include "set_time_widget.h" +#include "pulseometer_widget.h" #include "fake_widget_1.h" #include "fake_widget_2.h" diff --git a/launcher/make/Makefile b/launcher/make/Makefile index 2f35f58c..c6d18137 100755 --- a/launcher/make/Makefile +++ b/launcher/make/Makefile @@ -13,6 +13,7 @@ INCLUDES += \ -I../widgets/ \ -I../widgets/clock/ \ -I../widgets/settings/ \ + -I../widgets/complications/ \ # If you add any other source files you wish to compile, add them after ../app.c # Note that you will need to add a backslash at the end of any line you wish to continue, i.e. @@ -25,6 +26,7 @@ SRCS += \ ../widgets/clock/simple_clock_widget.c \ ../widgets/settings/preferences_widget.c \ ../widgets/settings/set_time_widget.c \ + ../widgets/complications/pulseometer_widget.c \ ../widgets/fake_widget_1.c \ ../widgets/fake_widget_2.c \ diff --git a/launcher/widgets/complications/pulseometer_widget.c b/launcher/widgets/complications/pulseometer_widget.c new file mode 100644 index 00000000..3df1cb44 --- /dev/null +++ b/launcher/widgets/complications/pulseometer_widget.c @@ -0,0 +1,83 @@ +#include +#include +#include "pulseometer_widget.h" +#include "watch.h" + +void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); +} + +void pulseometer_widget_activate(LauncherSettings *settings, void *context) { + (void) settings; + memset(context, 0, sizeof(PulsometerState)); +} + +bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("pulseometer_widget_loop\n"); + (void) settings; + PulsometerState *pulsometer_state = (PulsometerState *)context; + char buf[14]; + // starts at index 15 + const uint8_t pulse_lookup[] = {240, 225, 212, 200, 189, 180, 171, 164, 157, 150, 144, 138, 133, 129, 124, 120, 116, 113, 109, 106, 103, 100, 97, 95, 92, 90, 88, 86, 84, 82, 80, 78, 77, 75, 73, 72, 71, 69, 68, 67, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 55, 54, 53, 52, 51, 51, 50, 49, 49, 48, 47, 47, 46, 46, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, 40, 40}; + switch (event.bit.event_type) { + case EVENT_TICK: + if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { + switch (pulsometer_state->ticks % 5) { + case 0: + watch_display_string(" Hold ", 2); + break; + case 1: + watch_display_string(" Alarn", 4); + break; + case 2: + watch_display_string("+ Count ", 0); + break; + case 3: + watch_display_string(" 30Beats ", 0); + break; + case 4: + watch_clear_display(); + break; + } + pulsometer_state->ticks++; + } else { + if (pulsometer_state->ticks < 15) { + watch_display_string(" Lo", 0); + } else if (pulsometer_state->ticks > 91) { + watch_display_string(" Hi", 0); + } else { + if (pulsometer_state->measuring) pulsometer_state->pulse = pulse_lookup[pulsometer_state->ticks - 15]; + sprintf(buf, " %-3dbpn", pulsometer_state->pulse); + watch_display_string(buf, 0); + } + if (pulsometer_state->measuring) pulsometer_state->ticks++; + } + return false; + case EVENT_MODE_BUTTON_UP: + launcher_move_to_next_widget(); + return false; + case EVENT_LIGHT_BUTTON_UP: + launcher_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_DOWN: + pulsometer_state->ticks = 0; + pulsometer_state->measuring = true; + launcher_request_tick_frequency(2); + break; + case EVENT_ALARM_BUTTON_UP: + case EVENT_ALARM_LONG_PRESS: + pulsometer_state->measuring = false; + launcher_request_tick_frequency(1); + break; + default: + break; + } + + return true; +} + +void pulseometer_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/launcher/widgets/complications/pulseometer_widget.h b/launcher/widgets/complications/pulseometer_widget.h new file mode 100644 index 00000000..5b18d7f3 --- /dev/null +++ b/launcher/widgets/complications/pulseometer_widget.h @@ -0,0 +1,24 @@ +#ifndef PULSEOMETER_WIDGET_H_ +#define PULSEOMETER_WIDGET_H_ + +#include "launcher.h" + +typedef struct { + bool measuring; + int16_t pulse; + int16_t ticks; +} PulsometerState; + +void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr); +void pulseometer_widget_activate(LauncherSettings *settings, void *context); +bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void pulseometer_widget_resign(LauncherSettings *settings, void *context); + +#define pulseometer_widget { \ + pulseometer_widget_setup, \ + pulseometer_widget_activate, \ + pulseometer_widget_loop, \ + pulseometer_widget_resign, \ +} + +#endif // PULSEOMETER_WIDGET_H_ \ No newline at end of file -- cgit v1.2.3 From 12ee9221354c863bddb21a076dd3e3bdface3c67 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 5 Oct 2021 18:01:26 -0400 Subject: remove fake / placeholder widgets --- launcher/launcher_config.h | 2 -- launcher/make/Makefile | 10 ++++------ launcher/widgets/fake_widget_1.c | 37 ------------------------------------- launcher/widgets/fake_widget_1.h | 18 ------------------ launcher/widgets/fake_widget_2.c | 37 ------------------------------------- launcher/widgets/fake_widget_2.h | 18 ------------------ 6 files changed, 4 insertions(+), 118 deletions(-) delete mode 100644 launcher/widgets/fake_widget_1.c delete mode 100644 launcher/widgets/fake_widget_1.h delete mode 100644 launcher/widgets/fake_widget_2.c delete mode 100644 launcher/widgets/fake_widget_2.h diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h index 5280b989..ff656350 100644 --- a/launcher/launcher_config.h +++ b/launcher/launcher_config.h @@ -5,8 +5,6 @@ #include "preferences_widget.h" #include "set_time_widget.h" #include "pulseometer_widget.h" -#include "fake_widget_1.h" -#include "fake_widget_2.h" #define LAUNCHER_NUM_WIDGETS 3 diff --git a/launcher/make/Makefile b/launcher/make/Makefile index c6d18137..a1059bbd 100755 --- a/launcher/make/Makefile +++ b/launcher/make/Makefile @@ -7,7 +7,7 @@ include $(TOP)/make.mk # INCLUDES += \ # -I../ \ # -I../drivers/ \ -# -I../utils/ +# -I../widgets/fitness/ INCLUDES += \ -I../ \ -I../widgets/ \ @@ -18,17 +18,15 @@ INCLUDES += \ # If you add any other source files you wish to compile, add them after ../app.c # Note that you will need to add a backslash at the end of any line you wish to continue, i.e. # SRCS += \ -# ../app.c \ -# ../drivers/bmp280.c \ -# ../utils/temperature.c +# ../launcher.c \ +# ../drivers/lis2dh.c \ +# ../widgets/fitness/step_count_widget.c SRCS += \ ../launcher.c \ ../widgets/clock/simple_clock_widget.c \ ../widgets/settings/preferences_widget.c \ ../widgets/settings/set_time_widget.c \ ../widgets/complications/pulseometer_widget.c \ - ../widgets/fake_widget_1.c \ - ../widgets/fake_widget_2.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/launcher/widgets/fake_widget_1.c b/launcher/widgets/fake_widget_1.c deleted file mode 100644 index bdc964e2..00000000 --- a/launcher/widgets/fake_widget_1.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "fake_widget_1.h" -#include "watch.h" - -void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - *context_ptr = NULL; -} - -void fake_widget_1_activate(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} - -bool fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("fake_widget_1_loop\n"); - (void) settings; - (void) context; - watch_display_string("W1 d get01", 0); - - switch (event.bit.event_type) { - case EVENT_MODE_BUTTON_UP: - launcher_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - launcher_illuminate_led(); - break; - default: - break; - } - - return true; -} - -void fake_widget_1_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} diff --git a/launcher/widgets/fake_widget_1.h b/launcher/widgets/fake_widget_1.h deleted file mode 100644 index d033b49a..00000000 --- a/launcher/widgets/fake_widget_1.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FAKE_WIDGET_1_H_ -#define FAKE_WIDGET_1_H_ - -#include "launcher.h" - -void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr); -void fake_widget_1_activate(LauncherSettings *settings, void *context); -bool fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void fake_widget_1_resign(LauncherSettings *settings, void *context); - -#define fake_widget_1 { \ - fake_widget_1_setup, \ - fake_widget_1_activate, \ - fake_widget_1_loop, \ - fake_widget_1_resign, \ -} - -#endif // FAKE_WIDGET_1_H_ \ No newline at end of file diff --git a/launcher/widgets/fake_widget_2.c b/launcher/widgets/fake_widget_2.c deleted file mode 100644 index 46772222..00000000 --- a/launcher/widgets/fake_widget_2.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "fake_widget_2.h" -#include "watch.h" - -void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - *context_ptr = NULL; -} - -void fake_widget_2_activate(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} - -bool fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("fake_widget_2_loop\n"); - (void) settings; - (void) context; - watch_display_string("W1 d get02", 0); - - switch (event.bit.event_type) { - case EVENT_MODE_BUTTON_UP: - launcher_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - launcher_illuminate_led(); - break; - default: - break; - } - - return true; -} - -void fake_widget_2_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} diff --git a/launcher/widgets/fake_widget_2.h b/launcher/widgets/fake_widget_2.h deleted file mode 100644 index cf01969d..00000000 --- a/launcher/widgets/fake_widget_2.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FAKE_WIDGET_2_H_ -#define FAKE_WIDGET_2_H_ - -#include "launcher.h" - -void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr); -void fake_widget_2_activate(LauncherSettings *settings, void *context); -bool fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void fake_widget_2_resign(LauncherSettings *settings, void *context); - -#define fake_widget_2 { \ - fake_widget_2_setup, \ - fake_widget_2_activate, \ - fake_widget_2_loop, \ - fake_widget_2_resign, \ -} - -#endif // FAKE_WIDGET_2_H_ \ No newline at end of file -- cgit v1.2.3 From 3516f4295eafbb04f7ccd1f4947c4921fae6e9bf Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Wed, 6 Oct 2021 10:25:28 -0400 Subject: launcher: clean up structs --- launcher/launcher.c | 32 ++++++++++++---------- launcher/launcher.h | 15 ++++------ launcher/widgets/clock/simple_clock_widget.c | 8 +++--- .../widgets/complications/pulseometer_widget.c | 2 +- launcher/widgets/settings/preferences_widget.c | 4 +-- launcher/widgets/settings/set_time_widget.c | 4 +-- 6 files changed, 31 insertions(+), 34 deletions(-) diff --git a/launcher/launcher.c b/launcher/launcher.c index 7d87c58a..7adb01a8 100644 --- a/launcher/launcher.c +++ b/launcher/launcher.c @@ -84,8 +84,8 @@ void app_setup() { } widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); - event.value = 0; - event.bit.event_type = EVENT_ACTIVATE; + event.subsecond = 0; + event.event_type = EVENT_ACTIVATE; } } @@ -105,8 +105,8 @@ bool app_loop() { launcher_state.current_widget = launcher_state.next_widget; watch_clear_display(); widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - event.value = 0; - event.bit.event_type = EVENT_ACTIVATE; + event.subsecond = 0; + event.event_type = EVENT_ACTIVATE; launcher_state.widget_changed = false; } @@ -137,17 +137,18 @@ bool app_loop() { alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); - event.value = 0; + event.event_type = EVENT_NONE; + event.subsecond = 0; // this is a little mini-runloop. // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. while (launcher_state.screensaver_ticks == -1) { - event.bit.event_type = EVENT_SCREENSAVER; + event.event_type = EVENT_SCREENSAVER; widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); watch_enter_shallow_sleep(true); } // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. - event.bit.event_type = EVENT_ACTIVATE; + event.event_type = EVENT_ACTIVATE; // this is a hack tho: waking from shallow sleep, app_setup does get called, but it happens before we have reset our ticks. // need to figure out if there's a better heuristic for determining how we woke up. app_setup(); @@ -155,10 +156,11 @@ bool app_loop() { static bool can_sleep = true; - if (event.bit.event_type) { - event.bit.subsecond = launcher_state.subsecond; + if (event.event_type) { + event.subsecond = launcher_state.subsecond; can_sleep = widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - event.value = 0; + event.event_type = EVENT_NONE; + event.subsecond = 0; } return can_sleep && !launcher_state.led_on; @@ -179,17 +181,17 @@ LauncherEventType _figure_out_button_event(LauncherEventType button_down_event, void cb_light_btn_interrupt() { _launcher_reset_screensaver_countdown(); - event.bit.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); + event.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); } void cb_mode_btn_interrupt() { _launcher_reset_screensaver_countdown(); - event.bit.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); + event.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); } void cb_alarm_btn_interrupt() { _launcher_reset_screensaver_countdown(); - event.bit.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); + event.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); } void cb_alarm_btn_extwake() { @@ -198,11 +200,11 @@ void cb_alarm_btn_extwake() { } void cb_alarm_fired() { - event.bit.event_type = EVENT_SCREENSAVER; + event.event_type = EVENT_SCREENSAVER; } void cb_tick() { - event.bit.event_type = EVENT_TICK; + event.event_type = EVENT_TICK; watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.second != launcher_state.last_second) { if (launcher_state.light_ticks) launcher_state.light_ticks--; diff --git a/launcher/launcher.h b/launcher/launcher.h index 97c56545..5c5315a3 100644 --- a/launcher/launcher.h +++ b/launcher/launcher.h @@ -37,29 +37,24 @@ typedef enum { EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released. } LauncherEventType; -typedef union { - struct { - uint32_t event_type : 8; - uint32_t subsecond : 8; - uint32_t reserved : 16; - } bit; - uint32_t value; +typedef struct { + uint8_t event_type; + uint8_t subsecond; } LauncherEvent; - typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context); typedef bool (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context); -typedef struct WatchWidget { +typedef struct { launcher_widget_setup setup; launcher_widget_activate activate; launcher_widget_loop loop; launcher_widget_resign resign; } WatchWidget; -typedef struct LauncherState { +typedef struct { // properties stored in BACKUP register LauncherSettings launcher_settings; diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c index 0c89cbc2..7fe0183d 100644 --- a/launcher/widgets/clock/simple_clock_widget.c +++ b/launcher/widgets/clock/simple_clock_widget.c @@ -25,7 +25,7 @@ bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, v watch_date_time date_time; uint32_t previous_date_time; - switch (event.bit.event_type) { + switch (event.event_type) { case EVENT_ACTIVATE: case EVENT_TICK: case EVENT_SCREENSAVER: @@ -33,11 +33,11 @@ bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, v previous_date_time = *((uint32_t *)context); *((uint32_t *)context) = date_time.reg; - if (date_time.reg >> 6 == previous_date_time >> 6 && event.bit.event_type != EVENT_SCREENSAVER) { + if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_SCREENSAVER) { // everything before seconds is the same, don't waste cycles setting those segments. pos = 8; sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.bit.event_type != EVENT_SCREENSAVER) { + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_SCREENSAVER) { // everything before minutes is the same. pos = 6; sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); @@ -54,7 +54,7 @@ bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, v if (date_time.unit.hour == 0) date_time.unit.hour = 12; } pos = 0; - if (event.bit.event_type == EVENT_SCREENSAVER) { + if (event.event_type == EVENT_SCREENSAVER) { sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); } else { sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); diff --git a/launcher/widgets/complications/pulseometer_widget.c b/launcher/widgets/complications/pulseometer_widget.c index 3df1cb44..a7272dcb 100644 --- a/launcher/widgets/complications/pulseometer_widget.c +++ b/launcher/widgets/complications/pulseometer_widget.c @@ -20,7 +20,7 @@ bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, vo char buf[14]; // starts at index 15 const uint8_t pulse_lookup[] = {240, 225, 212, 200, 189, 180, 171, 164, 157, 150, 144, 138, 133, 129, 124, 120, 116, 113, 109, 106, 103, 100, 97, 95, 92, 90, 88, 86, 84, 82, 80, 78, 77, 75, 73, 72, 71, 69, 68, 67, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 55, 54, 53, 52, 51, 51, 50, 49, 49, 48, 47, 47, 46, 46, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, 40, 40}; - switch (event.bit.event_type) { + switch (event.event_type) { case EVENT_TICK: if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { switch (pulsometer_state->ticks % 5) { diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c index 40e0ac50..1618a72c 100644 --- a/launcher/widgets/settings/preferences_widget.c +++ b/launcher/widgets/settings/preferences_widget.c @@ -19,7 +19,7 @@ void preferences_widget_activate(LauncherSettings *settings, void *context) { bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { printf("preferences_widget_loop\n"); uint8_t current_page = *((uint8_t *)context); - switch (event.bit.event_type) { + switch (event.event_type) { case EVENT_MODE_BUTTON_UP: watch_set_led_off(); launcher_move_to_next_widget(); @@ -53,7 +53,7 @@ bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, vo watch_display_string((char *)preferences_widget_titles[current_page], 0); - if (event.bit.subsecond % 2) return current_page <= 2; + if (event.subsecond % 2) return current_page <= 2; char buf[3]; switch (current_page) { case 0: diff --git a/launcher/widgets/settings/set_time_widget.c b/launcher/widgets/settings/set_time_widget.c index c7949a4f..d8cfb9fc 100644 --- a/launcher/widgets/settings/set_time_widget.c +++ b/launcher/widgets/settings/set_time_widget.c @@ -21,7 +21,7 @@ bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; watch_date_time date_time = watch_rtc_get_date_time(); - switch (event.bit.event_type) { + switch (event.event_type) { case EVENT_MODE_BUTTON_UP: launcher_move_to_next_widget(); return false; @@ -79,7 +79,7 @@ bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void watch_clear_indicator(WATCH_INDICATOR_PM); sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day); } - if (event.bit.subsecond % 2) { + if (event.subsecond % 2) { switch (current_page) { case 0: case 3: -- cgit v1.2.3 From 9d4367565b20ef9d42f793fc00daa575c46b0e3c Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Wed, 6 Oct 2021 12:03:02 -0400 Subject: pulseometer: support variable update frequency --- launcher/widgets/complications/pulseometer_widget.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/launcher/widgets/complications/pulseometer_widget.c b/launcher/widgets/complications/pulseometer_widget.c index a7272dcb..7b3f3efe 100644 --- a/launcher/widgets/complications/pulseometer_widget.c +++ b/launcher/widgets/complications/pulseometer_widget.c @@ -3,6 +3,9 @@ #include "pulseometer_widget.h" #include "watch.h" +#define PULSOMETER_WIDGET_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) +#define PULSOMETER_WIDGET_FREQUENCY (1 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) + void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr) { (void) settings; if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); @@ -18,8 +21,6 @@ bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, vo (void) settings; PulsometerState *pulsometer_state = (PulsometerState *)context; char buf[14]; - // starts at index 15 - const uint8_t pulse_lookup[] = {240, 225, 212, 200, 189, 180, 171, 164, 157, 150, 144, 138, 133, 129, 124, 120, 116, 113, 109, 106, 103, 100, 97, 95, 92, 90, 88, 86, 84, 82, 80, 78, 77, 75, 73, 72, 71, 69, 68, 67, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 55, 54, 53, 52, 51, 51, 50, 49, 49, 48, 47, 47, 46, 46, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, 40, 40}; switch (event.event_type) { case EVENT_TICK: if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { @@ -40,14 +41,16 @@ bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, vo watch_clear_display(); break; } - pulsometer_state->ticks++; + pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; } else { - if (pulsometer_state->ticks < 15) { - watch_display_string(" Lo", 0); - } else if (pulsometer_state->ticks > 91) { + if (pulsometer_state->measuring && pulsometer_state->ticks) { + pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); + } + if (pulsometer_state->pulse > 240) { watch_display_string(" Hi", 0); + } else if (pulsometer_state->pulse < 40) { + watch_display_string(" Lo", 0); } else { - if (pulsometer_state->measuring) pulsometer_state->pulse = pulse_lookup[pulsometer_state->ticks - 15]; sprintf(buf, " %-3dbpn", pulsometer_state->pulse); watch_display_string(buf, 0); } @@ -62,8 +65,9 @@ bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, vo break; case EVENT_ALARM_BUTTON_DOWN: pulsometer_state->ticks = 0; + pulsometer_state->pulse = 0xFFFF; pulsometer_state->measuring = true; - launcher_request_tick_frequency(2); + launcher_request_tick_frequency(PULSOMETER_WIDGET_FREQUENCY); break; case EVENT_ALARM_BUTTON_UP: case EVENT_ALARM_LONG_PRESS: -- cgit v1.2.3 From e8461984d60a80841a5f4b219358cc20567114f8 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 12:58:14 -0400 Subject: launcher is now movement --- launcher/launcher.c | 218 --------------------- launcher/launcher.h | 89 --------- launcher/launcher_config.h | 18 -- launcher/make/.gitignore | 1 - launcher/make/Makefile | 32 --- launcher/widgets/clock/simple_clock_widget.c | 92 --------- launcher/widgets/clock/simple_clock_widget.h | 20 -- .../widgets/complications/pulseometer_widget.c | 87 -------- .../widgets/complications/pulseometer_widget.h | 24 --- launcher/widgets/settings/preferences_widget.c | 120 ------------ launcher/widgets/settings/preferences_widget.h | 18 -- launcher/widgets/settings/set_time_widget.c | 109 ----------- launcher/widgets/settings/set_time_widget.h | 18 -- movement/make/.gitignore | 1 + movement/make/Makefile | 32 +++ movement/movement.c | 218 +++++++++++++++++++++ movement/movement.h | 89 +++++++++ movement/movement_config.h | 18 ++ movement/widgets/clock/simple_clock_widget.c | 92 +++++++++ movement/widgets/clock/simple_clock_widget.h | 20 ++ .../widgets/complications/pulseometer_widget.c | 87 ++++++++ .../widgets/complications/pulseometer_widget.h | 24 +++ movement/widgets/settings/preferences_widget.c | 120 ++++++++++++ movement/widgets/settings/preferences_widget.h | 18 ++ movement/widgets/settings/set_time_widget.c | 109 +++++++++++ movement/widgets/settings/set_time_widget.h | 18 ++ 26 files changed, 846 insertions(+), 846 deletions(-) delete mode 100644 launcher/launcher.c delete mode 100644 launcher/launcher.h delete mode 100644 launcher/launcher_config.h delete mode 100755 launcher/make/.gitignore delete mode 100755 launcher/make/Makefile delete mode 100644 launcher/widgets/clock/simple_clock_widget.c delete mode 100644 launcher/widgets/clock/simple_clock_widget.h delete mode 100644 launcher/widgets/complications/pulseometer_widget.c delete mode 100644 launcher/widgets/complications/pulseometer_widget.h delete mode 100644 launcher/widgets/settings/preferences_widget.c delete mode 100644 launcher/widgets/settings/preferences_widget.h delete mode 100644 launcher/widgets/settings/set_time_widget.c delete mode 100644 launcher/widgets/settings/set_time_widget.h create mode 100755 movement/make/.gitignore create mode 100755 movement/make/Makefile create mode 100644 movement/movement.c create mode 100644 movement/movement.h create mode 100644 movement/movement_config.h create mode 100644 movement/widgets/clock/simple_clock_widget.c create mode 100644 movement/widgets/clock/simple_clock_widget.h create mode 100644 movement/widgets/complications/pulseometer_widget.c create mode 100644 movement/widgets/complications/pulseometer_widget.h create mode 100644 movement/widgets/settings/preferences_widget.c create mode 100644 movement/widgets/settings/preferences_widget.h create mode 100644 movement/widgets/settings/set_time_widget.c create mode 100644 movement/widgets/settings/set_time_widget.h diff --git a/launcher/launcher.c b/launcher/launcher.c deleted file mode 100644 index 7adb01a8..00000000 --- a/launcher/launcher.c +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include -#include "watch.h" -#include "launcher.h" -#include "launcher_config.h" - -LauncherState launcher_state; -void * widget_contexts[LAUNCHER_NUM_WIDGETS]; -const int32_t launcher_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; -LauncherEvent event; - -void cb_mode_btn_interrupt(); -void cb_light_btn_interrupt(); -void cb_alarm_btn_interrupt(); -void cb_alarm_btn_extwake(); -void cb_alarm_fired(); -void cb_tick(); - -static inline void _launcher_reset_screensaver_countdown() { - // for testing, make the timeout happen 60x faster. - launcher_state.screensaver_ticks = launcher_screensaver_deadlines[launcher_state.launcher_settings.bit.screensaver_interval] / 60; -} - -void launcher_request_tick_frequency(uint8_t freq) { - watch_rtc_disable_all_periodic_callbacks(); - launcher_state.subsecond = 0; - launcher_state.tick_frequency = freq; - watch_rtc_register_periodic_callback(cb_tick, freq); -} - -void launcher_illuminate_led() { - launcher_state.light_ticks = 3; -} - -void launcher_move_to_widget(uint8_t widget_index) { - launcher_state.widget_changed = true; - launcher_state.next_widget = widget_index; -} - -void launcher_move_to_next_widget() { - launcher_move_to_widget((launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS); -} - -void app_init() { - memset(&launcher_state, 0, sizeof(launcher_state)); - - launcher_state.launcher_settings.bit.led_green_color = 0xF; - launcher_state.launcher_settings.bit.button_should_sound = true; - launcher_state.launcher_settings.bit.screensaver_interval = 1; - _launcher_reset_screensaver_countdown(); -} - -void app_wake_from_deep_sleep() { - // This app does not support deep sleep mode. -} - -void app_setup() { - static bool is_first_launch = true; - - if (is_first_launch) { - for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { - widget_contexts[i] = NULL; - is_first_launch = false; - } - } - if (launcher_state.screensaver_ticks != -1) { - watch_disable_extwake_interrupt(BTN_ALARM); - watch_rtc_disable_alarm_callback(); - - watch_enable_external_interrupts(); - watch_register_interrupt_callback(BTN_MODE, cb_mode_btn_interrupt, INTERRUPT_TRIGGER_BOTH); - watch_register_interrupt_callback(BTN_LIGHT, cb_light_btn_interrupt, INTERRUPT_TRIGGER_BOTH); - watch_register_interrupt_callback(BTN_ALARM, cb_alarm_btn_interrupt, INTERRUPT_TRIGGER_BOTH); - - watch_enable_buzzer(); - watch_enable_leds(); - watch_enable_display(); - - launcher_request_tick_frequency(1); - - for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) { - widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]); - } - - widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]); - event.subsecond = 0; - event.event_type = EVENT_ACTIVATE; - } -} - -void app_prepare_for_sleep() { -} - -void app_wake_from_sleep() { -} - -bool app_loop() { - if (launcher_state.widget_changed) { - if (launcher_state.launcher_settings.bit.button_should_sound) { - // low note for nonzero case, high note for return to widget 0 - watch_buzzer_play_note(launcher_state.next_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); - } - widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - launcher_state.current_widget = launcher_state.next_widget; - watch_clear_display(); - widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - event.subsecond = 0; - event.event_type = EVENT_ACTIVATE; - launcher_state.widget_changed = false; - } - - // If the LED is off and should be on, turn it on - if (launcher_state.light_ticks > 0 && !launcher_state.led_on) { - watch_set_led_color(launcher_state.launcher_settings.bit.led_red_color ? (0xF | launcher_state.launcher_settings.bit.led_red_color << 4) : 0, - launcher_state.launcher_settings.bit.led_green_color ? (0xF | launcher_state.launcher_settings.bit.led_green_color << 4) : 0); - launcher_state.led_on = true; - - } - - // if the LED is on and should be off, turn it off - if (launcher_state.led_on && launcher_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)) { - launcher_state.light_ticks = 3; - } else { - watch_set_led_off(); - launcher_state.led_on = false; - } - } - - // if we have timed out of our screensaver countdown, enter screensaver mode. - if (launcher_state.screensaver_ticks == 0) { - launcher_state.screensaver_ticks = -1; - watch_date_time alarm_time; - alarm_time.reg = 0; - alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 - watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); - watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); - event.event_type = EVENT_NONE; - event.subsecond = 0; - - // this is a little mini-runloop. - // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. - while (launcher_state.screensaver_ticks == -1) { - event.event_type = EVENT_SCREENSAVER; - widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - watch_enter_shallow_sleep(true); - } - // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. - event.event_type = EVENT_ACTIVATE; - // this is a hack tho: waking from shallow sleep, app_setup does get called, but it happens before we have reset our ticks. - // need to figure out if there's a better heuristic for determining how we woke up. - app_setup(); - } - - static bool can_sleep = true; - - if (event.event_type) { - event.subsecond = launcher_state.subsecond; - can_sleep = widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]); - event.event_type = EVENT_NONE; - event.subsecond = 0; - } - - return can_sleep && !launcher_state.led_on; -} - -LauncherEventType _figure_out_button_event(LauncherEventType button_down_event, 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; - *down_timestamp = 0; - if (diff > 1) return button_down_event + 2; - else return button_down_event + 1; - } else { - *down_timestamp = date_time.unit.second + 1; - return button_down_event; - } -} - -void cb_light_btn_interrupt() { - _launcher_reset_screensaver_countdown(); - event.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &launcher_state.light_down_timestamp); -} - -void cb_mode_btn_interrupt() { - _launcher_reset_screensaver_countdown(); - event.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &launcher_state.mode_down_timestamp); -} - -void cb_alarm_btn_interrupt() { - _launcher_reset_screensaver_countdown(); - event.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &launcher_state.alarm_down_timestamp); -} - -void cb_alarm_btn_extwake() { - // wake up! - _launcher_reset_screensaver_countdown(); -} - -void cb_alarm_fired() { - event.event_type = EVENT_SCREENSAVER; -} - -void cb_tick() { - event.event_type = EVENT_TICK; - watch_date_time date_time = watch_rtc_get_date_time(); - if (date_time.unit.second != launcher_state.last_second) { - if (launcher_state.light_ticks) launcher_state.light_ticks--; - if (launcher_state.launcher_settings.bit.screensaver_interval && launcher_state.screensaver_ticks > 0) launcher_state.screensaver_ticks--; - - launcher_state.last_second = date_time.unit.second; - launcher_state.subsecond = 0; - } else { - launcher_state.subsecond++; - } -} diff --git a/launcher/launcher.h b/launcher/launcher.h deleted file mode 100644 index 5c5315a3..00000000 --- a/launcher/launcher.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef LAUNCHER_H_ -#define LAUNCHER_H_ -#include -#include - -// TODO: none of this is implemented -typedef union { - struct { - uint32_t reserved : 3; - uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. - uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. - uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour. - uint32_t alarm_should_sound : 1; // if true, the alarm interrupt can match a time and play a song. - uint32_t alarm_minute : 6; // the minute of the alarm we want to match - uint32_t alarm_hour : 5; // the second of the alarm we want to match - uint32_t screensaver_interval : 3; // 0 to disable screensaver, or a screensaver activation interval. - uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. - uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) - uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) - } bit; - uint32_t value; -} LauncherSettings; - -typedef enum { - EVENT_NONE = 0, // There is no event to report. - EVENT_ACTIVATE, // Your widget is entering the foreground. - EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. - EVENT_SCREENSAVER, // Your widget is being asked to display its output for screensaver mode. - EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. - EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. - EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. - EVENT_MODE_BUTTON_DOWN, // The mode button has been pressed, but not yet released. - EVENT_MODE_BUTTON_UP, // The mode button was pressed and released. - EVENT_MODE_LONG_PRESS, // The mode button was held for >2 seconds, and released. - EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released. - EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released. - EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released. -} LauncherEventType; - -typedef struct { - uint8_t event_type; - uint8_t subsecond; -} LauncherEvent; - -typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr); -typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context); -typedef bool (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); -typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context); - -typedef struct { - launcher_widget_setup setup; - launcher_widget_activate activate; - launcher_widget_loop loop; - launcher_widget_resign resign; -} WatchWidget; - -typedef struct { - // properties stored in BACKUP register - LauncherSettings launcher_settings; - - // transient properties - int16_t current_widget; - int16_t next_widget; - bool widget_changed; - - // LED stuff - uint8_t light_ticks; - bool led_on; - - // button tracking for long press - uint8_t light_down_timestamp; - uint8_t mode_down_timestamp; - uint8_t alarm_down_timestamp; - - // screensaver countdown - int32_t screensaver_ticks; - - // stuff for subsecond tracking - uint8_t tick_frequency; - uint8_t last_second; - uint8_t subsecond; -} LauncherState; - -void launcher_move_to_widget(uint8_t widget_index); -void launcher_move_to_next_widget(); -void launcher_illuminate_led(); -void launcher_request_tick_frequency(uint8_t freq); - -#endif // LAUNCHER_H_ diff --git a/launcher/launcher_config.h b/launcher/launcher_config.h deleted file mode 100644 index ff656350..00000000 --- a/launcher/launcher_config.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef LAUNCHER_CONFIG_H_ -#define LAUNCHER_CONFIG_H_ - -#include "simple_clock_widget.h" -#include "preferences_widget.h" -#include "set_time_widget.h" -#include "pulseometer_widget.h" - -#define LAUNCHER_NUM_WIDGETS 3 - -WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = { - simple_clock_widget, - preferences_widget, - set_time_widget, -}; - - -#endif // LAUNCHER_CONFIG_H_ diff --git a/launcher/make/.gitignore b/launcher/make/.gitignore deleted file mode 100755 index 3722ac63..00000000 --- a/launcher/make/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/launcher/make/Makefile b/launcher/make/Makefile deleted file mode 100755 index a1059bbd..00000000 --- a/launcher/make/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Leave this line at the top of the file; it has all the watch library sources and includes. -TOP = ../.. -include $(TOP)/make.mk - -# If you add any other subdirectories with header files you wish to include, add them after ../ -# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. -# INCLUDES += \ -# -I../ \ -# -I../drivers/ \ -# -I../widgets/fitness/ -INCLUDES += \ - -I../ \ - -I../widgets/ \ - -I../widgets/clock/ \ - -I../widgets/settings/ \ - -I../widgets/complications/ \ - -# If you add any other source files you wish to compile, add them after ../app.c -# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. -# SRCS += \ -# ../launcher.c \ -# ../drivers/lis2dh.c \ -# ../widgets/fitness/step_count_widget.c -SRCS += \ - ../launcher.c \ - ../widgets/clock/simple_clock_widget.c \ - ../widgets/settings/preferences_widget.c \ - ../widgets/settings/set_time_widget.c \ - ../widgets/complications/pulseometer_widget.c \ - -# Leave this line at the bottom of the file; it has all the targets for making your project. -include $(TOP)/rules.mk diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c deleted file mode 100644 index 7fe0183d..00000000 --- a/launcher/widgets/clock/simple_clock_widget.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "simple_clock_widget.h" -#include "watch.h" - -void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - // the only context we need is the timestamp of the previous tick. - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint32_t)); -} - -void simple_clock_widget_activate(LauncherSettings *settings, void *context) { - if (settings->bit.clock_mode_24h) { - watch_set_indicator(WATCH_INDICATOR_24H); - } - watch_set_colon(); - // this ensures that none of the timestamp fields will match, so we can re-render them all. - *((uint32_t *)context) = 0xFFFFFFFF; -} - -bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("simple_clock_widget_loop\n"); - const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; - char buf[11]; - uint8_t pos; - - watch_date_time date_time; - uint32_t previous_date_time; - switch (event.event_type) { - case EVENT_ACTIVATE: - case EVENT_TICK: - case EVENT_SCREENSAVER: - date_time = watch_rtc_get_date_time(); - previous_date_time = *((uint32_t *)context); - *((uint32_t *)context) = date_time.reg; - - if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_SCREENSAVER) { - // everything before seconds is the same, don't waste cycles setting those segments. - pos = 8; - sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_SCREENSAVER) { - // everything before minutes is the same. - pos = 6; - sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); - } else { - // other stuff changed; let's do it all. - if (!settings->bit.clock_mode_24h) { - // if we are in 12 hour mode, do some cleanup. - if (date_time.unit.hour < 12) { - watch_clear_indicator(WATCH_INDICATOR_PM); - } else { - watch_set_indicator(WATCH_INDICATOR_PM); - } - date_time.unit.hour %= 12; - if (date_time.unit.hour == 0) date_time.unit.hour = 12; - } - pos = 0; - if (event.event_type == EVENT_SCREENSAVER) { - sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); - } else { - sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); - } - } - watch_display_string(buf, pos); - break; - case EVENT_MODE_BUTTON_UP: - launcher_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - launcher_illuminate_led(); - break; - case EVENT_ALARM_BUTTON_UP: - break; - default: - break; - } - - return true; -} - -void simple_clock_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} - -uint8_t simple_clock_widget_get_weekday(uint16_t year, uint16_t month, uint16_t day) { - year += 20; - if (month <= 2) { - month += 12; - year--; - } - return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7; -} diff --git a/launcher/widgets/clock/simple_clock_widget.h b/launcher/widgets/clock/simple_clock_widget.h deleted file mode 100644 index 739c942b..00000000 --- a/launcher/widgets/clock/simple_clock_widget.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SIMPLE_CLOCK_WIDGET_H_ -#define SIMPLE_CLOCK_WIDGET_H_ - -#include "launcher.h" - -void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr); -void simple_clock_widget_activate(LauncherSettings *settings, void *context); -bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void simple_clock_widget_resign(LauncherSettings *settings, void *context); - -uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year); - -#define simple_clock_widget { \ - simple_clock_widget_setup, \ - simple_clock_widget_activate, \ - simple_clock_widget_loop, \ - simple_clock_widget_resign, \ -} - -#endif // FAKE_WIDGET_H_ \ No newline at end of file diff --git a/launcher/widgets/complications/pulseometer_widget.c b/launcher/widgets/complications/pulseometer_widget.c deleted file mode 100644 index 7b3f3efe..00000000 --- a/launcher/widgets/complications/pulseometer_widget.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include "pulseometer_widget.h" -#include "watch.h" - -#define PULSOMETER_WIDGET_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) -#define PULSOMETER_WIDGET_FREQUENCY (1 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) - -void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); -} - -void pulseometer_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - memset(context, 0, sizeof(PulsometerState)); -} - -bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("pulseometer_widget_loop\n"); - (void) settings; - PulsometerState *pulsometer_state = (PulsometerState *)context; - char buf[14]; - switch (event.event_type) { - case EVENT_TICK: - if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { - switch (pulsometer_state->ticks % 5) { - case 0: - watch_display_string(" Hold ", 2); - break; - case 1: - watch_display_string(" Alarn", 4); - break; - case 2: - watch_display_string("+ Count ", 0); - break; - case 3: - watch_display_string(" 30Beats ", 0); - break; - case 4: - watch_clear_display(); - break; - } - pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; - } else { - if (pulsometer_state->measuring && pulsometer_state->ticks) { - pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); - } - if (pulsometer_state->pulse > 240) { - watch_display_string(" Hi", 0); - } else if (pulsometer_state->pulse < 40) { - watch_display_string(" Lo", 0); - } else { - sprintf(buf, " %-3dbpn", pulsometer_state->pulse); - watch_display_string(buf, 0); - } - if (pulsometer_state->measuring) pulsometer_state->ticks++; - } - return false; - case EVENT_MODE_BUTTON_UP: - launcher_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - launcher_illuminate_led(); - break; - case EVENT_ALARM_BUTTON_DOWN: - pulsometer_state->ticks = 0; - pulsometer_state->pulse = 0xFFFF; - pulsometer_state->measuring = true; - launcher_request_tick_frequency(PULSOMETER_WIDGET_FREQUENCY); - break; - case EVENT_ALARM_BUTTON_UP: - case EVENT_ALARM_LONG_PRESS: - pulsometer_state->measuring = false; - launcher_request_tick_frequency(1); - break; - default: - break; - } - - return true; -} - -void pulseometer_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} diff --git a/launcher/widgets/complications/pulseometer_widget.h b/launcher/widgets/complications/pulseometer_widget.h deleted file mode 100644 index 5b18d7f3..00000000 --- a/launcher/widgets/complications/pulseometer_widget.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PULSEOMETER_WIDGET_H_ -#define PULSEOMETER_WIDGET_H_ - -#include "launcher.h" - -typedef struct { - bool measuring; - int16_t pulse; - int16_t ticks; -} PulsometerState; - -void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr); -void pulseometer_widget_activate(LauncherSettings *settings, void *context); -bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void pulseometer_widget_resign(LauncherSettings *settings, void *context); - -#define pulseometer_widget { \ - pulseometer_widget_setup, \ - pulseometer_widget_activate, \ - pulseometer_widget_loop, \ - pulseometer_widget_resign, \ -} - -#endif // PULSEOMETER_WIDGET_H_ \ No newline at end of file diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c deleted file mode 100644 index 1618a72c..00000000 --- a/launcher/widgets/settings/preferences_widget.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include "preferences_widget.h" -#include "watch.h" - -#define PREFERENCES_WIDGET_NUM_PREFEFENCES (5) -const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; - -void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); -} - -void preferences_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - *((uint8_t *)context) = 0; - launcher_request_tick_frequency(4); // we need to manually blink some pixels -} - -bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("preferences_widget_loop\n"); - uint8_t current_page = *((uint8_t *)context); - switch (event.event_type) { - case EVENT_MODE_BUTTON_UP: - watch_set_led_off(); - launcher_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - current_page = (current_page + 1) % PREFERENCES_WIDGET_NUM_PREFEFENCES; - *((uint8_t *)context) = current_page; - break; - case EVENT_ALARM_BUTTON_UP: - switch (current_page) { - case 0: - settings->bit.clock_mode_24h = !(settings->bit.clock_mode_24h); - break; - case 1: - settings->bit.button_should_sound = !(settings->bit.button_should_sound); - break; - case 2: - settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1; - break; - case 3: - settings->bit.led_green_color = settings->bit.led_green_color + 1; - break; - case 4: - settings->bit.led_red_color = settings->bit.led_red_color + 1; - break; - } - break; - default: - break; - } - - watch_display_string((char *)preferences_widget_titles[current_page], 0); - - if (event.subsecond % 2) return current_page <= 2; - char buf[3]; - switch (current_page) { - case 0: - if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); - else watch_display_string("12h", 4); - break; - case 1: - if (settings->bit.button_should_sound) watch_display_string("y", 9); - else watch_display_string("n", 9); - break; - case 2: - switch (settings->bit.screensaver_interval) { - case 0: - watch_display_string(" never", 4); - break; - case 1: - watch_display_string("1 hour", 4); - break; - case 2: - watch_display_string("2 hour", 4); - break; - case 3: - watch_display_string("6 hour", 4); - break; - case 4: - watch_display_string("12 hr", 4); - break; - case 5: - watch_display_string(" 1 day", 4); - break; - case 6: - watch_display_string(" 2 day", 4); - break; - case 7: - watch_display_string(" 7 day", 4); - break; - } - break; - case 3: - sprintf(buf, "%2d", settings->bit.led_green_color); - watch_display_string(buf, 8); - break; - case 4: - sprintf(buf, "%2d", settings->bit.led_red_color); - watch_display_string(buf, 8); - break; - } - - if (current_page > 2) { - watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, - settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); - return false; - } - - watch_set_led_off(); - return true; -} - -void preferences_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; - watch_set_led_off(); - launcher_request_tick_frequency(1); -} diff --git a/launcher/widgets/settings/preferences_widget.h b/launcher/widgets/settings/preferences_widget.h deleted file mode 100644 index 11a189f8..00000000 --- a/launcher/widgets/settings/preferences_widget.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PREFERENCES_WIDGET_H_ -#define PREFERENCES_WIDGET_H_ - -#include "launcher.h" - -void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr); -void preferences_widget_activate(LauncherSettings *settings, void *context); -bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void preferences_widget_resign(LauncherSettings *settings, void *context); - -#define preferences_widget { \ - preferences_widget_setup, \ - preferences_widget_activate, \ - preferences_widget_loop, \ - preferences_widget_resign, \ -} - -#endif // PREFERENCES_WIDGET_H_ \ No newline at end of file diff --git a/launcher/widgets/settings/set_time_widget.c b/launcher/widgets/settings/set_time_widget.c deleted file mode 100644 index d8cfb9fc..00000000 --- a/launcher/widgets/settings/set_time_widget.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include "set_time_widget.h" -#include "watch.h" - -#define SET_TIME_WIDGET_NUM_SETTINGS (6) -const char set_time_widget_titles[SET_TIME_WIDGET_NUM_SETTINGS][3] = {"HR", "MN", "SE", "YR", "MO", "DA"}; - -void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); -} - -void set_time_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - *((uint8_t *)context) = 0; - launcher_request_tick_frequency(4); -} - -bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - uint8_t current_page = *((uint8_t *)context); - const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; - watch_date_time date_time = watch_rtc_get_date_time(); - - switch (event.event_type) { - case EVENT_MODE_BUTTON_UP: - launcher_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - current_page = (current_page + 1) % SET_TIME_WIDGET_NUM_SETTINGS; - *((uint8_t *)context) = current_page; - break; - case EVENT_ALARM_BUTTON_UP: - switch (current_page) { - case 0: // hour - date_time.unit.hour = (date_time.unit.hour + 1) % 24; - break; - case 1: // minute - date_time.unit.minute = (date_time.unit.minute + 1) % 60; - break; - case 2: // second - date_time.unit.second = 0; - break; - case 3: // year - // only allow 2021-2030. fix this sometime next decade - date_time.unit.year = ((date_time.unit.year % 10) + 1); - break; - case 4: // month - date_time.unit.month = (date_time.unit.month % 12) + 1; - break; - case 5: // day - date_time.unit.day = date_time.unit.day + 1; - // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. - // and it should roll over. - if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { - date_time.unit.day = 1; - } - break; - } - watch_rtc_set_date_time(date_time); - break; - default: - break; - } - - char buf[11]; - if (current_page < 3) { - watch_set_colon(); - if (settings->bit.clock_mode_24h) { - watch_set_indicator(WATCH_INDICATOR_24H); - sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second); - } else { - sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second); - if (date_time.unit.hour > 12) watch_set_indicator(WATCH_INDICATOR_PM); - else watch_clear_indicator(WATCH_INDICATOR_PM); - } - } else { - watch_clear_colon(); - watch_clear_indicator(WATCH_INDICATOR_24H); - watch_clear_indicator(WATCH_INDICATOR_PM); - sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day); - } - if (event.subsecond % 2) { - switch (current_page) { - case 0: - case 3: - buf[4] = buf[5] = ' '; - break; - case 1: - case 4: - buf[6] = buf[7] = ' '; - break; - case 2: - case 5: - buf[8] = buf[9] = ' '; - break; - } - } - - watch_display_string(buf, 0); - - return true; -} - -void set_time_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; - watch_set_led_off(); - launcher_request_tick_frequency(1); -} diff --git a/launcher/widgets/settings/set_time_widget.h b/launcher/widgets/settings/set_time_widget.h deleted file mode 100644 index dc492dce..00000000 --- a/launcher/widgets/settings/set_time_widget.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SET_TIME_WIDGET_H_ -#define SET_TIME_WIDGET_H_ - -#include "launcher.h" - -void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr); -void set_time_widget_activate(LauncherSettings *settings, void *context); -bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void set_time_widget_resign(LauncherSettings *settings, void *context); - -#define set_time_widget { \ - set_time_widget_setup, \ - set_time_widget_activate, \ - set_time_widget_loop, \ - set_time_widget_resign, \ -} - -#endif // SET_TIME_WIDGET_H_ diff --git a/movement/make/.gitignore b/movement/make/.gitignore new file mode 100755 index 00000000..3722ac63 --- /dev/null +++ b/movement/make/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/movement/make/Makefile b/movement/make/Makefile new file mode 100755 index 00000000..35b80079 --- /dev/null +++ b/movement/make/Makefile @@ -0,0 +1,32 @@ +# Leave this line at the top of the file; it has all the watch library sources and includes. +TOP = ../.. +include $(TOP)/make.mk + +# If you add any other subdirectories with header files you wish to include, add them after ../ +# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. +# INCLUDES += \ +# -I../ \ +# -I../drivers/ \ +# -I../widgets/fitness/ +INCLUDES += \ + -I../ \ + -I../widgets/ \ + -I../widgets/clock/ \ + -I../widgets/settings/ \ + -I../widgets/complications/ \ + +# If you add any other source files you wish to compile, add them after ../app.c +# Note that you will need to add a backslash at the end of any line you wish to continue, i.e. +# SRCS += \ +# ../movement.c \ +# ../drivers/lis2dh.c \ +# ../widgets/fitness/step_count_widget.c +SRCS += \ + ../movement.c \ + ../widgets/clock/simple_clock_widget.c \ + ../widgets/settings/preferences_widget.c \ + ../widgets/settings/set_time_widget.c \ + ../widgets/complications/pulseometer_widget.c \ + +# Leave this line at the bottom of the file; it has all the targets for making your project. +include $(TOP)/rules.mk diff --git a/movement/movement.c b/movement/movement.c new file mode 100644 index 00000000..9c15833c --- /dev/null +++ b/movement/movement.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include "watch.h" +#include "movement.h" +#include "movement_config.h" + +LauncherState movement_state; +void * widget_contexts[MOVEMENT_NUM_WIDGETS]; +const int32_t movement_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; +LauncherEvent event; + +void cb_mode_btn_interrupt(); +void cb_light_btn_interrupt(); +void cb_alarm_btn_interrupt(); +void cb_alarm_btn_extwake(); +void cb_alarm_fired(); +void cb_tick(); + +static inline void _movement_reset_screensaver_countdown() { + // for testing, make the timeout happen 60x faster. + movement_state.screensaver_ticks = movement_screensaver_deadlines[movement_state.movement_settings.bit.screensaver_interval] / 60; +} + +void movement_request_tick_frequency(uint8_t freq) { + watch_rtc_disable_all_periodic_callbacks(); + movement_state.subsecond = 0; + movement_state.tick_frequency = freq; + watch_rtc_register_periodic_callback(cb_tick, freq); +} + +void movement_illuminate_led() { + movement_state.light_ticks = 3; +} + +void movement_move_to_widget(uint8_t widget_index) { + movement_state.widget_changed = true; + movement_state.next_widget = widget_index; +} + +void movement_move_to_next_widget() { + movement_move_to_widget((movement_state.current_widget + 1) % MOVEMENT_NUM_WIDGETS); +} + +void app_init() { + memset(&movement_state, 0, sizeof(movement_state)); + + movement_state.movement_settings.bit.led_green_color = 0xF; + movement_state.movement_settings.bit.button_should_sound = true; + movement_state.movement_settings.bit.screensaver_interval = 1; + _movement_reset_screensaver_countdown(); +} + +void app_wake_from_deep_sleep() { + // This app does not support deep sleep mode. +} + +void app_setup() { + static bool is_first_launch = true; + + if (is_first_launch) { + for(uint8_t i = 0; i < MOVEMENT_NUM_WIDGETS; i++) { + widget_contexts[i] = NULL; + is_first_launch = false; + } + } + if (movement_state.screensaver_ticks != -1) { + watch_disable_extwake_interrupt(BTN_ALARM); + watch_rtc_disable_alarm_callback(); + + watch_enable_external_interrupts(); + watch_register_interrupt_callback(BTN_MODE, cb_mode_btn_interrupt, INTERRUPT_TRIGGER_BOTH); + watch_register_interrupt_callback(BTN_LIGHT, cb_light_btn_interrupt, INTERRUPT_TRIGGER_BOTH); + watch_register_interrupt_callback(BTN_ALARM, cb_alarm_btn_interrupt, INTERRUPT_TRIGGER_BOTH); + + watch_enable_buzzer(); + watch_enable_leds(); + watch_enable_display(); + + movement_request_tick_frequency(1); + + for(uint8_t i = 0; i < MOVEMENT_NUM_WIDGETS; i++) { + widgets[i].setup(&movement_state.movement_settings, &widget_contexts[i]); + } + + widgets[0].activate(&movement_state.movement_settings, widget_contexts[0]); + event.subsecond = 0; + event.event_type = EVENT_ACTIVATE; + } +} + +void app_prepare_for_sleep() { +} + +void app_wake_from_sleep() { +} + +bool app_loop() { + if (movement_state.widget_changed) { + if (movement_state.movement_settings.bit.button_should_sound) { + // low note for nonzero case, high note for return to widget 0 + watch_buzzer_play_note(movement_state.next_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); + } + widgets[movement_state.current_widget].resign(&movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + movement_state.current_widget = movement_state.next_widget; + watch_clear_display(); + widgets[movement_state.current_widget].activate(&movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + event.subsecond = 0; + event.event_type = EVENT_ACTIVATE; + movement_state.widget_changed = false; + } + + // If the LED is off and should be on, turn it on + if (movement_state.light_ticks > 0 && !movement_state.led_on) { + watch_set_led_color(movement_state.movement_settings.bit.led_red_color ? (0xF | movement_state.movement_settings.bit.led_red_color << 4) : 0, + movement_state.movement_settings.bit.led_green_color ? (0xF | movement_state.movement_settings.bit.led_green_color << 4) : 0); + movement_state.led_on = true; + + } + + // if the LED is on and should be off, turn it off + if (movement_state.led_on && 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; + } else { + watch_set_led_off(); + movement_state.led_on = false; + } + } + + // if we have timed out of our screensaver countdown, enter screensaver mode. + if (movement_state.screensaver_ticks == 0) { + movement_state.screensaver_ticks = -1; + watch_date_time alarm_time; + alarm_time.reg = 0; + alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 + watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); + watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); + event.event_type = EVENT_NONE; + event.subsecond = 0; + + // this is a little mini-runloop. + // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. + while (movement_state.screensaver_ticks == -1) { + event.event_type = EVENT_SCREENSAVER; + widgets[movement_state.current_widget].loop(event, &movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + watch_enter_shallow_sleep(true); + } + // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. + event.event_type = EVENT_ACTIVATE; + // this is a hack tho: waking from shallow sleep, app_setup does get called, but it happens before we have reset our ticks. + // need to figure out if there's a better heuristic for determining how we woke up. + app_setup(); + } + + static bool can_sleep = true; + + if (event.event_type) { + event.subsecond = movement_state.subsecond; + can_sleep = widgets[movement_state.current_widget].loop(event, &movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + event.event_type = EVENT_NONE; + event.subsecond = 0; + } + + return can_sleep && !movement_state.led_on; +} + +LauncherEventType _figure_out_button_event(LauncherEventType button_down_event, 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; + *down_timestamp = 0; + if (diff > 1) return button_down_event + 2; + else return button_down_event + 1; + } else { + *down_timestamp = date_time.unit.second + 1; + return button_down_event; + } +} + +void cb_light_btn_interrupt() { + _movement_reset_screensaver_countdown(); + event.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp); +} + +void cb_mode_btn_interrupt() { + _movement_reset_screensaver_countdown(); + event.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp); +} + +void cb_alarm_btn_interrupt() { + _movement_reset_screensaver_countdown(); + event.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &movement_state.alarm_down_timestamp); +} + +void cb_alarm_btn_extwake() { + // wake up! + _movement_reset_screensaver_countdown(); +} + +void cb_alarm_fired() { + event.event_type = EVENT_SCREENSAVER; +} + +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) { + if (movement_state.light_ticks) movement_state.light_ticks--; + if (movement_state.movement_settings.bit.screensaver_interval && movement_state.screensaver_ticks > 0) movement_state.screensaver_ticks--; + + movement_state.last_second = date_time.unit.second; + movement_state.subsecond = 0; + } else { + movement_state.subsecond++; + } +} diff --git a/movement/movement.h b/movement/movement.h new file mode 100644 index 00000000..025a5aa6 --- /dev/null +++ b/movement/movement.h @@ -0,0 +1,89 @@ +#ifndef MOVEMENT_H_ +#define MOVEMENT_H_ +#include +#include + +// TODO: none of this is implemented +typedef union { + struct { + uint32_t reserved : 3; + uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. + uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. + uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour. + uint32_t alarm_should_sound : 1; // if true, the alarm interrupt can match a time and play a song. + uint32_t alarm_minute : 6; // the minute of the alarm we want to match + uint32_t alarm_hour : 5; // the second of the alarm we want to match + uint32_t screensaver_interval : 3; // 0 to disable screensaver, or a screensaver activation interval. + uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. + uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) + uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) + } bit; + uint32_t value; +} LauncherSettings; + +typedef enum { + EVENT_NONE = 0, // There is no event to report. + EVENT_ACTIVATE, // Your widget is entering the foreground. + EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. + EVENT_SCREENSAVER, // Your widget is being asked to display its output for screensaver mode. + EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. + EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. + EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. + EVENT_MODE_BUTTON_DOWN, // The mode button has been pressed, but not yet released. + EVENT_MODE_BUTTON_UP, // The mode button was pressed and released. + EVENT_MODE_LONG_PRESS, // The mode button was held for >2 seconds, and released. + EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released. + EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released. + EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released. +} LauncherEventType; + +typedef struct { + uint8_t event_type; + uint8_t subsecond; +} LauncherEvent; + +typedef void (*movement_widget_setup)(LauncherSettings *settings, void ** context_ptr); +typedef void (*movement_widget_activate)(LauncherSettings *settings, void *context); +typedef bool (*movement_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); +typedef void (*movement_widget_resign)(LauncherSettings *settings, void *context); + +typedef struct { + movement_widget_setup setup; + movement_widget_activate activate; + movement_widget_loop loop; + movement_widget_resign resign; +} WatchWidget; + +typedef struct { + // properties stored in BACKUP register + LauncherSettings movement_settings; + + // transient properties + int16_t current_widget; + int16_t next_widget; + bool widget_changed; + + // LED stuff + uint8_t light_ticks; + bool led_on; + + // button tracking for long press + uint8_t light_down_timestamp; + uint8_t mode_down_timestamp; + uint8_t alarm_down_timestamp; + + // screensaver countdown + int32_t screensaver_ticks; + + // stuff for subsecond tracking + uint8_t tick_frequency; + uint8_t last_second; + uint8_t subsecond; +} LauncherState; + +void movement_move_to_widget(uint8_t widget_index); +void movement_move_to_next_widget(); +void movement_illuminate_led(); +void movement_request_tick_frequency(uint8_t freq); + +#endif // MOVEMENT_H_ diff --git a/movement/movement_config.h b/movement/movement_config.h new file mode 100644 index 00000000..49f342ca --- /dev/null +++ b/movement/movement_config.h @@ -0,0 +1,18 @@ +#ifndef MOVEMENT_CONFIG_H_ +#define MOVEMENT_CONFIG_H_ + +#include "simple_clock_widget.h" +#include "preferences_widget.h" +#include "set_time_widget.h" +#include "pulseometer_widget.h" + +#define MOVEMENT_NUM_WIDGETS 3 + +WatchWidget widgets[MOVEMENT_NUM_WIDGETS] = { + simple_clock_widget, + preferences_widget, + set_time_widget, +}; + + +#endif // MOVEMENT_CONFIG_H_ diff --git a/movement/widgets/clock/simple_clock_widget.c b/movement/widgets/clock/simple_clock_widget.c new file mode 100644 index 00000000..22218860 --- /dev/null +++ b/movement/widgets/clock/simple_clock_widget.c @@ -0,0 +1,92 @@ +#include +#include "simple_clock_widget.h" +#include "watch.h" + +void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + // the only context we need is the timestamp of the previous tick. + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint32_t)); +} + +void simple_clock_widget_activate(LauncherSettings *settings, void *context) { + if (settings->bit.clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + } + watch_set_colon(); + // this ensures that none of the timestamp fields will match, so we can re-render them all. + *((uint32_t *)context) = 0xFFFFFFFF; +} + +bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("simple_clock_widget_loop\n"); + const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; + char buf[11]; + uint8_t pos; + + watch_date_time date_time; + uint32_t previous_date_time; + switch (event.event_type) { + case EVENT_ACTIVATE: + case EVENT_TICK: + case EVENT_SCREENSAVER: + date_time = watch_rtc_get_date_time(); + previous_date_time = *((uint32_t *)context); + *((uint32_t *)context) = date_time.reg; + + if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_SCREENSAVER) { + // everything before seconds is the same, don't waste cycles setting those segments. + pos = 8; + sprintf(buf, "%02d", date_time.unit.second); + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_SCREENSAVER) { + // everything before minutes is the same. + pos = 6; + sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); + } else { + // other stuff changed; let's do it all. + if (!settings->bit.clock_mode_24h) { + // if we are in 12 hour mode, do some cleanup. + if (date_time.unit.hour < 12) { + watch_clear_indicator(WATCH_INDICATOR_PM); + } else { + watch_set_indicator(WATCH_INDICATOR_PM); + } + date_time.unit.hour %= 12; + if (date_time.unit.hour == 0) date_time.unit.hour = 12; + } + pos = 0; + if (event.event_type == EVENT_SCREENSAVER) { + sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); + } else { + sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } + } + watch_display_string(buf, pos); + break; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_widget(); + return false; + case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_UP: + break; + default: + break; + } + + return true; +} + +void simple_clock_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} + +uint8_t simple_clock_widget_get_weekday(uint16_t year, uint16_t month, uint16_t day) { + year += 20; + if (month <= 2) { + month += 12; + year--; + } + return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7; +} diff --git a/movement/widgets/clock/simple_clock_widget.h b/movement/widgets/clock/simple_clock_widget.h new file mode 100644 index 00000000..3bf4c9a3 --- /dev/null +++ b/movement/widgets/clock/simple_clock_widget.h @@ -0,0 +1,20 @@ +#ifndef SIMPLE_CLOCK_WIDGET_H_ +#define SIMPLE_CLOCK_WIDGET_H_ + +#include "movement.h" + +void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr); +void simple_clock_widget_activate(LauncherSettings *settings, void *context); +bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void simple_clock_widget_resign(LauncherSettings *settings, void *context); + +uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year); + +#define simple_clock_widget { \ + simple_clock_widget_setup, \ + simple_clock_widget_activate, \ + simple_clock_widget_loop, \ + simple_clock_widget_resign, \ +} + +#endif // FAKE_WIDGET_H_ \ No newline at end of file diff --git a/movement/widgets/complications/pulseometer_widget.c b/movement/widgets/complications/pulseometer_widget.c new file mode 100644 index 00000000..6384685a --- /dev/null +++ b/movement/widgets/complications/pulseometer_widget.c @@ -0,0 +1,87 @@ +#include +#include +#include "pulseometer_widget.h" +#include "watch.h" + +#define PULSOMETER_WIDGET_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) +#define PULSOMETER_WIDGET_FREQUENCY (1 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) + +void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); +} + +void pulseometer_widget_activate(LauncherSettings *settings, void *context) { + (void) settings; + memset(context, 0, sizeof(PulsometerState)); +} + +bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("pulseometer_widget_loop\n"); + (void) settings; + PulsometerState *pulsometer_state = (PulsometerState *)context; + char buf[14]; + switch (event.event_type) { + case EVENT_TICK: + if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { + switch (pulsometer_state->ticks % 5) { + case 0: + watch_display_string(" Hold ", 2); + break; + case 1: + watch_display_string(" Alarn", 4); + break; + case 2: + watch_display_string("+ Count ", 0); + break; + case 3: + watch_display_string(" 30Beats ", 0); + break; + case 4: + watch_clear_display(); + break; + } + pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; + } else { + if (pulsometer_state->measuring && pulsometer_state->ticks) { + pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); + } + if (pulsometer_state->pulse > 240) { + watch_display_string(" Hi", 0); + } else if (pulsometer_state->pulse < 40) { + watch_display_string(" Lo", 0); + } else { + sprintf(buf, " %-3dbpn", pulsometer_state->pulse); + watch_display_string(buf, 0); + } + if (pulsometer_state->measuring) pulsometer_state->ticks++; + } + return false; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_widget(); + return false; + case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_DOWN: + pulsometer_state->ticks = 0; + pulsometer_state->pulse = 0xFFFF; + pulsometer_state->measuring = true; + movement_request_tick_frequency(PULSOMETER_WIDGET_FREQUENCY); + break; + case EVENT_ALARM_BUTTON_UP: + case EVENT_ALARM_LONG_PRESS: + pulsometer_state->measuring = false; + movement_request_tick_frequency(1); + break; + default: + break; + } + + return true; +} + +void pulseometer_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/movement/widgets/complications/pulseometer_widget.h b/movement/widgets/complications/pulseometer_widget.h new file mode 100644 index 00000000..e5947660 --- /dev/null +++ b/movement/widgets/complications/pulseometer_widget.h @@ -0,0 +1,24 @@ +#ifndef PULSEOMETER_WIDGET_H_ +#define PULSEOMETER_WIDGET_H_ + +#include "movement.h" + +typedef struct { + bool measuring; + int16_t pulse; + int16_t ticks; +} PulsometerState; + +void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr); +void pulseometer_widget_activate(LauncherSettings *settings, void *context); +bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void pulseometer_widget_resign(LauncherSettings *settings, void *context); + +#define pulseometer_widget { \ + pulseometer_widget_setup, \ + pulseometer_widget_activate, \ + pulseometer_widget_loop, \ + pulseometer_widget_resign, \ +} + +#endif // PULSEOMETER_WIDGET_H_ \ No newline at end of file diff --git a/movement/widgets/settings/preferences_widget.c b/movement/widgets/settings/preferences_widget.c new file mode 100644 index 00000000..c4537329 --- /dev/null +++ b/movement/widgets/settings/preferences_widget.c @@ -0,0 +1,120 @@ +#include +#include "preferences_widget.h" +#include "watch.h" + +#define PREFERENCES_WIDGET_NUM_PREFEFENCES (5) +const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; + +void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); +} + +void preferences_widget_activate(LauncherSettings *settings, void *context) { + (void) settings; + *((uint8_t *)context) = 0; + movement_request_tick_frequency(4); // we need to manually blink some pixels +} + +bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("preferences_widget_loop\n"); + uint8_t current_page = *((uint8_t *)context); + switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + watch_set_led_off(); + movement_move_to_next_widget(); + return false; + case EVENT_LIGHT_BUTTON_UP: + current_page = (current_page + 1) % PREFERENCES_WIDGET_NUM_PREFEFENCES; + *((uint8_t *)context) = current_page; + break; + case EVENT_ALARM_BUTTON_UP: + switch (current_page) { + case 0: + settings->bit.clock_mode_24h = !(settings->bit.clock_mode_24h); + break; + case 1: + settings->bit.button_should_sound = !(settings->bit.button_should_sound); + break; + case 2: + settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1; + break; + case 3: + settings->bit.led_green_color = settings->bit.led_green_color + 1; + break; + case 4: + settings->bit.led_red_color = settings->bit.led_red_color + 1; + break; + } + break; + default: + break; + } + + watch_display_string((char *)preferences_widget_titles[current_page], 0); + + if (event.subsecond % 2) return current_page <= 2; + char buf[3]; + switch (current_page) { + case 0: + if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); + else watch_display_string("12h", 4); + break; + case 1: + if (settings->bit.button_should_sound) watch_display_string("y", 9); + else watch_display_string("n", 9); + break; + case 2: + switch (settings->bit.screensaver_interval) { + case 0: + watch_display_string(" never", 4); + break; + case 1: + watch_display_string("1 hour", 4); + break; + case 2: + watch_display_string("2 hour", 4); + break; + case 3: + watch_display_string("6 hour", 4); + break; + case 4: + watch_display_string("12 hr", 4); + break; + case 5: + watch_display_string(" 1 day", 4); + break; + case 6: + watch_display_string(" 2 day", 4); + break; + case 7: + watch_display_string(" 7 day", 4); + break; + } + break; + case 3: + sprintf(buf, "%2d", settings->bit.led_green_color); + watch_display_string(buf, 8); + break; + case 4: + sprintf(buf, "%2d", settings->bit.led_red_color); + watch_display_string(buf, 8); + break; + } + + if (current_page > 2) { + watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, + settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); + return false; + } + + watch_set_led_off(); + return true; +} + +void preferences_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + watch_set_led_off(); + movement_request_tick_frequency(1); +} diff --git a/movement/widgets/settings/preferences_widget.h b/movement/widgets/settings/preferences_widget.h new file mode 100644 index 00000000..3d463027 --- /dev/null +++ b/movement/widgets/settings/preferences_widget.h @@ -0,0 +1,18 @@ +#ifndef PREFERENCES_WIDGET_H_ +#define PREFERENCES_WIDGET_H_ + +#include "movement.h" + +void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr); +void preferences_widget_activate(LauncherSettings *settings, void *context); +bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void preferences_widget_resign(LauncherSettings *settings, void *context); + +#define preferences_widget { \ + preferences_widget_setup, \ + preferences_widget_activate, \ + preferences_widget_loop, \ + preferences_widget_resign, \ +} + +#endif // PREFERENCES_WIDGET_H_ \ No newline at end of file diff --git a/movement/widgets/settings/set_time_widget.c b/movement/widgets/settings/set_time_widget.c new file mode 100644 index 00000000..9464eb5b --- /dev/null +++ b/movement/widgets/settings/set_time_widget.c @@ -0,0 +1,109 @@ +#include +#include "set_time_widget.h" +#include "watch.h" + +#define SET_TIME_WIDGET_NUM_SETTINGS (6) +const char set_time_widget_titles[SET_TIME_WIDGET_NUM_SETTINGS][3] = {"HR", "MN", "SE", "YR", "MO", "DA"}; + +void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); +} + +void set_time_widget_activate(LauncherSettings *settings, void *context) { + (void) settings; + *((uint8_t *)context) = 0; + movement_request_tick_frequency(4); +} + +bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + uint8_t current_page = *((uint8_t *)context); + const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; + watch_date_time date_time = watch_rtc_get_date_time(); + + switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_widget(); + return false; + case EVENT_LIGHT_BUTTON_UP: + current_page = (current_page + 1) % SET_TIME_WIDGET_NUM_SETTINGS; + *((uint8_t *)context) = current_page; + break; + case EVENT_ALARM_BUTTON_UP: + switch (current_page) { + case 0: // hour + date_time.unit.hour = (date_time.unit.hour + 1) % 24; + break; + case 1: // minute + date_time.unit.minute = (date_time.unit.minute + 1) % 60; + break; + case 2: // second + date_time.unit.second = 0; + break; + case 3: // year + // only allow 2021-2030. fix this sometime next decade + date_time.unit.year = ((date_time.unit.year % 10) + 1); + break; + case 4: // month + date_time.unit.month = (date_time.unit.month % 12) + 1; + break; + case 5: // day + date_time.unit.day = date_time.unit.day + 1; + // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. + // and it should roll over. + if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { + date_time.unit.day = 1; + } + break; + } + watch_rtc_set_date_time(date_time); + break; + default: + break; + } + + char buf[11]; + if (current_page < 3) { + watch_set_colon(); + if (settings->bit.clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } else { + sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second); + if (date_time.unit.hour > 12) watch_set_indicator(WATCH_INDICATOR_PM); + else watch_clear_indicator(WATCH_INDICATOR_PM); + } + } else { + watch_clear_colon(); + watch_clear_indicator(WATCH_INDICATOR_24H); + watch_clear_indicator(WATCH_INDICATOR_PM); + sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day); + } + if (event.subsecond % 2) { + switch (current_page) { + case 0: + case 3: + buf[4] = buf[5] = ' '; + break; + case 1: + case 4: + buf[6] = buf[7] = ' '; + break; + case 2: + case 5: + buf[8] = buf[9] = ' '; + break; + } + } + + watch_display_string(buf, 0); + + return true; +} + +void set_time_widget_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + watch_set_led_off(); + movement_request_tick_frequency(1); +} diff --git a/movement/widgets/settings/set_time_widget.h b/movement/widgets/settings/set_time_widget.h new file mode 100644 index 00000000..363fd571 --- /dev/null +++ b/movement/widgets/settings/set_time_widget.h @@ -0,0 +1,18 @@ +#ifndef SET_TIME_WIDGET_H_ +#define SET_TIME_WIDGET_H_ + +#include "movement.h" + +void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr); +void set_time_widget_activate(LauncherSettings *settings, void *context); +bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void set_time_widget_resign(LauncherSettings *settings, void *context); + +#define set_time_widget { \ + set_time_widget_setup, \ + set_time_widget_activate, \ + set_time_widget_loop, \ + set_time_widget_resign, \ +} + +#endif // SET_TIME_WIDGET_H_ -- cgit v1.2.3 From d5ac4cb71b4e328a27e26843cfdc6719b152ac7d Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 13:14:52 -0400 Subject: widgets are now watch faces --- movement/make/Makefile | 20 ++-- movement/movement.c | 40 +++---- movement/movement.h | 34 +++--- movement/movement_config.h | 18 ++-- movement/watch_faces/clock/simple_clock_face.c | 92 ++++++++++++++++ movement/watch_faces/clock/simple_clock_face.h | 20 ++++ .../watch_faces/complications/pulseometer_face.c | 87 +++++++++++++++ .../watch_faces/complications/pulseometer_face.h | 24 +++++ movement/watch_faces/settings/preferences_face.c | 120 +++++++++++++++++++++ movement/watch_faces/settings/preferences_face.h | 18 ++++ movement/watch_faces/settings/set_time_face.c | 109 +++++++++++++++++++ movement/watch_faces/settings/set_time_face.h | 18 ++++ movement/widgets/clock/simple_clock_widget.c | 92 ---------------- movement/widgets/clock/simple_clock_widget.h | 20 ---- .../widgets/complications/pulseometer_widget.c | 87 --------------- .../widgets/complications/pulseometer_widget.h | 24 ----- movement/widgets/settings/preferences_widget.c | 120 --------------------- movement/widgets/settings/preferences_widget.h | 18 ---- movement/widgets/settings/set_time_widget.c | 109 ------------------- movement/widgets/settings/set_time_widget.h | 18 ---- 20 files changed, 544 insertions(+), 544 deletions(-) create mode 100644 movement/watch_faces/clock/simple_clock_face.c create mode 100644 movement/watch_faces/clock/simple_clock_face.h create mode 100644 movement/watch_faces/complications/pulseometer_face.c create mode 100644 movement/watch_faces/complications/pulseometer_face.h create mode 100644 movement/watch_faces/settings/preferences_face.c create mode 100644 movement/watch_faces/settings/preferences_face.h create mode 100644 movement/watch_faces/settings/set_time_face.c create mode 100644 movement/watch_faces/settings/set_time_face.h delete mode 100644 movement/widgets/clock/simple_clock_widget.c delete mode 100644 movement/widgets/clock/simple_clock_widget.h delete mode 100644 movement/widgets/complications/pulseometer_widget.c delete mode 100644 movement/widgets/complications/pulseometer_widget.h delete mode 100644 movement/widgets/settings/preferences_widget.c delete mode 100644 movement/widgets/settings/preferences_widget.h delete mode 100644 movement/widgets/settings/set_time_widget.c delete mode 100644 movement/widgets/settings/set_time_widget.h diff --git a/movement/make/Makefile b/movement/make/Makefile index 35b80079..8b29fba4 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -7,26 +7,26 @@ include $(TOP)/make.mk # INCLUDES += \ # -I../ \ # -I../drivers/ \ -# -I../widgets/fitness/ +# -I../watch_faces/fitness/ INCLUDES += \ -I../ \ - -I../widgets/ \ - -I../widgets/clock/ \ - -I../widgets/settings/ \ - -I../widgets/complications/ \ + -I../watch_faces/ \ + -I../watch_faces/clock/ \ + -I../watch_faces/settings/ \ + -I../watch_faces/complications/ \ # If you add any other source files you wish to compile, add them after ../app.c # Note that you will need to add a backslash at the end of any line you wish to continue, i.e. # SRCS += \ # ../movement.c \ # ../drivers/lis2dh.c \ -# ../widgets/fitness/step_count_widget.c +# ../watch_faces/fitness/step_count_face.c SRCS += \ ../movement.c \ - ../widgets/clock/simple_clock_widget.c \ - ../widgets/settings/preferences_widget.c \ - ../widgets/settings/set_time_widget.c \ - ../widgets/complications/pulseometer_widget.c \ + ../watch_faces/clock/simple_clock_face.c \ + ../watch_faces/settings/preferences_face.c \ + ../watch_faces/settings/set_time_face.c \ + ../watch_faces/complications/pulseometer_face.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/movement/movement.c b/movement/movement.c index 9c15833c..3417345c 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -6,7 +6,7 @@ #include "movement_config.h" LauncherState movement_state; -void * widget_contexts[MOVEMENT_NUM_WIDGETS]; +void * watch_face_contexts[MOVEMENT_NUM_FACES]; const int32_t movement_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; LauncherEvent event; @@ -33,13 +33,13 @@ void movement_illuminate_led() { movement_state.light_ticks = 3; } -void movement_move_to_widget(uint8_t widget_index) { - movement_state.widget_changed = true; - movement_state.next_widget = widget_index; +void movement_move_to_face(uint8_t watch_face_index) { + movement_state.watch_face_changed = true; + movement_state.next_face = watch_face_index; } -void movement_move_to_next_widget() { - movement_move_to_widget((movement_state.current_widget + 1) % MOVEMENT_NUM_WIDGETS); +void movement_move_to_next_face() { + movement_move_to_face((movement_state.current_watch_face + 1) % MOVEMENT_NUM_FACES); } void app_init() { @@ -59,8 +59,8 @@ void app_setup() { static bool is_first_launch = true; if (is_first_launch) { - for(uint8_t i = 0; i < MOVEMENT_NUM_WIDGETS; i++) { - widget_contexts[i] = NULL; + for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) { + watch_face_contexts[i] = NULL; is_first_launch = false; } } @@ -79,11 +79,11 @@ void app_setup() { movement_request_tick_frequency(1); - for(uint8_t i = 0; i < MOVEMENT_NUM_WIDGETS; i++) { - widgets[i].setup(&movement_state.movement_settings, &widget_contexts[i]); + for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) { + watch_faces[i].setup(&movement_state.movement_settings, &watch_face_contexts[i]); } - widgets[0].activate(&movement_state.movement_settings, widget_contexts[0]); + watch_faces[0].activate(&movement_state.movement_settings, watch_face_contexts[0]); event.subsecond = 0; event.event_type = EVENT_ACTIVATE; } @@ -96,18 +96,18 @@ void app_wake_from_sleep() { } bool app_loop() { - if (movement_state.widget_changed) { + if (movement_state.watch_face_changed) { if (movement_state.movement_settings.bit.button_should_sound) { - // low note for nonzero case, high note for return to widget 0 - watch_buzzer_play_note(movement_state.next_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); + // low note for nonzero case, high note for return to watch_face 0 + watch_buzzer_play_note(movement_state.next_face ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); } - widgets[movement_state.current_widget].resign(&movement_state.movement_settings, widget_contexts[movement_state.current_widget]); - movement_state.current_widget = movement_state.next_widget; + watch_faces[movement_state.current_watch_face].resign(&movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); + movement_state.current_watch_face = movement_state.next_face; watch_clear_display(); - widgets[movement_state.current_widget].activate(&movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + watch_faces[movement_state.current_watch_face].activate(&movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); event.subsecond = 0; event.event_type = EVENT_ACTIVATE; - movement_state.widget_changed = false; + movement_state.watch_face_changed = false; } // If the LED is off and should be on, turn it on @@ -144,7 +144,7 @@ bool app_loop() { // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. while (movement_state.screensaver_ticks == -1) { event.event_type = EVENT_SCREENSAVER; - widgets[movement_state.current_widget].loop(event, &movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + watch_faces[movement_state.current_watch_face].loop(event, &movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); watch_enter_shallow_sleep(true); } // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. @@ -158,7 +158,7 @@ bool app_loop() { if (event.event_type) { event.subsecond = movement_state.subsecond; - can_sleep = widgets[movement_state.current_widget].loop(event, &movement_state.movement_settings, widget_contexts[movement_state.current_widget]); + can_sleep = watch_faces[movement_state.current_watch_face].loop(event, &movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); event.event_type = EVENT_NONE; event.subsecond = 0; } diff --git a/movement/movement.h b/movement/movement.h index 025a5aa6..719a3d95 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -23,9 +23,9 @@ typedef union { typedef enum { EVENT_NONE = 0, // There is no event to report. - EVENT_ACTIVATE, // Your widget is entering the foreground. - EVENT_TICK, // Most common event type. Your widget is being called from the tick callback. - EVENT_SCREENSAVER, // Your widget is being asked to display its output for screensaver mode. + EVENT_ACTIVATE, // Your watch face is entering the foreground. + EVENT_TICK, // Most common event type. Your watch face is being called from the tick callback. + EVENT_SCREENSAVER, // Your watch face is being asked to display its output for screensaver mode. EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. @@ -42,26 +42,26 @@ typedef struct { uint8_t subsecond; } LauncherEvent; -typedef void (*movement_widget_setup)(LauncherSettings *settings, void ** context_ptr); -typedef void (*movement_widget_activate)(LauncherSettings *settings, void *context); -typedef bool (*movement_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context); -typedef void (*movement_widget_resign)(LauncherSettings *settings, void *context); +typedef void (*watch_face_setup)(LauncherSettings *settings, void ** context_ptr); +typedef void (*watch_face_activate)(LauncherSettings *settings, void *context); +typedef bool (*watch_face_loop)(LauncherEvent event, LauncherSettings *settings, void *context); +typedef void (*watch_face_resign)(LauncherSettings *settings, void *context); typedef struct { - movement_widget_setup setup; - movement_widget_activate activate; - movement_widget_loop loop; - movement_widget_resign resign; -} WatchWidget; + watch_face_setup setup; + watch_face_activate activate; + watch_face_loop loop; + watch_face_resign resign; +} WatchFace; typedef struct { // properties stored in BACKUP register LauncherSettings movement_settings; // transient properties - int16_t current_widget; - int16_t next_widget; - bool widget_changed; + int16_t current_watch_face; + int16_t next_face; + bool watch_face_changed; // LED stuff uint8_t light_ticks; @@ -81,8 +81,8 @@ typedef struct { uint8_t subsecond; } LauncherState; -void movement_move_to_widget(uint8_t widget_index); -void movement_move_to_next_widget(); +void movement_move_to_face(uint8_t watch_face_index); +void movement_move_to_next_face(); void movement_illuminate_led(); void movement_request_tick_frequency(uint8_t freq); diff --git a/movement/movement_config.h b/movement/movement_config.h index 49f342ca..41066d19 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -1,17 +1,17 @@ #ifndef MOVEMENT_CONFIG_H_ #define MOVEMENT_CONFIG_H_ -#include "simple_clock_widget.h" -#include "preferences_widget.h" -#include "set_time_widget.h" -#include "pulseometer_widget.h" +#include "simple_clock_face.h" +#include "preferences_face.h" +#include "set_time_face.h" +#include "pulseometer_face.h" -#define MOVEMENT_NUM_WIDGETS 3 +#define MOVEMENT_NUM_FACES 3 -WatchWidget widgets[MOVEMENT_NUM_WIDGETS] = { - simple_clock_widget, - preferences_widget, - set_time_widget, +WatchFace watch_faces[MOVEMENT_NUM_FACES] = { + simple_clock_face, + preferences_face, + set_time_face, }; diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c new file mode 100644 index 00000000..97067b0f --- /dev/null +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -0,0 +1,92 @@ +#include +#include "simple_clock_face.h" +#include "watch.h" + +void simple_clock_face_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + // the only context we need is the timestamp of the previous tick. + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint32_t)); +} + +void simple_clock_face_activate(LauncherSettings *settings, void *context) { + if (settings->bit.clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + } + watch_set_colon(); + // this ensures that none of the timestamp fields will match, so we can re-render them all. + *((uint32_t *)context) = 0xFFFFFFFF; +} + +bool simple_clock_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("simple_clock_face_loop\n"); + const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; + char buf[11]; + uint8_t pos; + + watch_date_time date_time; + uint32_t previous_date_time; + switch (event.event_type) { + case EVENT_ACTIVATE: + case EVENT_TICK: + case EVENT_SCREENSAVER: + date_time = watch_rtc_get_date_time(); + previous_date_time = *((uint32_t *)context); + *((uint32_t *)context) = date_time.reg; + + if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_SCREENSAVER) { + // everything before seconds is the same, don't waste cycles setting those segments. + pos = 8; + sprintf(buf, "%02d", date_time.unit.second); + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_SCREENSAVER) { + // everything before minutes is the same. + pos = 6; + sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); + } else { + // other stuff changed; let's do it all. + if (!settings->bit.clock_mode_24h) { + // if we are in 12 hour mode, do some cleanup. + if (date_time.unit.hour < 12) { + watch_clear_indicator(WATCH_INDICATOR_PM); + } else { + watch_set_indicator(WATCH_INDICATOR_PM); + } + date_time.unit.hour %= 12; + if (date_time.unit.hour == 0) date_time.unit.hour = 12; + } + pos = 0; + if (event.event_type == EVENT_SCREENSAVER) { + sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); + } else { + sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } + } + watch_display_string(buf, pos); + break; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + return false; + case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_UP: + break; + default: + break; + } + + return true; +} + +void simple_clock_face_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} + +uint8_t simple_clock_face_get_weekday(uint16_t year, uint16_t month, uint16_t day) { + year += 20; + if (month <= 2) { + month += 12; + year--; + } + return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7; +} diff --git a/movement/watch_faces/clock/simple_clock_face.h b/movement/watch_faces/clock/simple_clock_face.h new file mode 100644 index 00000000..59201a1f --- /dev/null +++ b/movement/watch_faces/clock/simple_clock_face.h @@ -0,0 +1,20 @@ +#ifndef SIMPLE_CLOCK_FACE_H_ +#define SIMPLE_CLOCK_FACE_H_ + +#include "movement.h" + +void simple_clock_face_setup(LauncherSettings *settings, void ** context_ptr); +void simple_clock_face_activate(LauncherSettings *settings, void *context); +bool simple_clock_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void simple_clock_face_resign(LauncherSettings *settings, void *context); + +uint8_t simple_clock_face_get_weekday(uint16_t day, uint16_t month, uint16_t year); + +#define simple_clock_face { \ + simple_clock_face_setup, \ + simple_clock_face_activate, \ + simple_clock_face_loop, \ + simple_clock_face_resign, \ +} + +#endif // FAKE_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/complications/pulseometer_face.c b/movement/watch_faces/complications/pulseometer_face.c new file mode 100644 index 00000000..e38153d6 --- /dev/null +++ b/movement/watch_faces/complications/pulseometer_face.c @@ -0,0 +1,87 @@ +#include +#include +#include "pulseometer_face.h" +#include "watch.h" + +#define PULSOMETER_FACE_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) +#define PULSOMETER_FACE_FREQUENCY (1 << PULSOMETER_FACE_FREQUENCY_FACTOR) + +void pulseometer_face_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); +} + +void pulseometer_face_activate(LauncherSettings *settings, void *context) { + (void) settings; + memset(context, 0, sizeof(PulsometerState)); +} + +bool pulseometer_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("pulseometer_face_loop\n"); + (void) settings; + PulsometerState *pulsometer_state = (PulsometerState *)context; + char buf[14]; + switch (event.event_type) { + case EVENT_TICK: + if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { + switch (pulsometer_state->ticks % 5) { + case 0: + watch_display_string(" Hold ", 2); + break; + case 1: + watch_display_string(" Alarn", 4); + break; + case 2: + watch_display_string("+ Count ", 0); + break; + case 3: + watch_display_string(" 30Beats ", 0); + break; + case 4: + watch_clear_display(); + break; + } + pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; + } else { + if (pulsometer_state->measuring && pulsometer_state->ticks) { + pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_FACE_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); + } + if (pulsometer_state->pulse > 240) { + watch_display_string(" Hi", 0); + } else if (pulsometer_state->pulse < 40) { + watch_display_string(" Lo", 0); + } else { + sprintf(buf, " %-3dbpn", pulsometer_state->pulse); + watch_display_string(buf, 0); + } + if (pulsometer_state->measuring) pulsometer_state->ticks++; + } + return false; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + return false; + case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_DOWN: + pulsometer_state->ticks = 0; + pulsometer_state->pulse = 0xFFFF; + pulsometer_state->measuring = true; + movement_request_tick_frequency(PULSOMETER_FACE_FREQUENCY); + break; + case EVENT_ALARM_BUTTON_UP: + case EVENT_ALARM_LONG_PRESS: + pulsometer_state->measuring = false; + movement_request_tick_frequency(1); + break; + default: + break; + } + + return true; +} + +void pulseometer_face_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/movement/watch_faces/complications/pulseometer_face.h b/movement/watch_faces/complications/pulseometer_face.h new file mode 100644 index 00000000..7b96259c --- /dev/null +++ b/movement/watch_faces/complications/pulseometer_face.h @@ -0,0 +1,24 @@ +#ifndef PULSEOMETER_FACE_H_ +#define PULSEOMETER_FACE_H_ + +#include "movement.h" + +typedef struct { + bool measuring; + int16_t pulse; + int16_t ticks; +} PulsometerState; + +void pulseometer_face_setup(LauncherSettings *settings, void ** context_ptr); +void pulseometer_face_activate(LauncherSettings *settings, void *context); +bool pulseometer_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void pulseometer_face_resign(LauncherSettings *settings, void *context); + +#define pulseometer_face { \ + pulseometer_face_setup, \ + pulseometer_face_activate, \ + pulseometer_face_loop, \ + pulseometer_face_resign, \ +} + +#endif // PULSEOMETER_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/settings/preferences_face.c b/movement/watch_faces/settings/preferences_face.c new file mode 100644 index 00000000..f499e36f --- /dev/null +++ b/movement/watch_faces/settings/preferences_face.c @@ -0,0 +1,120 @@ +#include +#include "preferences_face.h" +#include "watch.h" + +#define PREFERENCES_FACE_NUM_PREFEFENCES (5) +const char preferences_face_titles[PREFERENCES_FACE_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; + +void preferences_face_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); +} + +void preferences_face_activate(LauncherSettings *settings, void *context) { + (void) settings; + *((uint8_t *)context) = 0; + movement_request_tick_frequency(4); // we need to manually blink some pixels +} + +bool preferences_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + printf("preferences_face_loop\n"); + uint8_t current_page = *((uint8_t *)context); + switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + watch_set_led_off(); + movement_move_to_next_face(); + return false; + case EVENT_LIGHT_BUTTON_UP: + current_page = (current_page + 1) % PREFERENCES_FACE_NUM_PREFEFENCES; + *((uint8_t *)context) = current_page; + break; + case EVENT_ALARM_BUTTON_UP: + switch (current_page) { + case 0: + settings->bit.clock_mode_24h = !(settings->bit.clock_mode_24h); + break; + case 1: + settings->bit.button_should_sound = !(settings->bit.button_should_sound); + break; + case 2: + settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1; + break; + case 3: + settings->bit.led_green_color = settings->bit.led_green_color + 1; + break; + case 4: + settings->bit.led_red_color = settings->bit.led_red_color + 1; + break; + } + break; + default: + break; + } + + watch_display_string((char *)preferences_face_titles[current_page], 0); + + if (event.subsecond % 2) return current_page <= 2; + char buf[3]; + switch (current_page) { + case 0: + if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); + else watch_display_string("12h", 4); + break; + case 1: + if (settings->bit.button_should_sound) watch_display_string("y", 9); + else watch_display_string("n", 9); + break; + case 2: + switch (settings->bit.screensaver_interval) { + case 0: + watch_display_string(" never", 4); + break; + case 1: + watch_display_string("1 hour", 4); + break; + case 2: + watch_display_string("2 hour", 4); + break; + case 3: + watch_display_string("6 hour", 4); + break; + case 4: + watch_display_string("12 hr", 4); + break; + case 5: + watch_display_string(" 1 day", 4); + break; + case 6: + watch_display_string(" 2 day", 4); + break; + case 7: + watch_display_string(" 7 day", 4); + break; + } + break; + case 3: + sprintf(buf, "%2d", settings->bit.led_green_color); + watch_display_string(buf, 8); + break; + case 4: + sprintf(buf, "%2d", settings->bit.led_red_color); + watch_display_string(buf, 8); + break; + } + + if (current_page > 2) { + watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, + settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); + return false; + } + + watch_set_led_off(); + return true; +} + +void preferences_face_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + watch_set_led_off(); + movement_request_tick_frequency(1); +} diff --git a/movement/watch_faces/settings/preferences_face.h b/movement/watch_faces/settings/preferences_face.h new file mode 100644 index 00000000..218f99c2 --- /dev/null +++ b/movement/watch_faces/settings/preferences_face.h @@ -0,0 +1,18 @@ +#ifndef PREFERENCES_FACE_H_ +#define PREFERENCES_FACE_H_ + +#include "movement.h" + +void preferences_face_setup(LauncherSettings *settings, void ** context_ptr); +void preferences_face_activate(LauncherSettings *settings, void *context); +bool preferences_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void preferences_face_resign(LauncherSettings *settings, void *context); + +#define preferences_face { \ + preferences_face_setup, \ + preferences_face_activate, \ + preferences_face_loop, \ + preferences_face_resign, \ +} + +#endif // PREFERENCES_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/settings/set_time_face.c b/movement/watch_faces/settings/set_time_face.c new file mode 100644 index 00000000..36498611 --- /dev/null +++ b/movement/watch_faces/settings/set_time_face.c @@ -0,0 +1,109 @@ +#include +#include "set_time_face.h" +#include "watch.h" + +#define SET_TIME_FACE_NUM_SETTINGS (6) +const char set_time_face_titles[SET_TIME_FACE_NUM_SETTINGS][3] = {"HR", "MN", "SE", "YR", "MO", "DA"}; + +void set_time_face_setup(LauncherSettings *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); +} + +void set_time_face_activate(LauncherSettings *settings, void *context) { + (void) settings; + *((uint8_t *)context) = 0; + movement_request_tick_frequency(4); +} + +bool set_time_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { + uint8_t current_page = *((uint8_t *)context); + const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; + watch_date_time date_time = watch_rtc_get_date_time(); + + switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + return false; + case EVENT_LIGHT_BUTTON_UP: + current_page = (current_page + 1) % SET_TIME_FACE_NUM_SETTINGS; + *((uint8_t *)context) = current_page; + break; + case EVENT_ALARM_BUTTON_UP: + switch (current_page) { + case 0: // hour + date_time.unit.hour = (date_time.unit.hour + 1) % 24; + break; + case 1: // minute + date_time.unit.minute = (date_time.unit.minute + 1) % 60; + break; + case 2: // second + date_time.unit.second = 0; + break; + case 3: // year + // only allow 2021-2030. fix this sometime next decade + date_time.unit.year = ((date_time.unit.year % 10) + 1); + break; + case 4: // month + date_time.unit.month = (date_time.unit.month % 12) + 1; + break; + case 5: // day + date_time.unit.day = date_time.unit.day + 1; + // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. + // and it should roll over. + if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { + date_time.unit.day = 1; + } + break; + } + watch_rtc_set_date_time(date_time); + break; + default: + break; + } + + char buf[11]; + if (current_page < 3) { + watch_set_colon(); + if (settings->bit.clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } else { + sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second); + if (date_time.unit.hour > 12) watch_set_indicator(WATCH_INDICATOR_PM); + else watch_clear_indicator(WATCH_INDICATOR_PM); + } + } else { + watch_clear_colon(); + watch_clear_indicator(WATCH_INDICATOR_24H); + watch_clear_indicator(WATCH_INDICATOR_PM); + sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day); + } + if (event.subsecond % 2) { + switch (current_page) { + case 0: + case 3: + buf[4] = buf[5] = ' '; + break; + case 1: + case 4: + buf[6] = buf[7] = ' '; + break; + case 2: + case 5: + buf[8] = buf[9] = ' '; + break; + } + } + + watch_display_string(buf, 0); + + return true; +} + +void set_time_face_resign(LauncherSettings *settings, void *context) { + (void) settings; + (void) context; + watch_set_led_off(); + movement_request_tick_frequency(1); +} diff --git a/movement/watch_faces/settings/set_time_face.h b/movement/watch_faces/settings/set_time_face.h new file mode 100644 index 00000000..0c34d6b2 --- /dev/null +++ b/movement/watch_faces/settings/set_time_face.h @@ -0,0 +1,18 @@ +#ifndef SET_TIME_FACE_H_ +#define SET_TIME_FACE_H_ + +#include "movement.h" + +void set_time_face_setup(LauncherSettings *settings, void ** context_ptr); +void set_time_face_activate(LauncherSettings *settings, void *context); +bool set_time_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); +void set_time_face_resign(LauncherSettings *settings, void *context); + +#define set_time_face { \ + set_time_face_setup, \ + set_time_face_activate, \ + set_time_face_loop, \ + set_time_face_resign, \ +} + +#endif // SET_TIME_FACE_H_ diff --git a/movement/widgets/clock/simple_clock_widget.c b/movement/widgets/clock/simple_clock_widget.c deleted file mode 100644 index 22218860..00000000 --- a/movement/widgets/clock/simple_clock_widget.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "simple_clock_widget.h" -#include "watch.h" - -void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - // the only context we need is the timestamp of the previous tick. - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint32_t)); -} - -void simple_clock_widget_activate(LauncherSettings *settings, void *context) { - if (settings->bit.clock_mode_24h) { - watch_set_indicator(WATCH_INDICATOR_24H); - } - watch_set_colon(); - // this ensures that none of the timestamp fields will match, so we can re-render them all. - *((uint32_t *)context) = 0xFFFFFFFF; -} - -bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("simple_clock_widget_loop\n"); - const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; - char buf[11]; - uint8_t pos; - - watch_date_time date_time; - uint32_t previous_date_time; - switch (event.event_type) { - case EVENT_ACTIVATE: - case EVENT_TICK: - case EVENT_SCREENSAVER: - date_time = watch_rtc_get_date_time(); - previous_date_time = *((uint32_t *)context); - *((uint32_t *)context) = date_time.reg; - - if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_SCREENSAVER) { - // everything before seconds is the same, don't waste cycles setting those segments. - pos = 8; - sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_SCREENSAVER) { - // everything before minutes is the same. - pos = 6; - sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); - } else { - // other stuff changed; let's do it all. - if (!settings->bit.clock_mode_24h) { - // if we are in 12 hour mode, do some cleanup. - if (date_time.unit.hour < 12) { - watch_clear_indicator(WATCH_INDICATOR_PM); - } else { - watch_set_indicator(WATCH_INDICATOR_PM); - } - date_time.unit.hour %= 12; - if (date_time.unit.hour == 0) date_time.unit.hour = 12; - } - pos = 0; - if (event.event_type == EVENT_SCREENSAVER) { - sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); - } else { - sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); - } - } - watch_display_string(buf, pos); - break; - case EVENT_MODE_BUTTON_UP: - movement_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - movement_illuminate_led(); - break; - case EVENT_ALARM_BUTTON_UP: - break; - default: - break; - } - - return true; -} - -void simple_clock_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} - -uint8_t simple_clock_widget_get_weekday(uint16_t year, uint16_t month, uint16_t day) { - year += 20; - if (month <= 2) { - month += 12; - year--; - } - return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7; -} diff --git a/movement/widgets/clock/simple_clock_widget.h b/movement/widgets/clock/simple_clock_widget.h deleted file mode 100644 index 3bf4c9a3..00000000 --- a/movement/widgets/clock/simple_clock_widget.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SIMPLE_CLOCK_WIDGET_H_ -#define SIMPLE_CLOCK_WIDGET_H_ - -#include "movement.h" - -void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr); -void simple_clock_widget_activate(LauncherSettings *settings, void *context); -bool simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void simple_clock_widget_resign(LauncherSettings *settings, void *context); - -uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year); - -#define simple_clock_widget { \ - simple_clock_widget_setup, \ - simple_clock_widget_activate, \ - simple_clock_widget_loop, \ - simple_clock_widget_resign, \ -} - -#endif // FAKE_WIDGET_H_ \ No newline at end of file diff --git a/movement/widgets/complications/pulseometer_widget.c b/movement/widgets/complications/pulseometer_widget.c deleted file mode 100644 index 6384685a..00000000 --- a/movement/widgets/complications/pulseometer_widget.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include "pulseometer_widget.h" -#include "watch.h" - -#define PULSOMETER_WIDGET_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) -#define PULSOMETER_WIDGET_FREQUENCY (1 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) - -void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); -} - -void pulseometer_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - memset(context, 0, sizeof(PulsometerState)); -} - -bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("pulseometer_widget_loop\n"); - (void) settings; - PulsometerState *pulsometer_state = (PulsometerState *)context; - char buf[14]; - switch (event.event_type) { - case EVENT_TICK: - if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { - switch (pulsometer_state->ticks % 5) { - case 0: - watch_display_string(" Hold ", 2); - break; - case 1: - watch_display_string(" Alarn", 4); - break; - case 2: - watch_display_string("+ Count ", 0); - break; - case 3: - watch_display_string(" 30Beats ", 0); - break; - case 4: - watch_clear_display(); - break; - } - pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; - } else { - if (pulsometer_state->measuring && pulsometer_state->ticks) { - pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_WIDGET_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); - } - if (pulsometer_state->pulse > 240) { - watch_display_string(" Hi", 0); - } else if (pulsometer_state->pulse < 40) { - watch_display_string(" Lo", 0); - } else { - sprintf(buf, " %-3dbpn", pulsometer_state->pulse); - watch_display_string(buf, 0); - } - if (pulsometer_state->measuring) pulsometer_state->ticks++; - } - return false; - case EVENT_MODE_BUTTON_UP: - movement_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - movement_illuminate_led(); - break; - case EVENT_ALARM_BUTTON_DOWN: - pulsometer_state->ticks = 0; - pulsometer_state->pulse = 0xFFFF; - pulsometer_state->measuring = true; - movement_request_tick_frequency(PULSOMETER_WIDGET_FREQUENCY); - break; - case EVENT_ALARM_BUTTON_UP: - case EVENT_ALARM_LONG_PRESS: - pulsometer_state->measuring = false; - movement_request_tick_frequency(1); - break; - default: - break; - } - - return true; -} - -void pulseometer_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; -} diff --git a/movement/widgets/complications/pulseometer_widget.h b/movement/widgets/complications/pulseometer_widget.h deleted file mode 100644 index e5947660..00000000 --- a/movement/widgets/complications/pulseometer_widget.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PULSEOMETER_WIDGET_H_ -#define PULSEOMETER_WIDGET_H_ - -#include "movement.h" - -typedef struct { - bool measuring; - int16_t pulse; - int16_t ticks; -} PulsometerState; - -void pulseometer_widget_setup(LauncherSettings *settings, void ** context_ptr); -void pulseometer_widget_activate(LauncherSettings *settings, void *context); -bool pulseometer_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void pulseometer_widget_resign(LauncherSettings *settings, void *context); - -#define pulseometer_widget { \ - pulseometer_widget_setup, \ - pulseometer_widget_activate, \ - pulseometer_widget_loop, \ - pulseometer_widget_resign, \ -} - -#endif // PULSEOMETER_WIDGET_H_ \ No newline at end of file diff --git a/movement/widgets/settings/preferences_widget.c b/movement/widgets/settings/preferences_widget.c deleted file mode 100644 index c4537329..00000000 --- a/movement/widgets/settings/preferences_widget.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include "preferences_widget.h" -#include "watch.h" - -#define PREFERENCES_WIDGET_NUM_PREFEFENCES (5) -const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; - -void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); -} - -void preferences_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - *((uint8_t *)context) = 0; - movement_request_tick_frequency(4); // we need to manually blink some pixels -} - -bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - printf("preferences_widget_loop\n"); - uint8_t current_page = *((uint8_t *)context); - switch (event.event_type) { - case EVENT_MODE_BUTTON_UP: - watch_set_led_off(); - movement_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - current_page = (current_page + 1) % PREFERENCES_WIDGET_NUM_PREFEFENCES; - *((uint8_t *)context) = current_page; - break; - case EVENT_ALARM_BUTTON_UP: - switch (current_page) { - case 0: - settings->bit.clock_mode_24h = !(settings->bit.clock_mode_24h); - break; - case 1: - settings->bit.button_should_sound = !(settings->bit.button_should_sound); - break; - case 2: - settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1; - break; - case 3: - settings->bit.led_green_color = settings->bit.led_green_color + 1; - break; - case 4: - settings->bit.led_red_color = settings->bit.led_red_color + 1; - break; - } - break; - default: - break; - } - - watch_display_string((char *)preferences_widget_titles[current_page], 0); - - if (event.subsecond % 2) return current_page <= 2; - char buf[3]; - switch (current_page) { - case 0: - if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); - else watch_display_string("12h", 4); - break; - case 1: - if (settings->bit.button_should_sound) watch_display_string("y", 9); - else watch_display_string("n", 9); - break; - case 2: - switch (settings->bit.screensaver_interval) { - case 0: - watch_display_string(" never", 4); - break; - case 1: - watch_display_string("1 hour", 4); - break; - case 2: - watch_display_string("2 hour", 4); - break; - case 3: - watch_display_string("6 hour", 4); - break; - case 4: - watch_display_string("12 hr", 4); - break; - case 5: - watch_display_string(" 1 day", 4); - break; - case 6: - watch_display_string(" 2 day", 4); - break; - case 7: - watch_display_string(" 7 day", 4); - break; - } - break; - case 3: - sprintf(buf, "%2d", settings->bit.led_green_color); - watch_display_string(buf, 8); - break; - case 4: - sprintf(buf, "%2d", settings->bit.led_red_color); - watch_display_string(buf, 8); - break; - } - - if (current_page > 2) { - watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, - settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); - return false; - } - - watch_set_led_off(); - return true; -} - -void preferences_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; - watch_set_led_off(); - movement_request_tick_frequency(1); -} diff --git a/movement/widgets/settings/preferences_widget.h b/movement/widgets/settings/preferences_widget.h deleted file mode 100644 index 3d463027..00000000 --- a/movement/widgets/settings/preferences_widget.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PREFERENCES_WIDGET_H_ -#define PREFERENCES_WIDGET_H_ - -#include "movement.h" - -void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr); -void preferences_widget_activate(LauncherSettings *settings, void *context); -bool preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void preferences_widget_resign(LauncherSettings *settings, void *context); - -#define preferences_widget { \ - preferences_widget_setup, \ - preferences_widget_activate, \ - preferences_widget_loop, \ - preferences_widget_resign, \ -} - -#endif // PREFERENCES_WIDGET_H_ \ No newline at end of file diff --git a/movement/widgets/settings/set_time_widget.c b/movement/widgets/settings/set_time_widget.c deleted file mode 100644 index 9464eb5b..00000000 --- a/movement/widgets/settings/set_time_widget.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include "set_time_widget.h" -#include "watch.h" - -#define SET_TIME_WIDGET_NUM_SETTINGS (6) -const char set_time_widget_titles[SET_TIME_WIDGET_NUM_SETTINGS][3] = {"HR", "MN", "SE", "YR", "MO", "DA"}; - -void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); -} - -void set_time_widget_activate(LauncherSettings *settings, void *context) { - (void) settings; - *((uint8_t *)context) = 0; - movement_request_tick_frequency(4); -} - -bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) { - uint8_t current_page = *((uint8_t *)context); - const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; - watch_date_time date_time = watch_rtc_get_date_time(); - - switch (event.event_type) { - case EVENT_MODE_BUTTON_UP: - movement_move_to_next_widget(); - return false; - case EVENT_LIGHT_BUTTON_UP: - current_page = (current_page + 1) % SET_TIME_WIDGET_NUM_SETTINGS; - *((uint8_t *)context) = current_page; - break; - case EVENT_ALARM_BUTTON_UP: - switch (current_page) { - case 0: // hour - date_time.unit.hour = (date_time.unit.hour + 1) % 24; - break; - case 1: // minute - date_time.unit.minute = (date_time.unit.minute + 1) % 60; - break; - case 2: // second - date_time.unit.second = 0; - break; - case 3: // year - // only allow 2021-2030. fix this sometime next decade - date_time.unit.year = ((date_time.unit.year % 10) + 1); - break; - case 4: // month - date_time.unit.month = (date_time.unit.month % 12) + 1; - break; - case 5: // day - date_time.unit.day = date_time.unit.day + 1; - // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th. - // and it should roll over. - if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) { - date_time.unit.day = 1; - } - break; - } - watch_rtc_set_date_time(date_time); - break; - default: - break; - } - - char buf[11]; - if (current_page < 3) { - watch_set_colon(); - if (settings->bit.clock_mode_24h) { - watch_set_indicator(WATCH_INDICATOR_24H); - sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.hour, date_time.unit.minute, date_time.unit.second); - } else { - sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12, date_time.unit.minute, date_time.unit.second); - if (date_time.unit.hour > 12) watch_set_indicator(WATCH_INDICATOR_PM); - else watch_clear_indicator(WATCH_INDICATOR_PM); - } - } else { - watch_clear_colon(); - watch_clear_indicator(WATCH_INDICATOR_24H); - watch_clear_indicator(WATCH_INDICATOR_PM); - sprintf(buf, "%s %2d%02d%02d", set_time_widget_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day); - } - if (event.subsecond % 2) { - switch (current_page) { - case 0: - case 3: - buf[4] = buf[5] = ' '; - break; - case 1: - case 4: - buf[6] = buf[7] = ' '; - break; - case 2: - case 5: - buf[8] = buf[9] = ' '; - break; - } - } - - watch_display_string(buf, 0); - - return true; -} - -void set_time_widget_resign(LauncherSettings *settings, void *context) { - (void) settings; - (void) context; - watch_set_led_off(); - movement_request_tick_frequency(1); -} diff --git a/movement/widgets/settings/set_time_widget.h b/movement/widgets/settings/set_time_widget.h deleted file mode 100644 index 363fd571..00000000 --- a/movement/widgets/settings/set_time_widget.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SET_TIME_WIDGET_H_ -#define SET_TIME_WIDGET_H_ - -#include "movement.h" - -void set_time_widget_setup(LauncherSettings *settings, void ** context_ptr); -void set_time_widget_activate(LauncherSettings *settings, void *context); -bool set_time_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void set_time_widget_resign(LauncherSettings *settings, void *context); - -#define set_time_widget { \ - set_time_widget_setup, \ - set_time_widget_activate, \ - set_time_widget_loop, \ - set_time_widget_resign, \ -} - -#endif // SET_TIME_WIDGET_H_ -- cgit v1.2.3 From d36331ce4e79d275e0ef09414a1a1a1a8949b0ea Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 13:23:23 -0400 Subject: rename types to be more c-like --- movement/movement.c | 12 ++++++------ movement/movement.h | 20 ++++++++++---------- movement/movement_config.h | 2 +- movement/watch_faces/clock/simple_clock_face.c | 8 ++++---- movement/watch_faces/clock/simple_clock_face.h | 8 ++++---- .../watch_faces/complications/pulseometer_face.c | 8 ++++---- .../watch_faces/complications/pulseometer_face.h | 8 ++++---- movement/watch_faces/settings/preferences_face.c | 8 ++++---- movement/watch_faces/settings/preferences_face.h | 8 ++++---- movement/watch_faces/settings/set_time_face.c | 8 ++++---- movement/watch_faces/settings/set_time_face.h | 8 ++++---- 11 files changed, 49 insertions(+), 49 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 3417345c..779674c7 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -5,10 +5,10 @@ #include "movement.h" #include "movement_config.h" -LauncherState movement_state; +movement_state_t movement_state; void * watch_face_contexts[MOVEMENT_NUM_FACES]; const int32_t movement_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; -LauncherEvent event; +movement_event_t event; void cb_mode_btn_interrupt(); void cb_light_btn_interrupt(); @@ -166,16 +166,16 @@ bool app_loop() { return can_sleep && !movement_state.led_on; } -LauncherEventType _figure_out_button_event(LauncherEventType button_down_event, uint8_t *down_timestamp) { +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; *down_timestamp = 0; - if (diff > 1) return button_down_event + 2; - else return button_down_event + 1; + if (diff > 1) 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; + return button_down_event_type; } } diff --git a/movement/movement.h b/movement/movement.h index 719a3d95..d78e0f44 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -19,7 +19,7 @@ typedef union { uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) } bit; uint32_t value; -} LauncherSettings; +} movement_settings_t; typedef enum { EVENT_NONE = 0, // There is no event to report. @@ -35,28 +35,28 @@ typedef enum { EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released. EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released. EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released. -} LauncherEventType; +} movement_event_type_t; typedef struct { uint8_t event_type; uint8_t subsecond; -} LauncherEvent; +} movement_event_t; -typedef void (*watch_face_setup)(LauncherSettings *settings, void ** context_ptr); -typedef void (*watch_face_activate)(LauncherSettings *settings, void *context); -typedef bool (*watch_face_loop)(LauncherEvent event, LauncherSettings *settings, void *context); -typedef void (*watch_face_resign)(LauncherSettings *settings, void *context); +typedef void (*watch_face_setup)(movement_settings_t *settings, void ** context_ptr); +typedef void (*watch_face_activate)(movement_settings_t *settings, void *context); +typedef bool (*watch_face_loop)(movement_event_t event, movement_settings_t *settings, void *context); +typedef void (*watch_face_resign)(movement_settings_t *settings, void *context); typedef struct { watch_face_setup setup; watch_face_activate activate; watch_face_loop loop; watch_face_resign resign; -} WatchFace; +} watch_face_t; typedef struct { // properties stored in BACKUP register - LauncherSettings movement_settings; + movement_settings_t movement_settings; // transient properties int16_t current_watch_face; @@ -79,7 +79,7 @@ typedef struct { uint8_t tick_frequency; uint8_t last_second; uint8_t subsecond; -} LauncherState; +} movement_state_t; void movement_move_to_face(uint8_t watch_face_index); void movement_move_to_next_face(); diff --git a/movement/movement_config.h b/movement/movement_config.h index 41066d19..172736f1 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -8,7 +8,7 @@ #define MOVEMENT_NUM_FACES 3 -WatchFace watch_faces[MOVEMENT_NUM_FACES] = { +watch_face_t watch_faces[MOVEMENT_NUM_FACES] = { simple_clock_face, preferences_face, set_time_face, diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index 97067b0f..bdee7dec 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -2,13 +2,13 @@ #include "simple_clock_face.h" #include "watch.h" -void simple_clock_face_setup(LauncherSettings *settings, void ** context_ptr) { +void simple_clock_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; // the only context we need is the timestamp of the previous tick. if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint32_t)); } -void simple_clock_face_activate(LauncherSettings *settings, void *context) { +void simple_clock_face_activate(movement_settings_t *settings, void *context) { if (settings->bit.clock_mode_24h) { watch_set_indicator(WATCH_INDICATOR_24H); } @@ -17,7 +17,7 @@ void simple_clock_face_activate(LauncherSettings *settings, void *context) { *((uint32_t *)context) = 0xFFFFFFFF; } -bool simple_clock_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool simple_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { printf("simple_clock_face_loop\n"); const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; char buf[11]; @@ -77,7 +77,7 @@ bool simple_clock_face_loop(LauncherEvent event, LauncherSettings *settings, voi return true; } -void simple_clock_face_resign(LauncherSettings *settings, void *context) { +void simple_clock_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; } diff --git a/movement/watch_faces/clock/simple_clock_face.h b/movement/watch_faces/clock/simple_clock_face.h index 59201a1f..3cdc09e8 100644 --- a/movement/watch_faces/clock/simple_clock_face.h +++ b/movement/watch_faces/clock/simple_clock_face.h @@ -3,10 +3,10 @@ #include "movement.h" -void simple_clock_face_setup(LauncherSettings *settings, void ** context_ptr); -void simple_clock_face_activate(LauncherSettings *settings, void *context); -bool simple_clock_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void simple_clock_face_resign(LauncherSettings *settings, void *context); +void simple_clock_face_setup(movement_settings_t *settings, void ** context_ptr); +void simple_clock_face_activate(movement_settings_t *settings, void *context); +bool simple_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void simple_clock_face_resign(movement_settings_t *settings, void *context); uint8_t simple_clock_face_get_weekday(uint16_t day, uint16_t month, uint16_t year); diff --git a/movement/watch_faces/complications/pulseometer_face.c b/movement/watch_faces/complications/pulseometer_face.c index e38153d6..7c524b8d 100644 --- a/movement/watch_faces/complications/pulseometer_face.c +++ b/movement/watch_faces/complications/pulseometer_face.c @@ -6,17 +6,17 @@ #define PULSOMETER_FACE_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) #define PULSOMETER_FACE_FREQUENCY (1 << PULSOMETER_FACE_FREQUENCY_FACTOR) -void pulseometer_face_setup(LauncherSettings *settings, void ** context_ptr) { +void pulseometer_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); } -void pulseometer_face_activate(LauncherSettings *settings, void *context) { +void pulseometer_face_activate(movement_settings_t *settings, void *context) { (void) settings; memset(context, 0, sizeof(PulsometerState)); } -bool pulseometer_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool pulseometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { printf("pulseometer_face_loop\n"); (void) settings; PulsometerState *pulsometer_state = (PulsometerState *)context; @@ -81,7 +81,7 @@ bool pulseometer_face_loop(LauncherEvent event, LauncherSettings *settings, void return true; } -void pulseometer_face_resign(LauncherSettings *settings, void *context) { +void pulseometer_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; } diff --git a/movement/watch_faces/complications/pulseometer_face.h b/movement/watch_faces/complications/pulseometer_face.h index 7b96259c..f8e69d27 100644 --- a/movement/watch_faces/complications/pulseometer_face.h +++ b/movement/watch_faces/complications/pulseometer_face.h @@ -9,10 +9,10 @@ typedef struct { int16_t ticks; } PulsometerState; -void pulseometer_face_setup(LauncherSettings *settings, void ** context_ptr); -void pulseometer_face_activate(LauncherSettings *settings, void *context); -bool pulseometer_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void pulseometer_face_resign(LauncherSettings *settings, void *context); +void pulseometer_face_setup(movement_settings_t *settings, void ** context_ptr); +void pulseometer_face_activate(movement_settings_t *settings, void *context); +bool pulseometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void pulseometer_face_resign(movement_settings_t *settings, void *context); #define pulseometer_face { \ pulseometer_face_setup, \ diff --git a/movement/watch_faces/settings/preferences_face.c b/movement/watch_faces/settings/preferences_face.c index f499e36f..18dff6cd 100644 --- a/movement/watch_faces/settings/preferences_face.c +++ b/movement/watch_faces/settings/preferences_face.c @@ -5,18 +5,18 @@ #define PREFERENCES_FACE_NUM_PREFEFENCES (5) const char preferences_face_titles[PREFERENCES_FACE_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; -void preferences_face_setup(LauncherSettings *settings, void ** context_ptr) { +void preferences_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); } -void preferences_face_activate(LauncherSettings *settings, void *context) { +void preferences_face_activate(movement_settings_t *settings, void *context) { (void) settings; *((uint8_t *)context) = 0; movement_request_tick_frequency(4); // we need to manually blink some pixels } -bool preferences_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool preferences_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { printf("preferences_face_loop\n"); uint8_t current_page = *((uint8_t *)context); switch (event.event_type) { @@ -112,7 +112,7 @@ bool preferences_face_loop(LauncherEvent event, LauncherSettings *settings, void return true; } -void preferences_face_resign(LauncherSettings *settings, void *context) { +void preferences_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; watch_set_led_off(); diff --git a/movement/watch_faces/settings/preferences_face.h b/movement/watch_faces/settings/preferences_face.h index 218f99c2..c8f1a14e 100644 --- a/movement/watch_faces/settings/preferences_face.h +++ b/movement/watch_faces/settings/preferences_face.h @@ -3,10 +3,10 @@ #include "movement.h" -void preferences_face_setup(LauncherSettings *settings, void ** context_ptr); -void preferences_face_activate(LauncherSettings *settings, void *context); -bool preferences_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void preferences_face_resign(LauncherSettings *settings, void *context); +void preferences_face_setup(movement_settings_t *settings, void ** context_ptr); +void preferences_face_activate(movement_settings_t *settings, void *context); +bool preferences_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void preferences_face_resign(movement_settings_t *settings, void *context); #define preferences_face { \ preferences_face_setup, \ diff --git a/movement/watch_faces/settings/set_time_face.c b/movement/watch_faces/settings/set_time_face.c index 36498611..7bb63d0b 100644 --- a/movement/watch_faces/settings/set_time_face.c +++ b/movement/watch_faces/settings/set_time_face.c @@ -5,18 +5,18 @@ #define SET_TIME_FACE_NUM_SETTINGS (6) const char set_time_face_titles[SET_TIME_FACE_NUM_SETTINGS][3] = {"HR", "MN", "SE", "YR", "MO", "DA"}; -void set_time_face_setup(LauncherSettings *settings, void ** context_ptr) { +void set_time_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; if (*context_ptr == NULL) *context_ptr = malloc(sizeof(uint8_t)); } -void set_time_face_activate(LauncherSettings *settings, void *context) { +void set_time_face_activate(movement_settings_t *settings, void *context) { (void) settings; *((uint8_t *)context) = 0; movement_request_tick_frequency(4); } -bool set_time_face_loop(LauncherEvent event, LauncherSettings *settings, void *context) { +bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { uint8_t current_page = *((uint8_t *)context); const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; watch_date_time date_time = watch_rtc_get_date_time(); @@ -101,7 +101,7 @@ bool set_time_face_loop(LauncherEvent event, LauncherSettings *settings, void *c return true; } -void set_time_face_resign(LauncherSettings *settings, void *context) { +void set_time_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; watch_set_led_off(); diff --git a/movement/watch_faces/settings/set_time_face.h b/movement/watch_faces/settings/set_time_face.h index 0c34d6b2..b330d852 100644 --- a/movement/watch_faces/settings/set_time_face.h +++ b/movement/watch_faces/settings/set_time_face.h @@ -3,10 +3,10 @@ #include "movement.h" -void set_time_face_setup(LauncherSettings *settings, void ** context_ptr); -void set_time_face_activate(LauncherSettings *settings, void *context); -bool set_time_face_loop(LauncherEvent event, LauncherSettings *settings, void *context); -void set_time_face_resign(LauncherSettings *settings, void *context); +void set_time_face_setup(movement_settings_t *settings, void ** context_ptr); +void set_time_face_activate(movement_settings_t *settings, void *context); +bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void set_time_face_resign(movement_settings_t *settings, void *context); #define set_time_face { \ set_time_face_setup, \ -- cgit v1.2.3 From 8f5de18b94ad4b01b43421e13e7d38e56afd54db Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 13:28:52 -0400 Subject: clarify property names --- movement/movement.c | 34 +++++++++++++++++----------------- movement/movement.h | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 779674c7..1a6ca496 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -19,7 +19,7 @@ void cb_tick(); static inline void _movement_reset_screensaver_countdown() { // for testing, make the timeout happen 60x faster. - movement_state.screensaver_ticks = movement_screensaver_deadlines[movement_state.movement_settings.bit.screensaver_interval] / 60; + movement_state.screensaver_ticks = movement_screensaver_deadlines[movement_state.settings.bit.screensaver_interval] / 60; } void movement_request_tick_frequency(uint8_t freq) { @@ -35,7 +35,7 @@ void movement_illuminate_led() { void movement_move_to_face(uint8_t watch_face_index) { movement_state.watch_face_changed = true; - movement_state.next_face = watch_face_index; + movement_state.next_watch_face = watch_face_index; } void movement_move_to_next_face() { @@ -45,9 +45,9 @@ void movement_move_to_next_face() { void app_init() { memset(&movement_state, 0, sizeof(movement_state)); - movement_state.movement_settings.bit.led_green_color = 0xF; - movement_state.movement_settings.bit.button_should_sound = true; - movement_state.movement_settings.bit.screensaver_interval = 1; + movement_state.settings.bit.led_green_color = 0xF; + movement_state.settings.bit.button_should_sound = true; + movement_state.settings.bit.screensaver_interval = 1; _movement_reset_screensaver_countdown(); } @@ -80,10 +80,10 @@ void app_setup() { movement_request_tick_frequency(1); for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) { - watch_faces[i].setup(&movement_state.movement_settings, &watch_face_contexts[i]); + watch_faces[i].setup(&movement_state.settings, &watch_face_contexts[i]); } - watch_faces[0].activate(&movement_state.movement_settings, watch_face_contexts[0]); + watch_faces[0].activate(&movement_state.settings, watch_face_contexts[0]); event.subsecond = 0; event.event_type = EVENT_ACTIVATE; } @@ -97,14 +97,14 @@ void app_wake_from_sleep() { bool app_loop() { if (movement_state.watch_face_changed) { - if (movement_state.movement_settings.bit.button_should_sound) { + if (movement_state.settings.bit.button_should_sound) { // low note for nonzero case, high note for return to watch_face 0 - watch_buzzer_play_note(movement_state.next_face ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); + watch_buzzer_play_note(movement_state.next_watch_face ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50); } - watch_faces[movement_state.current_watch_face].resign(&movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); - movement_state.current_watch_face = movement_state.next_face; + watch_faces[movement_state.current_watch_face].resign(&movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); + movement_state.current_watch_face = movement_state.next_watch_face; watch_clear_display(); - watch_faces[movement_state.current_watch_face].activate(&movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); + watch_faces[movement_state.current_watch_face].activate(&movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); event.subsecond = 0; event.event_type = EVENT_ACTIVATE; movement_state.watch_face_changed = false; @@ -112,8 +112,8 @@ bool app_loop() { // If the LED is off and should be on, turn it on if (movement_state.light_ticks > 0 && !movement_state.led_on) { - watch_set_led_color(movement_state.movement_settings.bit.led_red_color ? (0xF | movement_state.movement_settings.bit.led_red_color << 4) : 0, - movement_state.movement_settings.bit.led_green_color ? (0xF | movement_state.movement_settings.bit.led_green_color << 4) : 0); + 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; } @@ -144,7 +144,7 @@ bool app_loop() { // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. while (movement_state.screensaver_ticks == -1) { event.event_type = EVENT_SCREENSAVER; - watch_faces[movement_state.current_watch_face].loop(event, &movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); + watch_faces[movement_state.current_watch_face].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); watch_enter_shallow_sleep(true); } // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. @@ -158,7 +158,7 @@ bool app_loop() { if (event.event_type) { event.subsecond = movement_state.subsecond; - can_sleep = watch_faces[movement_state.current_watch_face].loop(event, &movement_state.movement_settings, watch_face_contexts[movement_state.current_watch_face]); + can_sleep = watch_faces[movement_state.current_watch_face].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); event.event_type = EVENT_NONE; event.subsecond = 0; } @@ -208,7 +208,7 @@ void cb_tick() { watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.second != movement_state.last_second) { if (movement_state.light_ticks) movement_state.light_ticks--; - if (movement_state.movement_settings.bit.screensaver_interval && movement_state.screensaver_ticks > 0) movement_state.screensaver_ticks--; + if (movement_state.settings.bit.screensaver_interval && movement_state.screensaver_ticks > 0) movement_state.screensaver_ticks--; movement_state.last_second = date_time.unit.second; movement_state.subsecond = 0; diff --git a/movement/movement.h b/movement/movement.h index d78e0f44..65b66ab5 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -56,11 +56,11 @@ typedef struct { typedef struct { // properties stored in BACKUP register - movement_settings_t movement_settings; + movement_settings_t settings; // transient properties int16_t current_watch_face; - int16_t next_face; + int16_t next_watch_face; bool watch_face_changed; // LED stuff -- cgit v1.2.3 From 3e539a9e6362841b9cd5924f0d309ec15b2698b1 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 13:40:17 -0400 Subject: screensaver mode is now low energy mode --- movement/movement.c | 38 ++++++++++++------------ movement/movement.h | 8 ++--- movement/watch_faces/clock/simple_clock_face.c | 8 ++--- movement/watch_faces/settings/preferences_face.c | 4 +-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 1a6ca496..9b7e90a0 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -7,7 +7,7 @@ movement_state_t movement_state; void * watch_face_contexts[MOVEMENT_NUM_FACES]; -const int32_t movement_screensaver_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; +const int32_t movement_inactivity_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; movement_event_t event; void cb_mode_btn_interrupt(); @@ -17,9 +17,9 @@ void cb_alarm_btn_extwake(); void cb_alarm_fired(); void cb_tick(); -static inline void _movement_reset_screensaver_countdown() { +static inline void _movement_reset_inactivity_countdown() { // for testing, make the timeout happen 60x faster. - movement_state.screensaver_ticks = movement_screensaver_deadlines[movement_state.settings.bit.screensaver_interval] / 60; + movement_state.le_mode_ticks = movement_inactivity_deadlines[movement_state.settings.bit.le_inactivity_interval] / 60; } void movement_request_tick_frequency(uint8_t freq) { @@ -47,8 +47,8 @@ void app_init() { movement_state.settings.bit.led_green_color = 0xF; movement_state.settings.bit.button_should_sound = true; - movement_state.settings.bit.screensaver_interval = 1; - _movement_reset_screensaver_countdown(); + movement_state.settings.bit.le_inactivity_interval = 1; + _movement_reset_inactivity_countdown(); } void app_wake_from_deep_sleep() { @@ -64,7 +64,7 @@ void app_setup() { is_first_launch = false; } } - if (movement_state.screensaver_ticks != -1) { + if (movement_state.le_mode_ticks != -1) { watch_disable_extwake_interrupt(BTN_ALARM); watch_rtc_disable_alarm_callback(); @@ -129,9 +129,9 @@ bool app_loop() { } } - // if we have timed out of our screensaver countdown, enter screensaver mode. - if (movement_state.screensaver_ticks == 0) { - movement_state.screensaver_ticks = -1; + // if we have timed out of our low energy mode countdown, enter low energy mode. + if (movement_state.le_mode_ticks == 0) { + movement_state.le_mode_ticks = -1; watch_date_time alarm_time; alarm_time.reg = 0; alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 @@ -141,13 +141,13 @@ bool app_loop() { event.subsecond = 0; // this is a little mini-runloop. - // as long as screensaver_ticks is -1 (i.e. screensaver is active), we wake up here, update the screen, and go right back to sleep. - while (movement_state.screensaver_ticks == -1) { - event.event_type = EVENT_SCREENSAVER; + // as long as le_mode_ticks is -1 (i.e. we are in low energy mode), we wake up here, update the screen, and go right back to sleep. + while (movement_state.le_mode_ticks == -1) { + event.event_type = EVENT_LOW_POWER_TICK; watch_faces[movement_state.current_watch_face].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); watch_enter_shallow_sleep(true); } - // as soon as screensaver_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. + // as soon as le_mode_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. event.event_type = EVENT_ACTIVATE; // this is a hack tho: waking from shallow sleep, app_setup does get called, but it happens before we have reset our ticks. // need to figure out if there's a better heuristic for determining how we woke up. @@ -180,27 +180,27 @@ movement_event_type_t _figure_out_button_event(movement_event_type_t button_down } void cb_light_btn_interrupt() { - _movement_reset_screensaver_countdown(); + _movement_reset_inactivity_countdown(); event.event_type = _figure_out_button_event(EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp); } void cb_mode_btn_interrupt() { - _movement_reset_screensaver_countdown(); + _movement_reset_inactivity_countdown(); event.event_type = _figure_out_button_event(EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp); } void cb_alarm_btn_interrupt() { - _movement_reset_screensaver_countdown(); + _movement_reset_inactivity_countdown(); event.event_type = _figure_out_button_event(EVENT_ALARM_BUTTON_DOWN, &movement_state.alarm_down_timestamp); } void cb_alarm_btn_extwake() { // wake up! - _movement_reset_screensaver_countdown(); + _movement_reset_inactivity_countdown(); } void cb_alarm_fired() { - event.event_type = EVENT_SCREENSAVER; + event.event_type = EVENT_LOW_POWER_TICK; } void cb_tick() { @@ -208,7 +208,7 @@ void cb_tick() { watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.second != movement_state.last_second) { if (movement_state.light_ticks) movement_state.light_ticks--; - if (movement_state.settings.bit.screensaver_interval && movement_state.screensaver_ticks > 0) movement_state.screensaver_ticks--; + if (movement_state.settings.bit.le_inactivity_interval && movement_state.le_mode_ticks > 0) movement_state.le_mode_ticks--; movement_state.last_second = date_time.unit.second; movement_state.subsecond = 0; diff --git a/movement/movement.h b/movement/movement.h index 65b66ab5..934254bc 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -13,7 +13,7 @@ typedef union { uint32_t alarm_should_sound : 1; // if true, the alarm interrupt can match a time and play a song. uint32_t alarm_minute : 6; // the minute of the alarm we want to match uint32_t alarm_hour : 5; // the second of the alarm we want to match - uint32_t screensaver_interval : 3; // 0 to disable screensaver, or a screensaver activation interval. + uint32_t le_inactivity_interval : 3;// 0 to disable low energy mode, or an inactivity interval for going into low energy mode. uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) @@ -25,7 +25,7 @@ typedef enum { EVENT_NONE = 0, // There is no event to report. EVENT_ACTIVATE, // Your watch face is entering the foreground. EVENT_TICK, // Most common event type. Your watch face is being called from the tick callback. - EVENT_SCREENSAVER, // Your watch face is being asked to display its output for screensaver mode. + EVENT_LOW_POWER_TICK, // The watch is in low energy mode, and you are getting the once-per-minute tick callback. EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. @@ -72,8 +72,8 @@ typedef struct { uint8_t mode_down_timestamp; uint8_t alarm_down_timestamp; - // screensaver countdown - int32_t screensaver_ticks; + // low energy mode countdown + int32_t le_mode_ticks; // stuff for subsecond tracking uint8_t tick_frequency; diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index bdee7dec..6e58313a 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -28,16 +28,16 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting switch (event.event_type) { case EVENT_ACTIVATE: case EVENT_TICK: - case EVENT_SCREENSAVER: + case EVENT_LOW_POWER_TICK: date_time = watch_rtc_get_date_time(); previous_date_time = *((uint32_t *)context); *((uint32_t *)context) = date_time.reg; - if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_SCREENSAVER) { + if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_LOW_POWER_TICK) { // everything before seconds is the same, don't waste cycles setting those segments. pos = 8; sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_SCREENSAVER) { + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_LOW_POWER_TICK) { // everything before minutes is the same. pos = 6; sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); @@ -54,7 +54,7 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting if (date_time.unit.hour == 0) date_time.unit.hour = 12; } pos = 0; - if (event.event_type == EVENT_SCREENSAVER) { + if (event.event_type == EVENT_LOW_POWER_TICK) { sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); } else { sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); diff --git a/movement/watch_faces/settings/preferences_face.c b/movement/watch_faces/settings/preferences_face.c index 18dff6cd..c3b7663c 100644 --- a/movement/watch_faces/settings/preferences_face.c +++ b/movement/watch_faces/settings/preferences_face.c @@ -37,7 +37,7 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings settings->bit.button_should_sound = !(settings->bit.button_should_sound); break; case 2: - settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1; + settings->bit.le_inactivity_interval = settings->bit.le_inactivity_interval + 1; break; case 3: settings->bit.led_green_color = settings->bit.led_green_color + 1; @@ -65,7 +65,7 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings else watch_display_string("n", 9); break; case 2: - switch (settings->bit.screensaver_interval) { + switch (settings->bit.le_inactivity_interval) { case 0: watch_display_string(" never", 4); break; -- cgit v1.2.3 From 69397e9b0f011cd9108547f05ab21073c4a9ddb6 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 13:47:42 -0400 Subject: implement led duration setting --- movement/movement.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/movement/movement.c b/movement/movement.c index 9b7e90a0..03ddb244 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -30,7 +30,7 @@ void movement_request_tick_frequency(uint8_t freq) { } void movement_illuminate_led() { - movement_state.light_ticks = 3; + movement_state.light_ticks = movement_state.settings.bit.led_duration; } void movement_move_to_face(uint8_t watch_face_index) { @@ -48,6 +48,7 @@ void app_init() { movement_state.settings.bit.led_green_color = 0xF; movement_state.settings.bit.button_should_sound = true; movement_state.settings.bit.le_inactivity_interval = 1; + movement_state.settings.bit.led_duration = 3; _movement_reset_inactivity_countdown(); } -- cgit v1.2.3 From 458ebf6987d6de143c53493782d438e55253d6e9 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 13:48:16 -0400 Subject: remove unimplemented settings for now --- movement/movement.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/movement/movement.h b/movement/movement.h index 934254bc..0ae0cc13 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -6,13 +6,9 @@ // TODO: none of this is implemented typedef union { struct { - uint32_t reserved : 3; + uint32_t reserved : 16; uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. - uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour. - uint32_t alarm_should_sound : 1; // if true, the alarm interrupt can match a time and play a song. - uint32_t alarm_minute : 6; // the minute of the alarm we want to match - uint32_t alarm_hour : 5; // the second of the alarm we want to match uint32_t le_inactivity_interval : 3;// 0 to disable low energy mode, or an inactivity interval for going into low energy mode. uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) -- cgit v1.2.3 From 0cfb37c6716326dea78a8dca512d286e6484e509 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 16:03:27 -0400 Subject: early work on background tasks, documentation --- movement/movement.c | 4 +- movement/movement.h | 93 +++++++++++++++++++++- movement/watch_faces/clock/simple_clock_face.c | 8 +- movement/watch_faces/clock/simple_clock_face.h | 1 + .../watch_faces/complications/pulseometer_face.h | 1 + movement/watch_faces/settings/preferences_face.h | 1 + movement/watch_faces/settings/set_time_face.h | 1 + 7 files changed, 102 insertions(+), 7 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 03ddb244..d43285e1 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -144,7 +144,7 @@ bool app_loop() { // this is a little mini-runloop. // as long as le_mode_ticks is -1 (i.e. we are in low energy mode), we wake up here, update the screen, and go right back to sleep. while (movement_state.le_mode_ticks == -1) { - event.event_type = EVENT_LOW_POWER_TICK; + event.event_type = EVENT_LOW_ENERGY_UPDATE; watch_faces[movement_state.current_watch_face].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); watch_enter_shallow_sleep(true); } @@ -201,7 +201,7 @@ void cb_alarm_btn_extwake() { } void cb_alarm_fired() { - event.event_type = EVENT_LOW_POWER_TICK; + event.event_type = EVENT_LOW_ENERGY_UPDATE; } void cb_tick() { diff --git a/movement/movement.h b/movement/movement.h index 0ae0cc13..3f3f0365 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -21,7 +21,8 @@ typedef enum { EVENT_NONE = 0, // There is no event to report. EVENT_ACTIVATE, // Your watch face is entering the foreground. EVENT_TICK, // Most common event type. Your watch face is being called from the tick callback. - EVENT_LOW_POWER_TICK, // The watch is in low energy mode, and you are getting the once-per-minute tick callback. + EVENT_LOW_ENERGY_UPDATE, // If the watch is in low energy mode and you are in the foreground, you will get a chance to update the display once per minute. + EVENT_BACKGROUND_TASK, // Your watch face is being invoked to perform a background task. Don't update the display here; you may not be in the foreground. EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. @@ -38,16 +39,106 @@ typedef struct { uint8_t subsecond; } movement_event_t; +/** @brief Perform setup for your watch face. + * @details It's tempting to say this is 'one-time' setup, but technically this function is called more than + * once. When the watch first boots, this function is called with a NULL context_ptr, indicating + * that it is the first run. At this time you should set context_ptr to something non-NULL if you + * need to keep track of any state in your watch face. If your watch face requires any other setup, + * like configuring a pin mode or a peripheral, you may want to do that here too. + * This function will be called again after waking from sleep mode, since sleep mode disables all + * of the device's pins and peripherals. + * @param settings A pointer to the global Movement settings. You can use this to inform how you present your + * display to the user (i.e. taking into account whether they have silenced the buttons, or if + * they prefer 12 or 24-hour mode). You can also change these settings if you like. + * @param context_ptr A pointer to a pointer; at first invocation, this value will be NULL, and you can set it + * to any value you like. Subsequent invocations will pass in whatever value you previously + * set. You may want to check if this is NULL and if so, allocate some space to store any + * data required for your watch face. + * + */ typedef void (*watch_face_setup)(movement_settings_t *settings, void ** context_ptr); + +/** @brief Prepare to go on-screen. + * @details This function is called just before your watch enters the foreground. If your watch face has any + * segments or text that is always displayed, you may want to set that here. In addition, if your + * watch face depends on data from a peripheral (like an I2C sensor), you will likely want to enable + * that peripheral here. In addition, if your watch face requires an update frequncy other than 1 Hz, + * you may want to request that here using the movement_request_tick_frequency function. + * @param settings A pointer to the global Movement settings. @see watch_face_setup. + * @param context A pointer to your watch face's context. @see watch_face_setup. + * + */ typedef void (*watch_face_activate)(movement_settings_t *settings, void *context); + +/** @brief Handle events and update the display. + * @details This function is called in response to an event. You should set up a switch statement that handles, + * at the very least, the EVENT_TICK and EVENT_MODE_BUTTON_UP event types. The tick event happens once + * per second (or more frequently if you asked for a faster tick with movement_request_tick_frequency). + * The mode button up event occurs when the user presses the MODE button. **Your loop function SHOULD + * call the movement_move_to_next_face function in response to this event.** If you have a good reason + * to override this behavior (e.g. your user interface requires all three buttons), your watch face MUST + * call the movement_move_to_next_face function in response to the EVENT_MODE_LONG_PRESS event. If you + * fail to do this, the user will become stuck on your watch face. + * @param event A struct containing information about the event, including its type. @see movement_event_type_t + * for a list of all possible event types. + * @param settings A pointer to the global Movement settings. @see watch_face_setup. + * @param context A pointer to your application's context. @see watch_face_setup. + * @return true if Movement can enter STANDBY mode; false to keep it awake. You should almost always return true. + * @note There are two event types that require some extra thought: + The EVENT_LOW_ENERGY_UPDATE event type is a special case. If you are in the foreground when the watch + goes into low energy mode, you will receive this tick once a minute (at the top of the minute) so that + you can update the screen. Great! But! When you receive this event, all pins and peripherals other than + the RTC will have been disabled to save energy. If your display is clock or calendar oriented, this is + fine. But if your display requires polling an I2C sensor or reading a value with the ADC, you won't be + able to do this. You should either display the name of the watch face in response to the low power tick, + or ensure that you resign before low power mode triggers, (e.g. by calling movement_move_to_face(0)). + **Your watch face MUST NOT wake up peripherals in response to a low power tick.** The purpose of this + mode is to consume as little energy as possible during the (potentially long) intervals when it's + unlikely the user is wearing or looking at the watch. + EVENT_BACKGROUND_TASK is also a special case. @see watch_face_wants_background_task for details. + */ typedef bool (*watch_face_loop)(movement_event_t event, movement_settings_t *settings, void *context); + +/** @brief Prepare to go off-screen. + * @details This function is called before your watch face enters the background. If you requested a tick + * frequency other than the standard 1 Hz, **you must call movement_request_tick_frequency(1) here** + * to reset to 1 Hz. You should also disable any peripherals you enabled when you entered the foreground. + * @param settings A pointer to the global Movement settings. @see watch_face_setup. + * @param context A pointer to your application's context. @see watch_face_setup. + */ typedef void (*watch_face_resign)(movement_settings_t *settings, void *context); +/** @brief OPTIONAL. Request an opportunity to run a background task. + * @warning NOT YET IMPLEMENTED. + * @details Most apps will not need this function, but if you provide it, Movement will call it once per minute in + * both active and low power modes, regardless of whether your app is in the foreground. You can check the + * current time to determine whether you require a background task. If you return true here, Movement will + * immediately call your loop function with an EVENT_BACKGROUND_TASK event. Note that it will not call your + * activate or deactivate functions, since you are not going on screen. + * + * Examples of background tasks: + * - Wake and play a sound when an alarm or timer has been triggered. + * - Check the state of an RTC interrupt pin or the timestamp of an RTC interrupt event. + * - Log a data point from a sensor, and then return to sleep mode. + * + * Guidelines for background tasks: + * - Assume all peripherals and pins other than the RTC will be disabled when you get an EVENT_BACKGROUND_TASK. + * - Even if your background task involves only the RTC peripheral, try to request background tasks sparingly. + * - If your background task involves an external pin or peripheral, request background tasks no more than once per hour. + * - If you need to enable a pin or a peripheral to perform your task, return it to its original state afterwards. + * + * @param settings A pointer to the global Movement settings. @see watch_face_setup. + * @param context A pointer to your application's context. @see watch_face_setup. + * @return true to request a background task; false otherwise. + */ +typedef bool (*watch_face_wants_background_task)(movement_settings_t *settings, void *context); + typedef struct { watch_face_setup setup; watch_face_activate activate; watch_face_loop loop; watch_face_resign resign; + watch_face_wants_background_task wants_background_task; } watch_face_t; typedef struct { diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index 6e58313a..351c7ebc 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -28,16 +28,16 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting switch (event.event_type) { case EVENT_ACTIVATE: case EVENT_TICK: - case EVENT_LOW_POWER_TICK: + case EVENT_LOW_ENERGY_UPDATE: date_time = watch_rtc_get_date_time(); previous_date_time = *((uint32_t *)context); *((uint32_t *)context) = date_time.reg; - if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_LOW_POWER_TICK) { + if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_LOW_ENERGY_UPDATE) { // everything before seconds is the same, don't waste cycles setting those segments. pos = 8; sprintf(buf, "%02d", date_time.unit.second); - } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_LOW_POWER_TICK) { + } else if (date_time.reg >> 12 == previous_date_time >> 12 && event.event_type != EVENT_LOW_ENERGY_UPDATE) { // everything before minutes is the same. pos = 6; sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second); @@ -54,7 +54,7 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting if (date_time.unit.hour == 0) date_time.unit.hour = 12; } pos = 0; - if (event.event_type == EVENT_LOW_POWER_TICK) { + if (event.event_type == EVENT_LOW_ENERGY_UPDATE) { sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); } else { sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); diff --git a/movement/watch_faces/clock/simple_clock_face.h b/movement/watch_faces/clock/simple_clock_face.h index 3cdc09e8..7daaba3e 100644 --- a/movement/watch_faces/clock/simple_clock_face.h +++ b/movement/watch_faces/clock/simple_clock_face.h @@ -15,6 +15,7 @@ uint8_t simple_clock_face_get_weekday(uint16_t day, uint16_t month, uint16_t yea simple_clock_face_activate, \ simple_clock_face_loop, \ simple_clock_face_resign, \ + NULL, \ } #endif // FAKE_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/complications/pulseometer_face.h b/movement/watch_faces/complications/pulseometer_face.h index f8e69d27..5a9c66b0 100644 --- a/movement/watch_faces/complications/pulseometer_face.h +++ b/movement/watch_faces/complications/pulseometer_face.h @@ -19,6 +19,7 @@ void pulseometer_face_resign(movement_settings_t *settings, void *context); pulseometer_face_activate, \ pulseometer_face_loop, \ pulseometer_face_resign, \ + NULL, \ } #endif // PULSEOMETER_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/settings/preferences_face.h b/movement/watch_faces/settings/preferences_face.h index c8f1a14e..5b735db9 100644 --- a/movement/watch_faces/settings/preferences_face.h +++ b/movement/watch_faces/settings/preferences_face.h @@ -13,6 +13,7 @@ void preferences_face_resign(movement_settings_t *settings, void *context); preferences_face_activate, \ preferences_face_loop, \ preferences_face_resign, \ + NULL, \ } #endif // PREFERENCES_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/settings/set_time_face.h b/movement/watch_faces/settings/set_time_face.h index b330d852..06dbe2ce 100644 --- a/movement/watch_faces/settings/set_time_face.h +++ b/movement/watch_faces/settings/set_time_face.h @@ -13,6 +13,7 @@ void set_time_face_resign(movement_settings_t *settings, void *context); set_time_face_activate, \ set_time_face_loop, \ set_time_face_resign, \ + NULL, \ } #endif // SET_TIME_FACE_H_ -- cgit v1.2.3 From 05fe055f99b9b950086b1e38a9c795d7e076c5b2 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 16:25:30 -0400 Subject: automatically determine number of watch faces --- movement/movement_config.h | 5 ++--- movement/watch_faces/clock/simple_clock_face.h | 16 ++++++++-------- movement/watch_faces/complications/pulseometer_face.h | 14 +++++++------- movement/watch_faces/settings/preferences_face.h | 14 +++++++------- movement/watch_faces/settings/set_time_face.h | 14 +++++++------- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/movement/movement_config.h b/movement/movement_config.h index 172736f1..e95e46c0 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -6,13 +6,12 @@ #include "set_time_face.h" #include "pulseometer_face.h" -#define MOVEMENT_NUM_FACES 3 - -watch_face_t watch_faces[MOVEMENT_NUM_FACES] = { +const watch_face_t watch_faces[] = { simple_clock_face, preferences_face, set_time_face, }; +#define MOVEMENT_NUM_FACES (sizeof(watch_faces) / sizeof(watch_face_t)) #endif // MOVEMENT_CONFIG_H_ diff --git a/movement/watch_faces/clock/simple_clock_face.h b/movement/watch_faces/clock/simple_clock_face.h index 7daaba3e..3db894d2 100644 --- a/movement/watch_faces/clock/simple_clock_face.h +++ b/movement/watch_faces/clock/simple_clock_face.h @@ -10,12 +10,12 @@ void simple_clock_face_resign(movement_settings_t *settings, void *context); uint8_t simple_clock_face_get_weekday(uint16_t day, uint16_t month, uint16_t year); -#define simple_clock_face { \ - simple_clock_face_setup, \ - simple_clock_face_activate, \ - simple_clock_face_loop, \ - simple_clock_face_resign, \ - NULL, \ -} +static const watch_face_t simple_clock_face = { + simple_clock_face_setup, + simple_clock_face_activate, + simple_clock_face_loop, + simple_clock_face_resign, + NULL +}; -#endif // FAKE_FACE_H_ \ No newline at end of file +#endif // SIMPLE_CLOCK_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/complications/pulseometer_face.h b/movement/watch_faces/complications/pulseometer_face.h index 5a9c66b0..52bccf24 100644 --- a/movement/watch_faces/complications/pulseometer_face.h +++ b/movement/watch_faces/complications/pulseometer_face.h @@ -14,12 +14,12 @@ void pulseometer_face_activate(movement_settings_t *settings, void *context); bool pulseometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context); void pulseometer_face_resign(movement_settings_t *settings, void *context); -#define pulseometer_face { \ - pulseometer_face_setup, \ - pulseometer_face_activate, \ - pulseometer_face_loop, \ - pulseometer_face_resign, \ - NULL, \ -} +static const watch_face_t pulseometer_face = { + pulseometer_face_setup, + pulseometer_face_activate, + pulseometer_face_loop, + pulseometer_face_resign, + NULL +}; #endif // PULSEOMETER_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/settings/preferences_face.h b/movement/watch_faces/settings/preferences_face.h index 5b735db9..af628ba3 100644 --- a/movement/watch_faces/settings/preferences_face.h +++ b/movement/watch_faces/settings/preferences_face.h @@ -8,12 +8,12 @@ void preferences_face_activate(movement_settings_t *settings, void *context); bool preferences_face_loop(movement_event_t event, movement_settings_t *settings, void *context); void preferences_face_resign(movement_settings_t *settings, void *context); -#define preferences_face { \ - preferences_face_setup, \ - preferences_face_activate, \ - preferences_face_loop, \ - preferences_face_resign, \ - NULL, \ -} +static const watch_face_t preferences_face = { + preferences_face_setup, + preferences_face_activate, + preferences_face_loop, + preferences_face_resign, + NULL +}; #endif // PREFERENCES_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/settings/set_time_face.h b/movement/watch_faces/settings/set_time_face.h index 06dbe2ce..21fb1e44 100644 --- a/movement/watch_faces/settings/set_time_face.h +++ b/movement/watch_faces/settings/set_time_face.h @@ -8,12 +8,12 @@ void set_time_face_activate(movement_settings_t *settings, void *context); bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, void *context); void set_time_face_resign(movement_settings_t *settings, void *context); -#define set_time_face { \ - set_time_face_setup, \ - set_time_face_activate, \ - set_time_face_loop, \ - set_time_face_resign, \ - NULL, \ -} +static const watch_face_t set_time_face = { + set_time_face_setup, + set_time_face_activate, + set_time_face_loop, + set_time_face_resign, + NULL +}; #endif // SET_TIME_FACE_H_ -- cgit v1.2.3 From c27dbc779b252c32370e2cd34a22f51d120d0f38 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 16 Oct 2021 16:51:36 -0400 Subject: fix misspelling of pulsometer --- movement/make/Makefile | 2 +- movement/movement_config.h | 2 +- .../watch_faces/complications/pulseometer_face.c | 87 ---------------------- .../watch_faces/complications/pulseometer_face.h | 25 ------- .../watch_faces/complications/pulsometer_face.c | 87 ++++++++++++++++++++++ .../watch_faces/complications/pulsometer_face.h | 25 +++++++ 6 files changed, 114 insertions(+), 114 deletions(-) delete mode 100644 movement/watch_faces/complications/pulseometer_face.c delete mode 100644 movement/watch_faces/complications/pulseometer_face.h create mode 100644 movement/watch_faces/complications/pulsometer_face.c create mode 100644 movement/watch_faces/complications/pulsometer_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index 8b29fba4..f17fc7e5 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -26,7 +26,7 @@ SRCS += \ ../watch_faces/clock/simple_clock_face.c \ ../watch_faces/settings/preferences_face.c \ ../watch_faces/settings/set_time_face.c \ - ../watch_faces/complications/pulseometer_face.c \ + ../watch_faces/complications/pulsometer_face.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/movement/movement_config.h b/movement/movement_config.h index e95e46c0..6a7aec5a 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -4,7 +4,7 @@ #include "simple_clock_face.h" #include "preferences_face.h" #include "set_time_face.h" -#include "pulseometer_face.h" +#include "pulsometer_face.h" const watch_face_t watch_faces[] = { simple_clock_face, diff --git a/movement/watch_faces/complications/pulseometer_face.c b/movement/watch_faces/complications/pulseometer_face.c deleted file mode 100644 index 7c524b8d..00000000 --- a/movement/watch_faces/complications/pulseometer_face.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include "pulseometer_face.h" -#include "watch.h" - -#define PULSOMETER_FACE_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) -#define PULSOMETER_FACE_FREQUENCY (1 << PULSOMETER_FACE_FREQUENCY_FACTOR) - -void pulseometer_face_setup(movement_settings_t *settings, void ** context_ptr) { - (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); -} - -void pulseometer_face_activate(movement_settings_t *settings, void *context) { - (void) settings; - memset(context, 0, sizeof(PulsometerState)); -} - -bool pulseometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { - printf("pulseometer_face_loop\n"); - (void) settings; - PulsometerState *pulsometer_state = (PulsometerState *)context; - char buf[14]; - switch (event.event_type) { - case EVENT_TICK: - if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { - switch (pulsometer_state->ticks % 5) { - case 0: - watch_display_string(" Hold ", 2); - break; - case 1: - watch_display_string(" Alarn", 4); - break; - case 2: - watch_display_string("+ Count ", 0); - break; - case 3: - watch_display_string(" 30Beats ", 0); - break; - case 4: - watch_clear_display(); - break; - } - pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; - } else { - if (pulsometer_state->measuring && pulsometer_state->ticks) { - pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_FACE_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); - } - if (pulsometer_state->pulse > 240) { - watch_display_string(" Hi", 0); - } else if (pulsometer_state->pulse < 40) { - watch_display_string(" Lo", 0); - } else { - sprintf(buf, " %-3dbpn", pulsometer_state->pulse); - watch_display_string(buf, 0); - } - if (pulsometer_state->measuring) pulsometer_state->ticks++; - } - return false; - case EVENT_MODE_BUTTON_UP: - movement_move_to_next_face(); - return false; - case EVENT_LIGHT_BUTTON_UP: - movement_illuminate_led(); - break; - case EVENT_ALARM_BUTTON_DOWN: - pulsometer_state->ticks = 0; - pulsometer_state->pulse = 0xFFFF; - pulsometer_state->measuring = true; - movement_request_tick_frequency(PULSOMETER_FACE_FREQUENCY); - break; - case EVENT_ALARM_BUTTON_UP: - case EVENT_ALARM_LONG_PRESS: - pulsometer_state->measuring = false; - movement_request_tick_frequency(1); - break; - default: - break; - } - - return true; -} - -void pulseometer_face_resign(movement_settings_t *settings, void *context) { - (void) settings; - (void) context; -} diff --git a/movement/watch_faces/complications/pulseometer_face.h b/movement/watch_faces/complications/pulseometer_face.h deleted file mode 100644 index 52bccf24..00000000 --- a/movement/watch_faces/complications/pulseometer_face.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef PULSEOMETER_FACE_H_ -#define PULSEOMETER_FACE_H_ - -#include "movement.h" - -typedef struct { - bool measuring; - int16_t pulse; - int16_t ticks; -} PulsometerState; - -void pulseometer_face_setup(movement_settings_t *settings, void ** context_ptr); -void pulseometer_face_activate(movement_settings_t *settings, void *context); -bool pulseometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context); -void pulseometer_face_resign(movement_settings_t *settings, void *context); - -static const watch_face_t pulseometer_face = { - pulseometer_face_setup, - pulseometer_face_activate, - pulseometer_face_loop, - pulseometer_face_resign, - NULL -}; - -#endif // PULSEOMETER_FACE_H_ \ No newline at end of file diff --git a/movement/watch_faces/complications/pulsometer_face.c b/movement/watch_faces/complications/pulsometer_face.c new file mode 100644 index 00000000..dffdcd35 --- /dev/null +++ b/movement/watch_faces/complications/pulsometer_face.c @@ -0,0 +1,87 @@ +#include +#include +#include "pulsometer_face.h" +#include "watch.h" + +#define PULSOMETER_FACE_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) +#define PULSOMETER_FACE_FREQUENCY (1 << PULSOMETER_FACE_FREQUENCY_FACTOR) + +void pulsometer_face_setup(movement_settings_t *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); +} + +void pulsometer_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + memset(context, 0, sizeof(PulsometerState)); +} + +bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + printf("pulsometer_face_loop\n"); + (void) settings; + PulsometerState *pulsometer_state = (PulsometerState *)context; + char buf[14]; + switch (event.event_type) { + case EVENT_TICK: + if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { + switch (pulsometer_state->ticks % 5) { + case 0: + watch_display_string(" Hold ", 2); + break; + case 1: + watch_display_string(" Alarn", 4); + break; + case 2: + watch_display_string("+ Count ", 0); + break; + case 3: + watch_display_string(" 30Beats ", 0); + break; + case 4: + watch_clear_display(); + break; + } + pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; + } else { + if (pulsometer_state->measuring && pulsometer_state->ticks) { + pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_FACE_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); + } + if (pulsometer_state->pulse > 240) { + watch_display_string(" Hi", 0); + } else if (pulsometer_state->pulse < 40) { + watch_display_string(" Lo", 0); + } else { + sprintf(buf, " %-3dbpn", pulsometer_state->pulse); + watch_display_string(buf, 0); + } + if (pulsometer_state->measuring) pulsometer_state->ticks++; + } + return false; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + return false; + case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_DOWN: + pulsometer_state->ticks = 0; + pulsometer_state->pulse = 0xFFFF; + pulsometer_state->measuring = true; + movement_request_tick_frequency(PULSOMETER_FACE_FREQUENCY); + break; + case EVENT_ALARM_BUTTON_UP: + case EVENT_ALARM_LONG_PRESS: + pulsometer_state->measuring = false; + movement_request_tick_frequency(1); + break; + default: + break; + } + + return true; +} + +void pulsometer_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/movement/watch_faces/complications/pulsometer_face.h b/movement/watch_faces/complications/pulsometer_face.h new file mode 100644 index 00000000..76af8257 --- /dev/null +++ b/movement/watch_faces/complications/pulsometer_face.h @@ -0,0 +1,25 @@ +#ifndef PULSOMETER_FACE_H_ +#define PULSOMETER_FACE_H_ + +#include "movement.h" + +typedef struct { + bool measuring; + int16_t pulse; + int16_t ticks; +} PulsometerState; + +void pulsometer_face_setup(movement_settings_t *settings, void ** context_ptr); +void pulsometer_face_activate(movement_settings_t *settings, void *context); +bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void pulsometer_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t pulsometer_face = { + pulsometer_face_setup, + pulsometer_face_activate, + pulsometer_face_loop, + pulsometer_face_resign, + NULL +}; + +#endif // PULSOMETER_FACE_H_ \ No newline at end of file -- cgit v1.2.3 From b4d4f62ba8ec4f5983a639ddd0e0089cebe380e4 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 11:15:45 -0400 Subject: pulsometer: reset tick in resign function --- movement/watch_faces/complications/pulsometer_face.c | 1 + 1 file changed, 1 insertion(+) diff --git a/movement/watch_faces/complications/pulsometer_face.c b/movement/watch_faces/complications/pulsometer_face.c index dffdcd35..396ac0dd 100644 --- a/movement/watch_faces/complications/pulsometer_face.c +++ b/movement/watch_faces/complications/pulsometer_face.c @@ -84,4 +84,5 @@ bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void pulsometer_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; + movement_request_tick_frequency(1); } -- cgit v1.2.3 From 8dbbe92a9bad950219c4bc1a46871f44dda5fef3 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 11:27:36 -0400 Subject: pulsometer: make type more c-like --- movement/watch_faces/complications/pulsometer_face.c | 6 +++--- movement/watch_faces/complications/pulsometer_face.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/movement/watch_faces/complications/pulsometer_face.c b/movement/watch_faces/complications/pulsometer_face.c index 396ac0dd..db5c5d0e 100644 --- a/movement/watch_faces/complications/pulsometer_face.c +++ b/movement/watch_faces/complications/pulsometer_face.c @@ -8,18 +8,18 @@ void pulsometer_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; - if (*context_ptr == NULL) *context_ptr = malloc(sizeof(PulsometerState)); + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(pulsometer_state_t)); } void pulsometer_face_activate(movement_settings_t *settings, void *context) { (void) settings; - memset(context, 0, sizeof(PulsometerState)); + memset(context, 0, sizeof(pulsometer_state_t)); } bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { printf("pulsometer_face_loop\n"); (void) settings; - PulsometerState *pulsometer_state = (PulsometerState *)context; + pulsometer_state_t *pulsometer_state = (pulsometer_state_t *)context; char buf[14]; switch (event.event_type) { case EVENT_TICK: diff --git a/movement/watch_faces/complications/pulsometer_face.h b/movement/watch_faces/complications/pulsometer_face.h index 76af8257..cdb5b977 100644 --- a/movement/watch_faces/complications/pulsometer_face.h +++ b/movement/watch_faces/complications/pulsometer_face.h @@ -7,7 +7,7 @@ typedef struct { bool measuring; int16_t pulse; int16_t ticks; -} PulsometerState; +} pulsometer_state_t; void pulsometer_face_setup(movement_settings_t *settings, void ** context_ptr); void pulsometer_face_activate(movement_settings_t *settings, void *context); -- cgit v1.2.3 From 93624f0b692648eac415a3df5689de6dee06c2db Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 12:15:57 -0400 Subject: add timeout event to give faces a chance to resign --- movement/movement.c | 15 ++++++++++++--- movement/movement.h | 7 ++++++- movement/watch_faces/clock/simple_clock_face.c | 2 +- movement/watch_faces/complications/pulsometer_face.c | 4 +++- movement/watch_faces/settings/preferences_face.c | 4 +++- movement/watch_faces/settings/set_time_face.c | 3 +++ 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index d43285e1..6576bd75 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -7,7 +7,8 @@ movement_state_t movement_state; void * watch_face_contexts[MOVEMENT_NUM_FACES]; -const int32_t movement_inactivity_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; +const int32_t movement_le_inactivity_deadlines[8] = {INT_MAX, 3600, 7200, 21600, 43200, 86400, 172800, 604800}; +const int32_t movement_timeout_inactivity_deadlines[4] = {60, 120, 300, 1800}; movement_event_t event; void cb_mode_btn_interrupt(); @@ -18,8 +19,10 @@ void cb_alarm_fired(); void cb_tick(); static inline void _movement_reset_inactivity_countdown() { - // for testing, make the timeout happen 60x faster. - movement_state.le_mode_ticks = movement_inactivity_deadlines[movement_state.settings.bit.le_inactivity_interval] / 60; + // for testing, make the low energy timeout happen 60x faster. + movement_state.le_mode_ticks = movement_le_inactivity_deadlines[movement_state.settings.bit.le_inactivity_interval] / 60; + // for testing, make the inactivity timeout happen 4x faster. + movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_inactivity_interval] / 4; } void movement_request_tick_frequency(uint8_t freq) { @@ -130,6 +133,11 @@ bool app_loop() { } } + // if we have timed out of our timeout countdown, give the app a hint that they can resign. + if (movement_state.timeout_ticks == 0) { + event.event_type = EVENT_TIMEOUT; + } + // if we have timed out of our low energy mode countdown, enter low energy mode. if (movement_state.le_mode_ticks == 0) { movement_state.le_mode_ticks = -1; @@ -210,6 +218,7 @@ void cb_tick() { if (date_time.unit.second != movement_state.last_second) { if (movement_state.light_ticks) movement_state.light_ticks--; if (movement_state.settings.bit.le_inactivity_interval && movement_state.le_mode_ticks > 0) movement_state.le_mode_ticks--; + if (movement_state.timeout_ticks > 0) movement_state.timeout_ticks--; movement_state.last_second = date_time.unit.second; movement_state.subsecond = 0; diff --git a/movement/movement.h b/movement/movement.h index 3f3f0365..d116a6e0 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -6,9 +6,10 @@ // TODO: none of this is implemented typedef union { struct { - uint32_t reserved : 16; + uint32_t reserved : 14; uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. + uint32_t to_inactivity_interval : 2;// an inactivity interval for asking the active face to resign. uint32_t le_inactivity_interval : 3;// 0 to disable low energy mode, or an inactivity interval for going into low energy mode. uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) @@ -23,6 +24,7 @@ typedef enum { EVENT_TICK, // Most common event type. Your watch face is being called from the tick callback. EVENT_LOW_ENERGY_UPDATE, // If the watch is in low energy mode and you are in the foreground, you will get a chance to update the display once per minute. EVENT_BACKGROUND_TASK, // Your watch face is being invoked to perform a background task. Don't update the display here; you may not be in the foreground. + EVENT_TIMEOUT, // Your watch face has been inactive for a while. You may want to resign, depending on your watch face's intended use case. EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released. EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released. EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released. @@ -162,6 +164,9 @@ typedef struct { // low energy mode countdown int32_t le_mode_ticks; + // app resignation countdown (TODO: consolidate with LE countdown?) + int16_t timeout_ticks; + // stuff for subsecond tracking uint8_t tick_frequency; uint8_t last_second; diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index 351c7ebc..95db3901 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -18,7 +18,6 @@ void simple_clock_face_activate(movement_settings_t *settings, void *context) { } bool simple_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { - printf("simple_clock_face_loop\n"); const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; char buf[11]; uint8_t pos; @@ -28,6 +27,7 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting switch (event.event_type) { case EVENT_ACTIVATE: case EVENT_TICK: + case EVENT_TIMEOUT: case EVENT_LOW_ENERGY_UPDATE: date_time = watch_rtc_get_date_time(); previous_date_time = *((uint32_t *)context); diff --git a/movement/watch_faces/complications/pulsometer_face.c b/movement/watch_faces/complications/pulsometer_face.c index db5c5d0e..e54b4551 100644 --- a/movement/watch_faces/complications/pulsometer_face.c +++ b/movement/watch_faces/complications/pulsometer_face.c @@ -17,7 +17,6 @@ void pulsometer_face_activate(movement_settings_t *settings, void *context) { } bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { - printf("pulsometer_face_loop\n"); (void) settings; pulsometer_state_t *pulsometer_state = (pulsometer_state_t *)context; char buf[14]; @@ -74,6 +73,9 @@ bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, pulsometer_state->measuring = false; movement_request_tick_frequency(1); break; + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; default: break; } diff --git a/movement/watch_faces/settings/preferences_face.c b/movement/watch_faces/settings/preferences_face.c index c3b7663c..98a2372d 100644 --- a/movement/watch_faces/settings/preferences_face.c +++ b/movement/watch_faces/settings/preferences_face.c @@ -17,7 +17,6 @@ void preferences_face_activate(movement_settings_t *settings, void *context) { } bool preferences_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { - printf("preferences_face_loop\n"); uint8_t current_page = *((uint8_t *)context); switch (event.event_type) { case EVENT_MODE_BUTTON_UP: @@ -47,6 +46,9 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings break; } break; + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; default: break; } diff --git a/movement/watch_faces/settings/set_time_face.c b/movement/watch_faces/settings/set_time_face.c index 7bb63d0b..6b82c68b 100644 --- a/movement/watch_faces/settings/set_time_face.c +++ b/movement/watch_faces/settings/set_time_face.c @@ -58,6 +58,9 @@ bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, v } watch_rtc_set_date_time(date_time); break; + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; default: break; } -- cgit v1.2.3 From 1db9e18b927a45b6f93279ee6b9929679f0a9cc5 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 12:31:44 -0400 Subject: pulsometer: rearrange switch for clarity --- .../watch_faces/complications/pulsometer_face.c | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/movement/watch_faces/complications/pulsometer_face.c b/movement/watch_faces/complications/pulsometer_face.c index e54b4551..abe002fb 100644 --- a/movement/watch_faces/complications/pulsometer_face.c +++ b/movement/watch_faces/complications/pulsometer_face.c @@ -21,6 +21,23 @@ bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, pulsometer_state_t *pulsometer_state = (pulsometer_state_t *)context; char buf[14]; switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; + case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_DOWN: + pulsometer_state->measuring = true; + pulsometer_state->pulse = 0xFFFF; + pulsometer_state->ticks = 0; + movement_request_tick_frequency(PULSOMETER_FACE_FREQUENCY); + break; + case EVENT_ALARM_BUTTON_UP: + case EVENT_ALARM_LONG_PRESS: + pulsometer_state->measuring = false; + movement_request_tick_frequency(1); + break; case EVENT_TICK: if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { switch (pulsometer_state->ticks % 5) { @@ -55,23 +72,6 @@ bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, } if (pulsometer_state->measuring) pulsometer_state->ticks++; } - return false; - case EVENT_MODE_BUTTON_UP: - movement_move_to_next_face(); - return false; - case EVENT_LIGHT_BUTTON_UP: - movement_illuminate_led(); - break; - case EVENT_ALARM_BUTTON_DOWN: - pulsometer_state->ticks = 0; - pulsometer_state->pulse = 0xFFFF; - pulsometer_state->measuring = true; - movement_request_tick_frequency(PULSOMETER_FACE_FREQUENCY); - break; - case EVENT_ALARM_BUTTON_UP: - case EVENT_ALARM_LONG_PRESS: - pulsometer_state->measuring = false; - movement_request_tick_frequency(1); break; case EVENT_TIMEOUT: movement_move_to_face(0); -- cgit v1.2.3 From 86d316008c7e6667c83760a8eaefadf91b1456bb Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 12:33:07 -0400 Subject: movement: remove faster sleep / timeout intervals --- movement/movement.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 6576bd75..8d28cc55 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -19,10 +19,8 @@ void cb_alarm_fired(); void cb_tick(); static inline void _movement_reset_inactivity_countdown() { - // for testing, make the low energy timeout happen 60x faster. - movement_state.le_mode_ticks = movement_le_inactivity_deadlines[movement_state.settings.bit.le_inactivity_interval] / 60; - // for testing, make the inactivity timeout happen 4x faster. - movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_inactivity_interval] / 4; + movement_state.le_mode_ticks = movement_le_inactivity_deadlines[movement_state.settings.bit.le_inactivity_interval]; + movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_inactivity_interval]; } void movement_request_tick_frequency(uint8_t freq) { -- cgit v1.2.3 From 77951ccda1d11caa9a53214cefcceb9a9c6e7a76 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 15:11:01 -0400 Subject: add readme for movement app --- movement/README.md | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 movement/README.md diff --git a/movement/README.md b/movement/README.md new file mode 100644 index 00000000..8b3d478a --- /dev/null +++ b/movement/README.md @@ -0,0 +1,297 @@ +Movement: the community watch face app +====================================== + +The Sensor Watch Library allows you to write your own bare-metal applications for the Sensor Watch. This is great if you want full control over the code running on the device, but it also means that you may have to implement your own UI for many common tasks like setting the time or illuminating the screen. + +**Movement** is an application that manages the display of different screens of content on the watch. These screens are called **watch faces**. Watch faces can be passive displays of information like a clock or a calendar, or they can be fully interactive user interfaces like the Preferences face, which allows the user to customize Movement's behavior. Movement handles the instantiation of your watch face and manages transitions between screens. It also provides a low-power sleep mode, triggered after a period of inactivity, to preserve the watch battery. + +Several faces are provided that offer baseline functionality like a clock, a settings screen and an interface for setting the time. You can change and reorder the watch faces that Movement displays by editing `movement_config.h`, and you can write your own watch face using the guidance in this document. + +Watch Face API +-------------- + +You can implement a watch face using just four functions: + +* `watch_face_setup` +* `watch_face_activate` +* `watch_face_loop` +* `watch_face_resign` + +A fifth optional function, `watch_face_wants_background_task`, has not yet had its implementation ironed out, but it will be added to the guide at a later date. + +To create a new watch face, you should create a new C header and source file in the watch-faces folder (i.e. for a watch face that displays moon phases: `moon_phase_face.h`, `moon_phase_face.c`), and implement these functions with your own unique prefix (i.e. `moon_phase_face_setup`). Then declare your watch face in your header file as follows: + +```c +static const watch_face_t moon_phase_face = { + moon_phase_face_setup, + moon_phase_face_activate, + moon_phase_face_loop, + moon_phase_face_resign, + NULL // or moon_phase_face_wants_background_task, if you implemented this function +}; +``` + +This section will go over how each function works. The section headings use the watch_face prefix, but know that you should implement each function with your own prefix as described above. + +### watch_face_setup + +If you have worked with Arduino, this function is similar to setup() in that it is called at first boot. In our case, it is also called when waking from sleep mode. You will be passed three parameters: + +* `settings` - a pointer to the global Movement settings. You can use this to inform how you present your display to the user (i.e. taking into account whether they have silenced the buttons, or if they prefer 12 or 24-hour mode). You can also change these settings if you like. +* `position` - The 0-indexed position of your watch face in the list of faces. +* `context_ptr` - A pointer to a pointer. On first run, the pointee will be NULL. If you need to keep track of any state within your watch face, you should check if it is NULL, and if so, set its value to a pointer to some value or struct that will keep track of that state. For example, the Preferences face needs to keep track of which page the user is viewing (just an integer), whereas the Pulsometer face needs to track several different properties in a struct. + +Beyond setting up the context pointer, you may want to configure any peripherals that your watch face requires; for example, a temperature watch face that reads a thermistor output may want to configure the ADC here. Still, to save power, you should avoid leaving the peripheral enabled, and wait to set pin function in the activate function. + +It was mentioned above but it's worth mentioning again: this function will be called again after waking from sleep mode, since sleep mode disables all of the device's pins and peripherals. This would give the temperature watch face a chance to re-configure the ADC. + +### watch_face_activate + +This function is called just before your watch enters the foreground. If your watch face has any segments or text that is always displayed, you may want to set that here. In addition, if your watch face depends on data from a peripheral (like that temperature watch face), you will likely want to enable that peripheral and set any required pin modes here. This function is also passed a pointer to the settings and your application context. + +### watch_face_loop + +This is a lot like your loop() function in Arduinoland in that it is called repeatedly whenever your watch face is on screen. There is one crucial difference though: it is called less often. By default, this function is called once per second, and in response to events like button presses. You can request a more frequent tick interval by calling `movement_request_tick_frequency` with any power of 2 from 1 to 128. + +In addition to the settings and context, this function receives another parameter: an `event`. This is a struct containing information about the event that triggered the update. You mostly need to check the `event_type` to determine what kind of event triggered the loop. A detailed list of all events is provided at the bottom of this document. + +There is also a `subsecond` property on the event that contains the fractional second of the event. If you are using 1 Hz updates, subsecond will always be 0. + +You should set up a switch statement that handles, at the very least, the `EVENT_TICK` and `EVENT_MODE_BUTTON_UP` event types. The mode button up event occurs when the user presses the MODE button. **Your loop function SHOULD call the movement_move_to_next_face function in response to this event.** If you have a good reason to override this behavior (e.g. your user interface requires all three buttons), your watch face MUST call the movement_move_to_next_face function in response to the EVENT_MODE_LONG_PRESS event. If you fail to do this, the user will become stuck on your watch face. + +### watch_face_resign + +This function is called just before your watch face goes off screen. You should disable any peripherals you enabled in `watch_face_activate`. If you requested an tick frequency other than 1 Hz at any point in your code, **you must reset it to 1 Hz when you resign**. It is passed the same settings and context as the other functions. + +Putting it into practice: the Pulsometer watch face +--------------------------------------------------- + +Let's take a look at a watch face to see how these pieces fit together. A *pulsometer* is [a mechanical watch complication designed to determine someone's pulse](https://www.ablogtowatch.com/longines-pulsometer-chronograph-watch/) by counting their heartbeats: you start the pulsometer, count heartbeats, and stop it when you reach the specified number. The needle will point to the pulse rate. + +Let's implement a pulsometer for the Sensor Watch. These files are in the repository as `pulsometer_face.h` and `pulsometer_face.c`, but we'll walk through them inline here. + +### pulsometer_face.h + +First, let's take a look at the header file. First we include the Movement header file, which defines the various types we need to build a watch face: + +```c +#include "movement.h" +``` + +The pulsometer needs to track certain state to do its job, so we define a struct to contain our watch face's context: + +```c +typedef struct { + bool measuring; + int16_t pulse; + int16_t ticks; +} pulsometer_state_t; +``` + +Finally, we define the four required functions, and define the watch face struct that users will use to add the face to their watch: + +```c +void pulsometer_face_setup(movement_settings_t *settings, void ** context_ptr); +void pulsometer_face_activate(movement_settings_t *settings, void *context); +bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void pulsometer_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t pulsometer_face = { + pulsometer_face_setup, + pulsometer_face_activate, + pulsometer_face_loop, + pulsometer_face_resign, + NULL +}; +``` + +### pulsometer_face.c + +Now let's look at the implementation of the Pulsometer face. First up, we have a couple of definitions that we'll reference in the code: + +```c +#define PULSOMETER_FACE_FREQUENCY_FACTOR (4ul) // refresh rate will be 2 to this power Hz (0 for 1 Hz, 2 for 4 Hz, etc.) +#define PULSOMETER_FACE_FREQUENCY (1 << PULSOMETER_FACE_FREQUENCY_FACTOR) +``` + +These define the tick frequency: when the pulsometer widget is updating the screen, it will request 16 Hz updates (2^4). + +#### Watch Face Setup + +```c +void pulsometer_face_setup(movement_settings_t *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(pulsometer_state_t)); +} +``` + +The `(void) settings;` line just silences a compiler warning about the unused parameter. The next line checks if the context pointer is NULL, and if so, allocates a `pulsometer_state_t`-sized chunk of memory to hold our state. + +#### Watch Face Activation + +```c +void pulsometer_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + memset(context, 0, sizeof(pulsometer_state_t)); +} +``` + +The pulsometer face doesn't need to keep track of context in between appearances; there's no need to keep displaying an old pulse reading hours or days after it was taken. So this line just sets the context to all zeroes before the watch face goes on screen. + +#### Watch Face Loop + +Next we have the loop function. First things first: it fetches our application context, and casts it to a `pulsometer_state_t` type so we can make use of it. It also creates a buffer for any text we plan to put on screen, and declares a switch statement for handling events: + +```c +bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + (void) settings; + pulsometer_state_t *pulsometer_state = (pulsometer_state_t *)context; + char buf[14]; + switch (event.event_type) { +``` + +Let's go through each case one by one. In response to the user releasing the MODE button, we tell Movement to move to the next watch face. + +```c +case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; +``` + +Similarly in response to the user releasing the LIGHT button, we tell Movement to illuminate the LED. Movement does not do this automatically, in case your watch face UI has another use for the LIGHT button. + +```c +case EVENT_LIGHT_BUTTON_UP: + movement_illuminate_led(); + break; +``` + +The ALARM button is the main button the user will use to interact with the pulsometer. In response to the user pressing the ALARM button, we begin a measurement. We also request a faster tick frequency, so that we can update the display at 16 Hz. + +```c +case EVENT_ALARM_BUTTON_DOWN: + pulsometer_state->measuring = true; + pulsometer_state->pulse = 0xFFFF; + pulsometer_state->ticks = 0; + movement_request_tick_frequency(PULSOMETER_FACE_FREQUENCY); + break; +``` + +When the user releases the ALARM button, we finish the measurement. We also scale the update frequency back down to 1 Hz. + +```c +case EVENT_ALARM_BUTTON_UP: +case EVENT_ALARM_LONG_PRESS: + pulsometer_state->measuring = false; + movement_request_tick_frequency(1); + break; +``` + +The tick event handler is long, but handles all display updates. The first half of this conditional handles the case where we haven't yet measured anything: it just loops through five screens with instructions, and increments the tick count. + +```c +case EVENT_TICK: + if (pulsometer_state->pulse == 0 && !pulsometer_state->measuring) { + switch (pulsometer_state->ticks % 5) { + case 0: + watch_display_string(" Hold ", 2); + break; + case 1: + watch_display_string(" Alarn", 4); + break; + case 2: + watch_display_string("+ Count ", 0); + break; + case 3: + watch_display_string(" 30Beats ", 0); + break; + case 4: + watch_clear_display(); + break; + } + pulsometer_state->ticks = (pulsometer_state->ticks + 1) % 5; +``` + +The second half of the conditional handles the case where we are measuring or have a measurement to display. It does the math, updates the screen, and increments the tick count if needed. + +```c + } else { + if (pulsometer_state->measuring && pulsometer_state->ticks) { + pulsometer_state->pulse = (int16_t)((30.0 * ((float)(60 << PULSOMETER_FACE_FREQUENCY_FACTOR) / (float)pulsometer_state->ticks)) + 0.5); + } + if (pulsometer_state->pulse > 240) { + watch_display_string(" Hi", 0); + } else if (pulsometer_state->pulse < 40) { + watch_display_string(" Lo", 0); + } else { + sprintf(buf, " %-3dbpn", pulsometer_state->pulse); + watch_display_string(buf, 0); + } + if (pulsometer_state->measuring) pulsometer_state->ticks++; + } + break; +``` + +Finally, the timeout event. After a period of inactivity (configurable from one to thirty minutes), Movement will send this event to indicate that the user has not interacted with your watch face in some time. Watch faces do not need to resign when they receive the timeout event, but depending on what kind of information your watch face displays, you may want to resign by asking Movement to return to the first watch face (usually a clock). The pulsometer widget has no need to remain on screen, so it opts to return to the clock when it receives the timeout event. + +```c +case EVENT_TIMEOUT: + movement_move_to_face(0); + break; +``` + +#### Watch Face Resignation + +The resign function doesn't have to do much here; it just resets the tick frequency to 1 Hz. + +```c +void pulsometer_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + movement_request_tick_frequency(1); +} +``` + +And that's that! + +Low Energy Mode +--------------- + +To save energy, the watch enters a low energy mode after a timeout period (confugurable from 1 hour to 7 days). In this mode, the watch will turn off all pins and peripherals except for the screen and real-time clock, and will wake up once a minute to allow the current watch face to update its display. + +Movement Event Types +-------------------- + +### EVENT_ACTIVATE + +You will receive this event when your watch face is entering the foreground. You can treat it like a tick event and just update the display. + +### EVENT_TICK + +This is the most common event type. Your watch face is being called as a result of the real-time clock ticking. By default this tick occurs once per second, but you can request more frequent updates. + +### EVENT_LIGHT_BUTTON_DOWN, EVENT_MODE_BUTTON_DOWN, EVENT_ALARM_BUTTON_DOWN + +Your watch face receives these events when one of the buttons is initially depressed, but before it is released. + +### EVENT_LIGHT_BUTTON_UP, EVENT_MODE_BUTTON_UP, EVENT_ALARM_BUTTON_UP + +Your watch face receives these events when one of these buttons is released quickly after being depressed (i.e. held for less than one second). + +### EVENT_LIGHT_LONG_PRESS, EVENT_MODE_LONG_PRESS, EVENT_ALARM_LONG_PRESS + +Your watch face receives these events when one of these buttons is released after having been held down for more than two seconds. + +### EVENT_TIMEOUT + +Your watch face receives this event after it has has been inactive for a while. You may want to resign here, depending on your watch face's intended use case. + +### EVENT_LOW_ENERGY_UPDATE + +If your watch face is in the foreground when the watch goes into low energy mode, you will receive an `EVENT_LOW_ENERGY_UPDATE` event once a minute (at the top of the minute) so that you can update the screen. Note however that when you receive this event, all pins and peripherals other than the RTC will have been disabled to save energy. If your display is clock or calendar oriented, this is fine. But if your display requires polling an I2C sensor or reading a value with the ADC, you won't be able to do this. You should either display the name of the watch face in response to the low power tick, or ensure that you resign before low power mode triggers (you can do this by calling `movement_move_to_face(0)` in your `EVENT_TIMEOUT` handler). + +**Your watch face MUST NOT wake up peripherals in response to a low energy update event.** The purpose of this mode is to consume as little energy as possible during the (potentially long) intervals when it's unlikely the user is wearing or looking at the watch. + +### EVENT_BACKGROUND_TASK + +The `EVENT_BACKGROUND_TASK` event is not yet implemented, but the plan is for this event type to allow waking peripherals even in low power mode. More information will be added in a future version of this guide. -- cgit v1.2.3 From 32710098577c982123d9391132165c0b02a57482 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 18 Oct 2021 15:36:39 -0400 Subject: fix typos --- movement/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/movement/README.md b/movement/README.md index 8b3d478a..e4eeb1c4 100644 --- a/movement/README.md +++ b/movement/README.md @@ -61,7 +61,7 @@ You should set up a switch statement that handles, at the very least, the `EVENT ### watch_face_resign -This function is called just before your watch face goes off screen. You should disable any peripherals you enabled in `watch_face_activate`. If you requested an tick frequency other than 1 Hz at any point in your code, **you must reset it to 1 Hz when you resign**. It is passed the same settings and context as the other functions. +This function is called just before your watch face goes off screen. You should disable any peripherals you enabled in `watch_face_activate`. If you requested a tick frequency other than 1 Hz at any point in your code, **you must reset it to 1 Hz when you resign**. The watch_face_resign function is passed the same settings and context as the other functions. Putting it into practice: the Pulsometer watch face --------------------------------------------------- -- cgit v1.2.3 From 52c5747d2e873d4946d211c548c03498b72c1fb5 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 19 Oct 2021 10:14:24 -0400 Subject: getting the sensor watch dev board working --- boards/OSO-FEAL-A1-00/pins.h | 120 +++++++++++++++++++++++++++ boards/OSO-MISC-21-013/pins.h | 120 --------------------------- make.mk | 4 + watch-library/config/hpl_eic_config.h | 7 +- watch-library/config/hpl_gclk_config.h | 5 ++ watch-library/config/hpl_osc32kctrl_config.h | 4 + watch-library/watch/watch_extint.c | 8 +- 7 files changed, 142 insertions(+), 126 deletions(-) create mode 100644 boards/OSO-FEAL-A1-00/pins.h delete mode 100644 boards/OSO-MISC-21-013/pins.h diff --git a/boards/OSO-FEAL-A1-00/pins.h b/boards/OSO-FEAL-A1-00/pins.h new file mode 100644 index 00000000..47d925cc --- /dev/null +++ b/boards/OSO-FEAL-A1-00/pins.h @@ -0,0 +1,120 @@ +#ifndef PINS_H_INCLUDED +#define PINS_H_INCLUDED + +// Detects if we are on USB power. +#define VBUS_DET GPIO(GPIO_PORTA, 3) + +// Buttons +#define BTN_ALARM GPIO(GPIO_PORTA, 2) +#define WATCH_BTN_ALARM_EIC_CHANNEL 2 +#define BTN_LIGHT GPIO(GPIO_PORTB, 5) +#define WATCH_BTN_LIGHT_EIC_CHANNEL 5 +#define BTN_MODE GPIO(GPIO_PORTA, 7) +#define WATCH_BTN_MODE_EIC_CHANNEL 7 + +// Buzzer +#define BUZZER GPIO(GPIO_PORTA, 27) +#define WATCH_BUZZER_TCC_PINMUX PINMUX_PA27F_TCC0_WO5 +#define WATCH_BUZZER_TCC_CHANNEL 1 + +// LEDs +#define WATCH_INVERT_LED_POLARITY +#define RED GPIO(GPIO_PORTA, 4) +#define WATCH_RED_TCC_CHANNEL 0 +#define WATCH_RED_TCC_PINMUX PINMUX_PA04E_TCC0_WO0 + +#ifdef WATCH_SWAP_LED_PINS + #define GREEN GPIO(GPIO_PORTB, 22) + #define WATCH_GREEN_TCC_CHANNEL 2 + #define WATCH_GREEN_TCC_PINMUX PINMUX_PB22F_TCC0_WO2 +#else + #define GREEN GPIO(GPIO_PORTB, 23) + #define WATCH_GREEN_TCC_CHANNEL 3 + #define WATCH_GREEN_TCC_PINMUX PINMUX_PB23F_TCC0_WO3 +#endif + + +// Segment LCD +#define SLCD0 GPIO(GPIO_PORTB, 6) +#define SLCD1 GPIO(GPIO_PORTB, 7) +#define SLCD2 GPIO(GPIO_PORTB, 8) +#define SLCD3 GPIO(GPIO_PORTB, 9) +#define SLCD4 GPIO(GPIO_PORTA, 5) +#define SLCD5 GPIO(GPIO_PORTA, 6) +#define SLCD6 GPIO(GPIO_PORTA, 8) +#define SLCD7 GPIO(GPIO_PORTA, 9) +#define SLCD8 GPIO(GPIO_PORTA, 10) +#define SLCD9 GPIO(GPIO_PORTA, 11) +#define SLCD10 GPIO(GPIO_PORTB, 11) +#define SLCD11 GPIO(GPIO_PORTB, 12) +#define SLCD12 GPIO(GPIO_PORTB, 13) +#define SLCD13 GPIO(GPIO_PORTB, 14) +#define SLCD14 GPIO(GPIO_PORTB, 15) +#define SLCD15 GPIO(GPIO_PORTA, 14) +#define SLCD16 GPIO(GPIO_PORTA, 15) +#define SLCD17 GPIO(GPIO_PORTA, 16) +#define SLCD18 GPIO(GPIO_PORTA, 17) +#define SLCD19 GPIO(GPIO_PORTA, 18) +#define SLCD20 GPIO(GPIO_PORTA, 19) +#define SLCD21 GPIO(GPIO_PORTB, 16) +#define SLCD22 GPIO(GPIO_PORTB, 17) +#define SLCD23 GPIO(GPIO_PORTA, 20) +#define SLCD24 GPIO(GPIO_PORTA, 21) +#define SLCD25 GPIO(GPIO_PORTA, 22) +#define SLCD26 GPIO(GPIO_PORTA, 23) +// This board uses a slightly different pin mapping from the standard watch, and it's not enough to +// just declare the pins. We also have to set the LCD Pin Enable register with the SLCD pins we're +// using. These numbers are not port/pin numbers, but the "SLCD/LP[x]" numbers in the pinmux table. +// If not defined in pins.h, the LCD drover will fall back to the pin mapping in hpl_slcd_config.h. +// LPENL is for pins SLCD/LP[0..31]. +#define CONF_SLCD_LPENL (\ + (uint32_t)1 << 0 | \ + (uint32_t)1 << 1 | \ + (uint32_t)1 << 2 | \ + (uint32_t)1 << 3 | \ + (uint32_t)1 << 5 | \ + (uint32_t)1 << 6 | \ + (uint32_t)1 << 11 | \ + (uint32_t)1 << 12 | \ + (uint32_t)1 << 13 | \ + (uint32_t)1 << 14 | \ + (uint32_t)1 << 21 | \ + (uint32_t)1 << 22 | \ + (uint32_t)1 << 23 | \ + (uint32_t)1 << 24 | \ + (uint32_t)1 << 25 | \ + (uint32_t)1 << 30 | \ + (uint32_t)1 << 31 | 0) +// LPENH is for pins SLCD/LP[32..51], where bit 0 represents pin 32. +#define CONF_SLCD_LPENH (\ + (uint32_t)1 << (32 - 32) | \ + (uint32_t)1 << (33 - 32) | \ + (uint32_t)1 << (34 - 32) | \ + (uint32_t)1 << (35 - 32) | \ + (uint32_t)1 << (42 - 32) | \ + (uint32_t)1 << (43 - 32) | \ + (uint32_t)1 << (48 - 32) | \ + (uint32_t)1 << (49 - 32) | \ + (uint32_t)1 << (50 - 32) | \ + (uint32_t)1 << (51 - 32) | 0) + + +// 9-pin connector +#define A0 GPIO(GPIO_PORTB, 4) +#define WATCH_A0_EIC_CHANNEL 4 +#define A1 GPIO(GPIO_PORTB, 1) +#define WATCH_A1_EIC_CHANNEL 1 +#define A2 GPIO(GPIO_PORTB, 2) +#define WATCH_A2_EIC_CHANNEL 2 +#define A3 GPIO(GPIO_PORTB, 3) +#define WATCH_A3_EIC_CHANNEL 3 +#define A4 GPIO(GPIO_PORTB, 0) +#define WATCH_A4_EIC_CHANNEL 0 +#define SDA GPIO(GPIO_PORTB, 30) +#define SCL GPIO(GPIO_PORTB, 31) + +// aliases for as A3/A4; these were mentioned as D0/D1 in early documentation. +#define D0 GPIO(GPIO_PORTB, 3) +#define D1 GPIO(GPIO_PORTB, 0) + +#endif // PINS_H_INCLUDED diff --git a/boards/OSO-MISC-21-013/pins.h b/boards/OSO-MISC-21-013/pins.h deleted file mode 100644 index a4e936a4..00000000 --- a/boards/OSO-MISC-21-013/pins.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef PINS_H_INCLUDED -#define PINS_H_INCLUDED - -// Detects if we are on USB power. -#define VBUS_DET GPIO(GPIO_PORTA, 3) - -// Buttons -#define BTN_ALARM GPIO(GPIO_PORTA, 2) -#define WATCH_BTN_ALARM_EIC_CHANNEL 2 -#define BTN_LIGHT GPIO(GPIO_PORTB, 5) -#define WATCH_BTN_LIGHT_EIC_CHANNEL 5 -#define BTN_MODE GPIO(GPIO_PORTA, 7) -#define WATCH_BTN_MODE_EIC_CHANNEL 7 - -// Buzzer -#define BUZZER GPIO(GPIO_PORTA, 27) -#define WATCH_BUZZER_TCC_PINMUX PINMUX_PA27F_TCC0_WO5 -#define WATCH_BUZZER_TCC_CHANNEL 1 - -// LEDs -#define WATCH_INVERT_LED_POLARITY -#define RED GPIO(GPIO_PORTB, 22) -#define WATCH_RED_TCC_PINMUX PINMUX_PB22F_TCC0_WO2 -#define WATCH_RED_TCC_CHANNEL 2 - -#ifdef WATCH_SWAP_LED_PINS - #define GREEN GPIO(GPIO_PORTA, 4) - #define WATCH_GREEN_TCC_CHANNEL 0 - #define WATCH_GREEN_TCC_PINMUX PINMUX_PA04E_TCC0_WO0 -#else - #define GREEN GPIO(GPIO_PORTB, 23) - #define WATCH_GREEN_TCC_CHANNEL 3 - #define WATCH_GREEN_TCC_PINMUX PINMUX_PB23F_TCC0_WO3 -#endif - - -// Segment LCD -#define SLCD0 GPIO(GPIO_PORTB, 6) -#define SLCD1 GPIO(GPIO_PORTB, 7) -#define SLCD2 GPIO(GPIO_PORTB, 8) -#define SLCD3 GPIO(GPIO_PORTB, 9) -#define SLCD4 GPIO(GPIO_PORTA, 5) -#define SLCD5 GPIO(GPIO_PORTA, 6) -#define SLCD6 GPIO(GPIO_PORTA, 8) -#define SLCD7 GPIO(GPIO_PORTA, 9) -#define SLCD8 GPIO(GPIO_PORTA, 10) -#define SLCD9 GPIO(GPIO_PORTA, 11) -#define SLCD10 GPIO(GPIO_PORTB, 11) -#define SLCD11 GPIO(GPIO_PORTB, 12) -#define SLCD12 GPIO(GPIO_PORTB, 13) -#define SLCD13 GPIO(GPIO_PORTB, 14) -#define SLCD14 GPIO(GPIO_PORTB, 15) -#define SLCD15 GPIO(GPIO_PORTA, 14) -#define SLCD16 GPIO(GPIO_PORTA, 15) -#define SLCD17 GPIO(GPIO_PORTA, 16) -#define SLCD18 GPIO(GPIO_PORTA, 17) -#define SLCD19 GPIO(GPIO_PORTA, 18) -#define SLCD20 GPIO(GPIO_PORTA, 19) -#define SLCD21 GPIO(GPIO_PORTB, 16) -#define SLCD22 GPIO(GPIO_PORTB, 17) -#define SLCD23 GPIO(GPIO_PORTA, 20) -#define SLCD24 GPIO(GPIO_PORTA, 21) -#define SLCD25 GPIO(GPIO_PORTA, 22) -#define SLCD26 GPIO(GPIO_PORTA, 23) -// This board uses a slightly different pin mapping from the standard watch, and it's not enough to -// just declare the pins. We also have to set the LCD Pin Enable register with the SLCD pins we're -// using. These numbers are not port/pin numbers, but the "SLCD/LP[x]" numbers in the pinmux table. -// If not defined in pins.h, the LCD drover will fall back to the pin mapping in hpl_slcd_config.h. -// LPENL is for pins SLCD/LP[0..31]. -#define CONF_SLCD_LPENL (\ - (uint32_t)1 << 0 | \ - (uint32_t)1 << 1 | \ - (uint32_t)1 << 2 | \ - (uint32_t)1 << 3 | \ - (uint32_t)1 << 5 | \ - (uint32_t)1 << 6 | \ - (uint32_t)1 << 11 | \ - (uint32_t)1 << 12 | \ - (uint32_t)1 << 13 | \ - (uint32_t)1 << 14 | \ - (uint32_t)1 << 21 | \ - (uint32_t)1 << 22 | \ - (uint32_t)1 << 23 | \ - (uint32_t)1 << 24 | \ - (uint32_t)1 << 25 | \ - (uint32_t)1 << 30 | \ - (uint32_t)1 << 31 | 0) -// LPENH is for pins SLCD/LP[32..51], where bit 0 represents pin 32. -#define CONF_SLCD_LPENH (\ - (uint32_t)1 << (32 - 32) | \ - (uint32_t)1 << (33 - 32) | \ - (uint32_t)1 << (34 - 32) | \ - (uint32_t)1 << (35 - 32) | \ - (uint32_t)1 << (42 - 32) | \ - (uint32_t)1 << (43 - 32) | \ - (uint32_t)1 << (48 - 32) | \ - (uint32_t)1 << (49 - 32) | \ - (uint32_t)1 << (50 - 32) | \ - (uint32_t)1 << (51 - 32) | 0) - - -// 9-pin connector -#define A0 GPIO(GPIO_PORTB, 4) -#define WATCH_A0_EIC_CHANNEL 4 -#define A1 GPIO(GPIO_PORTB, 1) -#define WATCH_A1_EIC_CHANNEL 1 -#define A2 GPIO(GPIO_PORTB, 2) -#define WATCH_A2_EIC_CHANNEL 2 -#define A3 GPIO(GPIO_PORTB, 3) -#define WATCH_A3_EIC_CHANNEL 3 -#define A4 GPIO(GPIO_PORTB, 0) -#define WATCH_A4_EIC_CHANNEL 0 -#define SDA GPIO(GPIO_PORTB, 30) -#define SCL GPIO(GPIO_PORTB, 31) - -// aliases for as A3/A4; these were mentioned as D0/D1 in early documentation. -#define D0 GPIO(GPIO_PORTB, 3) -#define D1 GPIO(GPIO_PORTB, 0) - -#endif // PINS_H_INCLUDED diff --git a/make.mk b/make.mk index 299d9d31..1c2a72f4 100644 --- a/make.mk +++ b/make.mk @@ -116,3 +116,7 @@ DEFINES += \ ifeq ($(LED), BLUE) CFLAGS += -DWATCH_SWAP_LED_PINS endif + +ifeq ($(BOARD), OSO-FEAL-A1-00) +CFLAGS += -DCRYSTALLESS +endif diff --git a/watch-library/config/hpl_eic_config.h b/watch-library/config/hpl_eic_config.h index 46aba150..53fee6cf 100644 --- a/watch-library/config/hpl_eic_config.h +++ b/watch-library/config/hpl_eic_config.h @@ -271,7 +271,7 @@ // Indicates whether the external interrupt 5 filter is enabled or not // eic_arch_filten5 #ifndef CONF_EIC_FILTEN5 -#define CONF_EIC_FILTEN5 0 +#define CONF_EIC_FILTEN5 1 #endif // External Interrupt 5 Event Output Enable @@ -723,7 +723,12 @@ // +// my god this is a hack. need to refactor this out of ASF and into our driver. - joey 10/19 +#ifdef CRYSTALLESS +#define CONFIG_EIC_EXTINT_MAP {2, PIN_PA02}, {5, PIN_PB05}, {7, PIN_PA07}, +#else #define CONFIG_EIC_EXTINT_MAP {2, PIN_PA02}, {6, PIN_PA22}, {7, PIN_PA23}, +#endif // <<< end of configuration section >>> diff --git a/watch-library/config/hpl_gclk_config.h b/watch-library/config/hpl_gclk_config.h index c56e2816..ee7aace3 100644 --- a/watch-library/config/hpl_gclk_config.h +++ b/watch-library/config/hpl_gclk_config.h @@ -248,9 +248,14 @@ // This defines the clock source for generic clock generator 3 // gclk_gen_3_oscillator #ifndef CONF_GCLK_GEN_3_SOURCE +#ifdef CRYSTALLESS +#define CONF_GCLK_GEN_3_SOURCE GCLK_GENCTRL_SRC_OSCULP32K +#else #define CONF_GCLK_GEN_3_SOURCE GCLK_GENCTRL_SRC_XOSC32K #endif +#endif + // Run in Standby // Indicates whether Run in Standby is enabled or not // gclk_arch_gen_3_runstdby diff --git a/watch-library/config/hpl_osc32kctrl_config.h b/watch-library/config/hpl_osc32kctrl_config.h index 94b46617..540f1c60 100644 --- a/watch-library/config/hpl_osc32kctrl_config.h +++ b/watch-library/config/hpl_osc32kctrl_config.h @@ -17,8 +17,12 @@ // This defines the clock source for RTC // rtc_source_oscillator #ifndef CONF_RTCCTRL_SRC +#ifdef CRYSTALLESS +#define CONF_RTCCTRL_SRC GCLK_GENCTRL_SRC_OSCULP32K +#else #define CONF_RTCCTRL_SRC GCLK_GENCTRL_SRC_XOSC32K #endif +#endif // Use 1 kHz output // rtc_1khz_selection diff --git a/watch-library/watch/watch_extint.c b/watch-library/watch/watch_extint.c index dcaa0d80..d6ad5b60 100644 --- a/watch-library/watch/watch_extint.c +++ b/watch-library/watch/watch_extint.c @@ -65,18 +65,14 @@ void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, sense_pos = 4 * (WATCH_A4_EIC_CHANNEL % 8); break; case BTN_ALARM: - // for the buttons, we need an internal pull-down. - gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); config_index = (WATCH_BTN_ALARM_EIC_CHANNEL > 7) ? 1 : 0; sense_pos = 4 * (WATCH_BTN_ALARM_EIC_CHANNEL % 8); break; case BTN_LIGHT: - gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); config_index = (WATCH_BTN_LIGHT_EIC_CHANNEL > 7) ? 1 : 0; sense_pos = 4 * (WATCH_BTN_LIGHT_EIC_CHANNEL % 8); break; case BTN_MODE: - gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); config_index = (WATCH_BTN_MODE_EIC_CHANNEL > 7) ? 1 : 0; sense_pos = 4 * (WATCH_BTN_MODE_EIC_CHANNEL % 8); break; @@ -85,7 +81,6 @@ void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, } gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_A); // EIC configuration register is enable-protected, so we have to disable it first... if (hri_eic_get_CTRLA_reg(EIC, EIC_CTRLA_ENABLE)) { @@ -98,6 +93,9 @@ void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, config &= ~(7 << sense_pos); config |= trigger << (sense_pos); hri_eic_write_CONFIG_reg(EIC, config_index, config); + // ...set the pin mode... + gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_A); + if (pin == BTN_ALARM || pin == BTN_LIGHT || pin == BTN_MODE) gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); // ...and re-enable the EIC hri_eic_set_CTRLA_ENABLE_bit(EIC); -- cgit v1.2.3 From 75be6219142a7333fb62ac91fb6abaaf648077e4 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 19 Oct 2021 13:33:11 -0400 Subject: movement settings: add timeout and LED duration --- movement/README.md | 4 +- movement/movement.c | 23 ++++----- movement/movement.h | 8 +-- movement/watch_faces/clock/simple_clock_face.c | 2 +- .../watch_faces/complications/pulsometer_face.c | 2 +- movement/watch_faces/settings/preferences_face.c | 59 ++++++++++++++++++---- 6 files changed, 67 insertions(+), 31 deletions(-) diff --git a/movement/README.md b/movement/README.md index e4eeb1c4..009234f8 100644 --- a/movement/README.md +++ b/movement/README.md @@ -158,10 +158,10 @@ case EVENT_MODE_BUTTON_UP: break; ``` -Similarly in response to the user releasing the LIGHT button, we tell Movement to illuminate the LED. Movement does not do this automatically, in case your watch face UI has another use for the LIGHT button. +Similarly in response to the user pressing the LIGHT button, we tell Movement to illuminate the LED. Movement does not do this automatically, in case your watch face UI has another use for the LIGHT button. ```c -case EVENT_LIGHT_BUTTON_UP: +case EVENT_LIGHT_BUTTON_DOWN: movement_illuminate_led(); break; ``` diff --git a/movement/movement.c b/movement/movement.c index 8d28cc55..a95501a4 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -19,8 +19,8 @@ void cb_alarm_fired(); void cb_tick(); static inline void _movement_reset_inactivity_countdown() { - movement_state.le_mode_ticks = movement_le_inactivity_deadlines[movement_state.settings.bit.le_inactivity_interval]; - movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_inactivity_interval]; + movement_state.le_mode_ticks = movement_le_inactivity_deadlines[movement_state.settings.bit.le_interval]; + movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_interval]; } void movement_request_tick_frequency(uint8_t freq) { @@ -31,7 +31,10 @@ void movement_request_tick_frequency(uint8_t freq) { } void movement_illuminate_led() { - movement_state.light_ticks = 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.led_on = true; + movement_state.light_ticks = movement_state.settings.bit.led_duration * 2; } void movement_move_to_face(uint8_t watch_face_index) { @@ -48,8 +51,8 @@ void app_init() { movement_state.settings.bit.led_green_color = 0xF; movement_state.settings.bit.button_should_sound = true; - movement_state.settings.bit.le_inactivity_interval = 1; - movement_state.settings.bit.led_duration = 3; + movement_state.settings.bit.le_interval = 1; + movement_state.settings.bit.led_duration = 1; _movement_reset_inactivity_countdown(); } @@ -112,14 +115,6 @@ bool app_loop() { movement_state.watch_face_changed = false; } - // If the LED is off and should be on, turn it on - if (movement_state.light_ticks > 0 && !movement_state.led_on) { - 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; - - } - // if the LED is on and should be off, turn it off if (movement_state.led_on && movement_state.light_ticks == 0) { // unless the user is holding down the LIGHT button, in which case, give them more time. @@ -215,7 +210,7 @@ void cb_tick() { watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.second != movement_state.last_second) { if (movement_state.light_ticks) movement_state.light_ticks--; - if (movement_state.settings.bit.le_inactivity_interval && movement_state.le_mode_ticks > 0) movement_state.le_mode_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--; movement_state.last_second = date_time.unit.second; diff --git a/movement/movement.h b/movement/movement.h index d116a6e0..41446a9b 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -6,12 +6,12 @@ // TODO: none of this is implemented typedef union { struct { - uint32_t reserved : 14; + uint32_t reserved : 15; uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. - uint32_t to_inactivity_interval : 2;// an inactivity interval for asking the active face to resign. - uint32_t le_inactivity_interval : 3;// 0 to disable low energy mode, or an inactivity interval for going into low energy mode. - uint32_t led_duration : 3; // how many seconds to shine the LED for, or 0 to disable it. + uint32_t to_interval : 2; // an inactivity interval for asking the active face to resign. + uint32_t le_interval : 3; // 0 to disable low energy mode, or an inactivity interval for going into low energy mode. + uint32_t led_duration : 2; // how many seconds to shine the LED for (x2), or 0 to disable it. uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) } bit; diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index 95db3901..70e35047 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -65,7 +65,7 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting case EVENT_MODE_BUTTON_UP: movement_move_to_next_face(); return false; - case EVENT_LIGHT_BUTTON_UP: + case EVENT_LIGHT_BUTTON_DOWN: movement_illuminate_led(); break; case EVENT_ALARM_BUTTON_UP: diff --git a/movement/watch_faces/complications/pulsometer_face.c b/movement/watch_faces/complications/pulsometer_face.c index abe002fb..d54d8ddf 100644 --- a/movement/watch_faces/complications/pulsometer_face.c +++ b/movement/watch_faces/complications/pulsometer_face.c @@ -24,7 +24,7 @@ bool pulsometer_face_loop(movement_event_t event, movement_settings_t *settings, case EVENT_MODE_BUTTON_UP: movement_move_to_next_face(); break; - case EVENT_LIGHT_BUTTON_UP: + case EVENT_LIGHT_BUTTON_DOWN: movement_illuminate_led(); break; case EVENT_ALARM_BUTTON_DOWN: diff --git a/movement/watch_faces/settings/preferences_face.c b/movement/watch_faces/settings/preferences_face.c index 98a2372d..b68f2a39 100644 --- a/movement/watch_faces/settings/preferences_face.c +++ b/movement/watch_faces/settings/preferences_face.c @@ -2,8 +2,16 @@ #include "preferences_face.h" #include "watch.h" -#define PREFERENCES_FACE_NUM_PREFEFENCES (5) -const char preferences_face_titles[PREFERENCES_FACE_NUM_PREFEFENCES][11] = {"CL ", "Bt Beep ", "SC ", "Lt grn ", "Lt red "}; +#define PREFERENCES_FACE_NUM_PREFEFENCES (7) +const char preferences_face_titles[PREFERENCES_FACE_NUM_PREFEFENCES][11] = { + "CL ", // Clock: 12 or 24 hour + "BT Beep ", // Buttons: should they beep? + "TO ", // Timeout: how long before we snap back to the clock face? + "LE ", // Low Energy mode: how long before it engages? + "LT ", // Light: duration + "LT grn ", // Light: green component + "LT red ", // Light: red component +}; void preferences_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; @@ -36,12 +44,18 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings settings->bit.button_should_sound = !(settings->bit.button_should_sound); break; case 2: - settings->bit.le_inactivity_interval = settings->bit.le_inactivity_interval + 1; + settings->bit.to_interval = settings->bit.to_interval + 1; break; case 3: - settings->bit.led_green_color = settings->bit.led_green_color + 1; + settings->bit.le_interval = settings->bit.le_interval + 1; break; case 4: + settings->bit.led_duration = settings->bit.led_duration + 1; + break; + case 5: + settings->bit.led_green_color = settings->bit.led_green_color + 1; + break; + case 6: settings->bit.led_red_color = settings->bit.led_red_color + 1; break; } @@ -56,7 +70,7 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings watch_display_string((char *)preferences_face_titles[current_page], 0); if (event.subsecond % 2) return current_page <= 2; - char buf[3]; + char buf[8]; switch (current_page) { case 0: if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); @@ -67,7 +81,23 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings else watch_display_string("n", 9); break; case 2: - switch (settings->bit.le_inactivity_interval) { + switch (settings->bit.to_interval) { + case 0: + watch_display_string("60 sec", 4); + break; + case 1: + watch_display_string("2 n&in", 4); + break; + case 2: + watch_display_string("5 n&in", 4); + break; + case 3: + watch_display_string("30n&in", 4); + break; + } + break; + case 3: + switch (settings->bit.le_interval) { case 0: watch_display_string(" never", 4); break; @@ -94,17 +124,28 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings break; } break; - case 3: + case 4: + if (settings->bit.led_duration) { + // FIXME: 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. so the setting is "1-2 s", + // "3-4 s", or "5-6 s". If we time this with the system tick we can do better. + sprintf(buf, " %1d-%1d s", settings->bit.led_duration * 2 - 1, settings->bit.led_duration * 2); + watch_display_string(buf, 4); + } else { + watch_display_string("no LEd", 4); + } + break; + case 5: sprintf(buf, "%2d", settings->bit.led_green_color); watch_display_string(buf, 8); break; - case 4: + case 6: sprintf(buf, "%2d", settings->bit.led_red_color); watch_display_string(buf, 8); break; } - if (current_page > 2) { + if (current_page >= 5) { watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); return false; -- cgit v1.2.3 From 148a47f76a457514c0571345d59c2179842cd30d Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 19 Oct 2021 15:37:08 -0400 Subject: movement: add tick animation in sleep mode --- movement/watch_faces/clock/simple_clock_face.c | 8 +++++--- watch-library/watch/watch_slcd.c | 4 ++++ watch-library/watch/watch_slcd.h | 5 +++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index 70e35047..e1e82031 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -9,9 +9,10 @@ void simple_clock_face_setup(movement_settings_t *settings, void ** context_ptr) } void simple_clock_face_activate(movement_settings_t *settings, void *context) { - if (settings->bit.clock_mode_24h) { - watch_set_indicator(WATCH_INDICATOR_24H); - } + if (watch_tick_animation_is_running()) watch_stop_tick_animation(); + + if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H); + watch_set_colon(); // this ensures that none of the timestamp fields will match, so we can re-render them all. *((uint32_t *)context) = 0xFFFFFFFF; @@ -55,6 +56,7 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting } pos = 0; if (event.event_type == EVENT_LOW_ENERGY_UPDATE) { + if (!watch_tick_animation_is_running()) watch_start_tick_animation(500); sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); } else { sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c index 08f8c0e3..6c63d966 100644 --- a/watch-library/watch/watch_slcd.c +++ b/watch-library/watch/watch_slcd.c @@ -277,6 +277,10 @@ void watch_start_tick_animation(uint32_t duration) { slcd_sync_start_animation(&SEGMENT_LCD_0, segs, 1, duration); } +bool watch_tick_animation_is_running() { + return hri_slcd_get_CTRLD_CSREN_bit(SLCD); +} + void watch_stop_tick_animation() { const uint32_t segs[] = { SLCD_SEGID(0, 2)}; slcd_sync_stop_animation(&SEGMENT_LCD_0, segs, 1); diff --git a/watch-library/watch/watch_slcd.h b/watch-library/watch/watch_slcd.h index e18ee9b4..724d3dde 100644 --- a/watch-library/watch/watch_slcd.h +++ b/watch-library/watch/watch_slcd.h @@ -138,6 +138,11 @@ void watch_stop_blink(); */ void watch_start_tick_animation(uint32_t duration); +/** @brief Checks if the tick animation is currently running. + * @return true if the animation is running; false otherwise. + */ +bool watch_tick_animation_is_running(); + /** @brief Stops the tick/tock animation and clears all animating segments. * @details This will stop the animation and clear all segments in position 8. */ -- cgit v1.2.3 From 1020dd78981e0d4b4f20399aa5e76ea7d37beec6 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Wed, 20 Oct 2021 10:36:55 -0400 Subject: movement: fix preferences glitch, add some notes --- movement/movement.c | 4 + movement/watch_faces/settings/preferences_face.c | 153 ++++++++++++----------- 2 files changed, 83 insertions(+), 74 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index a95501a4..df3cbf0b 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -209,7 +209,11 @@ 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--; diff --git a/movement/watch_faces/settings/preferences_face.c b/movement/watch_faces/settings/preferences_face.c index b68f2a39..afe71034 100644 --- a/movement/watch_faces/settings/preferences_face.c +++ b/movement/watch_faces/settings/preferences_face.c @@ -69,85 +69,90 @@ bool preferences_face_loop(movement_event_t event, movement_settings_t *settings watch_display_string((char *)preferences_face_titles[current_page], 0); - if (event.subsecond % 2) return current_page <= 2; - char buf[8]; - switch (current_page) { - case 0: - if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); - else watch_display_string("12h", 4); - break; - case 1: - if (settings->bit.button_should_sound) watch_display_string("y", 9); - else watch_display_string("n", 9); - break; - case 2: - switch (settings->bit.to_interval) { - case 0: - watch_display_string("60 sec", 4); - break; - case 1: - watch_display_string("2 n&in", 4); - break; - case 2: - watch_display_string("5 n&in", 4); - break; - case 3: - watch_display_string("30n&in", 4); - break; - } - break; - case 3: - switch (settings->bit.le_interval) { - case 0: - watch_display_string(" never", 4); - break; - case 1: - watch_display_string("1 hour", 4); - break; - case 2: - watch_display_string("2 hour", 4); - break; - case 3: - watch_display_string("6 hour", 4); - break; - case 4: - watch_display_string("12 hr", 4); - break; - case 5: - watch_display_string(" 1 day", 4); - break; - case 6: - watch_display_string(" 2 day", 4); - break; - case 7: - watch_display_string(" 7 day", 4); - break; - } - break; - case 4: - if (settings->bit.led_duration) { - // FIXME: 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. so the setting is "1-2 s", - // "3-4 s", or "5-6 s". If we time this with the system tick we can do better. - sprintf(buf, " %1d-%1d s", settings->bit.led_duration * 2 - 1, settings->bit.led_duration * 2); - watch_display_string(buf, 4); - } else { - watch_display_string("no LEd", 4); - } - break; - case 5: - sprintf(buf, "%2d", settings->bit.led_green_color); - watch_display_string(buf, 8); - break; - case 6: - sprintf(buf, "%2d", settings->bit.led_red_color); - watch_display_string(buf, 8); - break; + // blink active setting on even-numbered quarter-seconds + if (event.subsecond % 2) { + char buf[8]; + switch (current_page) { + case 0: + if (settings->bit.clock_mode_24h) watch_display_string("24h", 4); + else watch_display_string("12h", 4); + break; + case 1: + if (settings->bit.button_should_sound) watch_display_string("y", 9); + else watch_display_string("n", 9); + break; + case 2: + switch (settings->bit.to_interval) { + case 0: + watch_display_string("60 sec", 4); + break; + case 1: + watch_display_string("2 n&in", 4); + break; + case 2: + watch_display_string("5 n&in", 4); + break; + case 3: + watch_display_string("30n&in", 4); + break; + } + break; + case 3: + switch (settings->bit.le_interval) { + case 0: + watch_display_string(" never", 4); + break; + case 1: + watch_display_string("1 hour", 4); + break; + case 2: + watch_display_string("2 hour", 4); + break; + case 3: + watch_display_string("6 hour", 4); + break; + case 4: + watch_display_string("12 hr", 4); + break; + case 5: + watch_display_string(" 1 day", 4); + break; + case 6: + watch_display_string(" 2 day", 4); + break; + case 7: + watch_display_string(" 7 day", 4); + break; + } + break; + case 4: + if (settings->bit.led_duration) { + // 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. so the setting is "1-2 s", + // "3-4 s", or "5-6 s". If we time this with the system tick we can do better. + // see also cb_tick at the bottom of movement.c + sprintf(buf, " %1d-%1d s", settings->bit.led_duration * 2 - 1, settings->bit.led_duration * 2); + watch_display_string(buf, 4); + } else { + watch_display_string("no LEd", 4); + } + break; + case 5: + sprintf(buf, "%2d", settings->bit.led_green_color); + watch_display_string(buf, 8); + break; + case 6: + sprintf(buf, "%2d", settings->bit.led_red_color); + watch_display_string(buf, 8); + break; + } } + // on LED color select screns, preview the color. if (current_page >= 5) { watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0, settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0); + // return false so the watch stays awake (needed for the PWM driver to function). return false; } -- cgit v1.2.3 From 38a2dff23491c4b22a8e55ffd6d096a198857c9f Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Wed, 20 Oct 2021 13:45:22 -0400 Subject: more accurate names for deep sleep and shallow sleep modes --- apps/Sensor Watch BME280 Project/app.c | 8 +-- apps/Sensor Watch Buzzer Demo/app.c | 6 +- apps/Sensor Watch Starter Project/app.c | 36 +++++----- apps/beats-time/app.c | 8 +-- movement/movement.c | 12 ++-- watch-library/main.c | 6 +- watch-library/watch/watch_app.h | 44 ++++++------ watch-library/watch/watch_deepsleep.c | 35 ++++++---- watch-library/watch/watch_deepsleep.h | 118 ++++++++++++++++++++++---------- watch-library/watch/watch_rtc.h | 4 +- watch-library/watch/watch_slcd.h | 6 +- 11 files changed, 169 insertions(+), 114 deletions(-) diff --git a/apps/Sensor Watch BME280 Project/app.c b/apps/Sensor Watch BME280 Project/app.c index 366ccde9..85439d9b 100644 --- a/apps/Sensor Watch BME280 Project/app.c +++ b/apps/Sensor Watch BME280 Project/app.c @@ -16,8 +16,8 @@ void app_init() { memset(&application_state, 0, sizeof(application_state)); } -void app_wake_from_deep_sleep() { - // This app does not support deep sleep mode. +void app_wake_from_backup() { + // This app does not support BACKUP mode. } void app_setup() { @@ -63,13 +63,13 @@ void app_setup() { /** * Nothing to do here. */ -void app_prepare_for_sleep() { +void app_prepare_for_standby() { } /** * @todo restore the BME280's calibration values from backup memory */ -void app_wake_from_sleep() { +void app_wake_from_standby() { } /** diff --git a/apps/Sensor Watch Buzzer Demo/app.c b/apps/Sensor Watch Buzzer Demo/app.c index 74777fcc..58158dff 100644 --- a/apps/Sensor Watch Buzzer Demo/app.c +++ b/apps/Sensor Watch Buzzer Demo/app.c @@ -17,7 +17,7 @@ void app_init() { memset(&application_state, 0, sizeof(application_state)); } -void app_wake_from_deep_sleep() { +void app_wake_from_backup() { } void app_setup() { @@ -28,11 +28,11 @@ void app_setup() { watch_enable_buzzer(); } -void app_prepare_for_sleep() { +void app_prepare_for_standby() { watch_display_string(" rains ", 2); } -void app_wake_from_sleep() { +void app_wake_from_standby() { } bool app_loop() { diff --git a/apps/Sensor Watch Starter Project/app.c b/apps/Sensor Watch Starter Project/app.c index ae5aa6e8..fa887bae 100644 --- a/apps/Sensor Watch Starter Project/app.c +++ b/apps/Sensor Watch Starter Project/app.c @@ -51,14 +51,14 @@ void app_init() { } /** - * @brief the app_wake_from_deep_sleep function is only called if your app is waking from + * @brief the app_wake_from_backup function is only called if your app is waking from * the ultra-low power BACKUP sleep mode. You may have chosen to store some state in the * RTC's backup registers prior to entering this mode. You may restore that state here. * * @see watch_enter_deep_sleep() */ -void app_wake_from_deep_sleep() { - // this app only supports shallow sleep mode. +void app_wake_from_backup() { + // This app does not support BACKUP mode. } /** @@ -69,9 +69,12 @@ void app_wake_from_deep_sleep() { * accelerometer that will run at all times should be configured here, whereas you may * want to enable a more power-hungry environmental sensor only when you need it. * - * @note If your app enters the ultra-low power BACKUP sleep mode, this function will - * be called again when it wakes from that deep sleep state. In this state, the RTC will - * still be configured with the correct date and time. + * @note If your app enters the Sleep or Deep Sleep modes, this function will be called + * again on wake, since those modes will have disabled all pins and peripherals; you'll + * likely need to set them up again. This function will also be called again if your app + * entered the ultra-low power BACKUP mode, since BACKUP mode will have done all that and + * also wiped out the system RAM. Note that when this is called after waking from sleep, + * the RTC will still be configured with the correct date and time. */ void app_setup() { watch_enable_leds(); @@ -94,25 +97,24 @@ void app_setup() { } /** - * @brief the app_prepare_for_sleep function is called before the watch goes into the - * STANDBY sleep mode. In STANDBY mode, most peripherals are shut down, and no code - * will run until the watch receives an interrupt (generally either the 1Hz tick or - * a press on one of the buttons). + * @brief the app_prepare_for_standby function is called before the watch goes into STANDBY mode. + * In STANDBY mode, most peripherals are shut down, and no code will run until the watch receives + * an interrupt (generally either the 1Hz tick or a press on one of the buttons). */ -void app_prepare_for_sleep() { +void app_prepare_for_standby() { } /** - * @brief the app_wake_from_sleep function is called after the watch wakes from the - * STANDBY sleep mode. + * @brief the app_wake_from_standby function is called after the watch wakes from STANDBY mode, + * but before your main app_loop. */ -void app_wake_from_sleep() { +void app_wake_from_standby() { application_state.wake_count++; } /** - * @brief the app_loop function is called once on app startup and then again each time - * the watch STANDBY sleep mode. + * @brief the app_loop function is called once on app startup and then again each time the + * watch exits STANDBY mode. */ bool app_loop() { if (application_state.beep) { @@ -157,7 +159,7 @@ bool app_loop() { delay_ms(250); // nap time :) - watch_enter_shallow_sleep(false); + watch_enter_deep_sleep_mode(); // we just woke up; wait a moment again for the user's finger to be off the button... delay_ms(250); diff --git a/apps/beats-time/app.c b/apps/beats-time/app.c index 611e7f16..5c68a3e8 100644 --- a/apps/beats-time/app.c +++ b/apps/beats-time/app.c @@ -50,8 +50,8 @@ void app_init() { memset(&application_state, 0, sizeof(application_state)); } -void app_wake_from_deep_sleep() { - // This app does not support deep sleep mode. +void app_wake_from_backup() { + // This app does not support BACKUP mode. } void app_setup() { @@ -67,10 +67,10 @@ void app_setup() { watch_rtc_register_tick_callback(cb_tick); } -void app_prepare_for_sleep() { +void app_prepare_for_standby() { } -void app_wake_from_sleep() { +void app_wake_from_standby() { } void update_tick_frequency() { diff --git a/movement/movement.c b/movement/movement.c index df3cbf0b..e1ab322f 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -56,8 +56,8 @@ void app_init() { _movement_reset_inactivity_countdown(); } -void app_wake_from_deep_sleep() { - // This app does not support deep sleep mode. +void app_wake_from_backup() { + // This app does not support BACKUP mode. } void app_setup() { @@ -94,10 +94,10 @@ void app_setup() { } } -void app_prepare_for_sleep() { +void app_prepare_for_standby() { } -void app_wake_from_sleep() { +void app_wake_from_standby() { } bool app_loop() { @@ -147,11 +147,11 @@ bool app_loop() { while (movement_state.le_mode_ticks == -1) { event.event_type = EVENT_LOW_ENERGY_UPDATE; watch_faces[movement_state.current_watch_face].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); - watch_enter_shallow_sleep(true); + watch_enter_sleep_mode(); } // as soon as le_mode_ticks is reset by the extwake handler, we bail out of the loop and reactivate ourselves. event.event_type = EVENT_ACTIVATE; - // this is a hack tho: waking from shallow sleep, app_setup does get called, but it happens before we have reset our ticks. + // this is a hack tho: waking from sleep mode, app_setup does get called, but it happens before we have reset our ticks. // need to figure out if there's a better heuristic for determining how we woke up. app_setup(); } diff --git a/watch-library/main.c b/watch-library/main.c index db602a34..1fe751ef 100755 --- a/watch-library/main.c +++ b/watch-library/main.c @@ -57,7 +57,7 @@ int main(void) { // Ideally we should check if the TAMPER or CMP0 (alarm) flags are set. if (_watch_rtc_is_enabled()) { // User code. Give the application a chance to restore state from backup registers. - app_wake_from_deep_sleep(); + app_wake_from_backup(); // disable the tamper interrupt and clear the tamper bit hri_rtcmode0_clear_INTEN_TAMPER_bit(RTC); @@ -75,9 +75,9 @@ int main(void) { bool can_sleep = app_loop(); if (can_sleep && !usb_enabled) { - app_prepare_for_sleep(); + app_prepare_for_standby(); sleep(4); - app_wake_from_sleep(); + app_wake_from_standby(); } } diff --git a/watch-library/watch/watch_app.h b/watch-library/watch/watch_app.h index 00a6a610..56b9bfd3 100644 --- a/watch-library/watch/watch_app.h +++ b/watch-library/watch/watch_app.h @@ -33,7 +33,7 @@ * * 1. Your app_init() function is called. * - This method should only be used to set your initial application state. - * 2. If your app is waking from BACKUP, app_wake_from_deep_sleep() is called. + * 2. If your app is waking from BACKUP, app_wake_from_backup() is called. * - If you saved state in the RTC's backup registers, you can restore it here. * 3. Your app_setup() method is called. * - You may wish to enable some functionality and peripherals here. @@ -43,11 +43,11 @@ * - Return true if your app is prepared to enter STANDBY mode. * 5. This step differs depending on the value returned by app_loop: * - If you returned false, execution resumes at (4). - * - If you returned true, app_prepare_for_sleep() is called; execution moves on to (6). - * 6. The microcontroller enters the STANDBY sleep mode. + * - If you returned true, app_prepare_for_standby() is called; execution moves on to (6). + * 6. The microcontroller enters STANDBY mode. * - No user code will run, and the watch will enter a low power mode. * - The watch will remain in this state until an interrupt wakes it. - * 7. Once woken from STANDBY, your app_wake_from_sleep() function is called. + * 7. Once woken from STANDBY, your app_wake_from_standby() function is called. * - After this, execution resumes at (4). */ /// @{ @@ -57,11 +57,11 @@ */ void app_init(); -/** @brief A function you will implement to wake from deep sleep mode. The app_wake_from_deep_sleep function is only - * called if your app is waking from the ultra-low power BACKUP sleep mode. You may have chosen to store some - * state in the RTC's backup registers prior to entering this mode. You may restore that state here. +/** @brief A function you will implement to wake from BACKUP mode, which wipes the system's RAM, and with it, your + * application's state. You may have chosen to store some important application state in the RTC's backup + * registers prior to entering this mode. You may restore that state here. */ -void app_wake_from_deep_sleep(); +void app_wake_from_backup(); /** @brief A function you will implement to set up your application. The app_setup function is like setup() in Arduino. * It is called once when the program begins. You should set pin modes and enable any peripherals you want to @@ -74,12 +74,12 @@ void app_wake_from_deep_sleep(); void app_setup(); /** @brief A function you will implement to serve as the app's main run loop. This method will be called repeatedly, - or if you enter STANDBY sleep mode, as soon as the device wakes from sleep. - * @return You should return true if your app is prepared to enter STANDBY sleep mode. If you return false, your - * app's app_loop method will be called again immediately. Note that in STANDBY mode, the watch will consume - * only about 95 microamperes of power, whereas if you return false and keep the app awake, it will consume - * about 355 microamperes. This is the difference between months of battery life and days. As much as - * possible, you should limit the amount of time your app spends awake. + or if you enter STANDBY mode, as soon as the device wakes from sleep. + * @return You should return true if your app is prepared to enter STANDBY mode. If you return false, your app's + * app_loop method will be called again immediately. Note that in STANDBY mode, the watch will consume only + * about 95 microamperes of power, whereas if you return false and keep the app awake, it will consume about + * 355 microamperes. This is the difference between months of battery life and days. As much as possible, + * you should limit the amount of time your app spends awake. * @note Only the RTC, the segment LCD controller and the external interrupt controller run in STANDBY mode. If you * are using, e.g. the PWM function to set a custom LED color, you should return false here until you are * finished with that operation. Note however that the peripherals will continue running after waking up, @@ -88,21 +88,21 @@ void app_setup(); */ bool app_loop(); -/** @brief A function you will implement to prepare to enter STANDBY sleep mode. The app_prepare_for_sleep function is - * called before the watch goes into the STANDBY sleep mode. In STANDBY mode, most peripherals are shut down, - * and no code will run until the watch receives an interrupt (generally either the 1Hz tick or a press on one - * of the buttons). +/** @brief A function you will implement to prepare to enter STANDBY mode. The app_prepare_for_standby function is + * called after your app_loop function returns true, and just before the watch enters STANDBY mode. In this + * mode most peripherals are shut down, and no code will run until the watch receives an interrupt (generally + * either the 1Hz tick or a press on one of the buttons). * @note If you are PWM'ing the LED or playing a sound on the buzzer, the TC/TCC peripherals that drive those operations * will not run in STANDBY. BUT! the output pins will retain the state they had when entering standby. This means * you could end up entering standby with an LED on and draining power, or with a DC potential across the piezo * buzzer that could damage it if left in this state. If your app_loop does not prevent sleep during these - * activities, you should make sure to disable these outputs in app_prepare_for_sleep. + * activities, you should make sure to disable these outputs in app_prepare_for_standby. */ -void app_prepare_for_sleep(); +void app_prepare_for_standby(); -/** @brief A method you will implement to configure the app after waking from STANDBY sleep mode. +/** @brief A method you will implement to configure the app after waking from STANDBY mode. */ -void app_wake_from_sleep(); +void app_wake_from_standby(); /// @} #endif diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index 9ca53db0..8120617b 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -151,12 +151,7 @@ void _watch_disable_all_peripherals_except_slcd() { MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_SERCOM3; } -void watch_enter_shallow_sleep(bool display_on) { - if (!display_on) { - slcd_sync_deinit(&SEGMENT_LCD_0); - hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); - } - +void watch_enter_sleep_mode() { // disable all other peripherals _watch_disable_all_peripherals_except_slcd(); @@ -178,15 +173,19 @@ void watch_enter_shallow_sleep(bool display_on) { // call app_setup so the app can re-enable everything we disabled. app_setup(); - // and call app_wake_from_sleep (since main won't have a chance to do it) - app_wake_from_sleep(); + // and call app_wake_from_standby (since main won't have a chance to do it) + app_wake_from_standby(); } -void watch_enter_deep_sleep() { - // this will not work on the current silicon revision, but I said in the documentation that we do it. - // so let's do it! - watch_register_extwake_callback(BTN_ALARM, NULL, true); +void watch_enter_deep_sleep_mode() { + // identical to sleep mode except we disable the LCD first. + slcd_sync_deinit(&SEGMENT_LCD_0); + hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); + + watch_enter_sleep_mode(); +} +void watch_enter_backup_mode() { watch_rtc_disable_all_periodic_callbacks(); _watch_disable_all_peripherals_except_slcd(); slcd_sync_deinit(&SEGMENT_LCD_0); @@ -196,3 +195,15 @@ void watch_enter_deep_sleep() { // go into backup sleep mode (5). when we exit, the reset controller will take over. sleep(5); } + +// deprecated +void watch_enter_shallow_sleep(bool display_on) { + if (display_on) watch_enter_sleep_mode(); + else watch_enter_deep_sleep_mode(); +} + +// deprecated +void watch_enter_deep_sleep() { + watch_register_extwake_callback(BTN_ALARM, NULL, true); + watch_enter_backup_mode(); +} diff --git a/watch-library/watch/watch_deepsleep.h b/watch-library/watch/watch_deepsleep.h index 84825f00..a453e763 100644 --- a/watch-library/watch/watch_deepsleep.h +++ b/watch-library/watch/watch_deepsleep.h @@ -32,26 +32,54 @@ extern ext_irq_cb_t btn_alarm_callback; extern ext_irq_cb_t a2_callback; extern ext_irq_cb_t a4_callback; -/** @addtogroup deepsleep Deep Sleep Control - * @brief This section covers functions related to preparing for and entering BACKUP mode, the - * deepest sleep mode available on the SAM L22 +/** @addtogroup deepsleep Sleep Control + * @brief This section covers functions related to the various sleep modes available to the watch, + * including Sleep, Deep Sleep, and BACKUP mode. + * @details These terms changed meaning a bit over the course of development; if you are coming + * to this documentation after having worked with an earlier version of the library, + * these definitions should clarify the terminology. Terms in all caps are modes of the + * SAM L22; terms in Title Case are specific implementations in this library. + * - ACTIVE mode is the mode the SAM L22 is in when both the main clock and the CPU are + * running. It is the most power-hungry mode. If you ever call delay_ms to wait a beat, + * the watch will remain in ACTIVE mode while taking that delay. In addition, whenever + * your `app_loop` function returns false, the device will remain in ACTIVE mode and + * call your `app_loop` function again. + * - STANDBY mode turns off the main clock and halts the CPU. Since the PWM driver is + * run from the main clock, it also stops the buzzer and any dimming of the LEDs. + * In this mode, the watch can wake from any interrupt source. Whenever your `app_loop` + * function returns true, the watch enters STANDBY mode until the next tick or other + * interrupt. This mode uses much less power than ACTIVE mode. + * - Sleep Mode is a special case of STANDBY mode. In this mode, the watch turns off + * almost all peripherals (including the external interrupt controller), and disables + * all pins except for the external wake pins. In this mode the watch can only wake + * from the RTC alarm interrupt or an external wake pin (A2, A4 or the alarm button), + * but the display remains on and your app's state is retained. You can enter this + * mode by calling `watch_enter_sleep_mode`. It consumes an order of magnitude less + * power than STANDBY mode. + * - Deep Sleep Mode is identical to sleep mode, but it also turns off the LCD to save + * a bit more power. You can enter this mode by calling `watch_enter_deep_sleep_mode`. + * - BACKUP mode is the lowest possible power mode on the SAM L22. It turns off all pins + * and peripherals except for the RTC. It also turns off the RAM, obliterating your + * application's state. The only way to wake from this mode is by setting an external + * wake interrupt on pin A2 or pin A4, and when you do wake it will be much like a + * wake from reset. You can enter this mode by calling `watch_enter_backup_mode`. */ /// @{ /** @brief Registers a callback on one of the RTC's external wake pins, which can wake the device - * from deep sleep (aka BACKUP) mode. + * from Sleep, Deep Sleep and BACKUP modes (but see warning re: BACKUP mode). * @param pin Either pin BTN_ALARM, A2, or A4. These are the three external wake pins. If the pin * is BTN_ALARM, this function also enables an internal pull down on that pin. - * @param callback The callback to be called if this pin triggers outside of deep sleep mode. If - * this is NULL, no callback will be called even in normal mode, but the interrupt - * will still be enabled so that it can wake from deep sleep or backup mode. + * @param callback The callback to be called if this pin triggers outside of BACKUP mode. If this is + * NULL, no callback will be called even in normal modes, but the interrupt will + * still be enabled so that it can wake the device. * @param level The level you wish to scan for: true for rising, false for falling. Note that you * cannot scan for both rising and falling edges like you can with the external interrupt * pins; with the external wake interrupt, you can only get one or the other. - * @note When in normal or STANDBY mode, this will function much like a standard external interrupt - * situation: these pins will wake from standby, and your callback will be called. However, - * if the device enters deep sleep and one of these pins wakes the device, your callback - * WILL NOT be called, as the device is basically waking from reset at that point. + * @note When in ACTIVE, STANDBY and Sleep / Deep sleep modes, this will function much like a standard + * external interrupt situation: these pins will wake the device, and your callback will be + * called. However, if the device enters BACKUP mode and one of these pins wakes the device, your + * callback WILL NOT be called, as the device is basically waking from reset at that point. * @warning As of the current SAM L22 silicon revision (rev B), the BTN_ALARM pin cannot wake the * device from BACKUP mode. You can still use this function to register a BTN_ALARM interrupt * in normal or deep sleep mode, but to wake from BACKUP, you will need to use pin A2 or A4. @@ -59,59 +87,73 @@ extern ext_irq_cb_t a4_callback; void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level); /** @brief Unregisters the RTC interrupt on one of the EXTWAKE pins. This will prevent a value change on - * one of these pins from waking the device from shallow and deep sleep modes. + * one of these pins from waking the device. * @param pin Either pin BTN_ALARM, A2, or A4. If the pin is BTN_ALARM, this function DOES NOT disable * the internal pull down on that pin. */ void watch_disable_extwake_interrupt(uint8_t pin); -/** @brief Stores data in one of the RTC's backup registers, which retain their data in deep sleep mode. +/** @brief Stores data in one of the RTC's backup registers, which retain their data in BACKUP mode. * @param data An unsigned 32 bit integer with the data you wish to store. * @param reg A register from 0-7. */ void watch_store_backup_data(uint32_t data, uint8_t reg); -/** @brief Gets 32 bits of data from the RTC's backup register. +/** @brief Gets 32 bits of data from the RTC's BACKUP register. * @param reg A register from 0-7. * @return An unsigned 32 bit integer with the from the backup register. */ uint32_t watch_get_backup_data(uint8_t reg); -/** @brief Enters a shallow sleep mode by disabling all pins and peripherals except the RTC and (optionally) - * the LCD. You can wake from this mode by pressing the ALARM button, if you have an registered an - * external wake callback on the ALARM button. When your app wakes from this shallow sleep mode, your - * app_setup method will be called, since this function will have disabled things you set up. - * @param display_on if true, leaves the LCD on to display whatever content was on-screen. If false, disables - * the segment LCD controller for additional power savings. - * @details This shallow sleep mode is not the lowest power mode available (see watch_enter_deep_sleep), but - * it has the benefit of retaining your application state and being able to wake from the ALARM button. - * It also provides an option for displaying a message to the user when asleep. Note that whether you - * want to wake from the ALARM button, the A2 RTC interrupt or the A4 interrupt, you must configure - * this by calling watch_register_extwake_callback first. +/** @brief enters Sleep Mode by disabling all pins and peripherals except the RTC and the LCD. + * @details This sleep mode is not the lowest power mode available, but it has the benefit of allowing you + * to display a message to the user while asleep. You can also set an alarm interrupt to wake at a + * configfurable interval (every minute, hour or day) to update the display. You can wake from this + * mode by pressing the ALARM button, if you registered an extwake callback on the ALARM button. + * Also note that when your app wakes from this sleep mode, your app_setup method will be called + * again, since this function will have disabled things you set up there. * - * Power consumption in shallow sleep mode varies a bit with the battery voltage and the temperature, - * but at 3 V and 25~30° C you can roughly estimate: - * * < 12µA current draw with the LCD controller on - * * < 6µA current draw with the LCD controller off + * Note that to wake from either the ALARM button, the A2 interrupt or the A4 interrupt, you + * must first configure this by calling watch_register_extwake_callback. + * + * You can estimate the power consumption of this mode to be on the order of 30 microwatts + * (about 10 µA at 3 V). */ -void watch_enter_shallow_sleep(bool display_on); +void watch_enter_sleep_mode(); + +/** @brief enters Deep Sleep Mode by disabling all pins and peripherals except the RTC. + * @details Short of BACKUP mode, this is the lowest power mode you can enter while retaining your + * application state (and the ability to wake with the alarm button). Just note that the display + * will be completely off, so you should document to the user of your application that they will + * need to press the alarm button to wake the device, or use a sensor board with support for + * an external wake pin. + * + * All notes from watch_enter_sleep_mode apply here, except for power consumption. You can estimate + * the power consumption of this mode to be on the order of 12 microwatts (about 4µA at 3 V). + */ +void watch_enter_deep_sleep_mode(); /** @brief Enters the SAM L22's lowest-power mode, BACKUP. - * @details This function does some housekeeping before entering BACKUP mode. It first disables all - * peripherals except for the RTC, and disables the tick interrupt (since that would wake - * us up from deep sleep). It also sets an external wake source on the ALARM button, if one - * was not already set. If you wish to wake from another source, such as one of the external - * wake interrupt pins on the 9-pin connector, set that up prior to calling this function. + * @details This function does some housekeeping before entering BACKUP mode. It first disables all pins + * and peripherals except for the RTC, and disables the tick interrupt (since that would wake + * us up from BACKUP mode). Once again, if you wish to wake from the A2 or the A4 interrupt, + * you must first configure this by calling watch_register_extwake_callback. * @note If you have a callback set for an external wake interrupt, it will be called if triggered while - * in ACTIVE, IDLE or STANDBY modes, but it *will not be called* when waking from BACKUP. - * Waking from backup is effectively like waking from reset, except that your @ref - * app_wake_from_deep_sleep function will be called. + * in ACTIVE, STANDBY, Sleep and Deep Sleep modes, but it *will not be called* when waking from + * BACKUP mode. Waking from backup is effectively like waking from reset, except that your + * @ref app_wake_from_backup function will be called. * @warning On current revisions of the SAM L22 silicon, the ALARM_BTN pin (PA02 RTC/IN2) cannot wake * the device from deep sleep mode. There is an errata note (Reference: 15010) that says that * due to a silicon bug, RTC/IN2 is not functional in BACKUP. As a result, you should not call * this function unless you have a device on the nine-pin connector with an external interrupt * on pin A2 or A4 (i.e. an accelerometer with an interrupt pin). */ +void watch_enter_backup_mode(); + +__attribute__((deprecated("Use watch_enter_sleep_mode or watch_enter_deep_sleep_mode instead"))) +void watch_enter_shallow_sleep(bool display_on); + +__attribute__((deprecated("Use watch_enter_backup_mode instead"))) void watch_enter_deep_sleep(); /// @} #endif diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h index 1776a712..7ddd7483 100644 --- a/watch-library/watch/watch_rtc.h +++ b/watch-library/watch/watch_rtc.h @@ -88,8 +88,8 @@ watch_date_time watch_rtc_get_date_time(); * @param alarm_time The time that you wish to match. The date is currently ignored. * @param mask One of the values in watch_rtc_alarm_match indicating which values to check. * @details The alarm interrupt is a versatile tool for scheduling events in the future, especially since it can - * wake the device from both shallow and deep sleep modes. The key to its versatility is the mask - * parameter. Suppose we set an alarm for midnight, 00:00:00. + * wake the device from all sleep modes. The key to its versatility is the mask parameter. + * Suppose we set an alarm for midnight, 00:00:00. * * if mask is ALARM_MATCH_SS, the alarm will fire every minute when the clock ticks to seconds == 0. * * with ALARM_MATCH_MMSS, the alarm will once an hour, at the top of each hour. * * with ALARM_MATCH_HHMMSS, the alarm will fire at midnight every day. diff --git a/watch-library/watch/watch_slcd.h b/watch-library/watch/watch_slcd.h index 724d3dde..abe4d744 100644 --- a/watch-library/watch/watch_slcd.h +++ b/watch-library/watch/watch_slcd.h @@ -110,7 +110,7 @@ void watch_clear_all_indicators(); /** @brief Blinks a single character in position 7. Does not affect other positions. * @details Six of the seven segments in position 7 (and only position 7) are capable of autonomous * blinking. This blinking does not require any CPU resources, and will continue even in - * standby and shallow sleep mode (if the LCD remains on). + * STANDBY and Sleep mode (but not Deep Sleep mode, since that mode turns off the LCD). * @param character The character you wish to blink. * @param duration The duration of the on/off cycle in milliseconds, from 50 to ~4250 ms. * @note Segment B of position 7 cannot blink autonomously, so not all characters will work well. @@ -132,8 +132,8 @@ void watch_stop_blink(); * or backward in a shift register whose positions map to fixed segments on the LCD. Given * this constraint, an animation across all six segments does not make sense; so the watch * library offers only a simple "tick/tock" in segments D and E. This animation does not - * require any CPU resources, and will continue even in standby and shallow sleep mode - * (if the LCD remains on). + * require any CPU resources, and will continue even in STANDBY and Sleep mode (but not Deep + * Sleep mode, since that mode turns off the LCD). * @param duration The duration of each frame in ms. 500 milliseconds produces a classic tick/tock. */ void watch_start_tick_animation(uint32_t duration); -- cgit v1.2.3 From b88cd0cd7e058679960adaf89818ed755f6e71a3 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 21 Oct 2021 11:02:44 -0400 Subject: movement: add thermistor readout face --- movement/make/Makefile | 3 + movement/movement.h | 10 ++- movement/movement_config.h | 1 + .../watch_faces/thermistor/thermistor_driver.c | 76 ++++++++++++++++++++++ .../watch_faces/thermistor/thermistor_driver.h | 13 ++++ .../thermistor/thermistor_readout_face.c | 73 +++++++++++++++++++++ .../thermistor/thermistor_readout_face.h | 19 ++++++ 7 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 movement/watch_faces/thermistor/thermistor_driver.c create mode 100644 movement/watch_faces/thermistor/thermistor_driver.h create mode 100644 movement/watch_faces/thermistor/thermistor_readout_face.c create mode 100644 movement/watch_faces/thermistor/thermistor_readout_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index f17fc7e5..2ed06d96 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -14,6 +14,7 @@ INCLUDES += \ -I../watch_faces/clock/ \ -I../watch_faces/settings/ \ -I../watch_faces/complications/ \ + -I../watch_faces/thermistor/ \ # If you add any other source files you wish to compile, add them after ../app.c # Note that you will need to add a backslash at the end of any line you wish to continue, i.e. @@ -27,6 +28,8 @@ SRCS += \ ../watch_faces/settings/preferences_face.c \ ../watch_faces/settings/set_time_face.c \ ../watch_faces/complications/pulsometer_face.c \ + ../watch_faces/thermistor/thermistor_driver.c \ + ../watch_faces/thermistor/thermistor_readout_face.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/movement/movement.h b/movement/movement.h index 41446a9b..e8bf9247 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -6,14 +6,20 @@ // TODO: none of this is implemented typedef union { struct { - uint32_t reserved : 15; - uint32_t clock_mode_24h : 1; // determines whether clock should use 12 or 24 hour mode. + uint32_t reserved : 14; uint32_t button_should_sound : 1; // if true, pressing a button emits a sound. uint32_t to_interval : 2; // an inactivity interval for asking the active face to resign. uint32_t le_interval : 3; // 0 to disable low energy mode, or an inactivity interval for going into low energy mode. uint32_t led_duration : 2; // how many seconds to shine the LED for (x2), or 0 to disable it. uint32_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15) uint32_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15) + + // while Movement itself doesn't implement a clock or display units, it may make sense to include some + // global settings for watch faces to check. The 12/24 hour preference could inform a clock or a + // time-oriented complication like a sunrise/sunset timer, and a simple locale preference could tell an + // altimeter to display feet or meters as easily as it tells a thermometer to display degrees in F or C. + uint32_t clock_mode_24h : 1; // indicates whether clock should use 12 or 24 hour mode. + uint32_t use_imperial_units : 1; // indicates whether to use metric units (the default) or imperial. } bit; uint32_t value; } movement_settings_t; diff --git a/movement/movement_config.h b/movement/movement_config.h index 6a7aec5a..92539a3f 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -5,6 +5,7 @@ #include "preferences_face.h" #include "set_time_face.h" #include "pulsometer_face.h" +#include "thermistor_readout_face.h" const watch_face_t watch_faces[] = { simple_clock_face, diff --git a/movement/watch_faces/thermistor/thermistor_driver.c b/movement/watch_faces/thermistor/thermistor_driver.c new file mode 100644 index 00000000..9e5d6fd7 --- /dev/null +++ b/movement/watch_faces/thermistor/thermistor_driver.c @@ -0,0 +1,76 @@ +#include "thermistor_driver.h" +#include "watch.h" + +#define THERMISTOR_B_COEFFICIENT (3950.0) +#define THERMISTOR_NOMINAL_TEMPERATURE (25.0) +#define THERMISTOR_NOMINAL_RESISTANCE (10000.0) +#define THERMISTOR_SERIES_RESISTANCE (10000.0) + +// TODO: we really need a math library. +uint32_t msb(uint32_t v); +double ln(double y); + +void thermistor_driver_enable() { + // Enable the ADC peripheral, which we'll use to read the thermistor value. + watch_enable_adc(); + // Enable analog circuitry on pin A1, which is tied to the thermistor resistor divider. + watch_enable_analog_input(A1); + // Enable digital output on A0, which is the power to the thermistor circuit. + watch_enable_digital_output(A0); +} + +void thermistor_driver_disable() { + // Enable the ADC peripheral, which we'll use to read the thermistor value. + watch_disable_adc(); + // Disable analog circuitry on pin A1 to save power. + watch_disable_analog_input(A1); + // Disable A0's output circuitry. + watch_disable_digital_output(A0); +} + +float thermistor_driver_get_temperature() { + // set A0 high to power the thermistor circuit. + watch_set_pin_level(A0, true); + // get the pin level + uint16_t val = watch_get_analog_pin_level(A1); + // and then set A0 low to power down the thermistor circuit. + watch_set_pin_level(A0, false); + + double reading = (double)val; + reading = (1023.0 * THERMISTOR_SERIES_RESISTANCE) / (reading / 64.0); + reading -= THERMISTOR_SERIES_RESISTANCE; + reading = reading / THERMISTOR_NOMINAL_RESISTANCE; + reading = ln(reading); + reading /= THERMISTOR_B_COEFFICIENT; + reading += 1.0 / (THERMISTOR_NOMINAL_TEMPERATURE + 273.15); + reading = 1.0 / reading; + reading -= 273.15; + + return reading; +} + +uint32_t msb(uint32_t v) { + static const int pos[32] = {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v = (v >> 1) + 1; + return pos[(v * 0x077CB531UL) >> 27]; +} + +double ln(double y) { + int log2; + double divisor, x, result; + + log2 = msb((int)y); // See: https://stackoverflow.com/a/4970859/6630230 + divisor = (double)(1 << log2); + x = y / divisor; // normalized value between [1.0, 2.0] + + result = -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x; + result += ((double)log2) * 0.69314718; // ln(2) = 0.69314718 + + return result; +} + diff --git a/movement/watch_faces/thermistor/thermistor_driver.h b/movement/watch_faces/thermistor/thermistor_driver.h new file mode 100644 index 00000000..837eb15b --- /dev/null +++ b/movement/watch_faces/thermistor/thermistor_driver.h @@ -0,0 +1,13 @@ +#ifndef THERMISTOR_DRIVER_H_ +#define THERMISTOR_DRIVER_H_ + +// NOTE: This implementation is specific to one prototype sensor board, OSO-MISC-21-009, but both +// the sensor board design and this implementation are likely to change. Thermistor functionality +// may even end up being baked into the Sensor Watch library. This is all by way of saying this +// code is very temporary and the thermistor screens will likely get a rewrite in the future. + +void thermistor_driver_enable(); +void thermistor_driver_disable(); +float thermistor_driver_get_temperature(); + +#endif // THERMISTOR_DRIVER_H_ diff --git a/movement/watch_faces/thermistor/thermistor_readout_face.c b/movement/watch_faces/thermistor/thermistor_readout_face.c new file mode 100644 index 00000000..2a4ec3a1 --- /dev/null +++ b/movement/watch_faces/thermistor/thermistor_readout_face.c @@ -0,0 +1,73 @@ +#include +#include +#include "thermistor_readout_face.h" +#include "thermistor_driver.h" +#include "watch.h" + +void _thermistor_readout_face_update_display(bool in_fahrenheit) { + float temperature_c = thermistor_driver_get_temperature(); + char buf[14]; + if (in_fahrenheit) { + sprintf(buf, "%4.1f#F", temperature_c * 1.8 + 32.0); + } else { + sprintf(buf, "%4.1f#C", temperature_c); + } + watch_display_string(buf, 4); +} + +void thermistor_readout_face_setup(movement_settings_t *settings, void ** context_ptr) { + (void) settings; + (void) context_ptr; +} + +void thermistor_readout_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + watch_display_string("TE", 0); + thermistor_driver_enable(); +} + +bool thermistor_readout_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + (void) context; + watch_date_time date_time = watch_rtc_get_date_time(); + switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; + case EVENT_LIGHT_BUTTON_DOWN: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_UP: + settings->bit.use_imperial_units = !settings->bit.use_imperial_units; + _thermistor_readout_face_update_display(settings->bit.use_imperial_units); + break; + case EVENT_ACTIVATE: + // force a measurement to be taken immediately. + date_time.unit.second = 0; + // fall through + case EVENT_TICK: + if (date_time.unit.second % 5 == 4) { + // Not 100% on this, but I like the idea of using the signal indicator to indicate that we're sensing data. + // In this case we turn the indicator on a second before the reading is taken, and clear it when we're done. + // In reality the measurement takes a fraction of a second, but this is just to show something is happening. + watch_set_indicator(WATCH_INDICATOR_SIGNAL); + } else if (date_time.unit.second % 5 == 0) { + _thermistor_readout_face_update_display(settings->bit.use_imperial_units); + watch_clear_indicator(WATCH_INDICATOR_SIGNAL); + } + break; + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; + default: + break; + } + + return true; +} + +void thermistor_readout_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + thermistor_driver_disable(); +} diff --git a/movement/watch_faces/thermistor/thermistor_readout_face.h b/movement/watch_faces/thermistor/thermistor_readout_face.h new file mode 100644 index 00000000..639d00a4 --- /dev/null +++ b/movement/watch_faces/thermistor/thermistor_readout_face.h @@ -0,0 +1,19 @@ +#ifndef THERMISTOR_FACE_H_ +#define THERMISTOR_FACE_H_ + +#include "movement.h" + +void thermistor_readout_face_setup(movement_settings_t *settings, void ** context_ptr); +void thermistor_readout_face_activate(movement_settings_t *settings, void *context); +bool thermistor_readout_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void thermistor_readout_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t thermistor_readout_face = { + thermistor_readout_face_setup, + thermistor_readout_face_activate, + thermistor_readout_face_loop, + thermistor_readout_face_resign, + NULL +}; + +#endif // THERMISTOR_FACE_H_ \ No newline at end of file -- cgit v1.2.3 From 4df23ea9f9292ab9371302f69e5192b91cbce620 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 21 Oct 2021 15:10:06 -0400 Subject: typo in documentation: all five pins are analog capable --- watch-library/watch/watch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/watch-library/watch/watch.h b/watch-library/watch/watch.h index 5cd45a6c..fee8f4ea 100644 --- a/watch-library/watch/watch.h +++ b/watch-library/watch/watch.h @@ -42,7 +42,7 @@ - @ref led - This section covers functions related to the bi-color red/green LED mounted behind the LCD. - @ref buzzer - This section covers functions related to the piezo buzzer. - @ref adc - This section covers functions related to the SAM L22's analog-to-digital converter, as well as - configuring and reading values from the three analog-capable pins on the 9-pin connector. + configuring and reading values from the five analog-capable pins on the 9-pin connector. - @ref gpio - This section covers functions related to general-purpose input and output signals. - @ref i2c - This section covers functions related to the SAM L22's built-I2C driver, including configuring the I2C bus, putting values directly on the bus and reading data from registers on I2C devices. -- cgit v1.2.3 From f1a706792e995f45b6b6f2ef70b2318253002249 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Thu, 21 Oct 2021 17:28:59 -0400 Subject: movement: add character set demo --- movement/make/Makefile | 2 + movement/movement_config.h | 1 + movement/watch_faces/demos/character_set_face.c | 51 +++++++++++++++++++++++++ movement/watch_faces/demos/character_set_face.h | 19 +++++++++ watch-library/watch/watch_slcd.c | 1 + 5 files changed, 74 insertions(+) create mode 100644 movement/watch_faces/demos/character_set_face.c create mode 100644 movement/watch_faces/demos/character_set_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index 2ed06d96..b65d1a47 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -15,6 +15,7 @@ INCLUDES += \ -I../watch_faces/settings/ \ -I../watch_faces/complications/ \ -I../watch_faces/thermistor/ \ + -I../watch_faces/demos/ \ # If you add any other source files you wish to compile, add them after ../app.c # Note that you will need to add a backslash at the end of any line you wish to continue, i.e. @@ -30,6 +31,7 @@ SRCS += \ ../watch_faces/complications/pulsometer_face.c \ ../watch_faces/thermistor/thermistor_driver.c \ ../watch_faces/thermistor/thermistor_readout_face.c \ + ../watch_faces/demos/character_set_face.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/movement/movement_config.h b/movement/movement_config.h index 92539a3f..99bffdd2 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -6,6 +6,7 @@ #include "set_time_face.h" #include "pulsometer_face.h" #include "thermistor_readout_face.h" +#include "character_set_face.h" const watch_face_t watch_faces[] = { simple_clock_face, diff --git a/movement/watch_faces/demos/character_set_face.c b/movement/watch_faces/demos/character_set_face.c new file mode 100644 index 00000000..7daea5a9 --- /dev/null +++ b/movement/watch_faces/demos/character_set_face.c @@ -0,0 +1,51 @@ +#include +#include +#include "character_set_face.h" +#include "watch.h" + +void character_set_face_setup(movement_settings_t *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(char)); +} + +void character_set_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + char *c = (char *)context; + *c = '@'; +} + +bool character_set_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + (void) settings; + char *c = (char *)context; + char buf[11]; + switch (event.event_type) { + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; + case EVENT_LIGHT_BUTTON_DOWN: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_UP: + *c = (*c) + 1; + if (*c & 0x80) *c = ' '; + // fall through + case EVENT_ACTIVATE: + sprintf(buf, "%c%c%c%c%c%c%c%c%c%c", *c, *c, *c, *c, *c, *c, *c, *c, *c, *c); + watch_display_string(buf, 0); + break; + case EVENT_TICK: + break; + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; + default: + break; + } + + return true; +} + +void character_set_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/movement/watch_faces/demos/character_set_face.h b/movement/watch_faces/demos/character_set_face.h new file mode 100644 index 00000000..b27a8359 --- /dev/null +++ b/movement/watch_faces/demos/character_set_face.h @@ -0,0 +1,19 @@ +#ifndef CHARACTER_SET_FACE_H_ +#define CHARACTER_SET_FACE_H_ + +#include "movement.h" + +void character_set_face_setup(movement_settings_t *settings, void ** context_ptr); +void character_set_face_activate(movement_settings_t *settings, void *context); +bool character_set_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void character_set_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t character_set_face = { + character_set_face_setup, + character_set_face_activate, + character_set_face_loop, + character_set_face_resign, + NULL +}; + +#endif // CHARACTER_SET_FACE_H_ \ No newline at end of file diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c index 6c63d966..63ba7988 100644 --- a/watch-library/watch/watch_slcd.c +++ b/watch-library/watch/watch_slcd.c @@ -204,6 +204,7 @@ void watch_display_character(uint8_t character, uint8_t position) { } if (character == 'T' && position == 1) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(1, 12)); // add descender else if (position == 0 && (character == 'B' || character == 'D')) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(0, 15)); // add funky ninth segment + else if (position == 0 && (character == 'B' || character == 'D' || character == '@')) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(0, 15)); // add funky ninth segment } void watch_display_string(char *string, uint8_t position) { -- cgit v1.2.3 From 66e95e4ab85444b2bdda32e7d04e7df138c52cc5 Mon Sep 17 00:00:00 2001 From: Wesley Ellis Date: Fri, 22 Oct 2021 22:00:52 -0400 Subject: Port beats to movement framework --- movement/make/Makefile | 1 + movement/movement_config.h | 1 + movement/watch_faces/complications/beats_face.c | 75 +++++++++++++++++++++++++ movement/watch_faces/complications/beats_face.h | 20 +++++++ 4 files changed, 97 insertions(+) create mode 100644 movement/watch_faces/complications/beats_face.c create mode 100644 movement/watch_faces/complications/beats_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index b65d1a47..9ff13b59 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -32,6 +32,7 @@ SRCS += \ ../watch_faces/thermistor/thermistor_driver.c \ ../watch_faces/thermistor/thermistor_readout_face.c \ ../watch_faces/demos/character_set_face.c \ + ../watch_faces/complications/beats_face.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. include $(TOP)/rules.mk diff --git a/movement/movement_config.h b/movement/movement_config.h index 99bffdd2..22daf2cb 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -7,6 +7,7 @@ #include "pulsometer_face.h" #include "thermistor_readout_face.h" #include "character_set_face.h" +#include "beats_face.h" const watch_face_t watch_faces[] = { simple_clock_face, diff --git a/movement/watch_faces/complications/beats_face.c b/movement/watch_faces/complications/beats_face.c new file mode 100644 index 00000000..73a82719 --- /dev/null +++ b/movement/watch_faces/complications/beats_face.c @@ -0,0 +1,75 @@ +#include +#include +#include "beats_face.h" +#include "watch.h" + +const uint8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time +const uint8_t BEAT_REFRESH_FREQUENCY = 8; + +void beats_face_setup(movement_settings_t *settings, void ** context_ptr) { + (void) settings; + (void) context_ptr; +} + +void beats_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + movement_request_tick_frequency(BEAT_REFRESH_FREQUENCY); +} + +bool beats_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + + char buf[14]; + float beats; + + watch_date_time date_time; + switch (event.event_type) { + case EVENT_TICK: + date_time = watch_rtc_get_date_time(); + beats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, event.subsecond, UTC_OFFSET); + sprintf(buf, "bt %6.0f", beats * 100); + + watch_display_string(buf, 0); + break; + case EVENT_LOW_ENERGY_UPDATE: + date_time = watch_rtc_get_date_time(); + beats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, event.subsecond, UTC_OFFSET); + sprintf(buf, "bt %4d ", (int)beats); + + watch_display_string(buf, 0); + break; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; + case EVENT_LIGHT_BUTTON_DOWN: + movement_illuminate_led(); + break; + case EVENT_ALARM_BUTTON_DOWN: + case EVENT_ALARM_BUTTON_UP: + case EVENT_ALARM_LONG_PRESS: + default: + break; + } + + return true; +} + +void beats_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + movement_request_tick_frequency(1); +} + +float clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, uint16_t subseconds, int16_t utc_offset) { + float beats = seconds + ((float)subseconds / (float)BEAT_REFRESH_FREQUENCY); + beats += 60 * minutes; + beats += (float)hours * 60 * 60; + beats += (utc_offset + 1) * 60 * 60; // offset from utc + 1 since beats in in UTC+1 + + beats /= 86.4; // convert to beats + while(beats > 1000) beats -= 1000; // beats %= 1000 but for a float + + return beats; +} \ No newline at end of file diff --git a/movement/watch_faces/complications/beats_face.h b/movement/watch_faces/complications/beats_face.h new file mode 100644 index 00000000..fe34f5aa --- /dev/null +++ b/movement/watch_faces/complications/beats_face.h @@ -0,0 +1,20 @@ +#ifndef BEATS_FACE_H_ +#define BEATS_FACE_H_ + +#include "movement.h" + +float clock2beats(uint16_t, uint16_t, uint16_t, uint16_t, int16_t); +void beats_face_setup(movement_settings_t *settings, void ** context_ptr); +void beats_face_activate(movement_settings_t *settings, void *context); +bool beats_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void beats_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t beats_face = { + beats_face_setup, + beats_face_activate, + beats_face_loop, + beats_face_resign, + NULL +}; + +#endif // BEATS_FACE_H_ \ No newline at end of file -- cgit v1.2.3 From 8f6cd8b29062622095c489235061287f13e74dda Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 23 Oct 2021 16:13:11 -0400 Subject: move weekday lookup to new utilities file --- make.mk | 1 + movement/watch_faces/clock/simple_clock_face.c | 15 ++-------- watch-library/watch/watch_utility.c | 35 ++++++++++++++++++++++ watch-library/watch/watch_utility.h | 41 ++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 watch-library/watch/watch_utility.c create mode 100644 watch-library/watch/watch_utility.h diff --git a/make.mk b/make.mk index 1c2a72f4..c9ef6534 100644 --- a/make.mk +++ b/make.mk @@ -81,6 +81,7 @@ SRCS += \ $(TOP)/watch-library/watch/watch_i2c.c \ $(TOP)/watch-library/watch/watch_uart.c \ $(TOP)/watch-library/watch/watch_deepsleep.c \ + $(TOP)/watch-library/watch/watch_utility.c \ $(TOP)/watch-library/watch/watch_private.c \ $(TOP)/watch-library/watch/watch.c \ $(TOP)/watch-library/hal/src/hal_atomic.c \ diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index e1e82031..9e279d95 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -1,6 +1,7 @@ #include #include "simple_clock_face.h" #include "watch.h" +#include "watch_utility.h" void simple_clock_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; @@ -19,7 +20,6 @@ void simple_clock_face_activate(movement_settings_t *settings, void *context) { } bool simple_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { - const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; char buf[11]; uint8_t pos; @@ -57,9 +57,9 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting pos = 0; if (event.event_type == EVENT_LOW_ENERGY_UPDATE) { if (!watch_tick_animation_is_running()) watch_start_tick_animation(500); - sprintf(buf, "%s%2d%2d%02d ", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute); + sprintf(buf, "%s%2d%2d%02d ", watch_utility_get_weekday(date_time), date_time.unit.day, date_time.unit.hour, date_time.unit.minute); } else { - sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_face_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + sprintf(buf, "%s%2d%2d%02d%02d", watch_utility_get_weekday(date_time), date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); } } watch_display_string(buf, pos); @@ -83,12 +83,3 @@ void simple_clock_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; } - -uint8_t simple_clock_face_get_weekday(uint16_t year, uint16_t month, uint16_t day) { - year += 20; - if (month <= 2) { - month += 12; - year--; - } - return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7; -} diff --git a/watch-library/watch/watch_utility.c b/watch-library/watch/watch_utility.c new file mode 100644 index 00000000..a0f361b4 --- /dev/null +++ b/watch-library/watch/watch_utility.c @@ -0,0 +1,35 @@ +/* + * MIT License + * + * Copyright (c) 2021 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 "watch_utility.h" + +const char * watch_utility_get_weekday(watch_date_time date_time) { + static const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"}; + date_time.unit.year += 20; + if (date_time.unit.month <= 2) { + date_time.unit.month += 12; + date_time.unit.year--; + } + return weekdays[(date_time.unit.day + 13 * (date_time.unit.month + 1) / 5 + date_time.unit.year + date_time.unit.year / 4 + 525) % 7]; +} diff --git a/watch-library/watch/watch_utility.h b/watch-library/watch/watch_utility.h new file mode 100644 index 00000000..e8808923 --- /dev/null +++ b/watch-library/watch/watch_utility.h @@ -0,0 +1,41 @@ +/* + * MIT License + * + * Copyright (c) 2021 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. + */ + +#ifndef _WATCH_UTILITY_H_INCLUDED +#define _WATCH_UTILITY_H_INCLUDED +////< @file watch_utility.h + +#include "watch.h" + +/** @addtogroup utility Utility Functions + * @brief This section covers various useful functions that don't fit anywhere else. + **/ +/// @{ +/** @brief Returns a two-letter weekday for the given timestamp, suitable for display + * in positions 0-1 of the watch face + * @param date_time The watch_date_time whose weekday you want. + */ +const char * watch_utility_get_weekday(watch_date_time date_time); + +#endif -- cgit v1.2.3 From 13d6ea10d74656914f989ae78a0f6cf5f7c5e534 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 23 Oct 2021 16:14:03 -0400 Subject: fix name of ifdef in thermistor readout face --- movement/watch_faces/thermistor/thermistor_readout_face.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/movement/watch_faces/thermistor/thermistor_readout_face.h b/movement/watch_faces/thermistor/thermistor_readout_face.h index 639d00a4..71d15427 100644 --- a/movement/watch_faces/thermistor/thermistor_readout_face.h +++ b/movement/watch_faces/thermistor/thermistor_readout_face.h @@ -1,5 +1,5 @@ -#ifndef THERMISTOR_FACE_H_ -#define THERMISTOR_FACE_H_ +#ifndef THERMISTOR_READOUT_FACE_H_ +#define THERMISTOR_READOUT_FACE_H_ #include "movement.h" @@ -16,4 +16,4 @@ static const watch_face_t thermistor_readout_face = { NULL }; -#endif // THERMISTOR_FACE_H_ \ No newline at end of file +#endif // THERMISTOR_READOUT_FACE_H_ -- cgit v1.2.3 From 27f699af80df5948400ff4ddc5bd34f2b7a75914 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 23 Oct 2021 16:23:36 -0400 Subject: WIP: thermistor data logger --- movement/make/Makefile | 1 + movement/movement_config.h | 1 + .../thermistor/thermistor_logging_face.c | 109 +++++++++++++++++++++ .../thermistor/thermistor_logging_face.h | 34 +++++++ 4 files changed, 145 insertions(+) create mode 100644 movement/watch_faces/thermistor/thermistor_logging_face.c create mode 100644 movement/watch_faces/thermistor/thermistor_logging_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index b65d1a47..aae21d22 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -31,6 +31,7 @@ SRCS += \ ../watch_faces/complications/pulsometer_face.c \ ../watch_faces/thermistor/thermistor_driver.c \ ../watch_faces/thermistor/thermistor_readout_face.c \ + ../watch_faces/thermistor/thermistor_logging_face.c \ ../watch_faces/demos/character_set_face.c \ # Leave this line at the bottom of the file; it has all the targets for making your project. diff --git a/movement/movement_config.h b/movement/movement_config.h index 99bffdd2..79f49144 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -6,6 +6,7 @@ #include "set_time_face.h" #include "pulsometer_face.h" #include "thermistor_readout_face.h" +#include "thermistor_logging_face.h" #include "character_set_face.h" const watch_face_t watch_faces[] = { diff --git a/movement/watch_faces/thermistor/thermistor_logging_face.c b/movement/watch_faces/thermistor/thermistor_logging_face.c new file mode 100644 index 00000000..1ff20483 --- /dev/null +++ b/movement/watch_faces/thermistor/thermistor_logging_face.c @@ -0,0 +1,109 @@ +#include +#include +#include "thermistor_logging_face.h" +#include "thermistor_driver.h" +#include "watch.h" + +void _thermistor_logging_face_log_data(thermistor_logger_state_t *logger_state) { + thermistor_driver_enable(); + watch_date_time date_time = watch_rtc_get_date_time(); + size_t pos = logger_state->data_points % THERMISTOR_LOGGING_NUM_DATA_POINTS; + + logger_state->data[pos].timestamp.reg = date_time.reg; + logger_state->data[pos].temperature_c = thermistor_driver_get_temperature(); + logger_state->data_points++; + + thermistor_driver_disable(); +} + +void _thermistor_logging_face_update_display(thermistor_logger_state_t *logger_state, bool in_fahrenheit, bool clock_mode_24h) { + int8_t pos = (logger_state->data_points - 1 - logger_state->display_index) % THERMISTOR_LOGGING_NUM_DATA_POINTS; + char buf[14]; + + watch_clear_indicator(WATCH_INDICATOR_24H); + watch_clear_indicator(WATCH_INDICATOR_PM); + watch_clear_colon(); + + if (pos < 0) { + sprintf(buf, "TL%2dno dat", logger_state->display_index); + } else if (logger_state->ts_ticks) { + watch_date_time date_time = logger_state->data[pos].timestamp; + watch_set_colon(); + if (clock_mode_24h) { + watch_set_indicator(WATCH_INDICATOR_24H); + } else { + if (date_time.unit.hour > 11) watch_set_indicator(WATCH_INDICATOR_PM); + date_time.unit.hour %= 12; + if (date_time.unit.hour == 0) date_time.unit.hour = 12; + } + sprintf(buf, "AT%2d%2d%02d%02d", date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second); + } else { + if (in_fahrenheit) { + sprintf(buf, "TL%2d%4.1f#F", logger_state->display_index, logger_state->data[pos].temperature_c * 1.8 + 32.0); + } else { + sprintf(buf, "TL%2d%4.1f#C", logger_state->display_index, logger_state->data[pos].temperature_c); + } + } + + watch_display_string(buf, 0); +} + +void thermistor_logging_face_setup(movement_settings_t *settings, void ** context_ptr) { + (void) settings; + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(thermistor_logger_state_t)); + memset(*context_ptr, 0, sizeof(thermistor_logger_state_t)); +} + +void thermistor_logging_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + thermistor_logger_state_t *logger_state = (thermistor_logger_state_t *)context; + logger_state->display_index = 0; + logger_state->ts_ticks = 0; +} + +bool thermistor_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + thermistor_logger_state_t *logger_state = (thermistor_logger_state_t *)context; + watch_date_time date_time = watch_rtc_get_date_time(); + switch (event.event_type) { + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; + case EVENT_LIGHT_LONG_PRESS: + // light button shows the timestamp, but if you need the light, long press it. + movement_illuminate_led(); + break; + case EVENT_LIGHT_BUTTON_DOWN: + logger_state->ts_ticks = 2; + _thermistor_logging_face_update_display(logger_state, settings->bit.use_imperial_units, settings->bit.clock_mode_24h); + break; + case EVENT_ALARM_BUTTON_DOWN: + logger_state->display_index = (logger_state->display_index + 1) % THERMISTOR_LOGGING_NUM_DATA_POINTS; + logger_state->ts_ticks = 0; + // fall through + case EVENT_ACTIVATE: + _thermistor_logging_face_update_display(logger_state, settings->bit.use_imperial_units, settings->bit.clock_mode_24h); + break; + case EVENT_TICK: + if (logger_state->ts_ticks && --logger_state->ts_ticks == 0) { + _thermistor_logging_face_update_display(logger_state, settings->bit.use_imperial_units, settings->bit.clock_mode_24h); + } + // this is just temporary for testing: log a data point every 30 seconds. + if (date_time.unit.second % 30 == 0 && !logger_state->ts_ticks) { + _thermistor_logging_face_log_data(logger_state); + _thermistor_logging_face_update_display(logger_state, settings->bit.use_imperial_units, settings->bit.clock_mode_24h); + } + break; + default: + break; + } + + return true; +} + +void thermistor_logging_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; +} diff --git a/movement/watch_faces/thermistor/thermistor_logging_face.h b/movement/watch_faces/thermistor/thermistor_logging_face.h new file mode 100644 index 00000000..43d441be --- /dev/null +++ b/movement/watch_faces/thermistor/thermistor_logging_face.h @@ -0,0 +1,34 @@ +#ifndef THERMISTOR_LOGGING_FACE_H_ +#define THERMISTOR_LOGGING_FACE_H_ + +#include "movement.h" +#include "watch.h" + +#define THERMISTOR_LOGGING_NUM_DATA_POINTS (36) + +typedef struct { + watch_date_time timestamp; + float temperature_c; +} thermistor_logger_data_point_t; + +typedef struct { + uint8_t display_index; // the index we are displaying on screen + uint8_t ts_ticks; // when the user taps the LIGHT button, we show the timestamp for a few ticks. + int32_t data_points; // the absolute number of data points logged + thermistor_logger_data_point_t data[THERMISTOR_LOGGING_NUM_DATA_POINTS]; +} thermistor_logger_state_t; + +void thermistor_logging_face_setup(movement_settings_t *settings, void ** context_ptr); +void thermistor_logging_face_activate(movement_settings_t *settings, void *context); +bool thermistor_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void thermistor_logging_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t thermistor_logging_face = { + thermistor_logging_face_setup, + thermistor_logging_face_activate, + thermistor_logging_face_loop, + thermistor_logging_face_resign, + NULL +}; + +#endif // THERMISTOR_LOGGING_FACE_H_ -- cgit v1.2.3 From ee1b3c8780c5573a11cdd21620243ef4b0bd8488 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 23 Oct 2021 16:44:20 -0400 Subject: fix typo --- boards/OSO-FEAL-A1-00/pins.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/OSO-FEAL-A1-00/pins.h b/boards/OSO-FEAL-A1-00/pins.h index 47d925cc..c860911f 100644 --- a/boards/OSO-FEAL-A1-00/pins.h +++ b/boards/OSO-FEAL-A1-00/pins.h @@ -65,7 +65,7 @@ // This board uses a slightly different pin mapping from the standard watch, and it's not enough to // just declare the pins. We also have to set the LCD Pin Enable register with the SLCD pins we're // using. These numbers are not port/pin numbers, but the "SLCD/LP[x]" numbers in the pinmux table. -// If not defined in pins.h, the LCD drover will fall back to the pin mapping in hpl_slcd_config.h. +// If not defined in pins.h, the LCD driver will fall back to the pin mapping in hpl_slcd_config.h. // LPENL is for pins SLCD/LP[0..31]. #define CONF_SLCD_LPENL (\ (uint32_t)1 << 0 | \ -- cgit v1.2.3 From 8475ffcd7aaebcbf17c7188ef96ce01a9730e9b3 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 23 Oct 2021 17:55:19 -0400 Subject: movement: first crack at background tasks API --- movement/movement.c | 31 +++++++++++++++++----- movement/movement.h | 3 +++ .../thermistor/thermistor_logging_face.c | 17 +++++++----- .../thermistor/thermistor_logging_face.h | 3 ++- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index e1ab322f..5622f17f 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -23,6 +23,18 @@ static inline void _movement_reset_inactivity_countdown() { movement_state.timeout_ticks = movement_timeout_inactivity_deadlines[movement_state.settings.bit.to_interval]; } +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... + if (watch_faces[i].wants_background_task != NULL && watch_faces[i].wants_background_task(&movement_state.settings, watch_face_contexts[i])) { + // ...we give it one. pretty straightforward! + movement_event_t background_event = { EVENT_BACKGROUND_TASK, 0 }; + watch_faces[i].loop(background_event, &movement_state.settings, watch_face_contexts[i]); + } + } + movement_state.needs_background_tasks_handled = false; +} + void movement_request_tick_frequency(uint8_t freq) { watch_rtc_disable_all_periodic_callbacks(); movement_state.subsecond = 0; @@ -68,10 +80,15 @@ void app_setup() { watch_face_contexts[i] = NULL; is_first_launch = false; } + + // set up the 1 minute alarm (for background tasks and low power updates) + watch_date_time alarm_time; + alarm_time.reg = 0; + alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 + watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); } if (movement_state.le_mode_ticks != -1) { watch_disable_extwake_interrupt(BTN_ALARM); - watch_rtc_disable_alarm_callback(); watch_enable_external_interrupts(); watch_register_interrupt_callback(BTN_MODE, cb_mode_btn_interrupt, INTERRUPT_TRIGGER_BOTH); @@ -131,13 +148,12 @@ bool app_loop() { event.event_type = EVENT_TIMEOUT; } + // handle background tasks, if the alarm handler told us we need to + if (movement_state.needs_background_tasks_handled) _movement_handle_background_tasks(); + // if we have timed out of our low energy mode countdown, enter low energy mode. if (movement_state.le_mode_ticks == 0) { movement_state.le_mode_ticks = -1; - watch_date_time alarm_time; - alarm_time.reg = 0; - alarm_time.unit.second = 59; // after a match, the alarm fires at the next rising edge of CLK_RTC_CNT, so 59 seconds lets us update at :00 - watch_rtc_register_alarm_callback(cb_alarm_fired, alarm_time, ALARM_MATCH_SS); watch_register_extwake_callback(BTN_ALARM, cb_alarm_btn_extwake, true); event.event_type = EVENT_NONE; event.subsecond = 0; @@ -145,6 +161,9 @@ bool app_loop() { // this is a little mini-runloop. // as long as le_mode_ticks is -1 (i.e. we are in low energy mode), we wake up here, update the screen, and go right back to sleep. while (movement_state.le_mode_ticks == -1) { + // we also have to handle background tasks here in the mini-runloop + if (movement_state.needs_background_tasks_handled) _movement_handle_background_tasks(); + event.event_type = EVENT_LOW_ENERGY_UPDATE; watch_faces[movement_state.current_watch_face].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_watch_face]); watch_enter_sleep_mode(); @@ -202,7 +221,7 @@ void cb_alarm_btn_extwake() { } void cb_alarm_fired() { - event.event_type = EVENT_LOW_ENERGY_UPDATE; + movement_state.needs_background_tasks_handled = true; } void cb_tick() { diff --git a/movement/movement.h b/movement/movement.h index e8bf9247..cb162b95 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -167,6 +167,9 @@ typedef struct { uint8_t mode_down_timestamp; uint8_t alarm_down_timestamp; + // background task handling + bool needs_background_tasks_handled; + // low energy mode countdown int32_t le_mode_ticks; diff --git a/movement/watch_faces/thermistor/thermistor_logging_face.c b/movement/watch_faces/thermistor/thermistor_logging_face.c index 1ff20483..5351ce88 100644 --- a/movement/watch_faces/thermistor/thermistor_logging_face.c +++ b/movement/watch_faces/thermistor/thermistor_logging_face.c @@ -63,7 +63,6 @@ void thermistor_logging_face_activate(movement_settings_t *settings, void *conte bool thermistor_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { thermistor_logger_state_t *logger_state = (thermistor_logger_state_t *)context; - watch_date_time date_time = watch_rtc_get_date_time(); switch (event.event_type) { case EVENT_TIMEOUT: movement_move_to_face(0); @@ -90,11 +89,9 @@ bool thermistor_logging_face_loop(movement_event_t event, movement_settings_t *s if (logger_state->ts_ticks && --logger_state->ts_ticks == 0) { _thermistor_logging_face_update_display(logger_state, settings->bit.use_imperial_units, settings->bit.clock_mode_24h); } - // this is just temporary for testing: log a data point every 30 seconds. - if (date_time.unit.second % 30 == 0 && !logger_state->ts_ticks) { - _thermistor_logging_face_log_data(logger_state); - _thermistor_logging_face_update_display(logger_state, settings->bit.use_imperial_units, settings->bit.clock_mode_24h); - } + break; + case EVENT_BACKGROUND_TASK: + _thermistor_logging_face_log_data(logger_state); break; default: break; @@ -107,3 +104,11 @@ void thermistor_logging_face_resign(movement_settings_t *settings, void *context (void) settings; (void) context; } + +bool thermistor_logging_face_wants_background_task(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + // this will get called at the top of each minute, so all we check is if we're at the top of the hour as well. + // if we are, we ask for a background task. + return watch_rtc_get_date_time().unit.minute == 0; +} diff --git a/movement/watch_faces/thermistor/thermistor_logging_face.h b/movement/watch_faces/thermistor/thermistor_logging_face.h index 43d441be..ece89396 100644 --- a/movement/watch_faces/thermistor/thermistor_logging_face.h +++ b/movement/watch_faces/thermistor/thermistor_logging_face.h @@ -22,13 +22,14 @@ void thermistor_logging_face_setup(movement_settings_t *settings, void ** contex void thermistor_logging_face_activate(movement_settings_t *settings, void *context); bool thermistor_logging_face_loop(movement_event_t event, movement_settings_t *settings, void *context); void thermistor_logging_face_resign(movement_settings_t *settings, void *context); +bool thermistor_logging_face_wants_background_task(movement_settings_t *settings, void *context); static const watch_face_t thermistor_logging_face = { thermistor_logging_face_setup, thermistor_logging_face_activate, thermistor_logging_face_loop, thermistor_logging_face_resign, - NULL + thermistor_logging_face_wants_background_task }; #endif // THERMISTOR_LOGGING_FACE_H_ -- cgit v1.2.3 From c8041627ee540aba886144b528a9020f0e41e8da Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sat, 23 Oct 2021 18:15:22 -0400 Subject: movement temperature face: only enable thermistor when reading data --- movement/watch_faces/thermistor/thermistor_readout_face.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/movement/watch_faces/thermistor/thermistor_readout_face.c b/movement/watch_faces/thermistor/thermistor_readout_face.c index 2a4ec3a1..5cee2e96 100644 --- a/movement/watch_faces/thermistor/thermistor_readout_face.c +++ b/movement/watch_faces/thermistor/thermistor_readout_face.c @@ -5,6 +5,7 @@ #include "watch.h" void _thermistor_readout_face_update_display(bool in_fahrenheit) { + thermistor_driver_enable(); float temperature_c = thermistor_driver_get_temperature(); char buf[14]; if (in_fahrenheit) { @@ -13,6 +14,7 @@ void _thermistor_readout_face_update_display(bool in_fahrenheit) { sprintf(buf, "%4.1f#C", temperature_c); } watch_display_string(buf, 4); + thermistor_driver_disable(); } void thermistor_readout_face_setup(movement_settings_t *settings, void ** context_ptr) { @@ -24,7 +26,6 @@ void thermistor_readout_face_activate(movement_settings_t *settings, void *conte (void) settings; (void) context; watch_display_string("TE", 0); - thermistor_driver_enable(); } bool thermistor_readout_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { @@ -69,5 +70,4 @@ bool thermistor_readout_face_loop(movement_event_t event, movement_settings_t *s void thermistor_readout_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; - thermistor_driver_disable(); } -- cgit v1.2.3 From badb4ba9090c6228738a555b82c988aafbe72fec Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 25 Oct 2021 14:52:15 -0400 Subject: new batch of sensor boards --- ...OSO-MISC-21-015 Temperature and Light Board.brd | 621 ++++++++ ...OSO-MISC-21-015 Temperature and Light Board.sch | 1090 ++++++++++++++ PCB/Sensor Boards/OSO-MISC-21-016 Power Test.brd | 543 +++++++ PCB/Sensor Boards/OSO-MISC-21-016 Power Test.sch | 1558 ++++++++++++++++++++ .../OSO-MISC-21-017 Sensor Watch Flash.brd | 576 ++++++++ .../OSO-MISC-21-017 Sensor Watch Flash.sch | 1324 +++++++++++++++++ .../OSO-MISC-21-018 Temperature Board.brd | 541 +++++++ .../OSO-MISC-21-018 Temperature Board.sch | 947 ++++++++++++ 8 files changed, 7200 insertions(+) create mode 100644 PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.brd create mode 100644 PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.sch create mode 100644 PCB/Sensor Boards/OSO-MISC-21-016 Power Test.brd create mode 100644 PCB/Sensor Boards/OSO-MISC-21-016 Power Test.sch create mode 100644 PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.brd create mode 100644 PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.sch create mode 100644 PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.brd create mode 100644 PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.sch diff --git a/PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.brd b/PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.brd new file mode 100644 index 00000000..03809c7f --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.brd @@ -0,0 +1,621 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +OSO-MISC-21-015 +Temp + Light + + + + +A0: Thermistor !EN +A2: Temp. Sense +A3: Phototrans. !EN +A4: Light Sense + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +</p> + + +<b>0603</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>OSH Park Design Rules</b> +<p> +Please make sure your boards conform to these design rules. +</p> +<p> +Note, that not all DRC settings must be set by the manufacturer. Several can be adjusted for the design, including those listed on our docs page here. +<a href="http://docs.oshpark.com/design-tools/eagle/design-rules-files/">Adjustable Settings</a> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.sch b/PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.sch new file mode 100644 index 00000000..e100f1f4 --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-015 Temperature and Light Board.sch @@ -0,0 +1,1090 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>Hiking Log FeatherWing.brd</b><p> +by exp-lbrs.ulp + + + + + + + + + + + + + + + + + + + + +>DRAWING_NAME +>LAST_DATE_TIME +>SHEET +Sheet: + +oddly +specific +objects +by joey castillo +cc-by-sa 4.0 + + + + +<b>FRAME</b><p> +DIN A4, landscape with location and doc. field + + + + + + + + + + + + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +</p> + + +0603-Mini +<p>Mini footprint for dense boards</p> + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b> 0402</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0402 MicroPitch<p> + + + + + +>NAME +>VALUE + + + + + +<b>0603</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + +<b>0805</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0805 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR 2512 (Metric 6432)</b> + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<p><b>Resistors</b></p> +<p>For new designs, use the packages preceded by an '_' character since they are more reliable:</p> +<p>The following footprints should be used on most boards:</p> +<ul> +<li><b>_0402</b> - Standard footprint for regular board layouts</li> +<li><b>_0603</b> - Standard footprint for regular board layouts</li> +<li><b>_0805</b> - Standard footprint for regular board layouts</li> +<li><b>_1206</b> - Standard footprint for regular board layouts</li> +</ul> +<p>For extremely tight-pitch boards where space is at a premium, the following 'micro-pitch' footprints can be used (smaller pads, no silkscreen outline, etc.):</p> +<ul> +<li><b>_0402MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0603MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0805MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_1206MP</b> - Micro-pitch footprint for very dense/compact boards</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Phototransistors 630nm 2-SMD, No Lead + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Supply Symbols</b><p> + GND, VCC, 0V, +5V, -5V, etc.<p> + Please keep in mind, that these devices are necessary for the + automatic wiring of the supply signals.<p> + The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> + In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> + <author>Created by librarian@cadsoft.de</author> + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-016 Power Test.brd b/PCB/Sensor Boards/OSO-MISC-21-016 Power Test.brd new file mode 100644 index 00000000..0960450d --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-016 Power Test.brd @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +OSO-MISC-21-016 +Power Tester + + + + +Must be only power +source to watch. +DO NOT USE ALONG +WITH A COIN CELL!!! + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Test Pins/Pads</b><p> +Cream on SMD OFF.<br> +new: Attribute TP_SIGNAL_NAME<br> +<author>Created by librarian@cadsoft.de</author> + + +<b>TEST PAD</b> + + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + + +TEST PAD + + + + + + + + + + + + + + + + + + + + + +<b>OSH Park Design Rules</b> +<p> +Please make sure your boards conform to these design rules. +</p> +<p> +Note, that not all DRC settings must be set by the manufacturer. Several can be adjusted for the design, including those listed on our docs page here. +<a href="http://docs.oshpark.com/design-tools/eagle/design-rules-files/">Adjustable Settings</a> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + +Since Version 8.3, EAGLE supports the association of 3D packages +with devices in libraries, schematics, and board files. Those 3D +packages will not be understood (or retained) with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-016 Power Test.sch b/PCB/Sensor Boards/OSO-MISC-21-016 Power Test.sch new file mode 100644 index 00000000..7ca85fbd --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-016 Power Test.sch @@ -0,0 +1,1558 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>Hiking Log FeatherWing.brd</b><p> +by exp-lbrs.ulp + + + + + + + + + + + + + + + + + + + + +>DRAWING_NAME +>LAST_DATE_TIME +>SHEET +Sheet: + +oddly +specific +objects +by joey castillo +cc-by-sa 4.0 + + + + +<b>FRAME</b><p> +DIN A4, landscape with location and doc. field + + + + + + + + + + + + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Supply Symbols</b><p> + GND, VCC, 0V, +5V, -5V, etc.<p> + Please keep in mind, that these devices are necessary for the + automatic wiring of the supply signals.<p> + The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> + In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> + <author>Created by librarian@cadsoft.de</author> + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + +<b>Test Pins/Pads</b><p> +Cream on SMD OFF.<br> +new: Attribute TP_SIGNAL_NAME<br> +<author>Created by librarian@cadsoft.de</author> + + +<b>TEST PAD</b> + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + +TEST PAD + + + + + + + + + + + +>NAME +>TP_SIGNAL_NAME + + + + + +<b>Test pad</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + +Since Version 8.3, EAGLE supports the association of 3D packages +with devices in libraries, schematics, and board files. Those 3D +packages will not be understood (or retained) with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.brd b/PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.brd new file mode 100644 index 00000000..28ebaf47 --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.brd @@ -0,0 +1,576 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +OSO-MISC-21-017 +SPI Flash Chip + + + + +A1: SPI Clock (SCK) +A2: Watch SDO (MOSI) +A3: Chip Select (CS) +A4: Watch SDI (MISO) + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>OSH Park Design Rules</b> +<p> +Please make sure your boards conform to these design rules. +</p> +<p> +Note, that not all DRC settings must be set by the manufacturer. Several can be adjusted for the design, including those listed on our docs page here. +<a href="http://docs.oshpark.com/design-tools/eagle/design-rules-files/">Adjustable Settings</a> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.sch b/PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.sch new file mode 100644 index 00000000..c3fedd1f --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-017 Sensor Watch Flash.sch @@ -0,0 +1,1324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>Hiking Log FeatherWing.brd</b><p> +by exp-lbrs.ulp + + + + + + + + + + + + + + + + + + + + +>DRAWING_NAME +>LAST_DATE_TIME +>SHEET +Sheet: + +oddly +specific +objects +by joey castillo +cc-by-sa 4.0 + + + + +<b>FRAME</b><p> +DIN A4, landscape with location and doc. field + + + + + + + + + + + + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Supply Symbols</b><p> + GND, VCC, 0V, +5V, -5V, etc.<p> + Please keep in mind, that these devices are necessary for the + automatic wiring of the supply signals.<p> + The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> + In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> + <author>Created by librarian@cadsoft.de</author> + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + + + +0603-Mini +<p>Mini footprint for dense boards</p> + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b> 0402</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0402 MicroPitch<p> + + + + + +>NAME +>VALUE + + + + + +<b>0603</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + +<b>0805</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0805 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + +<b>Small Outline IC - 150mil Wide</b> + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + +<b>Small Outline IC - 208mil Wide</b> + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR 2512 (Metric 6432)</b> + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<p><b>Ceramic Capacitors</b></p> +<p>For new designs, use the packages preceded by an '_' character since they are more reliable:</p> +<p>The following footprints should be used on most boards:</p> +<ul> +<li><b>_0402</b> - Standard footprint for regular board layouts</li> +<li><b>_0603</b> - Standard footprint for regular board layouts</li> +<li><b>_0805</b> - Standard footprint for regular board layouts</li> +<li><b>_1206</b> - Standard footprint for regular board layouts</li> +</ul> +<p>For extremely tight-pitch boards where space is at a premium, the following 'micro-pitch' footprints can be used (smaller pads, no silkscreen outline, etc.):</p> +<ul> +<li><b>_0402MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0603MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0805MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_1206MP</b> - Micro-pitch footprint for very dense/compact boards</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>SOIC8 SPI Flash</b> +<p>Be careful with the size since SOIC8 flash comes in several 'widths'</p> +<p><b>SOIC8 150 mil</b> +<ul> +<li><b>M25P16</b> - 16Mbit (2Mbit x 8) Serial Flash (75MHz SPI Bus), Supply: 2.7-3.6V <br/><b>Digikey: </b> SOIC8 - M25P16-VMN6P-ND</li> +</ul> +</p> + +<p><b>SOIC8 208 mil</b> +<ul> +<li><b>W25Q16BVSSIG</b> - 16Mbit (2Mbit x 8) Serial Flash (104MHz SPI Bus), Supply: 2.7-3.6V <br/><b>Digikey: </b> SOIC8 - W25Q16BVSSIG-ND</li> +</ul> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p><b>Resistors</b></p> +<p>For new designs, use the packages preceded by an '_' character since they are more reliable:</p> +<p>The following footprints should be used on most boards:</p> +<ul> +<li><b>_0402</b> - Standard footprint for regular board layouts</li> +<li><b>_0603</b> - Standard footprint for regular board layouts</li> +<li><b>_0805</b> - Standard footprint for regular board layouts</li> +<li><b>_1206</b> - Standard footprint for regular board layouts</li> +</ul> +<p>For extremely tight-pitch boards where space is at a premium, the following 'micro-pitch' footprints can be used (smaller pads, no silkscreen outline, etc.):</p> +<ul> +<li><b>_0402MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0603MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0805MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_1206MP</b> - Micro-pitch footprint for very dense/compact boards</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.brd b/PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.brd new file mode 100644 index 00000000..24ed4ce9 --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.brd @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +OSO-MISC-21-018 +Simple Thermistor +Sensor Board + + + + +A0: Thermistor !EN +A2: Temp. Sense + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +</p> + + +<b>0603</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + +<b>OSH Park Design Rules</b> +<p> +Please make sure your boards conform to these design rules. +</p> +<p> +Note, that not all DRC settings must be set by the manufacturer. Several can be adjusted for the design, including those listed on our docs page here. +<a href="http://docs.oshpark.com/design-tools/eagle/design-rules-files/">Adjustable Settings</a> +</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + + diff --git a/PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.sch b/PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.sch new file mode 100644 index 00000000..030bf2b4 --- /dev/null +++ b/PCB/Sensor Boards/OSO-MISC-21-018 Temperature Board.sch @@ -0,0 +1,947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>Hiking Log FeatherWing.brd</b><p> +by exp-lbrs.ulp + + + + + + + + + + + + + + + + + + + + +>DRAWING_NAME +>LAST_DATE_TIME +>SHEET +Sheet: + +oddly +specific +objects +by joey castillo +cc-by-sa 4.0 + + + + +<b>FRAME</b><p> +DIN A4, landscape with location and doc. field + + + + + + + + + + + + + + +<b>https://componentsearchengine.com</b><p> +<author>Created by SamacSys</author> + + +<b>FH19C-9S-0.5SH(10)-1</b><br> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +</p> + + +0603-Mini +<p>Mini footprint for dense boards</p> + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b> 0402</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0402 MicroPitch<p> + + + + + +>NAME +>VALUE + + + + + +<b>0603</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0603 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + +<b>0805</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>0805 MicroPitch</b> + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR 2512 (Metric 6432)</b> + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<p><b>Resistors</b></p> +<p>For new designs, use the packages preceded by an '_' character since they are more reliable:</p> +<p>The following footprints should be used on most boards:</p> +<ul> +<li><b>_0402</b> - Standard footprint for regular board layouts</li> +<li><b>_0603</b> - Standard footprint for regular board layouts</li> +<li><b>_0805</b> - Standard footprint for regular board layouts</li> +<li><b>_1206</b> - Standard footprint for regular board layouts</li> +</ul> +<p>For extremely tight-pitch boards where space is at a premium, the following 'micro-pitch' footprints can be used (smaller pads, no silkscreen outline, etc.):</p> +<ul> +<li><b>_0402MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0603MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_0805MP</b> - Micro-pitch footprint for very dense/compact boards</li> +<li><b>_1206MP</b> - Micro-pitch footprint for very dense/compact boards</li> +</ul> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Supply Symbols</b><p> + GND, VCC, 0V, +5V, -5V, etc.<p> + Please keep in mind, that these devices are necessary for the + automatic wiring of the supply signals.<p> + The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> + In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> + <author>Created by librarian@cadsoft.de</author> + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + + -- cgit v1.2.3