diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 36c61c651..858ff1f6e 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -18,7 +18,7 @@ flavors = [ [features] # Enable nightly-only features -nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async"] +nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb"] # Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. # This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. @@ -64,7 +64,7 @@ _gpio-p1 = [] embassy = { version = "0.1.0", path = "../embassy" } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]} embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } -embassy-usb = {version = "0.1.0", path = "../embassy-usb" } +embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional=true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.7", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy2", optional = true} diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index aa2b2e61d..136ef4ec9 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -125,6 +125,7 @@ embassy_hal_common::peripherals! { TEMP, } +#[cfg(feature = "nightly")] impl_usb!(USBD, USBD, USBD); impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 498a3c307..35cf4224d 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -157,6 +157,7 @@ embassy_hal_common::peripherals! { TEMP, } +#[cfg(feature = "nightly")] impl_usb!(USBD, USBD, USBD); impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 411768146..d20abbfbd 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -160,6 +160,7 @@ embassy_hal_common::peripherals! { TEMP, } +#[cfg(feature = "nightly")] impl_usb!(USBD, USBD, USBD); impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index ae6887b3c..89579b69f 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -348,6 +348,7 @@ embassy_hal_common::peripherals! { P1_15, } +#[cfg(feature = "nightly")] impl_usb!(USBD, USBD, USBD); impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 06e8235e3..667e8ea38 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -91,6 +91,7 @@ pub mod uarte; feature = "nrf52833", feature = "nrf52840" ))] +#[cfg(feature = "nightly")] pub mod usb; #[cfg(not(feature = "_nrf5340"))] pub mod wdt; diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 1cd5a9ebb..b26e40272 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs @@ -4,6 +4,7 @@ use core::marker::PhantomData; use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use core::task::Poll; +use cortex_m::peripheral::NVIC; use embassy::interrupt::InterruptExt; use embassy::time::{with_timeout, Duration}; use embassy::util::Unborrow; @@ -14,7 +15,6 @@ use embassy_usb::driver::{self, Event, ReadError, WriteError}; use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; use futures::future::poll_fn; use futures::Future; -use pac::NVIC; pub use embassy_usb; @@ -617,7 +617,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a> { async move { let req = self.request.unwrap(); - assert_eq!(req.direction, UsbDirection::Out); + assert!(req.direction == UsbDirection::Out); assert!(req.length > 0); let req_length = usize::from(req.length); @@ -644,9 +644,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { fn accept_in<'a>(&'a mut self, buf: &'a [u8]) -> Self::AcceptInFuture<'a> { async move { - info!("control accept {=[u8]:x}", buf); + #[cfg(feature = "defmt")] + info!("control accept {:x}", buf); + #[cfg(not(feature = "defmt"))] + info!("control accept {:x?}", buf); let req = self.request.unwrap(); - assert_eq!(req.direction, UsbDirection::In); + assert!(req.direction == UsbDirection::In); let req_len = usize::from(req.length); let len = buf.len().min(req_len); diff --git a/embassy-usb-serial/Cargo.toml b/embassy-usb-serial/Cargo.toml new file mode 100644 index 000000000..16e03046e --- /dev/null +++ b/embassy-usb-serial/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "embassy-usb-serial" +version = "0.1.0" +edition = "2021" + +[dependencies] +embassy = { version = "0.1.0", path = "../embassy" } +embassy-usb = { version = "0.1.0", path = "../embassy-usb" } + +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } diff --git a/embassy-usb-serial/src/fmt.rs b/embassy-usb-serial/src/fmt.rs new file mode 100644 index 000000000..066970813 --- /dev/null +++ b/embassy-usb-serial/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/examples/nrf/src/bin/usb/cdc_acm.rs b/embassy-usb-serial/src/lib.rs similarity index 98% rename from examples/nrf/src/bin/usb/cdc_acm.rs rename to embassy-usb-serial/src/lib.rs index c28681dc4..d6c31c86e 100644 --- a/examples/nrf/src/bin/usb/cdc_acm.rs +++ b/embassy-usb-serial/src/lib.rs @@ -1,7 +1,13 @@ +#![no_std] +#![feature(generic_associated_types)] +#![feature(type_alias_impl_trait)] + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + use core::cell::Cell; use core::mem::{self, MaybeUninit}; use core::sync::atomic::{AtomicBool, Ordering}; -use defmt::info; use embassy::blocking_mutex::CriticalSectionMutex; use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError}; @@ -291,11 +297,6 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { self.read_ep.read(data).await } - - /// Gets the address of the IN endpoint. - pub(crate) fn write_ep_address(&self) -> EndpointAddress { - self.write_ep.info().addr - } } /// Number of stop bits for LineCoding diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index af5986c15..01bf5ef6f 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -8,6 +8,4 @@ embassy = { version = "0.1.0", path = "../embassy" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -cortex-m = "0.7.3" -num-traits = { version = "0.2.14", default-features = false } heapless = "0.7.10" \ No newline at end of file diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index 746c6b828..5f8b0d560 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -136,6 +136,7 @@ impl<'a> DescriptorWriter<'a> { ) } + #[allow(unused)] pub(crate) fn end_class(&mut self) { self.num_endpoints_mark = None; } diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index cbb909244..5a6b21906 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -302,7 +302,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { async fn handle_get_descriptor(&mut self, req: Request) { let (dtype, index) = req.descriptor_type_index(); - let config = self.config.clone(); match dtype { descriptor_type::BOS => self.control.accept_in(self.bos_descriptor).await, @@ -321,13 +320,10 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { 2 => self.config.product, 3 => self.config.serial_number, _ => { - let index = StringIndex::new(index); - let lang_id = req.index; + let _index = StringIndex::new(index); + let _lang_id = req.index; + // TODO None - //classes - // .iter() - // .filter_map(|cls| cls.get_string(index, lang_id)) - // .nth(0) } }; diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index 59e5de026..58450a045 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml @@ -12,6 +12,7 @@ nightly = ["embassy-nrf/nightly", "embassy-nrf/unstable-traits"] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/nrf/src/bin/usb/main.rs b/examples/nrf/src/bin/usb_serial.rs similarity index 95% rename from examples/nrf/src/bin/usb/main.rs rename to examples/nrf/src/bin/usb_serial.rs index c4b9c0176..0a4ff9489 100644 --- a/examples/nrf/src/bin/usb/main.rs +++ b/examples/nrf/src/bin/usb_serial.rs @@ -3,11 +3,6 @@ #![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] -#[path = "../../example_common.rs"] -mod example_common; - -mod cdc_acm; - use core::mem; use defmt::*; use embassy::executor::Spawner; @@ -18,9 +13,11 @@ use embassy_nrf::usb::Driver; use embassy_nrf::Peripherals; use embassy_usb::driver::{EndpointIn, EndpointOut}; use embassy_usb::{Config, UsbDeviceBuilder}; +use embassy_usb_serial::{CdcAcmClass, State}; use futures::future::join3; -use crate::cdc_acm::{CdcAcmClass, State}; +use defmt_rtt as _; // global logger +use panic_probe as _; #[embassy::main] async fn main(_spawner: Spawner, p: Peripherals) {