From 2c1a759b4c4a37b1fe81bd623a1ca26576fe9487 Mon Sep 17 00:00:00 2001 From: Woyten Date: Mon, 11 Nov 2019 11:50:31 +0100 Subject: [PATCH 01/16] Add async runtime --- Cargo.toml | 1 + async-support/Cargo.toml | 8 ++++ async-support/src/lib.rs | 96 ++++++++++++++++++++++++++++++++++++++++ rust-toolchain | 2 +- src/syscalls.rs | 5 +++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 async-support/Cargo.toml create mode 100644 async-support/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 29d9b791..efb75af3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ license = "MIT/Apache-2.0" edition = "2018" [dependencies] +core = { package = "async-support", path = "async-support" } linked_list_allocator = "0.6.4" [dev-dependencies] diff --git a/async-support/Cargo.toml b/async-support/Cargo.toml new file mode 100644 index 00000000..cd228cfc --- /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 library for async-await syntax in a no_std environment" + +[dependencies] diff --git a/async-support/src/lib.rs b/async-support/src/lib.rs new file mode 100644 index 00000000..a83b0d99 --- /dev/null +++ b/async-support/src/lib.rs @@ -0,0 +1,96 @@ +#![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; + + const DUMMY_WAKER_VTABLE: RawWakerVTable = + RawWakerVTable::new(get_waker, do_nothing, do_nothing, do_nothing); + const DUMMY_WAKER: RawWaker = RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE); + + extern "Rust" { + #[link_name = "libtock::syscalls::yieldk"] + fn yieldk(); + } + + pub fn block_on(mut future: impl Future) -> T { + let waker = unsafe { Waker::from_raw(DUMMY_WAKER) }; + let mut context = Context::from_waker(&waker); + + loop { + let pinned_future = unsafe { Pin::new_unchecked(&mut future) }; + let result = pinned_future.poll(&mut context); + match result { + 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(DUMMY_WAKER) }; + let mut context = Context::from_waker(&waker); + pinned_future.poll(&mut context) + } + + 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 { + let pin = unsafe { Pin::new_unchecked(&mut Pin::into_inner_unchecked(self).generator) }; + match pin.resume() { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(out) => Poll::Ready(out), + } + } + } + + const fn get_waker(_x: *const ()) -> RawWaker { + DUMMY_WAKER + } + + const fn do_nothing(_x: *const ()) {} +} 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/syscalls.rs b/src/syscalls.rs index c40c4391..f4caca0f 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, From cd7597dbe6a76b4de85cc3c6c750ca4823e56bdc Mon Sep 17 00:00:00 2001 From: Woyten Date: Tue, 12 Nov 2019 12:38:35 +0100 Subject: [PATCH 02/16] Add general purpose waiting future --- examples/adc.rs | 2 +- examples/blink.rs | 3 ++- examples/blink_random.rs | 4 ++-- examples/button_leds.rs | 2 +- examples/button_read.rs | 2 +- examples/button_subscribe.rs | 2 +- examples/gpio.rs | 4 ++-- examples/gpio_read.rs | 2 +- examples/hello.rs | 2 +- examples/sensors.rs | 2 +- examples/seven_segment.rs | 2 +- examples/simple_ble.rs | 4 ++-- src/console.rs | 4 +++- src/futures.rs | 29 +++++++++++++++++++++++++++++ src/lang_items.rs | 6 +++--- src/lib.rs | 1 + src/rng.rs | 4 +++- src/sensors/mod.rs | 6 ++++-- src/sensors/ninedof.rs | 8 +++++--- src/syscalls.rs | 6 ------ src/timer.rs | 16 ++++++++++++++-- 21 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 src/futures.rs diff --git a/examples/adc.rs b/examples/adc.rs index 8ba602ba..5af25215 100644 --- a/examples/adc.rs +++ b/examples/adc.rs @@ -16,6 +16,6 @@ fn main() { loop { adc.sample(0).unwrap(); - timer::sleep(Duration::from_ms(2000)); + timer::sleep_sync(Duration::from_ms(2000)); } } diff --git a/examples/blink.rs b/examples/blink.rs index 8e8980e8..c011be0a 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use libtock::led; use libtock::timer; use libtock::timer::Duration; @@ -21,6 +22,6 @@ fn main() { count = count.wrapping_add(1); // This delay uses an underlying timer in the kernel. - timer::sleep(Duration::from_ms(250)); + executor::block_on(timer::sleep(Duration::from_ms(250))); } } diff --git a/examples/blink_random.rs b/examples/blink_random.rs index d114d397..748de9ae 100644 --- a/examples/blink_random.rs +++ b/examples/blink_random.rs @@ -16,9 +16,9 @@ fn main() { for &x in buf.iter() { blink_nibble(x); - timer::sleep(Duration::from_ms(100)); + timer::sleep_sync(Duration::from_ms(100)); blink_nibble(x >> 4); - timer::sleep(Duration::from_ms(100)); + timer::sleep_sync(Duration::from_ms(100)); } } } diff --git a/examples/button_leds.rs b/examples/button_leds.rs index 2ab76153..ba914868 100644 --- a/examples/button_leds.rs +++ b/examples/button_leds.rs @@ -22,6 +22,6 @@ fn main() { } loop { - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); } } diff --git a/examples/button_read.rs b/examples/button_read.rs index 539fa6c7..507449be 100644 --- a/examples/button_read.rs +++ b/examples/button_read.rs @@ -20,6 +20,6 @@ fn main() { ButtonState::Released => writeln!(console, "released"), } .unwrap(); - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); } } diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs index 6644e8dc..2d356791 100644 --- a/examples/button_subscribe.rs +++ b/examples/button_subscribe.rs @@ -31,6 +31,6 @@ fn main() { } loop { - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); } } diff --git a/examples/gpio.rs b/examples/gpio.rs index a09a2b24..1e918e27 100644 --- a/examples/gpio.rs +++ b/examples/gpio.rs @@ -11,8 +11,8 @@ fn main() { loop { pin.set_high(); - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); pin.set_low(); - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); } } diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs index a5d7f5bb..b5ec69bc 100644 --- a/examples/gpio_read.rs +++ b/examples/gpio_read.rs @@ -18,6 +18,6 @@ fn main() { } else { writeln!(console, "false").unwrap(); } - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); } } diff --git a/examples/hello.rs b/examples/hello.rs index a1e30f21..0117c740 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -10,6 +10,6 @@ fn main() { for i in 0.. { writeln!(console, "Hello world! {}", i).unwrap(); - timer::sleep(Duration::from_ms(500)) + timer::sleep_sync(Duration::from_ms(500)) } } diff --git a/examples/sensors.rs b/examples/sensors.rs index 7b3afd38..f565629b 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs @@ -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_sync(Duration::from_ms(500)); } } diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs index 9f767e6a..22ece37f 100644 --- a/examples/seven_segment.rs +++ b/examples/seven_segment.rs @@ -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_sync(Duration::from_ms(200)); } } diff --git a/examples/simple_ble.rs b/examples/simple_ble.rs index a467f970..65f6d421 100644 --- a/examples/simple_ble.rs +++ b/examples/simple_ble.rs @@ -44,8 +44,8 @@ fn main() { loop { led.on(); - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); led.off(); - timer::sleep(Duration::from_ms(500)); + timer::sleep_sync(Duration::from_ms(500)); } } 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 6d91bb06..39deb023 100644 --- a/src/lang_items.rs +++ b/src/lang_items.rs @@ -48,11 +48,11 @@ fn flash_all_leds(_info: &PanicInfo) -> ! { for led in led::all() { led.on(); } - timer::sleep(Duration::from_ms(100)); + timer::sleep_sync(Duration::from_ms(100)); for led in led::all() { led.off(); } - timer::sleep(Duration::from_ms(100)); + timer::sleep_sync(Duration::from_ms(100)); } } @@ -61,7 +61,7 @@ fn cycle_leds(_: Layout) -> ! { loop { for led in led::all() { led.on(); - timer::sleep(Duration::from_ms(100)); + timer::sleep_sync(Duration::from_ms(100)); led.off(); } } 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..915745cd 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -1,5 +1,7 @@ +use crate::futures; use crate::syscalls; use core::cell::Cell; +use core::executor; const DRIVER_NUMBER: usize = 0x40001; @@ -40,6 +42,6 @@ pub fn fill_buffer(buf: &mut [u8]) -> bool { return false; } - syscalls::yieldk_for(|| is_filled.get()); + executor::block_on(futures::wait_until(|| is_filled.get())); return 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 f4caca0f..8aed4146 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -56,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/timer.rs b/src/timer.rs index ae60b076..94359c11 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,10 +1,12 @@ use crate::callback::CallbackSubscription; use crate::callback::SubscribableCallback; +use crate::futures; use crate::result; use crate::result::TockResult; use crate::result::TockValue; use crate::syscalls; use core::cell::Cell; +use core::executor; use core::isize; use core::ops::{Add, AddAssign, Sub}; @@ -22,14 +24,24 @@ mod subscribe_nr { pub const SUBSCRIBE_CALLBACK: usize = 0; } -pub fn sleep(duration: Duration) { +pub fn sleep_sync(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()); + executor::block_on(futures::wait_until(|| expired.get())); +} + +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(); + + futures::wait_until(|| expired.get()).await; } pub fn with_callback(callback: CB) -> WithCallback { From 806de82f6aa8270a582df852e6eb58b433aa4680 Mon Sep 17 00:00:00 2001 From: torfmaster Date: Tue, 12 Nov 2019 13:54:55 +0100 Subject: [PATCH 03/16] Make temperature driver async. - amend temperature example --- examples/temperature.rs | 16 ++++++++-------- src/temperature.rs | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/examples/temperature.rs b/examples/temperature.rs index 39290f83..a7b332f2 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs @@ -1,20 +1,20 @@ #![no_std] +use core::executor; use core::fmt::Write; use libtock::console::Console; -use libtock::syscalls; use libtock::temperature; +use libtock::timer; 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 result = executor::block_on(async { + timer::sleep(timer::Duration::from_ms(1000)).await; + temperature::measure_temperature().await + }); + + writeln!(console, "Temperature: {}", result).unwrap(); } } 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 +} From ee5de05a22adee1249b1787bbc7533714d7319f6 Mon Sep 17 00:00:00 2001 From: Woyten Date: Tue, 12 Nov 2019 14:15:22 +0100 Subject: [PATCH 04/16] Add async example --- Cargo.toml | 1 + examples/async.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/buttons.rs | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 examples/async.rs diff --git a/Cargo.toml b/Cargo.toml index efb75af3..af525780 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,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/examples/async.rs b/examples/async.rs new file mode 100644 index 00000000..4ec36556 --- /dev/null +++ b/examples/async.rs @@ -0,0 +1,41 @@ +#![no_std] + +use core::executor; +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; + +fn main() { + executor::block_on(future::join(blink_periodically(), blink_on_button_press())); +} + +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/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, From 4c01091b0c9d274458b168fc79b26bfccb6afe59 Mon Sep 17 00:00:00 2001 From: torfmaster Date: Tue, 12 Nov 2019 14:19:24 +0100 Subject: [PATCH 05/16] Update toolchain for travis. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 534939805140e7500e3b653985df7ea6a95f43e4 Mon Sep 17 00:00:00 2001 From: torfmaster Date: Tue, 12 Nov 2019 14:39:51 +0100 Subject: [PATCH 06/16] Remove sleep_sync. --- examples/adc.rs | 11 ++++++---- examples/blink_random.rs | 19 ++++++++++-------- examples/button_leds.rs | 5 ++--- examples/button_read.rs | 17 +++++++++------- examples/button_subscribe.rs | 5 ++--- examples/gpio.rs | 15 ++++++++------ examples/gpio_read.rs | 17 +++++++++------- examples/hello.rs | 11 ++++++---- examples/sensors.rs | 17 +++++++++------- examples/seven_segment.rs | 13 +++++++----- examples/simple_ble.rs | 16 ++++++++------- src/lang_items.rs | 39 ++++++++++++++++++++++-------------- src/timer.rs | 11 ---------- 13 files changed, 109 insertions(+), 87 deletions(-) diff --git a/examples/adc.rs b/examples/adc.rs index 5af25215..f72f913c 100644 --- a/examples/adc.rs +++ b/examples/adc.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use core::fmt::Write; use libtock::adc; use libtock::console::Console; @@ -14,8 +15,10 @@ fn main() { let adc = with_callback.init().unwrap(); - loop { - adc.sample(0).unwrap(); - timer::sleep_sync(Duration::from_ms(2000)); - } + executor::block_on(async { + loop { + adc.sample(0).unwrap(); + timer::sleep(Duration::from_ms(2000)).await; + } + }); } diff --git a/examples/blink_random.rs b/examples/blink_random.rs index 748de9ae..4c5e222e 100644 --- a/examples/blink_random.rs +++ b/examples/blink_random.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use libtock::led; use libtock::rng; use libtock::timer; @@ -11,16 +12,18 @@ fn main() { assert_eq!(num_leds, 4); let mut buf = [0; 64]; - loop { - assert!(rng::fill_buffer(&mut buf)); + executor::block_on(async { + loop { + assert!(rng::fill_buffer(&mut buf)); - for &x in buf.iter() { - blink_nibble(x); - timer::sleep_sync(Duration::from_ms(100)); - blink_nibble(x >> 4); - timer::sleep_sync(Duration::from_ms(100)); + for &x in buf.iter() { + blink_nibble(x); + timer::sleep(Duration::from_ms(100)).await; + blink_nibble(x >> 4); + timer::sleep(Duration::from_ms(100)).await; + } } - } + }); } // Takes the 4 least-significant bits of x, and turn the 4 leds on/off accordingly. diff --git a/examples/button_leds.rs b/examples/button_leds.rs index ba914868..068d002a 100644 --- a/examples/button_leds.rs +++ b/examples/button_leds.rs @@ -3,8 +3,7 @@ use libtock::buttons; use libtock::buttons::ButtonState; use libtock::led; -use libtock::timer; -use libtock::timer::Duration; +use libtock::syscalls; fn main() { let mut with_callback = buttons::with_callback(|button_num: usize, state| { @@ -22,6 +21,6 @@ fn main() { } loop { - timer::sleep_sync(Duration::from_ms(500)); + syscalls::yieldk(); } } diff --git a/examples/button_read.rs b/examples/button_read.rs index 507449be..bc97b2c1 100644 --- a/examples/button_read.rs +++ b/examples/button_read.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use core::fmt::Write; use libtock::buttons; use libtock::buttons::ButtonState; @@ -14,12 +15,14 @@ fn main() { let mut button = buttons.iter_mut().next().unwrap(); let button = button.enable().unwrap(); - loop { - match button.read() { - ButtonState::Pressed => writeln!(console, "pressed"), - ButtonState::Released => writeln!(console, "released"), + executor::block_on(async { + loop { + match button.read() { + ButtonState::Pressed => writeln!(console, "pressed"), + ButtonState::Released => writeln!(console, "released"), + } + .unwrap(); + timer::sleep(Duration::from_ms(500)).await; } - .unwrap(); - timer::sleep_sync(Duration::from_ms(500)); - } + }); } diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs index 2d356791..587c8601 100644 --- a/examples/button_subscribe.rs +++ b/examples/button_subscribe.rs @@ -4,8 +4,7 @@ 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() { @@ -31,6 +30,6 @@ fn main() { } loop { - timer::sleep_sync(Duration::from_ms(500)); + syscalls::yieldk(); } } diff --git a/examples/gpio.rs b/examples/gpio.rs index 1e918e27..2b90b7fe 100644 --- a/examples/gpio.rs +++ b/examples/gpio.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use libtock::gpio::GpioPinUnitialized; use libtock::timer; use libtock::timer::Duration; @@ -9,10 +10,12 @@ fn main() { let pin = GpioPinUnitialized::new(0); let pin = pin.open_for_write().unwrap(); - loop { - pin.set_high(); - timer::sleep_sync(Duration::from_ms(500)); - pin.set_low(); - timer::sleep_sync(Duration::from_ms(500)); - } + executor::block_on(async { + loop { + pin.set_high(); + timer::sleep(Duration::from_ms(500)).await; + pin.set_low(); + timer::sleep(Duration::from_ms(500)).await; + } + }); } diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs index b5ec69bc..a193fedc 100644 --- a/examples/gpio_read.rs +++ b/examples/gpio_read.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use core::fmt::Write; use libtock::console::Console; use libtock::gpio::{GpioPinUnitialized, InputMode}; @@ -12,12 +13,14 @@ fn main() { let pin = GpioPinUnitialized::new(0); let pin = pin.open_for_read(None, InputMode::PullDown).unwrap(); - loop { - if pin.read() { - writeln!(console, "true").unwrap(); - } else { - writeln!(console, "false").unwrap(); + executor::block_on(async { + loop { + if pin.read() { + writeln!(console, "true").unwrap(); + } else { + writeln!(console, "false").unwrap(); + } + timer::sleep(Duration::from_ms(500)).await; } - timer::sleep_sync(Duration::from_ms(500)); - } + }); } diff --git a/examples/hello.rs b/examples/hello.rs index 0117c740..a6da2c71 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use core::fmt::Write; use libtock::console::Console; use libtock::timer; @@ -8,8 +9,10 @@ use libtock::timer::Duration; fn main() { let mut console = Console::new(); - for i in 0.. { - writeln!(console, "Hello world! {}", i).unwrap(); - timer::sleep_sync(Duration::from_ms(500)) - } + executor::block_on(async { + for i in 0.. { + writeln!(console, "Hello world! {}", i).unwrap(); + timer::sleep(Duration::from_ms(500)).await; + } + }); } diff --git a/examples/sensors.rs b/examples/sensors.rs index f565629b..6491b0f9 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use core::fmt::Write; use libtock::console::Console; use libtock::sensors::*; @@ -12,11 +13,13 @@ fn main() { let mut temperature = TemperatureSensor; let mut light = AmbientLightSensor; let mut ninedof = unsafe { Ninedof::new() }; - loop { - writeln!(console, "Humidity: {}\n", humidity.read()).unwrap(); - writeln!(console, "Temperature: {}\n", temperature.read()).unwrap(); - writeln!(console, "Light: {}\n", light.read()).unwrap(); - writeln!(console, "Accel: {}\n", ninedof.read_acceleration()).unwrap(); - timer::sleep_sync(Duration::from_ms(500)); - } + executor::block_on(async { + loop { + writeln!(console, "Humidity: {}\n", humidity.read()).unwrap(); + 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)).await; + } + }); } diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs index 22ece37f..dafa54fa 100644 --- a/examples/seven_segment.rs +++ b/examples/seven_segment.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use libtock::electronics::ShiftRegister; use libtock::gpio::GpioPinUnitialized; use libtock::timer; @@ -30,9 +31,11 @@ fn main() { ); let mut i = 0; - loop { - i = (i + 1) % 11; - shift_register.write_bits(&number_to_bits(i)); - timer::sleep_sync(Duration::from_ms(200)); - } + executor::block_on(async { + loop { + i = (i + 1) % 11; + shift_register.write_bits(&number_to_bits(i)); + timer::sleep(Duration::from_ms(200)).await; + } + }); } diff --git a/examples/simple_ble.rs b/examples/simple_ble.rs index 65f6d421..47928ff2 100644 --- a/examples/simple_ble.rs +++ b/examples/simple_ble.rs @@ -1,5 +1,6 @@ #![no_std] +use core::executor; use libtock::ble_composer; use libtock::ble_composer::BlePayload; use libtock::led; @@ -41,11 +42,12 @@ 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_sync(Duration::from_ms(500)); - led.off(); - timer::sleep_sync(Duration::from_ms(500)); - } + executor::block_on(async { + loop { + led.on(); + timer::sleep(Duration::from_ms(500)).await; + led.off(); + timer::sleep(Duration::from_ms(500)).await; + } + }); } diff --git a/src/lang_items.rs b/src/lang_items.rs index 39deb023..0895e459 100644 --- a/src/lang_items.rs +++ b/src/lang_items.rs @@ -22,6 +22,7 @@ use crate::led; use crate::timer; use crate::timer::Duration; use core::alloc::Layout; +use core::executor; use core::panic::PanicInfo; #[lang = "start"] @@ -44,25 +45,33 @@ impl Termination for () { #[panic_handler] fn flash_all_leds(_info: &PanicInfo) -> ! { - loop { - for led in led::all() { - led.on(); + 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_sync(Duration::from_ms(100)); - for led in led::all() { - led.off(); - } - timer::sleep_sync(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_sync(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/timer.rs b/src/timer.rs index 94359c11..e40c32d5 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -6,7 +6,6 @@ use crate::result::TockResult; use crate::result::TockValue; use crate::syscalls; use core::cell::Cell; -use core::executor; use core::isize; use core::ops::{Add, AddAssign, Sub}; @@ -24,16 +23,6 @@ mod subscribe_nr { pub const SUBSCRIBE_CALLBACK: usize = 0; } -pub fn sleep_sync(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(); - - executor::block_on(futures::wait_until(|| expired.get())); -} - pub async fn sleep(duration: Duration) { let expired = Cell::new(false); let mut with_callback = with_callback(|_, _| expired.set(true)); From bf95b457b29b535341d3988ac4f86be8898bb017 Mon Sep 17 00:00:00 2001 From: Woyten Date: Tue, 12 Nov 2019 19:49:58 +0100 Subject: [PATCH 07/16] Make rng async --- examples/blink_random.rs | 2 +- src/rng.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/blink_random.rs b/examples/blink_random.rs index 4c5e222e..370e847b 100644 --- a/examples/blink_random.rs +++ b/examples/blink_random.rs @@ -14,7 +14,7 @@ fn main() { let mut buf = [0; 64]; executor::block_on(async { loop { - assert!(rng::fill_buffer(&mut buf)); + assert!(rng::fill_buffer(&mut buf).await); for &x in buf.iter() { blink_nibble(x); diff --git a/src/rng.rs b/src/rng.rs index 915745cd..955e2735 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -1,7 +1,6 @@ use crate::futures; use crate::syscalls; use core::cell::Cell; -use core::executor; const DRIVER_NUMBER: usize = 0x40001; @@ -17,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); @@ -42,6 +41,6 @@ pub fn fill_buffer(buf: &mut [u8]) -> bool { return false; } - executor::block_on(futures::wait_until(|| is_filled.get())); - return true; + futures::wait_until(|| is_filled.get()).await; + true } From 6794015326b9e959ddd9ac9c3645bfa265c42bbb Mon Sep 17 00:00:00 2001 From: Woyten Date: Wed, 13 Nov 2019 15:46:30 +0100 Subject: [PATCH 08/16] Remove yieldk_for in syscalls_mock --- src/syscalls_mock.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/syscalls_mock.rs b/src/syscalls_mock.rs index c9d90de5..af9f414b 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, From 6fc64fc1e6a6aa0918f955bbfa19eb495aaa1581 Mon Sep 17 00:00:00 2001 From: Woyten Date: Thu, 14 Nov 2019 09:10:02 +0100 Subject: [PATCH 09/16] Make RawWakerVTable static --- async-support/src/lib.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/async-support/src/lib.rs b/async-support/src/lib.rs index a83b0d99..367fd4e5 100644 --- a/async-support/src/lib.rs +++ b/async-support/src/lib.rs @@ -35,9 +35,8 @@ pub mod executor { use core::task::RawWakerVTable; use core::task::Waker; - const DUMMY_WAKER_VTABLE: RawWakerVTable = - RawWakerVTable::new(get_waker, do_nothing, do_nothing, do_nothing); - const DUMMY_WAKER: RawWaker = RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE); + static DUMMY_WAKER_VTABLE: RawWakerVTable = + RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing); extern "Rust" { #[link_name = "libtock::syscalls::yieldk"] @@ -45,7 +44,7 @@ pub mod executor { } pub fn block_on(mut future: impl Future) -> T { - let waker = unsafe { Waker::from_raw(DUMMY_WAKER) }; + let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; let mut context = Context::from_waker(&waker); loop { @@ -61,7 +60,7 @@ pub mod executor { } pub(crate) fn poll(pinned_future: Pin<&mut F>) -> Poll { - let waker = unsafe { Waker::from_raw(DUMMY_WAKER) }; + let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; let mut context = Context::from_waker(&waker); pinned_future.poll(&mut context) } @@ -88,9 +87,13 @@ pub mod executor { } } - const fn get_waker(_x: *const ()) -> RawWaker { - DUMMY_WAKER + fn clone(_x: *const ()) -> RawWaker { + get_dummy_waker() } - const fn do_nothing(_x: *const ()) {} + fn get_dummy_waker() -> RawWaker { + RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE) + } + + fn do_nothing(_x: *const ()) {} } From d5db030b5512b4b9de92d82d057d833b56acc288 Mon Sep 17 00:00:00 2001 From: torfmaster Date: Thu, 14 Nov 2019 19:06:10 +0100 Subject: [PATCH 10/16] Make main function async --- examples/adc.rs | 13 +++++-------- examples/adc_buffer.rs | 2 +- examples/async.rs | 5 ++--- examples/ble_scanning.rs | 2 +- examples/blink.rs | 2 +- examples/blink_random.rs | 21 +++++++++------------ examples/button_leds.rs | 2 +- examples/button_read.rs | 19 ++++++++----------- examples/button_subscribe.rs | 2 +- examples/gpio.rs | 17 +++++++---------- examples/gpio_read.rs | 19 ++++++++----------- examples/hardware_test.rs | 2 +- examples/hello.rs | 13 +++++-------- examples/panic.rs | 2 +- examples/sensors.rs | 19 ++++++++----------- examples/seven_segment.rs | 2 +- examples/simple_ble.rs | 18 ++++++++---------- examples/temperature.rs | 2 +- examples/timer_subscribe.rs | 2 +- src/lang_items.rs | 8 +++++++- 20 files changed, 77 insertions(+), 95 deletions(-) diff --git a/examples/adc.rs b/examples/adc.rs index f72f913c..202270f8 100644 --- a/examples/adc.rs +++ b/examples/adc.rs @@ -1,13 +1,12 @@ #![no_std] -use core::executor; use core::fmt::Write; use libtock::adc; 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(); @@ -15,10 +14,8 @@ fn main() { let adc = with_callback.init().unwrap(); - executor::block_on(async { - loop { - adc.sample(0).unwrap(); - timer::sleep(Duration::from_ms(2000)).await; - } - }); + loop { + adc.sample(0).unwrap(); + 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 index 4ec36556..f4cc9e7e 100644 --- a/examples/async.rs +++ b/examples/async.rs @@ -1,6 +1,5 @@ #![no_std] -use core::executor; use futures::future; use libtock::buttons; use libtock::buttons::ButtonState; @@ -9,8 +8,8 @@ use libtock::led; use libtock::timer; use libtock::timer::Duration; -fn main() { - executor::block_on(future::join(blink_periodically(), blink_on_button_press())); +async fn main() { + future::join(blink_periodically(), blink_on_button_press()).await; } async fn blink_periodically() { 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 c011be0a..9755ab62 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -5,7 +5,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 diff --git a/examples/blink_random.rs b/examples/blink_random.rs index 370e847b..48bbf5f1 100644 --- a/examples/blink_random.rs +++ b/examples/blink_random.rs @@ -1,29 +1,26 @@ #![no_std] -use core::executor; use libtock::led; 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]; - executor::block_on(async { - loop { - assert!(rng::fill_buffer(&mut buf).await); + loop { + assert!(rng::fill_buffer(&mut buf).await); - for &x in buf.iter() { - blink_nibble(x); - timer::sleep(Duration::from_ms(100)).await; - blink_nibble(x >> 4); - timer::sleep(Duration::from_ms(100)).await; - } + for &x in buf.iter() { + blink_nibble(x); + timer::sleep(Duration::from_ms(100)).await; + blink_nibble(x >> 4); + timer::sleep(Duration::from_ms(100)).await; } - }); + } } // Takes the 4 least-significant bits of x, and turn the 4 leds on/off accordingly. diff --git a/examples/button_leds.rs b/examples/button_leds.rs index 068d002a..bb854222 100644 --- a/examples/button_leds.rs +++ b/examples/button_leds.rs @@ -5,7 +5,7 @@ use libtock::buttons::ButtonState; use libtock::led; 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 { diff --git a/examples/button_read.rs b/examples/button_read.rs index bc97b2c1..336955dd 100644 --- a/examples/button_read.rs +++ b/examples/button_read.rs @@ -1,6 +1,5 @@ #![no_std] -use core::executor; use core::fmt::Write; use libtock::buttons; use libtock::buttons::ButtonState; @@ -8,21 +7,19 @@ 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(); let mut button = buttons.iter_mut().next().unwrap(); let button = button.enable().unwrap(); - executor::block_on(async { - loop { - match button.read() { - ButtonState::Pressed => writeln!(console, "pressed"), - ButtonState::Released => writeln!(console, "released"), - } - .unwrap(); - timer::sleep(Duration::from_ms(500)).await; + loop { + match button.read() { + ButtonState::Pressed => writeln!(console, "pressed"), + ButtonState::Released => writeln!(console, "released"), } - }); + .unwrap(); + timer::sleep(Duration::from_ms(500)).await; + } } diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs index 587c8601..86168098 100644 --- a/examples/button_subscribe.rs +++ b/examples/button_subscribe.rs @@ -7,7 +7,7 @@ use libtock::console::Console; 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| { diff --git a/examples/gpio.rs b/examples/gpio.rs index 2b90b7fe..4d5b9a43 100644 --- a/examples/gpio.rs +++ b/examples/gpio.rs @@ -1,21 +1,18 @@ #![no_std] -use core::executor; use libtock::gpio::GpioPinUnitialized; 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(); - executor::block_on(async { - loop { - pin.set_high(); - timer::sleep(Duration::from_ms(500)).await; - pin.set_low(); - timer::sleep(Duration::from_ms(500)).await; - } - }); + loop { + pin.set_high(); + timer::sleep(Duration::from_ms(500)).await; + pin.set_low(); + timer::sleep(Duration::from_ms(500)).await; + } } diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs index a193fedc..5c18f627 100644 --- a/examples/gpio_read.rs +++ b/examples/gpio_read.rs @@ -1,6 +1,5 @@ #![no_std] -use core::executor; use core::fmt::Write; use libtock::console::Console; use libtock::gpio::{GpioPinUnitialized, InputMode}; @@ -8,19 +7,17 @@ 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(); - executor::block_on(async { - loop { - if pin.read() { - writeln!(console, "true").unwrap(); - } else { - writeln!(console, "false").unwrap(); - } - timer::sleep(Duration::from_ms(500)).await; + loop { + if pin.read() { + writeln!(console, "true").unwrap(); + } else { + writeln!(console, "false").unwrap(); } - }); + 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 a6da2c71..c95bbd80 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,18 +1,15 @@ #![no_std] -use core::executor; use core::fmt::Write; use libtock::console::Console; use libtock::timer; use libtock::timer::Duration; -fn main() { +async fn main() { let mut console = Console::new(); - executor::block_on(async { - for i in 0.. { - writeln!(console, "Hello world! {}", i).unwrap(); - timer::sleep(Duration::from_ms(500)).await; - } - }); + for i in 0.. { + writeln!(console, "Hello world! {}", i).unwrap(); + 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 6491b0f9..acd36e97 100644 --- a/examples/sensors.rs +++ b/examples/sensors.rs @@ -1,25 +1,22 @@ #![no_std] -use core::executor; use core::fmt::Write; use libtock::console::Console; 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; let mut light = AmbientLightSensor; let mut ninedof = unsafe { Ninedof::new() }; - executor::block_on(async { - loop { - writeln!(console, "Humidity: {}\n", humidity.read()).unwrap(); - 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)).await; - } - }); + loop { + writeln!(console, "Humidity: {}\n", humidity.read()).unwrap(); + 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)).await; + } } diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs index dafa54fa..94feb6fd 100644 --- a/examples/seven_segment.rs +++ b/examples/seven_segment.rs @@ -23,7 +23,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(), diff --git a/examples/simple_ble.rs b/examples/simple_ble.rs index 47928ff2..ce083d18 100644 --- a/examples/simple_ble.rs +++ b/examples/simple_ble.rs @@ -1,6 +1,5 @@ #![no_std] -use core::executor; use libtock::ble_composer; use libtock::ble_composer::BlePayload; use libtock::led; @@ -16,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]; @@ -42,12 +41,11 @@ fn main() { gap_payload.add_service_payload([91, 79], &payload).unwrap(); let handle = BleAdvertisingDriver::initialize(100, &gap_payload, &mut buffer).unwrap(); - executor::block_on(async { - loop { - led.on(); - timer::sleep(Duration::from_ms(500)).await; - led.off(); - timer::sleep(Duration::from_ms(500)).await; - } - }); + loop { + led.on(); + timer::sleep(Duration::from_ms(500)).await; + led.off(); + timer::sleep(Duration::from_ms(500)).await; + break; + } } diff --git a/examples/temperature.rs b/examples/temperature.rs index a7b332f2..e86dca31 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs @@ -6,7 +6,7 @@ use libtock::console::Console; use libtock::temperature; use libtock::timer; -fn main() { +async fn main() { let mut console = Console::new(); loop { 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/src/lang_items.rs b/src/lang_items.rs index 89a06428..c27c549e 100644 --- a/src/lang_items.rs +++ b/src/lang_items.rs @@ -23,6 +23,7 @@ use crate::timer; use crate::timer::Duration; use core::alloc::Layout; use core::executor; +use core::future::Future; use core::panic::PanicInfo; #[lang = "start"] @@ -33,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 } } From 272f7b47bc747780c4935ef79e7459eb2c9ec041 Mon Sep 17 00:00:00 2001 From: Woyten Date: Thu, 14 Nov 2019 20:34:31 +0100 Subject: [PATCH 11/16] Improve documentation of async-support --- async-support/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async-support/Cargo.toml b/async-support/Cargo.toml index cd228cfc..9287c6bf 100644 --- a/async-support/Cargo.toml +++ b/async-support/Cargo.toml @@ -3,6 +3,6 @@ name = "async-support" version = "0.1.0" authors = ["Woyten "] edition = "2018" -description = "Libtock specific patch of core library for async-await syntax in a no_std environment" +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] From 193a7aff7d6e2a19034a2a66e3f5950b689492c8 Mon Sep 17 00:00:00 2001 From: Woyten Date: Thu, 14 Nov 2019 21:19:48 +0100 Subject: [PATCH 12/16] Remove unnecessary usages of executor::block_on --- examples/blink.rs | 3 +-- examples/seven_segment.rs | 13 +++++-------- examples/temperature.rs | 13 ++----------- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/examples/blink.rs b/examples/blink.rs index 9755ab62..b731dd7c 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -1,6 +1,5 @@ #![no_std] -use core::executor; use libtock::led; use libtock::timer; use libtock::timer::Duration; @@ -22,6 +21,6 @@ async fn main() { count = count.wrapping_add(1); // This delay uses an underlying timer in the kernel. - executor::block_on(timer::sleep(Duration::from_ms(250))); + timer::sleep(Duration::from_ms(250)).await; } } diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs index 94feb6fd..9e5752d5 100644 --- a/examples/seven_segment.rs +++ b/examples/seven_segment.rs @@ -1,6 +1,5 @@ #![no_std] -use core::executor; use libtock::electronics::ShiftRegister; use libtock::gpio::GpioPinUnitialized; use libtock::timer; @@ -31,11 +30,9 @@ async fn main() { ); let mut i = 0; - executor::block_on(async { - loop { - i = (i + 1) % 11; - shift_register.write_bits(&number_to_bits(i)); - timer::sleep(Duration::from_ms(200)).await; - } - }); + loop { + i = (i + 1) % 11; + shift_register.write_bits(&number_to_bits(i)); + timer::sleep(Duration::from_ms(200)).await; + } } diff --git a/examples/temperature.rs b/examples/temperature.rs index e86dca31..5d7fd7f0 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs @@ -1,20 +1,11 @@ #![no_std] -use core::executor; use core::fmt::Write; use libtock::console::Console; use libtock::temperature; -use libtock::timer; async fn main() { let mut console = Console::new(); - - loop { - let result = executor::block_on(async { - timer::sleep(timer::Duration::from_ms(1000)).await; - temperature::measure_temperature().await - }); - - writeln!(console, "Temperature: {}", result).unwrap(); - } + let temperature = temperature::measure_temperature().await; + writeln!(console, "Temperature: {}", temperature).unwrap(); } From 5a5a204b2524f79d6a91c91c0ce1268fe22c08ef Mon Sep 17 00:00:00 2001 From: torfmaster Date: Thu, 14 Nov 2019 21:32:37 +0100 Subject: [PATCH 13/16] Small changes in the documentation --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 0286fc51..e7a016e4 100644 --- a/README.md +++ b/README.md @@ -52,16 +52,13 @@ 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. From 9ca48f03fb819e12a851b6fcf8195fc7543f018e Mon Sep 17 00:00:00 2001 From: torfmaster Date: Fri, 15 Nov 2019 08:49:36 +0100 Subject: [PATCH 14/16] Fix documentation and example - alloc can be used without feature since Rust 1.36 - remove break from example --- README.md | 2 +- examples/simple_ble.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e7a016e4..4a3efe98 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ async fn main() { ``` 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/examples/simple_ble.rs b/examples/simple_ble.rs index ce083d18..e8ce3e8b 100644 --- a/examples/simple_ble.rs +++ b/examples/simple_ble.rs @@ -46,6 +46,5 @@ async fn main() { timer::sleep(Duration::from_ms(500)).await; led.off(); timer::sleep(Duration::from_ms(500)).await; - break; } } From c37d4280ac91d9238db88cf45c99b10912f686f5 Mon Sep 17 00:00:00 2001 From: Woyten Date: Fri, 15 Nov 2019 10:03:32 +0100 Subject: [PATCH 15/16] Bump new version and add CHANGELOG.md --- CHANGELOG.md | 15 +++++++++++++++ Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md 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 af525780..fca5e62f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libtock" -version = "0.1.0" +version = "0.2.0" authors = ["Tock Project Developers "] license = "MIT/Apache-2.0" edition = "2018" From cda7db9506daa46580b482b373c51878655986b6 Mon Sep 17 00:00:00 2001 From: Woyten Date: Fri, 15 Nov 2019 19:50:22 +0100 Subject: [PATCH 16/16] Improve understandability of async-support --- async-support/src/lib.rs | 47 +++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/async-support/src/lib.rs b/async-support/src/lib.rs index 367fd4e5..7d368202 100644 --- a/async-support/src/lib.rs +++ b/async-support/src/lib.rs @@ -35,22 +35,18 @@ pub mod executor { use core::task::RawWakerVTable; use core::task::Waker; - static DUMMY_WAKER_VTABLE: RawWakerVTable = - RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing); - extern "Rust" { #[link_name = "libtock::syscalls::yieldk"] fn yieldk(); } pub fn block_on(mut future: impl Future) -> T { - let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; - let mut context = Context::from_waker(&waker); + // 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 { - let pinned_future = unsafe { Pin::new_unchecked(&mut future) }; - let result = pinned_future.poll(&mut context); - match result { + match poll(pinned_future.as_mut()) { Poll::Pending => unsafe { yieldk() }, Poll::Ready(value) => { return value; @@ -65,6 +61,23 @@ pub mod executor { 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 { @@ -79,21 +92,15 @@ pub mod executor { type Output = G::Return; fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - let pin = unsafe { Pin::new_unchecked(&mut Pin::into_inner_unchecked(self).generator) }; - match pin.resume() { + // 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), } } } - - fn clone(_x: *const ()) -> RawWaker { - get_dummy_waker() - } - - fn get_dummy_waker() -> RawWaker { - RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE) - } - - fn do_nothing(_x: *const ()) {} }