From 4a7344cb6f33bc6acdb982b7c180e0da81ad2710 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 28 Dec 2020 03:40:28 +0100 Subject: [PATCH] Add embassy-std crate with glue to run embassy on std. --- .vscode/settings.json | 1 - embassy-std/Cargo.toml | 10 +++++ embassy-std/src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++++++ embassy/Cargo.toml | 5 +-- embassy/src/rand.rs | 15 ------- 5 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 embassy-std/Cargo.toml create mode 100644 embassy-std/src/lib.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index ef95cf96e..8c53d2097 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,6 @@ "editor.formatOnSave": true, "rust-analyzer.cargo.allFeatures": false, "rust-analyzer.checkOnSave.allFeatures": false, - "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", "rust-analyzer.checkOnSave.allTargets": false, "files.watcherExclude": { "**/.git/objects/**": true, diff --git a/embassy-std/Cargo.toml b/embassy-std/Cargo.toml new file mode 100644 index 000000000..2a8028137 --- /dev/null +++ b/embassy-std/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "embassy-std" +version = "0.1.0" +authors = ["Dario Nieuwenhuis "] +edition = "2018" + +[dependencies] +embassy = { version = "0.1.0", path = "../embassy", features = ["std"] } +lazy_static = "1.4.0" +rand_core = { version = "0.6.0", features = ["std"] } diff --git a/embassy-std/src/lib.rs b/embassy-std/src/lib.rs new file mode 100644 index 000000000..2fb814b4d --- /dev/null +++ b/embassy-std/src/lib.rs @@ -0,0 +1,95 @@ +use embassy::executor::Executor; +use embassy::time::TICKS_PER_SECOND; +use embassy::time::{Alarm, Clock}; +use embassy::util::Forever; +use rand_core::{OsRng, RngCore}; +use std::mem::MaybeUninit; +use std::sync::{Condvar, Mutex}; +use std::time::{Duration as StdDuration, Instant as StdInstant}; + +static mut CLOCK_ZERO: MaybeUninit = MaybeUninit::uninit(); +struct StdClock; +impl Clock for StdClock { + fn now(&self) -> u64 { + let zero = unsafe { CLOCK_ZERO.as_ptr().read() }; + let dur = StdInstant::now().duration_since(zero); + dur.as_secs() * (TICKS_PER_SECOND as u64) + + (dur.subsec_nanos() as u64) * (TICKS_PER_SECOND as u64) / 1_000_000_000 + } +} + +struct StdRand; +impl embassy::rand::Rand for StdRand { + fn rand(&self, buf: &mut [u8]) { + OsRng.fill_bytes(buf); + } +} + +static mut ALARM_AT: u64 = u64::MAX; + +pub struct StdAlarm; +impl Alarm for StdAlarm { + fn set_callback(&self, _callback: fn()) {} + fn set(&self, timestamp: u64) { + unsafe { ALARM_AT = timestamp } + } + + fn clear(&self) { + unsafe { ALARM_AT = u64::MAX } + } +} + +static EXECUTOR: Forever = Forever::new(); + +lazy_static::lazy_static! { + static ref MUTEX: Mutex = Mutex::new(false); + static ref CONDVAR: Condvar = Condvar::new(); +} + +pub fn init() -> &'static Executor { + unsafe { + CLOCK_ZERO.as_mut_ptr().write(StdInstant::now()); + embassy::time::set_clock(&StdClock); + embassy::rand::set_rand(&StdRand); + + EXECUTOR.put(Executor::new_with_alarm(&StdAlarm, || { + let mut signaled = MUTEX.lock().unwrap(); + *signaled = true; + CONDVAR.notify_one(); + })) + } +} + +pub fn run(executor: &'static Executor) -> ! { + unsafe { + loop { + executor.run(); + + let mut signaled = MUTEX.lock().unwrap(); + while !*signaled { + let alarm_at = ALARM_AT; + if alarm_at == u64::MAX { + signaled = CONDVAR.wait(signaled).unwrap(); + } else { + let now = StdClock.now(); + if now >= alarm_at { + break; + } + + let left = alarm_at - now; + let dur = StdDuration::new( + left / (TICKS_PER_SECOND as u64), + (left % (TICKS_PER_SECOND as u64) * 1_000_000_000 + / (TICKS_PER_SECOND as u64)) as u32, + ); + let (signaled2, timeout) = CONDVAR.wait_timeout(signaled, dur).unwrap(); + signaled = signaled2; + if timeout.timed_out() { + break; + } + } + } + *signaled = false; + } + } +} diff --git a/embassy/Cargo.toml b/embassy/Cargo.toml index 8b05e29fe..1d16d1110 100644 --- a/embassy/Cargo.toml +++ b/embassy/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Dario Nieuwenhuis "] edition = "2018" [features] -std = ["futures/std", "rand_core"] +std = ["futures/std"] defmt-trace = [] defmt-debug = [] defmt-info = [] @@ -16,9 +16,6 @@ defmt-error = [] defmt = { version = "0.1.3", optional = true } log = { version = "0.4.11", optional = true } -# std-only -rand_core = { version = "0.5.1", optional = true, features = ["std"] } - cortex-m = "0.6.4" futures = { version = "0.3.5", default-features = false } pin-project = { version = "1.0.2", default-features = false } diff --git a/embassy/src/rand.rs b/embassy/src/rand.rs index 6e78c24ae..7e3788380 100644 --- a/embassy/src/rand.rs +++ b/embassy/src/rand.rs @@ -4,9 +4,6 @@ pub trait Rand { fn rand(&self, buf: &mut [u8]); } -#[cfg(feature = "std")] -static mut RAND: Option<&'static dyn Rand> = Some(&if_std::Rand); -#[cfg(not(feature = "std"))] static mut RAND: Option<&'static dyn Rand> = None; pub unsafe fn set_rand(rand: &'static dyn Rand) { @@ -16,15 +13,3 @@ pub unsafe fn set_rand(rand: &'static dyn Rand) { pub fn rand(buf: &mut [u8]) { unsafe { unwrap!(RAND, "No rand set").rand(buf) } } - -#[cfg(feature = "std")] -mod if_std { - use rand_core::{OsRng, RngCore}; - - pub(crate) struct Rand; - impl super::Rand for Rand { - fn rand(&self, buf: &mut [u8]) { - OsRng.fill_bytes(buf) - } - } -}