diff --git a/Makefile b/Makefile index d5b47da0..1532bd29 100644 --- a/Makefile +++ b/Makefile @@ -29,9 +29,8 @@ INCLUDES += \ # Add your source files here. SRCS += \ - ./watch-library/hardware/watch/watch_buzzer.c \ ./watch-library/hardware/watch/watch_gpio.c \ - ./watch-library/hardware/watch/watch_led.c \ + ./watch-library/hardware/watch/watch_tcc.c \ ./app.c \ # Finally, leave this line at the bottom of the file. diff --git a/watch-library/hardware/watch/watch_led.c b/watch-library/hardware/watch/watch_led.c deleted file mode 100644 index 70ce3057..00000000 --- a/watch-library/hardware/watch/watch_led.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020 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_led.h" -#include "watch_private.h" -#include "tcc.h" - -void _watch_enable_tcc(void); - -void watch_enable_leds(void) { - if (!tcc_is_enabled(0)) { - _watch_enable_tcc(); - } -} - -void watch_disable_leds(void) { - _watch_disable_tcc(); -} - -void watch_set_led_color(uint8_t red, uint8_t green) { -#ifdef WATCH_BLUE_TCC_CHANNEL - watch_set_led_color_rgb(red, green, 0); -#else - watch_set_led_color_rgb(red, green, green); -#endif -} - -void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) { - if (tcc_is_enabled(0)) { - uint32_t period = tcc_get_period(0); - tcc_set_cc(0, (WATCH_RED_TCC_CHANNEL) % 4, ((period * (uint32_t)red * 1000ull) / 255000ull), true); -#ifdef WATCH_GREEN_TCC_CHANNEL - tcc_set_cc(0, (WATCH_GREEN_TCC_CHANNEL) % 4, ((period * (uint32_t)green * 1000ull) / 255000ull), true); -#else - (void) green; // silence warning -#endif -#ifdef WATCH_BLUE_TCC_CHANNEL - tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, ((period * (uint32_t)blue * 1000ull) / 255000ull), true); -#else - (void) blue; // silence warning -#endif - } -} - -void watch_set_led_red(void) { - watch_set_led_color_rgb(255, 0, 0); -} - -void watch_set_led_green(void) { - watch_set_led_color_rgb(0, 255, 0); -} - -void watch_set_led_yellow(void) { - watch_set_led_color_rgb(255, 255, 0); -} - -void watch_set_led_off(void) { - watch_set_led_color_rgb(0, 0, 0); -} diff --git a/watch-library/hardware/watch/watch_buzzer.c b/watch-library/hardware/watch/watch_tcc.c similarity index 78% rename from watch-library/hardware/watch/watch_buzzer.c rename to watch-library/hardware/watch/watch_tcc.c index f762dd2b..630f95d0 100644 --- a/watch-library/hardware/watch/watch_buzzer.c +++ b/watch-library/hardware/watch/watch_tcc.c @@ -22,12 +22,12 @@ * SOFTWARE. */ -#include "watch_buzzer.h" -#include "watch_private.h" +#include "watch_tcc.h" #include "delay.h" #include "tcc.h" void _watch_enable_tcc(void); +void _watch_disable_tcc(void); bool watch_is_buzzer_or_led_enabled(void){ return tcc_is_enabled(0); @@ -139,3 +139,54 @@ void _watch_disable_tcc(void) { #endif tcc_disable(0); } + +void watch_enable_leds(void) { + if (!tcc_is_enabled(0)) { + _watch_enable_tcc(); + } +} + +void watch_disable_leds(void) { + _watch_disable_tcc(); +} + +void watch_set_led_color(uint8_t red, uint8_t green) { +#ifdef WATCH_BLUE_TCC_CHANNEL + watch_set_led_color_rgb(red, green, 0); +#else + watch_set_led_color_rgb(red, green, green); +#endif +} + +void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) { + if (tcc_is_enabled(0)) { + uint32_t period = tcc_get_period(0); + tcc_set_cc(0, (WATCH_RED_TCC_CHANNEL) % 4, ((period * (uint32_t)red * 1000ull) / 255000ull), true); +#ifdef WATCH_GREEN_TCC_CHANNEL + tcc_set_cc(0, (WATCH_GREEN_TCC_CHANNEL) % 4, ((period * (uint32_t)green * 1000ull) / 255000ull), true); +#else + (void) green; // silence warning +#endif +#ifdef WATCH_BLUE_TCC_CHANNEL + tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, ((period * (uint32_t)blue * 1000ull) / 255000ull), true); +#else + (void) blue; // silence warning +#endif + } +} + +void watch_set_led_red(void) { + watch_set_led_color_rgb(255, 0, 0); +} + +void watch_set_led_green(void) { + watch_set_led_color_rgb(0, 255, 0); +} + +void watch_set_led_yellow(void) { + watch_set_led_color_rgb(255, 255, 0); +} + +void watch_set_led_off(void) { + watch_set_led_color_rgb(0, 0, 0); +} diff --git a/watch-library/shared/watch/watch.h b/watch-library/shared/watch/watch.h index d2bdeba0..10d9c474 100644 --- a/watch-library/shared/watch/watch.h +++ b/watch-library/shared/watch/watch.h @@ -44,8 +44,8 @@ - @ref slcd - 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. - @ref buttons - This section covers functions related to the three buttons: Light, Mode and Alarm. - - @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 tcc - This section covers functions related to the LED and piezo buzzer, which are controlled by the + SAM L22's Timer Counter for Control, or TCC peripheral. - @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 five analog-capable pins on the 9-pin connector. - @ref gpio - This section covers functions related to general-purpose input and output signals. @@ -60,8 +60,7 @@ // #include "watch_rtc.h" // #include "watch_slcd.h" // #include "watch_extint.h" -#include "watch_led.h" -#include "watch_buzzer.h" +#include "watch_tcc.h" // #include "watch_adc.h" #include "watch_gpio.h" // #include "watch_i2c.h" diff --git a/watch-library/shared/watch/watch_led.h b/watch-library/shared/watch/watch_led.h deleted file mode 100644 index 134803a8..00000000 --- a/watch-library/shared/watch/watch_led.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020 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_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- - * hungry. The green LED, at full power, consumes more power than the whole chip in active mode, - * and the red LED consumes about twelve times as much power! The LED's should thus be used only - * sparingly in order to preserve battery life. - * @note Some watches use a red/blue LED instead of a red/green LED. You will be able to determine this - * easily when you double tap the reset button: if the pulsing bootloader LED is red, you have a - * red/green edition; if it is blue, you have a red/blue edition. For red/blue watches, build your - * project with the command `make COLOR=BLUE`, and the watch library will automatically swap the pins - * so that watch_set_led_red sets the red LED, and watch_set_led_green sets the blue one. - */ -/// @{ -/** @brief Enables the bi-color LED. - * @note The TCC peripheral that drives the LEDs does not run in STANDBY mode — but the outputs do! This - * means that if you set either red, green or both LEDs to full power, they will shine even when - * your app is asleep. If, however, you set a custom color using watch_set_led_color, the color will - * not display correctly in STANDBY mode. You will need to keep your app running while the LED is on. - */ -void watch_enable_leds(void); - -/** @brief Disables the LEDs. - * @note This method will also disable the buzzer, since the buzzer and LED both make use of the same - * peripheral to drive their PWM behavior. - */ -void watch_disable_leds(void); - -/** @brief Sets the LED to a custom color by modulating each output's duty cycle. - * @param red The red value from 0-255. - * @param green The green value from 0-255. If your watch has a red/blue LED, this will be the blue value. - * @note If you are displaying a custom color, you will need to prevent your app from going to sleep - * while the LED is on; otherwise, the color will not display correctly. You can do this by - * returning false in your app_loop method. - */ -void watch_set_led_color(uint8_t red, uint8_t green); - -/** @brief On boards with an RGB LED, sets the LED to a custom color by modulating each output's duty cycle. - * @param red The red value from 0-255. - * @param green The green value from 0-255. - * @param blue The blue value from 0-255. - * @note If you are displaying a custom color, you will need to prevent your app from going to sleep - * while the LED is on; otherwise, the color will not display correctly. You can do this by - * returning false in your app_loop method. - */ -void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue); - -/** @brief Sets the red LED to full brightness, and turns the green LED off. - * @details Of the two LED's in the RG bi-color LED, the red LED is the less power-efficient one (~4.5 mA). - */ -void watch_set_led_red(void); - -/** @brief Sets the green LED to full brightness, and turns the red LED off. - * @details Of the two LED's in the RG bi-color LED, the green LED is the more power-efficient one (~0.44 mA). - * @note If your watch has a red/blue LED, this method will set the LED to blue. - */ -void watch_set_led_green(void); - -/** @brief Sets both red and green LEDs to full brightness. - * @details The total current draw between the two LED's in this mode will be ~5 mA, which is more than the - * watch draws in any other mode. Take care not to drain the battery. - * @note If your watch has a red/blue LED, this method will set the LED to pink. - */ -void watch_set_led_yellow(void); - -/** @brief Turns both the red and the green LEDs off. */ -void watch_set_led_off(void); - -/// @} -#endif diff --git a/watch-library/shared/watch/watch_buzzer.h b/watch-library/shared/watch/watch_tcc.h similarity index 70% rename from watch-library/shared/watch/watch_buzzer.h rename to watch-library/shared/watch/watch_tcc.h index 89dc3954..0443b425 100644 --- a/watch-library/shared/watch/watch_buzzer.h +++ b/watch-library/shared/watch/watch_tcc.h @@ -190,5 +190,72 @@ void watch_buzzer_abort_sequence(void); void TC3_Handler(void); #endif +/** @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- + * hungry. The green LED, at full power, consumes more power than the whole chip in active mode, + * and the red LED consumes about twelve times as much power! The LED's should thus be used only + * sparingly in order to preserve battery life. + * @note Some watches use a red/blue LED instead of a red/green LED. You will be able to determine this + * easily when you double tap the reset button: if the pulsing bootloader LED is red, you have a + * red/green edition; if it is blue, you have a red/blue edition. For red/blue watches, build your + * project with the command `make COLOR=BLUE`, and the watch library will automatically swap the pins + * so that watch_set_led_red sets the red LED, and watch_set_led_green sets the blue one. + */ +/// @{ +/** @brief Enables the bi-color LED. + * @note The TCC peripheral that drives the LEDs does not run in STANDBY mode — but the outputs do! This + * means that if you set either red, green or both LEDs to full power, they will shine even when + * your app is asleep. If, however, you set a custom color using watch_set_led_color, the color will + * not display correctly in STANDBY mode. You will need to keep your app running while the LED is on. + */ +void watch_enable_leds(void); + +/** @brief Disables the LEDs. + * @note This method will also disable the buzzer, since the buzzer and LED both make use of the same + * peripheral to drive their PWM behavior. + */ +void watch_disable_leds(void); + +/** @brief Sets the LED to a custom color by modulating each output's duty cycle. + * @param red The red value from 0-255. + * @param green The green value from 0-255. If your watch has a red/blue LED, this will be the blue value. + * @note If you are displaying a custom color, you will need to prevent your app from going to sleep + * while the LED is on; otherwise, the color will not display correctly. You can do this by + * returning false in your app_loop method. + */ +void watch_set_led_color(uint8_t red, uint8_t green); + +/** @brief On boards with an RGB LED, sets the LED to a custom color by modulating each output's duty cycle. + * @param red The red value from 0-255. + * @param green The green value from 0-255. + * @param blue The blue value from 0-255. + * @note If you are displaying a custom color, you will need to prevent your app from going to sleep + * while the LED is on; otherwise, the color will not display correctly. You can do this by + * returning false in your app_loop method. + */ +void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue); + +/** @brief Sets the red LED to full brightness, and turns the green LED off. + * @details Of the two LED's in the RG bi-color LED, the red LED is the less power-efficient one (~4.5 mA). + */ +void watch_set_led_red(void); + +/** @brief Sets the green LED to full brightness, and turns the red LED off. + * @details Of the two LED's in the RG bi-color LED, the green LED is the more power-efficient one (~0.44 mA). + * @note If your watch has a red/blue LED, this method will set the LED to blue. + */ +void watch_set_led_green(void); + +/** @brief Sets both red and green LEDs to full brightness. + * @details The total current draw between the two LED's in this mode will be ~5 mA, which is more than the + * watch draws in any other mode. Take care not to drain the battery. + * @note If your watch has a red/blue LED, this method will set the LED to pink. + */ +void watch_set_led_yellow(void); + +/** @brief Turns both the red and the green LEDs off. */ +void watch_set_led_off(void); + /// @} #endif diff --git a/watch-library/simulator/watch/watch_led.c b/watch-library/simulator/watch/watch_led.c deleted file mode 100644 index 584611fe..00000000 --- a/watch-library/simulator/watch/watch_led.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020 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_led.h" - -#include - -void watch_enable_leds(void) {} - -void watch_disable_leds(void) {} - -void watch_set_led_color(uint8_t red, uint8_t green) { - EM_ASM({ - // the watch svg contains an feColorMatrix filter with id ledcolor - // and a green svg gradient that mimics the led being on - // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feColorMatrix - // this changes the color of the gradient to match the red+green combination - let filter = document.getElementById("ledcolor"); - let color_matrix = filter.children[0].values.baseVal; - color_matrix[1].value = $0 / 255; // red value - color_matrix[6].value = $1 / 255; // green value - document.getElementById('light').style.opacity = Math.min(255, $0 + $1) / 255; - }, red, green); -} - -void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) { - (void) blue; - watch_set_led_color(red, green); -} - -void watch_set_led_red(void) { - watch_set_led_color(255, 0); -} - -void watch_set_led_green(void) { - watch_set_led_color(0, 255); -} - -void watch_set_led_yellow(void) { - watch_set_led_color(255, 255); -} - -void watch_set_led_off(void) { - watch_set_led_color(0, 0); -} diff --git a/watch-library/simulator/watch/watch_buzzer.c b/watch-library/simulator/watch/watch_tcc.c similarity index 83% rename from watch-library/simulator/watch/watch_buzzer.c rename to watch-library/simulator/watch/watch_tcc.c index c5d9d7ee..77c06401 100644 --- a/watch-library/simulator/watch/watch_buzzer.c +++ b/watch-library/simulator/watch/watch_tcc.c @@ -181,3 +181,42 @@ void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) { main_loop_sleep(duration_ms); watch_set_buzzer_off(); } + +void watch_enable_leds(void) {} + +void watch_disable_leds(void) {} + +void watch_set_led_color(uint8_t red, uint8_t green) { + EM_ASM({ + // the watch svg contains an feColorMatrix filter with id ledcolor + // and a green svg gradient that mimics the led being on + // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feColorMatrix + // this changes the color of the gradient to match the red+green combination + let filter = document.getElementById("ledcolor"); + let color_matrix = filter.children[0].values.baseVal; + color_matrix[1].value = $0 / 255; // red value + color_matrix[6].value = $1 / 255; // green value + document.getElementById('light').style.opacity = Math.min(255, $0 + $1) / 255; + }, red, green); +} + +void watch_set_led_color_rgb(uint8_t red, uint8_t green, uint8_t blue) { + (void) blue; + watch_set_led_color(red, green); +} + +void watch_set_led_red(void) { + watch_set_led_color(255, 0); +} + +void watch_set_led_green(void) { + watch_set_led_color(0, 255); +} + +void watch_set_led_yellow(void) { + watch_set_led_color(255, 255); +} + +void watch_set_led_off(void) { + watch_set_led_color(0, 0); +}