diff options
| -rw-r--r-- | Cargo.toml | 5 | ||||
| -rw-r--r-- | README.md | 16 | ||||
| -rw-r--r-- | embassy-macros/src/lib.rs | 11 | ||||
| -rw-r--r-- | embassy-nrf-examples/.cargo/config (renamed from examples/.cargo/config) | 6 | ||||
| -rw-r--r-- | embassy-nrf-examples/Cargo.toml (renamed from examples/Cargo.toml) | 2 | ||||
| -rw-r--r-- | embassy-nrf-examples/build.rs (renamed from examples/build.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/memory.x (renamed from examples/memory.x) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/buffered_uart.rs (renamed from examples/src/bin/buffered_uart.rs) | 11 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/executor_fairness_test.rs (renamed from examples/src/bin/executor_fairness_test.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/gpiote.rs (renamed from examples/src/bin/gpiote.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/gpiote_port.rs (renamed from examples/src/bin/gpiote_port.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/multiprio.rs (renamed from examples/src/bin/multiprio.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/qspi.rs (renamed from examples/src/bin/qspi.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/rtc_async.rs (renamed from examples/src/bin/rtc_async.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/rtc_raw.rs (renamed from examples/src/bin/rtc_raw.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/uart.rs (renamed from examples/src/bin/uart.rs) | 37 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/example_common.rs (renamed from examples/src/example_common.rs) | 0 | ||||
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 326 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 144 | ||||
| -rw-r--r-- | embassy-nrf/src/util/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-nrf/src/util/peripheral.rs | 107 | ||||
| -rw-r--r-- | embassy-nrf/src/util/ring_buffer.rs | 80 | ||||
| -rw-r--r-- | embassy/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy/src/uart.rs | 15 | ||||
| -rw-r--r-- | embassy/src/util/mod.rs | 4 | ||||
| -rw-r--r-- | embassy/src/util/waker.rs | 38 | ||||
| -rw-r--r-- | embassy/src/util/waker_store.rs | 23 | ||||
| -rwxr-xr-x | test-build.sh | 6 |
29 files changed, 474 insertions, 362 deletions
diff --git a/Cargo.toml b/Cargo.toml index be98b26f6..843c5f6c3 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
| @@ -5,8 +5,9 @@ members = [ | |||
| 5 | "embassy-nrf", | 5 | "embassy-nrf", |
| 6 | "embassy-stm32f4", | 6 | "embassy-stm32f4", |
| 7 | "embassy-macros", | 7 | "embassy-macros", |
| 8 | "examples", | 8 | "embassy-nrf-examples", |
| 9 | "examples-stm32f4", | 9 | "embassy-stm32f4-examples", |
| 10 | "embassy-macros", | ||
| 10 | ] | 11 | ] |
| 11 | 12 | ||
| 12 | exclude = [ | 13 | exclude = [ |
| @@ -11,15 +11,17 @@ Embassy is a project to make async/await a first-class option for embedded devel | |||
| 11 | - `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. | 11 | - `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. |
| 12 | - More traits for SPI, I2C, UART async HAL coming soon. | 12 | - More traits for SPI, I2C, UART async HAL coming soon. |
| 13 | 13 | ||
| 14 | ## Executor with timers | 14 | ## Executor |
| 15 | 15 | ||
| 16 | The `embassy::executor` module provides an async/await executor based on [static-executor](https://github.com/Dirbaio/static-executor). | 16 | The `embassy::executor` module provides an async/await executor designed for embedded usage. |
| 17 | 17 | ||
| 18 | - No `alloc`, no heap needed. Task futures are statically allocated. | 18 | - No `alloc`, no heap needed. Task futures are statically allocated. |
| 19 | - Integrated timer queue allows simple sleeping: `Timer::after(Duration::from_ticks(64000)).await;`. | 19 | - No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. |
| 20 | - Suitable for low-power operation. Using interrupts or `WFE/SEV` ensures the CPU sleeps when there's no work to do. No busy-loop polling. | 20 | - Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`. |
| 21 | - No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. | ||
| 22 | - Efficient polling: a wake will only poll the woken task, not all of them. | ||
| 23 | - Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. | ||
| 21 | - Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. | 24 | - Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. |
| 22 | - Compatible with RTIC (example coming soon). | ||
| 23 | 25 | ||
| 24 | ## Utils | 26 | ## Utils |
| 25 | 27 | ||
| @@ -54,9 +56,7 @@ cargo run --bin rtc_async | |||
| 54 | 56 | ||
| 55 | ## Minimum supported Rust version (MSRV) | 57 | ## Minimum supported Rust version (MSRV) |
| 56 | 58 | ||
| 57 | `rustc 1.48.0-nightly (1fd5b9d51 2020-09-20)` | 59 | Only recent nighly supported. Nightly is required for: |
| 58 | |||
| 59 | Any recent nightly should work. Nightly is required for: | ||
| 60 | 60 | ||
| 61 | - `generic_associated_types`: for trait funcs returning futures. | 61 | - `generic_associated_types`: for trait funcs returning futures. |
| 62 | - `type_alias_impl_trait`: for trait funcs returning futures implemented with `async{}` blocks, and for `static-executor`. | 62 | - `type_alias_impl_trait`: for trait funcs returning futures implemented with `async{}` blocks, and for `static-executor`. |
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index c2e2d9e27..c46f114a0 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs | |||
| @@ -55,9 +55,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 55 | 55 | ||
| 56 | let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> = | 56 | let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> = |
| 57 | syn::punctuated::Punctuated::new(); | 57 | syn::punctuated::Punctuated::new(); |
| 58 | let args = &task_fn.sig.inputs; | 58 | let mut args = task_fn.sig.inputs.clone(); |
| 59 | 59 | ||
| 60 | for arg in args.iter() { | 60 | for arg in args.iter_mut() { |
| 61 | match arg { | 61 | match arg { |
| 62 | syn::FnArg::Receiver(_) => { | 62 | syn::FnArg::Receiver(_) => { |
| 63 | arg.span() | 63 | arg.span() |
| @@ -66,8 +66,11 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 66 | .emit(); | 66 | .emit(); |
| 67 | fail = true; | 67 | fail = true; |
| 68 | } | 68 | } |
| 69 | syn::FnArg::Typed(t) => match t.pat.as_ref() { | 69 | syn::FnArg::Typed(t) => match t.pat.as_mut() { |
| 70 | syn::Pat::Ident(i) => arg_names.push(i.ident.clone()), | 70 | syn::Pat::Ident(i) => { |
| 71 | arg_names.push(i.ident.clone()); | ||
| 72 | i.mutability = None; | ||
| 73 | } | ||
| 71 | _ => { | 74 | _ => { |
| 72 | arg.span() | 75 | arg.span() |
| 73 | .unwrap() | 76 | .unwrap() |
diff --git a/examples/.cargo/config b/embassy-nrf-examples/.cargo/config index 3f319ae55..591288879 100644 --- a/examples/.cargo/config +++ b/embassy-nrf-examples/.cargo/config | |||
| @@ -20,8 +20,4 @@ rustflags = [ | |||
| 20 | ] | 20 | ] |
| 21 | 21 | ||
| 22 | [build] | 22 | [build] |
| 23 | # Pick ONE of these compilation targets | 23 | target = "thumbv7em-none-eabi" |
| 24 | # target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ | ||
| 25 | # target = "thumbv7m-none-eabi" # Cortex-M3 | ||
| 26 | # target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) | ||
| 27 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
diff --git a/examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml index c845c1bfb..0c812db1d 100644 --- a/examples/Cargo.toml +++ b/embassy-nrf-examples/Cargo.toml | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | authors = ["Dario Nieuwenhuis <[email protected]>"] | 2 | authors = ["Dario Nieuwenhuis <[email protected]>"] |
| 3 | edition = "2018" | 3 | edition = "2018" |
| 4 | name = "embassy-examples" | 4 | name = "embassy-nrf-examples" |
| 5 | version = "0.1.0" | 5 | version = "0.1.0" |
| 6 | 6 | ||
| 7 | [features] | 7 | [features] |
diff --git a/examples/build.rs b/embassy-nrf-examples/build.rs index d534cc3df..d534cc3df 100644 --- a/examples/build.rs +++ b/embassy-nrf-examples/build.rs | |||
diff --git a/examples/memory.x b/embassy-nrf-examples/memory.x index 9b04edec0..9b04edec0 100644 --- a/examples/memory.x +++ b/embassy-nrf-examples/memory.x | |||
diff --git a/examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs index 6e15fbcfa..68a76f71e 100644 --- a/examples/src/bin/buffered_uart.rs +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs | |||
| @@ -8,15 +8,17 @@ use example_common::*; | |||
| 8 | 8 | ||
| 9 | use cortex_m_rt::entry; | 9 | use cortex_m_rt::entry; |
| 10 | use defmt::panic; | 10 | use defmt::panic; |
| 11 | use futures::pin_mut; | ||
| 12 | use nrf52840_hal::gpio; | 11 | use nrf52840_hal::gpio; |
| 13 | 12 | ||
| 14 | use embassy::executor::{task, Executor}; | 13 | use embassy::executor::{task, Executor}; |
| 15 | use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; | 14 | use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; |
| 16 | use embassy::util::Forever; | 15 | use embassy::util::Forever; |
| 17 | use embassy_nrf::buffered_uarte; | 16 | use embassy_nrf::buffered_uarte; |
| 18 | use embassy_nrf::interrupt; | 17 | use embassy_nrf::interrupt; |
| 19 | 18 | ||
| 19 | static mut TX_BUFFER: [u8; 4096] = [0; 4096]; | ||
| 20 | static mut RX_BUFFER: [u8; 4096] = [0; 4096]; | ||
| 21 | |||
| 20 | #[task] | 22 | #[task] |
| 21 | async fn run() { | 23 | async fn run() { |
| 22 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); | 24 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); |
| @@ -34,14 +36,15 @@ async fn run() { | |||
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 36 | let irq = interrupt::take!(UARTE0_UART0); | 38 | let irq = interrupt::take!(UARTE0_UART0); |
| 37 | let u = buffered_uarte::BufferedUarte::new( | 39 | let mut u = buffered_uarte::BufferedUarte::new( |
| 38 | p.UARTE0, | 40 | p.UARTE0, |
| 39 | irq, | 41 | irq, |
| 42 | unsafe { &mut RX_BUFFER }, | ||
| 43 | unsafe { &mut TX_BUFFER }, | ||
| 40 | pins, | 44 | pins, |
| 41 | buffered_uarte::Parity::EXCLUDED, | 45 | buffered_uarte::Parity::EXCLUDED, |
| 42 | buffered_uarte::Baudrate::BAUD115200, | 46 | buffered_uarte::Baudrate::BAUD115200, |
| 43 | ); | 47 | ); |
| 44 | pin_mut!(u); | ||
| 45 | 48 | ||
| 46 | info!("uarte initialized!"); | 49 | info!("uarte initialized!"); |
| 47 | 50 | ||
diff --git a/examples/src/bin/executor_fairness_test.rs b/embassy-nrf-examples/src/bin/executor_fairness_test.rs index 9b2c1bd26..9b2c1bd26 100644 --- a/examples/src/bin/executor_fairness_test.rs +++ b/embassy-nrf-examples/src/bin/executor_fairness_test.rs | |||
diff --git a/examples/src/bin/gpiote.rs b/embassy-nrf-examples/src/bin/gpiote.rs index afa1b85d5..afa1b85d5 100644 --- a/examples/src/bin/gpiote.rs +++ b/embassy-nrf-examples/src/bin/gpiote.rs | |||
diff --git a/examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index f5aa81322..f5aa81322 100644 --- a/examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs | |||
diff --git a/examples/src/bin/multiprio.rs b/embassy-nrf-examples/src/bin/multiprio.rs index c821e3dba..c821e3dba 100644 --- a/examples/src/bin/multiprio.rs +++ b/embassy-nrf-examples/src/bin/multiprio.rs | |||
diff --git a/examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index a7d47f79c..a7d47f79c 100644 --- a/examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs | |||
diff --git a/examples/src/bin/rtc_async.rs b/embassy-nrf-examples/src/bin/rtc_async.rs index dcdeb7049..dcdeb7049 100644 --- a/examples/src/bin/rtc_async.rs +++ b/embassy-nrf-examples/src/bin/rtc_async.rs | |||
diff --git a/examples/src/bin/rtc_raw.rs b/embassy-nrf-examples/src/bin/rtc_raw.rs index 438585460..438585460 100644 --- a/examples/src/bin/rtc_raw.rs +++ b/embassy-nrf-examples/src/bin/rtc_raw.rs | |||
diff --git a/examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs index 107936686..cb38e8fcb 100644 --- a/examples/src/bin/uart.rs +++ b/embassy-nrf-examples/src/bin/uart.rs | |||
| @@ -10,6 +10,7 @@ use cortex_m_rt::entry; | |||
| 10 | use defmt::panic; | 10 | use defmt::panic; |
| 11 | use embassy::executor::{task, Executor}; | 11 | use embassy::executor::{task, Executor}; |
| 12 | use embassy::time::{Duration, Timer}; | 12 | use embassy::time::{Duration, Timer}; |
| 13 | use embassy::uart::Uart; | ||
| 13 | use embassy::util::Forever; | 14 | use embassy::util::Forever; |
| 14 | use embassy_nrf::{interrupt, pac, rtc, uarte}; | 15 | use embassy_nrf::{interrupt, pac, rtc, uarte}; |
| 15 | use futures::future::{select, Either}; | 16 | use futures::future::{select, Either}; |
| @@ -24,29 +25,37 @@ async fn run(mut uart: uarte::Uarte<pac::UARTE0>) { | |||
| 24 | let mut buf = [0; 8]; | 25 | let mut buf = [0; 8]; |
| 25 | buf.copy_from_slice(b"Hello!\r\n"); | 26 | buf.copy_from_slice(b"Hello!\r\n"); |
| 26 | 27 | ||
| 27 | uart.send(&buf).await; | 28 | unwrap!(uart.send(&buf).await); |
| 28 | info!("wrote hello in uart!"); | 29 | info!("wrote hello in uart!"); |
| 29 | 30 | ||
| 30 | info!("reading..."); | ||
| 31 | loop { | 31 | loop { |
| 32 | let received = match select( | 32 | let buf_len = buf.len(); |
| 33 | uart.receive(&mut buf), | 33 | info!("reading..."); |
| 34 | Timer::after(Duration::from_millis(10)), | 34 | |
| 35 | ) | 35 | // `receive()` doesn't return until the buffer has been completely filled with |
| 36 | .await | 36 | // incoming data, which in this case is 8 bytes. |
| 37 | { | 37 | // |
| 38 | Either::Left((buf, _)) => buf, | 38 | // This example shows how to use `select` to run an uart receive concurrently with a |
| 39 | Either::Right((_, read)) => { | 39 | // 1 second timer, effectively adding a timeout to the receive operation. |
| 40 | let (buf, n) = read.stop().await; | 40 | let recv_fut = uart.receive(&mut buf); |
| 41 | &buf[..n] | 41 | let timer_fut = Timer::after(Duration::from_millis(1000)); |
| 42 | } | 42 | let received_len = match select(recv_fut, timer_fut).await { |
| 43 | // recv_fut completed first, so we've received `buf_len` bytes. | ||
| 44 | Either::Left(_) => buf_len, | ||
| 45 | // timer_fut completed first. `select` gives us back the future that didn't complete, which | ||
| 46 | // is `recv_fut` in this case, so we can do further stuff with it. | ||
| 47 | // | ||
| 48 | // The recv_fut would stop the uart read automatically when dropped. However, we want to know how | ||
| 49 | // many bytes have been received, so we have to "gracefully stop" it with `.stop()`. | ||
| 50 | Either::Right((_, recv_fut)) => recv_fut.stop().await, | ||
| 43 | }; | 51 | }; |
| 52 | let received = &mut buf[..received_len]; | ||
| 44 | 53 | ||
| 45 | if received.len() > 0 { | 54 | if received.len() > 0 { |
| 46 | info!("read done, got {:[u8]}", received); | 55 | info!("read done, got {:[u8]}", received); |
| 47 | 56 | ||
| 48 | // Echo back received data | 57 | // Echo back received data |
| 49 | uart.send(received).await; | 58 | unwrap!(uart.send(received).await); |
| 50 | } | 59 | } |
| 51 | } | 60 | } |
| 52 | } | 61 | } |
diff --git a/examples/src/example_common.rs b/embassy-nrf-examples/src/example_common.rs index 60bb02082..60bb02082 100644 --- a/examples/src/example_common.rs +++ b/embassy-nrf-examples/src/example_common.rs | |||
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index db6a83fb4..c67b6f166 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -4,114 +4,29 @@ | |||
| 4 | //! | 4 | //! |
| 5 | //! - nrf52832: Section 35 | 5 | //! - nrf52832: Section 35 |
| 6 | //! - nrf52840: Section 6.34 | 6 | //! - nrf52840: Section 6.34 |
| 7 | use core::cell::UnsafeCell; | ||
| 8 | use core::cmp::min; | 7 | use core::cmp::min; |
| 9 | use core::marker::PhantomPinned; | 8 | use core::marker::PhantomData; |
| 9 | use core::mem; | ||
| 10 | use core::ops::Deref; | 10 | use core::ops::Deref; |
| 11 | use core::pin::Pin; | 11 | use core::pin::Pin; |
| 12 | use core::ptr; | ||
| 13 | use core::sync::atomic::{compiler_fence, Ordering}; | 12 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 14 | use core::task::{Context, Poll}; | 13 | use core::task::{Context, Poll}; |
| 15 | 14 | use embassy::io::{AsyncBufRead, AsyncWrite, Result}; | |
| 15 | use embassy::util::WakerRegistration; | ||
| 16 | use embedded_hal::digital::v2::OutputPin; | 16 | use embedded_hal::digital::v2::OutputPin; |
| 17 | 17 | ||
| 18 | use crate::hal::gpio::{Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull}; | 18 | use crate::fmt::{panic, todo, *}; |
| 19 | use crate::interrupt; | 19 | use crate::hal::gpio::Port as GpioPort; |
| 20 | use crate::interrupt::{CriticalSection, OwnedInterrupt}; | 20 | use crate::interrupt::{self, OwnedInterrupt}; |
| 21 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | 21 | use crate::pac; |
| 22 | use crate::pac::UARTE1; | 22 | use crate::pac::uarte0; |
| 23 | use crate::pac::{uarte0, UARTE0}; | 23 | use crate::util::peripheral; |
| 24 | use crate::util::ring_buffer::RingBuffer; | ||
| 24 | 25 | ||
| 25 | // Re-export SVD variants to allow user to directly set values | 26 | // Re-export SVD variants to allow user to directly set values |
| 27 | pub use crate::hal::uarte::Pins; | ||
| 26 | pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 28 | pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 27 | 29 | ||
| 28 | use embassy::io::{AsyncBufRead, AsyncWrite, Result}; | ||
| 29 | use embassy::util::WakerStore; | ||
| 30 | |||
| 31 | use crate::fmt::{assert, panic, todo, *}; | ||
| 32 | |||
| 33 | //use crate::trace; | ||
| 34 | |||
| 35 | const RINGBUF_SIZE: usize = 512; | ||
| 36 | struct RingBuf { | ||
| 37 | buf: [u8; RINGBUF_SIZE], | ||
| 38 | start: usize, | ||
| 39 | end: usize, | ||
| 40 | empty: bool, | ||
| 41 | } | ||
| 42 | |||
| 43 | impl RingBuf { | ||
| 44 | fn new() -> Self { | ||
| 45 | RingBuf { | ||
| 46 | buf: [0; RINGBUF_SIZE], | ||
| 47 | start: 0, | ||
| 48 | end: 0, | ||
| 49 | empty: true, | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | fn push_buf(&mut self) -> &mut [u8] { | ||
| 54 | if self.start == self.end && !self.empty { | ||
| 55 | trace!(" ringbuf: push_buf empty"); | ||
| 56 | return &mut self.buf[..0]; | ||
| 57 | } | ||
| 58 | |||
| 59 | let n = if self.start <= self.end { | ||
| 60 | RINGBUF_SIZE - self.end | ||
| 61 | } else { | ||
| 62 | self.start - self.end | ||
| 63 | }; | ||
| 64 | |||
| 65 | trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); | ||
| 66 | &mut self.buf[self.end..self.end + n] | ||
| 67 | } | ||
| 68 | |||
| 69 | fn push(&mut self, n: usize) { | ||
| 70 | trace!(" ringbuf: push {:?}", n); | ||
| 71 | if n == 0 { | ||
| 72 | return; | ||
| 73 | } | ||
| 74 | |||
| 75 | self.end = Self::wrap(self.end + n); | ||
| 76 | self.empty = false; | ||
| 77 | } | ||
| 78 | |||
| 79 | fn pop_buf(&mut self) -> &mut [u8] { | ||
| 80 | if self.empty { | ||
| 81 | trace!(" ringbuf: pop_buf empty"); | ||
| 82 | return &mut self.buf[..0]; | ||
| 83 | } | ||
| 84 | |||
| 85 | let n = if self.end <= self.start { | ||
| 86 | RINGBUF_SIZE - self.start | ||
| 87 | } else { | ||
| 88 | self.end - self.start | ||
| 89 | }; | ||
| 90 | |||
| 91 | trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); | ||
| 92 | &mut self.buf[self.start..self.start + n] | ||
| 93 | } | ||
| 94 | |||
| 95 | fn pop(&mut self, n: usize) { | ||
| 96 | trace!(" ringbuf: pop {:?}", n); | ||
| 97 | if n == 0 { | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | |||
| 101 | self.start = Self::wrap(self.start + n); | ||
| 102 | self.empty = self.start == self.end; | ||
| 103 | } | ||
| 104 | |||
| 105 | fn wrap(n: usize) -> usize { | ||
| 106 | assert!(n <= RINGBUF_SIZE); | ||
| 107 | if n == RINGBUF_SIZE { | ||
| 108 | 0 | ||
| 109 | } else { | ||
| 110 | n | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | #[derive(Copy, Clone, Debug, PartialEq)] | 30 | #[derive(Copy, Clone, Debug, PartialEq)] |
| 116 | enum RxState { | 31 | enum RxState { |
| 117 | Idle, | 32 | Idle, |
| @@ -133,28 +48,12 @@ enum TxState { | |||
| 133 | /// are disabled before using `Uarte`. See product specification: | 48 | /// are disabled before using `Uarte`. See product specification: |
| 134 | /// - nrf52832: Section 15.2 | 49 | /// - nrf52832: Section 15.2 |
| 135 | /// - nrf52840: Section 6.1.2 | 50 | /// - nrf52840: Section 6.1.2 |
| 136 | pub struct BufferedUarte<T: Instance> { | 51 | pub struct BufferedUarte<'a, T: Instance> { |
| 137 | started: bool, | 52 | reg: peripheral::Registration<State<'a, T>>, |
| 138 | state: UnsafeCell<UarteState<T>>, | 53 | wtf: PhantomData<&'a ()>, |
| 139 | } | 54 | } |
| 140 | 55 | ||
| 141 | // public because it needs to be used in Instance::{get_state, set_state}, but | 56 | impl<'a, T: Instance> Unpin for BufferedUarte<'a, T> {} |
| 142 | // should not be used outside the module | ||
| 143 | #[doc(hidden)] | ||
| 144 | pub struct UarteState<T: Instance> { | ||
| 145 | inner: T, | ||
| 146 | irq: T::Interrupt, | ||
| 147 | |||
| 148 | rx: RingBuf, | ||
| 149 | rx_state: RxState, | ||
| 150 | rx_waker: WakerStore, | ||
| 151 | |||
| 152 | tx: RingBuf, | ||
| 153 | tx_state: TxState, | ||
| 154 | tx_waker: WakerStore, | ||
| 155 | |||
| 156 | _pin: PhantomPinned, | ||
| 157 | } | ||
| 158 | 57 | ||
| 159 | #[cfg(any(feature = "52833", feature = "52840"))] | 58 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 160 | fn port_bit(port: GpioPort) -> bool { | 59 | fn port_bit(port: GpioPort) -> bool { |
| @@ -164,10 +63,12 @@ fn port_bit(port: GpioPort) -> bool { | |||
| 164 | } | 63 | } |
| 165 | } | 64 | } |
| 166 | 65 | ||
| 167 | impl<T: Instance> BufferedUarte<T> { | 66 | impl<'a, T: Instance> BufferedUarte<'a, T> { |
| 168 | pub fn new( | 67 | pub fn new( |
| 169 | uarte: T, | 68 | uarte: T, |
| 170 | irq: T::Interrupt, | 69 | irq: T::Interrupt, |
| 70 | rx_buffer: &'a mut [u8], | ||
| 71 | tx_buffer: &'a mut [u8], | ||
| 171 | mut pins: Pins, | 72 | mut pins: Pins, |
| 172 | parity: Parity, | 73 | parity: Parity, |
| 173 | baudrate: Baudrate, | 74 | baudrate: Baudrate, |
| @@ -225,87 +126,79 @@ impl<T: Instance> BufferedUarte<T> { | |||
| 225 | // Configure frequency | 126 | // Configure frequency |
| 226 | uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); | 127 | uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); |
| 227 | 128 | ||
| 129 | irq.pend(); | ||
| 130 | |||
| 228 | BufferedUarte { | 131 | BufferedUarte { |
| 229 | started: false, | 132 | reg: peripheral::Registration::new( |
| 230 | state: UnsafeCell::new(UarteState { | ||
| 231 | inner: uarte, | ||
| 232 | irq, | 133 | irq, |
| 233 | 134 | State { | |
| 234 | rx: RingBuf::new(), | 135 | inner: uarte, |
| 235 | rx_state: RxState::Idle, | 136 | |
| 236 | rx_waker: WakerStore::new(), | 137 | rx: RingBuffer::new(rx_buffer), |
| 237 | 138 | rx_state: RxState::Idle, | |
| 238 | tx: RingBuf::new(), | 139 | rx_waker: WakerRegistration::new(), |
| 239 | tx_state: TxState::Idle, | 140 | |
| 240 | tx_waker: WakerStore::new(), | 141 | tx: RingBuffer::new(tx_buffer), |
| 241 | 142 | tx_state: TxState::Idle, | |
| 242 | _pin: PhantomPinned, | 143 | tx_waker: WakerRegistration::new(), |
| 243 | }), | 144 | }, |
| 145 | ), | ||
| 146 | wtf: PhantomData, | ||
| 244 | } | 147 | } |
| 245 | } | 148 | } |
| 246 | |||
| 247 | fn with_state<'a, R>( | ||
| 248 | self: Pin<&'a mut Self>, | ||
| 249 | f: impl FnOnce(Pin<&'a mut UarteState<T>>) -> R, | ||
| 250 | ) -> R { | ||
| 251 | let Self { state, started } = unsafe { self.get_unchecked_mut() }; | ||
| 252 | |||
| 253 | interrupt::free(|cs| { | ||
| 254 | let ptr = state.get(); | ||
| 255 | |||
| 256 | if !*started { | ||
| 257 | T::set_state(cs, ptr); | ||
| 258 | |||
| 259 | *started = true; | ||
| 260 | |||
| 261 | // safety: safe because critical section ensures only one *mut UartState | ||
| 262 | // exists at the same time. | ||
| 263 | unsafe { Pin::new_unchecked(&mut *ptr) }.start(); | ||
| 264 | } | ||
| 265 | |||
| 266 | // safety: safe because critical section ensures only one *mut UartState | ||
| 267 | // exists at the same time. | ||
| 268 | f(unsafe { Pin::new_unchecked(&mut *ptr) }) | ||
| 269 | }) | ||
| 270 | } | ||
| 271 | } | 149 | } |
| 272 | 150 | ||
| 273 | impl<T: Instance> Drop for BufferedUarte<T> { | 151 | impl<'a, T: Instance> Drop for BufferedUarte<'a, T> { |
| 274 | fn drop(&mut self) { | 152 | fn drop(&mut self) { |
| 275 | // stop DMA before dropping, because DMA is using the buffer in `self`. | 153 | // stop DMA before dropping, because DMA is using the buffer in `self`. |
| 276 | todo!() | 154 | todo!() |
| 277 | } | 155 | } |
| 278 | } | 156 | } |
| 279 | 157 | ||
| 280 | impl<T: Instance> AsyncBufRead for BufferedUarte<T> { | 158 | impl<'a, T: Instance> AsyncBufRead for BufferedUarte<'a, T> { |
| 281 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | 159 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { |
| 282 | self.with_state(|s| s.poll_fill_buf(cx)) | 160 | let this = unsafe { self.get_unchecked_mut() }; |
| 161 | this.reg.with(|state, _| { | ||
| 162 | let z: Poll<Result<&[u8]>> = state.poll_fill_buf(cx); | ||
| 163 | let z: Poll<Result<&[u8]>> = unsafe { mem::transmute(z) }; | ||
| 164 | z | ||
| 165 | }) | ||
| 283 | } | 166 | } |
| 284 | 167 | ||
| 285 | fn consume(self: Pin<&mut Self>, amt: usize) { | 168 | fn consume(self: Pin<&mut Self>, amt: usize) { |
| 286 | self.with_state(|s| s.consume(amt)) | 169 | let this = unsafe { self.get_unchecked_mut() }; |
| 170 | this.reg.with(|state, irq| state.consume(irq, amt)) | ||
| 287 | } | 171 | } |
| 288 | } | 172 | } |
| 289 | 173 | ||
| 290 | impl<T: Instance> AsyncWrite for BufferedUarte<T> { | 174 | impl<'a, T: Instance> AsyncWrite for BufferedUarte<'a, T> { |
| 291 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { | 175 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { |
| 292 | self.with_state(|s| s.poll_write(cx, buf)) | 176 | let this = unsafe { self.get_unchecked_mut() }; |
| 177 | this.reg.with(|state, irq| state.poll_write(irq, cx, buf)) | ||
| 293 | } | 178 | } |
| 294 | } | 179 | } |
| 295 | 180 | ||
| 296 | impl<T: Instance> UarteState<T> { | 181 | // ==================================== |
| 297 | pub fn start(self: Pin<&mut Self>) { | 182 | // ==================================== |
| 298 | self.irq.set_handler(|| unsafe { | 183 | // ==================================== |
| 299 | interrupt::free(|cs| T::get_state(cs).as_mut().unwrap().on_interrupt()); | ||
| 300 | }); | ||
| 301 | 184 | ||
| 302 | self.irq.pend(); | 185 | // public because it needs to be used in Instance trait, but |
| 303 | self.irq.enable(); | 186 | // should not be used outside the module |
| 304 | } | 187 | #[doc(hidden)] |
| 188 | pub struct State<'a, T: Instance> { | ||
| 189 | inner: T, | ||
| 305 | 190 | ||
| 306 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | 191 | rx: RingBuffer<'a>, |
| 307 | let this = unsafe { self.get_unchecked_mut() }; | 192 | rx_state: RxState, |
| 193 | rx_waker: WakerRegistration, | ||
| 194 | |||
| 195 | tx: RingBuffer<'a>, | ||
| 196 | tx_state: TxState, | ||
| 197 | tx_waker: WakerRegistration, | ||
| 198 | } | ||
| 308 | 199 | ||
| 200 | impl<'a, T: Instance> State<'a, T> { | ||
| 201 | fn poll_fill_buf(&mut self, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | ||
| 309 | // Conservative compiler fence to prevent optimizations that do not | 202 | // Conservative compiler fence to prevent optimizations that do not |
| 310 | // take in to account actions by DMA. The fence has been placed here, | 203 | // take in to account actions by DMA. The fence has been placed here, |
| 311 | // before any DMA action has started | 204 | // before any DMA action has started |
| @@ -313,7 +206,7 @@ impl<T: Instance> UarteState<T> { | |||
| 313 | trace!("poll_read"); | 206 | trace!("poll_read"); |
| 314 | 207 | ||
| 315 | // We have data ready in buffer? Return it. | 208 | // We have data ready in buffer? Return it. |
| 316 | let buf = this.rx.pop_buf(); | 209 | let buf = self.rx.pop_buf(); |
| 317 | if buf.len() != 0 { | 210 | if buf.len() != 0 { |
| 318 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); | 211 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); |
| 319 | return Poll::Ready(Ok(buf)); | 212 | return Poll::Ready(Ok(buf)); |
| @@ -321,38 +214,40 @@ impl<T: Instance> UarteState<T> { | |||
| 321 | 214 | ||
| 322 | trace!(" empty"); | 215 | trace!(" empty"); |
| 323 | 216 | ||
| 324 | if this.rx_state == RxState::ReceivingReady { | 217 | if self.rx_state == RxState::ReceivingReady { |
| 325 | trace!(" stopping"); | 218 | trace!(" stopping"); |
| 326 | this.rx_state = RxState::Stopping; | 219 | self.rx_state = RxState::Stopping; |
| 327 | this.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | 220 | self.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); |
| 328 | } | 221 | } |
| 329 | 222 | ||
| 330 | this.rx_waker.store(cx.waker()); | 223 | self.rx_waker.register(cx.waker()); |
| 331 | Poll::Pending | 224 | Poll::Pending |
| 332 | } | 225 | } |
| 333 | 226 | ||
| 334 | fn consume(self: Pin<&mut Self>, amt: usize) { | 227 | fn consume(&mut self, irq: &mut T::Interrupt, amt: usize) { |
| 335 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 336 | trace!("consume {:?}", amt); | 228 | trace!("consume {:?}", amt); |
| 337 | this.rx.pop(amt); | 229 | self.rx.pop(amt); |
| 338 | this.irq.pend(); | 230 | irq.pend(); |
| 339 | } | 231 | } |
| 340 | 232 | ||
| 341 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { | 233 | fn poll_write( |
| 342 | let this = unsafe { self.get_unchecked_mut() }; | 234 | &mut self, |
| 343 | 235 | irq: &mut T::Interrupt, | |
| 236 | cx: &mut Context<'_>, | ||
| 237 | buf: &[u8], | ||
| 238 | ) -> Poll<Result<usize>> { | ||
| 344 | trace!("poll_write: {:?}", buf.len()); | 239 | trace!("poll_write: {:?}", buf.len()); |
| 345 | 240 | ||
| 346 | let tx_buf = this.tx.push_buf(); | 241 | let tx_buf = self.tx.push_buf(); |
| 347 | if tx_buf.len() == 0 { | 242 | if tx_buf.len() == 0 { |
| 348 | trace!("poll_write: pending"); | 243 | trace!("poll_write: pending"); |
| 349 | this.tx_waker.store(cx.waker()); | 244 | self.tx_waker.register(cx.waker()); |
| 350 | return Poll::Pending; | 245 | return Poll::Pending; |
| 351 | } | 246 | } |
| 352 | 247 | ||
| 353 | let n = min(tx_buf.len(), buf.len()); | 248 | let n = min(tx_buf.len(), buf.len()); |
| 354 | tx_buf[..n].copy_from_slice(&buf[..n]); | 249 | tx_buf[..n].copy_from_slice(&buf[..n]); |
| 355 | this.tx.push(n); | 250 | self.tx.push(n); |
| 356 | 251 | ||
| 357 | trace!("poll_write: queued {:?}", n); | 252 | trace!("poll_write: queued {:?}", n); |
| 358 | 253 | ||
| @@ -361,10 +256,17 @@ impl<T: Instance> UarteState<T> { | |||
| 361 | // before any DMA action has started | 256 | // before any DMA action has started |
| 362 | compiler_fence(Ordering::SeqCst); | 257 | compiler_fence(Ordering::SeqCst); |
| 363 | 258 | ||
| 364 | this.irq.pend(); | 259 | irq.pend(); |
| 365 | 260 | ||
| 366 | Poll::Ready(Ok(n)) | 261 | Poll::Ready(Ok(n)) |
| 367 | } | 262 | } |
| 263 | } | ||
| 264 | |||
| 265 | impl<'a, T: Instance> peripheral::State for State<'a, T> { | ||
| 266 | type Interrupt = T::Interrupt; | ||
| 267 | fn store<'b>() -> &'b peripheral::Store<Self> { | ||
| 268 | unsafe { mem::transmute(T::storage()) } | ||
| 269 | } | ||
| 368 | 270 | ||
| 369 | fn on_interrupt(&mut self) { | 271 | fn on_interrupt(&mut self) { |
| 370 | trace!("irq: start"); | 272 | trace!("irq: start"); |
| @@ -504,13 +406,6 @@ impl<T: Instance> UarteState<T> { | |||
| 504 | } | 406 | } |
| 505 | } | 407 | } |
| 506 | 408 | ||
| 507 | pub struct Pins { | ||
| 508 | pub rxd: GpioPin<Input<Floating>>, | ||
| 509 | pub txd: GpioPin<Output<PushPull>>, | ||
| 510 | pub cts: Option<GpioPin<Input<Floating>>>, | ||
| 511 | pub rts: Option<GpioPin<Output<PushPull>>>, | ||
| 512 | } | ||
| 513 | |||
| 514 | mod private { | 409 | mod private { |
| 515 | pub trait Sealed {} | 410 | pub trait Sealed {} |
| 516 | 411 | ||
| @@ -519,39 +414,28 @@ mod private { | |||
| 519 | impl Sealed for crate::pac::UARTE1 {} | 414 | impl Sealed for crate::pac::UARTE1 {} |
| 520 | } | 415 | } |
| 521 | 416 | ||
| 522 | pub trait Instance: Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed { | 417 | pub trait Instance: |
| 418 | Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed + 'static | ||
| 419 | { | ||
| 523 | type Interrupt: OwnedInterrupt; | 420 | type Interrupt: OwnedInterrupt; |
| 524 | 421 | fn storage() -> &'static peripheral::Store<State<'static, Self>>; | |
| 525 | #[doc(hidden)] | ||
| 526 | fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self>; | ||
| 527 | |||
| 528 | #[doc(hidden)] | ||
| 529 | fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>); | ||
| 530 | } | 422 | } |
| 531 | 423 | ||
| 532 | static mut UARTE0_STATE: *mut UarteState<UARTE0> = ptr::null_mut(); | 424 | impl Instance for pac::UARTE0 { |
| 533 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | ||
| 534 | static mut UARTE1_STATE: *mut UarteState<UARTE1> = ptr::null_mut(); | ||
| 535 | |||
| 536 | impl Instance for UARTE0 { | ||
| 537 | type Interrupt = interrupt::UARTE0_UART0Interrupt; | 425 | type Interrupt = interrupt::UARTE0_UART0Interrupt; |
| 538 | 426 | fn storage() -> &'static peripheral::Store<State<'static, Self>> { | |
| 539 | fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> { | 427 | static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE0>> = |
| 540 | unsafe { UARTE0_STATE } // Safe because of CriticalSection | 428 | peripheral::Store::uninit(); |
| 541 | } | 429 | &STORAGE |
| 542 | fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) { | ||
| 543 | unsafe { UARTE0_STATE = state } // Safe because of CriticalSection | ||
| 544 | } | 430 | } |
| 545 | } | 431 | } |
| 546 | 432 | ||
| 547 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | 433 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] |
| 548 | impl Instance for UARTE1 { | 434 | impl Instance for pac::UARTE1 { |
| 549 | type Interrupt = interrupt::UARTE1Interrupt; | 435 | type Interrupt = interrupt::UARTE1Interrupt; |
| 550 | 436 | fn storage() -> &'static peripheral::Store<State<'static, Self>> { | |
| 551 | fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> { | 437 | static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE1>> = |
| 552 | unsafe { UARTE1_STATE } // Safe because of CriticalSection | 438 | peripheral::Store::uninit(); |
| 553 | } | 439 | &STORAGE |
| 554 | fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) { | ||
| 555 | unsafe { UARTE1_STATE = state } // Safe because of CriticalSection | ||
| 556 | } | 440 | } |
| 557 | } | 441 | } |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index e97002a20..ac2371766 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -50,6 +50,7 @@ pub use nrf52840_hal as hal; | |||
| 50 | 50 | ||
| 51 | // This mod MUST go first, so that the others see its macros. | 51 | // This mod MUST go first, so that the others see its macros. |
| 52 | pub(crate) mod fmt; | 52 | pub(crate) mod fmt; |
| 53 | pub(crate) mod util; | ||
| 53 | 54 | ||
| 54 | pub mod buffered_uarte; | 55 | pub mod buffered_uarte; |
| 55 | pub mod gpiote; | 56 | pub mod gpiote; |
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index f0337be8b..648298b84 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -10,7 +10,6 @@ use core::sync::atomic::{compiler_fence, Ordering}; | |||
| 10 | use core::task::{Context, Poll}; | 10 | use core::task::{Context, Poll}; |
| 11 | 11 | ||
| 12 | use embassy::util::Signal; | 12 | use embassy::util::Signal; |
| 13 | use embedded_dma::{ReadBuffer, WriteBuffer}; | ||
| 14 | 13 | ||
| 15 | use crate::fmt::{assert, *}; | 14 | use crate::fmt::{assert, *}; |
| 16 | #[cfg(any(feature = "52833", feature = "52840"))] | 15 | #[cfg(any(feature = "52833", feature = "52840"))] |
| @@ -140,57 +139,10 @@ where | |||
| 140 | self.instance.enable.write(|w| w.enable().enabled()); | 139 | self.instance.enable.write(|w| w.enable().enabled()); |
| 141 | } | 140 | } |
| 142 | 141 | ||
| 143 | /// Sends serial data. | ||
| 144 | /// | ||
| 145 | /// `tx_buffer` is marked as static as per `embedded-dma` requirements. | ||
| 146 | /// It it safe to use a buffer with a non static lifetime if memory is not | ||
| 147 | /// reused until the future has finished. | ||
| 148 | pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> SendFuture<'a, T, B> | ||
| 149 | where | ||
| 150 | B: ReadBuffer<Word = u8>, | ||
| 151 | { | ||
| 152 | // Panic if TX is running which can happen if the user has called | ||
| 153 | // `mem::forget()` on a previous future after polling it once. | ||
| 154 | assert!(!self.tx_started()); | ||
| 155 | |||
| 156 | self.enable(); | ||
| 157 | |||
| 158 | SendFuture { | ||
| 159 | uarte: self, | ||
| 160 | buf: tx_buffer, | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | fn tx_started(&self) -> bool { | 142 | fn tx_started(&self) -> bool { |
| 165 | self.instance.events_txstarted.read().bits() != 0 | 143 | self.instance.events_txstarted.read().bits() != 0 |
| 166 | } | 144 | } |
| 167 | 145 | ||
| 168 | /// Receives serial data. | ||
| 169 | /// | ||
| 170 | /// The future is pending until the buffer is completely filled. | ||
| 171 | /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel | ||
| 172 | /// unfinished transfers after a timeout to prevent lockup when no more data | ||
| 173 | /// is incoming. | ||
| 174 | /// | ||
| 175 | /// `rx_buffer` is marked as static as per `embedded-dma` requirements. | ||
| 176 | /// It it safe to use a buffer with a non static lifetime if memory is not | ||
| 177 | /// reused until the future has finished. | ||
| 178 | pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> ReceiveFuture<'a, T, B> | ||
| 179 | where | ||
| 180 | B: WriteBuffer<Word = u8>, | ||
| 181 | { | ||
| 182 | // Panic if RX is running which can happen if the user has called | ||
| 183 | // `mem::forget()` on a previous future after polling it once. | ||
| 184 | assert!(!self.rx_started()); | ||
| 185 | |||
| 186 | self.enable(); | ||
| 187 | |||
| 188 | ReceiveFuture { | ||
| 189 | uarte: self, | ||
| 190 | buf: Some(rx_buffer), | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | fn rx_started(&self) -> bool { | 146 | fn rx_started(&self) -> bool { |
| 195 | self.instance.events_rxstarted.read().bits() != 0 | 147 | self.instance.events_rxstarted.read().bits() != 0 |
| 196 | } | 148 | } |
| @@ -238,16 +190,62 @@ where | |||
| 238 | } | 190 | } |
| 239 | } | 191 | } |
| 240 | 192 | ||
| 193 | impl<T: Instance> embassy::uart::Uart for Uarte<T> { | ||
| 194 | type ReceiveFuture<'a> = ReceiveFuture<'a, T>; | ||
| 195 | type SendFuture<'a> = SendFuture<'a, T>; | ||
| 196 | |||
| 197 | /// Sends serial data. | ||
| 198 | /// | ||
| 199 | /// `tx_buffer` is marked as static as per `embedded-dma` requirements. | ||
| 200 | /// It it safe to use a buffer with a non static lifetime if memory is not | ||
| 201 | /// reused until the future has finished. | ||
| 202 | fn send<'a>(&'a mut self, tx_buffer: &'a [u8]) -> SendFuture<'a, T> { | ||
| 203 | // Panic if TX is running which can happen if the user has called | ||
| 204 | // `mem::forget()` on a previous future after polling it once. | ||
| 205 | assert!(!self.tx_started()); | ||
| 206 | |||
| 207 | self.enable(); | ||
| 208 | |||
| 209 | SendFuture { | ||
| 210 | uarte: self, | ||
| 211 | buf: tx_buffer, | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | /// Receives serial data. | ||
| 216 | /// | ||
| 217 | /// The future is pending until the buffer is completely filled. | ||
| 218 | /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel | ||
| 219 | /// unfinished transfers after a timeout to prevent lockup when no more data | ||
| 220 | /// is incoming. | ||
| 221 | /// | ||
| 222 | /// `rx_buffer` is marked as static as per `embedded-dma` requirements. | ||
| 223 | /// It it safe to use a buffer with a non static lifetime if memory is not | ||
| 224 | /// reused until the future has finished. | ||
| 225 | fn receive<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> ReceiveFuture<'a, T> { | ||
| 226 | // Panic if RX is running which can happen if the user has called | ||
| 227 | // `mem::forget()` on a previous future after polling it once. | ||
| 228 | assert!(!self.rx_started()); | ||
| 229 | |||
| 230 | self.enable(); | ||
| 231 | |||
| 232 | ReceiveFuture { | ||
| 233 | uarte: self, | ||
| 234 | buf: rx_buffer, | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 241 | /// Future for the [`Uarte::send()`] method. | 239 | /// Future for the [`Uarte::send()`] method. |
| 242 | pub struct SendFuture<'a, T, B> | 240 | pub struct SendFuture<'a, T> |
| 243 | where | 241 | where |
| 244 | T: Instance, | 242 | T: Instance, |
| 245 | { | 243 | { |
| 246 | uarte: &'a Uarte<T>, | 244 | uarte: &'a Uarte<T>, |
| 247 | buf: B, | 245 | buf: &'a [u8], |
| 248 | } | 246 | } |
| 249 | 247 | ||
| 250 | impl<'a, T, B> Drop for SendFuture<'a, T, B> | 248 | impl<'a, T> Drop for SendFuture<'a, T> |
| 251 | where | 249 | where |
| 252 | T: Instance, | 250 | T: Instance, |
| 253 | { | 251 | { |
| @@ -266,14 +264,13 @@ where | |||
| 266 | } | 264 | } |
| 267 | } | 265 | } |
| 268 | 266 | ||
| 269 | impl<'a, T, B> Future for SendFuture<'a, T, B> | 267 | impl<'a, T> Future for SendFuture<'a, T> |
| 270 | where | 268 | where |
| 271 | T: Instance, | 269 | T: Instance, |
| 272 | B: ReadBuffer<Word = u8>, | ||
| 273 | { | 270 | { |
| 274 | type Output = (); | 271 | type Output = Result<(), embassy::uart::Error>; |
| 275 | 272 | ||
| 276 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { | 273 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 277 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; | 274 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; |
| 278 | 275 | ||
| 279 | if !uarte.tx_started() { | 276 | if !uarte.tx_started() { |
| @@ -281,7 +278,8 @@ where | |||
| 281 | 278 | ||
| 282 | T::state().tx_done.reset(); | 279 | T::state().tx_done.reset(); |
| 283 | 280 | ||
| 284 | let (ptr, len) = unsafe { buf.read_buffer() }; | 281 | let ptr = buf.as_ptr(); |
| 282 | let len = buf.len(); | ||
| 285 | assert!(len <= EASY_DMA_SIZE); | 283 | assert!(len <= EASY_DMA_SIZE); |
| 286 | // TODO: panic if buffer is not in SRAM | 284 | // TODO: panic if buffer is not in SRAM |
| 287 | 285 | ||
| @@ -296,20 +294,20 @@ where | |||
| 296 | uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 294 | uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 297 | } | 295 | } |
| 298 | 296 | ||
| 299 | T::state().tx_done.poll_wait(cx) | 297 | T::state().tx_done.poll_wait(cx).map(|()| Ok(())) |
| 300 | } | 298 | } |
| 301 | } | 299 | } |
| 302 | 300 | ||
| 303 | /// Future for the [`Uarte::receive()`] method. | 301 | /// Future for the [`Uarte::receive()`] method. |
| 304 | pub struct ReceiveFuture<'a, T, B> | 302 | pub struct ReceiveFuture<'a, T> |
| 305 | where | 303 | where |
| 306 | T: Instance, | 304 | T: Instance, |
| 307 | { | 305 | { |
| 308 | uarte: &'a Uarte<T>, | 306 | uarte: &'a Uarte<T>, |
| 309 | buf: Option<B>, | 307 | buf: &'a mut [u8], |
| 310 | } | 308 | } |
| 311 | 309 | ||
| 312 | impl<'a, T, B> Drop for ReceiveFuture<'a, T, B> | 310 | impl<'a, T> Drop for ReceiveFuture<'a, T> |
| 313 | where | 311 | where |
| 314 | T: Instance, | 312 | T: Instance, |
| 315 | { | 313 | { |
| @@ -327,14 +325,13 @@ where | |||
| 327 | } | 325 | } |
| 328 | } | 326 | } |
| 329 | 327 | ||
| 330 | impl<'a, T, B> Future for ReceiveFuture<'a, T, B> | 328 | impl<'a, T> Future for ReceiveFuture<'a, T> |
| 331 | where | 329 | where |
| 332 | T: Instance, | 330 | T: Instance, |
| 333 | B: WriteBuffer<Word = u8>, | ||
| 334 | { | 331 | { |
| 335 | type Output = B; | 332 | type Output = Result<(), embassy::uart::Error>; |
| 336 | 333 | ||
| 337 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B> { | 334 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 338 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; | 335 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; |
| 339 | 336 | ||
| 340 | if !uarte.rx_started() { | 337 | if !uarte.rx_started() { |
| @@ -342,7 +339,8 @@ where | |||
| 342 | 339 | ||
| 343 | T::state().rx_done.reset(); | 340 | T::state().rx_done.reset(); |
| 344 | 341 | ||
| 345 | let (ptr, len) = unsafe { buf.as_mut().unwrap().write_buffer() }; | 342 | let ptr = buf.as_ptr(); |
| 343 | let len = buf.len(); | ||
| 346 | assert!(len <= EASY_DMA_SIZE); | 344 | assert!(len <= EASY_DMA_SIZE); |
| 347 | 345 | ||
| 348 | compiler_fence(Ordering::SeqCst); | 346 | compiler_fence(Ordering::SeqCst); |
| @@ -356,24 +354,20 @@ where | |||
| 356 | uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 354 | uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); |
| 357 | } | 355 | } |
| 358 | 356 | ||
| 359 | T::state() | 357 | T::state().rx_done.poll_wait(cx).map(|_| Ok(())) |
| 360 | .rx_done | ||
| 361 | .poll_wait(cx) | ||
| 362 | .map(|_| buf.take().unwrap()) | ||
| 363 | } | 358 | } |
| 364 | } | 359 | } |
| 365 | 360 | ||
| 366 | /// Future for the [`receive()`] method. | 361 | /// Future for the [`receive()`] method. |
| 367 | impl<'a, T, B> ReceiveFuture<'a, T, B> | 362 | impl<'a, T> ReceiveFuture<'a, T> |
| 368 | where | 363 | where |
| 369 | T: Instance, | 364 | T: Instance, |
| 370 | { | 365 | { |
| 371 | /// Stops the ongoing reception and returns the number of bytes received. | 366 | /// Stops the ongoing reception and returns the number of bytes received. |
| 372 | pub async fn stop(mut self) -> (B, usize) { | 367 | pub async fn stop(self) -> usize { |
| 373 | let buf = self.buf.take().unwrap(); | ||
| 374 | drop(self); | 368 | drop(self); |
| 375 | let len = T::state().rx_done.wait().await; | 369 | let len = T::state().rx_done.wait().await; |
| 376 | (buf, len as _) | 370 | len as _ |
| 377 | } | 371 | } |
| 378 | } | 372 | } |
| 379 | 373 | ||
| @@ -381,7 +375,9 @@ mod private { | |||
| 381 | pub trait Sealed {} | 375 | pub trait Sealed {} |
| 382 | } | 376 | } |
| 383 | 377 | ||
| 384 | pub trait Instance: Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed { | 378 | pub trait Instance: |
| 379 | Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed + 'static | ||
| 380 | { | ||
| 385 | type Interrupt: OwnedInterrupt; | 381 | type Interrupt: OwnedInterrupt; |
| 386 | 382 | ||
| 387 | #[doc(hidden)] | 383 | #[doc(hidden)] |
diff --git a/embassy-nrf/src/util/mod.rs b/embassy-nrf/src/util/mod.rs new file mode 100644 index 000000000..2fd5453d3 --- /dev/null +++ b/embassy-nrf/src/util/mod.rs | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | pub mod peripheral; | ||
| 2 | pub mod ring_buffer; | ||
diff --git a/embassy-nrf/src/util/peripheral.rs b/embassy-nrf/src/util/peripheral.rs new file mode 100644 index 000000000..85de3419e --- /dev/null +++ b/embassy-nrf/src/util/peripheral.rs | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | use core::mem; | ||
| 2 | use core::mem::MaybeUninit; | ||
| 3 | use core::ptr; | ||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 5 | use core::{cell::UnsafeCell, marker::PhantomData}; | ||
| 6 | |||
| 7 | use crate::interrupt::OwnedInterrupt; | ||
| 8 | |||
| 9 | pub struct Store<T>(MaybeUninit<UnsafeCell<T>>); | ||
| 10 | impl<T> Store<T> { | ||
| 11 | pub const fn uninit() -> Self { | ||
| 12 | Self(MaybeUninit::uninit()) | ||
| 13 | } | ||
| 14 | |||
| 15 | unsafe fn as_mut_ptr(&self) -> *mut T { | ||
| 16 | (*self.0.as_ptr()).get() | ||
| 17 | } | ||
| 18 | |||
| 19 | unsafe fn as_mut(&self) -> &mut T { | ||
| 20 | &mut *self.as_mut_ptr() | ||
| 21 | } | ||
| 22 | |||
| 23 | unsafe fn write(&self, val: T) { | ||
| 24 | ptr::write(self.as_mut_ptr(), val) | ||
| 25 | } | ||
| 26 | |||
| 27 | unsafe fn drop_in_place(&self) { | ||
| 28 | ptr::drop_in_place(self.as_mut_ptr()) | ||
| 29 | } | ||
| 30 | |||
| 31 | unsafe fn read(&self) -> T { | ||
| 32 | ptr::read(self.as_mut_ptr()) | ||
| 33 | } | ||
| 34 | } | ||
| 35 | unsafe impl<T> Send for Store<T> {} | ||
| 36 | unsafe impl<T> Sync for Store<T> {} | ||
| 37 | |||
| 38 | pub trait State: Sized { | ||
| 39 | type Interrupt: OwnedInterrupt; | ||
| 40 | fn on_interrupt(&mut self); | ||
| 41 | #[doc(hidden)] | ||
| 42 | fn store<'a>() -> &'a Store<Self>; | ||
| 43 | } | ||
| 44 | |||
| 45 | pub struct Registration<P: State> { | ||
| 46 | irq: P::Interrupt, | ||
| 47 | not_send: PhantomData<*mut P>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<P: State> Registration<P> { | ||
| 51 | pub fn new(irq: P::Interrupt, state: P) -> Self { | ||
| 52 | // safety: | ||
| 53 | // - No other PeripheralRegistration can already exist because we have the owned interrupt | ||
| 54 | // - therefore, storage is uninitialized | ||
| 55 | // - therefore it's safe to overwrite it without dropping the previous contents | ||
| 56 | unsafe { P::store().write(state) } | ||
| 57 | |||
| 58 | irq.set_handler(|| { | ||
| 59 | // safety: | ||
| 60 | // - If a PeripheralRegistration instance exists, P::storage() is initialized. | ||
| 61 | // - It's OK to get a &mut to it since the irq is disabled. | ||
| 62 | unsafe { P::store().as_mut() }.on_interrupt(); | ||
| 63 | }); | ||
| 64 | |||
| 65 | compiler_fence(Ordering::SeqCst); | ||
| 66 | irq.enable(); | ||
| 67 | |||
| 68 | Self { | ||
| 69 | irq, | ||
| 70 | not_send: PhantomData, | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn with<R>(&mut self, f: impl FnOnce(&mut P, &mut P::Interrupt) -> R) -> R { | ||
| 75 | self.irq.disable(); | ||
| 76 | compiler_fence(Ordering::SeqCst); | ||
| 77 | |||
| 78 | // safety: | ||
| 79 | // - If a PeripheralRegistration instance exists, P::storage() is initialized. | ||
| 80 | // - It's OK to get a &mut to it since the irq is disabled. | ||
| 81 | let r = f(unsafe { P::store().as_mut() }, &mut self.irq); | ||
| 82 | |||
| 83 | compiler_fence(Ordering::SeqCst); | ||
| 84 | self.irq.enable(); | ||
| 85 | |||
| 86 | r | ||
| 87 | } | ||
| 88 | |||
| 89 | pub fn free(self) -> (P::Interrupt, P) { | ||
| 90 | let irq = unsafe { ptr::read(&self.irq) }; | ||
| 91 | irq.disable(); | ||
| 92 | irq.set_handler(|| ()); | ||
| 93 | mem::forget(self); | ||
| 94 | let storage = P::store(); | ||
| 95 | (irq, unsafe { storage.read() }) | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | impl<P: State> Drop for Registration<P> { | ||
| 100 | fn drop(&mut self) { | ||
| 101 | self.irq.disable(); | ||
| 102 | self.irq.set_handler(|| ()); | ||
| 103 | |||
| 104 | let storage = P::store(); | ||
| 105 | unsafe { storage.drop_in_place() }; | ||
| 106 | } | ||
| 107 | } | ||
diff --git a/embassy-nrf/src/util/ring_buffer.rs b/embassy-nrf/src/util/ring_buffer.rs new file mode 100644 index 000000000..f395785a5 --- /dev/null +++ b/embassy-nrf/src/util/ring_buffer.rs | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | use crate::fmt::{assert, panic, todo, *}; | ||
| 2 | |||
| 3 | pub struct RingBuffer<'a> { | ||
| 4 | buf: &'a mut [u8], | ||
| 5 | start: usize, | ||
| 6 | end: usize, | ||
| 7 | empty: bool, | ||
| 8 | } | ||
| 9 | |||
| 10 | impl<'a> RingBuffer<'a> { | ||
| 11 | pub fn new(buf: &'a mut [u8]) -> Self { | ||
| 12 | Self { | ||
| 13 | buf, | ||
| 14 | start: 0, | ||
| 15 | end: 0, | ||
| 16 | empty: true, | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | pub fn push_buf(&mut self) -> &mut [u8] { | ||
| 21 | if self.start == self.end && !self.empty { | ||
| 22 | trace!(" ringbuf: push_buf empty"); | ||
| 23 | return &mut self.buf[..0]; | ||
| 24 | } | ||
| 25 | |||
| 26 | let n = if self.start <= self.end { | ||
| 27 | self.buf.len() - self.end | ||
| 28 | } else { | ||
| 29 | self.start - self.end | ||
| 30 | }; | ||
| 31 | |||
| 32 | trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); | ||
| 33 | &mut self.buf[self.end..self.end + n] | ||
| 34 | } | ||
| 35 | |||
| 36 | pub fn push(&mut self, n: usize) { | ||
| 37 | trace!(" ringbuf: push {:?}", n); | ||
| 38 | if n == 0 { | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | |||
| 42 | self.end = self.wrap(self.end + n); | ||
| 43 | self.empty = false; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn pop_buf(&mut self) -> &mut [u8] { | ||
| 47 | if self.empty { | ||
| 48 | trace!(" ringbuf: pop_buf empty"); | ||
| 49 | return &mut self.buf[..0]; | ||
| 50 | } | ||
| 51 | |||
| 52 | let n = if self.end <= self.start { | ||
| 53 | self.buf.len() - self.start | ||
| 54 | } else { | ||
| 55 | self.end - self.start | ||
| 56 | }; | ||
| 57 | |||
| 58 | trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); | ||
| 59 | &mut self.buf[self.start..self.start + n] | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn pop(&mut self, n: usize) { | ||
| 63 | trace!(" ringbuf: pop {:?}", n); | ||
| 64 | if n == 0 { | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | self.start = self.wrap(self.start + n); | ||
| 69 | self.empty = self.start == self.end; | ||
| 70 | } | ||
| 71 | |||
| 72 | fn wrap(&self, n: usize) -> usize { | ||
| 73 | assert!(n <= self.buf.len()); | ||
| 74 | if n == self.buf.len() { | ||
| 75 | 0 | ||
| 76 | } else { | ||
| 77 | n | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index bc06ebd13..02d72a84f 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | #![cfg_attr(not(feature = "std"), no_std)] | 1 | #![cfg_attr(not(feature = "std"), no_std)] |
| 2 | #![feature(slice_fill)] | ||
| 3 | #![feature(generic_associated_types)] | 2 | #![feature(generic_associated_types)] |
| 4 | #![feature(const_fn)] | 3 | #![feature(const_fn)] |
| 5 | #![feature(const_fn_fn_ptr_basics)] | 4 | #![feature(const_fn_fn_ptr_basics)] |
| @@ -13,4 +12,5 @@ pub mod interrupt; | |||
| 13 | pub mod io; | 12 | pub mod io; |
| 14 | pub mod rand; | 13 | pub mod rand; |
| 15 | pub mod time; | 14 | pub mod time; |
| 15 | pub mod uart; | ||
| 16 | pub mod util; | 16 | pub mod util; |
diff --git a/embassy/src/uart.rs b/embassy/src/uart.rs new file mode 100644 index 000000000..b40b9e9bd --- /dev/null +++ b/embassy/src/uart.rs | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | |||
| 3 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
| 4 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 5 | #[non_exhaustive] | ||
| 6 | pub enum Error { | ||
| 7 | Other, | ||
| 8 | } | ||
| 9 | |||
| 10 | pub trait Uart { | ||
| 11 | type ReceiveFuture<'a>: Future<Output = Result<(), Error>>; | ||
| 12 | type SendFuture<'a>: Future<Output = Result<(), Error>>; | ||
| 13 | fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>; | ||
| 14 | fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>; | ||
| 15 | } | ||
diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 94745b834..5694d6bfb 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs | |||
| @@ -2,10 +2,10 @@ mod drop_bomb; | |||
| 2 | mod forever; | 2 | mod forever; |
| 3 | mod portal; | 3 | mod portal; |
| 4 | mod signal; | 4 | mod signal; |
| 5 | mod waker_store; | 5 | mod waker; |
| 6 | 6 | ||
| 7 | pub use drop_bomb::*; | 7 | pub use drop_bomb::*; |
| 8 | pub use forever::*; | 8 | pub use forever::*; |
| 9 | pub use portal::*; | 9 | pub use portal::*; |
| 10 | pub use signal::*; | 10 | pub use signal::*; |
| 11 | pub use waker_store::*; | 11 | pub use waker::*; |
diff --git a/embassy/src/util/waker.rs b/embassy/src/util/waker.rs new file mode 100644 index 000000000..9735438b5 --- /dev/null +++ b/embassy/src/util/waker.rs | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | use core::task::Context; | ||
| 2 | use core::task::Waker; | ||
| 3 | |||
| 4 | /// Utility struct to register and wake a waker. | ||
| 5 | #[derive(Debug)] | ||
| 6 | pub struct WakerRegistration { | ||
| 7 | waker: Option<Waker>, | ||
| 8 | } | ||
| 9 | |||
| 10 | impl WakerRegistration { | ||
| 11 | pub const fn new() -> Self { | ||
| 12 | Self { waker: None } | ||
| 13 | } | ||
| 14 | |||
| 15 | /// Register a waker. Overwrites the previous waker, if any. | ||
| 16 | pub fn register(&mut self, w: &Waker) { | ||
| 17 | match self.waker { | ||
| 18 | // Optimization: If both the old and new Wakers wake the same task, we can simply | ||
| 19 | // keep the old waker, skipping the clone. (In most executor implementations, | ||
| 20 | // cloning a waker is somewhat expensive, comparable to cloning an Arc). | ||
| 21 | Some(ref w2) if (w2.will_wake(w)) => {} | ||
| 22 | // In all other cases | ||
| 23 | // - we have no waker registered | ||
| 24 | // - we have a waker registered but it's for a different task. | ||
| 25 | // then clone the new waker and store it | ||
| 26 | _ => self.waker = Some(w.clone()), | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Wake the registered waker, if any. | ||
| 31 | pub fn wake(&mut self) { | ||
| 32 | self.waker.take().map(|w| w.wake()); | ||
| 33 | } | ||
| 34 | |||
| 35 | pub fn context(&self) -> Option<Context<'_>> { | ||
| 36 | self.waker.as_ref().map(|w| Context::from_waker(w)) | ||
| 37 | } | ||
| 38 | } \ No newline at end of file | ||
diff --git a/embassy/src/util/waker_store.rs b/embassy/src/util/waker_store.rs deleted file mode 100644 index 0b2f09f4b..000000000 --- a/embassy/src/util/waker_store.rs +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | use core::task::Waker; | ||
| 2 | |||
| 3 | pub struct WakerStore { | ||
| 4 | waker: Option<Waker>, | ||
| 5 | } | ||
| 6 | |||
| 7 | impl WakerStore { | ||
| 8 | pub const fn new() -> Self { | ||
| 9 | Self { waker: None } | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn store(&mut self, w: &Waker) { | ||
| 13 | match self.waker { | ||
| 14 | Some(ref w2) if (w2.will_wake(w)) => {} | ||
| 15 | Some(_) => panic!("Waker overflow"), | ||
| 16 | None => self.waker = Some(w.clone()), | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | pub fn wake(&mut self) { | ||
| 21 | self.waker.take().map(|w| w.wake()); | ||
| 22 | } | ||
| 23 | } | ||
diff --git a/test-build.sh b/test-build.sh index 52bf7bb7b..f67cc5b2b 100755 --- a/test-build.sh +++ b/test-build.sh | |||
| @@ -2,9 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | set -euxo pipefail | 3 | set -euxo pipefail |
| 4 | 4 | ||
| 5 | # examples | ||
| 6 | (cd examples; cargo build --target thumbv7em-none-eabi --bins) | ||
| 7 | |||
| 8 | # embassy std | 5 | # embassy std |
| 9 | (cd embassy; cargo build --features log,std) | 6 | (cd embassy; cargo build --features log,std) |
| 10 | 7 | ||
| @@ -14,6 +11,9 @@ set -euxo pipefail | |||
| 14 | (cd embassy; cargo build --target thumbv7em-none-eabi --features defmt) | 11 | (cd embassy; cargo build --target thumbv7em-none-eabi --features defmt) |
| 15 | 12 | ||
| 16 | # embassy-nrf | 13 | # embassy-nrf |
| 14 | |||
| 15 | (cd embassy-nrf-examples; cargo build --target thumbv7em-none-eabi --bins) | ||
| 16 | |||
| 17 | (cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810) | 17 | (cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810) |
| 18 | #(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet | 18 | #(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet |
| 19 | (cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832) | 19 | (cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832) |
