#![no_std]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, AtomicU16, Ordering};
use core::task::Poll;
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver as driver;
use embassy_usb_driver::{
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
};
mod fmt;
pub mod regs;
pub use regs::common;
pub use regs::info::*;
mod endpoint;
pub use endpoint::Endpoint;
use endpoint::{EndpointData, EndPointConfig};
#[path ="driver.rs"]
mod usb_driver;
pub use usb_driver::MusbDriver;
mod bus;
pub use bus::Bus;
mod control_pipe;
pub use control_pipe::ControlPipe;
const NEW_AW: AtomicWaker = AtomicWaker::new();
static BUS_WAKER: AtomicWaker = NEW_AW;
static EP_TX_WAKERS: [AtomicWaker; ENDPOINTS_NUM] = [NEW_AW; ENDPOINTS_NUM];
static EP_RX_WAKERS: [AtomicWaker; ENDPOINTS_NUM] = [NEW_AW; ENDPOINTS_NUM];
static IRQ_RESET: AtomicBool = AtomicBool::new(false);
static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false);
static IRQ_RESUME: AtomicBool = AtomicBool::new(false);
static EP_TX_ENABLED: AtomicU16 = AtomicU16::new(0);
static EP_RX_ENABLED: AtomicU16 = AtomicU16::new(0);
fn calc_max_fifo_size_dword(len: u16) -> u16 {
let dwords = ((len + 7) / 8) as u16;
if dwords > 8 {
panic!("Invalid length: {}", len);
}
dwords
}
pub struct InterruptHandler<T: MusbInstance> {
_phantom: PhantomData<T>,
}
pub unsafe fn on_interrupt<T: MusbInstance>() {
let intrusb = T::regs().intrusb().read();
if intrusb.reset() {
IRQ_RESET.store(true, Ordering::SeqCst);
BUS_WAKER.wake();
}
if intrusb.suspend() {
IRQ_SUSPEND.store(true, Ordering::SeqCst);
BUS_WAKER.wake();
}
if intrusb.resume() {
IRQ_RESUME.store(true, Ordering::SeqCst);
BUS_WAKER.wake();
}
let intrtx = T::regs().intrtx().read();
let intrrx = T::regs().intrrx().read();
if intrtx.ep_tx(0) {
EP_TX_WAKERS[0].wake();
EP_RX_WAKERS[0].wake();
}
for index in 1..ENDPOINTS_NUM {
if intrtx.ep_tx(index) {
EP_TX_WAKERS[index].wake();
}
if intrrx.ep_rx(index) {
EP_RX_WAKERS[index].wake();
}
if T::regs().txcsrl().read().under_run(){
T::regs().txcsrl().modify(|w| w.set_under_run(false));
warn!("Underrun: ep {}", index);
}
}
}
pub trait Dir {
fn dir() -> Direction;
}
pub enum In {}
impl Dir for In {
fn dir() -> Direction {
Direction::In
}
}
pub enum Out {}
impl Dir for Out {
fn dir() -> Direction {
Direction::Out
}
}
pub trait MusbInstance: 'static {
fn regs() -> regs::Usb;
}