summaryrefslogtreecommitdiffstats
path: root/watch-library/simulator/watch
diff options
context:
space:
mode:
Diffstat (limited to 'watch-library/simulator/watch')
-rw-r--r--watch-library/simulator/watch/watch.c9
-rw-r--r--watch-library/simulator/watch/watch_adc.c48
-rw-r--r--watch-library/simulator/watch/watch_buzzer.c60
-rw-r--r--watch-library/simulator/watch/watch_deepsleep.c99
-rw-r--r--watch-library/simulator/watch/watch_extint.c191
-rw-r--r--watch-library/simulator/watch/watch_gpio.c47
-rw-r--r--watch-library/simulator/watch/watch_i2c.c51
-rw-r--r--watch-library/simulator/watch/watch_led.c63
-rw-r--r--watch-library/simulator/watch/watch_private.c78
-rw-r--r--watch-library/simulator/watch/watch_rtc.c223
-rw-r--r--watch-library/simulator/watch/watch_slcd.c115
-rw-r--r--watch-library/simulator/watch/watch_uart.c65
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