From 7bfb763e0990aac1b0bc4ad95dcc55df53cdb6d9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jul 2021 13:44:51 +0200 Subject: Rename embassy-extras to embassy-hal-common --- Cargo.example.toml | 2 +- embassy-extras/Cargo.toml | 20 - embassy-extras/src/fmt.rs | 225 ----------- embassy-extras/src/interrupt.rs | 571 ---------------------------- embassy-extras/src/lib.rs | 21 - embassy-extras/src/macros.rs | 130 ------- embassy-extras/src/peripheral.rs | 160 -------- embassy-extras/src/peripheral_shared.rs | 122 ------ embassy-extras/src/ring_buffer.rs | 84 ---- embassy-extras/src/usb/cdc_acm.rs | 338 ---------------- embassy-extras/src/usb/mod.rs | 258 ------------- embassy-extras/src/usb/usb_serial.rs | 310 --------------- embassy-hal-common/Cargo.toml | 20 + embassy-hal-common/src/fmt.rs | 225 +++++++++++ embassy-hal-common/src/interrupt.rs | 571 ++++++++++++++++++++++++++++ embassy-hal-common/src/lib.rs | 21 + embassy-hal-common/src/macros.rs | 130 +++++++ embassy-hal-common/src/peripheral.rs | 160 ++++++++ embassy-hal-common/src/peripheral_shared.rs | 122 ++++++ embassy-hal-common/src/ring_buffer.rs | 84 ++++ embassy-hal-common/src/usb/cdc_acm.rs | 338 ++++++++++++++++ embassy-hal-common/src/usb/mod.rs | 258 +++++++++++++ embassy-hal-common/src/usb/usb_serial.rs | 310 +++++++++++++++ embassy-nrf/Cargo.toml | 2 +- embassy-nrf/src/buffered_uarte.rs | 6 +- embassy-nrf/src/chips/nrf52805.rs | 2 +- embassy-nrf/src/chips/nrf52810.rs | 2 +- embassy-nrf/src/chips/nrf52811.rs | 2 +- embassy-nrf/src/chips/nrf52820.rs | 2 +- embassy-nrf/src/chips/nrf52832.rs | 2 +- embassy-nrf/src/chips/nrf52833.rs | 2 +- embassy-nrf/src/chips/nrf52840.rs | 2 +- embassy-nrf/src/gpio.rs | 2 +- embassy-nrf/src/gpiote.rs | 2 +- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/ppi.rs | 2 +- embassy-nrf/src/pwm.rs | 2 +- embassy-nrf/src/qspi.rs | 2 +- embassy-nrf/src/rng.rs | 2 +- embassy-nrf/src/saadc.rs | 2 +- embassy-nrf/src/spim.rs | 2 +- embassy-nrf/src/timer.rs | 2 +- embassy-nrf/src/twim.rs | 2 +- embassy-nrf/src/uarte.rs | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-rp/src/gpio.rs | 2 +- embassy-rp/src/interrupt.rs | 2 +- embassy-rp/src/lib.rs | 2 +- embassy-rp/src/spi.rs | 2 +- embassy-rp/src/uart.rs | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-stm32/gen.py | 2 +- embassy-stm32/src/adc/v3.rs | 2 +- embassy-stm32/src/dac/v2.rs | 2 +- embassy-stm32/src/eth/v2/mod.rs | 4 +- embassy-stm32/src/exti/mod.rs | 2 +- embassy-stm32/src/gpio.rs | 2 +- embassy-stm32/src/i2c/v1.rs | 2 +- embassy-stm32/src/i2c/v2.rs | 2 +- embassy-stm32/src/interrupt.rs | 2 +- embassy-stm32/src/rcc/f4/mod.rs | 2 +- embassy-stm32/src/rcc/l0/mod.rs | 2 +- embassy-stm32/src/rcc/l4/mod.rs | 2 +- embassy-stm32/src/rcc/wb55/mod.rs | 2 +- embassy-stm32/src/rcc/wl5x/mod.rs | 2 +- embassy-stm32/src/rng.rs | 2 +- embassy-stm32/src/sdmmc/v2.rs | 2 +- embassy-stm32/src/spi/v1.rs | 2 +- embassy-stm32/src/spi/v2.rs | 2 +- embassy-stm32/src/spi/v3.rs | 2 +- embassy-stm32/src/usart/v1.rs | 2 +- embassy-stm32/src/usart/v2.rs | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32wb55/Cargo.toml | 2 +- 77 files changed, 2297 insertions(+), 2297 deletions(-) delete mode 100644 embassy-extras/Cargo.toml delete mode 100644 embassy-extras/src/fmt.rs delete mode 100644 embassy-extras/src/interrupt.rs delete mode 100644 embassy-extras/src/lib.rs delete mode 100644 embassy-extras/src/macros.rs delete mode 100644 embassy-extras/src/peripheral.rs delete mode 100644 embassy-extras/src/peripheral_shared.rs delete mode 100644 embassy-extras/src/ring_buffer.rs delete mode 100644 embassy-extras/src/usb/cdc_acm.rs delete mode 100644 embassy-extras/src/usb/mod.rs delete mode 100644 embassy-extras/src/usb/usb_serial.rs create mode 100644 embassy-hal-common/Cargo.toml create mode 100644 embassy-hal-common/src/fmt.rs create mode 100644 embassy-hal-common/src/interrupt.rs create mode 100644 embassy-hal-common/src/lib.rs create mode 100644 embassy-hal-common/src/macros.rs create mode 100644 embassy-hal-common/src/peripheral.rs create mode 100644 embassy-hal-common/src/peripheral_shared.rs create mode 100644 embassy-hal-common/src/ring_buffer.rs create mode 100644 embassy-hal-common/src/usb/cdc_acm.rs create mode 100644 embassy-hal-common/src/usb/mod.rs create mode 100644 embassy-hal-common/src/usb/usb_serial.rs diff --git a/Cargo.example.toml b/Cargo.example.toml index 3362d0bc0..f072c2f96 100644 --- a/Cargo.example.toml +++ b/Cargo.example.toml @@ -21,7 +21,7 @@ members = [ "embassy", "embassy-traits", "embassy-macros", - "embassy-extras", + "embassy-hal-common", "embassy-net", # Uncomment ONLY ONE of the groups below. diff --git a/embassy-extras/Cargo.toml b/embassy-extras/Cargo.toml deleted file mode 100644 index 5d07901a9..000000000 --- a/embassy-extras/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "embassy-extras" -version = "0.1.0" -authors = ["Dario Nieuwenhuis "] -edition = "2018" - -[features] -defmt-trace = [ ] -defmt-debug = [ ] -defmt-info = [ ] -defmt-warn = [ ] -defmt-error = [ ] - -[dependencies] -embassy = { version = "0.1.0", path = "../embassy" } - -defmt = { version = "0.2.0", optional = true } -log = { version = "0.4.11", optional = true } -cortex-m = "0.7.1" -usb-device = "0.2.7" diff --git a/embassy-extras/src/fmt.rs b/embassy-extras/src/fmt.rs deleted file mode 100644 index 066970813..000000000 --- a/embassy-extras/src/fmt.rs +++ /dev/null @@ -1,225 +0,0 @@ -#![macro_use] -#![allow(unused_macros)] - -#[cfg(all(feature = "defmt", feature = "log"))] -compile_error!("You may not enable both `defmt` and `log` features."); - -macro_rules! assert { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert!($($x)*); - } - }; -} - -macro_rules! assert_eq { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert_eq!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert_eq!($($x)*); - } - }; -} - -macro_rules! assert_ne { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert_ne!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert_ne!($($x)*); - } - }; -} - -macro_rules! debug_assert { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert!($($x)*); - } - }; -} - -macro_rules! debug_assert_eq { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert_eq!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert_eq!($($x)*); - } - }; -} - -macro_rules! debug_assert_ne { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert_ne!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert_ne!($($x)*); - } - }; -} - -macro_rules! todo { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::todo!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::todo!($($x)*); - } - }; -} - -macro_rules! unreachable { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } - }; -} - -macro_rules! panic { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::panic!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::panic!($($x)*); - } - }; -} - -macro_rules! trace { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::trace!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::trace!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! debug { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::debug!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::debug!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! info { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::info!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::info!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! warn { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::warn!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::warn!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! error { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::error!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::error!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -#[cfg(feature = "defmt")] -macro_rules! unwrap { - ($($x:tt)*) => { - ::defmt::unwrap!($($x)*) - }; -} - -#[cfg(not(feature = "defmt"))] -macro_rules! unwrap { - ($arg:expr) => { - match $crate::fmt::Try::into_result($arg) { - ::core::result::Result::Ok(t) => t, - ::core::result::Result::Err(e) => { - ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); - } - } - }; - ($arg:expr, $($msg:expr),+ $(,)? ) => { - match $crate::fmt::Try::into_result($arg) { - ::core::result::Result::Ok(t) => t, - ::core::result::Result::Err(e) => { - ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); - } - } - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct NoneError; - -pub trait Try { - type Ok; - type Error; - fn into_result(self) -> Result; -} - -impl Try for Option { - type Ok = T; - type Error = NoneError; - - #[inline] - fn into_result(self) -> Result { - self.ok_or(NoneError) - } -} - -impl Try for Result { - type Ok = T; - type Error = E; - - #[inline] - fn into_result(self) -> Self { - self - } -} diff --git a/embassy-extras/src/interrupt.rs b/embassy-extras/src/interrupt.rs deleted file mode 100644 index 80b2cad5d..000000000 --- a/embassy-extras/src/interrupt.rs +++ /dev/null @@ -1,571 +0,0 @@ -use core::mem; - -macro_rules! prio { - ($name:ident, $mask:expr, ($($k:ident = $v:expr,)*)) => { - #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[repr(u8)] - pub enum $name { - $($k = $v),* - } - - impl From for $name { - fn from(priority: u8) -> Self { - unsafe { mem::transmute(priority & $mask) } - } - } - - impl From<$name> for u8 { - fn from(p: $name) -> Self { - p as u8 - } - } - }; -} - -#[rustfmt::skip] -prio!(Priority0, 0x00, ( - P0 = 0x0, -)); - -#[rustfmt::skip] -prio!(Priority1, 0x80, ( - P0 = 0x0, - P1 = 0x80, -)); - -#[rustfmt::skip] -prio!(Priority2, 0xc0, ( - P0 = 0x0, - P1 = 0x40, - P2 = 0x80, - P3 = 0xc0, -)); - -#[rustfmt::skip] -prio!(Priority3, 0xe0, ( - P0 = 0x0, - P1 = 0x20, - P2 = 0x40, - P3 = 0x60, - P4 = 0x80, - P5 = 0xa0, - P6 = 0xc0, - P7 = 0xe0, -)); - -#[rustfmt::skip] -prio!(Priority4, 0xf0, ( - P0 = 0x0, - P1 = 0x10, - P2 = 0x20, - P3 = 0x30, - P4 = 0x40, - P5 = 0x50, - P6 = 0x60, - P7 = 0x70, - P8 = 0x80, - P9 = 0x90, - P10 = 0xa0, - P11 = 0xb0, - P12 = 0xc0, - P13 = 0xd0, - P14 = 0xe0, - P15 = 0xf0, -)); - -#[rustfmt::skip] -prio!(Priority5, 0xf8, ( - P0 = 0x0, - P1 = 0x8, - P2 = 0x10, - P3 = 0x18, - P4 = 0x20, - P5 = 0x28, - P6 = 0x30, - P7 = 0x38, - P8 = 0x40, - P9 = 0x48, - P10 = 0x50, - P11 = 0x58, - P12 = 0x60, - P13 = 0x68, - P14 = 0x70, - P15 = 0x78, - P16 = 0x80, - P17 = 0x88, - P18 = 0x90, - P19 = 0x98, - P20 = 0xa0, - P21 = 0xa8, - P22 = 0xb0, - P23 = 0xb8, - P24 = 0xc0, - P25 = 0xc8, - P26 = 0xd0, - P27 = 0xd8, - P28 = 0xe0, - P29 = 0xe8, - P30 = 0xf0, - P31 = 0xf8, -)); - -#[rustfmt::skip] -prio!(Priority6, 0xfc, ( - P0 = 0x0, - P1 = 0x4, - P2 = 0x8, - P3 = 0xc, - P4 = 0x10, - P5 = 0x14, - P6 = 0x18, - P7 = 0x1c, - P8 = 0x20, - P9 = 0x24, - P10 = 0x28, - P11 = 0x2c, - P12 = 0x30, - P13 = 0x34, - P14 = 0x38, - P15 = 0x3c, - P16 = 0x40, - P17 = 0x44, - P18 = 0x48, - P19 = 0x4c, - P20 = 0x50, - P21 = 0x54, - P22 = 0x58, - P23 = 0x5c, - P24 = 0x60, - P25 = 0x64, - P26 = 0x68, - P27 = 0x6c, - P28 = 0x70, - P29 = 0x74, - P30 = 0x78, - P31 = 0x7c, - P32 = 0x80, - P33 = 0x84, - P34 = 0x88, - P35 = 0x8c, - P36 = 0x90, - P37 = 0x94, - P38 = 0x98, - P39 = 0x9c, - P40 = 0xa0, - P41 = 0xa4, - P42 = 0xa8, - P43 = 0xac, - P44 = 0xb0, - P45 = 0xb4, - P46 = 0xb8, - P47 = 0xbc, - P48 = 0xc0, - P49 = 0xc4, - P50 = 0xc8, - P51 = 0xcc, - P52 = 0xd0, - P53 = 0xd4, - P54 = 0xd8, - P55 = 0xdc, - P56 = 0xe0, - P57 = 0xe4, - P58 = 0xe8, - P59 = 0xec, - P60 = 0xf0, - P61 = 0xf4, - P62 = 0xf8, - P63 = 0xfc, -)); - -#[rustfmt::skip] -prio!(Priority7, 0xfe, ( - P0 = 0x0, - P1 = 0x2, - P2 = 0x4, - P3 = 0x6, - P4 = 0x8, - P5 = 0xa, - P6 = 0xc, - P7 = 0xe, - P8 = 0x10, - P9 = 0x12, - P10 = 0x14, - P11 = 0x16, - P12 = 0x18, - P13 = 0x1a, - P14 = 0x1c, - P15 = 0x1e, - P16 = 0x20, - P17 = 0x22, - P18 = 0x24, - P19 = 0x26, - P20 = 0x28, - P21 = 0x2a, - P22 = 0x2c, - P23 = 0x2e, - P24 = 0x30, - P25 = 0x32, - P26 = 0x34, - P27 = 0x36, - P28 = 0x38, - P29 = 0x3a, - P30 = 0x3c, - P31 = 0x3e, - P32 = 0x40, - P33 = 0x42, - P34 = 0x44, - P35 = 0x46, - P36 = 0x48, - P37 = 0x4a, - P38 = 0x4c, - P39 = 0x4e, - P40 = 0x50, - P41 = 0x52, - P42 = 0x54, - P43 = 0x56, - P44 = 0x58, - P45 = 0x5a, - P46 = 0x5c, - P47 = 0x5e, - P48 = 0x60, - P49 = 0x62, - P50 = 0x64, - P51 = 0x66, - P52 = 0x68, - P53 = 0x6a, - P54 = 0x6c, - P55 = 0x6e, - P56 = 0x70, - P57 = 0x72, - P58 = 0x74, - P59 = 0x76, - P60 = 0x78, - P61 = 0x7a, - P62 = 0x7c, - P63 = 0x7e, - P64 = 0x80, - P65 = 0x82, - P66 = 0x84, - P67 = 0x86, - P68 = 0x88, - P69 = 0x8a, - P70 = 0x8c, - P71 = 0x8e, - P72 = 0x90, - P73 = 0x92, - P74 = 0x94, - P75 = 0x96, - P76 = 0x98, - P77 = 0x9a, - P78 = 0x9c, - P79 = 0x9e, - P80 = 0xa0, - P81 = 0xa2, - P82 = 0xa4, - P83 = 0xa6, - P84 = 0xa8, - P85 = 0xaa, - P86 = 0xac, - P87 = 0xae, - P88 = 0xb0, - P89 = 0xb2, - P90 = 0xb4, - P91 = 0xb6, - P92 = 0xb8, - P93 = 0xba, - P94 = 0xbc, - P95 = 0xbe, - P96 = 0xc0, - P97 = 0xc2, - P98 = 0xc4, - P99 = 0xc6, - P100 = 0xc8, - P101 = 0xca, - P102 = 0xcc, - P103 = 0xce, - P104 = 0xd0, - P105 = 0xd2, - P106 = 0xd4, - P107 = 0xd6, - P108 = 0xd8, - P109 = 0xda, - P110 = 0xdc, - P111 = 0xde, - P112 = 0xe0, - P113 = 0xe2, - P114 = 0xe4, - P115 = 0xe6, - P116 = 0xe8, - P117 = 0xea, - P118 = 0xec, - P119 = 0xee, - P120 = 0xf0, - P121 = 0xf2, - P122 = 0xf4, - P123 = 0xf6, - P124 = 0xf8, - P125 = 0xfa, - P126 = 0xfc, - P127 = 0xfe, -)); - -#[rustfmt::skip] -prio!(Priority8, 0xff, ( - P0 = 0x0, - P1 = 0x1, - P2 = 0x2, - P3 = 0x3, - P4 = 0x4, - P5 = 0x5, - P6 = 0x6, - P7 = 0x7, - P8 = 0x8, - P9 = 0x9, - P10 = 0xa, - P11 = 0xb, - P12 = 0xc, - P13 = 0xd, - P14 = 0xe, - P15 = 0xf, - P16 = 0x10, - P17 = 0x11, - P18 = 0x12, - P19 = 0x13, - P20 = 0x14, - P21 = 0x15, - P22 = 0x16, - P23 = 0x17, - P24 = 0x18, - P25 = 0x19, - P26 = 0x1a, - P27 = 0x1b, - P28 = 0x1c, - P29 = 0x1d, - P30 = 0x1e, - P31 = 0x1f, - P32 = 0x20, - P33 = 0x21, - P34 = 0x22, - P35 = 0x23, - P36 = 0x24, - P37 = 0x25, - P38 = 0x26, - P39 = 0x27, - P40 = 0x28, - P41 = 0x29, - P42 = 0x2a, - P43 = 0x2b, - P44 = 0x2c, - P45 = 0x2d, - P46 = 0x2e, - P47 = 0x2f, - P48 = 0x30, - P49 = 0x31, - P50 = 0x32, - P51 = 0x33, - P52 = 0x34, - P53 = 0x35, - P54 = 0x36, - P55 = 0x37, - P56 = 0x38, - P57 = 0x39, - P58 = 0x3a, - P59 = 0x3b, - P60 = 0x3c, - P61 = 0x3d, - P62 = 0x3e, - P63 = 0x3f, - P64 = 0x40, - P65 = 0x41, - P66 = 0x42, - P67 = 0x43, - P68 = 0x44, - P69 = 0x45, - P70 = 0x46, - P71 = 0x47, - P72 = 0x48, - P73 = 0x49, - P74 = 0x4a, - P75 = 0x4b, - P76 = 0x4c, - P77 = 0x4d, - P78 = 0x4e, - P79 = 0x4f, - P80 = 0x50, - P81 = 0x51, - P82 = 0x52, - P83 = 0x53, - P84 = 0x54, - P85 = 0x55, - P86 = 0x56, - P87 = 0x57, - P88 = 0x58, - P89 = 0x59, - P90 = 0x5a, - P91 = 0x5b, - P92 = 0x5c, - P93 = 0x5d, - P94 = 0x5e, - P95 = 0x5f, - P96 = 0x60, - P97 = 0x61, - P98 = 0x62, - P99 = 0x63, - P100 = 0x64, - P101 = 0x65, - P102 = 0x66, - P103 = 0x67, - P104 = 0x68, - P105 = 0x69, - P106 = 0x6a, - P107 = 0x6b, - P108 = 0x6c, - P109 = 0x6d, - P110 = 0x6e, - P111 = 0x6f, - P112 = 0x70, - P113 = 0x71, - P114 = 0x72, - P115 = 0x73, - P116 = 0x74, - P117 = 0x75, - P118 = 0x76, - P119 = 0x77, - P120 = 0x78, - P121 = 0x79, - P122 = 0x7a, - P123 = 0x7b, - P124 = 0x7c, - P125 = 0x7d, - P126 = 0x7e, - P127 = 0x7f, - P128 = 0x80, - P129 = 0x81, - P130 = 0x82, - P131 = 0x83, - P132 = 0x84, - P133 = 0x85, - P134 = 0x86, - P135 = 0x87, - P136 = 0x88, - P137 = 0x89, - P138 = 0x8a, - P139 = 0x8b, - P140 = 0x8c, - P141 = 0x8d, - P142 = 0x8e, - P143 = 0x8f, - P144 = 0x90, - P145 = 0x91, - P146 = 0x92, - P147 = 0x93, - P148 = 0x94, - P149 = 0x95, - P150 = 0x96, - P151 = 0x97, - P152 = 0x98, - P153 = 0x99, - P154 = 0x9a, - P155 = 0x9b, - P156 = 0x9c, - P157 = 0x9d, - P158 = 0x9e, - P159 = 0x9f, - P160 = 0xa0, - P161 = 0xa1, - P162 = 0xa2, - P163 = 0xa3, - P164 = 0xa4, - P165 = 0xa5, - P166 = 0xa6, - P167 = 0xa7, - P168 = 0xa8, - P169 = 0xa9, - P170 = 0xaa, - P171 = 0xab, - P172 = 0xac, - P173 = 0xad, - P174 = 0xae, - P175 = 0xaf, - P176 = 0xb0, - P177 = 0xb1, - P178 = 0xb2, - P179 = 0xb3, - P180 = 0xb4, - P181 = 0xb5, - P182 = 0xb6, - P183 = 0xb7, - P184 = 0xb8, - P185 = 0xb9, - P186 = 0xba, - P187 = 0xbb, - P188 = 0xbc, - P189 = 0xbd, - P190 = 0xbe, - P191 = 0xbf, - P192 = 0xc0, - P193 = 0xc1, - P194 = 0xc2, - P195 = 0xc3, - P196 = 0xc4, - P197 = 0xc5, - P198 = 0xc6, - P199 = 0xc7, - P200 = 0xc8, - P201 = 0xc9, - P202 = 0xca, - P203 = 0xcb, - P204 = 0xcc, - P205 = 0xcd, - P206 = 0xce, - P207 = 0xcf, - P208 = 0xd0, - P209 = 0xd1, - P210 = 0xd2, - P211 = 0xd3, - P212 = 0xd4, - P213 = 0xd5, - P214 = 0xd6, - P215 = 0xd7, - P216 = 0xd8, - P217 = 0xd9, - P218 = 0xda, - P219 = 0xdb, - P220 = 0xdc, - P221 = 0xdd, - P222 = 0xde, - P223 = 0xdf, - P224 = 0xe0, - P225 = 0xe1, - P226 = 0xe2, - P227 = 0xe3, - P228 = 0xe4, - P229 = 0xe5, - P230 = 0xe6, - P231 = 0xe7, - P232 = 0xe8, - P233 = 0xe9, - P234 = 0xea, - P235 = 0xeb, - P236 = 0xec, - P237 = 0xed, - P238 = 0xee, - P239 = 0xef, - P240 = 0xf0, - P241 = 0xf1, - P242 = 0xf2, - P243 = 0xf3, - P244 = 0xf4, - P245 = 0xf5, - P246 = 0xf6, - P247 = 0xf7, - P248 = 0xf8, - P249 = 0xf9, - P250 = 0xfa, - P251 = 0xfb, - P252 = 0xfc, - P253 = 0xfd, - P254 = 0xfe, - P255 = 0xff, -)); diff --git a/embassy-extras/src/lib.rs b/embassy-extras/src/lib.rs deleted file mode 100644 index 7036986ef..000000000 --- a/embassy-extras/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![no_std] - -// This mod MUST go first, so that the others see its macros. -pub(crate) mod fmt; - -pub mod interrupt; -mod macros; -pub mod peripheral; -pub mod peripheral_shared; -pub mod ring_buffer; -pub mod usb; - -/// Low power blocking wait loop using WFE/SEV. -pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) { - while !condition() { - // WFE might "eat" an event that would have otherwise woken the executor. - cortex_m::asm::wfe(); - } - // Retrigger an event to be transparent to the executor. - cortex_m::asm::sev(); -} diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs deleted file mode 100644 index 771db40f6..000000000 --- a/embassy-extras/src/macros.rs +++ /dev/null @@ -1,130 +0,0 @@ -#[macro_export] -macro_rules! peripherals { - ($($(#[$cfg:meta])? $name:ident),*$(,)?) => { - pub mod peripherals { - $( - $(#[$cfg])? - #[allow(non_camel_case_types)] - pub struct $name { _private: () } - - $(#[$cfg])? - impl embassy::util::Steal for $name { - #[inline] - unsafe fn steal() -> Self { - Self{ _private: ()} - } - } - - $(#[$cfg])? - unsafe impl embassy::util::Unborrow for $name { - type Target = $name; - #[inline] - unsafe fn unborrow(self) -> $name { - self - } - } - - )* - } - - #[allow(non_snake_case)] - pub struct Peripherals { - $( - $(#[$cfg])? - pub $name: peripherals::$name, - )* - } - - impl Peripherals { - ///Returns all the peripherals *once* - #[inline] - pub(crate) fn take() -> Self { - - #[no_mangle] - static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; - - critical_section::with(|_| unsafe { - if _EMBASSY_DEVICE_PERIPHERALS { - panic!("init called more than once!") - } - _EMBASSY_DEVICE_PERIPHERALS = true; - ::steal() - }) - } - } - - impl embassy::util::Steal for Peripherals { - #[inline] - unsafe fn steal() -> Self { - Self { - $( - $(#[$cfg])? - $name: ::steal(), - )* - } - } - } - - }; -} - -#[macro_export] -macro_rules! unborrow { - ($($name:ident),*) => { - $( - let mut $name = unsafe { $name.unborrow() }; - )* - } -} - -#[macro_export] -macro_rules! unsafe_impl_unborrow { - ($type:ident) => { - unsafe impl ::embassy::util::Unborrow for $type { - type Target = $type; - #[inline] - unsafe fn unborrow(self) -> Self::Target { - self - } - } - }; -} - -#[macro_export] -macro_rules! std_peripherals { - ($($(#[$cfg:meta])? $name:ident),*$(,)?) => { - #[doc = r"All the peripherals"] - #[allow(non_snake_case)] - pub struct Peripherals { - $( - $(#[$cfg])? - pub $name: pac::$name, - )+ - } - - static mut GLOBAL_CLOCKS: Option = None; - - impl Peripherals { - pub fn take() -> Option<(Peripherals, Clocks)> { - match unsafe {GLOBAL_CLOCKS.take()} { - Some(clocks) => { - let dp = unsafe { pac::Peripherals::steal() }; - let peripherals = Peripherals { - $( - $(#[$cfg])? - $name: dp.$name, - )+ - }; - - Some((peripherals, clocks)) - }, - None => None, - } - } - - pub unsafe fn set_peripherals(clocks: Clocks) { - GLOBAL_CLOCKS.replace(clocks); - } - } - }; -} diff --git a/embassy-extras/src/peripheral.rs b/embassy-extras/src/peripheral.rs deleted file mode 100644 index 92512a0f6..000000000 --- a/embassy-extras/src/peripheral.rs +++ /dev/null @@ -1,160 +0,0 @@ -use core::cell::UnsafeCell; -use core::marker::{PhantomData, PhantomPinned}; -use core::pin::Pin; - -use cortex_m::peripheral::scb::VectActive; -use cortex_m::peripheral::{NVIC, SCB}; -use embassy::interrupt::{Interrupt, InterruptExt}; - -/// A type which can be used as state with `PeripheralMutex`. -/// -/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, -/// and `&mut T` is only `Send` where `T: Send`. -/// -/// It also requires `'static` to be used safely with `PeripheralMutex::register_interrupt`, -/// because although `Pin` guarantees that the memory of the state won't be invalidated, -/// it doesn't guarantee that the lifetime will last. -pub trait PeripheralState: Send { - type Interrupt: Interrupt; - fn on_interrupt(&mut self); -} - -pub struct PeripheralMutex { - state: UnsafeCell, - - irq_setup_done: bool, - irq: S::Interrupt, - - _not_send: PhantomData<*mut ()>, - _pinned: PhantomPinned, -} - -/// Whether `irq` can be preempted by the current interrupt. -pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { - match SCB::vect_active() { - // Thread mode can't preempt anything. - VectActive::ThreadMode => false, - // Exceptions don't always preempt interrupts, - // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway. - VectActive::Exception(_) => true, - VectActive::Interrupt { irqn } => { - #[derive(Clone, Copy)] - struct NrWrap(u16); - unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { - fn number(self) -> u16 { - self.0 - } - } - NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into() - } - } -} - -impl PeripheralMutex { - /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. - /// - /// This requires this `PeripheralMutex`'s `PeripheralState` to live for `'static`, - /// because `Pin` only guarantees that it's memory won't be repurposed, - /// not that it's lifetime will last. - /// - /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. - /// - /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; - /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. - pub fn register_interrupt(self: Pin<&mut Self>) { - // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. - unsafe { self.register_interrupt_unchecked() } - } -} - -impl PeripheralMutex { - /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`. - pub fn new(state: S, irq: S::Interrupt) -> Self { - if can_be_preempted(&irq) { - panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"); - } - - Self { - irq, - irq_setup_done: false, - - state: UnsafeCell::new(state), - _not_send: PhantomData, - _pinned: PhantomPinned, - } - } - - /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. - /// - /// # Safety - /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler - /// must not end without `Drop` being called on this `PeripheralMutex`. - /// - /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`, - /// or making sure that nothing like `mem::forget` is used on the `PeripheralMutex`. - - // TODO: this name isn't the best. - pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) { - let this = self.get_unchecked_mut(); - if this.irq_setup_done { - return; - } - - this.irq.disable(); - this.irq.set_handler(|p| { - // Safety: it's OK to get a &mut to the state, since - // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`. - // Interrupts' priorities can only be changed with raw embassy `Interrupts`, - // which can't safely store a `PeripheralMutex` across invocations. - // - We can't have preempted a with() call because the irq is disabled during it. - let state = unsafe { &mut *(p as *mut S) }; - state.on_interrupt(); - }); - this.irq - .set_handler_context((&mut this.state) as *mut _ as *mut ()); - this.irq.enable(); - - this.irq_setup_done = true; - } - - pub fn with(self: Pin<&mut Self>, f: impl FnOnce(&mut S) -> R) -> R { - let this = unsafe { self.get_unchecked_mut() }; - - this.irq.disable(); - - // Safety: it's OK to get a &mut to the state, since the irq is disabled. - let state = unsafe { &mut *this.state.get() }; - let r = f(state); - - this.irq.enable(); - - r - } - - /// Returns whether the wrapped interrupt is currently in a pending state. - pub fn is_pending(&self) -> bool { - self.irq.is_pending() - } - - /// Forces the wrapped interrupt into a pending state. - pub fn pend(&self) { - self.irq.pend() - } - - /// Forces the wrapped interrupt out of a pending state. - pub fn unpend(&self) { - self.irq.unpend() - } - - /// Gets the priority of the wrapped interrupt. - pub fn priority(&self) -> ::Priority { - self.irq.get_priority() - } -} - -impl Drop for PeripheralMutex { - fn drop(&mut self) { - self.irq.disable(); - self.irq.remove_handler(); - } -} diff --git a/embassy-extras/src/peripheral_shared.rs b/embassy-extras/src/peripheral_shared.rs deleted file mode 100644 index 71d746341..000000000 --- a/embassy-extras/src/peripheral_shared.rs +++ /dev/null @@ -1,122 +0,0 @@ -use core::marker::{PhantomData, PhantomPinned}; -use core::pin::Pin; - -use embassy::interrupt::{Interrupt, InterruptExt}; - -use crate::peripheral::can_be_preempted; - -/// A type which can be used as state with `Peripheral`. -/// -/// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt. -/// -/// It also requires `'static` to be used safely with `Peripheral::register_interrupt`, -/// because although `Pin` guarantees that the memory of the state won't be invalidated, -/// it doesn't guarantee that the lifetime will last. -pub trait PeripheralState: Sync { - type Interrupt: Interrupt; - fn on_interrupt(&self); -} - -pub struct Peripheral { - state: S, - - irq_setup_done: bool, - irq: S::Interrupt, - - _not_send: PhantomData<*mut ()>, - _pinned: PhantomPinned, -} - -impl Peripheral { - /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. - /// - /// This requires this `Peripheral`'s `PeripheralState` to live for `'static`, - /// because `Pin` only guarantees that it's memory won't be repurposed, - /// not that it's lifetime will last. - /// - /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. - /// - /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; - /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. - pub fn register_interrupt(self: Pin<&mut Self>) { - // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. - unsafe { self.register_interrupt_unchecked() } - } -} - -impl Peripheral { - pub fn new(irq: S::Interrupt, state: S) -> Self { - if can_be_preempted(&irq) { - panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps"); - } - - Self { - irq, - irq_setup_done: false, - - state, - _not_send: PhantomData, - _pinned: PhantomPinned, - } - } - - /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. - /// - /// # Safety - /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler - /// must not end without `Drop` being called on this `Peripheral`. - /// - /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`, - /// or making sure that nothing like `mem::forget` is used on the `Peripheral`. - pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) { - let this = self.get_unchecked_mut(); - if this.irq_setup_done { - return; - } - - this.irq.disable(); - this.irq.set_handler(|p| { - // The state can't have been dropped, otherwise the interrupt would have been disabled. - // We checked in `new` that the thread owning the `Peripheral` can't preempt the interrupt, - // so someone can't have preempted us before this point and dropped the `Peripheral`. - let state = unsafe { &*(p as *const S) }; - state.on_interrupt(); - }); - this.irq - .set_handler_context((&this.state) as *const _ as *mut ()); - this.irq.enable(); - - this.irq_setup_done = true; - } - - pub fn state(self: Pin<&mut Self>) -> &S { - &self.into_ref().get_ref().state - } - - /// Returns whether the wrapped interrupt is currently in a pending state. - pub fn is_pending(&self) -> bool { - self.irq.is_pending() - } - - /// Forces the wrapped interrupt into a pending state. - pub fn pend(&self) { - self.irq.pend() - } - - /// Forces the wrapped interrupt out of a pending state. - pub fn unpend(&self) { - self.irq.unpend() - } - - /// Gets the priority of the wrapped interrupt. - pub fn priority(&self) -> ::Priority { - self.irq.get_priority() - } -} - -impl Drop for Peripheral { - fn drop(&mut self) { - self.irq.disable(); - self.irq.remove_handler(); - } -} diff --git a/embassy-extras/src/ring_buffer.rs b/embassy-extras/src/ring_buffer.rs deleted file mode 100644 index 18795787f..000000000 --- a/embassy-extras/src/ring_buffer.rs +++ /dev/null @@ -1,84 +0,0 @@ -pub struct RingBuffer<'a> { - buf: &'a mut [u8], - start: usize, - end: usize, - empty: bool, -} - -impl<'a> RingBuffer<'a> { - pub fn new(buf: &'a mut [u8]) -> Self { - Self { - buf, - start: 0, - end: 0, - empty: true, - } - } - - pub fn push_buf(&mut self) -> &mut [u8] { - if self.start == self.end && !self.empty { - trace!(" ringbuf: push_buf empty"); - return &mut self.buf[..0]; - } - - let n = if self.start <= self.end { - self.buf.len() - self.end - } else { - self.start - self.end - }; - - trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); - &mut self.buf[self.end..self.end + n] - } - - pub fn push(&mut self, n: usize) { - trace!(" ringbuf: push {:?}", n); - if n == 0 { - return; - } - - self.end = self.wrap(self.end + n); - self.empty = false; - } - - pub fn pop_buf(&mut self) -> &mut [u8] { - if self.empty { - trace!(" ringbuf: pop_buf empty"); - return &mut self.buf[..0]; - } - - let n = if self.end <= self.start { - self.buf.len() - self.start - } else { - self.end - self.start - }; - - trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); - &mut self.buf[self.start..self.start + n] - } - - pub fn pop(&mut self, n: usize) { - trace!(" ringbuf: pop {:?}", n); - if n == 0 { - return; - } - - self.start = self.wrap(self.start + n); - self.empty = self.start == self.end; - } - - pub fn clear(&mut self) { - self.start = 0; - self.end = 0; - self.empty = true; - } - - fn wrap(&self, n: usize) -> usize { - assert!(n <= self.buf.len()); - if n == self.buf.len() { - 0 - } else { - n - } - } -} diff --git a/embassy-extras/src/usb/cdc_acm.rs b/embassy-extras/src/usb/cdc_acm.rs deleted file mode 100644 index 5a85b3846..000000000 --- a/embassy-extras/src/usb/cdc_acm.rs +++ /dev/null @@ -1,338 +0,0 @@ -// Copied from https://github.com/mvirkkunen/usbd-serial -#![allow(dead_code)] - -use core::convert::TryInto; -use core::mem; -use usb_device::class_prelude::*; -use usb_device::Result; - -/// This should be used as `device_class` when building the `UsbDevice`. -pub const USB_CLASS_CDC: u8 = 0x02; - -const USB_CLASS_CDC_DATA: u8 = 0x0a; -const CDC_SUBCLASS_ACM: u8 = 0x02; -const CDC_PROTOCOL_NONE: u8 = 0x00; - -const CS_INTERFACE: u8 = 0x24; -const CDC_TYPE_HEADER: u8 = 0x00; -const CDC_TYPE_CALL_MANAGEMENT: u8 = 0x01; -const CDC_TYPE_ACM: u8 = 0x02; -const CDC_TYPE_UNION: u8 = 0x06; - -const REQ_SEND_ENCAPSULATED_COMMAND: u8 = 0x00; -#[allow(unused)] -const REQ_GET_ENCAPSULATED_COMMAND: u8 = 0x01; -const REQ_SET_LINE_CODING: u8 = 0x20; -const REQ_GET_LINE_CODING: u8 = 0x21; -const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22; - -/// Packet level implementation of a CDC-ACM serial port. -/// -/// This class can be used directly and it has the least overhead due to directly reading and -/// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial -/// port. The following constraints must be followed if you use this class directly: -/// -/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes, and the -/// method will return a `WouldBlock` error if there is no packet to be read. -/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes, and the -/// method will return a `WouldBlock` error if the previous packet has not been sent yet. -/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the -/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) -/// can be sent if there is no other data to send. This is because USB bulk transactions must be -/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. -pub struct CdcAcmClass<'a, B: UsbBus> { - comm_if: InterfaceNumber, - comm_ep: EndpointIn<'a, B>, - data_if: InterfaceNumber, - read_ep: EndpointOut<'a, B>, - write_ep: EndpointIn<'a, B>, - line_coding: LineCoding, - dtr: bool, - rts: bool, -} - -impl CdcAcmClass<'_, B> { - /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For - /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. - pub fn new(alloc: &UsbBusAllocator, max_packet_size: u16) -> CdcAcmClass<'_, B> { - CdcAcmClass { - comm_if: alloc.interface(), - comm_ep: alloc.interrupt(8, 255), - data_if: alloc.interface(), - read_ep: alloc.bulk(max_packet_size), - write_ep: alloc.bulk(max_packet_size), - line_coding: LineCoding { - stop_bits: StopBits::One, - data_bits: 8, - parity_type: ParityType::None, - data_rate: 8_000, - }, - dtr: false, - rts: false, - } - } - - /// Gets the maximum packet size in bytes. - pub fn max_packet_size(&self) -> u16 { - // The size is the same for both endpoints. - self.read_ep.max_packet_size() - } - - /// Gets the current line coding. The line coding contains information that's mainly relevant - /// for USB to UART serial port emulators, and can be ignored if not relevant. - pub fn line_coding(&self) -> &LineCoding { - &self.line_coding - } - - /// Gets the DTR (data terminal ready) state - pub fn dtr(&self) -> bool { - self.dtr - } - - /// Gets the RTS (request to send) state - pub fn rts(&self) -> bool { - self.rts - } - - /// Writes a single packet into the IN endpoint. - pub fn write_packet(&mut self, data: &[u8]) -> Result { - self.write_ep.write(data) - } - - /// Reads a single packet from the OUT endpoint. - pub fn read_packet(&mut self, data: &mut [u8]) -> Result { - self.read_ep.read(data) - } - - /// Gets the address of the IN endpoint. - pub fn write_ep_address(&self) -> EndpointAddress { - self.write_ep.address() - } - - /// Gets the address of the OUT endpoint. - pub fn read_ep_address(&self) -> EndpointAddress { - self.read_ep.address() - } -} - -impl UsbClass for CdcAcmClass<'_, B> { - fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { - writer.iad( - self.comm_if, - 2, - USB_CLASS_CDC, - CDC_SUBCLASS_ACM, - CDC_PROTOCOL_NONE, - )?; - - writer.interface( - self.comm_if, - USB_CLASS_CDC, - CDC_SUBCLASS_ACM, - CDC_PROTOCOL_NONE, - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_HEADER, // bDescriptorSubtype - 0x10, - 0x01, // bcdCDC (1.10) - ], - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_ACM, // bDescriptorSubtype - 0x00, // bmCapabilities - ], - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_UNION, // bDescriptorSubtype - self.comm_if.into(), // bControlInterface - self.data_if.into(), // bSubordinateInterface - ], - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype - 0x00, // bmCapabilities - self.data_if.into(), // bDataInterface - ], - )?; - - writer.endpoint(&self.comm_ep)?; - - writer.interface(self.data_if, USB_CLASS_CDC_DATA, 0x00, 0x00)?; - - writer.endpoint(&self.write_ep)?; - writer.endpoint(&self.read_ep)?; - - Ok(()) - } - - fn reset(&mut self) { - self.line_coding = LineCoding::default(); - self.dtr = false; - self.rts = false; - } - - fn control_in(&mut self, xfer: ControlIn) { - let req = xfer.request(); - - if !(req.request_type == control::RequestType::Class - && req.recipient == control::Recipient::Interface - && req.index == u8::from(self.comm_if) as u16) - { - return; - } - - match req.request { - // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. - REQ_GET_LINE_CODING if req.length == 7 => { - xfer.accept(|data| { - data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes()); - data[4] = self.line_coding.stop_bits as u8; - data[5] = self.line_coding.parity_type as u8; - data[6] = self.line_coding.data_bits; - - Ok(7) - }) - .ok(); - } - _ => { - xfer.reject().ok(); - } - } - } - - fn control_out(&mut self, xfer: ControlOut) { - let req = xfer.request(); - - if !(req.request_type == control::RequestType::Class - && req.recipient == control::Recipient::Interface - && req.index == u8::from(self.comm_if) as u16) - { - return; - } - - match req.request { - REQ_SEND_ENCAPSULATED_COMMAND => { - // We don't actually support encapsulated commands but pretend we do for standards - // compatibility. - xfer.accept().ok(); - } - REQ_SET_LINE_CODING if xfer.data().len() >= 7 => { - self.line_coding.data_rate = - u32::from_le_bytes(xfer.data()[0..4].try_into().unwrap()); - self.line_coding.stop_bits = xfer.data()[4].into(); - self.line_coding.parity_type = xfer.data()[5].into(); - self.line_coding.data_bits = xfer.data()[6]; - - xfer.accept().ok(); - } - REQ_SET_CONTROL_LINE_STATE => { - self.dtr = (req.value & 0x0001) != 0; - self.rts = (req.value & 0x0002) != 0; - - xfer.accept().ok(); - } - _ => { - xfer.reject().ok(); - } - }; - } -} - -/// Number of stop bits for LineCoding -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum StopBits { - /// 1 stop bit - One = 0, - - /// 1.5 stop bits - OnePointFive = 1, - - /// 2 stop bits - Two = 2, -} - -impl From for StopBits { - fn from(value: u8) -> Self { - if value <= 2 { - unsafe { mem::transmute(value) } - } else { - StopBits::One - } - } -} - -/// Parity for LineCoding -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum ParityType { - None = 0, - Odd = 1, - Event = 2, - Mark = 3, - Space = 4, -} - -impl From for ParityType { - fn from(value: u8) -> Self { - if value <= 4 { - unsafe { mem::transmute(value) } - } else { - ParityType::None - } - } -} - -/// Line coding parameters -/// -/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can -/// be ignored if you don't plan to interface with a physical UART. -pub struct LineCoding { - stop_bits: StopBits, - data_bits: u8, - parity_type: ParityType, - data_rate: u32, -} - -impl LineCoding { - /// Gets the number of stop bits for UART communication. - pub fn stop_bits(&self) -> StopBits { - self.stop_bits - } - - /// Gets the number of data bits for UART communication. - pub fn data_bits(&self) -> u8 { - self.data_bits - } - - /// Gets the parity type for UART communication. - pub fn parity_type(&self) -> ParityType { - self.parity_type - } - - /// Gets the data rate in bits per second for UART communication. - pub fn data_rate(&self) -> u32 { - self.data_rate - } -} - -impl Default for LineCoding { - fn default() -> Self { - LineCoding { - stop_bits: StopBits::One, - data_bits: 8, - parity_type: ParityType::None, - data_rate: 8_000, - } - } -} diff --git a/embassy-extras/src/usb/mod.rs b/embassy-extras/src/usb/mod.rs deleted file mode 100644 index 1fb501d7f..000000000 --- a/embassy-extras/src/usb/mod.rs +++ /dev/null @@ -1,258 +0,0 @@ -use core::cell::RefCell; -use core::marker::PhantomData; -use core::pin::Pin; - -use usb_device::bus::UsbBus; -use usb_device::class::UsbClass; -use usb_device::device::UsbDevice; - -mod cdc_acm; -pub mod usb_serial; - -use crate::peripheral::{PeripheralMutex, PeripheralState}; -use embassy::interrupt::Interrupt; -use usb_serial::{ReadInterface, UsbSerial, WriteInterface}; - -/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction. -pub unsafe trait USBInterrupt: Interrupt + Send {} - -pub(crate) struct State<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - device: UsbDevice<'bus, B>, - pub(crate) classes: T, - _interrupt: PhantomData, -} - -pub struct Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - // Don't you dare moving out `PeripheralMutex` - inner: RefCell>>, -} - -impl<'bus, B, T, I> Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - pub fn new>(device: UsbDevice<'bus, B>, class_set: S, irq: I) -> Self { - let state = State { - device, - classes: class_set.into_class_set(), - _interrupt: PhantomData, - }; - let mutex = PeripheralMutex::new(state, irq); - Self { - inner: RefCell::new(mutex), - } - } - - /// # Safety - /// The `UsbDevice` passed to `Self::new` must not be dropped without calling `Drop` on this `Usb` first. - pub unsafe fn start(self: Pin<&mut Self>) { - let this = self.get_unchecked_mut(); - let mut mutex = this.inner.borrow_mut(); - let mutex = Pin::new_unchecked(&mut *mutex); - - // Use inner to register the irq - // SAFETY: the safety contract of this function makes sure the `UsbDevice` won't be invalidated - // without the `PeripheralMutex` being dropped. - mutex.register_interrupt_unchecked(); - } -} - -impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet + SerialState<'bus, 'c, B, Index0>, - I: USBInterrupt, -{ - /// Take a serial class that was passed as the first class in a tuple - pub fn take_serial_0<'a>( - self: Pin<&'a Self>, - ) -> ( - ReadInterface<'a, 'bus, 'c, Index0, B, T, I>, - WriteInterface<'a, 'bus, 'c, Index0, B, T, I>, - ) { - let this = self.get_ref(); - - let r = ReadInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - - let w = WriteInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - (r, w) - } -} - -impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet + SerialState<'bus, 'c, B, Index1>, - I: USBInterrupt, -{ - /// Take a serial class that was passed as the second class in a tuple - pub fn take_serial_1<'a>( - self: Pin<&'a Self>, - ) -> ( - ReadInterface<'a, 'bus, 'c, Index1, B, T, I>, - WriteInterface<'a, 'bus, 'c, Index1, B, T, I>, - ) { - let this = self.get_ref(); - - let r = ReadInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - - let w = WriteInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - (r, w) - } -} - -impl<'bus, B, T, I> PeripheralState for State<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - type Interrupt = I; - fn on_interrupt(&mut self) { - self.classes.poll_all(&mut self.device); - } -} - -pub trait ClassSet: Send { - fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool; -} - -pub trait IntoClassSet> { - fn into_class_set(self) -> C; -} - -pub struct ClassSet1 -where - B: UsbBus, - C1: UsbClass, -{ - class: C1, - _bus: PhantomData, -} - -pub struct ClassSet2 -where - B: UsbBus, - C1: UsbClass, - C2: UsbClass, -{ - class1: C1, - class2: C2, - _bus: PhantomData, -} - -/// The first class into a [`ClassSet`] -pub struct Index0; - -/// The second class into a [`ClassSet`] -pub struct Index1; - -impl ClassSet for ClassSet1 -where - B: UsbBus + Send, - C1: UsbClass + Send, -{ - fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { - device.poll(&mut [&mut self.class]) - } -} - -impl ClassSet for ClassSet2 -where - B: UsbBus + Send, - C1: UsbClass + Send, - C2: UsbClass + Send, -{ - fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { - device.poll(&mut [&mut self.class1, &mut self.class2]) - } -} - -impl IntoClassSet> for C1 -where - B: UsbBus + Send, - C1: UsbClass + Send, -{ - fn into_class_set(self) -> ClassSet1 { - ClassSet1 { - class: self, - _bus: PhantomData, - } - } -} - -impl IntoClassSet> for (C1, C2) -where - B: UsbBus + Send, - C1: UsbClass + Send, - C2: UsbClass + Send, -{ - fn into_class_set(self) -> ClassSet2 { - ClassSet2 { - class1: self.0, - class2: self.1, - _bus: PhantomData, - } - } -} - -/// Trait for a USB State that has a serial class inside -pub trait SerialState<'bus, 'a, B: UsbBus, I> { - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B>; -} - -impl<'bus, 'a, B: UsbBus> SerialState<'bus, 'a, B, Index0> - for ClassSet1> -{ - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { - &mut self.class - } -} - -impl<'bus, 'a, B, C2> SerialState<'bus, 'a, B, Index0> for ClassSet2, C2> -where - B: UsbBus, - C2: UsbClass, -{ - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { - &mut self.class1 - } -} - -impl<'bus, 'a, B, C1> SerialState<'bus, 'a, B, Index1> for ClassSet2> -where - B: UsbBus, - C1: UsbClass, -{ - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { - &mut self.class2 - } -} diff --git a/embassy-extras/src/usb/usb_serial.rs b/embassy-extras/src/usb/usb_serial.rs deleted file mode 100644 index a229b2000..000000000 --- a/embassy-extras/src/usb/usb_serial.rs +++ /dev/null @@ -1,310 +0,0 @@ -use core::cell::RefCell; -use core::marker::{PhantomData, Unpin}; -use core::pin::Pin; -use core::task::{Context, Poll}; - -use embassy::io::{self, AsyncBufRead, AsyncWrite}; -use embassy::util::WakerRegistration; -use usb_device::bus::UsbBus; -use usb_device::class_prelude::*; -use usb_device::UsbError; - -use super::cdc_acm::CdcAcmClass; -use crate::peripheral::PeripheralMutex; -use crate::ring_buffer::RingBuffer; -use crate::usb::{ClassSet, SerialState, State, USBInterrupt}; - -pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - // Don't you dare moving out `PeripheralMutex` - pub(crate) inner: &'a RefCell>>, - pub(crate) _buf_lifetime: PhantomData<&'c T>, - pub(crate) _index: PhantomData, -} - -/// Write interface for USB CDC_ACM -/// -/// This interface is buffered, meaning that after the write returns the bytes might not be fully -/// on the wire just yet -pub struct WriteInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - // Don't you dare moving out `PeripheralMutex` - pub(crate) inner: &'a RefCell>>, - pub(crate) _buf_lifetime: PhantomData<&'c T>, - pub(crate) _index: PhantomData, -} - -impl<'a, 'bus, 'c, I, B, T, INT> AsyncBufRead for ReadInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - let mutex = unsafe { Pin::new_unchecked(&mut *mutex) }; - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - match serial.poll_fill_buf(cx) { - Poll::Ready(Ok(buf)) => { - let buf: &[u8] = buf; - // NOTE(unsafe) This part of the buffer won't be modified until the user calls - // consume, which will invalidate this ref - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - Poll::Ready(Ok(buf)) - } - Poll::Ready(Err(_)) => Poll::Ready(Err(io::Error::Other)), - Poll::Pending => Poll::Pending, - } - }) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - let mutex = unsafe { Pin::new_unchecked(&mut *mutex) }; - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - serial.consume(amt); - }) - } -} - -impl<'a, 'bus, 'c, I, B, T, INT> AsyncWrite for WriteInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - let mutex = unsafe { Pin::new_unchecked(&mut *mutex) }; - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - serial.poll_write(cx, buf) - }) - } -} - -pub struct UsbSerial<'bus, 'a, B: UsbBus> { - inner: CdcAcmClass<'bus, B>, - read_buf: RingBuffer<'a>, - write_buf: RingBuffer<'a>, - read_waker: WakerRegistration, - write_waker: WakerRegistration, - write_state: WriteState, - read_error: bool, - write_error: bool, -} - -impl<'bus, 'a, B: UsbBus> AsyncBufRead for UsbSerial<'bus, 'a, B> { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - - if this.read_error { - this.read_error = false; - return Poll::Ready(Err(io::Error::Other)); - } - - let buf = this.read_buf.pop_buf(); - if buf.is_empty() { - this.read_waker.register(cx.waker()); - return Poll::Pending; - } - Poll::Ready(Ok(buf)) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.get_mut().read_buf.pop(amt); - } -} - -impl<'bus, 'a, B: UsbBus> AsyncWrite for UsbSerial<'bus, 'a, B> { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.get_mut(); - - if this.write_error { - this.write_error = false; - return Poll::Ready(Err(io::Error::Other)); - } - - let write_buf = this.write_buf.push_buf(); - if write_buf.is_empty() { - this.write_waker.register(cx.waker()); - return Poll::Pending; - } - - let count = write_buf.len().min(buf.len()); - write_buf[..count].copy_from_slice(&buf[..count]); - this.write_buf.push(count); - - this.flush_write(); - Poll::Ready(Ok(count)) - } -} - -/// Keeps track of the type of the last written packet. -enum WriteState { - /// No packets in-flight - Idle, - - /// Short packet currently in-flight - Short, - - /// Full packet current in-flight. A full packet must be followed by a short packet for the host - /// OS to see the transaction. The data is the number of subsequent full packets sent so far. A - /// short packet is forced every SHORT_PACKET_INTERVAL packets so that the OS sees data in a - /// timely manner. - Full(usize), -} - -impl<'bus, 'a, B: UsbBus> UsbSerial<'bus, 'a, B> { - pub fn new( - alloc: &'bus UsbBusAllocator, - read_buf: &'a mut [u8], - write_buf: &'a mut [u8], - ) -> Self { - Self { - inner: CdcAcmClass::new(alloc, 64), - read_buf: RingBuffer::new(read_buf), - write_buf: RingBuffer::new(write_buf), - read_waker: WakerRegistration::new(), - write_waker: WakerRegistration::new(), - write_state: WriteState::Idle, - read_error: false, - write_error: false, - } - } - - fn flush_write(&mut self) { - /// If this many full size packets have been sent in a row, a short packet will be sent so that the - /// host sees the data in a timely manner. - const SHORT_PACKET_INTERVAL: usize = 10; - - let full_size_packets = match self.write_state { - WriteState::Full(c) => c, - _ => 0, - }; - - let ep_size = self.inner.max_packet_size() as usize; - let max_size = if full_size_packets > SHORT_PACKET_INTERVAL { - ep_size - 1 - } else { - ep_size - }; - - let buf = { - let buf = self.write_buf.pop_buf(); - if buf.len() > max_size { - &buf[..max_size] - } else { - buf - } - }; - - if !buf.is_empty() { - let count = match self.inner.write_packet(buf) { - Ok(c) => c, - Err(UsbError::WouldBlock) => 0, - Err(_) => { - self.write_error = true; - return; - } - }; - - if buf.len() == ep_size { - self.write_state = WriteState::Full(full_size_packets + 1); - } else { - self.write_state = WriteState::Short; - } - self.write_buf.pop(count); - } else if full_size_packets > 0 { - if let Err(e) = self.inner.write_packet(&[]) { - if !matches!(e, UsbError::WouldBlock) { - self.write_error = true; - } - return; - } - self.write_state = WriteState::Idle; - } - } -} - -impl UsbClass for UsbSerial<'_, '_, B> -where - B: UsbBus, -{ - fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<(), UsbError> { - self.inner.get_configuration_descriptors(writer) - } - - fn reset(&mut self) { - self.inner.reset(); - self.read_buf.clear(); - self.write_buf.clear(); - self.write_state = WriteState::Idle; - } - - fn endpoint_in_complete(&mut self, addr: EndpointAddress) { - if addr == self.inner.write_ep_address() { - self.write_waker.wake(); - - self.flush_write(); - } - } - - fn endpoint_out(&mut self, addr: EndpointAddress) { - if addr == self.inner.read_ep_address() { - let buf = self.read_buf.push_buf(); - let count = match self.inner.read_packet(buf) { - Ok(c) => c, - Err(UsbError::WouldBlock) => 0, - Err(_) => { - self.read_error = true; - return; - } - }; - - if count > 0 { - self.read_buf.push(count); - self.read_waker.wake(); - } - } - } - - fn control_in(&mut self, xfer: ControlIn) { - self.inner.control_in(xfer); - } - - fn control_out(&mut self, xfer: ControlOut) { - self.inner.control_out(xfer); - } -} diff --git a/embassy-hal-common/Cargo.toml b/embassy-hal-common/Cargo.toml new file mode 100644 index 000000000..4db536de4 --- /dev/null +++ b/embassy-hal-common/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "embassy-hal-common" +version = "0.1.0" +authors = ["Dario Nieuwenhuis "] +edition = "2018" + +[features] +defmt-trace = [ ] +defmt-debug = [ ] +defmt-info = [ ] +defmt-warn = [ ] +defmt-error = [ ] + +[dependencies] +embassy = { version = "0.1.0", path = "../embassy" } + +defmt = { version = "0.2.0", optional = true } +log = { version = "0.4.11", optional = true } +cortex-m = "0.7.1" +usb-device = "0.2.7" diff --git a/embassy-hal-common/src/fmt.rs b/embassy-hal-common/src/fmt.rs new file mode 100644 index 000000000..066970813 --- /dev/null +++ b/embassy-hal-common/src/fmt.rs @@ -0,0 +1,225 @@ +#![macro_use] +#![allow(unused_macros)] + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +macro_rules! unreachable { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::unreachable!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::unreachable!($($x)*); + } + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} diff --git a/embassy-hal-common/src/interrupt.rs b/embassy-hal-common/src/interrupt.rs new file mode 100644 index 000000000..80b2cad5d --- /dev/null +++ b/embassy-hal-common/src/interrupt.rs @@ -0,0 +1,571 @@ +use core::mem; + +macro_rules! prio { + ($name:ident, $mask:expr, ($($k:ident = $v:expr,)*)) => { + #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[repr(u8)] + pub enum $name { + $($k = $v),* + } + + impl From for $name { + fn from(priority: u8) -> Self { + unsafe { mem::transmute(priority & $mask) } + } + } + + impl From<$name> for u8 { + fn from(p: $name) -> Self { + p as u8 + } + } + }; +} + +#[rustfmt::skip] +prio!(Priority0, 0x00, ( + P0 = 0x0, +)); + +#[rustfmt::skip] +prio!(Priority1, 0x80, ( + P0 = 0x0, + P1 = 0x80, +)); + +#[rustfmt::skip] +prio!(Priority2, 0xc0, ( + P0 = 0x0, + P1 = 0x40, + P2 = 0x80, + P3 = 0xc0, +)); + +#[rustfmt::skip] +prio!(Priority3, 0xe0, ( + P0 = 0x0, + P1 = 0x20, + P2 = 0x40, + P3 = 0x60, + P4 = 0x80, + P5 = 0xa0, + P6 = 0xc0, + P7 = 0xe0, +)); + +#[rustfmt::skip] +prio!(Priority4, 0xf0, ( + P0 = 0x0, + P1 = 0x10, + P2 = 0x20, + P3 = 0x30, + P4 = 0x40, + P5 = 0x50, + P6 = 0x60, + P7 = 0x70, + P8 = 0x80, + P9 = 0x90, + P10 = 0xa0, + P11 = 0xb0, + P12 = 0xc0, + P13 = 0xd0, + P14 = 0xe0, + P15 = 0xf0, +)); + +#[rustfmt::skip] +prio!(Priority5, 0xf8, ( + P0 = 0x0, + P1 = 0x8, + P2 = 0x10, + P3 = 0x18, + P4 = 0x20, + P5 = 0x28, + P6 = 0x30, + P7 = 0x38, + P8 = 0x40, + P9 = 0x48, + P10 = 0x50, + P11 = 0x58, + P12 = 0x60, + P13 = 0x68, + P14 = 0x70, + P15 = 0x78, + P16 = 0x80, + P17 = 0x88, + P18 = 0x90, + P19 = 0x98, + P20 = 0xa0, + P21 = 0xa8, + P22 = 0xb0, + P23 = 0xb8, + P24 = 0xc0, + P25 = 0xc8, + P26 = 0xd0, + P27 = 0xd8, + P28 = 0xe0, + P29 = 0xe8, + P30 = 0xf0, + P31 = 0xf8, +)); + +#[rustfmt::skip] +prio!(Priority6, 0xfc, ( + P0 = 0x0, + P1 = 0x4, + P2 = 0x8, + P3 = 0xc, + P4 = 0x10, + P5 = 0x14, + P6 = 0x18, + P7 = 0x1c, + P8 = 0x20, + P9 = 0x24, + P10 = 0x28, + P11 = 0x2c, + P12 = 0x30, + P13 = 0x34, + P14 = 0x38, + P15 = 0x3c, + P16 = 0x40, + P17 = 0x44, + P18 = 0x48, + P19 = 0x4c, + P20 = 0x50, + P21 = 0x54, + P22 = 0x58, + P23 = 0x5c, + P24 = 0x60, + P25 = 0x64, + P26 = 0x68, + P27 = 0x6c, + P28 = 0x70, + P29 = 0x74, + P30 = 0x78, + P31 = 0x7c, + P32 = 0x80, + P33 = 0x84, + P34 = 0x88, + P35 = 0x8c, + P36 = 0x90, + P37 = 0x94, + P38 = 0x98, + P39 = 0x9c, + P40 = 0xa0, + P41 = 0xa4, + P42 = 0xa8, + P43 = 0xac, + P44 = 0xb0, + P45 = 0xb4, + P46 = 0xb8, + P47 = 0xbc, + P48 = 0xc0, + P49 = 0xc4, + P50 = 0xc8, + P51 = 0xcc, + P52 = 0xd0, + P53 = 0xd4, + P54 = 0xd8, + P55 = 0xdc, + P56 = 0xe0, + P57 = 0xe4, + P58 = 0xe8, + P59 = 0xec, + P60 = 0xf0, + P61 = 0xf4, + P62 = 0xf8, + P63 = 0xfc, +)); + +#[rustfmt::skip] +prio!(Priority7, 0xfe, ( + P0 = 0x0, + P1 = 0x2, + P2 = 0x4, + P3 = 0x6, + P4 = 0x8, + P5 = 0xa, + P6 = 0xc, + P7 = 0xe, + P8 = 0x10, + P9 = 0x12, + P10 = 0x14, + P11 = 0x16, + P12 = 0x18, + P13 = 0x1a, + P14 = 0x1c, + P15 = 0x1e, + P16 = 0x20, + P17 = 0x22, + P18 = 0x24, + P19 = 0x26, + P20 = 0x28, + P21 = 0x2a, + P22 = 0x2c, + P23 = 0x2e, + P24 = 0x30, + P25 = 0x32, + P26 = 0x34, + P27 = 0x36, + P28 = 0x38, + P29 = 0x3a, + P30 = 0x3c, + P31 = 0x3e, + P32 = 0x40, + P33 = 0x42, + P34 = 0x44, + P35 = 0x46, + P36 = 0x48, + P37 = 0x4a, + P38 = 0x4c, + P39 = 0x4e, + P40 = 0x50, + P41 = 0x52, + P42 = 0x54, + P43 = 0x56, + P44 = 0x58, + P45 = 0x5a, + P46 = 0x5c, + P47 = 0x5e, + P48 = 0x60, + P49 = 0x62, + P50 = 0x64, + P51 = 0x66, + P52 = 0x68, + P53 = 0x6a, + P54 = 0x6c, + P55 = 0x6e, + P56 = 0x70, + P57 = 0x72, + P58 = 0x74, + P59 = 0x76, + P60 = 0x78, + P61 = 0x7a, + P62 = 0x7c, + P63 = 0x7e, + P64 = 0x80, + P65 = 0x82, + P66 = 0x84, + P67 = 0x86, + P68 = 0x88, + P69 = 0x8a, + P70 = 0x8c, + P71 = 0x8e, + P72 = 0x90, + P73 = 0x92, + P74 = 0x94, + P75 = 0x96, + P76 = 0x98, + P77 = 0x9a, + P78 = 0x9c, + P79 = 0x9e, + P80 = 0xa0, + P81 = 0xa2, + P82 = 0xa4, + P83 = 0xa6, + P84 = 0xa8, + P85 = 0xaa, + P86 = 0xac, + P87 = 0xae, + P88 = 0xb0, + P89 = 0xb2, + P90 = 0xb4, + P91 = 0xb6, + P92 = 0xb8, + P93 = 0xba, + P94 = 0xbc, + P95 = 0xbe, + P96 = 0xc0, + P97 = 0xc2, + P98 = 0xc4, + P99 = 0xc6, + P100 = 0xc8, + P101 = 0xca, + P102 = 0xcc, + P103 = 0xce, + P104 = 0xd0, + P105 = 0xd2, + P106 = 0xd4, + P107 = 0xd6, + P108 = 0xd8, + P109 = 0xda, + P110 = 0xdc, + P111 = 0xde, + P112 = 0xe0, + P113 = 0xe2, + P114 = 0xe4, + P115 = 0xe6, + P116 = 0xe8, + P117 = 0xea, + P118 = 0xec, + P119 = 0xee, + P120 = 0xf0, + P121 = 0xf2, + P122 = 0xf4, + P123 = 0xf6, + P124 = 0xf8, + P125 = 0xfa, + P126 = 0xfc, + P127 = 0xfe, +)); + +#[rustfmt::skip] +prio!(Priority8, 0xff, ( + P0 = 0x0, + P1 = 0x1, + P2 = 0x2, + P3 = 0x3, + P4 = 0x4, + P5 = 0x5, + P6 = 0x6, + P7 = 0x7, + P8 = 0x8, + P9 = 0x9, + P10 = 0xa, + P11 = 0xb, + P12 = 0xc, + P13 = 0xd, + P14 = 0xe, + P15 = 0xf, + P16 = 0x10, + P17 = 0x11, + P18 = 0x12, + P19 = 0x13, + P20 = 0x14, + P21 = 0x15, + P22 = 0x16, + P23 = 0x17, + P24 = 0x18, + P25 = 0x19, + P26 = 0x1a, + P27 = 0x1b, + P28 = 0x1c, + P29 = 0x1d, + P30 = 0x1e, + P31 = 0x1f, + P32 = 0x20, + P33 = 0x21, + P34 = 0x22, + P35 = 0x23, + P36 = 0x24, + P37 = 0x25, + P38 = 0x26, + P39 = 0x27, + P40 = 0x28, + P41 = 0x29, + P42 = 0x2a, + P43 = 0x2b, + P44 = 0x2c, + P45 = 0x2d, + P46 = 0x2e, + P47 = 0x2f, + P48 = 0x30, + P49 = 0x31, + P50 = 0x32, + P51 = 0x33, + P52 = 0x34, + P53 = 0x35, + P54 = 0x36, + P55 = 0x37, + P56 = 0x38, + P57 = 0x39, + P58 = 0x3a, + P59 = 0x3b, + P60 = 0x3c, + P61 = 0x3d, + P62 = 0x3e, + P63 = 0x3f, + P64 = 0x40, + P65 = 0x41, + P66 = 0x42, + P67 = 0x43, + P68 = 0x44, + P69 = 0x45, + P70 = 0x46, + P71 = 0x47, + P72 = 0x48, + P73 = 0x49, + P74 = 0x4a, + P75 = 0x4b, + P76 = 0x4c, + P77 = 0x4d, + P78 = 0x4e, + P79 = 0x4f, + P80 = 0x50, + P81 = 0x51, + P82 = 0x52, + P83 = 0x53, + P84 = 0x54, + P85 = 0x55, + P86 = 0x56, + P87 = 0x57, + P88 = 0x58, + P89 = 0x59, + P90 = 0x5a, + P91 = 0x5b, + P92 = 0x5c, + P93 = 0x5d, + P94 = 0x5e, + P95 = 0x5f, + P96 = 0x60, + P97 = 0x61, + P98 = 0x62, + P99 = 0x63, + P100 = 0x64, + P101 = 0x65, + P102 = 0x66, + P103 = 0x67, + P104 = 0x68, + P105 = 0x69, + P106 = 0x6a, + P107 = 0x6b, + P108 = 0x6c, + P109 = 0x6d, + P110 = 0x6e, + P111 = 0x6f, + P112 = 0x70, + P113 = 0x71, + P114 = 0x72, + P115 = 0x73, + P116 = 0x74, + P117 = 0x75, + P118 = 0x76, + P119 = 0x77, + P120 = 0x78, + P121 = 0x79, + P122 = 0x7a, + P123 = 0x7b, + P124 = 0x7c, + P125 = 0x7d, + P126 = 0x7e, + P127 = 0x7f, + P128 = 0x80, + P129 = 0x81, + P130 = 0x82, + P131 = 0x83, + P132 = 0x84, + P133 = 0x85, + P134 = 0x86, + P135 = 0x87, + P136 = 0x88, + P137 = 0x89, + P138 = 0x8a, + P139 = 0x8b, + P140 = 0x8c, + P141 = 0x8d, + P142 = 0x8e, + P143 = 0x8f, + P144 = 0x90, + P145 = 0x91, + P146 = 0x92, + P147 = 0x93, + P148 = 0x94, + P149 = 0x95, + P150 = 0x96, + P151 = 0x97, + P152 = 0x98, + P153 = 0x99, + P154 = 0x9a, + P155 = 0x9b, + P156 = 0x9c, + P157 = 0x9d, + P158 = 0x9e, + P159 = 0x9f, + P160 = 0xa0, + P161 = 0xa1, + P162 = 0xa2, + P163 = 0xa3, + P164 = 0xa4, + P165 = 0xa5, + P166 = 0xa6, + P167 = 0xa7, + P168 = 0xa8, + P169 = 0xa9, + P170 = 0xaa, + P171 = 0xab, + P172 = 0xac, + P173 = 0xad, + P174 = 0xae, + P175 = 0xaf, + P176 = 0xb0, + P177 = 0xb1, + P178 = 0xb2, + P179 = 0xb3, + P180 = 0xb4, + P181 = 0xb5, + P182 = 0xb6, + P183 = 0xb7, + P184 = 0xb8, + P185 = 0xb9, + P186 = 0xba, + P187 = 0xbb, + P188 = 0xbc, + P189 = 0xbd, + P190 = 0xbe, + P191 = 0xbf, + P192 = 0xc0, + P193 = 0xc1, + P194 = 0xc2, + P195 = 0xc3, + P196 = 0xc4, + P197 = 0xc5, + P198 = 0xc6, + P199 = 0xc7, + P200 = 0xc8, + P201 = 0xc9, + P202 = 0xca, + P203 = 0xcb, + P204 = 0xcc, + P205 = 0xcd, + P206 = 0xce, + P207 = 0xcf, + P208 = 0xd0, + P209 = 0xd1, + P210 = 0xd2, + P211 = 0xd3, + P212 = 0xd4, + P213 = 0xd5, + P214 = 0xd6, + P215 = 0xd7, + P216 = 0xd8, + P217 = 0xd9, + P218 = 0xda, + P219 = 0xdb, + P220 = 0xdc, + P221 = 0xdd, + P222 = 0xde, + P223 = 0xdf, + P224 = 0xe0, + P225 = 0xe1, + P226 = 0xe2, + P227 = 0xe3, + P228 = 0xe4, + P229 = 0xe5, + P230 = 0xe6, + P231 = 0xe7, + P232 = 0xe8, + P233 = 0xe9, + P234 = 0xea, + P235 = 0xeb, + P236 = 0xec, + P237 = 0xed, + P238 = 0xee, + P239 = 0xef, + P240 = 0xf0, + P241 = 0xf1, + P242 = 0xf2, + P243 = 0xf3, + P244 = 0xf4, + P245 = 0xf5, + P246 = 0xf6, + P247 = 0xf7, + P248 = 0xf8, + P249 = 0xf9, + P250 = 0xfa, + P251 = 0xfb, + P252 = 0xfc, + P253 = 0xfd, + P254 = 0xfe, + P255 = 0xff, +)); diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs new file mode 100644 index 000000000..7036986ef --- /dev/null +++ b/embassy-hal-common/src/lib.rs @@ -0,0 +1,21 @@ +#![no_std] + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +pub mod interrupt; +mod macros; +pub mod peripheral; +pub mod peripheral_shared; +pub mod ring_buffer; +pub mod usb; + +/// Low power blocking wait loop using WFE/SEV. +pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) { + while !condition() { + // WFE might "eat" an event that would have otherwise woken the executor. + cortex_m::asm::wfe(); + } + // Retrigger an event to be transparent to the executor. + cortex_m::asm::sev(); +} diff --git a/embassy-hal-common/src/macros.rs b/embassy-hal-common/src/macros.rs new file mode 100644 index 000000000..771db40f6 --- /dev/null +++ b/embassy-hal-common/src/macros.rs @@ -0,0 +1,130 @@ +#[macro_export] +macro_rules! peripherals { + ($($(#[$cfg:meta])? $name:ident),*$(,)?) => { + pub mod peripherals { + $( + $(#[$cfg])? + #[allow(non_camel_case_types)] + pub struct $name { _private: () } + + $(#[$cfg])? + impl embassy::util::Steal for $name { + #[inline] + unsafe fn steal() -> Self { + Self{ _private: ()} + } + } + + $(#[$cfg])? + unsafe impl embassy::util::Unborrow for $name { + type Target = $name; + #[inline] + unsafe fn unborrow(self) -> $name { + self + } + } + + )* + } + + #[allow(non_snake_case)] + pub struct Peripherals { + $( + $(#[$cfg])? + pub $name: peripherals::$name, + )* + } + + impl Peripherals { + ///Returns all the peripherals *once* + #[inline] + pub(crate) fn take() -> Self { + + #[no_mangle] + static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; + + critical_section::with(|_| unsafe { + if _EMBASSY_DEVICE_PERIPHERALS { + panic!("init called more than once!") + } + _EMBASSY_DEVICE_PERIPHERALS = true; + ::steal() + }) + } + } + + impl embassy::util::Steal for Peripherals { + #[inline] + unsafe fn steal() -> Self { + Self { + $( + $(#[$cfg])? + $name: ::steal(), + )* + } + } + } + + }; +} + +#[macro_export] +macro_rules! unborrow { + ($($name:ident),*) => { + $( + let mut $name = unsafe { $name.unborrow() }; + )* + } +} + +#[macro_export] +macro_rules! unsafe_impl_unborrow { + ($type:ident) => { + unsafe impl ::embassy::util::Unborrow for $type { + type Target = $type; + #[inline] + unsafe fn unborrow(self) -> Self::Target { + self + } + } + }; +} + +#[macro_export] +macro_rules! std_peripherals { + ($($(#[$cfg:meta])? $name:ident),*$(,)?) => { + #[doc = r"All the peripherals"] + #[allow(non_snake_case)] + pub struct Peripherals { + $( + $(#[$cfg])? + pub $name: pac::$name, + )+ + } + + static mut GLOBAL_CLOCKS: Option = None; + + impl Peripherals { + pub fn take() -> Option<(Peripherals, Clocks)> { + match unsafe {GLOBAL_CLOCKS.take()} { + Some(clocks) => { + let dp = unsafe { pac::Peripherals::steal() }; + let peripherals = Peripherals { + $( + $(#[$cfg])? + $name: dp.$name, + )+ + }; + + Some((peripherals, clocks)) + }, + None => None, + } + } + + pub unsafe fn set_peripherals(clocks: Clocks) { + GLOBAL_CLOCKS.replace(clocks); + } + } + }; +} diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs new file mode 100644 index 000000000..92512a0f6 --- /dev/null +++ b/embassy-hal-common/src/peripheral.rs @@ -0,0 +1,160 @@ +use core::cell::UnsafeCell; +use core::marker::{PhantomData, PhantomPinned}; +use core::pin::Pin; + +use cortex_m::peripheral::scb::VectActive; +use cortex_m::peripheral::{NVIC, SCB}; +use embassy::interrupt::{Interrupt, InterruptExt}; + +/// A type which can be used as state with `PeripheralMutex`. +/// +/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, +/// and `&mut T` is only `Send` where `T: Send`. +/// +/// It also requires `'static` to be used safely with `PeripheralMutex::register_interrupt`, +/// because although `Pin` guarantees that the memory of the state won't be invalidated, +/// it doesn't guarantee that the lifetime will last. +pub trait PeripheralState: Send { + type Interrupt: Interrupt; + fn on_interrupt(&mut self); +} + +pub struct PeripheralMutex { + state: UnsafeCell, + + irq_setup_done: bool, + irq: S::Interrupt, + + _not_send: PhantomData<*mut ()>, + _pinned: PhantomPinned, +} + +/// Whether `irq` can be preempted by the current interrupt. +pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { + match SCB::vect_active() { + // Thread mode can't preempt anything. + VectActive::ThreadMode => false, + // Exceptions don't always preempt interrupts, + // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway. + VectActive::Exception(_) => true, + VectActive::Interrupt { irqn } => { + #[derive(Clone, Copy)] + struct NrWrap(u16); + unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { + fn number(self) -> u16 { + self.0 + } + } + NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into() + } + } +} + +impl PeripheralMutex { + /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. + /// + /// This requires this `PeripheralMutex`'s `PeripheralState` to live for `'static`, + /// because `Pin` only guarantees that it's memory won't be repurposed, + /// not that it's lifetime will last. + /// + /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. + /// + /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; + /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. + pub fn register_interrupt(self: Pin<&mut Self>) { + // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. + unsafe { self.register_interrupt_unchecked() } + } +} + +impl PeripheralMutex { + /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`. + pub fn new(state: S, irq: S::Interrupt) -> Self { + if can_be_preempted(&irq) { + panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"); + } + + Self { + irq, + irq_setup_done: false, + + state: UnsafeCell::new(state), + _not_send: PhantomData, + _pinned: PhantomPinned, + } + } + + /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. + /// + /// # Safety + /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler + /// must not end without `Drop` being called on this `PeripheralMutex`. + /// + /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`, + /// or making sure that nothing like `mem::forget` is used on the `PeripheralMutex`. + + // TODO: this name isn't the best. + pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) { + let this = self.get_unchecked_mut(); + if this.irq_setup_done { + return; + } + + this.irq.disable(); + this.irq.set_handler(|p| { + // Safety: it's OK to get a &mut to the state, since + // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`. + // Interrupts' priorities can only be changed with raw embassy `Interrupts`, + // which can't safely store a `PeripheralMutex` across invocations. + // - We can't have preempted a with() call because the irq is disabled during it. + let state = unsafe { &mut *(p as *mut S) }; + state.on_interrupt(); + }); + this.irq + .set_handler_context((&mut this.state) as *mut _ as *mut ()); + this.irq.enable(); + + this.irq_setup_done = true; + } + + pub fn with(self: Pin<&mut Self>, f: impl FnOnce(&mut S) -> R) -> R { + let this = unsafe { self.get_unchecked_mut() }; + + this.irq.disable(); + + // Safety: it's OK to get a &mut to the state, since the irq is disabled. + let state = unsafe { &mut *this.state.get() }; + let r = f(state); + + this.irq.enable(); + + r + } + + /// Returns whether the wrapped interrupt is currently in a pending state. + pub fn is_pending(&self) -> bool { + self.irq.is_pending() + } + + /// Forces the wrapped interrupt into a pending state. + pub fn pend(&self) { + self.irq.pend() + } + + /// Forces the wrapped interrupt out of a pending state. + pub fn unpend(&self) { + self.irq.unpend() + } + + /// Gets the priority of the wrapped interrupt. + pub fn priority(&self) -> ::Priority { + self.irq.get_priority() + } +} + +impl Drop for PeripheralMutex { + fn drop(&mut self) { + self.irq.disable(); + self.irq.remove_handler(); + } +} diff --git a/embassy-hal-common/src/peripheral_shared.rs b/embassy-hal-common/src/peripheral_shared.rs new file mode 100644 index 000000000..71d746341 --- /dev/null +++ b/embassy-hal-common/src/peripheral_shared.rs @@ -0,0 +1,122 @@ +use core::marker::{PhantomData, PhantomPinned}; +use core::pin::Pin; + +use embassy::interrupt::{Interrupt, InterruptExt}; + +use crate::peripheral::can_be_preempted; + +/// A type which can be used as state with `Peripheral`. +/// +/// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt. +/// +/// It also requires `'static` to be used safely with `Peripheral::register_interrupt`, +/// because although `Pin` guarantees that the memory of the state won't be invalidated, +/// it doesn't guarantee that the lifetime will last. +pub trait PeripheralState: Sync { + type Interrupt: Interrupt; + fn on_interrupt(&self); +} + +pub struct Peripheral { + state: S, + + irq_setup_done: bool, + irq: S::Interrupt, + + _not_send: PhantomData<*mut ()>, + _pinned: PhantomPinned, +} + +impl Peripheral { + /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. + /// + /// This requires this `Peripheral`'s `PeripheralState` to live for `'static`, + /// because `Pin` only guarantees that it's memory won't be repurposed, + /// not that it's lifetime will last. + /// + /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. + /// + /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; + /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. + pub fn register_interrupt(self: Pin<&mut Self>) { + // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. + unsafe { self.register_interrupt_unchecked() } + } +} + +impl Peripheral { + pub fn new(irq: S::Interrupt, state: S) -> Self { + if can_be_preempted(&irq) { + panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps"); + } + + Self { + irq, + irq_setup_done: false, + + state, + _not_send: PhantomData, + _pinned: PhantomPinned, + } + } + + /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. + /// + /// # Safety + /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler + /// must not end without `Drop` being called on this `Peripheral`. + /// + /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`, + /// or making sure that nothing like `mem::forget` is used on the `Peripheral`. + pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) { + let this = self.get_unchecked_mut(); + if this.irq_setup_done { + return; + } + + this.irq.disable(); + this.irq.set_handler(|p| { + // The state can't have been dropped, otherwise the interrupt would have been disabled. + // We checked in `new` that the thread owning the `Peripheral` can't preempt the interrupt, + // so someone can't have preempted us before this point and dropped the `Peripheral`. + let state = unsafe { &*(p as *const S) }; + state.on_interrupt(); + }); + this.irq + .set_handler_context((&this.state) as *const _ as *mut ()); + this.irq.enable(); + + this.irq_setup_done = true; + } + + pub fn state(self: Pin<&mut Self>) -> &S { + &self.into_ref().get_ref().state + } + + /// Returns whether the wrapped interrupt is currently in a pending state. + pub fn is_pending(&self) -> bool { + self.irq.is_pending() + } + + /// Forces the wrapped interrupt into a pending state. + pub fn pend(&self) { + self.irq.pend() + } + + /// Forces the wrapped interrupt out of a pending state. + pub fn unpend(&self) { + self.irq.unpend() + } + + /// Gets the priority of the wrapped interrupt. + pub fn priority(&self) -> ::Priority { + self.irq.get_priority() + } +} + +impl Drop for Peripheral { + fn drop(&mut self) { + self.irq.disable(); + self.irq.remove_handler(); + } +} diff --git a/embassy-hal-common/src/ring_buffer.rs b/embassy-hal-common/src/ring_buffer.rs new file mode 100644 index 000000000..18795787f --- /dev/null +++ b/embassy-hal-common/src/ring_buffer.rs @@ -0,0 +1,84 @@ +pub struct RingBuffer<'a> { + buf: &'a mut [u8], + start: usize, + end: usize, + empty: bool, +} + +impl<'a> RingBuffer<'a> { + pub fn new(buf: &'a mut [u8]) -> Self { + Self { + buf, + start: 0, + end: 0, + empty: true, + } + } + + pub fn push_buf(&mut self) -> &mut [u8] { + if self.start == self.end && !self.empty { + trace!(" ringbuf: push_buf empty"); + return &mut self.buf[..0]; + } + + let n = if self.start <= self.end { + self.buf.len() - self.end + } else { + self.start - self.end + }; + + trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); + &mut self.buf[self.end..self.end + n] + } + + pub fn push(&mut self, n: usize) { + trace!(" ringbuf: push {:?}", n); + if n == 0 { + return; + } + + self.end = self.wrap(self.end + n); + self.empty = false; + } + + pub fn pop_buf(&mut self) -> &mut [u8] { + if self.empty { + trace!(" ringbuf: pop_buf empty"); + return &mut self.buf[..0]; + } + + let n = if self.end <= self.start { + self.buf.len() - self.start + } else { + self.end - self.start + }; + + trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); + &mut self.buf[self.start..self.start + n] + } + + pub fn pop(&mut self, n: usize) { + trace!(" ringbuf: pop {:?}", n); + if n == 0 { + return; + } + + self.start = self.wrap(self.start + n); + self.empty = self.start == self.end; + } + + pub fn clear(&mut self) { + self.start = 0; + self.end = 0; + self.empty = true; + } + + fn wrap(&self, n: usize) -> usize { + assert!(n <= self.buf.len()); + if n == self.buf.len() { + 0 + } else { + n + } + } +} diff --git a/embassy-hal-common/src/usb/cdc_acm.rs b/embassy-hal-common/src/usb/cdc_acm.rs new file mode 100644 index 000000000..5a85b3846 --- /dev/null +++ b/embassy-hal-common/src/usb/cdc_acm.rs @@ -0,0 +1,338 @@ +// Copied from https://github.com/mvirkkunen/usbd-serial +#![allow(dead_code)] + +use core::convert::TryInto; +use core::mem; +use usb_device::class_prelude::*; +use usb_device::Result; + +/// This should be used as `device_class` when building the `UsbDevice`. +pub const USB_CLASS_CDC: u8 = 0x02; + +const USB_CLASS_CDC_DATA: u8 = 0x0a; +const CDC_SUBCLASS_ACM: u8 = 0x02; +const CDC_PROTOCOL_NONE: u8 = 0x00; + +const CS_INTERFACE: u8 = 0x24; +const CDC_TYPE_HEADER: u8 = 0x00; +const CDC_TYPE_CALL_MANAGEMENT: u8 = 0x01; +const CDC_TYPE_ACM: u8 = 0x02; +const CDC_TYPE_UNION: u8 = 0x06; + +const REQ_SEND_ENCAPSULATED_COMMAND: u8 = 0x00; +#[allow(unused)] +const REQ_GET_ENCAPSULATED_COMMAND: u8 = 0x01; +const REQ_SET_LINE_CODING: u8 = 0x20; +const REQ_GET_LINE_CODING: u8 = 0x21; +const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22; + +/// Packet level implementation of a CDC-ACM serial port. +/// +/// This class can be used directly and it has the least overhead due to directly reading and +/// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial +/// port. The following constraints must be followed if you use this class directly: +/// +/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes, and the +/// method will return a `WouldBlock` error if there is no packet to be read. +/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes, and the +/// method will return a `WouldBlock` error if the previous packet has not been sent yet. +/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the +/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) +/// can be sent if there is no other data to send. This is because USB bulk transactions must be +/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. +pub struct CdcAcmClass<'a, B: UsbBus> { + comm_if: InterfaceNumber, + comm_ep: EndpointIn<'a, B>, + data_if: InterfaceNumber, + read_ep: EndpointOut<'a, B>, + write_ep: EndpointIn<'a, B>, + line_coding: LineCoding, + dtr: bool, + rts: bool, +} + +impl CdcAcmClass<'_, B> { + /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For + /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. + pub fn new(alloc: &UsbBusAllocator, max_packet_size: u16) -> CdcAcmClass<'_, B> { + CdcAcmClass { + comm_if: alloc.interface(), + comm_ep: alloc.interrupt(8, 255), + data_if: alloc.interface(), + read_ep: alloc.bulk(max_packet_size), + write_ep: alloc.bulk(max_packet_size), + line_coding: LineCoding { + stop_bits: StopBits::One, + data_bits: 8, + parity_type: ParityType::None, + data_rate: 8_000, + }, + dtr: false, + rts: false, + } + } + + /// Gets the maximum packet size in bytes. + pub fn max_packet_size(&self) -> u16 { + // The size is the same for both endpoints. + self.read_ep.max_packet_size() + } + + /// Gets the current line coding. The line coding contains information that's mainly relevant + /// for USB to UART serial port emulators, and can be ignored if not relevant. + pub fn line_coding(&self) -> &LineCoding { + &self.line_coding + } + + /// Gets the DTR (data terminal ready) state + pub fn dtr(&self) -> bool { + self.dtr + } + + /// Gets the RTS (request to send) state + pub fn rts(&self) -> bool { + self.rts + } + + /// Writes a single packet into the IN endpoint. + pub fn write_packet(&mut self, data: &[u8]) -> Result { + self.write_ep.write(data) + } + + /// Reads a single packet from the OUT endpoint. + pub fn read_packet(&mut self, data: &mut [u8]) -> Result { + self.read_ep.read(data) + } + + /// Gets the address of the IN endpoint. + pub fn write_ep_address(&self) -> EndpointAddress { + self.write_ep.address() + } + + /// Gets the address of the OUT endpoint. + pub fn read_ep_address(&self) -> EndpointAddress { + self.read_ep.address() + } +} + +impl UsbClass for CdcAcmClass<'_, B> { + fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { + writer.iad( + self.comm_if, + 2, + USB_CLASS_CDC, + CDC_SUBCLASS_ACM, + CDC_PROTOCOL_NONE, + )?; + + writer.interface( + self.comm_if, + USB_CLASS_CDC, + CDC_SUBCLASS_ACM, + CDC_PROTOCOL_NONE, + )?; + + writer.write( + CS_INTERFACE, + &[ + CDC_TYPE_HEADER, // bDescriptorSubtype + 0x10, + 0x01, // bcdCDC (1.10) + ], + )?; + + writer.write( + CS_INTERFACE, + &[ + CDC_TYPE_ACM, // bDescriptorSubtype + 0x00, // bmCapabilities + ], + )?; + + writer.write( + CS_INTERFACE, + &[ + CDC_TYPE_UNION, // bDescriptorSubtype + self.comm_if.into(), // bControlInterface + self.data_if.into(), // bSubordinateInterface + ], + )?; + + writer.write( + CS_INTERFACE, + &[ + CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype + 0x00, // bmCapabilities + self.data_if.into(), // bDataInterface + ], + )?; + + writer.endpoint(&self.comm_ep)?; + + writer.interface(self.data_if, USB_CLASS_CDC_DATA, 0x00, 0x00)?; + + writer.endpoint(&self.write_ep)?; + writer.endpoint(&self.read_ep)?; + + Ok(()) + } + + fn reset(&mut self) { + self.line_coding = LineCoding::default(); + self.dtr = false; + self.rts = false; + } + + fn control_in(&mut self, xfer: ControlIn) { + let req = xfer.request(); + + if !(req.request_type == control::RequestType::Class + && req.recipient == control::Recipient::Interface + && req.index == u8::from(self.comm_if) as u16) + { + return; + } + + match req.request { + // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. + REQ_GET_LINE_CODING if req.length == 7 => { + xfer.accept(|data| { + data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes()); + data[4] = self.line_coding.stop_bits as u8; + data[5] = self.line_coding.parity_type as u8; + data[6] = self.line_coding.data_bits; + + Ok(7) + }) + .ok(); + } + _ => { + xfer.reject().ok(); + } + } + } + + fn control_out(&mut self, xfer: ControlOut) { + let req = xfer.request(); + + if !(req.request_type == control::RequestType::Class + && req.recipient == control::Recipient::Interface + && req.index == u8::from(self.comm_if) as u16) + { + return; + } + + match req.request { + REQ_SEND_ENCAPSULATED_COMMAND => { + // We don't actually support encapsulated commands but pretend we do for standards + // compatibility. + xfer.accept().ok(); + } + REQ_SET_LINE_CODING if xfer.data().len() >= 7 => { + self.line_coding.data_rate = + u32::from_le_bytes(xfer.data()[0..4].try_into().unwrap()); + self.line_coding.stop_bits = xfer.data()[4].into(); + self.line_coding.parity_type = xfer.data()[5].into(); + self.line_coding.data_bits = xfer.data()[6]; + + xfer.accept().ok(); + } + REQ_SET_CONTROL_LINE_STATE => { + self.dtr = (req.value & 0x0001) != 0; + self.rts = (req.value & 0x0002) != 0; + + xfer.accept().ok(); + } + _ => { + xfer.reject().ok(); + } + }; + } +} + +/// Number of stop bits for LineCoding +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum StopBits { + /// 1 stop bit + One = 0, + + /// 1.5 stop bits + OnePointFive = 1, + + /// 2 stop bits + Two = 2, +} + +impl From for StopBits { + fn from(value: u8) -> Self { + if value <= 2 { + unsafe { mem::transmute(value) } + } else { + StopBits::One + } + } +} + +/// Parity for LineCoding +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ParityType { + None = 0, + Odd = 1, + Event = 2, + Mark = 3, + Space = 4, +} + +impl From for ParityType { + fn from(value: u8) -> Self { + if value <= 4 { + unsafe { mem::transmute(value) } + } else { + ParityType::None + } + } +} + +/// Line coding parameters +/// +/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can +/// be ignored if you don't plan to interface with a physical UART. +pub struct LineCoding { + stop_bits: StopBits, + data_bits: u8, + parity_type: ParityType, + data_rate: u32, +} + +impl LineCoding { + /// Gets the number of stop bits for UART communication. + pub fn stop_bits(&self) -> StopBits { + self.stop_bits + } + + /// Gets the number of data bits for UART communication. + pub fn data_bits(&self) -> u8 { + self.data_bits + } + + /// Gets the parity type for UART communication. + pub fn parity_type(&self) -> ParityType { + self.parity_type + } + + /// Gets the data rate in bits per second for UART communication. + pub fn data_rate(&self) -> u32 { + self.data_rate + } +} + +impl Default for LineCoding { + fn default() -> Self { + LineCoding { + stop_bits: StopBits::One, + data_bits: 8, + parity_type: ParityType::None, + data_rate: 8_000, + } + } +} diff --git a/embassy-hal-common/src/usb/mod.rs b/embassy-hal-common/src/usb/mod.rs new file mode 100644 index 000000000..1fb501d7f --- /dev/null +++ b/embassy-hal-common/src/usb/mod.rs @@ -0,0 +1,258 @@ +use core::cell::RefCell; +use core::marker::PhantomData; +use core::pin::Pin; + +use usb_device::bus::UsbBus; +use usb_device::class::UsbClass; +use usb_device::device::UsbDevice; + +mod cdc_acm; +pub mod usb_serial; + +use crate::peripheral::{PeripheralMutex, PeripheralState}; +use embassy::interrupt::Interrupt; +use usb_serial::{ReadInterface, UsbSerial, WriteInterface}; + +/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction. +pub unsafe trait USBInterrupt: Interrupt + Send {} + +pub(crate) struct State<'bus, B, T, I> +where + B: UsbBus, + T: ClassSet, + I: USBInterrupt, +{ + device: UsbDevice<'bus, B>, + pub(crate) classes: T, + _interrupt: PhantomData, +} + +pub struct Usb<'bus, B, T, I> +where + B: UsbBus, + T: ClassSet, + I: USBInterrupt, +{ + // Don't you dare moving out `PeripheralMutex` + inner: RefCell>>, +} + +impl<'bus, B, T, I> Usb<'bus, B, T, I> +where + B: UsbBus, + T: ClassSet, + I: USBInterrupt, +{ + pub fn new>(device: UsbDevice<'bus, B>, class_set: S, irq: I) -> Self { + let state = State { + device, + classes: class_set.into_class_set(), + _interrupt: PhantomData, + }; + let mutex = PeripheralMutex::new(state, irq); + Self { + inner: RefCell::new(mutex), + } + } + + /// # Safety + /// The `UsbDevice` passed to `Self::new` must not be dropped without calling `Drop` on this `Usb` first. + pub unsafe fn start(self: Pin<&mut Self>) { + let this = self.get_unchecked_mut(); + let mut mutex = this.inner.borrow_mut(); + let mutex = Pin::new_unchecked(&mut *mutex); + + // Use inner to register the irq + // SAFETY: the safety contract of this function makes sure the `UsbDevice` won't be invalidated + // without the `PeripheralMutex` being dropped. + mutex.register_interrupt_unchecked(); + } +} + +impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> +where + B: UsbBus, + T: ClassSet + SerialState<'bus, 'c, B, Index0>, + I: USBInterrupt, +{ + /// Take a serial class that was passed as the first class in a tuple + pub fn take_serial_0<'a>( + self: Pin<&'a Self>, + ) -> ( + ReadInterface<'a, 'bus, 'c, Index0, B, T, I>, + WriteInterface<'a, 'bus, 'c, Index0, B, T, I>, + ) { + let this = self.get_ref(); + + let r = ReadInterface { + inner: &this.inner, + _buf_lifetime: PhantomData, + _index: PhantomData, + }; + + let w = WriteInterface { + inner: &this.inner, + _buf_lifetime: PhantomData, + _index: PhantomData, + }; + (r, w) + } +} + +impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> +where + B: UsbBus, + T: ClassSet + SerialState<'bus, 'c, B, Index1>, + I: USBInterrupt, +{ + /// Take a serial class that was passed as the second class in a tuple + pub fn take_serial_1<'a>( + self: Pin<&'a Self>, + ) -> ( + ReadInterface<'a, 'bus, 'c, Index1, B, T, I>, + WriteInterface<'a, 'bus, 'c, Index1, B, T, I>, + ) { + let this = self.get_ref(); + + let r = ReadInterface { + inner: &this.inner, + _buf_lifetime: PhantomData, + _index: PhantomData, + }; + + let w = WriteInterface { + inner: &this.inner, + _buf_lifetime: PhantomData, + _index: PhantomData, + }; + (r, w) + } +} + +impl<'bus, B, T, I> PeripheralState for State<'bus, B, T, I> +where + B: UsbBus, + T: ClassSet, + I: USBInterrupt, +{ + type Interrupt = I; + fn on_interrupt(&mut self) { + self.classes.poll_all(&mut self.device); + } +} + +pub trait ClassSet: Send { + fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool; +} + +pub trait IntoClassSet> { + fn into_class_set(self) -> C; +} + +pub struct ClassSet1 +where + B: UsbBus, + C1: UsbClass, +{ + class: C1, + _bus: PhantomData, +} + +pub struct ClassSet2 +where + B: UsbBus, + C1: UsbClass, + C2: UsbClass, +{ + class1: C1, + class2: C2, + _bus: PhantomData, +} + +/// The first class into a [`ClassSet`] +pub struct Index0; + +/// The second class into a [`ClassSet`] +pub struct Index1; + +impl ClassSet for ClassSet1 +where + B: UsbBus + Send, + C1: UsbClass + Send, +{ + fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { + device.poll(&mut [&mut self.class]) + } +} + +impl ClassSet for ClassSet2 +where + B: UsbBus + Send, + C1: UsbClass + Send, + C2: UsbClass + Send, +{ + fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { + device.poll(&mut [&mut self.class1, &mut self.class2]) + } +} + +impl IntoClassSet> for C1 +where + B: UsbBus + Send, + C1: UsbClass + Send, +{ + fn into_class_set(self) -> ClassSet1 { + ClassSet1 { + class: self, + _bus: PhantomData, + } + } +} + +impl IntoClassSet> for (C1, C2) +where + B: UsbBus + Send, + C1: UsbClass + Send, + C2: UsbClass + Send, +{ + fn into_class_set(self) -> ClassSet2 { + ClassSet2 { + class1: self.0, + class2: self.1, + _bus: PhantomData, + } + } +} + +/// Trait for a USB State that has a serial class inside +pub trait SerialState<'bus, 'a, B: UsbBus, I> { + fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B>; +} + +impl<'bus, 'a, B: UsbBus> SerialState<'bus, 'a, B, Index0> + for ClassSet1> +{ + fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { + &mut self.class + } +} + +impl<'bus, 'a, B, C2> SerialState<'bus, 'a, B, Index0> for ClassSet2, C2> +where + B: UsbBus, + C2: UsbClass, +{ + fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { + &mut self.class1 + } +} + +impl<'bus, 'a, B, C1> SerialState<'bus, 'a, B, Index1> for ClassSet2> +where + B: UsbBus, + C1: UsbClass, +{ + fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { + &mut self.class2 + } +} diff --git a/embassy-hal-common/src/usb/usb_serial.rs b/embassy-hal-common/src/usb/usb_serial.rs new file mode 100644 index 000000000..a229b2000 --- /dev/null +++ b/embassy-hal-common/src/usb/usb_serial.rs @@ -0,0 +1,310 @@ +use core::cell::RefCell; +use core::marker::{PhantomData, Unpin}; +use core::pin::Pin; +use core::task::{Context, Poll}; + +use embassy::io::{self, AsyncBufRead, AsyncWrite}; +use embassy::util::WakerRegistration; +use usb_device::bus::UsbBus; +use usb_device::class_prelude::*; +use usb_device::UsbError; + +use super::cdc_acm::CdcAcmClass; +use crate::peripheral::PeripheralMutex; +use crate::ring_buffer::RingBuffer; +use crate::usb::{ClassSet, SerialState, State, USBInterrupt}; + +pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT> +where + I: Unpin, + B: UsbBus, + T: SerialState<'bus, 'c, B, I> + ClassSet, + INT: USBInterrupt, +{ + // Don't you dare moving out `PeripheralMutex` + pub(crate) inner: &'a RefCell>>, + pub(crate) _buf_lifetime: PhantomData<&'c T>, + pub(crate) _index: PhantomData, +} + +/// Write interface for USB CDC_ACM +/// +/// This interface is buffered, meaning that after the write returns the bytes might not be fully +/// on the wire just yet +pub struct WriteInterface<'a, 'bus, 'c, I, B, T, INT> +where + I: Unpin, + B: UsbBus, + T: SerialState<'bus, 'c, B, I> + ClassSet, + INT: USBInterrupt, +{ + // Don't you dare moving out `PeripheralMutex` + pub(crate) inner: &'a RefCell>>, + pub(crate) _buf_lifetime: PhantomData<&'c T>, + pub(crate) _index: PhantomData, +} + +impl<'a, 'bus, 'c, I, B, T, INT> AsyncBufRead for ReadInterface<'a, 'bus, 'c, I, B, T, INT> +where + I: Unpin, + B: UsbBus, + T: SerialState<'bus, 'c, B, I> + ClassSet, + INT: USBInterrupt, +{ + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.get_mut(); + let mut mutex = this.inner.borrow_mut(); + let mutex = unsafe { Pin::new_unchecked(&mut *mutex) }; + mutex.with(|state| { + let serial = state.classes.get_serial(); + let serial = Pin::new(serial); + + match serial.poll_fill_buf(cx) { + Poll::Ready(Ok(buf)) => { + let buf: &[u8] = buf; + // NOTE(unsafe) This part of the buffer won't be modified until the user calls + // consume, which will invalidate this ref + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + Poll::Ready(Ok(buf)) + } + Poll::Ready(Err(_)) => Poll::Ready(Err(io::Error::Other)), + Poll::Pending => Poll::Pending, + } + }) + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + let this = self.get_mut(); + let mut mutex = this.inner.borrow_mut(); + let mutex = unsafe { Pin::new_unchecked(&mut *mutex) }; + mutex.with(|state| { + let serial = state.classes.get_serial(); + let serial = Pin::new(serial); + + serial.consume(amt); + }) + } +} + +impl<'a, 'bus, 'c, I, B, T, INT> AsyncWrite for WriteInterface<'a, 'bus, 'c, I, B, T, INT> +where + I: Unpin, + B: UsbBus, + T: SerialState<'bus, 'c, B, I> + ClassSet, + INT: USBInterrupt, +{ + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let this = self.get_mut(); + let mut mutex = this.inner.borrow_mut(); + let mutex = unsafe { Pin::new_unchecked(&mut *mutex) }; + mutex.with(|state| { + let serial = state.classes.get_serial(); + let serial = Pin::new(serial); + + serial.poll_write(cx, buf) + }) + } +} + +pub struct UsbSerial<'bus, 'a, B: UsbBus> { + inner: CdcAcmClass<'bus, B>, + read_buf: RingBuffer<'a>, + write_buf: RingBuffer<'a>, + read_waker: WakerRegistration, + write_waker: WakerRegistration, + write_state: WriteState, + read_error: bool, + write_error: bool, +} + +impl<'bus, 'a, B: UsbBus> AsyncBufRead for UsbSerial<'bus, 'a, B> { + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.get_mut(); + + if this.read_error { + this.read_error = false; + return Poll::Ready(Err(io::Error::Other)); + } + + let buf = this.read_buf.pop_buf(); + if buf.is_empty() { + this.read_waker.register(cx.waker()); + return Poll::Pending; + } + Poll::Ready(Ok(buf)) + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + self.get_mut().read_buf.pop(amt); + } +} + +impl<'bus, 'a, B: UsbBus> AsyncWrite for UsbSerial<'bus, 'a, B> { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let this = self.get_mut(); + + if this.write_error { + this.write_error = false; + return Poll::Ready(Err(io::Error::Other)); + } + + let write_buf = this.write_buf.push_buf(); + if write_buf.is_empty() { + this.write_waker.register(cx.waker()); + return Poll::Pending; + } + + let count = write_buf.len().min(buf.len()); + write_buf[..count].copy_from_slice(&buf[..count]); + this.write_buf.push(count); + + this.flush_write(); + Poll::Ready(Ok(count)) + } +} + +/// Keeps track of the type of the last written packet. +enum WriteState { + /// No packets in-flight + Idle, + + /// Short packet currently in-flight + Short, + + /// Full packet current in-flight. A full packet must be followed by a short packet for the host + /// OS to see the transaction. The data is the number of subsequent full packets sent so far. A + /// short packet is forced every SHORT_PACKET_INTERVAL packets so that the OS sees data in a + /// timely manner. + Full(usize), +} + +impl<'bus, 'a, B: UsbBus> UsbSerial<'bus, 'a, B> { + pub fn new( + alloc: &'bus UsbBusAllocator, + read_buf: &'a mut [u8], + write_buf: &'a mut [u8], + ) -> Self { + Self { + inner: CdcAcmClass::new(alloc, 64), + read_buf: RingBuffer::new(read_buf), + write_buf: RingBuffer::new(write_buf), + read_waker: WakerRegistration::new(), + write_waker: WakerRegistration::new(), + write_state: WriteState::Idle, + read_error: false, + write_error: false, + } + } + + fn flush_write(&mut self) { + /// If this many full size packets have been sent in a row, a short packet will be sent so that the + /// host sees the data in a timely manner. + const SHORT_PACKET_INTERVAL: usize = 10; + + let full_size_packets = match self.write_state { + WriteState::Full(c) => c, + _ => 0, + }; + + let ep_size = self.inner.max_packet_size() as usize; + let max_size = if full_size_packets > SHORT_PACKET_INTERVAL { + ep_size - 1 + } else { + ep_size + }; + + let buf = { + let buf = self.write_buf.pop_buf(); + if buf.len() > max_size { + &buf[..max_size] + } else { + buf + } + }; + + if !buf.is_empty() { + let count = match self.inner.write_packet(buf) { + Ok(c) => c, + Err(UsbError::WouldBlock) => 0, + Err(_) => { + self.write_error = true; + return; + } + }; + + if buf.len() == ep_size { + self.write_state = WriteState::Full(full_size_packets + 1); + } else { + self.write_state = WriteState::Short; + } + self.write_buf.pop(count); + } else if full_size_packets > 0 { + if let Err(e) = self.inner.write_packet(&[]) { + if !matches!(e, UsbError::WouldBlock) { + self.write_error = true; + } + return; + } + self.write_state = WriteState::Idle; + } + } +} + +impl UsbClass for UsbSerial<'_, '_, B> +where + B: UsbBus, +{ + fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<(), UsbError> { + self.inner.get_configuration_descriptors(writer) + } + + fn reset(&mut self) { + self.inner.reset(); + self.read_buf.clear(); + self.write_buf.clear(); + self.write_state = WriteState::Idle; + } + + fn endpoint_in_complete(&mut self, addr: EndpointAddress) { + if addr == self.inner.write_ep_address() { + self.write_waker.wake(); + + self.flush_write(); + } + } + + fn endpoint_out(&mut self, addr: EndpointAddress) { + if addr == self.inner.read_ep_address() { + let buf = self.read_buf.push_buf(); + let count = match self.inner.read_packet(buf) { + Ok(c) => c, + Err(UsbError::WouldBlock) => 0, + Err(_) => { + self.read_error = true; + return; + } + }; + + if count > 0 { + self.read_buf.push(count); + self.read_waker.wake(); + } + } + } + + fn control_in(&mut self, xfer: ControlIn) { + self.inner.control_in(xfer); + } + + fn control_out(&mut self, xfer: ControlOut) { + self.inner.control_out(xfer); + } +} diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 1fdc83fb3..c4054cd18 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -30,7 +30,7 @@ nrf52840 = ["nrf52840-pac"] [dependencies] embassy = { version = "0.1.0", path = "../embassy", features = ["time-tick-32768hz"] } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]} -embassy-extras = {version = "0.1.0", path = "../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } defmt = { version = "0.2.0", optional = true } log = { version = "0.4.11", optional = true } diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 9be4d4d54..d6120bd0c 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -7,9 +7,9 @@ use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::io::{AsyncBufRead, AsyncWrite, Result}; use embassy::util::{Unborrow, WakerRegistration}; -use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; -use embassy_extras::ring_buffer::RingBuffer; -use embassy_extras::{low_power_wait_until, unborrow}; +use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState}; +use embassy_hal_common::ring_buffer::RingBuffer; +use embassy_hal_common::{low_power_wait_until, unborrow}; use crate::gpio::sealed::Pin as _; use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 2b02c1afe..2034c67e0 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -3,7 +3,7 @@ pub use nrf52805_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 256; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 4c93d5046..27e1f3d20 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -3,7 +3,7 @@ pub use nrf52810_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 10) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 256; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index f840214fa..0d0c5ac75 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -3,7 +3,7 @@ pub use nrf52811_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 256; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 180861f71..9b5bdef16 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -3,7 +3,7 @@ pub use nrf52820_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 15) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 512; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 1c38a7751..e79dba524 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -3,7 +3,7 @@ pub use nrf52832_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 8) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 255; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index bcb0fffc0..7c62a7fdc 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -3,7 +3,7 @@ pub use nrf52833_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 512; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index ee8b5a89c..00f6d49dd 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -3,7 +3,7 @@ pub use nrf52840_pac as pac; pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; pub const FORCE_COPY_BUFFER_SIZE: usize = 512; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { // RTC RTC0, RTC1, diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index b02e77874..e30df7e7e 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -5,7 +5,7 @@ use core::hint::unreachable_unchecked; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::{unborrow, unsafe_impl_unborrow}; +use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use gpio::pin_cnf::DRIVE_A; diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 54d3dd012..847b2fbf3 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -5,7 +5,7 @@ use core::task::{Context, Poll}; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits::gpio::{WaitForAnyEdge, WaitForHigh, WaitForLow}; use embassy::util::AtomicWaker; -use embassy_extras::unsafe_impl_unborrow; +use embassy_hal_common::unsafe_impl_unborrow; use embedded_hal::digital::v2::{InputPin, StatefulOutputPin}; use futures::future::poll_fn; diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 35815f792..1275a64f3 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -76,7 +76,7 @@ pub mod interrupt { pub use crate::chip::irqs::*; pub use cortex_m::interrupt::{CriticalSection, Mutex}; pub use embassy::interrupt::{declare, take, Interrupt}; - pub use embassy_extras::interrupt::Priority3 as Priority; + pub use embassy_hal_common::interrupt::Priority3 as Priority; } pub use embassy_macros::interrupt; diff --git a/embassy-nrf/src/ppi.rs b/embassy-nrf/src/ppi.rs index c91a69c10..61028c03a 100644 --- a/embassy-nrf/src/ppi.rs +++ b/embassy-nrf/src/ppi.rs @@ -12,7 +12,7 @@ use core::marker::PhantomData; use core::ptr::NonNull; use embassy::util::Unborrow; -use embassy_extras::{unborrow, unsafe_impl_unborrow}; +use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; use crate::{pac, peripherals}; diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 07509aef9..5e996e882 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -4,7 +4,7 @@ use core::cell::UnsafeCell; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use crate::gpio::sealed::Pin as _; use crate::gpio::OptionalPin as GpioOptionalPin; diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 42bf8f419..28becfd56 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -7,7 +7,7 @@ use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits::flash::{Error, Flash}; use embassy::util::{AtomicWaker, DropBomb, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index a444c9b3f..6cdcccf3b 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -11,7 +11,7 @@ use embassy::traits; use embassy::util::AtomicWaker; use embassy::util::OnDrop; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use rand_core::RngCore; diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index edb8aa21f..7bc38f1d3 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::util::{wake_on_interrupt, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use crate::interrupt; diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 221c52051..9a7fb4f67 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -7,7 +7,7 @@ use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::traits; use embassy::util::{AtomicWaker, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use traits::spi::{FullDuplex, Read, Spi, Write}; diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 7ff35c320..eab9a1416 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -7,7 +7,7 @@ use embassy::interrupt::Interrupt; use embassy::interrupt::InterruptExt; use embassy::util::OnDrop; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use crate::pac; diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index b533c69c4..ac263bad7 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -13,7 +13,7 @@ use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits; use embassy::util::{AtomicWaker, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use traits::i2c::I2c; diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 985854a5f..b2b298661 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -9,7 +9,7 @@ use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; use embassy::util::{AtomicWaker, OnDrop, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use crate::chip::EASY_DMA_SIZE; diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index c61b8c997..e2da226dd 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -20,7 +20,7 @@ defmt-error = [ ] [dependencies] embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] } -embassy-extras = {version = "0.1.0", path = "../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} defmt = { version = "0.2.0", optional = true } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 5edf47f52..4ea78016a 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -6,7 +6,7 @@ use crate::pac::SIO; use crate::peripherals; use embassy::util::Unborrow; -use embassy_extras::{unborrow, unsafe_impl_unborrow}; +use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; use embedded_hal::digital::v2 as digital; /// Represents a digital input or output level. diff --git a/embassy-rp/src/interrupt.rs b/embassy-rp/src/interrupt.rs index a4e5959ab..109afcbc4 100644 --- a/embassy-rp/src/interrupt.rs +++ b/embassy-rp/src/interrupt.rs @@ -5,7 +5,7 @@ // Re-exports pub use embassy::interrupt::{declare, take, Interrupt}; -pub use embassy_extras::interrupt::Priority3 as Priority; +pub use embassy_hal_common::interrupt::Priority3 as Priority; mod irqs { use super::*; diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c53d2e58d..10bf7158f 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -25,7 +25,7 @@ pub mod uart; mod clocks; mod reset; -embassy_extras::peripherals! { +embassy_hal_common::peripherals! { PIN_0, PIN_1, PIN_2, diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 959ad9b0f..906fa23e9 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embedded_hal::blocking::spi as eh; use embedded_hal::spi as ehnb; diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart.rs index 6d354e7c4..3f5c49079 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use gpio::Pin; use crate::{gpio, pac, peripherals}; diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4e4d7ff82..d94c9d523 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../embassy", features = ["time-tick-32768hz"] } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] } -embassy-extras = {version = "0.1.0", path = "../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } embassy-traits = {version = "0.1.0", path = "../embassy-traits" } embassy-net = { version = "0.1.0", path = "../embassy-net", default-features = false, optional = true } diff --git a/embassy-stm32/gen.py b/embassy-stm32/gen.py index 01c778716..e589f2f06 100644 --- a/embassy-stm32/gen.py +++ b/embassy-stm32/gen.py @@ -85,4 +85,4 @@ with open(output_file, 'w') as f: for (channel_id, defn) in core['dma_channels'].items(): singletons.append( channel_id ) - f.write(f"embassy_extras::peripherals!({','.join(singletons)});") + f.write(f"embassy_hal_common::peripherals!({','.join(singletons)});") diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 7480c4a36..db6a4e512 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,7 +1,7 @@ use crate::adc::{AdcPin, Instance}; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embedded_hal::blocking::delay::DelayUs; pub const VDDA_CALIB_MV: u32 = 3000; diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs index 25a87db06..f46145b8d 100644 --- a/embassy-stm32/src/dac/v2.rs +++ b/embassy-stm32/src/dac/v2.rs @@ -3,7 +3,7 @@ use crate::gpio::AnyPin; use crate::pac::dac; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 129d2d02c..3f72fb35e 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -4,8 +4,8 @@ use core::sync::atomic::{fence, Ordering}; use core::task::Waker; use embassy::util::{AtomicWaker, Unborrow}; -use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; -use embassy_extras::unborrow; +use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState}; +use embassy_hal_common::unborrow; use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU}; use crate::gpio::sealed::Pin as __GpioPin; diff --git a/embassy-stm32/src/exti/mod.rs b/embassy-stm32/src/exti/mod.rs index 217c8173b..bb9082f2e 100644 --- a/embassy-stm32/src/exti/mod.rs +++ b/embassy-stm32/src/exti/mod.rs @@ -42,7 +42,7 @@ mod _version; pub use _version::*; use crate::peripherals; -use embassy_extras::unsafe_impl_unborrow; +use embassy_hal_common::unsafe_impl_unborrow; pub(crate) mod sealed { pub trait Channel {} diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 5145bd689..7812709ce 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -2,7 +2,7 @@ use core::convert::Infallible; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::{unborrow, unsafe_impl_unborrow}; +use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; use embedded_hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin}; use crate::pac; diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 8573f01f4..578536855 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -2,7 +2,7 @@ use crate::i2c::{Error, Instance, SclPin, SdaPin}; use crate::time::Hertz; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embedded_hal::blocking::i2c::Read; use embedded_hal::blocking::i2c::Write; use embedded_hal::blocking::i2c::WriteRead; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 3179211ec..9f7206107 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,7 +1,7 @@ use core::cmp; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embedded_hal::blocking::i2c::Read; use embedded_hal::blocking::i2c::Write; use embedded_hal::blocking::i2c::WriteRead; diff --git a/embassy-stm32/src/interrupt.rs b/embassy-stm32/src/interrupt.rs index a12cdf235..27e441644 100644 --- a/embassy-stm32/src/interrupt.rs +++ b/embassy-stm32/src/interrupt.rs @@ -1,7 +1,7 @@ pub use bare_metal::Mutex; pub use critical_section::CriticalSection; pub use embassy::interrupt::{take, Interrupt}; -pub use embassy_extras::interrupt::Priority4 as Priority; +pub use embassy_hal_common::interrupt::Priority4 as Priority; use crate::pac::Interrupt as InterruptEnum; use embassy::interrupt::declare; diff --git a/embassy-stm32/src/rcc/f4/mod.rs b/embassy-stm32/src/rcc/f4/mod.rs index 6000192b9..d47510da7 100644 --- a/embassy-stm32/src/rcc/f4/mod.rs +++ b/embassy-stm32/src/rcc/f4/mod.rs @@ -6,7 +6,7 @@ use crate::time::Hertz; use crate::time::U32Ext; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use pac::rcc::vals::{Hpre, Ppre, Sw}; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs index 6107d5f55..ef8286e25 100644 --- a/embassy-stm32/src/rcc/l0/mod.rs +++ b/embassy-stm32/src/rcc/l0/mod.rs @@ -6,7 +6,7 @@ use crate::time::Hertz; use crate::time::U32Ext; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4/mod.rs index e6662f59f..4247d8ffb 100644 --- a/embassy-stm32/src/rcc/l4/mod.rs +++ b/embassy-stm32/src/rcc/l4/mod.rs @@ -6,7 +6,7 @@ use crate::time::Hertz; use crate::time::U32Ext; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// and with the addition of the init function to configure a system clock. diff --git a/embassy-stm32/src/rcc/wb55/mod.rs b/embassy-stm32/src/rcc/wb55/mod.rs index e6662f59f..4247d8ffb 100644 --- a/embassy-stm32/src/rcc/wb55/mod.rs +++ b/embassy-stm32/src/rcc/wb55/mod.rs @@ -6,7 +6,7 @@ use crate::time::Hertz; use crate::time::U32Ext; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// and with the addition of the init function to configure a system clock. diff --git a/embassy-stm32/src/rcc/wl5x/mod.rs b/embassy-stm32/src/rcc/wl5x/mod.rs index 554a27ca2..6a4f99e0c 100644 --- a/embassy-stm32/src/rcc/wl5x/mod.rs +++ b/embassy-stm32/src/rcc/wl5x/mod.rs @@ -6,7 +6,7 @@ use crate::time::Hertz; use crate::time::U32Ext; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// and with the addition of the init function to configure a system clock. diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index c2248c84d..d93a25f5a 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -4,7 +4,7 @@ use core::future::Future; use core::task::Poll; use embassy::traits; use embassy::util::{AtomicWaker, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use rand_core::{CryptoRng, RngCore}; diff --git a/embassy-stm32/src/sdmmc/v2.rs b/embassy-stm32/src/sdmmc/v2.rs index 9c7bad4df..aa1d68ae7 100644 --- a/embassy-stm32/src/sdmmc/v2.rs +++ b/embassy-stm32/src/sdmmc/v2.rs @@ -6,7 +6,7 @@ use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::util::{AtomicWaker, OnDrop, Unborrow}; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::future::poll_fn; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 43489bb6f..554981ce7 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -12,7 +12,7 @@ use core::future::Future; use core::marker::PhantomData; use core::ptr; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embassy_traits::spi as traits; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use futures::future::join3; diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs index 2144dfcc8..496d100f7 100644 --- a/embassy-stm32/src/spi/v2.rs +++ b/embassy-stm32/src/spi/v2.rs @@ -14,7 +14,7 @@ use core::future::Future; use core::marker::PhantomData; use core::ptr; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embassy_traits::spi as traits; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use futures::future::join3; diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index f433d7f9c..cfee54dac 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs @@ -14,7 +14,7 @@ use core::future::Future; use core::marker::PhantomData; use core::ptr; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use embassy_traits::spi as traits; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index 0f39c364b..d68215fea 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -1,7 +1,7 @@ use core::future::Future; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::TryFutureExt; use super::*; diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 8a4d63b20..6ce3a338e 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -1,7 +1,7 @@ use core::future::Future; use core::marker::PhantomData; use embassy::util::Unborrow; -use embassy_extras::unborrow; +use embassy_hal_common::unborrow; use futures::TryFutureExt; use super::*; diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 704a76390..693dac545 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -20,7 +20,7 @@ defmt-error = [] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f429zi", "unstable-pac"] } -embassy-extras = {version = "0.1.0", path = "../../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } defmt = "0.2.0" defmt-rtt = "0.2.0" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index ebaa4e5db..278ab6f6b 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -20,7 +20,7 @@ defmt-error = [] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32h743zi", "net"] } -embassy-extras = {version = "0.1.0", path = "../../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } embassy-net = { path = "../../embassy-net", default-features = false, features = ["defmt-debug", "defmt", "tcp", "medium-ethernet", "pool-16"] } stm32-metapac = { path = "../../stm32-metapac", features = ["stm32h743zi"] } embassy-macros = { path = "../../embassy-macros" } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 68291b007..47d23d08f 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -20,7 +20,7 @@ defmt-error = [] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32l072cz"] } -embassy-extras = {version = "0.1.0", path = "../../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } defmt = "0.2.0" defmt-rtt = "0.2.0" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index cbf002291..ce4618290 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -20,7 +20,7 @@ defmt-error = [] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "unstable-pac", "stm32l4s5vi"] } -embassy-extras = {version = "0.1.0", path = "../../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } defmt = "0.2.0" defmt-rtt = "0.2.0" diff --git a/examples/stm32wb55/Cargo.toml b/examples/stm32wb55/Cargo.toml index 92813ccd0..4d6f7789c 100644 --- a/examples/stm32wb55/Cargo.toml +++ b/examples/stm32wb55/Cargo.toml @@ -20,7 +20,7 @@ defmt-error = [] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32wb55cc"] } -embassy-extras = {version = "0.1.0", path = "../../embassy-extras" } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } defmt = "0.2.0" defmt-rtt = "0.2.0" -- cgit