time: split queue driver too, don't reexport drivers.

This commit is contained in:
Dario Nieuwenhuis 2024-01-11 22:47:05 +01:00
parent b3ab2d91f7
commit f0606da9ad
17 changed files with 100 additions and 128 deletions

View file

@ -33,7 +33,8 @@ log = { version = "0.4.14", optional = true }
rtos-trace = { version = "0.1.2", optional = true } rtos-trace = { version = "0.1.2", optional = true }
embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" }
embassy-time = { version = "0.2", path = "../embassy-time", optional = true} embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true }
embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true }
critical-section = "1.1" critical-section = "1.1"
document-features = "0.2.7" document-features = "0.2.7"
@ -63,8 +64,8 @@ nightly = ["embassy-executor-macros/nightly"]
# See: https://github.com/embassy-rs/embassy/pull/1263 # See: https://github.com/embassy-rs/embassy/pull/1263
turbowakers = [] turbowakers = []
## Use timers from `embassy-time` ## Use the executor-integrated `embassy-time` timer queue.
integrated-timers = ["dep:embassy-time"] integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"]
#! ### Architecture #! ### Architecture
_arch = [] # some arch was picked _arch = [] # some arch was picked

View file

@ -30,9 +30,7 @@ use core::ptr::NonNull;
use core::task::{Context, Poll}; use core::task::{Context, Poll};
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
use embassy_time::driver::{self, AlarmHandle}; use embassy_time_driver::{self, AlarmHandle};
#[cfg(feature = "integrated-timers")]
use embassy_time::Instant;
#[cfg(feature = "rtos-trace")] #[cfg(feature = "rtos-trace")]
use rtos_trace::trace; use rtos_trace::trace;
@ -50,7 +48,7 @@ pub(crate) struct TaskHeader {
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
pub(crate) expires_at: SyncUnsafeCell<Instant>, pub(crate) expires_at: SyncUnsafeCell<u64>,
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
pub(crate) timer_queue_item: timer_queue::TimerQueueItem, pub(crate) timer_queue_item: timer_queue::TimerQueueItem,
} }
@ -123,7 +121,7 @@ impl<F: Future + 'static> TaskStorage<F> {
poll_fn: SyncUnsafeCell::new(None), poll_fn: SyncUnsafeCell::new(None),
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
expires_at: SyncUnsafeCell::new(Instant::from_ticks(0)), expires_at: SyncUnsafeCell::new(0),
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
timer_queue_item: timer_queue::TimerQueueItem::new(), timer_queue_item: timer_queue::TimerQueueItem::new(),
}, },
@ -164,7 +162,7 @@ impl<F: Future + 'static> TaskStorage<F> {
this.raw.state.despawn(); this.raw.state.despawn();
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
this.raw.expires_at.set(Instant::MAX); this.raw.expires_at.set(u64::MAX);
} }
Poll::Pending => {} Poll::Pending => {}
} }
@ -328,7 +326,7 @@ pub(crate) struct SyncExecutor {
impl SyncExecutor { impl SyncExecutor {
pub(crate) fn new(pender: Pender) -> Self { pub(crate) fn new(pender: Pender) -> Self {
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
let alarm = unsafe { unwrap!(driver::allocate_alarm()) }; let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) };
Self { Self {
run_queue: RunQueue::new(), run_queue: RunQueue::new(),
@ -377,18 +375,19 @@ impl SyncExecutor {
/// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
pub(crate) unsafe fn poll(&'static self) { pub(crate) unsafe fn poll(&'static self) {
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ());
#[allow(clippy::never_loop)] #[allow(clippy::never_loop)]
loop { loop {
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
self.timer_queue.dequeue_expired(Instant::now(), wake_task_no_pend); self.timer_queue
.dequeue_expired(embassy_time_driver::now(), wake_task_no_pend);
self.run_queue.dequeue_all(|p| { self.run_queue.dequeue_all(|p| {
let task = p.header(); let task = p.header();
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
task.expires_at.set(Instant::MAX); task.expires_at.set(u64::MAX);
if !task.state.run_dequeue() { if !task.state.run_dequeue() {
// If task is not running, ignore it. This can happen in the following scenario: // If task is not running, ignore it. This can happen in the following scenario:
@ -418,7 +417,7 @@ impl SyncExecutor {
// If this is already in the past, set_alarm might return false // If this is already in the past, set_alarm might return false
// In that case do another poll loop iteration. // In that case do another poll loop iteration.
let next_expiration = self.timer_queue.next_expiration(); let next_expiration = self.timer_queue.next_expiration();
if driver::set_alarm(self.alarm, next_expiration.as_ticks()) { if embassy_time_driver::set_alarm(self.alarm, next_expiration) {
break; break;
} }
} }
@ -568,8 +567,8 @@ pub fn wake_task_no_pend(task: TaskRef) {
struct TimerQueue; struct TimerQueue;
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
impl embassy_time::queue::TimerQueue for TimerQueue { impl embassy_time_queue_driver::TimerQueue for TimerQueue {
fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) {
let task = waker::task_from_waker(waker); let task = waker::task_from_waker(waker);
let task = task.header(); let task = task.header();
unsafe { unsafe {
@ -580,7 +579,7 @@ impl embassy_time::queue::TimerQueue for TimerQueue {
} }
#[cfg(feature = "integrated-timers")] #[cfg(feature = "integrated-timers")]
embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue);
#[cfg(feature = "rtos-trace")] #[cfg(feature = "rtos-trace")]
impl rtos_trace::RtosTraceOSCallbacks for Executor { impl rtos_trace::RtosTraceOSCallbacks for Executor {

View file

@ -1,7 +1,5 @@
use core::cmp::min; use core::cmp::min;
use embassy_time::Instant;
use super::TaskRef; use super::TaskRef;
use crate::raw::util::SyncUnsafeCell; use crate::raw::util::SyncUnsafeCell;
@ -30,7 +28,7 @@ impl TimerQueue {
pub(crate) unsafe fn update(&self, p: TaskRef) { pub(crate) unsafe fn update(&self, p: TaskRef) {
let task = p.header(); let task = p.header();
if task.expires_at.get() != Instant::MAX { if task.expires_at.get() != u64::MAX {
if task.state.timer_enqueue() { if task.state.timer_enqueue() {
task.timer_queue_item.next.set(self.head.get()); task.timer_queue_item.next.set(self.head.get());
self.head.set(Some(p)); self.head.set(Some(p));
@ -38,18 +36,18 @@ impl TimerQueue {
} }
} }
pub(crate) unsafe fn next_expiration(&self) -> Instant { pub(crate) unsafe fn next_expiration(&self) -> u64 {
let mut res = Instant::MAX; let mut res = u64::MAX;
self.retain(|p| { self.retain(|p| {
let task = p.header(); let task = p.header();
let expires = task.expires_at.get(); let expires = task.expires_at.get();
res = min(res, expires); res = min(res, expires);
expires != Instant::MAX expires != u64::MAX
}); });
res res
} }
pub(crate) unsafe fn dequeue_expired(&self, now: Instant, on_task: impl Fn(TaskRef)) { pub(crate) unsafe fn dequeue_expired(&self, now: u64, on_task: impl Fn(TaskRef)) {
self.retain(|p| { self.retain(|p| {
let task = p.header(); let task = p.header();
if task.expires_at.get() <= now { if task.expires_at.get() <= now {

View file

@ -1,51 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.2.0 - 2023-12-04
- Added tick rates in multiples of 10 kHz
- Remove nightly and unstable-traits features in preparation for 1.75.
- Update heapless to 0.8.
## 0.1.5 - 2023-10-16
- Added `links` key to Cargo.toml, to prevent multiple copies of this crate in the same binary.
Needed because different copies might get different tick rates, causing
wrong delays if the time driver is using one copy and user code is using another.
This is especially common when mixing crates from crates.io and git.
## 0.1.4 - 2023-10-12
- Added more tick rates
## 0.1.3 - 2023-08-28
- Update `embedded-hal-async` to `1.0.0-rc.2`
- Update `embedded-hal v1` to `1.0.0-rc.2`
## 0.1.2 - 2023-07-05
- Update `embedded-hal-async` to `0.2.0-alpha.2`.
- Update `embedded-hal v1` to `1.0.0-alpha.11`. (Note: v0.2 support is kept unchanged).
## 0.1.1 - 2023-04-13
- Update `embedded-hal-async` to `0.2.0-alpha.1` (uses `async fn` in traits).
- Update `embedded-hal v1` to `1.0.0-alpha.10`. (Note: v0.2 support is kept unchanged).
- Remove dep on `embassy-sync`.
- Fix reentrancy issues in the `std` time driver (#1177)
- Add `Duration::from_hz()`.
- impl `From` conversions to/from `core::time::Duration`.
- Add `#[must_use]` to all futures.
- Add inherent `async fn tick()` to `Ticker`, so you can use it directly without the `Stream` trait.
- Add more tick rates.
- impl `Default` for `Signal`
- Remove unnecessary uses of `atomic-polyfill`
## 0.1.0 - 2022-08-26
- First release

View file

@ -0,0 +1,25 @@
[package]
name = "embassy-time-queue-driver"
version = "0.1.0"
edition = "2021"
description = "Timer queue driver trait for embassy-time"
repository = "https://github.com/embassy-rs/embassy"
readme = "README.md"
license = "MIT OR Apache-2.0"
categories = [
"embedded",
"no-std",
"concurrency",
"asynchronous",
]
# Prevent multiple copies of this crate in the same binary.
# Needed because different copies might get different tick rates, causing
# wrong delays if the time driver is using one copy and user code is using another.
# This is especially common when mixing crates from crates.io and git.
links = "embassy-time-queue"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/"
target = "x86_64-unknown-linux-gnu"

View file

@ -0,0 +1,8 @@
# embassy-time-queue-driver
This crate contains the driver trait used by the [`embassy-time`](https://crates.io/crates/embassy-time) timer queue.
You should rarely need to use this crate directly. Only use it when implementing your own timer queue.
There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and
another in `embassy-executor` enabled by the `integrated-timers` feature.

View file

@ -0,0 +1 @@
fn main() {}

View file

@ -1,20 +1,14 @@
//! Timer queue implementation #![no_std]
//! #![doc = include_str!("../README.md")]
//! This module defines the interface a timer queue needs to implement to power the `embassy_time` module. #![warn(missing_docs)]
//!
//! # Implementing a timer queue //! ## Implementing a timer queue
//! //!
//! - Define a struct `MyTimerQueue` //! - Define a struct `MyTimerQueue`
//! - Implement [`TimerQueue`] for it //! - Implement [`TimerQueue`] for it
//! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl). //! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl).
//! //!
//! # Linkage details //! ## Example
//!
//! Check the documentation of the [`driver`](crate::driver) module for more information.
//!
//! Similarly to driver, if there is none or multiple timer queues in the crate tree, linking will fail.
//!
//! # Example
//! //!
//! ``` //! ```
//! use core::task::Waker; //! use core::task::Waker;
@ -25,23 +19,29 @@
//! struct MyTimerQueue{}; // not public! //! struct MyTimerQueue{}; // not public!
//! //!
//! impl TimerQueue for MyTimerQueue { //! impl TimerQueue for MyTimerQueue {
//! fn schedule_wake(&'static self, at: Instant, waker: &Waker) { //! fn schedule_wake(&'static self, at: u64, waker: &Waker) {
//! todo!() //! todo!()
//! } //! }
//! } //! }
//! ``` //!
//! ```ignore //! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
//! embassy_time::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
//! ``` //! ```
use core::task::Waker; use core::task::Waker;
use crate::Instant;
/// Timer queue /// Timer queue
pub trait TimerQueue { pub trait TimerQueue {
/// Schedules a waker in the queue to be awoken at moment `at`. /// Schedules a waker in the queue to be awoken at moment `at`.
/// If this moment is in the past, the waker might be awoken immediately. /// If this moment is in the past, the waker might be awoken immediately.
fn schedule_wake(&'static self, at: Instant, waker: &Waker); fn schedule_wake(&'static self, at: u64, waker: &Waker);
}
extern "Rust" {
fn _embassy_time_schedule_wake(at: u64, waker: &Waker);
}
/// Schedule the given waker to be woken at `at`.
pub fn schedule_wake(at: u64, waker: &Waker) {
unsafe { _embassy_time_schedule_wake(at, waker) }
} }
/// Set the TimerQueue implementation. /// Set the TimerQueue implementation.
@ -53,8 +53,8 @@ macro_rules! timer_queue_impl {
static $name: $t = $val; static $name: $t = $val;
#[no_mangle] #[no_mangle]
fn _embassy_time_schedule_wake(at: $crate::Instant, waker: &core::task::Waker) { fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) {
<$t as $crate::queue::TimerQueue>::schedule_wake(&$name, at, waker); <$t as $crate::TimerQueue>::schedule_wake(&$name, at, waker);
} }
}; };
} }

View file

@ -398,6 +398,7 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"]
[dependencies] [dependencies]
embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" }
embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver" }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }

View file

@ -1,8 +1,8 @@
use core::cell::RefCell; use core::cell::RefCell;
use critical_section::Mutex as CsMutex; use critical_section::Mutex as CsMutex;
use embassy_time_driver::{AlarmHandle, Driver};
use crate::driver::{AlarmHandle, Driver};
use crate::{Duration, Instant}; use crate::{Duration, Instant};
/// A mock driver that can be manually advanced. /// A mock driver that can be manually advanced.
@ -28,7 +28,7 @@ use crate::{Duration, Instant};
/// ``` /// ```
pub struct MockDriver(CsMutex<RefCell<InnerMockDriver>>); pub struct MockDriver(CsMutex<RefCell<InnerMockDriver>>);
crate::driver::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new()); embassy_time_driver::time_driver_impl!(static DRIVER: MockDriver = MockDriver::new());
impl MockDriver { impl MockDriver {
/// Creates a new mock driver. /// Creates a new mock driver.

View file

@ -6,8 +6,7 @@ use std::time::{Duration as StdDuration, Instant as StdInstant};
use std::{mem, ptr, thread}; use std::{mem, ptr, thread};
use critical_section::Mutex as CsMutex; use critical_section::Mutex as CsMutex;
use embassy_time_driver::{AlarmHandle, Driver};
use crate::driver::{AlarmHandle, Driver};
const ALARM_COUNT: usize = 4; const ALARM_COUNT: usize = 4;
@ -45,7 +44,7 @@ struct TimeDriver {
} }
const ALARM_NEW: AlarmState = AlarmState::new(); const ALARM_NEW: AlarmState = AlarmState::new();
crate::driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
alarm_count: AtomicU8::new(0), alarm_count: AtomicU8::new(0),
once: Once::new(), once: Once::new(),

View file

@ -4,11 +4,10 @@ use std::mem::MaybeUninit;
use std::ptr; use std::ptr;
use std::sync::{Mutex, Once}; use std::sync::{Mutex, Once};
use embassy_time_driver::{AlarmHandle, Driver};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_timer::Instant as StdInstant; use wasm_timer::Instant as StdInstant;
use crate::driver::{AlarmHandle, Driver};
const ALARM_COUNT: usize = 4; const ALARM_COUNT: usize = 4;
struct AlarmState { struct AlarmState {
@ -42,7 +41,7 @@ struct TimeDriver {
} }
const ALARM_NEW: AlarmState = AlarmState::new(); const ALARM_NEW: AlarmState = AlarmState::new();
crate::driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
alarm_count: AtomicU8::new(0), alarm_count: AtomicU8::new(0),
once: Once::new(), once: Once::new(),
alarms: UninitCell::uninit(), alarms: UninitCell::uninit(),

View file

@ -1,7 +1,7 @@
use core::fmt; use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::ops::{Add, AddAssign, Sub, SubAssign};
use super::{driver, Duration, GCD_1K, GCD_1M, TICK_HZ}; use super::{Duration, GCD_1K, GCD_1M, TICK_HZ};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -18,7 +18,9 @@ impl Instant {
/// Returns an Instant representing the current time. /// Returns an Instant representing the current time.
pub fn now() -> Instant { pub fn now() -> Instant {
Instant { ticks: driver::now() } Instant {
ticks: embassy_time_driver::now(),
}
} }
/// Create an Instant from a tick count since system boot. /// Create an Instant from a tick count since system boot.

View file

@ -10,12 +10,9 @@
// This mod MUST go first, so that the others see its macros. // This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt; pub(crate) mod fmt;
pub use embassy_time_driver as driver;
mod delay; mod delay;
mod duration; mod duration;
mod instant; mod instant;
pub mod queue;
mod timer; mod timer;
#[cfg(feature = "mock-driver")] #[cfg(feature = "mock-driver")]
@ -32,8 +29,8 @@ mod driver_wasm;
mod queue_generic; mod queue_generic;
pub use delay::{block_for, Delay}; pub use delay::{block_for, Delay};
pub use driver::TICK_HZ;
pub use duration::Duration; pub use duration::Duration;
pub use embassy_time_driver::TICK_HZ;
pub use instant::Instant; pub use instant::Instant;
pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; pub use timer::{with_timeout, Ticker, TimeoutError, Timer};

View file

@ -3,10 +3,10 @@ use core::cmp::{min, Ordering};
use core::task::Waker; use core::task::Waker;
use critical_section::Mutex; use critical_section::Mutex;
use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle};
use embassy_time_queue_driver::TimerQueue;
use heapless::Vec; use heapless::Vec;
use crate::driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle};
use crate::queue::TimerQueue;
use crate::Instant; use crate::Instant;
#[cfg(feature = "generic-queue-8")] #[cfg(feature = "generic-queue-8")]
@ -167,12 +167,12 @@ impl Queue {
} }
impl TimerQueue for Queue { impl TimerQueue for Queue {
fn schedule_wake(&'static self, at: Instant, waker: &Waker) { fn schedule_wake(&'static self, at: u64, waker: &Waker) {
Queue::schedule_wake(self, at, waker); Queue::schedule_wake(self, Instant::from_ticks(at), waker);
} }
} }
crate::timer_queue_impl!(static QUEUE: Queue = Queue::new()); embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new());
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "mock-driver")] #[cfg(feature = "mock-driver")]

View file

@ -1,6 +1,6 @@
use core::future::{poll_fn, Future}; use core::future::{poll_fn, Future};
use core::pin::Pin; use core::pin::Pin;
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll};
use futures_util::future::{select, Either}; use futures_util::future::{select, Either};
use futures_util::stream::FusedStream; use futures_util::stream::FusedStream;
@ -116,7 +116,7 @@ impl Future for Timer {
if self.yielded_once && self.expires_at <= Instant::now() { if self.yielded_once && self.expires_at <= Instant::now() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
schedule_wake(self.expires_at, cx.waker()); embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker());
self.yielded_once = true; self.yielded_once = true;
Poll::Pending Poll::Pending
} }
@ -185,7 +185,7 @@ impl Ticker {
self.expires_at += dur; self.expires_at += dur;
Poll::Ready(()) Poll::Ready(())
} else { } else {
schedule_wake(self.expires_at, cx.waker()); embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker());
Poll::Pending Poll::Pending
} }
}) })
@ -202,7 +202,7 @@ impl Stream for Ticker {
self.expires_at += dur; self.expires_at += dur;
Poll::Ready(Some(())) Poll::Ready(Some(()))
} else { } else {
schedule_wake(self.expires_at, cx.waker()); embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker());
Poll::Pending Poll::Pending
} }
} }
@ -214,11 +214,3 @@ impl FusedStream for Ticker {
false false
} }
} }
extern "Rust" {
fn _embassy_time_schedule_wake(at: Instant, waker: &Waker);
}
fn schedule_wake(at: Instant, waker: &Waker) {
unsafe { _embassy_time_schedule_wake(at, waker) }
}

View file

@ -3,6 +3,7 @@ mod serial_port;
use async_io::Async; use async_io::Async;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time as _;
use embedded_io_async::Read; use embedded_io_async::Read;
use log::*; use log::*;
use nix::sys::termios; use nix::sys::termios;