diff --git a/watch-library/simulator/watch/watch_rtc.c b/watch-library/simulator/watch/watch_rtc.c index 4927ba14..93da5e6b 100644 --- a/watch-library/simulator/watch/watch_rtc.c +++ b/watch-library/simulator/watch/watch_rtc.c @@ -22,6 +22,7 @@ * SOFTWARE. */ #include +#include #include "watch_rtc.h" #include "watch_main_loop.h" @@ -35,9 +36,10 @@ static const uint32_t RTC_CNT_SUBSECOND_MASK = RTC_CNT_HZ - 1; static const uint32_t RTC_CNT_DIV = 7; static const uint32_t RTC_CNT_TICKS_PER_MINUTE = RTC_CNT_HZ * 60; -static uint32_t counter_interval; +static bool rtc_enabled; static uint32_t counter; static uint32_t reference_timestamp; +static double next_tick_time; #define WATCH_RTC_N_COMP_CB 8 @@ -66,7 +68,7 @@ static void _watch_process_periodic_callbacks(void); static void _watch_process_comp_callbacks(void); bool _watch_rtc_is_enabled(void) { - return counter_interval; + return rtc_enabled; } void _watch_rtc_init(void) { @@ -82,7 +84,7 @@ void _watch_rtc_init(void) { scheduled_comp_counter = 0; counter = 0; - counter_interval = 0; + rtc_enabled = false; watch_rtc_set_date_time(watch_get_init_date_time()); watch_rtc_enable(true); @@ -164,6 +166,27 @@ void watch_rtc_disable_tick_callback(void) { watch_rtc_disable_periodic_callback(1); } +static void _watch_schedule_next_tick(void) { + if (!rtc_enabled) return; + + double now = EM_ASM_DOUBLE({ return performance.now(); }); + + // Target interval in ms + double ms = 1000.0 / (double)RTC_CNT_HZ; + + // Schedule next tick, correcting for drift + next_tick_time += ms; + double delay = next_tick_time - now; + + // If we're behind, reset timing + if (delay < 0) { + next_tick_time = now + ms; + delay = ms; + } + + emscripten_async_call(_watch_increase_counter, NULL, delay); +} + static void _watch_increase_counter(void *userData) { (void) userData; @@ -174,6 +197,9 @@ static void _watch_increase_counter(void *userData) { _watch_process_comp_callbacks(); resume_main_loop(); + + // Schedule the next tick with drift correction + _watch_schedule_next_tick(); } static void _watch_process_periodic_callbacks(void) { @@ -338,17 +364,17 @@ void watch_rtc_schedule_next_comp(void) { void watch_rtc_enable(bool en) { // Nothing to do cases - if ((en && counter_interval) || (!en && !counter_interval)) { + if ((en && rtc_enabled) || (!en && !rtc_enabled)) { return; } if (en) { - // Very bad way to keep time, but okay way to emulates the hardware. - double ms = 1000.0 / (double)RTC_CNT_HZ; // in msec - counter_interval = emscripten_set_interval(_watch_increase_counter, ms, NULL); + // Use drift-correcting timer instead of fixed setInterval + rtc_enabled = true; + next_tick_time = EM_ASM_DOUBLE({ return performance.now(); }); + _watch_schedule_next_tick(); } else { - emscripten_clear_interval(counter_interval); - counter_interval = 0; + rtc_enabled = false; } }