diff --git a/libtock-sync/interface/console.c b/libtock-sync/interface/console.c index ec4ef2e28..f9f58a5ea 100644 --- a/libtock-sync/interface/console.c +++ b/libtock-sync/interface/console.c @@ -22,10 +22,10 @@ returncode_t libtocksync_console_write(const uint8_t* buffer, uint32_t length, i if (err != RETURNCODE_SUCCESS) return err; // Wait for the callback. - yield_for(&result.fired); - if (result.result != RETURNCODE_SUCCESS) return result.result; + yield_waitfor_return_t yval = yield_wait_for(DRIVER_NUM_CONSOLE, 1); + if (yval.data0 != RETURNCODE_SUCCESS) return yval.data0; - *written = result.length; + *written = yval.data1; return RETURNCODE_SUCCESS; } 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 * diff --git a/libtock/tock.c b/libtock/tock.c index dbf07f72d..855e59c15 100644 --- a/libtock/tock.c +++ b/libtock/tock.c @@ -234,6 +234,25 @@ int yield_no_wait(void) { } } +yield_waitfor_return_t yield_wait_for(uint32_t driver, uint32_t subscribe) { + register uint32_t waitfor __asm__ ("r0") = 2; // yield-waitfor + register uint32_t r1 __asm__ ("r1") = driver; + register uint32_t r2 __asm__ ("r2") = subscribe; + register int rv0 __asm__ ("r0"); + register int rv1 __asm__ ("r1"); + register int rv2 __asm__ ("r2"); + + __asm__ volatile ( + "svc 0 \n" + : "=r" (rv0), "=r" (rv1), "=r" (rv2) + : "r" (waitfor), "r" (r1), "r" (r2) + : "memory" + ); + yield_waitfor_return_t rv = {rv0, rv1, rv2}; + return rv; +} + + void tock_exit(uint32_t completion_code) { register uint32_t r0 __asm__ ("r0") = 0; // Terminate register uint32_t r1 __asm__ ("r1") = completion_code; @@ -459,6 +478,23 @@ int yield_no_wait(void) { } } +yield_waitfor_return_t yield_wait_for(uint32_t driver, uint32_t subscribe) { + register uint32_t waitfor __asm__ ("a0") = 2; // yield-waitfor + register uint32_t a1 __asm__ ("a1") = driver; + register uint32_t a2 __asm__ ("a2") = subscribe; + register uint32_t a4 __asm__ ("a4") = 0; // Yield + register int rv0 __asm__ ("a0"); + register int rv1 __asm__ ("a1"); + register int rv2 __asm__ ("a2"); + __asm__ volatile ( + "ecall\n" + : "=r" (rv0), "=r" (rv1), "=r" (rv2) + : "r" (waitfor), "r" (a1), "r" (a2), "r" (a4) + : "memory"); + yield_waitfor_return_t rv = {rv0, rv1, rv2}; + return rv; +} + void tock_restart(uint32_t completion_code) { register uint32_t a0 __asm__ ("a0") = 1; // exit-restart diff --git a/libtock/tock.h b/libtock/tock.h index 3ddc31cce..09f6b564b 100644 --- a/libtock/tock.h +++ b/libtock/tock.h @@ -127,6 +127,18 @@ typedef struct { uint32_t data; } memop_return_t; +// Return structure for a Yield-WaitFor syscall. The return value are the +// arguments that would have been passed to the upcall the the Yield-WaitFor was +// waiting on. +typedef struct { + // Upcall argument 1. + uint32_t data0; + // Upcall argument 2. + uint32_t data1; + // Upcall argument 3. + uint32_t data2; +} yield_waitfor_return_t; + //////////////////////////////////////////////////////////////////////////////// /// /// HELPER FUNCTIONS @@ -177,9 +189,10 @@ int tock_allow_userspace_r_return_to_returncode(allow_userspace_r_return_t); int tock_enqueue(subscribe_upcall cb, int arg0, int arg1, int arg2, void* ud); int yield_check_tasks(void); +int yield_no_wait(void); void yield(void); void yield_for(bool*); -int yield_no_wait(void); +yield_waitfor_return_t yield_wait_for(uint32_t driver, uint32_t subscribe); void tock_exit(uint32_t completion_code) __attribute__ ((noreturn)); void tock_restart(uint32_t completion_code) __attribute__ ((noreturn));