diff options
Diffstat (limited to 'watch-library/simulator/watch')
-rw-r--r-- | watch-library/simulator/watch/watch.c | 9 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_adc.c | 48 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_buzzer.c | 60 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_deepsleep.c | 99 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_extint.c | 191 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_gpio.c | 47 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_i2c.c | 51 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_led.c | 63 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_private.c | 78 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_rtc.c | 223 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_slcd.c | 115 | ||||
-rw-r--r-- | watch-library/simulator/watch/watch_uart.c | 65 |
12 files changed, 1049 insertions, 0 deletions
diff --git a/watch-library/simulator/watch/watch.c b/watch-library/simulator/watch/watch.c new file mode 100644 index 00000000..2b14d0ab --- /dev/null +++ b/watch-library/simulator/watch/watch.c @@ -0,0 +1,9 @@ +#include "watch.h" + +bool watch_is_battery_low(void) { + return false; +} + +bool watch_is_buzzer_or_led_enabled(void) { + return false; +} diff --git a/watch-library/simulator/watch/watch_adc.c b/watch-library/simulator/watch/watch_adc.c new file mode 100644 index 00000000..364e2119 --- /dev/null +++ b/watch-library/simulator/watch/watch_adc.c @@ -0,0 +1,48 @@ +/* + * 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" + +void watch_enable_adc(void) {} + +void watch_enable_analog_input(const uint8_t pin) {} + +uint16_t watch_get_analog_pin_level(const uint8_t pin) { + return 0; +} + +void watch_set_analog_num_samples(uint16_t samples) {} + +void watch_set_analog_sampling_length(uint8_t cycles) {} + +void watch_set_analog_reference_voltage(watch_adc_reference_voltage reference) {} + +uint16_t watch_get_vcc_voltage(void) { + // TODO: (a2) hook to UI + return 3000; +} + +inline void watch_disable_analog_input(const uint8_t pin) {} + +inline void watch_disable_adc(void) {} diff --git a/watch-library/simulator/watch/watch_buzzer.c b/watch-library/simulator/watch/watch_buzzer.c new file mode 100644 index 00000000..f19e1928 --- /dev/null +++ b/watch-library/simulator/watch/watch_buzzer.c @@ -0,0 +1,60 @@ +/* + * 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) { + // TODO: (a2) hook to UI +} +inline void watch_set_buzzer_period(uint32_t period) { + // TODO: (a2) hook to UI +} + +void watch_disable_buzzer(void) { + _watch_disable_tcc(); +} + +inline void watch_set_buzzer_on(void) { + // TODO: (a2) hook to UI +} + +inline void watch_set_buzzer_off(void) { + // TODO: (a2) hook to UI +} + +// 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] = {0}; + +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/simulator/watch/watch_deepsleep.c b/watch-library/simulator/watch/watch_deepsleep.c new file mode 100644 index 00000000..9f409570 --- /dev/null +++ b/watch-library/simulator/watch/watch_deepsleep.c @@ -0,0 +1,99 @@ +/* + * 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 + +static uint32_t watch_backup_data[8]; + +void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level) { + if (pin == BTN_ALARM) { + watch_register_interrupt_callback(pin, callback, level ? INTERRUPT_TRIGGER_RISING : INTERRUPT_TRIGGER_FALLING); + } +} + +void watch_disable_extwake_interrupt(uint8_t pin) { + if (pin == BTN_ALARM) { + watch_register_interrupt_callback(pin, NULL, INTERRUPT_TRIGGER_NONE); + } +} + +void watch_store_backup_data(uint32_t data, uint8_t reg) { + if (reg < 8) { + watch_backup_data[reg] = data; + } +} + +uint32_t watch_get_backup_data(uint8_t reg) { + if (reg < 8) { + return watch_backup_data[reg]; + } + + return 0; +} + +void watch_enter_sleep_mode(void) { + // TODO: (a2) hook to UI + + // enter standby (4); we basically hang out here until an interrupt wakes us. + // sleep(4); + + // 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. + // TODO: (a2) hook to UI + + watch_enter_sleep_mode(); +} + +void watch_enter_backup_mode(void) { + // TODO: (a2) hook to UI + + // 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/simulator/watch/watch_extint.c b/watch-library/simulator/watch/watch_extint.c new file mode 100644 index 00000000..d37059bf --- /dev/null +++ b/watch-library/simulator/watch/watch_extint.c @@ -0,0 +1,191 @@ +/* + * 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" + +#include <emscripten.h> +#include <emscripten/html5.h> + +static bool output_focused = false; +static bool external_interrupt_enabled = false; +static bool button_callbacks_installed = false; +static ext_irq_cb_t external_interrupt_mode_callback = NULL; +static watch_interrupt_trigger external_interrupt_mode_trigger = INTERRUPT_TRIGGER_NONE; +static ext_irq_cb_t external_interrupt_light_callback = NULL; +static watch_interrupt_trigger external_interrupt_light_trigger = INTERRUPT_TRIGGER_NONE; +static ext_irq_cb_t external_interrupt_alarm_callback = NULL; +static watch_interrupt_trigger external_interrupt_alarm_trigger = INTERRUPT_TRIGGER_NONE; + +#define BTN_ID_ALARM 3 +#define BTN_ID_LIGHT 1 +#define BTN_ID_MODE 2 +static const uint8_t BTN_IDS[] = { BTN_ID_ALARM, BTN_ID_LIGHT, BTN_ID_MODE }; +static void watch_invoke_interrupt_callback(const uint8_t button_id, watch_interrupt_trigger trigger); + +static EM_BOOL watch_invoke_key_callback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) { + if (output_focused || keyEvent->repeat) return EM_FALSE; + + const char *key = keyEvent->key; + if (key[1] != 0) return EM_FALSE; + + uint8_t button_id; + switch (key[0]) { + case 'A': + case 'a': + button_id = BTN_ID_ALARM; + break; + case 'L': + case 'l': + button_id = BTN_ID_LIGHT; + break; + case 'M': + case 'm': + button_id = BTN_ID_MODE; + break; + default: + return EM_FALSE; + } + + watch_interrupt_trigger trigger = eventType == EMSCRIPTEN_EVENT_KEYDOWN ? INTERRUPT_TRIGGER_RISING : INTERRUPT_TRIGGER_FALLING; + watch_invoke_interrupt_callback(button_id, trigger); + return EM_TRUE; +} + +static EM_BOOL watch_invoke_mouse_callback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) { + if (eventType == EMSCRIPTEN_EVENT_MOUSEOUT && mouseEvent->buttons == 0) return EM_FALSE; + uint8_t button_id = *(const char *)userData; + watch_interrupt_trigger trigger = eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? INTERRUPT_TRIGGER_RISING : INTERRUPT_TRIGGER_FALLING; + watch_invoke_interrupt_callback(button_id, trigger); + return EM_TRUE; +} + +static EM_BOOL watch_invoke_touch_callback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) { + uint8_t button_id = *(const char *)userData; + watch_interrupt_trigger trigger = eventType == EMSCRIPTEN_EVENT_TOUCHSTART ? INTERRUPT_TRIGGER_RISING : INTERRUPT_TRIGGER_FALLING; + watch_invoke_interrupt_callback(button_id, trigger); + return EM_TRUE; +} + +static EM_BOOL watch_invoke_focus_callback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData) { + output_focused = eventType == EMSCRIPTEN_EVENT_FOCUS; + return EM_TRUE; +} + +static void watch_install_button_callbacks(void) { + emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, watch_invoke_key_callback); + emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, watch_invoke_key_callback); + + const char *target_output = "#output"; + emscripten_set_focus_callback(target_output, NULL, EM_FALSE, watch_invoke_focus_callback); + emscripten_set_blur_callback(target_output, NULL, EM_FALSE, watch_invoke_focus_callback); + + for (int i = 0, count = sizeof(BTN_IDS) / sizeof(BTN_IDS[0]); i < count; i++) { + char target[] = "#btn_"; + target[4] = BTN_IDS[i] + '0'; + + emscripten_set_mousedown_callback(target, (void *)&BTN_IDS[i], EM_FALSE, watch_invoke_mouse_callback); + emscripten_set_mouseup_callback(target, (void *)&BTN_IDS[i], EM_FALSE, watch_invoke_mouse_callback); + emscripten_set_mouseout_callback(target, (void *)&BTN_IDS[i], EM_FALSE, watch_invoke_mouse_callback); + + emscripten_set_touchstart_callback(target, (void *)&BTN_IDS[i], EM_FALSE, watch_invoke_touch_callback); + emscripten_set_touchend_callback(target, (void *)&BTN_IDS[i], EM_FALSE, watch_invoke_touch_callback); + } +} + +void watch_enable_external_interrupts(void) { + external_interrupt_enabled = true; + + if (!button_callbacks_installed) { + watch_install_button_callbacks(); + button_callbacks_installed = true; + } +} + +void watch_disable_external_interrupts(void) { + external_interrupt_enabled = false; +} + +static void watch_invoke_interrupt_callback(const uint8_t button_id, watch_interrupt_trigger event) { + if (!external_interrupt_enabled) return; + + ext_irq_cb_t callback; + watch_interrupt_trigger trigger; + uint8_t pin; + switch (button_id) { + case BTN_ID_MODE: + pin = BTN_MODE; + callback = external_interrupt_mode_callback; + trigger = external_interrupt_mode_trigger; + break; + case BTN_ID_LIGHT: + pin = BTN_LIGHT; + callback = external_interrupt_light_callback; + trigger = external_interrupt_light_trigger; + break; + case BTN_ID_ALARM: + pin = BTN_ALARM; + callback = external_interrupt_alarm_callback; + trigger = external_interrupt_alarm_trigger; + break; + default: + return; + } + + const bool level = (event & INTERRUPT_TRIGGER_RISING) != 0; + EM_ASM({ + const classList = document.querySelector('#btn' + $0).classList; + const highlight = 'highlight'; + $1 ? classList.add(highlight) : classList.remove(highlight); + }, button_id, level); + + watch_set_pin_level(pin, level); + + if (callback && (event & trigger) != 0) { + callback(); + + void resume_main_loop(void); + resume_main_loop(); + } +} + +void watch_register_interrupt_callback(const uint8_t pin, ext_irq_cb_t callback, watch_interrupt_trigger trigger) { + if (pin == BTN_MODE) { + external_interrupt_mode_callback = callback; + external_interrupt_mode_trigger = trigger; + } else if (pin == BTN_LIGHT) { + external_interrupt_light_callback = callback; + external_interrupt_light_trigger = trigger; + } else if (pin == BTN_ALARM) { + external_interrupt_alarm_callback = callback; + external_interrupt_alarm_trigger = trigger; + } +} + +void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback) { + watch_register_interrupt_callback(pin, callback, INTERRUPT_TRIGGER_RISING); +} + +void watch_enable_buttons(void) { + watch_enable_external_interrupts(); +} diff --git a/watch-library/simulator/watch/watch_gpio.c b/watch-library/simulator/watch/watch_gpio.c new file mode 100644 index 00000000..4bea2c11 --- /dev/null +++ b/watch-library/simulator/watch/watch_gpio.c @@ -0,0 +1,47 @@ +/* + * 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" + +static bool pin_levels[UINT8_MAX]; + +void watch_enable_digital_input(const uint8_t pin) {} + +void watch_disable_digital_input(const uint8_t pin) {} + +void watch_enable_pull_up(const uint8_t pin) {} + +void watch_enable_pull_down(const uint8_t pin) {} + +bool watch_get_pin_level(const uint8_t pin) { + return pin_levels[pin]; +} + +void watch_enable_digital_output(const uint8_t pin) {} + +void watch_disable_digital_output(const uint8_t pin) {} + +void watch_set_pin_level(const uint8_t pin, const bool level) { + pin_levels[pin] = level; +} diff --git a/watch-library/simulator/watch/watch_i2c.c b/watch-library/simulator/watch/watch_i2c.c new file mode 100644 index 00000000..09339888 --- /dev/null +++ b/watch-library/simulator/watch/watch_i2c.c @@ -0,0 +1,51 @@ +/* + * 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" + +void watch_enable_i2c(void) {} + +void watch_disable_i2c(void) {} + +void watch_i2c_send(int16_t addr, uint8_t *buf, uint16_t length) {} + +void watch_i2c_receive(int16_t addr, uint8_t *buf, uint16_t length) {} + +void watch_i2c_write8(int16_t addr, uint8_t reg, uint8_t data) {} + +uint8_t watch_i2c_read8(int16_t addr, uint8_t reg) { + return 0; +} + +uint16_t watch_i2c_read16(int16_t addr, uint8_t reg) { + return 0; +} + +uint32_t watch_i2c_read24(int16_t addr, uint8_t reg) { + return 0; +} + +uint32_t watch_i2c_read32(int16_t addr, uint8_t reg) { + return 0; +} diff --git a/watch-library/simulator/watch/watch_led.c b/watch-library/simulator/watch/watch_led.c new file mode 100644 index 00000000..173f1b08 --- /dev/null +++ b/watch-library/simulator/watch/watch_led.c @@ -0,0 +1,63 @@ +/* + * MIT License + * + * Copyright (c) 2020 Joey Castillo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "watch_led.h" + +#include <emscripten.h> + +void watch_enable_leds(void) {} + +void watch_disable_leds(void) {} + +void watch_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) { + EM_ASM({ + document.getElementById('light').style.opacity = $1 / 255; + }, red, green); +} + +void watch_set_led_red(void) { + watch_set_led_color(255, 0); +} + +void watch_set_led_green(void) { + watch_set_led_color(0, 255); +} + +void watch_set_led_yellow(void) { + watch_set_led_color(255, 255); +} + +void watch_set_led_off(void) { + watch_set_led_color(0, 0); +} diff --git a/watch-library/simulator/watch/watch_private.c b/watch-library/simulator/watch/watch_private.c new file mode 100644 index 00000000..b852893b --- /dev/null +++ b/watch-library/simulator/watch/watch_private.c @@ -0,0 +1,78 @@ +/* + * 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 <sys/time.h> + +void _watch_init(void) { + // External wake depends on RTC; calendar is a required module. + _watch_rtc_init(); +} + +// 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); +int getentropy(void *buf, size_t buflen) { + // TODO: (a2) hook to RNG + return 0; +} + +int _gettimeofday(struct timeval *tv, void *tzvp); +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) {} + +void _watch_disable_tcc(void) {} + +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) { + // TODO: (a2) hook to UI + 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; +// } diff --git a/watch-library/simulator/watch/watch_rtc.c b/watch-library/simulator/watch/watch_rtc.c new file mode 100644 index 00000000..573c0ff2 --- /dev/null +++ b/watch-library/simulator/watch/watch_rtc.c @@ -0,0 +1,223 @@ +/* + * 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" + +#include <emscripten.h> +#include <emscripten/html5.h> + +static double time_offset = 0; +static long tick_callbacks[8]; + +static long alarm_interval_id; +static long alarm_timeout_id; +static double alarm_interval; +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 true; +} + +void _watch_rtc_init(void) { +} + +void watch_rtc_set_date_time(watch_date_time date_time) { + time_offset = EM_ASM_DOUBLE({ + const year = 2020 + (($0 >> 26) & 0x3f); + const month = ($0 >> 22) & 0xf; + const day = ($0 >> 17) & 0x1f; + const hour = ($0 >> 12) & 0x1f; + const minute = ($0 >> 6) & 0x3f; + const second = $0 & 0x3f; + const date = new Date(year, month - 1, day, hour, minute, second); + return date - Date.now(); + }, date_time.reg); +} + +watch_date_time watch_rtc_get_date_time(void) { + watch_date_time retval; + retval.reg = EM_ASM_INT({ + const date = new Date(Date.now() + $0); + return date.getSeconds() | + (date.getMinutes() << 6) | + (date.getHours() << 12) | + (date.getDate() << 17) | + ((date.getMonth() + 1) << 22) | + ((date.getFullYear() - 2020) << 26); + }, time_offset); + 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); +} + +static void watch_invoke_periodic_callback(void *userData) { + ext_irq_cb_t callback = userData; + callback(); + + void resume_main_loop(void); + resume_main_loop(); +} + +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. + double interval = 1000 / frequency; // in msec + tick_callbacks[per_n] = emscripten_set_interval(watch_invoke_periodic_callback, interval, (void *)callback); +} + +void watch_rtc_disable_periodic_callback(uint8_t frequency) { + if (__builtin_popcount(frequency) != 1) return; + uint8_t per_n = __builtin_clz(frequency << 24); + emscripten_clear_interval(tick_callbacks[per_n]); + tick_callbacks[per_n] = 0; +} + +void watch_rtc_disable_all_periodic_callbacks(void) { + for (int i = 0; i < 8; i++) { + if (tick_callbacks[i] != 0) { + emscripten_clear_interval(tick_callbacks[i]); + tick_callbacks[i] = 0; + } + } +} + +static void watch_invoke_alarm_interval_callback(void *userData) { + (void)userData; + if (alarm_callback) alarm_callback(); +} + +static void watch_invoke_alarm_callback(void *userData) { + (void)userData; + if (alarm_callback) alarm_callback(); + alarm_interval_id = emscripten_set_interval(watch_invoke_alarm_interval_callback, alarm_interval, NULL); +} + +void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) { + watch_rtc_disable_alarm_callback(); + + switch (mask) { + case ALARM_MATCH_DISABLED: + return; + case ALARM_MATCH_SS: + alarm_interval = 60 * 1000; + break; + case ALARM_MATCH_MMSS: + alarm_interval = 60 * 60 * 1000; + break; + case ALARM_MATCH_HHMMSS: + alarm_interval = 60 * 60 * 60 * 1000; + break; + } + + double timeout = EM_ASM_DOUBLE({ + const now = Date.now(); + const date = new Date(now + $0); + + const hour = ($1 >> 12) & 0x1f; + const minute = ($1 >> 6) & 0x3f; + const second = $1 & 0x3f; + + if ($2 == 1) { // SS + if (second < date.getSeconds()) date.setMinutes(date.getMinutes() + 1); + date.setSeconds(second); + } else if ($2 == 2) { // MMSS + if (second < date.getSeconds()) date.setMinutes(date.getMinutes() + 1); + if (minute < date.getMinutes()) date.setHours(date.getHours() + 1); + date.setMinutes(minute, second); + } else if ($2 == 3) { // HHMMSS + if (second < date.getSeconds()) date.setMinutes(date.getMinutes() + 1); + if (minute < date.getMinutes()) date.setHours(date.getHours() + 1); + if (hour < date.getHours()) date.setDate(date.getDate() + 1); + date.setHours(hour, minute, second); + } else { + throw 'Invalid alarm match mask'; + } + + return date - now; + }, time_offset, alarm_time.reg, mask); + + alarm_callback = callback; + alarm_timeout_id = emscripten_set_timeout(watch_invoke_alarm_callback, timeout, NULL); +} + +void watch_rtc_disable_alarm_callback(void) { + alarm_callback = NULL; + alarm_interval = 0; + + if (alarm_timeout_id) { + emscripten_clear_timeout(alarm_timeout_id); + alarm_timeout_id = 0; + } + + if (alarm_interval_id) { + emscripten_clear_interval(alarm_interval_id); + alarm_interval_id = 0; + } +} + +/////////////////////// +// Deprecated functions + +void watch_set_date_time(struct calendar_date_time date_time) { + watch_date_time val; + val.unit.second = date_time.time.sec; + val.unit.minute = date_time.time.min; + val.unit.hour = date_time.time.hour; + val.unit.day = date_time.date.day; + val.unit.month = date_time.date.month; + val.unit.year = date_time.date.year - WATCH_RTC_REFERENCE_YEAR; + watch_rtc_set_date_time(val); +} + +void watch_get_date_time(struct calendar_date_time *date_time) { + if (date_time == NULL) return; + watch_date_time val = watch_rtc_get_date_time(); + date_time->time.sec = val.unit.second; + date_time->time.min = val.unit.minute; + date_time->time.hour = val.unit.hour; + date_time->date.day = val.unit.day; + date_time->date.month = val.unit.month; + date_time->date.year = val.unit.year + WATCH_RTC_REFERENCE_YEAR; +} + +void watch_register_tick_callback(ext_irq_cb_t callback) { + watch_rtc_register_tick_callback(callback); +} diff --git a/watch-library/simulator/watch/watch_slcd.c b/watch-library/simulator/watch/watch_slcd.c new file mode 100644 index 00000000..2af96847 --- /dev/null +++ b/watch-library/simulator/watch/watch_slcd.c @@ -0,0 +1,115 @@ +/* + * 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 "watch_private_display.h" +#include "hpl_slcd_config.h" + +#include <emscripten.h> +#include <emscripten/html5.h> + +////////////////////////////////////////////////////////////////////////////////////////// +// Segmented Display + +static char blink_character; +static bool blink_state; +static long blink_interval_id; +static bool tick_state; +static long tick_interval_id; + +void watch_enable_display(void) { + watch_clear_display(); +} + +void watch_set_pixel(uint8_t com, uint8_t seg) { + EM_ASM({ + document.querySelectorAll("[data-com='" + $0 + "'][data-seg='" + $1 + "']") + .forEach((e) => e.style.opacity = 1); + }, com, seg); +} + +void watch_clear_pixel(uint8_t com, uint8_t seg) { + EM_ASM({ + document.querySelectorAll("[data-com='" + $0 + "'][data-seg='" + $1 + "']") + .forEach((e) => e.style.opacity = 0); + }, com, seg); +} + +void watch_clear_display(void) { + EM_ASM({ + document.querySelectorAll("[data-com][data-seg]") + .forEach((e) => e.style.opacity = 0); + }); +} + +static void watch_invoke_blink_callback(void *userData) { + blink_state = !blink_state; + watch_display_character(blink_state ? blink_character : ' ', 7); + watch_clear_pixel(2, 10); // clear segment B of position 7 since it can't blink +} + +void watch_start_character_blink(char character, uint32_t duration) { + watch_display_character(character, 7); + watch_clear_pixel(2, 10); // clear segment B of position 7 since it can't blink + + blink_state = true; + blink_character = character; + blink_interval_id = emscripten_set_interval(watch_invoke_blink_callback, (double)duration, NULL); +} + +void watch_stop_blink(void) { + emscripten_clear_timeout(blink_interval_id); + blink_interval_id = 0; + blink_state = false; +} + +static void watch_invoke_tick_callback(void *userData) { + tick_state = !tick_state; + if (tick_state) { + watch_clear_pixel(0, 2); + watch_set_pixel(0, 3); + } else { + watch_clear_pixel(0, 3); + watch_set_pixel(0, 2); + } +} + +void watch_start_tick_animation(uint32_t duration) { + watch_display_character(' ', 8); + + tick_state = true; + tick_interval_id = emscripten_set_interval(watch_invoke_tick_callback, (double)duration, NULL); +} + +bool watch_tick_animation_is_running(void) { + return tick_interval_id != 0; +} + +void watch_stop_tick_animation(void) { + emscripten_clear_timeout(tick_interval_id); + tick_interval_id = 0; + tick_state = false; + + watch_display_character(' ', 8); +} diff --git a/watch-library/simulator/watch/watch_uart.c b/watch-library/simulator/watch/watch_uart.c new file mode 100644 index 00000000..e37fabff --- /dev/null +++ b/watch-library/simulator/watch/watch_uart.c @@ -0,0 +1,65 @@ +/* + * 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) {} + +void watch_debug_putc(char 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 |