Add embassy-std crate with glue to run embassy on std.

This commit is contained in:
Dario Nieuwenhuis 2020-12-28 03:40:28 +01:00
parent 32c67381df
commit 4a7344cb6f
5 changed files with 106 additions and 20 deletions

View file

@ -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,

10
embassy-std/Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "embassy-std"
version = "0.1.0"
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
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"] }

95
embassy-std/src/lib.rs Normal file
View file

@ -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<StdInstant> = 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<Executor> = Forever::new();
lazy_static::lazy_static! {
static ref MUTEX: Mutex<bool> = 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;
}
}
}

View file

@ -5,7 +5,7 @@ authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
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 }

View file

@ -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)
}
}
}