Merge #972
972: Restructure USB crates r=Dirbaio a=Dirbaio - Split driver from `embassy-usb` to a separate crate. This allows making breaking changes to `embassy-usb` without having to bump all the crates with driver impls, such as HALs. - Merge classes into `embassy-usb`. Now that breaking changes to `embassy-usb` aren't that bad, having everything in a single crate is much easier. Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
commit
49070c75b6
38 changed files with 218 additions and 951 deletions
|
@ -10,8 +10,9 @@ use cortex_m::peripheral::NVIC;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
pub use embassy_usb;
|
pub use embassy_usb;
|
||||||
use embassy_usb::driver::{self, EndpointError, Event, Unsupported};
|
use embassy_usb::driver::{
|
||||||
use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
|
self, Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
||||||
|
};
|
||||||
use pac::usbd::RegisterBlock;
|
use pac::usbd::RegisterBlock;
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{Interrupt, InterruptExt};
|
||||||
|
@ -243,7 +244,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
|
||||||
interval: u8,
|
interval: u8,
|
||||||
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
|
||||||
let index = self.alloc_in.allocate(ep_type)?;
|
let index = self.alloc_in.allocate(ep_type)?;
|
||||||
let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In);
|
let ep_addr = EndpointAddress::from_parts(index, Direction::In);
|
||||||
Ok(Endpoint::new(EndpointInfo {
|
Ok(Endpoint::new(EndpointInfo {
|
||||||
addr: ep_addr,
|
addr: ep_addr,
|
||||||
ep_type,
|
ep_type,
|
||||||
|
@ -259,7 +260,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
|
||||||
interval: u8,
|
interval: u8,
|
||||||
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
|
||||||
let index = self.alloc_out.allocate(ep_type)?;
|
let index = self.alloc_out.allocate(ep_type)?;
|
||||||
let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out);
|
let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
|
||||||
Ok(Endpoint::new(EndpointInfo {
|
Ok(Endpoint::new(EndpointInfo {
|
||||||
addr: ep_addr,
|
addr: ep_addr,
|
||||||
ep_type,
|
ep_type,
|
||||||
|
@ -428,8 +429,8 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let i = ep_addr.index();
|
let i = ep_addr.index();
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
UsbDirection::Out => regs.halted.epout[i].read().getstatus().is_halted(),
|
Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(),
|
||||||
UsbDirection::In => regs.halted.epin[i].read().getstatus().is_halted(),
|
Direction::In => regs.halted.epin[i].read().getstatus().is_halted(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +443,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
|
||||||
debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
|
debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
|
||||||
|
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
UsbDirection::In => {
|
Direction::In => {
|
||||||
let mut was_enabled = false;
|
let mut was_enabled = false;
|
||||||
regs.epinen.modify(|r, w| {
|
regs.epinen.modify(|r, w| {
|
||||||
let mut bits = r.bits();
|
let mut bits = r.bits();
|
||||||
|
@ -466,7 +467,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
|
||||||
|
|
||||||
In::waker(i).wake();
|
In::waker(i).wake();
|
||||||
}
|
}
|
||||||
UsbDirection::Out => {
|
Direction::Out => {
|
||||||
regs.epouten.modify(|r, w| {
|
regs.epouten.modify(|r, w| {
|
||||||
let mut bits = r.bits();
|
let mut bits = r.bits();
|
||||||
if enabled {
|
if enabled {
|
||||||
|
|
|
@ -7,8 +7,9 @@ use core::task::Poll;
|
||||||
use atomic_polyfill::compiler_fence;
|
use atomic_polyfill::compiler_fence;
|
||||||
use embassy_hal_common::into_ref;
|
use embassy_hal_common::into_ref;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
|
use embassy_usb::driver::{
|
||||||
use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
|
self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{Interrupt, InterruptExt};
|
||||||
use crate::{pac, peripherals, Peripheral, RegExt};
|
use crate::{pac, peripherals, Peripheral, RegExt};
|
||||||
|
@ -204,8 +205,8 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let alloc = match D::dir() {
|
let alloc = match D::dir() {
|
||||||
UsbDirection::Out => &mut self.ep_out,
|
Direction::Out => &mut self.ep_out,
|
||||||
UsbDirection::In => &mut self.ep_in,
|
Direction::In => &mut self.ep_in,
|
||||||
};
|
};
|
||||||
|
|
||||||
let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
|
let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
|
||||||
|
@ -254,7 +255,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match D::dir() {
|
match D::dir() {
|
||||||
UsbDirection::Out => unsafe {
|
Direction::Out => unsafe {
|
||||||
T::dpram().ep_out_control(index - 1).write(|w| {
|
T::dpram().ep_out_control(index - 1).write(|w| {
|
||||||
w.set_enable(false);
|
w.set_enable(false);
|
||||||
w.set_buffer_address(addr);
|
w.set_buffer_address(addr);
|
||||||
|
@ -262,7 +263,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
w.set_endpoint_type(ep_type_reg);
|
w.set_endpoint_type(ep_type_reg);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
UsbDirection::In => unsafe {
|
Direction::In => unsafe {
|
||||||
T::dpram().ep_in_control(index - 1).write(|w| {
|
T::dpram().ep_in_control(index - 1).write(|w| {
|
||||||
w.set_enable(false);
|
w.set_enable(false);
|
||||||
w.set_buffer_address(addr);
|
w.set_buffer_address(addr);
|
||||||
|
@ -429,14 +430,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
|
|
||||||
let n = ep_addr.index();
|
let n = ep_addr.index();
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
UsbDirection::In => unsafe {
|
Direction::In => unsafe {
|
||||||
T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
|
T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
|
||||||
T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
|
T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
|
||||||
w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
|
w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
|
||||||
});
|
});
|
||||||
EP_IN_WAKERS[n].wake();
|
EP_IN_WAKERS[n].wake();
|
||||||
},
|
},
|
||||||
UsbDirection::Out => unsafe {
|
Direction::Out => unsafe {
|
||||||
T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
|
T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
|
||||||
|
|
||||||
T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
|
T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
|
||||||
|
@ -474,14 +475,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dir {
|
trait Dir {
|
||||||
fn dir() -> UsbDirection;
|
fn dir() -> Direction;
|
||||||
fn waker(i: usize) -> &'static AtomicWaker;
|
fn waker(i: usize) -> &'static AtomicWaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum In {}
|
pub enum In {}
|
||||||
impl Dir for In {
|
impl Dir for In {
|
||||||
fn dir() -> UsbDirection {
|
fn dir() -> Direction {
|
||||||
UsbDirection::In
|
Direction::In
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -492,8 +493,8 @@ impl Dir for In {
|
||||||
|
|
||||||
pub enum Out {}
|
pub enum Out {}
|
||||||
impl Dir for Out {
|
impl Dir for Out {
|
||||||
fn dir() -> UsbDirection {
|
fn dir() -> Direction {
|
||||||
UsbDirection::Out
|
Direction::Out
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -9,8 +9,9 @@ use atomic_polyfill::{AtomicBool, AtomicU8};
|
||||||
use embassy_hal_common::into_ref;
|
use embassy_hal_common::into_ref;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_time::{block_for, Duration};
|
use embassy_time::{block_for, Duration};
|
||||||
use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
|
use embassy_usb::driver::{
|
||||||
use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
|
self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
||||||
|
};
|
||||||
use pac::common::{Reg, RW};
|
use pac::common::{Reg, RW};
|
||||||
use pac::usb::vals::{EpType, Stat};
|
use pac::usb::vals::{EpType, Stat};
|
||||||
|
|
||||||
|
@ -279,8 +280,8 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
}
|
}
|
||||||
let used = ep.used_out || ep.used_in;
|
let used = ep.used_out || ep.used_in;
|
||||||
let used_dir = match D::dir() {
|
let used_dir = match D::dir() {
|
||||||
UsbDirection::Out => ep.used_out,
|
Direction::Out => ep.used_out,
|
||||||
UsbDirection::In => ep.used_in,
|
Direction::In => ep.used_in,
|
||||||
};
|
};
|
||||||
!used || (ep.ep_type == ep_type && !used_dir)
|
!used || (ep.ep_type == ep_type && !used_dir)
|
||||||
});
|
});
|
||||||
|
@ -293,7 +294,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
ep.ep_type = ep_type;
|
ep.ep_type = ep_type;
|
||||||
|
|
||||||
let buf = match D::dir() {
|
let buf = match D::dir() {
|
||||||
UsbDirection::Out => {
|
Direction::Out => {
|
||||||
assert!(!ep.used_out);
|
assert!(!ep.used_out);
|
||||||
ep.used_out = true;
|
ep.used_out = true;
|
||||||
|
|
||||||
|
@ -312,7 +313,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UsbDirection::In => {
|
Direction::In => {
|
||||||
assert!(!ep.used_in);
|
assert!(!ep.used_in);
|
||||||
ep.used_in = true;
|
ep.used_in = true;
|
||||||
|
|
||||||
|
@ -504,7 +505,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
// This can race, so do a retry loop.
|
// This can race, so do a retry loop.
|
||||||
let reg = T::regs().epr(ep_addr.index() as _);
|
let reg = T::regs().epr(ep_addr.index() as _);
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
UsbDirection::In => {
|
Direction::In => {
|
||||||
loop {
|
loop {
|
||||||
let r = unsafe { reg.read() };
|
let r = unsafe { reg.read() };
|
||||||
match r.stat_tx() {
|
match r.stat_tx() {
|
||||||
|
@ -523,7 +524,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
}
|
}
|
||||||
EP_IN_WAKERS[ep_addr.index()].wake();
|
EP_IN_WAKERS[ep_addr.index()].wake();
|
||||||
}
|
}
|
||||||
UsbDirection::Out => {
|
Direction::Out => {
|
||||||
loop {
|
loop {
|
||||||
let r = unsafe { reg.read() };
|
let r = unsafe { reg.read() };
|
||||||
match r.stat_rx() {
|
match r.stat_rx() {
|
||||||
|
@ -549,8 +550,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
|
let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
UsbDirection::In => epr.stat_tx() == Stat::STALL,
|
Direction::In => epr.stat_tx() == Stat::STALL,
|
||||||
UsbDirection::Out => epr.stat_rx() == Stat::STALL,
|
Direction::Out => epr.stat_rx() == Stat::STALL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +561,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
let reg = T::regs().epr(ep_addr.index() as _);
|
let reg = T::regs().epr(ep_addr.index() as _);
|
||||||
trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
|
trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
UsbDirection::In => {
|
Direction::In => {
|
||||||
loop {
|
loop {
|
||||||
let want_stat = match enabled {
|
let want_stat = match enabled {
|
||||||
false => Stat::DISABLED,
|
false => Stat::DISABLED,
|
||||||
|
@ -576,7 +577,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
}
|
}
|
||||||
EP_IN_WAKERS[ep_addr.index()].wake();
|
EP_IN_WAKERS[ep_addr.index()].wake();
|
||||||
}
|
}
|
||||||
UsbDirection::Out => {
|
Direction::Out => {
|
||||||
loop {
|
loop {
|
||||||
let want_stat = match enabled {
|
let want_stat = match enabled {
|
||||||
false => Stat::DISABLED,
|
false => Stat::DISABLED,
|
||||||
|
@ -616,14 +617,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dir {
|
trait Dir {
|
||||||
fn dir() -> UsbDirection;
|
fn dir() -> Direction;
|
||||||
fn waker(i: usize) -> &'static AtomicWaker;
|
fn waker(i: usize) -> &'static AtomicWaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum In {}
|
pub enum In {}
|
||||||
impl Dir for In {
|
impl Dir for In {
|
||||||
fn dir() -> UsbDirection {
|
fn dir() -> Direction {
|
||||||
UsbDirection::In
|
Direction::In
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -634,8 +635,8 @@ impl Dir for In {
|
||||||
|
|
||||||
pub enum Out {}
|
pub enum Out {}
|
||||||
impl Dir for Out {
|
impl Dir for Out {
|
||||||
fn dir() -> UsbDirection {
|
fn dir() -> Direction {
|
||||||
UsbDirection::Out
|
Direction::Out
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
[package]
|
[package]
|
||||||
name = "embassy-usb-ncm"
|
name = "embassy-usb-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-ncm-v$VERSION/embassy-usb-ncm/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-driver-v$VERSION/embassy-usb/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-ncm/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-driver/src/"
|
||||||
features = ["defmt"]
|
features = ["defmt"]
|
||||||
target = "thumbv7em-none-eabi"
|
target = "thumbv7em-none-eabi"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
|
||||||
embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
|
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
|
@ -1,6 +1,104 @@
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
|
||||||
use super::types::*;
|
/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
|
||||||
|
/// the perspective of the host, which is backward for devices, but the standard directions are used
|
||||||
|
/// for consistency.
|
||||||
|
///
|
||||||
|
/// The values of the enum also match the direction bit used in endpoint addresses and control
|
||||||
|
/// request types.
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Direction {
|
||||||
|
/// Host to device (OUT)
|
||||||
|
Out,
|
||||||
|
/// Device to host (IN)
|
||||||
|
In,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
|
||||||
|
/// transfer bmAttributes transfer type bits.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum EndpointType {
|
||||||
|
/// Control endpoint. Used for device management. Only the host can initiate requests. Usually
|
||||||
|
/// used only endpoint 0.
|
||||||
|
Control = 0b00,
|
||||||
|
/// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
|
||||||
|
Isochronous = 0b01,
|
||||||
|
/// Bulk endpoint. Used for large amounts of best-effort reliable data.
|
||||||
|
Bulk = 0b10,
|
||||||
|
/// Interrupt endpoint. Used for small amounts of time-critical reliable data.
|
||||||
|
Interrupt = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type-safe endpoint address.
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct EndpointAddress(u8);
|
||||||
|
|
||||||
|
impl From<u8> for EndpointAddress {
|
||||||
|
#[inline]
|
||||||
|
fn from(addr: u8) -> EndpointAddress {
|
||||||
|
EndpointAddress(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EndpointAddress> for u8 {
|
||||||
|
#[inline]
|
||||||
|
fn from(addr: EndpointAddress) -> u8 {
|
||||||
|
addr.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EndpointAddress {
|
||||||
|
const INBITS: u8 = Direction::In as u8;
|
||||||
|
|
||||||
|
/// Constructs a new EndpointAddress with the given index and direction.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_parts(index: usize, dir: Direction) -> Self {
|
||||||
|
EndpointAddress(index as u8 | dir as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the direction part of the address.
|
||||||
|
#[inline]
|
||||||
|
pub fn direction(&self) -> Direction {
|
||||||
|
if (self.0 & Self::INBITS) != 0 {
|
||||||
|
Direction::In
|
||||||
|
} else {
|
||||||
|
Direction::Out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the direction is IN, otherwise false.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_in(&self) -> bool {
|
||||||
|
(self.0 & Self::INBITS) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the direction is OUT, otherwise false.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_out(&self) -> bool {
|
||||||
|
(self.0 & Self::INBITS) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the index part of the endpoint address.
|
||||||
|
#[inline]
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
(self.0 & !Self::INBITS) as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct EndpointInfo {
|
||||||
|
pub addr: EndpointAddress,
|
||||||
|
pub ep_type: EndpointType,
|
||||||
|
pub max_packet_size: u16,
|
||||||
|
pub interval: u8,
|
||||||
|
}
|
||||||
|
|
||||||
/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
|
/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
|
||||||
/// platform.
|
/// platform.
|
|
@ -1,24 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "embassy-usb-hid"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-hid-v$VERSION/embassy-usb-hid/src/"
|
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-hid/src/"
|
|
||||||
features = ["defmt"]
|
|
||||||
target = "thumbv7em-none-eabi"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["usbd-hid"]
|
|
||||||
usbd-hid = ["dep:usbd-hid", "ssmarshal"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
|
||||||
embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
|
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
|
||||||
log = { version = "0.4.14", optional = true }
|
|
||||||
usbd-hid = { version = "0.6.0", optional = true }
|
|
||||||
ssmarshal = { version = "1.0", default-features = false, optional = true }
|
|
||||||
futures-util = { version = "0.3.21", default-features = false }
|
|
|
@ -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<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,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<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,17 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "embassy-usb-serial"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-serial-v$VERSION/embassy-usb-serial/src/"
|
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-serial/src/"
|
|
||||||
features = ["defmt"]
|
|
||||||
target = "thumbv7em-none-eabi"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
|
||||||
embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
|
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
|
||||||
log = { version = "0.4.14", optional = true }
|
|
|
@ -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<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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,9 +9,20 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb/s
|
||||||
features = ["defmt"]
|
features = ["defmt"]
|
||||||
target = "thumbv7em-none-eabi"
|
target = "thumbv7em-none-eabi"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
defmt = ["dep:defmt", "embassy-usb-driver/defmt"]
|
||||||
|
usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
|
||||||
|
default = ["usbd-hid"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
|
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
||||||
|
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
heapless = "0.7.10"
|
heapless = "0.7.10"
|
||||||
|
|
||||||
|
# for HID
|
||||||
|
usbd-hid = { version = "0.6.0", optional = true }
|
||||||
|
ssmarshal = { version = "1.0", default-features = false, optional = true }
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
use super::control::ControlHandler;
|
use crate::control::ControlHandler;
|
||||||
use super::descriptor::{BosWriter, DescriptorWriter};
|
use crate::descriptor::{BosWriter, DescriptorWriter};
|
||||||
use super::driver::{Driver, Endpoint};
|
use crate::driver::{Driver, Endpoint, EndpointType};
|
||||||
use super::types::*;
|
use crate::types::*;
|
||||||
use super::{DeviceStateHandler, UsbDevice, MAX_INTERFACE_COUNT};
|
use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
|
||||||
use crate::{Interface, STRING_INDEX_CUSTOM_START};
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
#![no_std]
|
|
||||||
#![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::cell::Cell;
|
||||||
use core::mem::{self, MaybeUninit};
|
use core::mem::{self, MaybeUninit};
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use embassy_sync::blocking_mutex::CriticalSectionMutex;
|
use embassy_sync::blocking_mutex::CriticalSectionMutex;
|
||||||
use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
|
||||||
use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
||||||
use embassy_usb::types::*;
|
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||||
use embassy_usb::Builder;
|
use crate::types::*;
|
||||||
|
use crate::Builder;
|
||||||
|
|
||||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||||
pub const USB_CLASS_CDC: u8 = 0x02;
|
pub const USB_CLASS_CDC: u8 = 0x02;
|
|
@ -1,15 +1,10 @@
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
// This mod MUST go first, so that the others see its macros.
|
|
||||||
pub(crate) mod fmt;
|
|
||||||
|
|
||||||
use core::intrinsics::copy_nonoverlapping;
|
use core::intrinsics::copy_nonoverlapping;
|
||||||
use core::mem::{size_of, MaybeUninit};
|
use core::mem::{size_of, MaybeUninit};
|
||||||
|
|
||||||
use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
|
||||||
use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||||
use embassy_usb::types::*;
|
use crate::types::*;
|
||||||
use embassy_usb::Builder;
|
use crate::Builder;
|
||||||
|
|
||||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||||
pub const USB_CLASS_CDC: u8 = 0x02;
|
pub const USB_CLASS_CDC: u8 = 0x02;
|
|
@ -1,23 +1,16 @@
|
||||||
#![no_std]
|
|
||||||
#![feature(type_alias_impl_trait)]
|
|
||||||
|
|
||||||
//! Implements HID functionality for a usb-device device.
|
|
||||||
|
|
||||||
// This mod MUST go first, so that the others see its macros.
|
|
||||||
pub(crate) mod fmt;
|
|
||||||
|
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use embassy_usb::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
|
|
||||||
use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
|
||||||
use embassy_usb::Builder;
|
|
||||||
#[cfg(feature = "usbd-hid")]
|
#[cfg(feature = "usbd-hid")]
|
||||||
use ssmarshal::serialize;
|
use ssmarshal::serialize;
|
||||||
#[cfg(feature = "usbd-hid")]
|
#[cfg(feature = "usbd-hid")]
|
||||||
use usbd_hid::descriptor::AsInputReport;
|
use usbd_hid::descriptor::AsInputReport;
|
||||||
|
|
||||||
|
use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
|
||||||
|
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
||||||
|
use crate::Builder;
|
||||||
|
|
||||||
const USB_CLASS_HID: u8 = 0x03;
|
const USB_CLASS_HID: u8 = 0x03;
|
||||||
const USB_SUBCLASS_NONE: u8 = 0x00;
|
const USB_SUBCLASS_NONE: u8 = 0x00;
|
||||||
const USB_PROTOCOL_NONE: u8 = 0x00;
|
const USB_PROTOCOL_NONE: u8 = 0x00;
|
||||||
|
@ -204,9 +197,9 @@ pub enum ReadError {
|
||||||
Sync(Range<usize>),
|
Sync(Range<usize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<embassy_usb::driver::EndpointError> for ReadError {
|
impl From<EndpointError> for ReadError {
|
||||||
fn from(val: embassy_usb::driver::EndpointError) -> Self {
|
fn from(val: EndpointError) -> Self {
|
||||||
use embassy_usb::driver::EndpointError::*;
|
use EndpointError::*;
|
||||||
match val {
|
match val {
|
||||||
BufferOverflow => ReadError::BufferOverflow,
|
BufferOverflow => ReadError::BufferOverflow,
|
||||||
Disabled => ReadError::Disabled,
|
Disabled => ReadError::Disabled,
|
||||||
|
@ -437,7 +430,7 @@ impl<'d> ControlHandler for Control<'d> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse {
|
fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
|
||||||
trace!("HID control_out {:?} {=[u8]:x}", req, data);
|
trace!("HID control_out {:?} {=[u8]:x}", req, data);
|
||||||
if let RequestType::Class = req.request_type {
|
if let RequestType::Class = req.request_type {
|
||||||
match req.request {
|
match req.request {
|
3
embassy-usb/src/class/mod.rs
Normal file
3
embassy-usb/src/class/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod cdc_acm;
|
||||||
|
pub mod cdc_ncm;
|
||||||
|
pub mod hid;
|
|
@ -1,7 +1,8 @@
|
||||||
//! USB control data types.
|
//! USB control data types.
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use super::types::*;
|
use crate::driver::Direction;
|
||||||
|
use crate::types::StringIndex;
|
||||||
|
|
||||||
/// Control request type.
|
/// Control request type.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -42,7 +43,7 @@ pub enum Recipient {
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
/// Direction of the request.
|
/// Direction of the request.
|
||||||
pub direction: UsbDirection,
|
pub direction: Direction,
|
||||||
/// Type of the request.
|
/// Type of the request.
|
||||||
pub request_type: RequestType,
|
pub request_type: RequestType,
|
||||||
/// Recipient of the request.
|
/// Recipient of the request.
|
||||||
|
@ -105,7 +106,7 @@ impl Request {
|
||||||
let recipient = rt & 0b11111;
|
let recipient = rt & 0b11111;
|
||||||
|
|
||||||
Request {
|
Request {
|
||||||
direction: rt.into(),
|
direction: if rt & 0x80 == 0 { Direction::Out } else { Direction::In },
|
||||||
request_type: unsafe { mem::transmute((rt >> 5) & 0b11) },
|
request_type: unsafe { mem::transmute((rt >> 5) & 0b11) },
|
||||||
recipient: if recipient <= 3 {
|
recipient: if recipient <= 3 {
|
||||||
unsafe { mem::transmute(recipient) }
|
unsafe { mem::transmute(recipient) }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::builder::Config;
|
use crate::builder::Config;
|
||||||
use super::types::*;
|
use crate::driver::EndpointInfo;
|
||||||
use super::CONFIGURATION_VALUE;
|
use crate::types::*;
|
||||||
|
use crate::CONFIGURATION_VALUE;
|
||||||
|
|
||||||
/// Standard descriptor types
|
/// Standard descriptor types
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::descriptor::descriptor_type;
|
use crate::descriptor::descriptor_type;
|
||||||
use crate::types::EndpointAddress;
|
use crate::driver::EndpointAddress;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
|
|
@ -4,23 +4,24 @@
|
||||||
// This mod MUST go first, so that the others see its macros.
|
// This mod MUST go first, so that the others see its macros.
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
|
||||||
|
pub use embassy_usb_driver as driver;
|
||||||
|
|
||||||
mod builder;
|
mod builder;
|
||||||
|
pub mod class;
|
||||||
pub mod control;
|
pub mod control;
|
||||||
pub mod descriptor;
|
pub mod descriptor;
|
||||||
mod descriptor_reader;
|
mod descriptor_reader;
|
||||||
pub mod driver;
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
pub use self::builder::{Builder, Config};
|
pub use crate::builder::{Builder, Config};
|
||||||
use self::control::*;
|
use crate::control::*;
|
||||||
use self::descriptor::*;
|
use crate::descriptor::*;
|
||||||
use self::driver::{Bus, Driver, Event};
|
|
||||||
use self::types::*;
|
|
||||||
use crate::descriptor_reader::foreach_endpoint;
|
use crate::descriptor_reader::foreach_endpoint;
|
||||||
use crate::driver::ControlPipe;
|
use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
/// The global state of the USB device.
|
/// The global state of the USB device.
|
||||||
///
|
///
|
||||||
|
@ -250,8 +251,8 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
||||||
trace!("control request: {:?}", req);
|
trace!("control request: {:?}", req);
|
||||||
|
|
||||||
match req.direction {
|
match req.direction {
|
||||||
UsbDirection::In => self.handle_control_in(req).await,
|
Direction::In => self.handle_control_in(req).await,
|
||||||
UsbDirection::Out => self.handle_control_out(req).await,
|
Direction::Out => self.handle_control_out(req).await,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.inner.set_address_pending {
|
if self.inner.set_address_pending {
|
||||||
|
|
|
@ -1,108 +1,3 @@
|
||||||
/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
|
|
||||||
/// the perspective of the host, which is backward for devices, but the standard directions are used
|
|
||||||
/// for consistency.
|
|
||||||
///
|
|
||||||
/// The values of the enum also match the direction bit used in endpoint addresses and control
|
|
||||||
/// request types.
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum UsbDirection {
|
|
||||||
/// Host to device (OUT)
|
|
||||||
Out = 0x00,
|
|
||||||
/// Device to host (IN)
|
|
||||||
In = 0x80,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for UsbDirection {
|
|
||||||
fn from(value: u8) -> Self {
|
|
||||||
unsafe { core::mem::transmute(value & 0x80) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
|
|
||||||
/// transfer bmAttributes transfer type bits.
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum EndpointType {
|
|
||||||
/// Control endpoint. Used for device management. Only the host can initiate requests. Usually
|
|
||||||
/// used only endpoint 0.
|
|
||||||
Control = 0b00,
|
|
||||||
/// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
|
|
||||||
Isochronous = 0b01,
|
|
||||||
/// Bulk endpoint. Used for large amounts of best-effort reliable data.
|
|
||||||
Bulk = 0b10,
|
|
||||||
/// Interrupt endpoint. Used for small amounts of time-critical reliable data.
|
|
||||||
Interrupt = 0b11,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Type-safe endpoint address.
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub struct EndpointAddress(u8);
|
|
||||||
|
|
||||||
impl From<u8> for EndpointAddress {
|
|
||||||
#[inline]
|
|
||||||
fn from(addr: u8) -> EndpointAddress {
|
|
||||||
EndpointAddress(addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EndpointAddress> for u8 {
|
|
||||||
#[inline]
|
|
||||||
fn from(addr: EndpointAddress) -> u8 {
|
|
||||||
addr.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EndpointAddress {
|
|
||||||
const INBITS: u8 = UsbDirection::In as u8;
|
|
||||||
|
|
||||||
/// Constructs a new EndpointAddress with the given index and direction.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_parts(index: usize, dir: UsbDirection) -> Self {
|
|
||||||
EndpointAddress(index as u8 | dir as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the direction part of the address.
|
|
||||||
#[inline]
|
|
||||||
pub fn direction(&self) -> UsbDirection {
|
|
||||||
if (self.0 & Self::INBITS) != 0 {
|
|
||||||
UsbDirection::In
|
|
||||||
} else {
|
|
||||||
UsbDirection::Out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the direction is IN, otherwise false.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_in(&self) -> bool {
|
|
||||||
(self.0 & Self::INBITS) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the direction is OUT, otherwise false.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_out(&self) -> bool {
|
|
||||||
(self.0 & Self::INBITS) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the index part of the endpoint address.
|
|
||||||
#[inline]
|
|
||||||
pub fn index(&self) -> usize {
|
|
||||||
(self.0 & !Self::INBITS) as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub struct EndpointInfo {
|
|
||||||
pub addr: EndpointAddress,
|
|
||||||
pub ep_type: EndpointType,
|
|
||||||
pub max_packet_size: u16,
|
|
||||||
pub interval: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A handle for a USB interface that contains its number.
|
/// A handle for a USB interface that contains its number.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
|
|
@ -5,7 +5,7 @@ version = "0.1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["nightly"]
|
default = ["nightly"]
|
||||||
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"]
|
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
@ -15,9 +15,6 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
|
||||||
embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true }
|
|
||||||
embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true }
|
|
||||||
embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true }
|
|
||||||
embedded-io = "0.3.0"
|
embedded-io = "0.3.0"
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
|
|
@ -15,8 +15,8 @@ use embassy_nrf::usb::{Driver, PowerUsb};
|
||||||
use embassy_nrf::{interrupt, pac, peripherals};
|
use embassy_nrf::{interrupt, pac, peripherals};
|
||||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
|
use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
|
|
||||||
use embedded_io::asynch::Write;
|
use embedded_io::asynch::Write;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
|
@ -14,9 +14,9 @@ use embassy_nrf::usb::{Driver, PowerUsb};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::{interrupt, pac};
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::signal::Signal;
|
use embassy_sync::signal::Signal;
|
||||||
|
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
||||||
use embassy_usb::control::OutResponse;
|
use embassy_usb::control::OutResponse;
|
||||||
use embassy_usb::{Builder, Config, DeviceStateHandler};
|
use embassy_usb::{Builder, Config, DeviceStateHandler};
|
||||||
use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
|
||||||
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create classes on the builder.
|
// Create classes on the builder.
|
||||||
let config = embassy_usb_hid::Config {
|
let config = embassy_usb::class::hid::Config {
|
||||||
report_descriptor: KeyboardReport::desc(),
|
report_descriptor: KeyboardReport::desc(),
|
||||||
request_handler: Some(&request_handler),
|
request_handler: Some(&request_handler),
|
||||||
poll_ms: 60,
|
poll_ms: 60,
|
||||||
|
|
|
@ -10,9 +10,9 @@ use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, PowerUsb};
|
use embassy_nrf::usb::{Driver, PowerUsb};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::{interrupt, pac};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
||||||
use embassy_usb::control::OutResponse;
|
use embassy_usb::control::OutResponse;
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
|
|
||||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create classes on the builder.
|
// Create classes on the builder.
|
||||||
let config = embassy_usb_hid::Config {
|
let config = embassy_usb::class::hid::Config {
|
||||||
report_descriptor: MouseReport::desc(),
|
report_descriptor: MouseReport::desc(),
|
||||||
request_handler: Some(&request_handler),
|
request_handler: Some(&request_handler),
|
||||||
poll_ms: 60,
|
poll_ms: 60,
|
||||||
|
|
|
@ -9,9 +9,9 @@ use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply};
|
use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::{interrupt, pac};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
|
|
@ -8,9 +8,9 @@ use defmt::{info, panic, unwrap};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::usb::{Driver, PowerUsb};
|
use embassy_nrf::usb::{Driver, PowerUsb};
|
||||||
use embassy_nrf::{interrupt, pac, peripherals};
|
use embassy_nrf::{interrupt, pac, peripherals};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] }
|
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
|
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
||||||
embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] }
|
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
|
|
@ -13,8 +13,8 @@ use embassy_rp::usb::Driver;
|
||||||
use embassy_rp::{interrupt, peripherals};
|
use embassy_rp::{interrupt, peripherals};
|
||||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
|
use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
|
|
||||||
use embedded_io::asynch::Write;
|
use embedded_io::asynch::Write;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
|
@ -7,9 +7,9 @@ use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_rp::interrupt;
|
use embassy_rp::interrupt;
|
||||||
use embassy_rp::usb::{Driver, Instance};
|
use embassy_rp::usb::{Driver, Instance};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
|
|
@ -9,7 +9,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
|
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
|
|
@ -10,9 +10,9 @@ use embassy_stm32::time::Hertz;
|
||||||
use embassy_stm32::usb::{Driver, Instance};
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
use embassy_stm32::{interrupt, Config};
|
use embassy_stm32::{interrupt, Config};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::Builder;
|
use embassy_usb::Builder;
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
|
|
@ -9,8 +9,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
|
|
||||||
embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
|
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
|
|
@ -10,9 +10,9 @@ use embassy_stm32::time::mhz;
|
||||||
use embassy_stm32::usb::{Driver, Instance};
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
use embassy_stm32::{interrupt, Config};
|
use embassy_stm32::{interrupt, Config};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::Builder;
|
use embassy_usb::Builder;
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
|
|
@ -11,9 +11,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
|
|
||||||
embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
|
|
||||||
embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] }
|
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
usbd-hid = "0.6.0"
|
usbd-hid = "0.6.0"
|
||||||
|
|
|
@ -15,8 +15,8 @@ use embassy_stm32::usb::Driver;
|
||||||
use embassy_stm32::{interrupt, Config};
|
use embassy_stm32::{interrupt, Config};
|
||||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
|
use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
|
||||||
use embassy_usb::{Builder, UsbDevice};
|
use embassy_usb::{Builder, UsbDevice};
|
||||||
use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
|
|
||||||
use embedded_io::asynch::Write;
|
use embedded_io::asynch::Write;
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
|
|
@ -9,9 +9,9 @@ use embassy_stm32::rcc::*;
|
||||||
use embassy_stm32::usb::Driver;
|
use embassy_stm32::usb::Driver;
|
||||||
use embassy_stm32::{interrupt, Config};
|
use embassy_stm32::{interrupt, Config};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
||||||
use embassy_usb::control::OutResponse;
|
use embassy_usb::control::OutResponse;
|
||||||
use embassy_usb::Builder;
|
use embassy_usb::Builder;
|
||||||
use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
|
|
||||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create classes on the builder.
|
// Create classes on the builder.
|
||||||
let config = embassy_usb_hid::Config {
|
let config = embassy_usb::class::hid::Config {
|
||||||
report_descriptor: MouseReport::desc(),
|
report_descriptor: MouseReport::desc(),
|
||||||
request_handler: Some(&request_handler),
|
request_handler: Some(&request_handler),
|
||||||
poll_ms: 60,
|
poll_ms: 60,
|
||||||
|
|
|
@ -8,9 +8,9 @@ use embassy_futures::join::join;
|
||||||
use embassy_stm32::rcc::*;
|
use embassy_stm32::rcc::*;
|
||||||
use embassy_stm32::usb::{Driver, Instance};
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
use embassy_stm32::{interrupt, Config};
|
use embassy_stm32::{interrupt, Config};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::Builder;
|
use embassy_usb::Builder;
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
|
Loading…
Reference in a new issue