diff options
Diffstat (limited to 'watch-library/watch')
28 files changed, 0 insertions, 3672 deletions
diff --git a/watch-library/watch/tusb_config.h b/watch-library/watch/tusb_config.h deleted file mode 100644 index a22b2b99..00000000 --- a/watch-library/watch/tusb_config.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * 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 _TUSB_CONFIG_H_ -#define _TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by board.mk -#define CFG_TUSB_MCU OPT_MCU_SAML22 - -#define BOARD_DEVICE_RHPORT_NUM 0 -#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) - -#define CFG_TUSB_OS OPT_OS_NONE - -// disable TinyUSB debug. our printf method prints stuff to the USB console, so you just get infinite noise. -// if you need to debug tinyUSB issues, use the alternate _write function in watch_private.c to echo to the UART. -#define CFG_TUSB_DEBUG 0 - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_CDC 1 -#define CFG_TUD_MSC 0 -#define CFG_TUD_HID 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 0 - -// CDC FIFO size of TX and RX -#define CFG_TUD_CDC_RX_BUFSIZE (64) -#define CFG_TUD_CDC_TX_BUFSIZE (64) - -// CDC Endpoint transfer buffer size, more is faster -#define CFG_TUD_CDC_EP_BUFSIZE (64) - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CONFIG_H_ */ diff --git a/watch-library/watch/watch.c b/watch-library/watch/watch.c deleted file mode 100644 index 791fd974..00000000 --- a/watch-library/watch/watch.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.h" - -bool battery_is_low = false; - -// receives interrupts from MCLK, OSC32KCTRL, OSCCTRL, PAC, PM, SUPC and TAL, whatever that is. -void SYSTEM_Handler(void) { - if (SUPC->INTFLAG.bit.BOD33DET) { - battery_is_low = true; - SUPC->INTENCLR.bit.BOD33DET = 1; - SUPC->INTFLAG.reg &= ~SUPC_INTFLAG_BOD33DET; - } -} - -bool watch_is_battery_low(void) { - return battery_is_low; -} - -bool watch_is_buzzer_or_led_enabled(void){ - return hri_mclk_get_APBCMASK_TCC0_bit(MCLK); -} diff --git a/watch-library/watch/watch.h b/watch-library/watch/watch.h deleted file mode 100644 index 064f90ec..00000000 --- a/watch-library/watch/watch.h +++ /dev/null @@ -1,83 +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. - */ -/// @file watch.h - -#ifndef WATCH_H_ -#define WATCH_H_ -#include <stdint.h> -#include <stdbool.h> -#include "driver_init.h" - -/** @mainpage Sensor Watch Documentation - * @brief This documentation covers most of the functions you will use to interact with the Sensor Watch - hardware. It is divided into the following sections: - - @ref app - This section covers the functions that you will implement in your app.c file when designing a - Sensor Watch app. - - @ref rtc - This section covers functions related to the SAM L22's real-time clock peripheral, including - date, time and alarm functions. - - @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 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. - - @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. - - @ref debug - This section covers functions related to the debug UART, available on pin D1 of the 9-pin connector. - - @ref deepsleep - This section covers functions related to preparing for and entering BACKUP mode, the - deepest sleep mode available on the SAM L22. - */ - -#include "watch_app.h" -#include "watch_rtc.h" -#include "watch_slcd.h" -#include "watch_extint.h" -#include "watch_led.h" -#include "watch_buzzer.h" -#include "watch_adc.h" -#include "watch_gpio.h" -#include "watch_i2c.h" -#include "watch_uart.h" -#include "watch_deepsleep.h" - -#include "watch_private.h" - -/** @brief Returns true when the battery voltage dips below 2.5V. - * @details A CR2016 battery will have a nominal voltage between 2.9 and 3 volts for most of its lifespan. Once the battery - * discharges to about 60%, the voltage will drift slightly lower; this may manifest as a dimmer LED. By the time - * the battery voltage has fallen to 2.5 volts, it will have probably less than 10% of its capacity remaining, and - * you can expect the voltage to drop relatively quickly as the battery dies. - */ -bool watch_is_battery_low(void); - -/** @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); - -#endif /* WATCH_H_ */
\ No newline at end of file diff --git a/watch-library/watch/watch_adc.c b/watch-library/watch/watch_adc.c deleted file mode 100644 index 5ba7abdf..00000000 --- a/watch-library/watch/watch_adc.c +++ /dev/null @@ -1,179 +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_adc.h" - -static void _watch_sync_adc(void) { - while (ADC->SYNCBUSY.reg); -} - -static uint16_t _watch_get_analog_value(uint16_t channel) { - if (ADC->INPUTCTRL.bit.MUXPOS != channel) { - ADC->INPUTCTRL.bit.MUXPOS = channel; - _watch_sync_adc(); - } - - ADC->SWTRIG.bit.START = 1; - while (!ADC->INTFLAG.bit.RESRDY); - - return ADC->RESULT.reg; -} - -void watch_enable_adc(void) { - MCLK->APBCMASK.reg |= MCLK_APBCMASK_ADC; - GCLK->PCHCTRL[ADC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; - - uint16_t calib_reg = 0; - calib_reg = ADC_CALIB_BIASREFBUF((*(uint32_t *)ADC_FUSES_BIASREFBUF_ADDR >> ADC_FUSES_BIASREFBUF_Pos)) | - ADC_CALIB_BIASCOMP((*(uint32_t *)ADC_FUSES_BIASCOMP_ADDR >> ADC_FUSES_BIASCOMP_Pos)); - - if (!ADC->SYNCBUSY.bit.SWRST) { - if (ADC->CTRLA.bit.ENABLE) { - ADC->CTRLA.bit.ENABLE = 0; - _watch_sync_adc(); - } - ADC->CTRLA.bit.SWRST = 1; - } - _watch_sync_adc(); - - if (USB->DEVICE.CTRLA.bit.ENABLE) { - // if USB is enabled, we are running an 8 MHz clock. - // divide by 16 for a 500kHz ADC clock. - ADC->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV16_Val; - } else { - // otherwise it's 4 Mhz. divide by 8 for a 500kHz ADC clock. - ADC->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV8_Val; - } - ADC->CALIB.reg = calib_reg; - ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC2_Val; - ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val; - ADC->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_16BIT_Val; - ADC->AVGCTRL.bit.SAMPLENUM = ADC_AVGCTRL_SAMPLENUM_16_Val; - ADC->SAMPCTRL.bit.SAMPLEN = 0; - ADC->INTENSET.reg = ADC_INTENSET_RESRDY; - ADC->CTRLA.bit.ENABLE = 1; - _watch_sync_adc(); - // throw away one measurement after reference change (the channel doesn't matter). - _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC); -} - -void watch_enable_analog_input(const uint8_t pin) { - gpio_set_pin_direction(pin, GPIO_DIRECTION_OFF); - switch (pin) { - case A0: - gpio_set_pin_function(pin, PINMUX_PB04B_ADC_AIN12); - break; - case A1: - gpio_set_pin_function(pin, PINMUX_PB01B_ADC_AIN9); - break; - case A2: - gpio_set_pin_function(pin, PINMUX_PB02B_ADC_AIN10); - break; - case A3: - gpio_set_pin_function(pin, PINMUX_PB03B_ADC_AIN11); - break; - case A4: - gpio_set_pin_function(pin, PINMUX_PB00B_ADC_AIN8); - break; - default: - return; - } -} - -uint16_t watch_get_analog_pin_level(const uint8_t pin) { - switch (pin) { - case A0: - return _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_AIN12_Val); - case A1: - return _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_AIN9_Val); - case A2: - return _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_AIN10_Val); - case A3: - return _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_AIN11_Val); - case A4: - return _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_AIN8_Val); - default: - return 0; - } -} - -void watch_set_analog_num_samples(uint16_t samples) { - // ignore any input that's not a power of 2 (i.e. only one bit set) - if (__builtin_popcount(samples) != 1) return; - // if only one bit is set, counting the trailing zeroes is equivalent to log2(samples) - uint8_t sample_val = __builtin_ctz(samples); - // make sure the desired value is within range and set it, if so. - if (sample_val <= ADC_AVGCTRL_SAMPLENUM_1024_Val) { - ADC->AVGCTRL.bit.SAMPLENUM = sample_val; - _watch_sync_adc(); - } -} - -void watch_set_analog_sampling_length(uint8_t cycles) { - // for clarity the API asks the user how many cycles they want the measurement to take. - // but the ADC always needs at least one cycle; it just wants to know how many *extra* cycles we want. - // so we subtract one from the user-provided value, and clamp to the maximum. - ADC->SAMPCTRL.bit.SAMPLEN = (cycles - 1) & 0x3F; - _watch_sync_adc(); -} - -void watch_set_analog_reference_voltage(watch_adc_reference_voltage reference) { - ADC->CTRLA.bit.ENABLE = 0; - - if (reference == ADC_REFERENCE_INTREF) SUPC->VREF.bit.VREFOE = 1; - else SUPC->VREF.bit.VREFOE = 0; - - ADC->REFCTRL.bit.REFSEL = reference; - ADC->CTRLA.bit.ENABLE = 1; - _watch_sync_adc(); - // throw away one measurement after reference change (the channel doesn't matter). - _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC); -} - -uint16_t watch_get_vcc_voltage(void) { - // stash the previous reference so we can restore it when we're done. - uint8_t oldref = ADC->REFCTRL.bit.REFSEL; - - // if we weren't already using the internal reference voltage, select it now. - if (oldref != ADC_REFERENCE_INTREF) watch_set_analog_reference_voltage(ADC_REFERENCE_INTREF); - - // get the data - uint32_t raw_val = _watch_get_analog_value(ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val); - - // restore the old reference, if needed. - if (oldref != ADC_REFERENCE_INTREF) watch_set_analog_reference_voltage(oldref); - - return (uint16_t)((raw_val * 1000) / (1024 * 1 << ADC->AVGCTRL.bit.SAMPLENUM)); -} - -inline void watch_disable_analog_input(const uint8_t pin) { - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF); -} - -inline void watch_disable_adc(void) { - ADC->CTRLA.bit.ENABLE = 0; - _watch_sync_adc(); - - MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_ADC; -} diff --git a/watch-library/watch/watch_adc.h b/watch-library/watch/watch_adc.h deleted file mode 100644 index aa7c801a..00000000 --- a/watch-library/watch/watch_adc.h +++ /dev/null @@ -1,157 +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_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 - * 9-pin connector. - */ -/// @{ -/** @brief Enables the ADC peripheral. You must call this before attempting to read a value - * from an analog pin. - */ -void watch_enable_adc(void); - -/** @brief Configures the selected pin for analog input. - * @param pin One of pins A0-A4. - */ -void watch_enable_analog_input(const uint8_t pin); - -/** @brief Reads an analog value from one of the pins. - * @param pin One of pins A0-A4. - * @return a 16-bit unsigned integer from 0-65535 representing the sampled value, unless you - * have changed the number of samples. @see watch_set_num_analog_samples for details - * on how that function changes the values returned from this one. - **/ -uint16_t watch_get_analog_pin_level(const uint8_t pin); - -/** @brief Sets the number of samples to accumulate when measuring a pin level. Default is 16. - * @param samples A power of 2 <= 1024. Specifically: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 - or 1024. Any other value will be ignored. - * @details The SAM L22's ADC has a resolution of 12 bits. By default, the watch configures - * the ADC to take 16 samples of the analog input and accumulate them in the result - * register; this effectively gives us a 16-bit resolution, at the cost of taking 16 - * ADC cycles to complete a measurement. If you are measuring a slowly changing signal - * like a thermistor output or an ambient light sensor this is probably fine, even - * desirable. If you are measuring something a bit more fast-paced, like an analog - * accelerometer, you may wish to exchange precision for speed. In this case you may - * call this function to configure the ADC to accumulate fewer samples. HOWEVER! Note - * that this may change the range of values returned from watch_get_analog_pin_level: - * - For watch_set_num_analog_samples(1), the returned value will be 12 bits (0-4095). - * - For watch_set_num_analog_samples(2), the returned value will be 13 bits (0-8191). - * - For watch_set_num_analog_samples(4), the returned value will be 14 bits (0-16383). - * - For watch_set_num_analog_samples(8), the returned value will be 15 bits (0-32767). - * For sampling values over 16, the returned value will still be 16 bits (0-65535); the - * ADC will automatically divide the measured value by whatever factor is necessary to fit - * the result in 16 bits. - * @see watch_get_analog_pin_level - **/ -void watch_set_analog_num_samples(uint16_t samples); - -/** @brief Sets the length of time spent sampling, which allows measurement of higher impedance inputs. - * Default is 1. - * @param cycles The number of ADC cycles to sample, between 1 and 64. - * @see this article by Thea Flowers: https://blog.thea.codes/getting-the-most-out-of-the-samd21-adc/ - * which is where I learned all of this. - * @details To measure an analog value, the SAM L22 must charge a capacitor to the analog voltage - * presented at the input. This takes time. Importantly, the higher the input impedance, - * the more time this takes. As a basic example: if you are using a thermistor tied to - * VCC to measure temperature, the capacitor has to charge through the thermistor. The - * higher the resistor value, the higher the input impedance, and the more time we need - * to allow for the measurement. By default, the ADC is configured to run on a 500 kHz - * clock with a sample time of one cycle. This is appropriate for an input impedance up - * to about 28kΩ. Setting the sampling time to 4 cycles allows for an input impedance up - * to 123kΩ. Setting the sampling time to the maximum of 64 cycles theoretically allows - * for input impedance up to 2 MΩ. (I based these numbers on the calculator in the linked - * blog post; it also has a ton of great info on the SAM D21 ADC, which is similar to the - * SAM L22's). - **/ -void watch_set_analog_sampling_length(uint8_t cycles); - -typedef enum { - ADC_REFERENCE_INTREF = ADC_REFCTRL_REFSEL_INTREF_Val, - ADC_REFERENCE_VCC_DIV1POINT6 = ADC_REFCTRL_REFSEL_INTVCC0_Val, - ADC_REFERENCE_VCC_DIV2 = ADC_REFCTRL_REFSEL_INTVCC1_Val, - ADC_REFERENCE_VCC = ADC_REFCTRL_REFSEL_INTVCC2_Val, -} watch_adc_reference_voltage; - - -/** @brief Selects the reference voltage to use for analog readings. Default is ADC_REFERENCE_VCC. - * @param reference One of ADC_REFERENCE_VCC, ADC_REFERENCE_VCC_DIV1POINT6, ADC_REFERENCE_VCC_DIV2 - * or ADC_REFERENCE_INTREF. - * @details In order to turn an analog voltage into a 16-bit integer, the ADC needs to compare the - * measured voltage to a reference point. For example, if you were powering the watch with - * VCC == 3.0V and you had two 10K resistors connected in series from 3V to GND, you could - * expect to get 3 volts when you measure the top of the voltage divider, 0 volts at the - * bottom, and 1.5 volts in the middle. If you read these values uising a reference voltage - * of ADC_REFERENCE_VCC, the top value would be about 65535, the bottom about 0, and the - * middle about 32768. However! If we used ADC_REFERENCE_VCC_DIV2 as our reference, we would - * expect to get 65535 both at the top and the middle, because the largest value the ADC can - * measure in this configutation is 1.5V (VCC / 2). - * - * By changing the reference voltage from ADC_REFERENCE_VCC to ADC_REFERENCE_VCC_DIV1POINT6 - * or ADC_REFERENCE_VCC_DIV2, you can get more resolution when measuring small voltages (i.e. - * a phototransistor circuit in low light). - * - * There is also a special reference voltage called ADC_REFERENCE_INTREF. The SAM L22's - * Supply Controller provides a selectable voltage reference (by default, 1.024 V) that you - * can select as a reference voltage for ADC conversions. Unlike the three references we - * talked about in the last paragraph, this reference voltage does not depend on VCC, which - * makes it very useful for measuring the battery voltage (since you can't really compare - * VCC to itself). You can change the INTREF voltage to 2.048 or 4.096 V by poking at the - * supply controller's VREF register, but the watch library does not support this use case. - **/ -void watch_set_analog_reference_voltage(watch_adc_reference_voltage reference); - -/** @brief Returns the voltage of the VCC supply in millivolts (i.e. 3000 mV == 3.0 V). If running on - * a coin cell, this will be the battery voltage. - * @details Unlike other ADC functions, this function does not return a raw value from the ADC, but - * rather scales it to an actual number of millivolts. This is because the ADC doesn't let - * us measure VCC per se; it instead lets us measure VCC / 4, and we choose to measure it - * against the internal reference voltage of 1.024 V. In short, the ADC gives us a number - * that's complicated to deal with, so we just turn it into a useful number for you :) - * @note This function depends on INTREF being 1.024V. If you have changed it by poking at the supply - * controller's VREF.SEL bits, this function will return inaccurate values. - */ -uint16_t watch_get_vcc_voltage(void); - -/** @brief Disables the analog circuitry on the selected pin. - * @param pin One of pins A0-A4. - */ -void watch_disable_analog_input(const uint8_t pin); - -/** @brief Disables the ADC peripheral. - * @note You will need to call watch_enable_adc to re-enable the ADC peripheral. When you do, it will - * have the default settings of 16 samples and 1 measurement cycle; if you customized these - * parameters, you will need to set them up again. - **/ -void watch_disable_adc(void); - -/// @} -#endif diff --git a/watch-library/watch/watch_app.h b/watch-library/watch/watch_app.h deleted file mode 100644 index 4fa29df8..00000000 --- a/watch-library/watch/watch_app.h +++ /dev/null @@ -1,108 +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_APP_H_INCLUDED -#define _WATCH_APP_H_INCLUDED -////< @file watch_app.h - -/** @addtogroup app Application Framework - * @brief This section covers the functions that you will implement in your app.c file when designing a Sensor Watch app. - * @details You should be able to write a watch app by simply implementing these functions and declaring callbacks for - * various GPIO and peripheral interrupts. The main.c file takes care of calling these functions for you. The - * general flow: - * - * 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_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. - * - You should definitely set up some interrupts here. - * 4. The main run loop begins: your app_loop() function is called. - * - Run code and update your UI here. - * - 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_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_standby() function is called. - * - After this, execution resumes at (4). - */ -/// @{ -/** @brief A function you will implement to initialize your application state. The app_init function is called before - * anything else. Use it to set up any internal data structures or application state required by your app, - * but don't configure any peripherals just yet. - */ -void app_init(void); - -/** @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_backup(void); - -/** @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 - * set up (real-time clock, I2C, etc.) Depending on your application, you may or may not want to configure - * sensors on your sensor board here. For example, a low-power accelerometer that will run at all times should - * be configured here, whereas you may want to enable a more power-hungry 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. - */ -void app_setup(void); - -/** @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 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, - * so e.g. the I2C controller, if configured, will sleep in STANDBY. But you can use it again as soon as your - * app wakes up. - */ -bool app_loop(void); - -/** @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_standby. - */ -void app_prepare_for_standby(void); - -/** @brief A method you will implement to configure the app after waking from STANDBY mode. - */ -void app_wake_from_standby(void); - -/// @} -#endif diff --git a/watch-library/watch/watch_buzzer.c b/watch-library/watch/watch_buzzer.c deleted file mode 100644 index a275b00d..00000000 --- a/watch-library/watch/watch_buzzer.c +++ /dev/null @@ -1,64 +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" - - inline void watch_enable_buzzer(void) { - if (!hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) { - _watch_enable_tcc(); - } -} -inline void watch_set_buzzer_period(uint32_t period) { - hri_tcc_write_PERBUF_reg(TCC0, period); -} - -void watch_disable_buzzer(void) { - _watch_disable_tcc(); -} - -inline void watch_set_buzzer_on(void) { - gpio_set_pin_direction(BUZZER, GPIO_DIRECTION_OUT); - gpio_set_pin_function(BUZZER, WATCH_BUZZER_TCC_PINMUX); -} - -inline void watch_set_buzzer_off(void) { - gpio_set_pin_direction(BUZZER, GPIO_DIRECTION_OFF); - gpio_set_pin_function(BUZZER, GPIO_PIN_FUNCTION_OFF); -} - -// note: the buzzer uses a 1 MHz clock. these values were determined by dividing 1,000,000 by the target frequency. -// i.e. for a 440 Hz tone (A4 on the piano), 1MHz/440Hz = 2273 -const uint16_t NotePeriods[108] = {18182,17161,16197,15288,14430,13620,12857,12134,11453,10811,10204,9631,9091,8581,8099,7645,7216,6811,6428,6068,5727,5405,5102,4816,4545,4290,4050,3822,3608,3405,3214,3034,2863,2703,2551,2408,2273,2145,2025,1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012,956,902,851,804,758,716,676,638,602,568,536,506,478,451,426,402,379,358,338,319,301,284,268,253,239,225,213,201,190,179,169,159,150,142,134,127}; - -void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms) { - if (note == BUZZER_NOTE_REST) { - watch_set_buzzer_off(); - } else { - hri_tcc_write_PERBUF_reg(TCC0, NotePeriods[note]); - hri_tcc_write_CCBUF_reg(TCC0, WATCH_BUZZER_TCC_CHANNEL, NotePeriods[note] / 2); - watch_set_buzzer_on(); - } - delay_ms(duration_ms); - watch_set_buzzer_off(); -} diff --git a/watch-library/watch/watch_buzzer.h b/watch-library/watch/watch_buzzer.h deleted file mode 100644 index 1b5d197c..00000000 --- a/watch-library/watch/watch_buzzer.h +++ /dev/null @@ -1,164 +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" - -/** @addtogroup buzzer Buzzer - * @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]; - -/// @} -#endif diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c deleted file mode 100644 index 1813ff24..00000000 --- a/watch-library/watch/watch_deepsleep.c +++ /dev/null @@ -1,209 +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_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. -#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 - -void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level) { - uint32_t pinmux; - hri_rtc_tampctrl_reg_t config = RTC->MODE2.TAMPCTRL.reg; - - switch (pin) { - case A4: - a4_callback = callback; - pinmux = PINMUX_PB00G_RTC_IN0; - config &= ~(3 << RTC_TAMPCTRL_IN0ACT_Pos); - config &= ~(1 << RTC_TAMPCTRL_TAMLVL0_Pos); - config |= 1 << RTC_TAMPCTRL_IN0ACT_Pos; - config |= 1 << RTC_TAMPCTRL_DEBNC0_Pos; - if (level) config |= 1 << RTC_TAMPCTRL_TAMLVL0_Pos; - break; - case A2: - a2_callback = callback; - pinmux = PINMUX_PB02G_RTC_IN1; - config &= ~(3 << RTC_TAMPCTRL_IN1ACT_Pos); - config &= ~(1 << RTC_TAMPCTRL_TAMLVL1_Pos); - config |= 1 << RTC_TAMPCTRL_IN1ACT_Pos; - config |= 1 << RTC_TAMPCTRL_DEBNC1_Pos; - if (level) config |= 1 << RTC_TAMPCTRL_TAMLVL1_Pos; - break; - case BTN_ALARM: - gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); - btn_alarm_callback = callback; - pinmux = PINMUX_PA02G_RTC_IN2; - config &= ~(3 << RTC_TAMPCTRL_IN2ACT_Pos); - config &= ~(1 << RTC_TAMPCTRL_TAMLVL2_Pos); - config |= 1 << RTC_TAMPCTRL_IN2ACT_Pos; - config |= 1 << RTC_TAMPCTRL_DEBNC2_Pos; - if (level) config |= 1 << RTC_TAMPCTRL_TAMLVL2_Pos; - break; - default: - return; - } - gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); - gpio_set_pin_function(pin, pinmux); - - // disable the RTC - RTC->MODE2.CTRLA.bit.ENABLE = 0; - while (RTC->MODE2.SYNCBUSY.bit.ENABLE); - - // update the configuration - RTC->MODE2.TAMPCTRL.reg = config; - // re-enable the RTC - RTC->MODE2.CTRLA.bit.ENABLE = 1; - - NVIC_ClearPendingIRQ(RTC_IRQn); - NVIC_EnableIRQ(RTC_IRQn); - RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_TAMPER; -} - -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; - } -} - -uint32_t watch_get_backup_data(uint8_t reg) { - if (reg < 8) { - return RTC->MODE0.BKUP[reg].reg; - } - - return 0; -} - -static void _watch_disable_all_pins_except_rtc(void) { - uint32_t config = RTC->MODE0.TAMPCTRL.reg; - uint32_t portb_pins_to_disable = 0xFFFFFFFF; - - // if there's an action set on RTC/IN[0], leave PB00 configured - if (config & RTC_TAMPCTRL_IN0ACT_Msk) portb_pins_to_disable &= 0xFFFFFFFE; - // same with RTC/IN[1] and PB02 - if (config & RTC_TAMPCTRL_IN1ACT_Msk) portb_pins_to_disable &= 0xFFFFFFFB; - - // port A: always keep PA02 configured as-is; that's our ALARM button. - gpio_set_port_direction(0, 0xFFFFFFFB, GPIO_DIRECTION_OFF); - // port B: disable all pins we didn't save above. - gpio_set_port_direction(1, portb_pins_to_disable, GPIO_DIRECTION_OFF); -} - -static void _watch_disable_all_peripherals_except_slcd(void) { - _watch_disable_tcc(); - watch_disable_adc(); - watch_disable_external_interrupts(); - watch_disable_i2c(); - // TODO: replace this with a proper function when we remove the debug UART - SERCOM3->USART.CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; - MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_SERCOM3; -} - -void watch_enter_sleep_mode(void) { - // disable all other peripherals - _watch_disable_all_peripherals_except_slcd(); - - // disable tick interrupt - watch_rtc_disable_all_periodic_callbacks(); - - // disable brownout detector interrupt, which could inadvertently wake us up. - SUPC->INTENCLR.bit.BOD33DET = 1; - - // disable all pins - _watch_disable_all_pins_except_rtc(); - - // enter standby (4); we basically hang out here until an interrupt wakes us. - sleep(4); - - // 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_standby (since main won't have a chance to do it) - app_wake_from_standby(); -} - -void watch_enter_deep_sleep_mode(void) { - // 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(void) { - 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); - _watch_disable_all_pins_except_rtc(); - - // 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(void) { - 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 deleted file mode 100644 index 56d75478..00000000 --- a/watch-library/watch/watch_deepsleep.h +++ /dev/null @@ -1,159 +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_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; -extern ext_irq_cb_t a4_callback; - -/** @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 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 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 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. - */ -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. - * @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 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. - * @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 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. - * - * 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_sleep_mode(void); - -/** @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(void); - -/** @brief Enters the SAM L22's lowest-power mode, BACKUP. - * @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, 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(void); - -__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(void); -/// @} -#endif diff --git a/watch-library/watch/watch_extint.c b/watch-library/watch/watch_extint.c deleted file mode 100644 index 5924b646..00000000 --- a/watch-library/watch/watch_extint.c +++ /dev/null @@ -1,111 +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_extint.h" - -void watch_enable_external_interrupts(void) { - // 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)); - // Enable AHB clock for the EIC - hri_mclk_set_APBAMASK_EIC_bit(MCLK); - // call HAL's external interrupt init function - ext_irq_init(); -} - -void watch_disable_external_interrupts(void) { - ext_irq_deinit(); - hri_mclk_clear_APBAMASK_EIC_bit(MCLK); -} - -void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger) { - uint8_t config_index; - uint8_t sense_pos; - switch (pin) { - case A0: - // for EIC channels 8-15, we need to set the SENSE value in CONFIG[1] - config_index = (WATCH_A0_EIC_CHANNEL > 7) ? 1 : 0; - // either way the index in CONFIG[n] must be 0-7 - sense_pos = 4 * (WATCH_A0_EIC_CHANNEL % 8); - break; - case A1: - config_index = (WATCH_A1_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A1_EIC_CHANNEL % 8); - break; - case A2: - config_index = (WATCH_A2_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A2_EIC_CHANNEL % 8); - break; - case A3: - config_index = (WATCH_A3_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A3_EIC_CHANNEL % 8); - break; - case A4: - config_index = (WATCH_A4_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_A4_EIC_CHANNEL % 8); - break; - case BTN_ALARM: - config_index = (WATCH_BTN_ALARM_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_BTN_ALARM_EIC_CHANNEL % 8); - break; - case BTN_LIGHT: - config_index = (WATCH_BTN_LIGHT_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_BTN_LIGHT_EIC_CHANNEL % 8); - break; - case BTN_MODE: - config_index = (WATCH_BTN_MODE_EIC_CHANNEL > 7) ? 1 : 0; - sense_pos = 4 * (WATCH_BTN_MODE_EIC_CHANNEL % 8); - break; - default: - return; - } - - gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); - - // EIC configuration register is enable-protected, so we have to disable it first... - if (hri_eic_get_CTRLA_reg(EIC, EIC_CTRLA_ENABLE)) { - hri_eic_clear_CTRLA_ENABLE_bit(EIC); - // ...and wait for it to synchronize. - hri_eic_wait_for_sync(EIC, EIC_SYNCBUSY_ENABLE); - } - // now update the configuration... - hri_eic_config_reg_t config = EIC->CONFIG[config_index].reg; - 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); - - ext_irq_register(pin, callback); -} - -inline void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback) { - watch_register_interrupt_callback(pin, callback, INTERRUPT_TRIGGER_RISING); -} - -inline void watch_enable_buttons(void) { - watch_enable_external_interrupts(); -} diff --git a/watch-library/watch/watch_extint.h b/watch-library/watch/watch_extint.h deleted file mode 100644 index 452461b3..00000000 --- a/watch-library/watch/watch_extint.h +++ /dev/null @@ -1,85 +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_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 - * @brief This section covers functions related to the three buttons: Light, Mode and Alarm, as well as - * external interrupts from devices on the nine-pin connector. - * @details The buttons are the core input UI of the watch, and the way the user will interact with - * your application. They are active high, pulled down by the microcontroller, and triggered - * when one of the "pushers" brings a tab from the metal frame into contact with the edge - * of the board. Note that the buttons can only wake the watch from STANDBY mode, at least as - * of the current SAM L22 silicon revision. The external interrupt controller runs in STANDBY - * mode, but it does not run in BACKUP mode; to wake from BACKUP, buttons will not cut it. - */ -/// @{ - -///@brief An enum defining the types of interrupt trigger you wish to scan for. -typedef enum watch_interrupt_trigger { - INTERRUPT_TRIGGER_NONE = 0, - INTERRUPT_TRIGGER_RISING, - INTERRUPT_TRIGGER_FALLING, - INTERRUPT_TRIGGER_BOTH, -} watch_interrupt_trigger; - -/// @brief Enables the external interrupt controller. -void watch_enable_external_interrupts(void); - -/// @brief Disables the external interrupt controller. -void watch_disable_external_interrupts(void); - -/** @brief Configures an external interrupt callback on one of the external interrupt pins. - * @details You can set one interrupt callback per pin, and you can monitor for a rising condition, - * a falling condition, or both. If you just want to detect a button press, register your - * interrupt with INTERRUPT_TRIGGER_RISING; if you want to detect an active-low interrupt - * signal from a device on the nine-pin connector, use INTERRUPT_TRIGGER_FALLING. If you - * want to detect both rising and falling conditions (i.e. button down and button up), use - * INTERRUPT_TRIGGER_BOTH and use watch_get_pin_level to check the pin level in your callback - * to determine which condition caused the interrupt. - * @param pin One of BTN_LIGHT, BTN_MODE, BTN_ALARM, A0, A1, A3 or A4. If the pin parameter matches one of - * the three button pins, this function will also enable an internal pull-down resistor. If - * the pin parameter is A0-A4, you are responsible for setting any required pull configuration - * using watch_enable_pull_up or watch_enable_pull_down. - * @param callback The function you wish to have called when the button is pressed. - * @param trigger The condition on which you wish to trigger: rising, falling or both. - * @note Pins A2 and A4 can also generate interrupts via the watch_register_extwake_callback function, which - * will allow them to trigger even when the watch is in deep sleep mode. - * @warning As of now, A2 is not usable via the watch_register_interrupt_callback function. To enable an - * external interrupt on pin A2, use the watch_register_extwake_callback function. This issue will be - * addressed in a future revision of the watch library. - */ -void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger); - -__attribute__((deprecated("Use watch_register_interrupt_callback or watch_register_extwake_callback instead"))) -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(void); -/// @} -#endif diff --git a/watch-library/watch/watch_gpio.c b/watch-library/watch/watch_gpio.c deleted file mode 100644 index b37d009f..00000000 --- a/watch-library/watch/watch_gpio.c +++ /dev/null @@ -1,61 +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_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); -} - -void watch_disable_digital_input(const uint8_t pin) { - gpio_set_pin_direction(pin, GPIO_DIRECTION_OFF); - gpio_set_pin_pull_mode(pin, GPIO_PULL_OFF); - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF); -} - -void watch_enable_pull_up(const uint8_t pin) { - gpio_set_pin_pull_mode(pin, GPIO_PULL_UP); -} - -void watch_enable_pull_down(const uint8_t pin) { - gpio_set_pin_pull_mode(pin, GPIO_PULL_DOWN); -} - -bool watch_get_pin_level(const uint8_t pin) { - return gpio_get_pin_level(pin); -} - -void watch_enable_digital_output(const uint8_t pin) { - gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT); - gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF); -} - -void watch_disable_digital_output(const uint8_t pin) { - gpio_set_pin_direction(pin, GPIO_DIRECTION_OFF); -} - -void watch_set_pin_level(const uint8_t pin, const bool level) { - gpio_set_pin_level(pin, level); -} diff --git a/watch-library/watch/watch_gpio.h b/watch-library/watch/watch_gpio.h deleted file mode 100644 index fc43642c..00000000 --- a/watch-library/watch/watch_gpio.h +++ /dev/null @@ -1,76 +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_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. - */ -/// @{ -/** @brief Configures the selected pin for digital input. - * @param pin The pin that you wish to act as an input. - */ -void watch_enable_digital_input(const uint8_t pin); - -/** @brief Disables any digital input, along with any pull-up or pull-down configuration. - * @param pin The pin that you wish to disable. - */ -void watch_disable_digital_input(const uint8_t pin); - -/** @brief Enables a pull-up resistor on the selected pin. - * @param pin The pin that you wish to configure. - */ -void watch_enable_pull_up(const uint8_t pin); - -/** @brief Enables a pull-down resistor on the selected pin. - * @param pin The pin that you wish to configure. - */ -void watch_enable_pull_down(const uint8_t pin); - -/** @brief Gets the level of the selected pin. - * @param pin The pin whose value you wish to read. - * @return true if the pin was logic high; otherwise, false. - */ -bool watch_get_pin_level(const uint8_t pin); - -/** @brief Configures the selected pin for digital output. - * @param pin The pin that you wish to act as an output. - */ -void watch_enable_digital_output(const uint8_t pin); - -/** @brief Disables digital output on the selected pin. - * @param pin The pin that you wish disable. - */ -void watch_disable_digital_output(const uint8_t pin); - -/** @brief Sets the level of the selected pin. - * @param pin The pin whose value you wish to set. - * @param level The level you wish to set: true for high, false for low. - */ -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 deleted file mode 100644 index ff20afc6..00000000 --- a/watch-library/watch/watch_i2c.c +++ /dev/null @@ -1,93 +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_i2c.h" - -struct io_descriptor *I2C_0_io; - -void watch_enable_i2c(void) { - I2C_0_init(); - i2c_m_sync_get_io_descriptor(&I2C_0, &I2C_0_io); - i2c_m_sync_enable(&I2C_0); -} - -void watch_disable_i2c(void) { - i2c_m_sync_disable(&I2C_0); - hri_mclk_clear_APBCMASK_SERCOM1_bit(MCLK); -} - -void watch_i2c_send(int16_t addr, uint8_t *buf, uint16_t length) { - i2c_m_sync_set_periphaddr(&I2C_0, addr, I2C_M_SEVEN); - io_write(I2C_0_io, buf, length); -} - -void watch_i2c_receive(int16_t addr, uint8_t *buf, uint16_t length) { - i2c_m_sync_set_periphaddr(&I2C_0, addr, I2C_M_SEVEN); - io_read(I2C_0_io, buf, length); -} - -void watch_i2c_write8(int16_t addr, uint8_t reg, uint8_t data) { - uint8_t buf[2]; - buf[0] = reg; - buf[1] = data; - - watch_i2c_send(addr, (uint8_t *)&buf, 2); -} - -uint8_t watch_i2c_read8(int16_t addr, uint8_t reg) { - uint8_t data; - - watch_i2c_send(addr, (uint8_t *)®, 1); - watch_i2c_receive(addr, (uint8_t *)&data, 1); - - return data; -} - -uint16_t watch_i2c_read16(int16_t addr, uint8_t reg) { - uint16_t data; - - watch_i2c_send(addr, (uint8_t *)®, 1); - watch_i2c_receive(addr, (uint8_t *)&data, 2); - - return data; -} - -uint32_t watch_i2c_read24(int16_t addr, uint8_t reg) { - uint32_t data; - data = 0; - - watch_i2c_send(addr, (uint8_t *)®, 1); - watch_i2c_receive(addr, (uint8_t *)&data, 3); - - return data << 8; -} - -uint32_t watch_i2c_read32(int16_t addr, uint8_t reg) { - uint32_t data; - - watch_i2c_send(addr, (uint8_t *)®, 1); - watch_i2c_receive(addr, (uint8_t *)&data, 4); - - return data; -} diff --git a/watch-library/watch/watch_i2c.h b/watch-library/watch/watch_i2c.h deleted file mode 100644 index fbcc1a92..00000000 --- a/watch-library/watch/watch_i2c.h +++ /dev/null @@ -1,106 +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_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 - * registers on I2C devices. - */ -/// @{ -/** @brief Enables the I2C peripheral. Call this before attempting to interface with I2C devices. - */ -void watch_enable_i2c(void); - -/** @brief Disables the I2C peripheral. - */ -void watch_disable_i2c(void); - -/** @brief Sends a series of values to a device on the I2C bus. - * @param addr The address of the device you wish to talk to. - * @param buf A series of unsigned bytes; the data you wish to transmit. - * @param length The number of bytes in buf that you wish to send. - */ -void watch_i2c_send(int16_t addr, uint8_t *buf, uint16_t length); - -/** @brief Receives a series of values from a device on the I2C bus. - * @param addr The address of the device you wish to hear from. - * @param buf Storage for the incoming bytes; on return, it will contain the received data. - * @param length The number of bytes that you wish to receive. - */ -void watch_i2c_receive(int16_t addr, uint8_t *buf, uint16_t length); - -/** @brief Writes a byte to a register in an I2C device. - * @param addr The address of the device you wish to address. - * @param reg The register on the device that you wish to set. - * @param data The value that you wish to set the register to. - */ -void watch_i2c_write8(int16_t addr, uint8_t reg, uint8_t data); - -/** @brief Reads a byte from a register in an I2C device. - * @param addr The address of the device you wish to address. - * @param reg The register on the device that you wish to read. - * @return An unsigned byte representing the value of the register that was read. - */ -uint8_t watch_i2c_read8(int16_t addr, uint8_t reg); - -/** @brief Reads an unsigned little-endian word from a register in an I2C device. - * @param addr The address of the device you wish to address. - * @param reg The register on the device that you wish to read. - * @return An unsigned word representing the value of the register that was read. - * @note This reads two bytes into the word in bus order. If the device returns - the LSB first and then the MSB, you can use this value as returned. - If the device returns the data in big-endian order or uses some other - kind of fancy bit packing, you may need to shuffle some bits around. - */ -uint16_t watch_i2c_read16(int16_t addr, uint8_t reg); - -/** @brief Reads three bytes as an unsigned little-endian int from a register in an I2C device. - * @param addr The address of the device you wish to address. - * @param reg The register on the device that you wish to read. - * @return An unsigned word representing the value of the register that was read. - * @note This reads three bytes into the word in bus order. If the device returns - these bytes LSB first, you can use this value as returned. If there is a - sign bit, the device returns the data in big-endian order, or it uses some - other kind of fancy bit packing, you may need to shuffle some bits around. - */ -uint32_t watch_i2c_read24(int16_t addr, uint8_t reg); - - -/** @brief Reads an unsigned little-endian int from a register in an I2C device. - * @param addr The address of the device you wish to address. - * @param reg The register on the device that you wish to read. - * @return An unsigned word representing the value of the register that was read. - * @note This reads three bytes into the word in bus order. If the device returns - these bytes LSB first, you can use this value as returned. If the device - returns the data in big-endian order, or it uses some other kind of fancy - bit packing, you may need to shuffle some bits around. - */ -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 deleted file mode 100644 index 52174b54..00000000 --- a/watch-library/watch/watch_led.c +++ /dev/null @@ -1,69 +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" - -void watch_enable_leds(void) { - if (!hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) { - _watch_enable_tcc(); - } -} - -void watch_disable_leds(void) { - _watch_disable_tcc(); -} - -void watch_enable_led(bool unused) { - (void)unused; - watch_enable_leds(); -} - -void watch_disable_led(bool unused) { - (void)unused; - watch_disable_leds(); -} - -void watch_set_led_color(uint8_t red, uint8_t green) { - if (hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) { - uint32_t period = hri_tcc_get_PER_reg(TCC0, TCC_PER_MASK); - hri_tcc_write_CCBUF_reg(TCC0, WATCH_RED_TCC_CHANNEL, ((period * red * 1000ull) / 255000ull)); - hri_tcc_write_CCBUF_reg(TCC0, WATCH_GREEN_TCC_CHANNEL, ((period * green * 1000ull) / 255000ull)); - } -} - -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/watch/watch_led.h b/watch-library/watch/watch_led.h deleted file mode 100644 index 9e9f5640..00000000 --- a/watch-library/watch/watch_led.h +++ /dev/null @@ -1,93 +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 LED=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 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); - -__attribute__((deprecated("Use watch_enable_leds instead"))) -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 deleted file mode 100644 index ae2589e7..00000000 --- a/watch-library/watch/watch_private.c +++ /dev/null @@ -1,423 +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_private.h" -#include "watch_utility.h" -#include "tusb.h" - -void _watch_init(void) { - // disable the LED pin (it may have been enabled by the bootloader) - watch_disable_digital_output(RED); - - // RAM should be back-biased in STANDBY - PM->STDBYCFG.bit.BBIASHS = 1; - - // Use switching regulator for lower power consumption. - SUPC->VREG.bit.SEL = 1; - while(!SUPC->STATUS.bit.VREGRDY); - - // set up the brownout detector (low battery warning) - NVIC_DisableIRQ(SYSTEM_IRQn); - NVIC_ClearPendingIRQ(SYSTEM_IRQn); - NVIC_EnableIRQ(SYSTEM_IRQn); - SUPC->BOD33.bit.ENABLE = 0; // BOD33 must be disabled to change its configuration - SUPC->BOD33.bit.VMON = 0; // Monitor VDD in active and standby mode - SUPC->BOD33.bit.ACTCFG = 1; // Enable sampling mode when active - SUPC->BOD33.bit.RUNSTDBY = 1; // Enable sampling mode in standby - SUPC->BOD33.bit.STDBYCFG = 1; // Run in standby - SUPC->BOD33.bit.RUNBKUP = 0; // Don't run in backup mode - SUPC->BOD33.bit.PSEL = 0xB; // Check battery level every 4 seconds - SUPC->BOD33.bit.LEVEL = 31; // Detect brownout at 2.5V (1.445V + level * 34mV) - SUPC->BOD33.bit.ACTION = 0x2; // Generate an interrupt when BOD33 is triggered - SUPC->BOD33.bit.HYST = 0; // Disable hysteresis - while(!SUPC->STATUS.bit.B33SRDY); - - // Enable interrupt on BOD33 detect - SUPC->INTENSET.bit.BOD33DET = 1; - SUPC->BOD33.bit.ENABLE = 1; - - // External wake depends on RTC; calendar is a required module. - _watch_rtc_init(); - - // set up state - btn_alarm_callback = NULL; - a2_callback = NULL; - a4_callback = NULL; -} - -static inline void _watch_wait_for_entropy() { - while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); -} - -// this function is called by arc4random to get entropy for random number generation. -// let's use the SAM L22's true random number generator to seed the PRNG! -int getentropy(void *buf, size_t buflen) { - hri_mclk_set_APBCMASK_TRNG_bit(MCLK); - hri_trng_set_CTRLA_ENABLE_bit(TRNG); - - size_t i = 0; - while(i < buflen / 4) { - _watch_wait_for_entropy(); - ((uint32_t *)buf)[i++] = hri_trng_read_DATA_reg(TRNG); - } - - // but what if they asked for an awkward number of bytes? - if (buflen % 4) { - // all good: let's fill in one, two or three bytes at the end of the buffer. - _watch_wait_for_entropy(); - uint32_t last_little_bit = hri_trng_read_DATA_reg(TRNG); - for(size_t j = 0; j <= (buflen % 4); j++) { - ((uint8_t *)buf)[i * 4 + j] = (last_little_bit >> (j * 8)) & 0xFF; - } - } - - hri_trng_clear_CTRLA_ENABLE_bit(TRNG); - hri_mclk_clear_APBCMASK_TRNG_bit(MCLK); - - return 0; -} - -int _gettimeofday(struct timeval *tv, void *tzvp) { - (void)tzvp; - watch_date_time date_time = watch_rtc_get_date_time(); - - // FIXME: this assumes the system time is UTC! Will break for any other time zone. - tv->tv_sec = watch_utility_date_time_to_unix_time(date_time, 0); - tv->tv_usec = 0; - - return 0; -} - -void _watch_enable_tcc(void) { - // clock TCC0 with the main clock (8 MHz) and enable the peripheral clock. - hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN); - hri_mclk_set_APBCMASK_TCC0_bit(MCLK); - // disable and reset TCC0. - hri_tcc_clear_CTRLA_ENABLE_bit(TCC0); - hri_tcc_wait_for_sync(TCC0, TCC_SYNCBUSY_ENABLE); - hri_tcc_write_CTRLA_reg(TCC0, TCC_CTRLA_SWRST); - hri_tcc_wait_for_sync(TCC0, TCC_SYNCBUSY_SWRST); - // divide the clock down to 1 MHz - if (hri_usbdevice_get_CTRLA_ENABLE_bit(USB)) { - // if USB is enabled, we are running an 8 MHz clock. - hri_tcc_write_CTRLA_reg(TCC0, TCC_CTRLA_PRESCALER_DIV8); - } else { - // otherwise it's 4 Mhz. - hri_tcc_write_CTRLA_reg(TCC0, TCC_CTRLA_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[2] and CC[3] can be set to any value from 0 (off) to PER (fully on). - hri_tcc_write_WAVE_reg(TCC0, TCC_WAVE_WAVEGEN_NPWM); - #ifdef WATCH_INVERT_LED_POLARITY - // This is here for the dev board, which uses a common anode LED (instead of common cathode like the actual watch). - hri_tcc_set_WAVE_reg(TCC0, (1 << (TCC_WAVE_POL0_Pos + WATCH_RED_TCC_CHANNEL)) | - (1 << (TCC_WAVE_POL0_Pos + WATCH_GREEN_TCC_CHANNEL))); - #endif - // The buzzer will set the period depending on the tone it wants to play, but we have to set some period here to - // get the LED working. Almost any period will do, tho it should be below 20000 (i.e. 50 Hz) to avoid flickering. - hri_tcc_write_PER_reg(TCC0, 4096); - // Set the duty cycle of all pins to 0: LED's off, buzzer not buzzing. - hri_tcc_write_CC_reg(TCC0, WATCH_BUZZER_TCC_CHANNEL, 0); - hri_tcc_write_CC_reg(TCC0, WATCH_RED_TCC_CHANNEL, 0); - hri_tcc_write_CC_reg(TCC0, WATCH_GREEN_TCC_CHANNEL, 0); - // Enable the TCC - hri_tcc_set_CTRLA_ENABLE_bit(TCC0); - hri_tcc_wait_for_sync(TCC0, TCC_SYNCBUSY_ENABLE); - - // enable LED PWM pins (the LED driver assumes if the TCC is on, the pins are enabled) - gpio_set_pin_direction(RED, GPIO_DIRECTION_OUT); - gpio_set_pin_function(RED, WATCH_RED_TCC_PINMUX); - gpio_set_pin_direction(GREEN, GPIO_DIRECTION_OUT); - gpio_set_pin_function(GREEN, WATCH_GREEN_TCC_PINMUX); -} - -void _watch_disable_tcc(void) { - // disable all PWM pins - gpio_set_pin_direction(BUZZER, GPIO_DIRECTION_OFF); - gpio_set_pin_function(BUZZER, GPIO_PIN_FUNCTION_OFF); - gpio_set_pin_direction(RED, GPIO_DIRECTION_OFF); - gpio_set_pin_function(RED, GPIO_PIN_FUNCTION_OFF); - gpio_set_pin_direction(GREEN, GPIO_DIRECTION_OFF); - gpio_set_pin_function(GREEN, GPIO_PIN_FUNCTION_OFF); - - // disable the TCC - hri_tcc_clear_CTRLA_ENABLE_bit(TCC0); - hri_mclk_clear_APBCMASK_TCC0_bit(MCLK); -} - -void _watch_enable_usb(void) { - // disable USB, just in case. - hri_usb_clear_CTRLA_ENABLE_bit(USB); - - // bump clock up to 8 MHz - hri_oscctrl_write_OSC16MCTRL_FSEL_bf(OSCCTRL, OSCCTRL_OSC16MCTRL_FSEL_8_Val); - - // reset flags and disable DFLL - OSCCTRL->INTFLAG.reg = OSCCTRL_INTFLAG_DFLLRDY; - OSCCTRL->DFLLCTRL.reg = 0; - while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)); - - // set the coarse and fine values to speed up frequency lock. - uint32_t coarse =(*((uint32_t *)NVMCTRL_OTP5)) >> 26; - OSCCTRL->DFLLVAL.reg = OSCCTRL_DFLLVAL_COARSE(coarse) | - OSCCTRL_DFLLVAL_FINE(0x200); - // set coarse and fine steps, and multiplier (48 MHz = 32768 Hz * 1465) - OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP( 1 ) | - OSCCTRL_DFLLMUL_FSTEP( 1 ) | - OSCCTRL_DFLLMUL_MUL( 1465 ); - // set closed loop mode, chill cycle disable and USB clock recovery mode, and enable the DFLL. - OSCCTRL->DFLLCTRL.reg = OSCCTRL_DFLLCTRL_MODE | OSCCTRL_DFLLCTRL_CCDIS | OSCCTRL_DFLLCTRL_ONDEMAND | OSCCTRL_DFLLCTRL_RUNSTDBY | OSCCTRL_DFLLCTRL_USBCRM | OSCCTRL_DFLLCTRL_ENABLE; - while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)); - - // assign DFLL to GCLK1 - GCLK->GENCTRL[1].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL48M) | GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_GENEN;// | GCLK_GENCTRL_OE; - while (GCLK->SYNCBUSY.bit.GENCTRL1); - - // assign GCLK1 to USB - hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN); - hri_mclk_set_AHBMASK_USB_bit(MCLK); - hri_mclk_set_APBBMASK_USB_bit(MCLK); - - // USB Pin Init - gpio_set_pin_direction(PIN_PA24, GPIO_DIRECTION_OUT); - gpio_set_pin_level(PIN_PA24, false); - gpio_set_pin_pull_mode(PIN_PA24, GPIO_PULL_OFF); - gpio_set_pin_direction(PIN_PA25, GPIO_DIRECTION_OUT); - gpio_set_pin_level(PIN_PA25, false); - gpio_set_pin_pull_mode(PIN_PA25, GPIO_PULL_OFF); - - gpio_set_pin_function(PIN_PA24, PINMUX_PA24G_USB_DM); - gpio_set_pin_function(PIN_PA25, PINMUX_PA25G_USB_DP); - - // before we init TinyUSB, we are going to need a periodic callback to handle TinyUSB tasks. - // TC2 and TC3 are reserved for devices on the 9-pin connector, so let's use TC0. - // clock TC0 with the 8 MHz clock on GCLK0. - hri_gclk_write_PCHCTRL_reg(GCLK, TC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN); - // and enable the peripheral clock. - hri_mclk_set_APBCMASK_TC0_bit(MCLK); - // disable and reset TC0. - hri_tc_clear_CTRLA_ENABLE_bit(TC0); - hri_tc_wait_for_sync(TC0, TC_SYNCBUSY_ENABLE); - hri_tc_write_CTRLA_reg(TC0, TC_CTRLA_SWRST); - hri_tc_wait_for_sync(TC0, TC_SYNCBUSY_SWRST); - // configure the TC to overflow 1,000 times per second - hri_tc_write_CTRLA_reg(TC0, TC_CTRLA_PRESCALER_DIV64 | // divide the 8 MHz clock by 64 to count at 125 KHz - TC_CTRLA_MODE_COUNT8 | // count in 8-bit mode - TC_CTRLA_RUNSTDBY); // run in standby, just in case we figure that out - hri_tccount8_write_PER_reg(TC0, 125); // 125000 Hz / 125 = 1,000 Hz - // set an interrupt on overflow; this will call TC0_Handler below. - hri_tc_set_INTEN_OVF_bit(TC0); - NVIC_ClearPendingIRQ(TC0_IRQn); - NVIC_EnableIRQ (TC0_IRQn); - - // now we can init TinyUSB - tusb_init(); - // and start the timer that handles USB device tasks. - hri_tc_set_CTRLA_ENABLE_bit(TC0); -} - -// this function ends up getting called by printf to log stuff to the USB console. -int _write(int file, char *ptr, int len) { - (void)file; - if (hri_usbdevice_get_CTRLA_ENABLE_bit(USB)) { - tud_cdc_n_write(0, (void const*)ptr, len); - tud_cdc_n_write_flush(0); - return len; - } - - return 0; -} - -// this method could be overridden to read stuff from the USB console? but no need rn. -int _read(void) { - return 0; -} - -// Alternate function that outputs to the debug UART. useful for debugging USB issues. -// int _write(int file, char *ptr, int len) { -// (void)file; -// int pos = 0; -// while(pos < len) watch_debug_putc(ptr[pos++]); - -// return 0; -// } - -void USB_Handler(void) { - tud_int_handler(0); -} - -void TC0_Handler(void) { - tud_task(); - TC0->COUNT8.INTFLAG.reg |= TC_INTFLAG_OVF; -} - - -// USB Descriptors and tinyUSB callbacks follow. - -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * 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. - * - */ - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -tusb_desc_device_t const desc_device = -{ - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, - - // Use Interface Association Descriptor (IAD) for CDC - // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, - - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = 0x1209, - .idProduct = 0x2151, - .bcdDevice = 0x0100, - - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, - - .bNumConfigurations = 0x01 -}; - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) { - return (uint8_t const *) &desc_device; -} - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ - -enum { - ITF_NUM_CDC = 0, - ITF_NUM_CDC_DATA, - ITF_NUM_TOTAL -}; - -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN) - -#define EPNUM_CDC_NOTIF 0x81 -#define EPNUM_CDC_OUT 0x02 -#define EPNUM_CDC_IN 0x82 - - -uint8_t const desc_fs_configuration[] = { - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), - - // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), -}; - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { - (void) index; // for multiple configurations - return desc_fs_configuration; -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// array of pointer to string descriptors -char const* string_desc_arr [] = -{ - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - "123456", // 3: Serials, should use chip ID - "TinyUSB CDC", // 4: CDC Interface -}; - -static uint16_t _desc_str[32]; - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) -{ - (void) langid; - - uint8_t chr_count; - - if ( index == 0) { - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - } else { - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; - - const char* str = string_desc_arr[index]; - - // Cap at max char - chr_count = strlen(str); - if ( chr_count > 31 ) chr_count = 31; - - // Convert ASCII string into UTF-16 - for(uint8_t i=0; i<chr_count; i++) - { - _desc_str[1+i] = str[i]; - } - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2); - - return _desc_str; -} diff --git a/watch-library/watch/watch_private.h b/watch-library/watch/watch_private.h deleted file mode 100644 index 7bb91d1f..00000000 --- a/watch-library/watch/watch_private.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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_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(void); - -/// Initializes the real-time clock peripheral. -void _watch_rtc_init(void); - -/// Called by buzzer and LED setup functions. You should not call this from your app. -void _watch_enable_tcc(void); - -/// Called by buzzer and LED teardown functions. You should not call this from your app. -void _watch_disable_tcc(void); - -/// Called by main.c if plugged in to USB. You should not call this from your app. -void _watch_enable_usb(void); - -// this function ends up getting called by printf to log stuff to the USB console. -int _write(int file, char *ptr, int len); - -// this method could be overridden to read stuff from the USB console? but no need rn. -int _read(void); - -#endif diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c deleted file mode 100644 index 14a968c4..00000000 --- a/watch-library/watch/watch_rtc.c +++ /dev/null @@ -1,195 +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_rtc.h" - -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; -ext_irq_cb_t a4_callback; - -bool _watch_rtc_is_enabled(void) { - return RTC->MODE2.CTRLA.bit.ENABLE; -} - -static void _sync_rtc(void) { - while (RTC->MODE2.SYNCBUSY.reg); -} - -void _watch_rtc_init(void) { - 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.reg = date_time.reg; - _sync_rtc(); -} - -watch_date_time watch_rtc_get_date_time(void) { - watch_date_time retval; - - _sync_rtc(); - retval.reg = RTC->MODE2.CLOCK.reg; - - return retval; -} - -void watch_rtc_register_tick_callback(ext_irq_cb_t callback) { - watch_rtc_register_periodic_callback(callback, 1); -} - -void watch_rtc_disable_tick_callback(void) { - watch_rtc_disable_periodic_callback(1); -} - -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(frequency) != 1) return; - - // this left-justifies the period in a 32-bit integer. - 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); - - // 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 = 1 << per_n; -} - -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_periodic_callbacks(void) { - 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) { - 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); - NVIC_EnableIRQ(RTC_IRQn); - RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0; -} - -void watch_rtc_disable_alarm_callback(void) { - 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_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; - } - } - } 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(); - } 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; - } 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; - } -} - -/////////////////////// -// 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; -} - -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 deleted file mode 100644 index 6dac63f5..00000000 --- a/watch-library/watch/watch_rtc.h +++ /dev/null @@ -1,164 +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_RTC_H_INCLUDED -#define _WATCH_RTC_H_INCLUDED -////< @file watch_rtc.h - -#include "watch.h" -#include "hpl_calendar.h" - -/** @addtogroup rtc Real-Time Clock - * @brief This section covers functions related to the SAM L22's real-time clock peripheral, including - * date, time and alarm functions. - * @details The real-time clock is the only peripheral that main.c enables for you. It is the cornerstone - * of low power operation on the watch, and it is required for several key functions that we - * assume will be available, namely the wake from BACKUP mode and the callback on the ALARM button. - * It is also required for the operation of the 1 Hz tick interrupt, which you will most likely use - * to wake from STANDBY mode. - */ -/// @{ - -#define WATCH_RTC_REFERENCE_YEAR (2020) - -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 { - 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 should always return true. - */ -bool _watch_rtc_is_enabled(void); - -/** @brief Sets the date and time. - * @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 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(void); - -/** @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 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. - * 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(void); - -/** @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_tick_callback(ext_irq_cb_t callback); - -/** @brief Disables the tick callback for the given period. - */ -void watch_rtc_disable_tick_callback(void); - -/** @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 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 - * 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_periodic_callback(ext_irq_cb_t callback, uint8_t frequency); - -/** @brief Disables the tick callback for the given period. - * @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_periodic_callback(uint8_t frequency); - -/** @brief Disables all periodic callbacks, including the once-per-second tick callback. - */ -void watch_rtc_disable_all_periodic_callbacks(void); - -/** @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 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. 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_tick_callback function instead"))) -void watch_register_tick_callback(ext_irq_cb_t callback); - -/// @} -#endif diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c deleted file mode 100644 index 1b1e53e4..00000000 --- a/watch-library/watch/watch_slcd.c +++ /dev/null @@ -1,318 +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_slcd.h" -#include "hpl_slcd_config.h" - - ////////////////////////////////////////////////////////////////////////////////////////// -// Segmented Display - -static const uint8_t Character_Set[] = -{ - 0b00000000, // - 0b01100000, // ! (L in the top half for positions 4 and 6) - 0b00100010, // " - 0b01100011, // # (degree symbol, hash mark doesn't fit) - 0b00000000, // $ (unused) - 0b00000000, // % (unused) - 0b01000100, // & ("lowercase 7" for positions 4 and 6) - 0b00100000, // ' - 0b00111001, // ( - 0b00001111, // ) - 0b00000000, // * (unused) - 0b11000000, // + (only works in position 0) - 0b00000100, // , - 0b01000000, // - - 0b01000000, // . (same as -, semantically most useful) - 0b00010010, // / - 0b00111111, // 0 - 0b00000110, // 1 - 0b01011011, // 2 - 0b01001111, // 3 - 0b01100110, // 4 - 0b01101101, // 5 - 0b01111101, // 6 - 0b00000111, // 7 - 0b01111111, // 8 - 0b01101111, // 9 - 0b00000000, // : (unused) - 0b00000000, // ; (unused) - 0b01011000, // < - 0b01001000, // = - 0b01001100, // > - 0b01010011, // ? - 0b11111111, // @ (all segments on) - 0b01110111, // A - 0b01111111, // B - 0b00111001, // C - 0b00111111, // D - 0b01111001, // E - 0b01110001, // F - 0b00111101, // G - 0b01110110, // H - 0b10001001, // I (only works in position 0) - 0b00001110, // J - 0b01110101, // K - 0b00111000, // L - 0b10110111, // M (only works in position 0) - 0b00110111, // N - 0b00111111, // O - 0b01110011, // P - 0b01100111, // Q - 0b11110111, // R (only works in position 1) - 0b01101101, // S - 0b10000001, // T (only works in position 0; set (1, 12) to make it work in position 1) - 0b00111110, // U - 0b00111110, // V - 0b10111110, // W (only works in position 0) - 0b01111110, // X - 0b01101110, // Y - 0b00011011, // Z - 0b00111001, // [ - 0b00100100, // backslash - 0b00001111, // ] - 0b00100011, // ^ - 0b00001000, // _ - 0b00000010, // ` - 0b01011111, // a - 0b01111100, // b - 0b01011000, // c - 0b01011110, // d - 0b01111011, // e - 0b01110001, // f - 0b01101111, // g - 0b01110100, // h - 0b00010000, // i - 0b01000010, // j (appears as superscript to work in more positions) - 0b01110101, // k - 0b00110000, // l - 0b10110111, // m (only works in position 0) - 0b01010100, // n - 0b01011100, // o - 0b01110011, // p - 0b01100111, // q - 0b01010000, // r - 0b01101101, // s - 0b01111000, // t - 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 - 0b00011011, // z - 0b00111001, // { - 0b00110000, // | - 0b00001111, // } - 0b00000001, // ~ -}; - -static const uint64_t Segment_Map[] = { - 0x4e4f0e8e8f8d4d0d, // Position 0, mode - 0xc8c4c4c8b4b4b0b, // Position 1, mode (Segments B and C shared, as are segments E and F) - 0xc049c00a49890949, // Position 2, day of month (Segments A, D, G shared; missing segment F) - 0xc048088886874707, // Position 3, day of month - 0xc053921252139352, // Position 4, clock hours (Segments A and D shared) - 0xc054511415559594, // Position 5, clock hours - 0xc057965616179716, // Position 6, clock minutes (Segments A and D shared) - 0xc041804000018a81, // Position 7, clock minutes - 0xc043420203048382, // Position 8, clock seconds - 0xc045440506468584, // Position 9, clock seconds -}; - -static const uint8_t Num_Chars = 10; - -static const uint32_t IndicatorSegments[6] = { - SLCD_SEGID(0, 17), // WATCH_INDICATOR_SIGNAL - SLCD_SEGID(0, 16), // WATCH_INDICATOR_BELL - SLCD_SEGID(2, 17), // WATCH_INDICATOR_PM - SLCD_SEGID(2, 16), // WATCH_INDICATOR_24H - SLCD_SEGID(1, 10), // WATCH_INDICATOR_LAP -}; - -static void _sync_slcd(void) { - while (SLCD->SYNCBUSY.reg); -} - -void watch_enable_display(void) { - SEGMENT_LCD_0_init(); - slcd_sync_enable(&SEGMENT_LCD_0); -} - -inline void watch_set_pixel(uint8_t com, uint8_t seg) { - slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(com, seg)); -} - -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(void) { - SLCD->SDATAL0.reg = 0; - SLCD->SDATAL1.reg = 0; - SLCD->SDATAL2.reg = 0; -} - -static void watch_display_character(uint8_t character, uint8_t position) { - // special cases for positions 4 and 6 - if (position == 4 || position == 6) { - if (character == '7') character = '&'; // "lowercase" 7 - else if (character == 'A') character = 'a'; // A needs to be lowercase - else if (character == 'o') character = 'O'; // O needs to be uppercase - else if (character == 'L') character = '!'; // L needs to be in top half - else if (character == 'M' || character == 'm' || character == 'N') character = 'n'; // M and uppercase N need to be lowercase n - else if (character == 'c') character = 'C'; // C needs to be uppercase - else if (character == 'J') character = 'j'; // same - else if (character == 'v' || character == 'V' || character == 'U' || character == 'W' || character == 'w') character = 'u'; // bottom segment duplicated, so show in top half - } else { - if (character == 'u') character = 'v'; // we can use the bottom segment; move to lower half - else if (character == 'j') character = 'J'; // same but just display a normal J - } - if (position > 1) { - if (character == 'T') character = 't'; // uppercase T only works in positions 0 and 1 - } - if (position == 1) { - if (character == 'o') character = 'O'; // O needs to be uppercase - if (character == 'i') character = 'l'; // I needs to be uppercase (use an l, it looks the same) - if (character == 'n') character = 'N'; // N needs to be uppercase - if (character == 'r') character = 'R'; // R needs to be uppercase - if (character == 'd') character = 'D'; // D needs to be uppercase - if (character == 'v' || character == 'V' || character == 'u') character = 'U'; // side segments shared, make uppercase - if (character == 'b') character = 'B'; // B needs to be uppercase - if (character == 'c') character = 'C'; // C needs to be uppercase - } else { - if (character == 'R') character = 'r'; // R needs to be lowercase almost everywhere - } - if (position == 0) { - slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(0, 15)); // clear funky ninth segment - } else { - if (character == 'I') character = 'l'; // uppercase I only works in position 0 - } - - uint64_t segmap = Segment_Map[position]; - uint64_t segdata = Character_Set[character - 0x20]; - - for (int i = 0; i < 8; i++) { - uint8_t com = (segmap & 0xFF) >> 6; - if (com > 2) { - // COM3 means no segment exists; skip it. - segmap = segmap >> 8; - segdata = segdata >> 1; - continue; - } - uint8_t seg = segmap & 0x3F; - slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(com, seg)); - if (segdata & 1) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(com, seg)); - segmap = segmap >> 8; - segdata = segdata >> 1; - } - 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 == 1 && (character == 'B' || character == 'D' || character == '@')) slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(0, 12)); // add funky ninth segment -} - -void watch_display_string(char *string, uint8_t position) { - size_t i = 0; - while(string[i] != 0) { - watch_display_character(string[i], position + i); - i++; - if (position + i >= Num_Chars) break; - } - // uncomment this line to see screen output on terminal, i.e. - // FR 29 - // 11 50 23 - // note that for partial displays (positon > 0) it will only show the characters that were updated. - // printf("________\n %c%c %c%c\n%c%c %c%c %c%c\n--------\n", (position > 0) ? ' ' : string[0], (position > 1) ? ' ' : string[1 - position], (position > 2) ? ' ' : string[2 - position], (position > 3) ? ' ' : string[3 - position], (position > 4) ? ' ' : string[4 - position], (position > 5) ? ' ' : string[5 - position], (position > 6) ? ' ' : string[6 - position], (position > 7) ? ' ' : string[7 - position], (position > 8) ? ' ' : string[8 - position], (position > 9) ? ' ' : string[9 - position]); -} - -inline void watch_set_colon(void) { - slcd_sync_seg_on(&SEGMENT_LCD_0, SLCD_SEGID(1, 16)); -} - -inline void watch_clear_colon(void) { - slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(1, 16)); -} - -inline void watch_set_indicator(WatchIndicatorSegment indicator) { - slcd_sync_seg_on(&SEGMENT_LCD_0, IndicatorSegments[indicator]); -} - -inline void watch_clear_indicator(WatchIndicatorSegment indicator) { - slcd_sync_seg_off(&SEGMENT_LCD_0, IndicatorSegments[indicator]); -} - -void watch_clear_all_indicators(void) { - slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(2, 17)); - slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(2, 16)); - slcd_sync_seg_off(&SEGMENT_LCD_0, SLCD_SEGID(0, 17)); - 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(void) { - 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); -} - -bool watch_tick_animation_is_running(void) { - return hri_slcd_get_CTRLD_CSREN_bit(SLCD); -} - -void watch_stop_tick_animation(void) { - 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 deleted file mode 100644 index 3f550bb0..00000000 --- a/watch-library/watch/watch_slcd.h +++ /dev/null @@ -1,151 +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_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. - * @details The segment LCD controller consumes about 3 microamperes of power with no segments on, and - * about 4 microamperes with all segments on. There is also a slight power impact associated - * with updating the screen (about 1 microampere to update at 1 Hz). For the absolute lowest - * power operation, update the display only when its contents have changed, and disable the - * SLCD peripheral when the screen is not in use. - * For a map of all common and segment pins, see <a href="segmap.html">segmap.html</a>. You can - * hover over any segment in that diagram to view the common and segment pins associated with - * each segment of the display. - */ -/// @{ - -/// An enum listing the icons and indicators available on the watch. -typedef enum WatchIndicatorSegment { - WATCH_INDICATOR_SIGNAL = 0, ///< The hourly signal indicator; also useful for indicating that sensors are on. - WATCH_INDICATOR_BELL, ///< The small bell indicating that an alarm is set. - WATCH_INDICATOR_PM, ///< The PM indicator, indicating that a time is in the afternoon. - WATCH_INDICATOR_24H, ///< The 24H indicator, indicating that the watch is in a 24-hour mode. - WATCH_INDICATOR_LAP ///< The LAP indicator; the F-91W uses this in its stopwatch UI. -} WatchIndicatorSegment; - -/** @brief Enables the Segment LCD display. - * Call this before attempting to set pixels or display strings. - */ -void watch_enable_display(void); - -/** @brief Sets a pixel. Use this to manually set a pixel with a given common and segment number. - * See <a href="segmap.html">segmap.html</a>. - * @param com the common pin, numbered from 0-2. - * @param seg the segment pin, numbered from 0-23. - */ -void watch_set_pixel(uint8_t com, uint8_t seg); - -/** @brief Clears a pixel. Use this to manually clear a pixel with a given common and segment number. - * See <a href="segmap.html">segmap.html</a>. - * @param com the common pin, numbered from 0-2. - * @param seg the segment pin, numbered from 0-23. - */ -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(void); - -/** @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. - * @param position The position where you wish to start displaying the string. The day of week digits - * are positions 0 and 1; the day of month digits are positions 2 and 3, and the main - * clock line occupies positions 4-9. - * @note This method does not clear the display; if for example you display a two-character string at - position 0, positions 2-9 will retain whatever state they were previously displaying. - */ -void watch_display_string(char *string, uint8_t position); - -/** @brief Turns the colon segment on. - */ -void watch_set_colon(void); - -/** @brief Turns the colon segment off. - */ -void watch_clear_colon(void); - -/** @brief Sets an indicator on the LCD. Use this to turn on one of the indicator segments. - * @param indicator One of the indicator segments from the enum. @see WatchIndicatorSegment - */ -void watch_set_indicator(WatchIndicatorSegment indicator); - -/** @brief Clears an indicator on the LCD. Use this to turn off one of the indicator segments. - * @param indicator One of the indicator segments from the enum. @see WatchIndicatorSegment - */ -void watch_clear_indicator(WatchIndicatorSegment indicator); - -/** @brief Clears all indicator segments. - * @see WatchIndicatorSegment - */ -void watch_clear_all_indicators(void); - -/** @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 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. - * 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(void); - -/** @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 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); - -/** @brief Checks if the tick animation is currently running. - * @return true if the animation is running; false otherwise. - */ -bool watch_tick_animation_is_running(void); - -/** @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(void); -/// @} -#endif diff --git a/watch-library/watch/watch_uart.c b/watch-library/watch/watch_uart.c deleted file mode 100644 index 64b63bee..00000000 --- a/watch-library/watch/watch_uart.c +++ /dev/null @@ -1,89 +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. - */ - - /* - * UART methods are Copyright (c) 2014-2017, Alex Taradov <alex@taradov.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER 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. - */ - -#include "watch_uart.h" -#include "peripheral_clk_config.h" - -void watch_enable_debug_uart(uint32_t baud) { - uint64_t br = (uint64_t)65536 * ((CONF_CPU_FREQUENCY * 4) - 16 * baud) / (CONF_CPU_FREQUENCY * 4); - - gpio_set_pin_direction(A2, GPIO_DIRECTION_OUT); - gpio_set_pin_function(A2, PINMUX_PB02C_SERCOM3_PAD0); - - MCLK->APBCMASK.reg |= MCLK_APBCMASK_SERCOM3; - - GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN(0) | GCLK_PCHCTRL_CHEN; - while (0 == (GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg & GCLK_PCHCTRL_CHEN)); - - SERCOM3->USART.CTRLA.reg = - SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE(1/*USART_INT_CLK*/) | - SERCOM_USART_CTRLA_RXPO(1/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(0/*PAD0*/); - - SERCOM3->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | - SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/); - - SERCOM3->USART.BAUD.reg = (uint16_t)br; - - SERCOM3->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; -} - -void watch_debug_putc(char c) { - while (!(SERCOM3->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)); - SERCOM3->USART.DATA.reg = c; -} - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -void watch_debug_puts(char *s) { - while (*s) watch_debug_putc(*s++); -} -#pragma GCC diagnostic pop diff --git a/watch-library/watch/watch_uart.h b/watch-library/watch/watch_uart.h deleted file mode 100644 index 3e98bd35..00000000 --- a/watch-library/watch/watch_uart.h +++ /dev/null @@ -1,58 +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_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. - * @warning These functions were used early on in development, before the TinyUSB - * CDC was implemented. You can now print debug messages to the USB console - * using printf, rendering this bit irrelevant. These methods will likely - * be refactored out in the future, in favor of a more full-featured UART - * on the nine-pin connector. - **/ -/// @{ -/** @brief Initializes the debug UART. - * @param baud The baud rate - */ -__attribute__((deprecated("Use printf to log debug messages over USB."))) -void watch_enable_debug_uart(uint32_t baud); - -/** @brief Outputs a single character on the debug UART. - * @param c The character you wish to output. - */ -__attribute__((deprecated("Use printf to log debug messages over USB."))) -void watch_debug_putc(char c); - -/** @brief Outputs a string on the debug UART. - * @param s A null-terminated string. - */ -__attribute__((deprecated("Use printf to log debug messages over USB."))) -void watch_debug_puts(char *s); -/// @} -#endif diff --git a/watch-library/watch/watch_utility.c b/watch-library/watch/watch_utility.c deleted file mode 100644 index 835076d9..00000000 --- a/watch-library/watch/watch_utility.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 <math.h> -#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]; -} - -uint32_t watch_utility_convert_to_unix_time(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t utc_offset) { - uint16_t DAYS_SO_FAR[] = { - 0, // Jan - 31, // Feb - 59, // March - 90, // April - 120, // May - 151, // June - 181, // July - 212, // August - 243, // September - 273, // October - 304, // November - 334 // December - }; - - uint32_t year_adj = year + 4800; - uint32_t febs = year_adj - (month <= 2 ? 1 : 0); /* Februaries since base. */ - uint32_t leap_days = 1 + (febs / 4) - (febs / 100) + (febs / 400); - uint32_t days = 365 * year_adj + leap_days + DAYS_SO_FAR[month - 1] + day - 1; - days -= 2472692; /* Adjust to Unix epoch. */ - - uint32_t timestamp = days * 86400; - timestamp += hour * 3600; - timestamp += minute * 60; - timestamp += second; - timestamp -= utc_offset; - - return timestamp; -} - -uint32_t watch_utility_date_time_to_unix_time(watch_date_time date_time, uint32_t utc_offset) { - return watch_utility_convert_to_unix_time(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR, date_time.unit.month, date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second, utc_offset); -} - -#define LEAPOCH (946684800LL + 86400*(31+29)) - -#define DAYS_PER_400Y (365*400 + 97) -#define DAYS_PER_100Y (365*100 + 24) -#define DAYS_PER_4Y (365*4 + 1) - -watch_date_time watch_utility_date_time_from_unix_time(uint32_t timestamp, uint32_t utc_offset) { - watch_date_time retval; - retval.reg = 0; - int32_t days, secs; - int32_t remdays, remsecs, remyears; - int32_t qc_cycles, c_cycles, q_cycles; - int32_t years, months; - int32_t wday, yday, leap; - static const int8_t days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29}; - timestamp += utc_offset; - - secs = timestamp - LEAPOCH; - days = secs / 86400; - remsecs = secs % 86400; - if (remsecs < 0) { - remsecs += 86400; - days--; - } - - wday = (3+days)%7; - if (wday < 0) wday += 7; - - qc_cycles = (int)(days / DAYS_PER_400Y); - remdays = days % DAYS_PER_400Y; - if (remdays < 0) { - remdays += DAYS_PER_400Y; - qc_cycles--; - } - - c_cycles = remdays / DAYS_PER_100Y; - if (c_cycles == 4) c_cycles--; - remdays -= c_cycles * DAYS_PER_100Y; - - q_cycles = remdays / DAYS_PER_4Y; - if (q_cycles == 25) q_cycles--; - remdays -= q_cycles * DAYS_PER_4Y; - - remyears = remdays / 365; - if (remyears == 4) remyears--; - remdays -= remyears * 365; - - leap = !remyears && (q_cycles || !c_cycles); - yday = remdays + 31 + 28 + leap; - if (yday >= 365+leap) yday -= 365+leap; - - years = remyears + 4*q_cycles + 100*c_cycles + 400*qc_cycles; - - for (months=0; days_in_month[months] <= remdays; months++) - remdays -= days_in_month[months]; - - years += 2000; - - months += 2; - if (months >= 12) { - months -=12; - years++; - } - - if (years < 2020 || years > 2083) return retval; - retval.unit.year = years - WATCH_RTC_REFERENCE_YEAR; - retval.unit.month = months + 1; - retval.unit.day = remdays + 1; - - retval.unit.hour = remsecs / 3600; - retval.unit.minute = remsecs / 60 % 60; - retval.unit.second = remsecs % 60; - - return retval; -} - -watch_date_time watch_utility_date_time_convert_zone(watch_date_time date_time, uint32_t origin_utc_offset, uint32_t destination_utc_offset) { - uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, origin_utc_offset); - return watch_utility_date_time_from_unix_time(timestamp, destination_utc_offset); -} - -float watch_utility_thermistor_temperature(uint16_t value, bool highside, float b_coefficient, float nominal_temperature, float nominal_resistance, float series_resistance) { - float reading = (float)value; - - if (highside) { - reading = (1023.0 * series_resistance) / (reading / 64.0); - reading -= series_resistance; - } else { - reading = series_resistance / (65535.0 / value - 1.0); - } - - reading = reading / nominal_resistance; - reading = log(reading); - reading /= b_coefficient; - reading += 1.0 / (nominal_temperature + 273.15); - reading = 1.0 / reading; - reading -= 273.15; - - return reading; -} diff --git a/watch-library/watch/watch_utility.h b/watch-library/watch/watch_utility.h deleted file mode 100644 index 66af6ed5..00000000 --- a/watch-library/watch/watch_utility.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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); - -/** @brief Returns the UNIX time (seconds since 1970) for a given date/time in UTC. - * @param date_time The watch_date_time that you wish to convert. - * @param year The year of the date you wish to convert. - * @param month The month of the date you wish to convert. - * @param day The day of the date you wish to convert. - * @param hour The hour of the date you wish to convert. - * @param minute The minute of the date you wish to convert. - * @param second The second of the date you wish to convert. - * @param utc_offset The number of seconds that date_time is offset from UTC, or 0 if the time is UTC. - * @return A UNIX timestamp for the given date/time and UTC offset. - * @note Implemented by Wesley Ellis (tahnok) and based on BSD-licensed code by Josh Haberman: - * https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html - */ -uint32_t watch_utility_convert_to_unix_time(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t utc_offset); - -/** @brief Returns the UNIX time (seconds since 1970) for a given watch_date_time struct. - * @param date_time The watch_date_time that you wish to convert. - * @param utc_offset The number of seconds that date_time is offset from UTC, or 0 if the time is UTC. - * @return A UNIX timestamp for the given watch_date_time and UTC offset. - */ -uint32_t watch_utility_date_time_to_unix_time(watch_date_time date_time, uint32_t utc_offset); - -/** @brief Returns the UNIX time (seconds since 1970) for a given watch_date_time struct. - * @param timestamp The UNIX timestamp that you wish to convert. - * @param utc_offset The number of seconds that you wish date_time to be offset from UTC. - * @return A watch_date_time for the given UNIX timestamp and UTC offset, or if outside the range that - * watch_date_time can represent, a watch_date_time with all fields set to 0. - * @note Adapted from MIT-licensed code from musl, Copyright © 2005-2014 Rich Felker, et al.: - * https://github.com/esmil/musl/blob/1cc81f5cb0df2b66a795ff0c26d7bbc4d16e13c6/src/time/__secs_to_tm.c - */ -watch_date_time watch_utility_date_time_from_unix_time(uint32_t timestamp, uint32_t utc_offset); - -/** @brief Converts a time from a given time zone to another time zone. - * @param date_time The watch_date_time that you wish to convert - * @param origin_utc_offset The number of seconds from UTC in the origin time zone - * @param destination_utc_offset The number of seconds from UTC in the destination time zone - * @return A watch_date_time for the given UNIX timestamp and UTC offset, or if outside the range that - * watch_date_time can represent, a watch_date_time with all fields set to 0. - * @note Adapted from MIT-licensed code from musl, Copyright © 2005-2014 Rich Felker, et al.: - * https://github.com/esmil/musl/blob/1cc81f5cb0df2b66a795ff0c26d7bbc4d16e13c6/src/time/__secs_to_tm.c - */ -watch_date_time watch_utility_date_time_convert_zone(watch_date_time date_time, uint32_t origin_utc_offset, uint32_t destination_utc_offset); - -/** @brief Returns a temperature in degrees Celsius for a given thermistor voltage divider circuit. - * @param value The raw analog reading from the thermistor pin (0-65535) - * @param highside True if the thermistor is connected to VCC and the series resistor is connected - * to GND; false if the thermistor is connected to GND and the series resistor is - * connected to VCC. - * @param b_coefficient From your thermistor's data sheet, the B25/85 coefficient. A typical value - * will be between 2000 and 5000. - * @param nominal_temperature From your thermistor's data sheet, the temperature (in Celsius) at - * which the thermistor's resistance is at its nominal value. - * @param nominal_resistance The thermistor's resistance at the nominal temperature. - * @param series_resistance The value of the other resistor in the voltage divider. - * @note Ported from Adafruit's MIT-licensed CircuitPython thermistor code, (c) 2017 Scott Shawcroft: - * https://github.com/adafruit/Adafruit_CircuitPython_Thermistor/blob/main/adafruit_thermistor.py - */ -float watch_utility_thermistor_temperature(uint16_t value, bool highside, float b_coefficient, float nominal_temperature, float nominal_resistance, float series_resistance); - -#endif |