]> git.earman.xyz Git - sensor-watch.git/commitdiff
consolidate buzzer and LED into TCC file
authorjoeycastillo <joeycastillo@utexas.edu>
Wed, 18 Sep 2024 18:53:46 +0000 (14:53 -0400)
committerjoeycastillo <joeycastillo@utexas.edu>
Wed, 18 Sep 2024 18:53:46 +0000 (14:53 -0400)
Makefile
watch-library/hardware/watch/watch_buzzer.c [deleted file]
watch-library/hardware/watch/watch_led.c [deleted file]
watch-library/hardware/watch/watch_tcc.c [new file with mode: 0644]
watch-library/shared/watch/watch.h
watch-library/shared/watch/watch_buzzer.h [deleted file]
watch-library/shared/watch/watch_led.h [deleted file]
watch-library/shared/watch/watch_tcc.h [new file with mode: 0644]
watch-library/simulator/watch/watch_buzzer.c [deleted file]
watch-library/simulator/watch/watch_led.c [deleted file]
watch-library/simulator/watch/watch_tcc.c [new file with mode: 0644]

index d5b47da0c9aa2e69590a2f0e1278c9281a7a73e0..1532bd2982320b01b931720ee54f433b7fd89bc7 100644 (file)
--- 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_buzzer.c b/watch-library/hardware/watch/watch_buzzer.c
deleted file mode 100644 (file)
index f762dd2..0000000
+++ /dev/null
@@ -1,141 +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_buzzer.h"
-#include "watch_private.h"
-#include "delay.h"
-#include "tcc.h"
-
-void _watch_enable_tcc(void);
-
-bool watch_is_buzzer_or_led_enabled(void){
-    return tcc_is_enabled(0);
-}
-
-inline void watch_enable_buzzer(void) {
-    if (!tcc_is_enabled(0)) {
-        _watch_enable_tcc();
-    }
-}
-
-inline void watch_set_buzzer_period(uint32_t period) {
-    tcc_set_period(0, period, true);
-    tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, period / 2, true);
-}
-
-void watch_disable_buzzer(void) {
-    _watch_disable_tcc();
-}
-
-inline void watch_set_buzzer_on(void) {
-    HAL_GPIO_BUZZER_out();
-    HAL_GPIO_BUZZER_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
-}
-
-inline void watch_set_buzzer_off(void) {
-    HAL_GPIO_BUZZER_pmuxdis();
-    HAL_GPIO_BUZZER_off();
-}
-
-void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) {
-    if (note == BUZZER_NOTE_REST) {
-        watch_set_buzzer_off();
-    } else {
-        watch_set_buzzer_period(NotePeriods[note]);
-        watch_set_buzzer_on();
-    }
-    delay_ms(duration_ms);
-    watch_set_buzzer_off();
-}
-
-void _watch_enable_tcc(void) {
-    // set up the TCC with a 1 MHz clock, but there's a trick:
-    if (USB->DEVICE.CTRLA.bit.ENABLE) {
-        // if USB is enabled, we are running an 8 MHz clock, so we divide by 8.
-        tcc_init(0, GENERIC_CLOCK_0, TCC_PRESCALER_DIV8);
-    } else {
-        // otherwise it's 4 Mhz and we divide by 4.
-        tcc_init(0, GENERIC_CLOCK_0, TCC_PRESCALER_DIV4);
-    }
-    // We're going to use normal PWM mode, which means period is controlled by PER, and duty cycle is controlled by
-    // each compare channel's value:
-    //  * Buzzer tones are set by setting PER to the desired period for a given frequency, and CC[1] to half of that
-    //    period (i.e. a square wave with a 50% duty cycle).
-    //  * LEDs on CC[0] CC[2] and CC[3] can be set to any value from 0 (off) to PER (fully on).
-    tcc_set_wavegen(0, TCC_WAVEGEN_NORMAL_PWM);
-#ifdef WATCH_INVERT_LED_POLARITY
-    // invert all channels, we'll flip the buzzer back in just a moment.
-    // this is easier than writing a maze of #ifdefs.
-    tcc_set_channel_polarity(0, 4, TCC_CHANNEL_POLARITY_INVERTED);
-    tcc_set_channel_polarity(0, 5, TCC_CHANNEL_POLARITY_INVERTED);
-    tcc_set_channel_polarity(0, 6, TCC_CHANNEL_POLARITY_INVERTED);
-    tcc_set_channel_polarity(0, 7, TCC_CHANNEL_POLARITY_INVERTED);
-#endif // WATCH_INVERT_LED_POLARITY
-    tcc_set_channel_polarity(0, WATCH_BUZZER_TCC_CHANNEL, TCC_CHANNEL_POLARITY_NORMAL);
-
-    // Set the period to 1 kHz to start.
-    tcc_set_period(0, 1000, false);
-
-    // Set the duty cycle of all pins to 0: LED's off, buzzer not buzzing.
-    tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, 0, false);
-    tcc_set_cc(0, (WATCH_RED_TCC_CHANNEL) % 4, 0, false);
-#ifdef WATCH_GREEN_TCC_CHANNEL
-    tcc_set_cc(0, (WATCH_GREEN_TCC_CHANNEL) % 4, 0, false);
-#endif
-#ifdef WATCH_BLUE_TCC_CHANNEL
-    tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, 0, false);
-#endif
-
-    // enable LED PWM pins (the LED driver assumes if the TCC is on, the pins are enabled)
-    HAL_GPIO_RED_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
-    HAL_GPIO_RED_out();
-#ifdef WATCH_GREEN_TCC_CHANNEL
-    HAL_GPIO_GREEN_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
-    HAL_GPIO_GREEN_out();
-#endif
-#ifdef WATCH_BLUE_TCC_CHANNEL
-    HAL_GPIO_BLUE_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
-    HAL_GPIO_BLUE_out();
-#endif
-
-    // Enable the TCC
-    tcc_enable(0);
-}
-
-void _watch_disable_tcc(void) {
-    // disable all PWM pins
-    HAL_GPIO_BUZZER_pmuxdis();
-    HAL_GPIO_BUZZER_off();
-    HAL_GPIO_RED_pmuxdis();
-    HAL_GPIO_RED_off();
-#ifdef WATCH_GREEN_TCC_CHANNEL
-    HAL_GPIO_GREEN_pmuxdis();
-    HAL_GPIO_GREEN_off();
-#endif
-#ifdef WATCH_BLUE_TCC_CHANNEL
-    HAL_GPIO_BLUE_pmuxdis();
-    HAL_GPIO_BLUE_off();
-#endif
-    tcc_disable(0);
-}
diff --git a/watch-library/hardware/watch/watch_led.c b/watch-library/hardware/watch/watch_led.c
deleted file mode 100644 (file)
index 70ce305..0000000
+++ /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_tcc.c b/watch-library/hardware/watch/watch_tcc.c
new file mode 100644 (file)
index 0000000..630f95d
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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_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);
+}
+
+inline void watch_enable_buzzer(void) {
+    if (!tcc_is_enabled(0)) {
+        _watch_enable_tcc();
+    }
+}
+
+inline void watch_set_buzzer_period(uint32_t period) {
+    tcc_set_period(0, period, true);
+    tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, period / 2, true);
+}
+
+void watch_disable_buzzer(void) {
+    _watch_disable_tcc();
+}
+
+inline void watch_set_buzzer_on(void) {
+    HAL_GPIO_BUZZER_out();
+    HAL_GPIO_BUZZER_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
+}
+
+inline void watch_set_buzzer_off(void) {
+    HAL_GPIO_BUZZER_pmuxdis();
+    HAL_GPIO_BUZZER_off();
+}
+
+void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) {
+    if (note == BUZZER_NOTE_REST) {
+        watch_set_buzzer_off();
+    } else {
+        watch_set_buzzer_period(NotePeriods[note]);
+        watch_set_buzzer_on();
+    }
+    delay_ms(duration_ms);
+    watch_set_buzzer_off();
+}
+
+void _watch_enable_tcc(void) {
+    // set up the TCC with a 1 MHz clock, but there's a trick:
+    if (USB->DEVICE.CTRLA.bit.ENABLE) {
+        // if USB is enabled, we are running an 8 MHz clock, so we divide by 8.
+        tcc_init(0, GENERIC_CLOCK_0, TCC_PRESCALER_DIV8);
+    } else {
+        // otherwise it's 4 Mhz and we divide by 4.
+        tcc_init(0, GENERIC_CLOCK_0, TCC_PRESCALER_DIV4);
+    }
+    // We're going to use normal PWM mode, which means period is controlled by PER, and duty cycle is controlled by
+    // each compare channel's value:
+    //  * Buzzer tones are set by setting PER to the desired period for a given frequency, and CC[1] to half of that
+    //    period (i.e. a square wave with a 50% duty cycle).
+    //  * LEDs on CC[0] CC[2] and CC[3] can be set to any value from 0 (off) to PER (fully on).
+    tcc_set_wavegen(0, TCC_WAVEGEN_NORMAL_PWM);
+#ifdef WATCH_INVERT_LED_POLARITY
+    // invert all channels, we'll flip the buzzer back in just a moment.
+    // this is easier than writing a maze of #ifdefs.
+    tcc_set_channel_polarity(0, 4, TCC_CHANNEL_POLARITY_INVERTED);
+    tcc_set_channel_polarity(0, 5, TCC_CHANNEL_POLARITY_INVERTED);
+    tcc_set_channel_polarity(0, 6, TCC_CHANNEL_POLARITY_INVERTED);
+    tcc_set_channel_polarity(0, 7, TCC_CHANNEL_POLARITY_INVERTED);
+#endif // WATCH_INVERT_LED_POLARITY
+    tcc_set_channel_polarity(0, WATCH_BUZZER_TCC_CHANNEL, TCC_CHANNEL_POLARITY_NORMAL);
+
+    // Set the period to 1 kHz to start.
+    tcc_set_period(0, 1000, false);
+
+    // Set the duty cycle of all pins to 0: LED's off, buzzer not buzzing.
+    tcc_set_cc(0, (WATCH_BUZZER_TCC_CHANNEL) % 4, 0, false);
+    tcc_set_cc(0, (WATCH_RED_TCC_CHANNEL) % 4, 0, false);
+#ifdef WATCH_GREEN_TCC_CHANNEL
+    tcc_set_cc(0, (WATCH_GREEN_TCC_CHANNEL) % 4, 0, false);
+#endif
+#ifdef WATCH_BLUE_TCC_CHANNEL
+    tcc_set_cc(0, (WATCH_BLUE_TCC_CHANNEL) % 4, 0, false);
+#endif
+
+    // enable LED PWM pins (the LED driver assumes if the TCC is on, the pins are enabled)
+    HAL_GPIO_RED_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
+    HAL_GPIO_RED_out();
+#ifdef WATCH_GREEN_TCC_CHANNEL
+    HAL_GPIO_GREEN_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
+    HAL_GPIO_GREEN_out();
+#endif
+#ifdef WATCH_BLUE_TCC_CHANNEL
+    HAL_GPIO_BLUE_pmuxen(HAL_GPIO_PMUX_TCC_ALT);
+    HAL_GPIO_BLUE_out();
+#endif
+
+    // Enable the TCC
+    tcc_enable(0);
+}
+
+void _watch_disable_tcc(void) {
+    // disable all PWM pins
+    HAL_GPIO_BUZZER_pmuxdis();
+    HAL_GPIO_BUZZER_off();
+    HAL_GPIO_RED_pmuxdis();
+    HAL_GPIO_RED_off();
+#ifdef WATCH_GREEN_TCC_CHANNEL
+    HAL_GPIO_GREEN_pmuxdis();
+    HAL_GPIO_GREEN_off();
+#endif
+#ifdef WATCH_BLUE_TCC_CHANNEL
+    HAL_GPIO_BLUE_pmuxdis();
+    HAL_GPIO_BLUE_off();
+#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);
+}
index d2bdeba03e32f6f01303e6836f7c1a860cfa6558..10d9c4745bcdddd761d02359df75e468eeec41d2 100644 (file)
@@ -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_buzzer.h b/watch-library/shared/watch/watch_buzzer.h
deleted file mode 100644 (file)
index 89dc395..0000000
+++ /dev/null
@@ -1,194 +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_BUZZER_H_INCLUDED
-#define _WATCH_BUZZER_H_INCLUDED
-////< @file watch_buzzer.h
-
-#include "watch.h"
-
-/** @brief Returns true if either the buzzer or the LED driver is enabled.
-  * @details Both the buzzer and the LED use the TCC peripheral to drive their behavior. This function returns true if that
-  *          peripheral is enabled. You can use this function to determine whether you need to call the watch_disable_leds or
-  *          or watch_enable_buzzer functions before using these peripherals.
-  */
-bool watch_is_buzzer_or_led_enabled(void);
-
-/** @addtogroup tcc Buzzer and LED Control (via the TCC peripheral)
-  * @brief This section covers functions related to the piezo buzzer embedded in the F-91W's back plate.
-  */
-/// @{
-/** @brief Enables the TCC peripheral, which drives the buzzer.
-  */
-void watch_enable_buzzer(void);
-
-/** @brief Sets the period of the buzzer.
-  * @param period The period of a single cycle for the TCC peripheral. You can determine the period for
-  *               a desired frequency with the following formula: period = 1000000 / freq
-  */
-void watch_set_buzzer_period(uint32_t period);
-
-/** @brief Disables the TCC peripheral that drives the buzzer.
-  * @note If you are using PWM to set custom LED colors, this method will also disable the LED PWM driver,
-  *       since the buzzer and LED both make use of the same peripheral to drive their PWM behavior.
-  */
-void watch_disable_buzzer(void);
-
-/** @brief Turns the buzzer output on. It will emit a continuous sound at the given frequency.
-  * @note The TCC peripheral that drives the buzzer does not run in standby mode; if you wish for buzzer
-  *       output to continue, you should prevent your app from going to sleep.
-  */
-void watch_set_buzzer_on(void);
-
-/** @brief Turns the buzzer output off.
-  */
-void watch_set_buzzer_off(void);
-
-/// @brief 87 notes for use with watch_buzzer_play_note
-typedef enum BuzzerNote {
-    BUZZER_NOTE_A1,              ///< 55.00 Hz
-    BUZZER_NOTE_A1SHARP_B1FLAT,  ///< 58.27 Hz
-    BUZZER_NOTE_B1,              ///< 61.74 Hz
-    BUZZER_NOTE_C2,              ///< 65.41 Hz
-    BUZZER_NOTE_C2SHARP_D2FLAT,  ///< 69.30 Hz
-    BUZZER_NOTE_D2,              ///< 73.42 Hz
-    BUZZER_NOTE_D2SHARP_E2FLAT,  ///< 77.78 Hz
-    BUZZER_NOTE_E2,              ///< 82.41 Hz
-    BUZZER_NOTE_F2,              ///< 87.31 Hz
-    BUZZER_NOTE_F2SHARP_G2FLAT,  ///< 92.50 Hz
-    BUZZER_NOTE_G2,              ///< 98.00 Hz
-    BUZZER_NOTE_G2SHARP_A2FLAT,  ///< 103.83 Hz
-    BUZZER_NOTE_A2,              ///< 110.00 Hz
-    BUZZER_NOTE_A2SHARP_B2FLAT,  ///< 116.54 Hz
-    BUZZER_NOTE_B2,              ///< 123.47 Hz
-    BUZZER_NOTE_C3,              ///< 130.81 Hz
-    BUZZER_NOTE_C3SHARP_D3FLAT,  ///< 138.59 Hz
-    BUZZER_NOTE_D3,              ///< 146.83 Hz
-    BUZZER_NOTE_D3SHARP_E3FLAT,  ///< 155.56 Hz
-    BUZZER_NOTE_E3,              ///< 164.81 Hz
-    BUZZER_NOTE_F3,              ///< 174.61 Hz
-    BUZZER_NOTE_F3SHARP_G3FLAT,  ///< 185.00 Hz
-    BUZZER_NOTE_G3,              ///< 196.00 Hz
-    BUZZER_NOTE_G3SHARP_A3FLAT,  ///< 207.65 Hz
-    BUZZER_NOTE_A3,              ///< 220.00 Hz
-    BUZZER_NOTE_A3SHARP_B3FLAT,  ///< 233.08 Hz
-    BUZZER_NOTE_B3,              ///< 246.94 Hz
-    BUZZER_NOTE_C4,              ///< 261.63 Hz
-    BUZZER_NOTE_C4SHARP_D4FLAT,  ///< 277.18 Hz
-    BUZZER_NOTE_D4,              ///< 293.66 Hz
-    BUZZER_NOTE_D4SHARP_E4FLAT,  ///< 311.13 Hz
-    BUZZER_NOTE_E4,              ///< 329.63 Hz
-    BUZZER_NOTE_F4,              ///< 349.23 Hz
-    BUZZER_NOTE_F4SHARP_G4FLAT,  ///< 369.99 Hz
-    BUZZER_NOTE_G4,              ///< 392.00 Hz
-    BUZZER_NOTE_G4SHARP_A4FLAT,  ///< 415.30 Hz
-    BUZZER_NOTE_A4,              ///< 440.00 Hz
-    BUZZER_NOTE_A4SHARP_B4FLAT,  ///< 466.16 Hz
-    BUZZER_NOTE_B4,              ///< 493.88 Hz
-    BUZZER_NOTE_C5,              ///< 523.25 Hz
-    BUZZER_NOTE_C5SHARP_D5FLAT,  ///< 554.37 Hz
-    BUZZER_NOTE_D5,              ///< 587.33 Hz
-    BUZZER_NOTE_D5SHARP_E5FLAT,  ///< 622.25 Hz
-    BUZZER_NOTE_E5,              ///< 659.25 Hz
-    BUZZER_NOTE_F5,              ///< 698.46 Hz
-    BUZZER_NOTE_F5SHARP_G5FLAT,  ///< 739.99 Hz
-    BUZZER_NOTE_G5,              ///< 783.99 Hz
-    BUZZER_NOTE_G5SHARP_A5FLAT,  ///< 830.61 Hz
-    BUZZER_NOTE_A5,              ///< 880.00 Hz
-    BUZZER_NOTE_A5SHARP_B5FLAT,  ///< 932.33 Hz
-    BUZZER_NOTE_B5,              ///< 987.77 Hz
-    BUZZER_NOTE_C6,              ///< 1046.50 Hz
-    BUZZER_NOTE_C6SHARP_D6FLAT,  ///< 1108.73 Hz
-    BUZZER_NOTE_D6,              ///< 1174.66 Hz
-    BUZZER_NOTE_D6SHARP_E6FLAT,  ///< 1244.51 Hz
-    BUZZER_NOTE_E6,              ///< 1318.51 Hz
-    BUZZER_NOTE_F6,              ///< 1396.91 Hz
-    BUZZER_NOTE_F6SHARP_G6FLAT,  ///< 1479.98 Hz
-    BUZZER_NOTE_G6,              ///< 1567.98 Hz
-    BUZZER_NOTE_G6SHARP_A6FLAT,  ///< 1661.22 Hz
-    BUZZER_NOTE_A6,              ///< 1760.00 Hz
-    BUZZER_NOTE_A6SHARP_B6FLAT,  ///< 1864.66 Hz
-    BUZZER_NOTE_B6,              ///< 1975.53 Hz
-    BUZZER_NOTE_C7,              ///< 2093.00 Hz
-    BUZZER_NOTE_C7SHARP_D7FLAT,  ///< 2217.46 Hz
-    BUZZER_NOTE_D7,              ///< 2349.32 Hz
-    BUZZER_NOTE_D7SHARP_E7FLAT,  ///< 2489.02 Hz
-    BUZZER_NOTE_E7,              ///< 2637.02 Hz
-    BUZZER_NOTE_F7,              ///< 2793.83 Hz
-    BUZZER_NOTE_F7SHARP_G7FLAT,  ///< 2959.96 Hz
-    BUZZER_NOTE_G7,              ///< 3135.96 Hz
-    BUZZER_NOTE_G7SHARP_A7FLAT,  ///< 3322.44 Hz
-    BUZZER_NOTE_A7,              ///< 3520.00 Hz
-    BUZZER_NOTE_A7SHARP_B7FLAT,  ///< 3729.31 Hz
-    BUZZER_NOTE_B7,              ///< 3951.07 Hz
-    BUZZER_NOTE_C8,              ///< 4186.01 Hz
-    BUZZER_NOTE_C8SHARP_D8FLAT,  ///< 4434.92 Hz
-    BUZZER_NOTE_D8,              ///< 4698.63 Hz
-    BUZZER_NOTE_D8SHARP_E8FLAT,  ///< 4978.03 Hz
-    BUZZER_NOTE_E8,              ///< 5274.04 Hz
-    BUZZER_NOTE_F8,              ///< 5587.65 Hz
-    BUZZER_NOTE_F8SHARP_G8FLAT,  ///< 5919.91 Hz
-    BUZZER_NOTE_G8,              ///< 6271.93 Hz
-    BUZZER_NOTE_G8SHARP_A8FLAT,  ///< 6644.88 Hz
-    BUZZER_NOTE_A8,              ///< 7040.00 Hz
-    BUZZER_NOTE_A8SHARP_B8FLAT,  ///< 7458.62 Hz
-    BUZZER_NOTE_B8,              ///< 7902.13 Hz
-    BUZZER_NOTE_REST             ///< no sound
-} BuzzerNote;
-
-/** @brief Plays the given note for a set duration.
-  * @param note The note you wish to play, or BUZZER_NOTE_REST to disable output for the given duration.
-  * @param duration_ms The duration of the note.
-  * @note Note that this will block your UI for the duration of the note's play time, and it will
-  *       after this call, the buzzer period will be set to the period of this note.
-  */
-void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms);
-
-/// @brief An array of periods for all the notes on a piano, corresponding to the names in BuzzerNote.
-extern const uint16_t NotePeriods[108];
-
-/** @brief Plays the given sequence of notes in a non-blocking way.
-  * @param note_sequence A pointer to the sequence of buzzer note & duration tuples, ending with a zero. A simple
-  *        RLE logic is implemented: a negative number instead of a buzzer note means that the sequence
-  *        is rewound by the given number of notes. The byte following a negative number determines the number
-  *        of loops. I.e. if you want to repeat the last three notes of the sequence one time, you should provide 
-  *        the tuple -3, 1. The repeated notes must not contain any other repeat markers, or you will end up with 
-  *        an eternal loop.
-  * @param callback_on_end A pointer to a callback function to be invoked when the sequence has finished playing.
-  * @note This function plays the sequence asynchronously, so the UI will not be blocked. 
-  *       Hint: It is not possible to play the lowest note BUZZER_NOTE_A1 (55.00 Hz). The note is represented by a 
-  *       zero byte, which is used here as the end-of-sequence marker. But hey, a frequency that low cannot be
-  *       played properly by the watch's buzzer, anyway.
-  */
-void watch_buzzer_play_sequence(int8_t *note_sequence, void (*callback_on_end)(void));
-
-/** @brief Aborts a playing sequence.
-  */
-void watch_buzzer_abort_sequence(void);
-
-#ifndef __EMSCRIPTEN__
-void TC3_Handler(void);
-#endif
-
-/// @}
-#endif
diff --git a/watch-library/shared/watch/watch_led.h b/watch-library/shared/watch/watch_led.h
deleted file mode 100644 (file)
index 134803a..0000000
+++ /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_tcc.h b/watch-library/shared/watch/watch_tcc.h
new file mode 100644 (file)
index 0000000..0443b42
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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_BUZZER_H_INCLUDED
+#define _WATCH_BUZZER_H_INCLUDED
+////< @file watch_buzzer.h
+
+#include "watch.h"
+
+/** @brief Returns true if either the buzzer or the LED driver is enabled.
+  * @details Both the buzzer and the LED use the TCC peripheral to drive their behavior. This function returns true if that
+  *          peripheral is enabled. You can use this function to determine whether you need to call the watch_disable_leds or
+  *          or watch_enable_buzzer functions before using these peripherals.
+  */
+bool watch_is_buzzer_or_led_enabled(void);
+
+/** @addtogroup tcc Buzzer and LED Control (via the TCC peripheral)
+  * @brief This section covers functions related to the piezo buzzer embedded in the F-91W's back plate.
+  */
+/// @{
+/** @brief Enables the TCC peripheral, which drives the buzzer.
+  */
+void watch_enable_buzzer(void);
+
+/** @brief Sets the period of the buzzer.
+  * @param period The period of a single cycle for the TCC peripheral. You can determine the period for
+  *               a desired frequency with the following formula: period = 1000000 / freq
+  */
+void watch_set_buzzer_period(uint32_t period);
+
+/** @brief Disables the TCC peripheral that drives the buzzer.
+  * @note If you are using PWM to set custom LED colors, this method will also disable the LED PWM driver,
+  *       since the buzzer and LED both make use of the same peripheral to drive their PWM behavior.
+  */
+void watch_disable_buzzer(void);
+
+/** @brief Turns the buzzer output on. It will emit a continuous sound at the given frequency.
+  * @note The TCC peripheral that drives the buzzer does not run in standby mode; if you wish for buzzer
+  *       output to continue, you should prevent your app from going to sleep.
+  */
+void watch_set_buzzer_on(void);
+
+/** @brief Turns the buzzer output off.
+  */
+void watch_set_buzzer_off(void);
+
+/// @brief 87 notes for use with watch_buzzer_play_note
+typedef enum BuzzerNote {
+    BUZZER_NOTE_A1,              ///< 55.00 Hz
+    BUZZER_NOTE_A1SHARP_B1FLAT,  ///< 58.27 Hz
+    BUZZER_NOTE_B1,              ///< 61.74 Hz
+    BUZZER_NOTE_C2,              ///< 65.41 Hz
+    BUZZER_NOTE_C2SHARP_D2FLAT,  ///< 69.30 Hz
+    BUZZER_NOTE_D2,              ///< 73.42 Hz
+    BUZZER_NOTE_D2SHARP_E2FLAT,  ///< 77.78 Hz
+    BUZZER_NOTE_E2,              ///< 82.41 Hz
+    BUZZER_NOTE_F2,              ///< 87.31 Hz
+    BUZZER_NOTE_F2SHARP_G2FLAT,  ///< 92.50 Hz
+    BUZZER_NOTE_G2,              ///< 98.00 Hz
+    BUZZER_NOTE_G2SHARP_A2FLAT,  ///< 103.83 Hz
+    BUZZER_NOTE_A2,              ///< 110.00 Hz
+    BUZZER_NOTE_A2SHARP_B2FLAT,  ///< 116.54 Hz
+    BUZZER_NOTE_B2,              ///< 123.47 Hz
+    BUZZER_NOTE_C3,              ///< 130.81 Hz
+    BUZZER_NOTE_C3SHARP_D3FLAT,  ///< 138.59 Hz
+    BUZZER_NOTE_D3,              ///< 146.83 Hz
+    BUZZER_NOTE_D3SHARP_E3FLAT,  ///< 155.56 Hz
+    BUZZER_NOTE_E3,              ///< 164.81 Hz
+    BUZZER_NOTE_F3,              ///< 174.61 Hz
+    BUZZER_NOTE_F3SHARP_G3FLAT,  ///< 185.00 Hz
+    BUZZER_NOTE_G3,              ///< 196.00 Hz
+    BUZZER_NOTE_G3SHARP_A3FLAT,  ///< 207.65 Hz
+    BUZZER_NOTE_A3,              ///< 220.00 Hz
+    BUZZER_NOTE_A3SHARP_B3FLAT,  ///< 233.08 Hz
+    BUZZER_NOTE_B3,              ///< 246.94 Hz
+    BUZZER_NOTE_C4,              ///< 261.63 Hz
+    BUZZER_NOTE_C4SHARP_D4FLAT,  ///< 277.18 Hz
+    BUZZER_NOTE_D4,              ///< 293.66 Hz
+    BUZZER_NOTE_D4SHARP_E4FLAT,  ///< 311.13 Hz
+    BUZZER_NOTE_E4,              ///< 329.63 Hz
+    BUZZER_NOTE_F4,              ///< 349.23 Hz
+    BUZZER_NOTE_F4SHARP_G4FLAT,  ///< 369.99 Hz
+    BUZZER_NOTE_G4,              ///< 392.00 Hz
+    BUZZER_NOTE_G4SHARP_A4FLAT,  ///< 415.30 Hz
+    BUZZER_NOTE_A4,              ///< 440.00 Hz
+    BUZZER_NOTE_A4SHARP_B4FLAT,  ///< 466.16 Hz
+    BUZZER_NOTE_B4,              ///< 493.88 Hz
+    BUZZER_NOTE_C5,              ///< 523.25 Hz
+    BUZZER_NOTE_C5SHARP_D5FLAT,  ///< 554.37 Hz
+    BUZZER_NOTE_D5,              ///< 587.33 Hz
+    BUZZER_NOTE_D5SHARP_E5FLAT,  ///< 622.25 Hz
+    BUZZER_NOTE_E5,              ///< 659.25 Hz
+    BUZZER_NOTE_F5,              ///< 698.46 Hz
+    BUZZER_NOTE_F5SHARP_G5FLAT,  ///< 739.99 Hz
+    BUZZER_NOTE_G5,              ///< 783.99 Hz
+    BUZZER_NOTE_G5SHARP_A5FLAT,  ///< 830.61 Hz
+    BUZZER_NOTE_A5,              ///< 880.00 Hz
+    BUZZER_NOTE_A5SHARP_B5FLAT,  ///< 932.33 Hz
+    BUZZER_NOTE_B5,              ///< 987.77 Hz
+    BUZZER_NOTE_C6,              ///< 1046.50 Hz
+    BUZZER_NOTE_C6SHARP_D6FLAT,  ///< 1108.73 Hz
+    BUZZER_NOTE_D6,              ///< 1174.66 Hz
+    BUZZER_NOTE_D6SHARP_E6FLAT,  ///< 1244.51 Hz
+    BUZZER_NOTE_E6,              ///< 1318.51 Hz
+    BUZZER_NOTE_F6,              ///< 1396.91 Hz
+    BUZZER_NOTE_F6SHARP_G6FLAT,  ///< 1479.98 Hz
+    BUZZER_NOTE_G6,              ///< 1567.98 Hz
+    BUZZER_NOTE_G6SHARP_A6FLAT,  ///< 1661.22 Hz
+    BUZZER_NOTE_A6,              ///< 1760.00 Hz
+    BUZZER_NOTE_A6SHARP_B6FLAT,  ///< 1864.66 Hz
+    BUZZER_NOTE_B6,              ///< 1975.53 Hz
+    BUZZER_NOTE_C7,              ///< 2093.00 Hz
+    BUZZER_NOTE_C7SHARP_D7FLAT,  ///< 2217.46 Hz
+    BUZZER_NOTE_D7,              ///< 2349.32 Hz
+    BUZZER_NOTE_D7SHARP_E7FLAT,  ///< 2489.02 Hz
+    BUZZER_NOTE_E7,              ///< 2637.02 Hz
+    BUZZER_NOTE_F7,              ///< 2793.83 Hz
+    BUZZER_NOTE_F7SHARP_G7FLAT,  ///< 2959.96 Hz
+    BUZZER_NOTE_G7,              ///< 3135.96 Hz
+    BUZZER_NOTE_G7SHARP_A7FLAT,  ///< 3322.44 Hz
+    BUZZER_NOTE_A7,              ///< 3520.00 Hz
+    BUZZER_NOTE_A7SHARP_B7FLAT,  ///< 3729.31 Hz
+    BUZZER_NOTE_B7,              ///< 3951.07 Hz
+    BUZZER_NOTE_C8,              ///< 4186.01 Hz
+    BUZZER_NOTE_C8SHARP_D8FLAT,  ///< 4434.92 Hz
+    BUZZER_NOTE_D8,              ///< 4698.63 Hz
+    BUZZER_NOTE_D8SHARP_E8FLAT,  ///< 4978.03 Hz
+    BUZZER_NOTE_E8,              ///< 5274.04 Hz
+    BUZZER_NOTE_F8,              ///< 5587.65 Hz
+    BUZZER_NOTE_F8SHARP_G8FLAT,  ///< 5919.91 Hz
+    BUZZER_NOTE_G8,              ///< 6271.93 Hz
+    BUZZER_NOTE_G8SHARP_A8FLAT,  ///< 6644.88 Hz
+    BUZZER_NOTE_A8,              ///< 7040.00 Hz
+    BUZZER_NOTE_A8SHARP_B8FLAT,  ///< 7458.62 Hz
+    BUZZER_NOTE_B8,              ///< 7902.13 Hz
+    BUZZER_NOTE_REST             ///< no sound
+} BuzzerNote;
+
+/** @brief Plays the given note for a set duration.
+  * @param note The note you wish to play, or BUZZER_NOTE_REST to disable output for the given duration.
+  * @param duration_ms The duration of the note.
+  * @note Note that this will block your UI for the duration of the note's play time, and it will
+  *       after this call, the buzzer period will be set to the period of this note.
+  */
+void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms);
+
+/// @brief An array of periods for all the notes on a piano, corresponding to the names in BuzzerNote.
+extern const uint16_t NotePeriods[108];
+
+/** @brief Plays the given sequence of notes in a non-blocking way.
+  * @param note_sequence A pointer to the sequence of buzzer note & duration tuples, ending with a zero. A simple
+  *        RLE logic is implemented: a negative number instead of a buzzer note means that the sequence
+  *        is rewound by the given number of notes. The byte following a negative number determines the number
+  *        of loops. I.e. if you want to repeat the last three notes of the sequence one time, you should provide 
+  *        the tuple -3, 1. The repeated notes must not contain any other repeat markers, or you will end up with 
+  *        an eternal loop.
+  * @param callback_on_end A pointer to a callback function to be invoked when the sequence has finished playing.
+  * @note This function plays the sequence asynchronously, so the UI will not be blocked. 
+  *       Hint: It is not possible to play the lowest note BUZZER_NOTE_A1 (55.00 Hz). The note is represented by a 
+  *       zero byte, which is used here as the end-of-sequence marker. But hey, a frequency that low cannot be
+  *       played properly by the watch's buzzer, anyway.
+  */
+void watch_buzzer_play_sequence(int8_t *note_sequence, void (*callback_on_end)(void));
+
+/** @brief Aborts a playing sequence.
+  */
+void watch_buzzer_abort_sequence(void);
+
+#ifndef __EMSCRIPTEN__
+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_buzzer.c b/watch-library/simulator/watch/watch_buzzer.c
deleted file mode 100644 (file)
index c5d9d7e..0000000
+++ /dev/null
@@ -1,183 +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_buzzer.h"
-#include "watch_private_buzzer.h"
-#include "watch_main_loop.h"
-
-#include <emscripten.h>
-#include <emscripten/html5.h>
-
-static bool buzzer_enabled = false;
-static uint32_t buzzer_period;
-
-void cb_watch_buzzer_seq(void *userData);
-
-static uint16_t _seq_position;
-static int8_t _tone_ticks, _repeat_counter;
-static long _em_interval_id = 0;
-static int8_t *_sequence;
-static void (*_cb_finished)(void);
-
-void _watch_enable_tcc(void) {}
-
-static inline void _em_interval_stop() {
-    emscripten_clear_interval(_em_interval_id);
-    _em_interval_id = 0;
-}
-
-void watch_buzzer_play_sequence(int8_t *note_sequence, void (*callback_on_end)(void)) {
-    if (_em_interval_id) _em_interval_stop();
-    watch_set_buzzer_off();
-    _sequence = note_sequence;
-    _cb_finished = callback_on_end;
-    _seq_position = 0;
-    _tone_ticks = 0;
-    _repeat_counter = -1;
-    // prepare buzzer
-    watch_enable_buzzer();
-    // initiate 64 hz callback
-    _em_interval_id = emscripten_set_interval(cb_watch_buzzer_seq, (double)(1000/64), (void *)NULL);
-}
-
-void cb_watch_buzzer_seq(void *userData) {
-    // callback for reading the note sequence
-    (void) userData;
-    if (_tone_ticks == 0) {
-        if (_sequence[_seq_position] < 0 && _sequence[_seq_position + 1]) {
-            // repeat indicator found
-            if (_repeat_counter == -1) {
-                // first encounter: load repeat counter
-                _repeat_counter = _sequence[_seq_position + 1];
-            } else _repeat_counter--;
-            if (_repeat_counter > 0)
-                // rewind
-                if (_seq_position > _sequence[_seq_position] * -2)
-                    _seq_position += _sequence[_seq_position] * 2;
-                else
-                    _seq_position = 0;
-            else {
-                // continue
-                _seq_position += 2;
-                _repeat_counter = -1;
-            }
-        }
-        if (_sequence[_seq_position] && _sequence[_seq_position + 1]) {
-            // read note
-            BuzzerNote note = _sequence[_seq_position];
-            if (note == BUZZER_NOTE_REST) {
-                watch_set_buzzer_off();
-            } else {
-                watch_set_buzzer_period(NotePeriods[note]);
-                watch_set_buzzer_on();
-            }
-            // set duration ticks and move to next tone
-            _tone_ticks = _sequence[_seq_position + 1];
-            _seq_position += 2;
-        } else {
-            // end the sequence
-            watch_buzzer_abort_sequence();
-            if (_cb_finished) _cb_finished();
-        }
-    } else _tone_ticks--;
-}
-
-void watch_buzzer_abort_sequence(void) {
-    // ends/aborts the sequence
-    if (_em_interval_id) _em_interval_stop();
-    watch_set_buzzer_off();
-}
-
-void watch_enable_buzzer(void) {
-    buzzer_enabled = true;
-    buzzer_period = NotePeriods[BUZZER_NOTE_A4];
-
-    EM_ASM({
-        Module['audioContext'] = new (window.AudioContext || window.webkitAudioContext)();
-    });
-}
-
-void watch_set_buzzer_period(uint32_t period) {
-    if (!buzzer_enabled) return;
-    buzzer_period = period;
-}
-
-void watch_disable_buzzer(void) {
-    buzzer_enabled = false;
-    buzzer_period = NotePeriods[BUZZER_NOTE_A4];
-
-    EM_ASM({
-        if (Module['audioContext']) {
-            Module['audioContext'].close();
-            Module['audioContext'] = null;
-        }
-    });
-}
-
-void watch_set_buzzer_on(void) {
-    if (!buzzer_enabled) return;
-
-    EM_ASM({
-        const audioContext = Module['audioContext'];
-        if (!audioContext) return;
-
-        if (!(audioContext._oscillator && audioContext._gain)) {
-            const oscillator = audioContext.createOscillator();
-            const gain = audioContext.createGain();
-            oscillator.type = 'triangle';
-            oscillator.connect(gain);
-            gain.connect(audioContext.destination);
-            oscillator.start(0);
-
-            audioContext._oscillator = oscillator;
-            audioContext._gain = gain;
-        }
-
-        audioContext._oscillator.frequency.value = 1e6/$0;
-        audioContext._gain.gain.value = volumeGain;
-    }, buzzer_period);
-}
-
-void watch_set_buzzer_off(void) {
-    if (!buzzer_enabled) return;
-
-    EM_ASM({
-        const audioContext = Module['audioContext'];
-        if (audioContext && audioContext._gain) {
-            audioContext._gain.gain.value = 0;
-        }
-    });
-}
-
-void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) {
-    if (note == BUZZER_NOTE_REST) {
-        watch_set_buzzer_off();
-    } else {
-        watch_set_buzzer_period(NotePeriods[note]);
-        watch_set_buzzer_on();
-    }
-
-    main_loop_sleep(duration_ms);
-    watch_set_buzzer_off();
-}
diff --git a/watch-library/simulator/watch/watch_led.c b/watch-library/simulator/watch/watch_led.c
deleted file mode 100644 (file)
index 584611f..0000000
+++ /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 <emscripten.h>
-
-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_tcc.c b/watch-library/simulator/watch/watch_tcc.c
new file mode 100644 (file)
index 0000000..77c0640
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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_buzzer.h"
+#include "watch_private_buzzer.h"
+#include "watch_main_loop.h"
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+static bool buzzer_enabled = false;
+static uint32_t buzzer_period;
+
+void cb_watch_buzzer_seq(void *userData);
+
+static uint16_t _seq_position;
+static int8_t _tone_ticks, _repeat_counter;
+static long _em_interval_id = 0;
+static int8_t *_sequence;
+static void (*_cb_finished)(void);
+
+void _watch_enable_tcc(void) {}
+
+static inline void _em_interval_stop() {
+    emscripten_clear_interval(_em_interval_id);
+    _em_interval_id = 0;
+}
+
+void watch_buzzer_play_sequence(int8_t *note_sequence, void (*callback_on_end)(void)) {
+    if (_em_interval_id) _em_interval_stop();
+    watch_set_buzzer_off();
+    _sequence = note_sequence;
+    _cb_finished = callback_on_end;
+    _seq_position = 0;
+    _tone_ticks = 0;
+    _repeat_counter = -1;
+    // prepare buzzer
+    watch_enable_buzzer();
+    // initiate 64 hz callback
+    _em_interval_id = emscripten_set_interval(cb_watch_buzzer_seq, (double)(1000/64), (void *)NULL);
+}
+
+void cb_watch_buzzer_seq(void *userData) {
+    // callback for reading the note sequence
+    (void) userData;
+    if (_tone_ticks == 0) {
+        if (_sequence[_seq_position] < 0 && _sequence[_seq_position + 1]) {
+            // repeat indicator found
+            if (_repeat_counter == -1) {
+                // first encounter: load repeat counter
+                _repeat_counter = _sequence[_seq_position + 1];
+            } else _repeat_counter--;
+            if (_repeat_counter > 0)
+                // rewind
+                if (_seq_position > _sequence[_seq_position] * -2)
+                    _seq_position += _sequence[_seq_position] * 2;
+                else
+                    _seq_position = 0;
+            else {
+                // continue
+                _seq_position += 2;
+                _repeat_counter = -1;
+            }
+        }
+        if (_sequence[_seq_position] && _sequence[_seq_position + 1]) {
+            // read note
+            BuzzerNote note = _sequence[_seq_position];
+            if (note == BUZZER_NOTE_REST) {
+                watch_set_buzzer_off();
+            } else {
+                watch_set_buzzer_period(NotePeriods[note]);
+                watch_set_buzzer_on();
+            }
+            // set duration ticks and move to next tone
+            _tone_ticks = _sequence[_seq_position + 1];
+            _seq_position += 2;
+        } else {
+            // end the sequence
+            watch_buzzer_abort_sequence();
+            if (_cb_finished) _cb_finished();
+        }
+    } else _tone_ticks--;
+}
+
+void watch_buzzer_abort_sequence(void) {
+    // ends/aborts the sequence
+    if (_em_interval_id) _em_interval_stop();
+    watch_set_buzzer_off();
+}
+
+void watch_enable_buzzer(void) {
+    buzzer_enabled = true;
+    buzzer_period = NotePeriods[BUZZER_NOTE_A4];
+
+    EM_ASM({
+        Module['audioContext'] = new (window.AudioContext || window.webkitAudioContext)();
+    });
+}
+
+void watch_set_buzzer_period(uint32_t period) {
+    if (!buzzer_enabled) return;
+    buzzer_period = period;
+}
+
+void watch_disable_buzzer(void) {
+    buzzer_enabled = false;
+    buzzer_period = NotePeriods[BUZZER_NOTE_A4];
+
+    EM_ASM({
+        if (Module['audioContext']) {
+            Module['audioContext'].close();
+            Module['audioContext'] = null;
+        }
+    });
+}
+
+void watch_set_buzzer_on(void) {
+    if (!buzzer_enabled) return;
+
+    EM_ASM({
+        const audioContext = Module['audioContext'];
+        if (!audioContext) return;
+
+        if (!(audioContext._oscillator && audioContext._gain)) {
+            const oscillator = audioContext.createOscillator();
+            const gain = audioContext.createGain();
+            oscillator.type = 'triangle';
+            oscillator.connect(gain);
+            gain.connect(audioContext.destination);
+            oscillator.start(0);
+
+            audioContext._oscillator = oscillator;
+            audioContext._gain = gain;
+        }
+
+        audioContext._oscillator.frequency.value = 1e6/$0;
+        audioContext._gain.gain.value = volumeGain;
+    }, buzzer_period);
+}
+
+void watch_set_buzzer_off(void) {
+    if (!buzzer_enabled) return;
+
+    EM_ASM({
+        const audioContext = Module['audioContext'];
+        if (audioContext && audioContext._gain) {
+            audioContext._gain.gain.value = 0;
+        }
+    });
+}
+
+void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) {
+    if (note == BUZZER_NOTE_REST) {
+        watch_set_buzzer_off();
+    } else {
+        watch_set_buzzer_period(NotePeriods[note]);
+        watch_set_buzzer_on();
+    }
+
+    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);
+}