usb: add -usb-serial crate, fix warnings and stable build.
This commit is contained in:
parent
c06488eb29
commit
d1e4b3d7d5
15 changed files with 265 additions and 27 deletions
|
@ -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}
|
||||
|
|
|
@ -125,6 +125,7 @@ embassy_hal_common::peripherals! {
|
|||
TEMP,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl_usb!(USBD, USBD, USBD);
|
||||
|
||||
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
||||
|
|
|
@ -157,6 +157,7 @@ embassy_hal_common::peripherals! {
|
|||
TEMP,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl_usb!(USBD, USBD, USBD);
|
||||
|
||||
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
||||
|
|
|
@ -160,6 +160,7 @@ embassy_hal_common::peripherals! {
|
|||
TEMP,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl_usb!(USBD, USBD, USBD);
|
||||
|
||||
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
||||
|
|
|
@ -348,6 +348,7 @@ embassy_hal_common::peripherals! {
|
|||
P1_15,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl_usb!(USBD, USBD, USBD);
|
||||
|
||||
impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0);
|
||||
|
|
|
@ -91,6 +91,7 @@ pub mod uarte;
|
|||
feature = "nrf52833",
|
||||
feature = "nrf52840"
|
||||
))]
|
||||
#[cfg(feature = "nightly")]
|
||||
pub mod usb;
|
||||
#[cfg(not(feature = "_nrf5340"))]
|
||||
pub mod wdt;
|
||||
|
|
|
@ -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);
|
||||
|
|
11
embassy-usb-serial/Cargo.toml
Normal file
11
embassy-usb-serial/Cargo.toml
Normal file
|
@ -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 }
|
225
embassy-usb-serial/src/fmt.rs
Normal file
225
embassy-usb-serial/src/fmt.rs
Normal file
|
@ -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<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> Try for Option<T> {
|
||||
type Ok = T;
|
||||
type Error = NoneError;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Result<T, NoneError> {
|
||||
self.ok_or(NoneError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Try for Result<T, E> {
|
||||
type Ok = T;
|
||||
type Error = E;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
|
@ -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<usize, ReadError> {
|
||||
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
|
|
@ -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"
|
|
@ -136,6 +136,7 @@ impl<'a> DescriptorWriter<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn end_class(&mut self) {
|
||||
self.num_endpoints_mark = None;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
Loading…
Reference in a new issue