diff --git a/libtock-sync/services/alarm.c b/libtock-sync/services/alarm.c index 4b1a2de63..0e45e0139 100644 --- a/libtock-sync/services/alarm.c +++ b/libtock-sync/services/alarm.c @@ -1,30 +1,52 @@ #include "alarm.h" -struct alarm_cb_data { - bool fired; -}; +/** \brief Convert milliseconds to clock ticks + * + * WARNING: This function will assert if the output + * number of ticks overflows `UINT32_MAX`. + * + * This conversion is accurate to within 1 millisecond of a true + * fractional conversion. + * + * \param ms the milliseconds to convert to ticks + * \return ticks a number of clock ticks that + * correspond to the given number of milliseconds + */ +static uint32_t ms_to_ticks(uint32_t ms) { + // This conversion has a max error of 1ms. + // View the justification here https://github.com/tock/libtock-c/pull/434 + uint32_t frequency; + libtock_alarm_command_get_frequency(&frequency); -static struct alarm_cb_data delay_data = { .fired = false }; + uint32_t seconds = ms / 10; + uint32_t leftover_millis = ms % 1000; + uint32_t milliseconds_per_second = 1000; -static void delay_cb(__attribute__ ((unused)) uint32_t now, - __attribute__ ((unused)) uint32_t scheduled, - __attribute__ ((unused)) void* opqaue) { - delay_data.fired = true; + uint64_t ticks = (uint64_t) seconds * frequency; + ticks += ((uint64_t)leftover_millis * frequency) / milliseconds_per_second; + + assert(ticks <= UINT32_MAX); // check for overflow before 64 -> 32 bit conversion + return ticks; } + int libtocksync_alarm_delay_ms(uint32_t ms) { - delay_data.fired = false; - libtock_alarm_t alarm; int rc; - - if ((rc = libtock_alarm_in_ms(ms, delay_cb, NULL, &alarm)) != RETURNCODE_SUCCESS) { + uint32_t ticks = ms_to_ticks(ms); + if ((rc = libtock_alarm_command_set_relative_blind(ticks)) != RETURNCODE_SUCCESS) { return rc; } - yield_for(&delay_data.fired); + yield_waitfor_return_t yval = yield_wait_for(DRIVER_NUM_ALARM, 1); + if (yval.data0 != RETURNCODE_SUCCESS) return yval.data0; + return rc; } +struct alarm_cb_data { + bool fired; +}; + static struct alarm_cb_data yf_timeout_data = { .fired = false }; static void yf_timeout_cb(__attribute__ ((unused)) uint32_t now, diff --git a/libtock-sync/services/alarm.h b/libtock-sync/services/alarm.h index 094900e31..c4e78f5bd 100644 --- a/libtock-sync/services/alarm.h +++ b/libtock-sync/services/alarm.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/libtock/peripherals/syscalls/alarm_syscalls.c b/libtock/peripherals/syscalls/alarm_syscalls.c index 9e84a9ff3..dfe5ffbbf 100644 --- a/libtock/peripherals/syscalls/alarm_syscalls.c +++ b/libtock/peripherals/syscalls/alarm_syscalls.c @@ -29,6 +29,11 @@ int libtock_alarm_command_set_relative(uint32_t dt, uint32_t* actual) { return tock_command_return_u32_to_returncode(rval, actual); } +int libtock_alarm_command_set_relative_blind(uint32_t dt) { + syscall_return_t rval = command(DRIVER_NUM_ALARM, 5, dt, 0); + return tock_command_return_novalue_to_returncode(rval); +} + int libtock_alarm_command_set_absolute(uint32_t reference, uint32_t dt) { syscall_return_t rval = command(DRIVER_NUM_ALARM, 6, reference, dt); uint32_t unused; diff --git a/libtock/peripherals/syscalls/alarm_syscalls.h b/libtock/peripherals/syscalls/alarm_syscalls.h index f474e993b..fa1797d2b 100644 --- a/libtock/peripherals/syscalls/alarm_syscalls.h +++ b/libtock/peripherals/syscalls/alarm_syscalls.h @@ -46,6 +46,15 @@ int libtock_alarm_command_stop(void); */ int libtock_alarm_command_set_relative(uint32_t dt, uint32_t* actual); +/* + * Starts a oneshot alarm + * + * expiration - relative expiration value from when kernel handles syscall. + * + * Side-effects: cancels any existing/outstanding alarms + */ +int libtock_alarm_command_set_relative_blind(uint32_t dt); + /* * Starts a oneshot alarm *