mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
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;
|
||||
|
||||
struct State {
|
||||
struct RtcDriver {
|
||||
/// Number of 2^23 periods elapsed since boot.
|
||||
period: AtomicU32,
|
||||
alarm_count: AtomicU8,
|
||||
@ -91,13 +91,13 @@ struct State {
|
||||
}
|
||||
|
||||
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
||||
static STATE: State = State {
|
||||
embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
period: AtomicU32::new(0),
|
||||
alarm_count: AtomicU8::new(0),
|
||||
alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
|
||||
};
|
||||
});
|
||||
|
||||
impl State {
|
||||
impl RtcDriver {
|
||||
fn init(&'static self, irq_prio: crate::interrupt::Priority) {
|
||||
let r = rtc();
|
||||
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 {
|
||||
// safety: we're allowed to assume the AlarmState is created by us, and
|
||||
// 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()) };
|
||||
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
|
||||
.alarm_count
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||
@ -201,7 +203,7 @@ impl State {
|
||||
});
|
||||
|
||||
match id {
|
||||
Ok(id) => Some(unsafe { AlarmHandle::new(id) }),
|
||||
Ok(id) => Some(AlarmHandle::new(id)),
|
||||
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]
|
||||
fn RTC1() {
|
||||
STATE.on_interrupt()
|
||||
DRIVER.on_interrupt()
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]);
|
||||
static NEXT_ALARM: AtomicU8 = AtomicU8::new(0);
|
||||
struct TimerDriver {
|
||||
alarms: Mutex<[AlarmState; ALARM_COUNT]>,
|
||||
next_alarm: AtomicU8,
|
||||
}
|
||||
|
||||
fn now() -> 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);
|
||||
embassy::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
|
||||
alarms: Mutex::new([DUMMY_ALARM; ALARM_COUNT]),
|
||||
next_alarm: AtomicU8::new(0),
|
||||
});
|
||||
|
||||
impl Driver for TimerDriver {
|
||||
fn now(&self) -> 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;
|
||||
embassy::time_driver_impl!(TimerDriver);
|
||||
|
||||
impl Driver for TimerDriver {
|
||||
fn now() -> u64 {
|
||||
now()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
});
|
||||
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||
let id = self
|
||||
.next_alarm
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||
if x < ALARM_COUNT as u8 {
|
||||
Some(x + 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
match 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;
|
||||
critical_section::with(|cs| {
|
||||
let alarm = &ALARMS.borrow(cs)[n];
|
||||
let alarm = &self.alarms.borrow(cs)[n];
|
||||
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;
|
||||
critical_section::with(|cs| {
|
||||
let alarm = &ALARMS.borrow(cs)[n];
|
||||
let alarm = &self.alarms.borrow(cs)[n];
|
||||
alarm.timestamp.set(timestamp);
|
||||
|
||||
// Arm it.
|
||||
@ -78,44 +80,46 @@ impl Driver for TimerDriver {
|
||||
// it is checked if the alarm time has passed.
|
||||
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.
|
||||
// This disarms it.
|
||||
if timestamp <= now {
|
||||
trigger_alarm(n, cs);
|
||||
self.trigger_alarm(n, cs);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn check_alarm(n: usize) {
|
||||
critical_section::with(|cs| {
|
||||
let alarm = &ALARMS.borrow(cs)[n];
|
||||
let timestamp = alarm.timestamp.get();
|
||||
if timestamp <= now() {
|
||||
trigger_alarm(n, cs)
|
||||
} else {
|
||||
// Not elapsed, arm it again.
|
||||
// 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) };
|
||||
impl TimerDriver {
|
||||
fn check_alarm(&self, n: usize) {
|
||||
critical_section::with(|cs| {
|
||||
let alarm = &self.alarms.borrow(cs)[n];
|
||||
let timestamp = alarm.timestamp.get();
|
||||
if timestamp <= self.now() {
|
||||
self.trigger_alarm(n, cs)
|
||||
} else {
|
||||
// Not elapsed, arm it again.
|
||||
// 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() {
|
||||
// init alarms
|
||||
critical_section::with(|cs| {
|
||||
let alarms = ALARMS.borrow(cs);
|
||||
let alarms = DRIVER.alarms.borrow(cs);
|
||||
for a in alarms {
|
||||
a.timestamp.set(u64::MAX);
|
||||
}
|
||||
@ -144,20 +148,20 @@ pub unsafe fn init() {
|
||||
|
||||
#[interrupt]
|
||||
unsafe fn TIMER_IRQ_0() {
|
||||
check_alarm(0)
|
||||
DRIVER.check_alarm(0)
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
unsafe fn TIMER_IRQ_1() {
|
||||
check_alarm(1)
|
||||
DRIVER.check_alarm(1)
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
unsafe fn TIMER_IRQ_2() {
|
||||
check_alarm(2)
|
||||
DRIVER.check_alarm(2)
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
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")]
|
||||
#[interrupt]
|
||||
fn TIM2() {
|
||||
STATE.on_interrupt()
|
||||
DRIVER.on_interrupt()
|
||||
}
|
||||
#[cfg(feature = "time-driver-tim3")]
|
||||
#[interrupt]
|
||||
fn TIM3() {
|
||||
STATE.on_interrupt()
|
||||
DRIVER.on_interrupt()
|
||||
}
|
||||
|
||||
// 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.
|
||||
period: AtomicU32,
|
||||
alarm_count: AtomicU8,
|
||||
@ -85,13 +85,14 @@ struct State {
|
||||
}
|
||||
|
||||
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
||||
static STATE: State = State {
|
||||
|
||||
embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
period: AtomicU32::new(0),
|
||||
alarm_count: AtomicU8::new(0),
|
||||
alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
|
||||
};
|
||||
});
|
||||
|
||||
impl State {
|
||||
impl RtcDriver {
|
||||
fn init(&'static self) {
|
||||
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 {
|
||||
// safety: we're allowed to assume the AlarmState is created by us, and
|
||||
// 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()) };
|
||||
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
|
||||
.alarm_count
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||
@ -226,7 +229,7 @@ impl State {
|
||||
});
|
||||
|
||||
match id {
|
||||
Ok(id) => Some(unsafe { AlarmHandle::new(id) }),
|
||||
Ok(id) => Some(AlarmHandle::new(id)),
|
||||
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() {
|
||||
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:
|
||||
//!
|
||||
//! - 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
|
||||
//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
|
||||
//! would yield incorrect results.
|
||||
//!
|
||||
/// # 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!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use embassy::time::driver::{Driver, AlarmHandle};
|
||||
//!
|
||||
//! struct MyDriver{}; // not public!
|
||||
//! embassy::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
|
||||
//!
|
||||
//! impl Driver for MyDriver {
|
||||
//! fn now(&self) -> u64 {
|
||||
//! todo!()
|
||||
//! }
|
||||
//! unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||
//! todo!()
|
||||
//! }
|
||||
//! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
||||
//! todo!()
|
||||
//! }
|
||||
//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
|
||||
//! todo!()
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
/// Alarm handle, assigned by the driver.
|
||||
#[derive(Clone, Copy)]
|
||||
@ -76,22 +78,22 @@ impl AlarmHandle {
|
||||
}
|
||||
|
||||
/// Time driver
|
||||
pub trait Driver {
|
||||
pub trait Driver: Send + Sync + 'static {
|
||||
/// Return the current timestamp in ticks.
|
||||
/// This is guaranteed to be monotonic, i.e. a call to now() will always return
|
||||
/// 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.
|
||||
/// Initially the alarm has no callback set, and a null `ctx` pointer.
|
||||
///
|
||||
/// # Safety
|
||||
/// 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.
|
||||
/// 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
|
||||
/// 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.
|
||||
///
|
||||
/// 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" {
|
||||
@ -125,49 +127,34 @@ pub(crate) fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
||||
|
||||
/// Set the time Driver implementation.
|
||||
///
|
||||
/// # 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!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// See the module documentation for an example.
|
||||
#[macro_export]
|
||||
macro_rules! time_driver_impl {
|
||||
($t: ty) => {
|
||||
(static $name:ident: $t: ty = $val:expr) => {
|
||||
static $name: $t = $val;
|
||||
|
||||
#[no_mangle]
|
||||
fn _embassy_time_now() -> u64 {
|
||||
<$t as $crate::time::driver::Driver>::now()
|
||||
<$t as $crate::time::driver::Driver>::now(&$name)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe fn _embassy_time_allocate_alarm() -> Option<AlarmHandle> {
|
||||
<$t as $crate::time::driver::Driver>::allocate_alarm()
|
||||
unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::time::driver::AlarmHandle> {
|
||||
<$t as $crate::time::driver::Driver>::allocate_alarm(&$name)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn _embassy_time_set_alarm_callback(
|
||||
alarm: AlarmHandle,
|
||||
alarm: $crate::time::driver::AlarmHandle,
|
||||
callback: fn(*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]
|
||||
fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) {
|
||||
<$t as $crate::time::driver::Driver>::set_alarm(alarm, timestamp)
|
||||
fn _embassy_time_set_alarm(alarm: $crate::time::driver::AlarmHandle, timestamp: u64) {
|
||||
<$t as $crate::time::driver::Driver>::set_alarm(&$name, alarm, timestamp)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user