time: allow storing state inside the driver struct.
This commit is contained in:
parent
55b2d7b524
commit
7c0990ad1e
@ -82,7 +82,7 @@ impl AlarmState {
|
|||||||
|
|
||||||
const ALARM_COUNT: usize = 3;
|
const ALARM_COUNT: usize = 3;
|
||||||
|
|
||||||
struct State {
|
struct RtcDriver {
|
||||||
/// Number of 2^23 periods elapsed since boot.
|
/// Number of 2^23 periods elapsed since boot.
|
||||||
period: AtomicU32,
|
period: AtomicU32,
|
||||||
alarm_count: AtomicU8,
|
alarm_count: AtomicU8,
|
||||||
@ -91,13 +91,13 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
||||||
static STATE: State = State {
|
embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||||
period: AtomicU32::new(0),
|
period: AtomicU32::new(0),
|
||||||
alarm_count: AtomicU8::new(0),
|
alarm_count: AtomicU8::new(0),
|
||||||
alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
|
alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
|
||||||
};
|
});
|
||||||
|
|
||||||
impl State {
|
impl RtcDriver {
|
||||||
fn init(&'static self, irq_prio: crate::interrupt::Priority) {
|
fn init(&'static self, irq_prio: crate::interrupt::Priority) {
|
||||||
let r = rtc();
|
let r = rtc();
|
||||||
r.cc[3].write(|w| unsafe { w.bits(0x800000) });
|
r.cc[3].write(|w| unsafe { w.bits(0x800000) });
|
||||||
@ -159,14 +159,6 @@ impl State {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn now(&self) -> u64 {
|
|
||||||
// `period` MUST be read before `counter`, see comment at the top for details.
|
|
||||||
let period = self.period.load(Ordering::Relaxed);
|
|
||||||
compiler_fence(Ordering::Acquire);
|
|
||||||
let counter = rtc().counter.read().bits();
|
|
||||||
calc_now(period, counter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
|
fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
|
||||||
// safety: we're allowed to assume the AlarmState is created by us, and
|
// safety: we're allowed to assume the AlarmState is created by us, and
|
||||||
// we never create one that's out of bounds.
|
// we never create one that's out of bounds.
|
||||||
@ -188,8 +180,18 @@ impl State {
|
|||||||
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
|
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
|
||||||
f(alarm.ctx.get());
|
f(alarm.ctx.get());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
impl Driver for RtcDriver {
|
||||||
|
fn now(&self) -> u64 {
|
||||||
|
// `period` MUST be read before `counter`, see comment at the top for details.
|
||||||
|
let period = self.period.load(Ordering::Relaxed);
|
||||||
|
compiler_fence(Ordering::Acquire);
|
||||||
|
let counter = rtc().counter.read().bits();
|
||||||
|
calc_now(period, counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||||
let id = self
|
let id = self
|
||||||
.alarm_count
|
.alarm_count
|
||||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||||
@ -201,7 +203,7 @@ impl State {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match id {
|
match id {
|
||||||
Ok(id) => Some(unsafe { AlarmHandle::new(id) }),
|
Ok(id) => Some(AlarmHandle::new(id)),
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,32 +265,11 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RtcDriver;
|
|
||||||
embassy::time_driver_impl!(RtcDriver);
|
|
||||||
|
|
||||||
impl Driver for RtcDriver {
|
|
||||||
fn now() -> u64 {
|
|
||||||
STATE.now()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn allocate_alarm() -> Option<AlarmHandle> {
|
|
||||||
STATE.allocate_alarm()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
|
||||||
STATE.set_alarm_callback(alarm, callback, ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
|
||||||
STATE.set_alarm(alarm, timestamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn RTC1() {
|
fn RTC1() {
|
||||||
STATE.on_interrupt()
|
DRIVER.on_interrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
||||||
STATE.init(irq_prio)
|
DRIVER.init(irq_prio)
|
||||||
}
|
}
|
||||||
|
@ -19,38 +19,40 @@ const DUMMY_ALARM: AlarmState = AlarmState {
|
|||||||
callback: Cell::new(None),
|
callback: Cell::new(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]);
|
struct TimerDriver {
|
||||||
static NEXT_ALARM: AtomicU8 = AtomicU8::new(0);
|
alarms: Mutex<[AlarmState; ALARM_COUNT]>,
|
||||||
|
next_alarm: AtomicU8,
|
||||||
|
}
|
||||||
|
|
||||||
fn now() -> u64 {
|
embassy::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
|
||||||
loop {
|
alarms: Mutex::new([DUMMY_ALARM; ALARM_COUNT]),
|
||||||
unsafe {
|
next_alarm: AtomicU8::new(0),
|
||||||
let hi = pac::TIMER.timerawh().read();
|
});
|
||||||
let lo = pac::TIMER.timerawl().read();
|
|
||||||
let hi2 = pac::TIMER.timerawh().read();
|
impl Driver for TimerDriver {
|
||||||
if hi == hi2 {
|
fn now(&self) -> u64 {
|
||||||
return (hi as u64) << 32 | (lo as u64);
|
loop {
|
||||||
|
unsafe {
|
||||||
|
let hi = pac::TIMER.timerawh().read();
|
||||||
|
let lo = pac::TIMER.timerawl().read();
|
||||||
|
let hi2 = pac::TIMER.timerawh().read();
|
||||||
|
if hi == hi2 {
|
||||||
|
return (hi as u64) << 32 | (lo as u64);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct TimerDriver;
|
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||||
embassy::time_driver_impl!(TimerDriver);
|
let id = self
|
||||||
|
.next_alarm
|
||||||
impl Driver for TimerDriver {
|
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||||
fn now() -> u64 {
|
if x < ALARM_COUNT as u8 {
|
||||||
now()
|
Some(x + 1)
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
unsafe fn allocate_alarm() -> Option<AlarmHandle> {
|
}
|
||||||
let id = NEXT_ALARM.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
});
|
||||||
if x < ALARM_COUNT as u8 {
|
|
||||||
Some(x + 1)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
match id {
|
match id {
|
||||||
Ok(id) => Some(AlarmHandle::new(id)),
|
Ok(id) => Some(AlarmHandle::new(id)),
|
||||||
@ -58,18 +60,18 @@ impl Driver for TimerDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
||||||
let n = alarm.id() as usize;
|
let n = alarm.id() as usize;
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
let alarm = &ALARMS.borrow(cs)[n];
|
let alarm = &self.alarms.borrow(cs)[n];
|
||||||
alarm.callback.set(Some((callback, ctx)));
|
alarm.callback.set(Some((callback, ctx)));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
|
||||||
let n = alarm.id() as usize;
|
let n = alarm.id() as usize;
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
let alarm = &ALARMS.borrow(cs)[n];
|
let alarm = &self.alarms.borrow(cs)[n];
|
||||||
alarm.timestamp.set(timestamp);
|
alarm.timestamp.set(timestamp);
|
||||||
|
|
||||||
// Arm it.
|
// Arm it.
|
||||||
@ -78,44 +80,46 @@ impl Driver for TimerDriver {
|
|||||||
// it is checked if the alarm time has passed.
|
// it is checked if the alarm time has passed.
|
||||||
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
|
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
|
||||||
|
|
||||||
let now = now();
|
let now = self.now();
|
||||||
|
|
||||||
// If alarm timestamp has passed, trigger it instantly.
|
// If alarm timestamp has passed, trigger it instantly.
|
||||||
// This disarms it.
|
// This disarms it.
|
||||||
if timestamp <= now {
|
if timestamp <= now {
|
||||||
trigger_alarm(n, cs);
|
self.trigger_alarm(n, cs);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_alarm(n: usize) {
|
impl TimerDriver {
|
||||||
critical_section::with(|cs| {
|
fn check_alarm(&self, n: usize) {
|
||||||
let alarm = &ALARMS.borrow(cs)[n];
|
critical_section::with(|cs| {
|
||||||
let timestamp = alarm.timestamp.get();
|
let alarm = &self.alarms.borrow(cs)[n];
|
||||||
if timestamp <= now() {
|
let timestamp = alarm.timestamp.get();
|
||||||
trigger_alarm(n, cs)
|
if timestamp <= self.now() {
|
||||||
} else {
|
self.trigger_alarm(n, cs)
|
||||||
// Not elapsed, arm it again.
|
} else {
|
||||||
// This can happen if it was set more than 2^32 us in the future.
|
// Not elapsed, arm it again.
|
||||||
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
|
// This can happen if it was set more than 2^32 us in the future.
|
||||||
|
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// clear the irq
|
||||||
|
unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
|
||||||
|
// disarm
|
||||||
|
unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) }
|
||||||
|
|
||||||
|
let alarm = &self.alarms.borrow(cs)[n];
|
||||||
|
alarm.timestamp.set(u64::MAX);
|
||||||
|
|
||||||
|
// Call after clearing alarm, so the callback can set another alarm.
|
||||||
|
if let Some((f, ctx)) = alarm.callback.get() {
|
||||||
|
f(ctx);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// clear the irq
|
|
||||||
unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trigger_alarm(n: usize, cs: CriticalSection) {
|
|
||||||
// disarm
|
|
||||||
unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) }
|
|
||||||
|
|
||||||
let alarm = &ALARMS.borrow(cs)[n];
|
|
||||||
alarm.timestamp.set(u64::MAX);
|
|
||||||
|
|
||||||
// Call after clearing alarm, so the callback can set another alarm.
|
|
||||||
if let Some((f, ctx)) = alarm.callback.get() {
|
|
||||||
f(ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +127,7 @@ fn trigger_alarm(n: usize, cs: CriticalSection) {
|
|||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
// init alarms
|
// init alarms
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
let alarms = ALARMS.borrow(cs);
|
let alarms = DRIVER.alarms.borrow(cs);
|
||||||
for a in alarms {
|
for a in alarms {
|
||||||
a.timestamp.set(u64::MAX);
|
a.timestamp.set(u64::MAX);
|
||||||
}
|
}
|
||||||
@ -144,20 +148,20 @@ pub unsafe fn init() {
|
|||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_0() {
|
unsafe fn TIMER_IRQ_0() {
|
||||||
check_alarm(0)
|
DRIVER.check_alarm(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_1() {
|
unsafe fn TIMER_IRQ_1() {
|
||||||
check_alarm(1)
|
DRIVER.check_alarm(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_2() {
|
unsafe fn TIMER_IRQ_2() {
|
||||||
check_alarm(2)
|
DRIVER.check_alarm(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_3() {
|
unsafe fn TIMER_IRQ_3() {
|
||||||
check_alarm(3)
|
DRIVER.check_alarm(3)
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,12 @@ type T = peripherals::TIM3;
|
|||||||
#[cfg(feature = "time-driver-tim2")]
|
#[cfg(feature = "time-driver-tim2")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn TIM2() {
|
fn TIM2() {
|
||||||
STATE.on_interrupt()
|
DRIVER.on_interrupt()
|
||||||
}
|
}
|
||||||
#[cfg(feature = "time-driver-tim3")]
|
#[cfg(feature = "time-driver-tim3")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn TIM3() {
|
fn TIM3() {
|
||||||
STATE.on_interrupt()
|
DRIVER.on_interrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clock timekeeping works with something we call "periods", which are time intervals
|
// Clock timekeeping works with something we call "periods", which are time intervals
|
||||||
@ -76,7 +76,7 @@ impl AlarmState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct RtcDriver {
|
||||||
/// Number of 2^15 periods elapsed since boot.
|
/// Number of 2^15 periods elapsed since boot.
|
||||||
period: AtomicU32,
|
period: AtomicU32,
|
||||||
alarm_count: AtomicU8,
|
alarm_count: AtomicU8,
|
||||||
@ -85,13 +85,14 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
||||||
static STATE: State = State {
|
|
||||||
|
embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||||
period: AtomicU32::new(0),
|
period: AtomicU32::new(0),
|
||||||
alarm_count: AtomicU8::new(0),
|
alarm_count: AtomicU8::new(0),
|
||||||
alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
|
alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
|
||||||
};
|
});
|
||||||
|
|
||||||
impl State {
|
impl RtcDriver {
|
||||||
fn init(&'static self) {
|
fn init(&'static self) {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
@ -185,16 +186,6 @@ impl State {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn now(&self) -> u64 {
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
let period = self.period.load(Ordering::Relaxed);
|
|
||||||
compiler_fence(Ordering::Acquire);
|
|
||||||
// NOTE(unsafe) Atomic read with no side-effects
|
|
||||||
let counter = unsafe { r.cnt().read().cnt() };
|
|
||||||
calc_now(period, counter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
|
fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
|
||||||
// safety: we're allowed to assume the AlarmState is created by us, and
|
// safety: we're allowed to assume the AlarmState is created by us, and
|
||||||
// we never create one that's out of bounds.
|
// we never create one that's out of bounds.
|
||||||
@ -213,8 +204,20 @@ impl State {
|
|||||||
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
|
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
|
||||||
f(alarm.ctx.get());
|
f(alarm.ctx.get());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
impl Driver for RtcDriver {
|
||||||
|
fn now(&self) -> u64 {
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
let period = self.period.load(Ordering::Relaxed);
|
||||||
|
compiler_fence(Ordering::Acquire);
|
||||||
|
// NOTE(unsafe) Atomic read with no side-effects
|
||||||
|
let counter = unsafe { r.cnt().read().cnt() };
|
||||||
|
calc_now(period, counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||||
let id = self
|
let id = self
|
||||||
.alarm_count
|
.alarm_count
|
||||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||||
@ -226,7 +229,7 @@ impl State {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match id {
|
match id {
|
||||||
Ok(id) => Some(unsafe { AlarmHandle::new(id) }),
|
Ok(id) => Some(AlarmHandle::new(id)),
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,29 +272,8 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RtcDriver;
|
|
||||||
embassy::time_driver_impl!(RtcDriver);
|
|
||||||
|
|
||||||
impl Driver for RtcDriver {
|
|
||||||
fn now() -> u64 {
|
|
||||||
STATE.now()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn allocate_alarm() -> Option<AlarmHandle> {
|
|
||||||
STATE.allocate_alarm()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
|
||||||
STATE.set_alarm_callback(alarm, callback, ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
|
||||||
STATE.set_alarm(alarm, timestamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
STATE.init()
|
DRIVER.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
67
embassy/src/executor/arch/std.rs
Normal file
67
embassy/src/executor/arch/std.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::{Condvar, Mutex};
|
||||||
|
|
||||||
|
use super::{raw, Spawner};
|
||||||
|
|
||||||
|
pub struct Executor {
|
||||||
|
inner: raw::Executor,
|
||||||
|
not_send: PhantomData<*mut ()>,
|
||||||
|
signaler: &'static Signaler,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Executor {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let signaler = &*Box::leak(Box::new(Signaler::new()));
|
||||||
|
Self {
|
||||||
|
inner: raw::Executor::new(
|
||||||
|
|p| unsafe {
|
||||||
|
let s = &*(p as *const () as *const Signaler);
|
||||||
|
s.signal()
|
||||||
|
},
|
||||||
|
signaler as *const _ as _,
|
||||||
|
),
|
||||||
|
not_send: PhantomData,
|
||||||
|
signaler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the executor.
|
||||||
|
///
|
||||||
|
/// This function never returns.
|
||||||
|
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
|
||||||
|
init(unsafe { self.inner.spawner() });
|
||||||
|
|
||||||
|
loop {
|
||||||
|
unsafe { self.inner.run_queued() };
|
||||||
|
self.signaler.wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Signaler {
|
||||||
|
mutex: Mutex<bool>,
|
||||||
|
condvar: Condvar,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signaler {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
mutex: Mutex::new(false),
|
||||||
|
condvar: Condvar::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait(&self) {
|
||||||
|
let mut signaled = self.mutex.lock().unwrap();
|
||||||
|
while !*signaled {
|
||||||
|
signaled = self.condvar.wait(signaled).unwrap();
|
||||||
|
}
|
||||||
|
*signaled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signal(&self) {
|
||||||
|
let mut signaled = self.mutex.lock().unwrap();
|
||||||
|
*signaled = true;
|
||||||
|
self.condvar.notify_one();
|
||||||
|
}
|
||||||
|
}
|
@ -26,32 +26,34 @@
|
|||||||
//! This method has a few key advantages for something as foundational as timekeeping:
|
//! This method has a few key advantages for something as foundational as timekeeping:
|
||||||
//!
|
//!
|
||||||
//! - The time driver is available everywhere easily, without having to thread the implementation
|
//! - The time driver is available everywhere easily, without having to thread the implementation
|
||||||
//~ through generic parameters. This is especially helpful for libraries.
|
//! through generic parameters. This is especially helpful for libraries.
|
||||||
//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
|
//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
|
||||||
//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
|
//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
|
||||||
//! would yield incorrect results.
|
//! would yield incorrect results.
|
||||||
//!
|
//!
|
||||||
/// # Example
|
//! # Example
|
||||||
///
|
//!
|
||||||
/// ```
|
//! ```
|
||||||
/// struct MyDriver; // not public!
|
//! use embassy::time::driver::{Driver, AlarmHandle};
|
||||||
/// embassy::time_driver_impl!(MyDriver);
|
//!
|
||||||
///
|
//! struct MyDriver{}; // not public!
|
||||||
/// unsafe impl embassy::time::driver::Driver for MyDriver {
|
//! embassy::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
|
||||||
/// fn now() -> u64 {
|
//!
|
||||||
/// todo!()
|
//! impl Driver for MyDriver {
|
||||||
/// }
|
//! fn now(&self) -> u64 {
|
||||||
/// unsafe fn allocate_alarm() -> Option<AlarmHandle> {
|
//! todo!()
|
||||||
/// todo!()
|
//! }
|
||||||
/// }
|
//! unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||||
/// fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
//! todo!()
|
||||||
/// todo!()
|
//! }
|
||||||
/// }
|
//! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
||||||
/// fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
//! todo!()
|
||||||
/// todo!()
|
//! }
|
||||||
/// }
|
//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
|
||||||
/// }
|
//! todo!()
|
||||||
/// ```
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
/// Alarm handle, assigned by the driver.
|
/// Alarm handle, assigned by the driver.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -76,22 +78,22 @@ impl AlarmHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Time driver
|
/// Time driver
|
||||||
pub trait Driver {
|
pub trait Driver: Send + Sync + 'static {
|
||||||
/// Return the current timestamp in ticks.
|
/// Return the current timestamp in ticks.
|
||||||
/// This is guaranteed to be monotonic, i.e. a call to now() will always return
|
/// This is guaranteed to be monotonic, i.e. a call to now() will always return
|
||||||
/// a greater or equal value than earler calls.
|
/// a greater or equal value than earler calls.
|
||||||
fn now() -> u64;
|
fn now(&self) -> u64;
|
||||||
|
|
||||||
/// Try allocating an alarm handle. Returns None if no alarms left.
|
/// Try allocating an alarm handle. Returns None if no alarms left.
|
||||||
/// Initially the alarm has no callback set, and a null `ctx` pointer.
|
/// Initially the alarm has no callback set, and a null `ctx` pointer.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// It is UB to make the alarm fire before setting a callback.
|
/// It is UB to make the alarm fire before setting a callback.
|
||||||
unsafe fn allocate_alarm() -> Option<AlarmHandle>;
|
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
|
||||||
|
|
||||||
/// Sets the callback function to be called when the alarm triggers.
|
/// Sets the callback function to be called when the alarm triggers.
|
||||||
/// The callback may be called from any context (interrupt or thread mode).
|
/// The callback may be called from any context (interrupt or thread mode).
|
||||||
fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
|
fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
|
||||||
|
|
||||||
/// Sets an alarm at the given timestamp. When the current timestamp reaches that
|
/// Sets an alarm at the given timestamp. When the current timestamp reaches that
|
||||||
/// timestamp, the provided callback funcion will be called.
|
/// timestamp, the provided callback funcion will be called.
|
||||||
@ -99,7 +101,7 @@ pub trait Driver {
|
|||||||
/// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
|
/// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
|
||||||
///
|
///
|
||||||
/// Only one alarm can be active at a time. This overwrites any previously-set alarm if any.
|
/// Only one alarm can be active at a time. This overwrites any previously-set alarm if any.
|
||||||
fn set_alarm(alarm: AlarmHandle, timestamp: u64);
|
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
@ -125,49 +127,34 @@ pub(crate) fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
|||||||
|
|
||||||
/// Set the time Driver implementation.
|
/// Set the time Driver implementation.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// See the module documentation for an example.
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// struct MyDriver; // not public!
|
|
||||||
/// embassy::time_driver_impl!(MyDriver);
|
|
||||||
///
|
|
||||||
/// unsafe impl embassy::time::driver::Driver for MyDriver {
|
|
||||||
/// fn now() -> u64 {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// unsafe fn allocate_alarm() -> Option<AlarmHandle> {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! time_driver_impl {
|
macro_rules! time_driver_impl {
|
||||||
($t: ty) => {
|
(static $name:ident: $t: ty = $val:expr) => {
|
||||||
|
static $name: $t = $val;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn _embassy_time_now() -> u64 {
|
fn _embassy_time_now() -> u64 {
|
||||||
<$t as $crate::time::driver::Driver>::now()
|
<$t as $crate::time::driver::Driver>::now(&$name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe fn _embassy_time_allocate_alarm() -> Option<AlarmHandle> {
|
unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::time::driver::AlarmHandle> {
|
||||||
<$t as $crate::time::driver::Driver>::allocate_alarm()
|
<$t as $crate::time::driver::Driver>::allocate_alarm(&$name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn _embassy_time_set_alarm_callback(
|
fn _embassy_time_set_alarm_callback(
|
||||||
alarm: AlarmHandle,
|
alarm: $crate::time::driver::AlarmHandle,
|
||||||
callback: fn(*mut ()),
|
callback: fn(*mut ()),
|
||||||
ctx: *mut (),
|
ctx: *mut (),
|
||||||
) {
|
) {
|
||||||
<$t as $crate::time::driver::Driver>::set_alarm_callback(alarm, callback, ctx)
|
<$t as $crate::time::driver::Driver>::set_alarm_callback(&$name, alarm, callback, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
fn _embassy_time_set_alarm(alarm: $crate::time::driver::AlarmHandle, timestamp: u64) {
|
||||||
<$t as $crate::time::driver::Driver>::set_alarm(alarm, timestamp)
|
<$t as $crate::time::driver::Driver>::set_alarm(&$name, alarm, timestamp)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user