Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add future runtime to libtock-rs #103

Merged
merged 17 commits into from
Nov 22, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: rust
rust:
- nightly-2019-09-19
- nightly-2019-11-06

os:
- linux
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ license = "MIT/Apache-2.0"
edition = "2018"

[dependencies]
core = { package = "async-support", path = "async-support" }
linked_list_allocator = "0.6.4"

[dev-dependencies]
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"
Expand Down
8 changes: 8 additions & 0 deletions async-support/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "async-support"
version = "0.1.0"
authors = ["Woyten <[email protected]>"]
edition = "2018"
description = "Libtock specific patch of core library for async-await syntax in a no_std environment"

[dependencies]
96 changes: 96 additions & 0 deletions async-support/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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>(f: Pin<&mut F>) -> Poll<F::Output>
where
F: Future,
{
crate::executor::poll(f)
}

pub fn from_generator<G: Generator<Yield = ()>>(
generator: G,
) -> impl Future<Output = G::Return> {
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();
}
Woyten marked this conversation as resolved.
Show resolved Hide resolved

pub fn block_on<T>(mut future: impl Future<Output = T>) -> 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<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> {
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<G: Generator<Yield = ()>>(
generator: G,
) -> impl Future<Output = G::Return> {
GeneratorFuture { generator }
}

struct GeneratorFuture<G> {
generator: G,
}

impl<G: Generator<Yield = ()>> Future for GeneratorFuture<G> {
type Output = G::Return;

fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
let pin = unsafe { Pin::new_unchecked(&mut Pin::into_inner_unchecked(self).generator) };
Woyten marked this conversation as resolved.
Show resolved Hide resolved
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 ()) {}
}
jrvanwhy marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 7 additions & 4 deletions examples/adc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use core::fmt::Write;
use libtock::adc;
use libtock::console::Console;
Expand All @@ -14,8 +15,10 @@ fn main() {

let adc = with_callback.init().unwrap();

loop {
adc.sample(0).unwrap();
timer::sleep(Duration::from_ms(2000));
}
executor::block_on(async {
loop {
adc.sample(0).unwrap();
timer::sleep(Duration::from_ms(2000)).await;
}
});
}
41 changes: 41 additions & 0 deletions examples/async.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
3 changes: 2 additions & 1 deletion examples/blink.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use libtock::led;
use libtock::timer;
use libtock::timer::Duration;
Expand All @@ -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)));
}
}
19 changes: 11 additions & 8 deletions examples/blink_random.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use libtock::led;
use libtock::rng;
use libtock::timer;
Expand All @@ -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).await);

for &x in buf.iter() {
blink_nibble(x);
timer::sleep(Duration::from_ms(100));
blink_nibble(x >> 4);
timer::sleep(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.
Expand Down
5 changes: 2 additions & 3 deletions examples/button_leds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand All @@ -22,6 +21,6 @@ fn main() {
}

loop {
timer::sleep(Duration::from_ms(500));
syscalls::yieldk();
}
}
17 changes: 10 additions & 7 deletions examples/button_read.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use core::fmt::Write;
use libtock::buttons;
use libtock::buttons::ButtonState;
Expand All @@ -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(Duration::from_ms(500));
}
});
}
5 changes: 2 additions & 3 deletions examples/button_subscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -31,6 +30,6 @@ fn main() {
}

loop {
timer::sleep(Duration::from_ms(500));
syscalls::yieldk();
}
}
15 changes: 9 additions & 6 deletions examples/gpio.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use libtock::gpio::GpioPinUnitialized;
use libtock::timer;
use libtock::timer::Duration;
Expand All @@ -9,10 +10,12 @@ fn main() {
let pin = GpioPinUnitialized::new(0);
let pin = pin.open_for_write().unwrap();

loop {
pin.set_high();
timer::sleep(Duration::from_ms(500));
pin.set_low();
timer::sleep(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;
}
});
}
17 changes: 10 additions & 7 deletions examples/gpio_read.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use core::fmt::Write;
use libtock::console::Console;
use libtock::gpio::{GpioPinUnitialized, InputMode};
Expand All @@ -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(Duration::from_ms(500));
}
});
}
11 changes: 7 additions & 4 deletions examples/hello.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]

use core::executor;
use core::fmt::Write;
use libtock::console::Console;
use libtock::timer;
Expand All @@ -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(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;
}
});
}
Loading