diff --git a/.travis.yml b/.travis.yml index 26f22ef6..97be43f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: - - nightly-2019-09-19 + - nightly-2019-11-06 os: - linux diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3b7a700f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Releases + +## 0.2.0 (WIP) + +- Many functions, including `main()` are asynchronous + - To retrieve the value of an asynchronous `value`, use `value.await` + - This is only possible within an `async fn`, so either + - Make the caller `fn` of `.await` an `async fn` + - Not recommended: Use `core::executor::block_on(value)` to retrieve the `value` +- `syscalls::yieldk_for` is no longer available + - Yielding manually is discouraged as it conflicts with Rust's safety guarantees. If you need to wait for a condition, use `futures::wait_until` and `.await`. + +## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0) + +- First and highly experimental `libtock-rs` API \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 29d9b791..fca5e62f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "libtock" -version = "0.1.0" +version = "0.2.0" authors = ["Tock Project Developers "] license = "MIT/Apache-2.0" edition = "2018" [dependencies] +core = { package = "async-support", path = "async-support" } linked_list_allocator = "0.6.4" [dev-dependencies] @@ -13,6 +14,7 @@ corepack = { version = "0.4.0", default-features = false, features = ["alloc"] } # We pin the serde version because newer serde versions may not be compatible # with the nightly toolchain used by libtock-rs. serde = { version = "=1.0.84", default-features = false, features = ["derive"] } +futures = { version = "0.3.1", default-features = false } [profile.dev] panic = "abort" diff --git a/README.md b/README.md index 0286fc51..4a3efe98 100644 --- a/README.md +++ b/README.md @@ -52,15 +52,12 @@ The boiler plate code you would write is ```rust #![no_std] -extern crate tock; - -fn main() { +async fn main() { // Your code } ``` If you want to use heap based allocation you will have to add ```rust -#![feature(alloc)] extern crate alloc; ``` to the preamble. diff --git a/async-support/Cargo.toml b/async-support/Cargo.toml new file mode 100644 index 00000000..9287c6bf --- /dev/null +++ b/async-support/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "async-support" +version = "0.1.0" +authors = ["Woyten "] +edition = "2018" +description = "`libtock` specific patch of `core` for `async`-`await` syntax in a `#![no_std]` environment. It implements the methods `core::future::poll_with_tls_context` and `core::future::from_generator` which are currently missing in `core`." + +[dependencies] diff --git a/async-support/src/lib.rs b/async-support/src/lib.rs new file mode 100644 index 00000000..7d368202 --- /dev/null +++ b/async-support/src/lib.rs @@ -0,0 +1,106 @@ +#![feature(generator_trait)] +#![no_std] + +pub use core::*; + +pub mod future { + pub use core::future::Future; + use core::ops::Generator; + use core::pin::Pin; + use core::task::Poll; + + pub fn poll_with_tls_context(f: Pin<&mut F>) -> Poll + where + F: Future, + { + crate::executor::poll(f) + } + + pub fn from_generator>( + generator: G, + ) -> impl Future { + crate::executor::from_generator(generator) + } +} + +pub mod executor { + use core::future::Future; + use core::ops::Generator; + use core::ops::GeneratorState; + use core::pin::Pin; + use core::ptr; + use core::task::Context; + use core::task::Poll; + use core::task::RawWaker; + use core::task::RawWakerVTable; + use core::task::Waker; + + extern "Rust" { + #[link_name = "libtock::syscalls::yieldk"] + fn yieldk(); + } + + pub fn block_on(mut future: impl Future) -> T { + // Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).". + // IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning. + let mut pinned_future = unsafe { Pin::new_unchecked(&mut future) }; + + loop { + match poll(pinned_future.as_mut()) { + Poll::Pending => unsafe { yieldk() }, + Poll::Ready(value) => { + return value; + } + } + } + } + + pub(crate) fn poll(pinned_future: Pin<&mut F>) -> Poll { + let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; + let mut context = Context::from_waker(&waker); + pinned_future.poll(&mut context) + } + + // Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all. + fn get_dummy_waker() -> RawWaker { + fn clone(_x: *const ()) -> RawWaker { + get_dummy_waker() + } + + fn do_nothing(_x: *const ()) {} + + // This vtable implements the methods required for managing the lifecycle of the wakers. + // Our wakers are dummies, so those functions don't do anything. + static DUMMY_WAKER_VTABLE: RawWakerVTable = + RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing); + + // The wakers don't have any implementation, so the instance can simply be null. + RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE) + } + + pub(crate) fn from_generator>( + generator: G, + ) -> impl Future { + GeneratorFuture { generator } + } + + struct GeneratorFuture { + generator: G, + } + + impl> Future for GeneratorFuture { + type Output = G::Return; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + // Pin::map_unchecked_mut is safe as long as the move and drop guarantees are propagated through the mapping. + // This is trivially satisfied since our future is only a newtype decorator of the generator. + let pinned_generator = + unsafe { self.map_unchecked_mut(|future| &mut future.generator) }; + + match pinned_generator.resume() { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(out) => Poll::Ready(out), + } + } + } +} diff --git a/examples/adc.rs b/examples/adc.rs index 8ba602ba..202270f8 100644 --- a/examples/adc.rs +++ b/examples/adc.rs @@ -6,7 +6,7 @@ use libtock::console::Console; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let mut console = Console::new(); let mut with_callback = adc::with_callback(|channel: usize, value: usize| { writeln!(console, "channel: {}, value: {}", channel, value).unwrap(); @@ -16,6 +16,6 @@ fn main() { loop { adc.sample(0).unwrap(); - timer::sleep(Duration::from_ms(2000)); + timer::sleep(Duration::from_ms(2000)).await; } } diff --git a/examples/adc_buffer.rs b/examples/adc_buffer.rs index c313bde9..a7258040 100644 --- a/examples/adc_buffer.rs +++ b/examples/adc_buffer.rs @@ -7,7 +7,7 @@ use libtock::console::Console; use libtock::syscalls; /// Reads a 128 byte sample into a buffer and prints the first value to the console. -fn main() { +async fn main() { let mut console = Console::new(); let mut adc_buffer = AdcBuffer::new(); let mut temp_buffer = [0; libtock::adc::BUFFER_SIZE]; diff --git a/examples/async.rs b/examples/async.rs new file mode 100644 index 00000000..f4cc9e7e --- /dev/null +++ b/examples/async.rs @@ -0,0 +1,40 @@ +#![no_std] + +use futures::future; +use libtock::buttons; +use libtock::buttons::ButtonState; +use libtock::futures as libtock_futures; +use libtock::led; +use libtock::timer; +use libtock::timer::Duration; + +async fn main() { + future::join(blink_periodically(), blink_on_button_press()).await; +} + +async fn blink_periodically() { + let led = led::get(0).unwrap(); + loop { + timer::sleep(Duration::from_ms(250)).await; + led.on(); + timer::sleep(Duration::from_ms(250)).await; + led.off(); + } +} + +async fn blink_on_button_press() { + let mut with_callback = buttons::with_callback(|_, _| {}); + let mut buttons = with_callback.init().unwrap(); + let mut button = buttons.iter_mut().next().unwrap(); + let button = button.enable().unwrap(); + let led = led::get(1).unwrap(); + + loop { + libtock_futures::wait_until(|| button.read() == ButtonState::Released).await; + libtock_futures::wait_until(|| button.read() == ButtonState::Pressed).await; + led.on(); + libtock_futures::wait_until(|| button.read() == ButtonState::Released).await; + libtock_futures::wait_until(|| button.read() == ButtonState::Pressed).await; + led.off(); + } +} diff --git a/examples/ble_scanning.rs b/examples/ble_scanning.rs index 451953fe..f32b7ec6 100644 --- a/examples/ble_scanning.rs +++ b/examples/ble_scanning.rs @@ -16,7 +16,7 @@ struct LedCommand { // Prevents the compiler from dropping the subscription too early. #[allow(unreachable_code)] -fn main() { +async fn main() { let mut shared_buffer = BleDriver::create_scan_buffer(); let mut my_buffer = BleDriver::create_scan_buffer(); let shared_memory = BleDriver::share_memory(&mut shared_buffer).unwrap(); diff --git a/examples/blink.rs b/examples/blink.rs index 8e8980e8..b731dd7c 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -4,7 +4,7 @@ use libtock::led; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let num_leds = led::count(); // Blink the LEDs in a binary count pattern and scale @@ -21,6 +21,6 @@ fn main() { count = count.wrapping_add(1); // This delay uses an underlying timer in the kernel. - timer::sleep(Duration::from_ms(250)); + timer::sleep(Duration::from_ms(250)).await; } } diff --git a/examples/blink_random.rs b/examples/blink_random.rs index d114d397..48bbf5f1 100644 --- a/examples/blink_random.rs +++ b/examples/blink_random.rs @@ -5,20 +5,20 @@ use libtock::rng; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let num_leds = led::count(); // blink_nibble assumes 4 leds. assert_eq!(num_leds, 4); let mut buf = [0; 64]; loop { - assert!(rng::fill_buffer(&mut buf)); + assert!(rng::fill_buffer(&mut buf).await); for &x in buf.iter() { blink_nibble(x); - timer::sleep(Duration::from_ms(100)); + timer::sleep(Duration::from_ms(100)).await; blink_nibble(x >> 4); - timer::sleep(Duration::from_ms(100)); + timer::sleep(Duration::from_ms(100)).await; } } } diff --git a/examples/button_leds.rs b/examples/button_leds.rs index 2ab76153..bb854222 100644 --- a/examples/button_leds.rs +++ b/examples/button_leds.rs @@ -3,10 +3,9 @@ use libtock::buttons; use libtock::buttons::ButtonState; use libtock::led; -use libtock::timer; -use libtock::timer::Duration; +use libtock::syscalls; -fn main() { +async fn main() { let mut with_callback = buttons::with_callback(|button_num: usize, state| { let i = button_num as isize; match state { @@ -22,6 +21,6 @@ fn main() { } loop { - timer::sleep(Duration::from_ms(500)); + syscalls::yieldk(); } } diff --git a/examples/button_read.rs b/examples/button_read.rs index 539fa6c7..336955dd 100644 --- a/examples/button_read.rs +++ b/examples/button_read.rs @@ -7,7 +7,7 @@ use libtock::console::Console; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let mut console = Console::new(); let mut with_callback = buttons::with_callback(|_, _| {}); let mut buttons = with_callback.init().unwrap(); @@ -20,6 +20,6 @@ fn main() { ButtonState::Released => writeln!(console, "released"), } .unwrap(); - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; } } diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs index 6644e8dc..86168098 100644 --- a/examples/button_subscribe.rs +++ b/examples/button_subscribe.rs @@ -4,11 +4,10 @@ use core::fmt::Write; use libtock::buttons; use libtock::buttons::ButtonState; use libtock::console::Console; -use libtock::timer; -use libtock::timer::Duration; +use libtock::syscalls; // FIXME: Hangs up when buttons are pressed rapidly - problem in console? -fn main() { +async fn main() { let mut console = Console::new(); let mut with_callback = buttons::with_callback(|button_num: usize, state| { @@ -31,6 +30,6 @@ fn main() { } loop { - timer::sleep(Duration::from_ms(500)); + syscalls::yieldk(); } } diff --git a/examples/gpio.rs b/examples/gpio.rs index a09a2b24..4d5b9a43 100644 --- a/examples/gpio.rs +++ b/examples/gpio.rs @@ -5,14 +5,14 @@ use libtock::timer; use libtock::timer::Duration; // Example works on P0.03 -fn main() { +async fn main() { let pin = GpioPinUnitialized::new(0); let pin = pin.open_for_write().unwrap(); loop { pin.set_high(); - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; pin.set_low(); - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; } } diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs index a5d7f5bb..5c18f627 100644 --- a/examples/gpio_read.rs +++ b/examples/gpio_read.rs @@ -7,7 +7,7 @@ use libtock::timer; use libtock::timer::Duration; // example works on p0.03 -fn main() { +async fn main() { let mut console = Console::new(); let pin = GpioPinUnitialized::new(0); let pin = pin.open_for_read(None, InputMode::PullDown).unwrap(); @@ -18,6 +18,6 @@ fn main() { } else { writeln!(console, "false").unwrap(); } - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; } } diff --git a/examples/hardware_test.rs b/examples/hardware_test.rs index c224f58d..a0f1bdbd 100644 --- a/examples/hardware_test.rs +++ b/examples/hardware_test.rs @@ -29,7 +29,7 @@ impl MyTrait for String { } } -fn main() { +async fn main() { let mut console = Console::new(); write!(console, "[test-results]\n").unwrap(); diff --git a/examples/hello.rs b/examples/hello.rs index a1e30f21..c95bbd80 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -5,11 +5,11 @@ use libtock::console::Console; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let mut console = Console::new(); for i in 0.. { writeln!(console, "Hello world! {}", i).unwrap(); - timer::sleep(Duration::from_ms(500)) + timer::sleep(Duration::from_ms(500)).await; } } diff --git a/examples/panic.rs b/examples/panic.rs index 43684153..8c58ac4b 100644 --- a/examples/panic.rs +++ b/examples/panic.rs @@ -1,6 +1,6 @@ #![no_std] -fn main() { +async fn main() { let _ = libtock::LibTock {}; panic!("Bye world!"); } diff --git a/examples/sensors.rs b/examples/sensors.rs index 7b3afd38..acd36e97 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs @@ -6,7 +6,7 @@ use libtock::sensors::*; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let mut console = Console::new(); let mut humidity = HumiditySensor; let mut temperature = TemperatureSensor; @@ -17,6 +17,6 @@ fn main() { writeln!(console, "Temperature: {}\n", temperature.read()).unwrap(); writeln!(console, "Light: {}\n", light.read()).unwrap(); writeln!(console, "Accel: {}\n", ninedof.read_acceleration()).unwrap(); - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; } } diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs index 9f767e6a..9e5752d5 100644 --- a/examples/seven_segment.rs +++ b/examples/seven_segment.rs @@ -22,7 +22,7 @@ fn number_to_bits(n: u8) -> [bool; 8] { } // Example works on a shift register on P0.03, P0.04, P0.28 -fn main() { +async fn main() { let shift_register = ShiftRegister::new( GpioPinUnitialized::new(0).open_for_write().unwrap(), GpioPinUnitialized::new(1).open_for_write().unwrap(), @@ -33,6 +33,6 @@ fn main() { loop { i = (i + 1) % 11; shift_register.write_bits(&number_to_bits(i)); - timer::sleep(Duration::from_ms(200)); + timer::sleep(Duration::from_ms(200)).await; } } diff --git a/examples/simple_ble.rs b/examples/simple_ble.rs index a467f970..e8ce3e8b 100644 --- a/examples/simple_ble.rs +++ b/examples/simple_ble.rs @@ -15,7 +15,7 @@ struct LedCommand { } #[allow(unused_variables)] -fn main() { +async fn main() { let led = led::get(0).unwrap(); let uuid: [u8; 2] = [0x00, 0x18]; @@ -41,11 +41,10 @@ fn main() { gap_payload.add_service_payload([91, 79], &payload).unwrap(); let handle = BleAdvertisingDriver::initialize(100, &gap_payload, &mut buffer).unwrap(); - loop { led.on(); - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; led.off(); - timer::sleep(Duration::from_ms(500)); + timer::sleep(Duration::from_ms(500)).await; } } diff --git a/examples/temperature.rs b/examples/temperature.rs index 39290f83..5d7fd7f0 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs @@ -2,19 +2,10 @@ use core::fmt::Write; use libtock::console::Console; -use libtock::syscalls; use libtock::temperature; -fn main() { +async fn main() { let mut console = Console::new(); - - let mut with_callback = temperature::with_callback(|result: isize| { - writeln!(console, "Temperature: {}", result).unwrap(); - }); - - let _temperature = with_callback.start_measurement(); - - loop { - syscalls::yieldk(); - } + let temperature = temperature::measure_temperature().await; + writeln!(console, "Temperature: {}", temperature).unwrap(); } diff --git a/examples/timer_subscribe.rs b/examples/timer_subscribe.rs index 28148c67..77d7042c 100644 --- a/examples/timer_subscribe.rs +++ b/examples/timer_subscribe.rs @@ -6,7 +6,7 @@ use libtock::syscalls; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let mut console = Console::new(); let mut with_callback = timer::with_callback(|_, _| { diff --git a/rust-toolchain b/rust-toolchain index e3041272..22e90489 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2019-09-19 +nightly-2019-11-06 diff --git a/src/buttons.rs b/src/buttons.rs index 1bd29d3f..916e052e 100644 --- a/src/buttons.rs +++ b/src/buttons.rs @@ -78,7 +78,7 @@ impl<'a> Buttons<'a> { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ButtonState { Pressed, Released, diff --git a/src/console.rs b/src/console.rs index ecd7ad1f..7942fb7b 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,5 +1,7 @@ +use crate::futures; use crate::syscalls; use core::cell::Cell; +use core::executor; use core::fmt; const DRIVER_NUMBER: usize = 1; @@ -65,7 +67,7 @@ impl Console { return; } - syscalls::yieldk_for(|| is_written.get()); + executor::block_on(futures::wait_until(|| is_written.get())); } } diff --git a/src/futures.rs b/src/futures.rs new file mode 100644 index 00000000..02235071 --- /dev/null +++ b/src/futures.rs @@ -0,0 +1,29 @@ +use core::future::Future; +use core::pin::Pin; +use core::task::Context; +use core::task::Poll; + +// TODO: Consider using FnMut +pub async fn wait_until bool>(condition: F) { + wait_for_value(move || if condition() { Some(()) } else { None }).await +} + +pub async fn wait_for_value Option>(value_provider: F) -> T { + WaitForValue { value_provider }.await +} + +struct WaitForValue { + value_provider: F, +} + +impl Option> Future for WaitForValue { + type Output = T; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + if let Some(value) = (self.value_provider)() { + Poll::Ready(value) + } else { + Poll::Pending + } + } +} diff --git a/src/lang_items.rs b/src/lang_items.rs index c63a9c17..c27c549e 100644 --- a/src/lang_items.rs +++ b/src/lang_items.rs @@ -22,6 +22,8 @@ use crate::led; use crate::timer; use crate::timer::Duration; use core::alloc::Layout; +use core::executor; +use core::future::Future; use core::panic::PanicInfo; #[lang = "start"] @@ -32,12 +34,17 @@ where main().report() } +#[lang = "termination"] pub trait Termination { fn report(self) -> i32; } -impl Termination for () { +impl Termination for T +where + T: Future, +{ fn report(self) -> i32 { + executor::block_on(self); 0 } } @@ -48,25 +55,33 @@ fn panic_handler(_info: &PanicInfo) -> ! { super::debug::low_level_status_code(1); // Flash all LEDs (if available). - loop { - for led in led::all() { - led.on(); - } - timer::sleep(Duration::from_ms(100)); - for led in led::all() { - led.off(); + executor::block_on(async { + loop { + for led in led::all() { + led.on(); + } + timer::sleep(Duration::from_ms(100)).await; + for led in led::all() { + led.off(); + } + timer::sleep(Duration::from_ms(100)).await; } - timer::sleep(Duration::from_ms(100)); - } + }); + // Never type is not supported for T in Future + unreachable!() } #[alloc_error_handler] fn cycle_leds(_: Layout) -> ! { - loop { - for led in led::all() { - led.on(); - timer::sleep(Duration::from_ms(100)); - led.off(); + executor::block_on(async { + loop { + for led in led::all() { + led.on(); + timer::sleep(Duration::from_ms(100)).await; + led.off(); + } } - } + }); + // Never type is not supported for T in Future + unreachable!() } diff --git a/src/lib.rs b/src/lib.rs index 1d4f26bf..004c4d3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub mod buttons; pub mod console; pub mod debug; pub mod electronics; +pub mod futures; pub mod gpio; pub mod led; pub mod memop; diff --git a/src/rng.rs b/src/rng.rs index 411030e0..955e2735 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -1,3 +1,4 @@ +use crate::futures; use crate::syscalls; use core::cell::Cell; @@ -15,7 +16,7 @@ mod allow_nr { pub const SHARE_BUFFER: usize = 0; } -pub fn fill_buffer(buf: &mut [u8]) -> bool { +pub async fn fill_buffer(buf: &mut [u8]) -> bool { let buf_len = buf.len(); let result = syscalls::allow(DRIVER_NUMBER, allow_nr::SHARE_BUFFER, buf); @@ -40,6 +41,6 @@ pub fn fill_buffer(buf: &mut [u8]) -> bool { return false; } - syscalls::yieldk_for(|| is_filled.get()); - return true; + futures::wait_until(|| is_filled.get()).await; + true } diff --git a/src/sensors/mod.rs b/src/sensors/mod.rs index f15a9dbc..7e62d8e5 100644 --- a/src/sensors/mod.rs +++ b/src/sensors/mod.rs @@ -1,6 +1,8 @@ -use crate::syscalls::{self, yieldk_for}; +use crate::futures; +use crate::syscalls; use core::cell::Cell; use core::convert::From; +use core::executor; use core::fmt; use core::mem; @@ -30,7 +32,7 @@ pub trait Sensor> { mem::transmute(&res), ); syscalls::command(driver_num, 1, 0, 0); - yieldk_for(|| res.get().is_some()); + executor::block_on(futures::wait_until(|| res.get().is_some())); res.get().unwrap() } } diff --git a/src/sensors/ninedof.rs b/src/sensors/ninedof.rs index a7a3a7e7..7c347c85 100644 --- a/src/sensors/ninedof.rs +++ b/src/sensors/ninedof.rs @@ -1,5 +1,7 @@ -use crate::syscalls::{self, yieldk_for}; +use crate::futures; +use crate::syscalls; use core::cell::Cell; +use core::executor; use core::fmt; use core::mem; @@ -36,7 +38,7 @@ impl Ninedof { unsafe { subscribe(Self::cb, mem::transmute(&res)); start_accel_reading(); - yieldk_for(|| res.ready.get()); + executor::block_on(futures::wait_until(|| res.ready.get())); } res.res.get() } @@ -46,7 +48,7 @@ impl Ninedof { unsafe { subscribe(Self::cb, mem::transmute(&res)); start_magnetometer_reading(); - yieldk_for(|| res.ready.get()); + executor::block_on(futures::wait_until(|| res.ready.get())); } res.res.get() } diff --git a/src/syscalls.rs b/src/syscalls.rs index 58b7ced6..0dad1309 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -2,6 +2,11 @@ use crate::callback::CallbackSubscription; use crate::callback::SubscribableCallback; use crate::shared_memory::SharedMemory; +#[export_name = "libtock::syscalls::yieldk"] +pub fn yieldk_c() { + yieldk() +} + #[cfg(target_arch = "arm")] pub fn yieldk() { // Note: A process stops yielding when there is a callback ready to run, @@ -51,12 +56,6 @@ pub fn yieldk() { } } -pub fn yieldk_for bool>(cond: F) { - while !cond() { - yieldk(); - } -} - pub fn subscribe( driver_number: usize, subscribe_number: usize, diff --git a/src/syscalls_mock.rs b/src/syscalls_mock.rs index 1357a19c..678bbb62 100644 --- a/src/syscalls_mock.rs +++ b/src/syscalls_mock.rs @@ -2,10 +2,6 @@ use crate::callback::CallbackSubscription; use crate::callback::SubscribableCallback; use crate::shared_memory::SharedMemory; -pub fn yieldk_for bool>(_: F) { - unimplemented() -} - pub fn subscribe( _: usize, _: usize, diff --git a/src/temperature.rs b/src/temperature.rs index 214fb784..fb671294 100644 --- a/src/temperature.rs +++ b/src/temperature.rs @@ -1,16 +1,18 @@ use crate::callback::CallbackSubscription; use crate::callback::SubscribableCallback; +use crate::futures; use crate::syscalls; +use core::cell::Cell; const DRIVER_NUMBER: usize = 0x60000; const SUBSCRIBE_CALLBACK: usize = 0; const START_MEASUREMENT: usize = 1; -pub fn with_callback(callback: CB) -> WithCallback { +fn with_callback(callback: CB) -> WithCallback { WithCallback { callback } } -pub struct WithCallback { +struct WithCallback { callback: CB, } @@ -24,9 +26,17 @@ impl WithCallback where Self: SubscribableCallback, { - pub fn start_measurement(&mut self) -> Result { + fn start_measurement(&mut self) -> Result { let subscription = syscalls::subscribe(DRIVER_NUMBER, SUBSCRIBE_CALLBACK, self)?; unsafe { syscalls::command(DRIVER_NUMBER, START_MEASUREMENT, 0, 0) }; Ok(subscription) } } + +pub async fn measure_temperature() -> isize { + let temperature = Cell::>::new(None); + let mut callback = |temp: isize| temperature.set(Some(temp)); + let mut withcallback = with_callback(&mut callback); + let _subscription = withcallback.start_measurement(); + futures::wait_for_value(|| temperature.get()).await +} diff --git a/src/timer.rs b/src/timer.rs index ae60b076..e40c32d5 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,5 +1,6 @@ use crate::callback::CallbackSubscription; use crate::callback::SubscribableCallback; +use crate::futures; use crate::result; use crate::result::TockResult; use crate::result::TockValue; @@ -22,14 +23,14 @@ mod subscribe_nr { pub const SUBSCRIBE_CALLBACK: usize = 0; } -pub fn sleep(duration: Duration) { +pub async fn sleep(duration: Duration) { let expired = Cell::new(false); let mut with_callback = with_callback(|_, _| expired.set(true)); let mut timer = with_callback.init().unwrap(); timer.set_alarm(duration).unwrap(); - syscalls::yieldk_for(|| expired.get()); + futures::wait_until(|| expired.get()).await; } pub fn with_callback(callback: CB) -> WithCallback {