use super::driver::Driver;
use crate::gpt;
use core::cell::RefCell;
use cortex_m::interrupt::{self, Mutex};
use usb_device::{
UsbDirection,
bus::{PollResult, UsbBus},
endpoint::{EndpointAddress, EndpointType},
};
pub use super::driver::Speed;
pub struct BusAdapter {
usb: Mutex<RefCell<Driver>>,
cs: Option<cortex_m::interrupt::CriticalSection>,
}
impl BusAdapter {
pub fn new<const N: u8, const SIZE: usize, const EP_COUNT: usize>(
instances: crate::Instances<N>,
buffer: &'static crate::buffer::EndpointMemory<SIZE>,
state: &'static crate::state::EndpointState<EP_COUNT>,
) -> Self {
Self::with_speed(instances, buffer, state, Speed::High)
}
pub fn with_speed<const N: u8, const SIZE: usize, const EP_COUNT: usize>(
instances: crate::Instances<N>,
buffer: &'static crate::buffer::EndpointMemory<SIZE>,
state: &'static crate::state::EndpointState<EP_COUNT>,
speed: Speed,
) -> Self {
Self::init(instances, buffer, state, speed, None)
}
pub unsafe fn without_critical_sections<
const N: u8,
const SIZE: usize,
const EP_COUNT: usize,
>(
instances: crate::Instances<N>,
buffer: &'static crate::buffer::EndpointMemory<SIZE>,
state: &'static crate::state::EndpointState<EP_COUNT>,
speed: Speed,
) -> Self {
Self::init(
instances,
buffer,
state,
speed,
Some(unsafe { cortex_m::interrupt::CriticalSection::new() }),
)
}
fn init<const N: u8, const SIZE: usize, const EP_COUNT: usize>(
instances: crate::Instances<N>,
buffer: &'static crate::buffer::EndpointMemory<SIZE>,
state: &'static crate::state::EndpointState<EP_COUNT>,
speed: Speed,
cs: Option<cortex_m::interrupt::CriticalSection>,
) -> Self {
let mut usb = Driver::new(instances, buffer, state);
usb.initialize(speed);
BusAdapter {
usb: Mutex::new(RefCell::new(usb)),
cs,
}
}
pub fn set_interrupts(&self, interrupts: bool) {
self.with_usb_mut(|usb| usb.set_interrupts(interrupts));
}
pub fn enable_zlt(&self, ep_addr: EndpointAddress) {
self.with_usb_mut(|usb| usb.enable_zlt(ep_addr));
}
fn with_usb<R>(&self, func: impl FnOnce(&Driver) -> R) -> R {
let with_cs = |cs: &'_ _| {
let usb = self.usb.borrow(cs);
let usb = usb.borrow();
func(&usb)
};
if let Some(cs) = &self.cs {
with_cs(cs)
} else {
interrupt::free(with_cs)
}
}
fn with_usb_mut<R>(&self, func: impl FnOnce(&mut Driver) -> R) -> R {
let with_cs = |cs: &'_ _| {
let usb = self.usb.borrow(cs);
let mut usb = usb.borrow_mut();
func(&mut usb)
};
if let Some(cs) = &self.cs {
with_cs(cs)
} else {
interrupt::free(with_cs)
}
}
pub fn configure(&self) {
self.with_usb_mut(|usb| {
usb.on_configured();
debug!("CONFIGURED");
});
}
pub fn gpt_mut<R>(&self, instance: gpt::Instance, func: impl FnOnce(&mut gpt::Gpt) -> R) -> R {
self.with_usb_mut(|usb| usb.gpt_mut(instance, func))
}
}
impl UsbBus for BusAdapter {
const QUIRK_SET_ADDRESS_BEFORE_STATUS: bool = true;
fn alloc_ep(
&mut self,
ep_dir: UsbDirection,
ep_addr: Option<EndpointAddress>,
ep_type: EndpointType,
max_packet_size: u16,
_interval: u8,
) -> usb_device::Result<EndpointAddress> {
self.with_usb_mut(|usb| {
if let Some(addr) = ep_addr {
if usb.is_allocated(addr) {
return Err(usb_device::UsbError::InvalidEndpoint);
}
let buffer = usb
.allocate_buffer(max_packet_size as usize)
.ok_or(usb_device::UsbError::EndpointMemoryOverflow)?;
usb.allocate_ep(addr, buffer, ep_type);
Ok(addr)
} else {
for idx in 1..8 {
let addr = EndpointAddress::from_parts(idx, ep_dir);
if usb.is_allocated(addr) {
continue;
}
let buffer = usb
.allocate_buffer(max_packet_size as usize)
.ok_or(usb_device::UsbError::EndpointMemoryOverflow)?;
usb.allocate_ep(addr, buffer, ep_type);
return Ok(addr);
}
Err(usb_device::UsbError::EndpointOverflow)
}
})
}
fn set_device_address(&self, addr: u8) {
self.with_usb_mut(|usb| {
usb.set_address(addr);
});
}
fn enable(&mut self) {
self.with_usb_mut(|usb| usb.attach());
}
fn reset(&self) {
self.with_usb_mut(|usb| {
usb.bus_reset();
});
}
fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> usb_device::Result<usize> {
self.with_usb_mut(|usb| {
if !usb.is_allocated(ep_addr) {
return Err(usb_device::UsbError::InvalidEndpoint);
}
let written = if ep_addr.index() == 0 {
usb.ctrl0_write(buf)
} else {
usb.ep_write(buf, ep_addr)
}
.inspect_err(|&_status| {
warn!(
"EP{=usize} {} STATUS {}",
ep_addr.index(),
ep_addr.direction(),
_status
);
})?;
Ok(written)
})
}
fn read(&self, ep_addr: EndpointAddress, buf: &mut [u8]) -> usb_device::Result<usize> {
self.with_usb_mut(|usb| {
if !usb.is_allocated(ep_addr) {
return Err(usb_device::UsbError::InvalidEndpoint);
}
let read = if ep_addr.index() == 0 {
usb.ctrl0_read(buf)
} else {
usb.ep_read(buf, ep_addr)
}
.inspect_err(|&_status| {
warn!(
"EP{=usize} {} STATUS {}",
ep_addr.index(),
ep_addr.direction(),
_status
);
})?;
Ok(read)
})
}
fn set_stalled(&self, ep_addr: EndpointAddress, stalled: bool) {
self.with_usb_mut(|usb| {
if usb.is_allocated(ep_addr) {
usb.ep_stall(stalled, ep_addr);
}
});
}
fn is_stalled(&self, ep_addr: EndpointAddress) -> bool {
self.with_usb(|usb| usb.is_ep_stalled(ep_addr))
}
fn suspend(&self) {
}
fn resume(&self) {
}
fn poll(&self) -> PollResult {
self.with_usb_mut(|usb| usb.poll())
}
}