use crate::endpoint_memory::{BufferDescriptor, EndpointBuffer, EndpointMemoryAllocator};
use crate::registers::UsbRegisters;
use crate::UsbPeripheral;
use core::marker::PhantomData;
use core::mem;
use cortex_m::interrupt::{self, CriticalSection, Mutex};
use usb_device::endpoint::EndpointType;
use usb_device::{Result, UsbError};
pub use crate::pac::usb;
pub const NUM_ENDPOINTS: usize = 8;
#[derive(Default)]
pub struct Endpoint<USB> {
out_buf: Option<Mutex<EndpointBuffer<USB>>>,
in_buf: Option<Mutex<EndpointBuffer<USB>>>,
ep_type: Option<EndpointType>,
index: u8,
_marker: PhantomData<USB>,
}
pub fn calculate_count_rx(mut size: usize) -> Result<(usize, u16)> {
if size <= 62 {
size = (size + 1) & !0x01;
let size_bits = size >> 1;
Ok((size, (size_bits << 10) as u16))
} else if size <= 1024 {
size = (size + 31) & !0x1f;
let size_bits = (size >> 5) - 1;
Ok((size, (0x8000 | (size_bits << 10)) as u16))
} else {
Err(UsbError::EndpointMemoryOverflow)
}
}
impl<USB: UsbPeripheral> Endpoint<USB> {
pub fn new(index: u8) -> Self {
Self {
out_buf: None,
in_buf: None,
ep_type: None,
index,
_marker: PhantomData,
}
}
pub fn ep_type(&self) -> Option<EndpointType> {
self.ep_type
}
pub fn set_ep_type(&mut self, ep_type: EndpointType) {
self.ep_type = Some(ep_type);
}
pub fn is_out_buf_set(&self) -> bool {
self.out_buf.is_some()
}
pub fn set_out_buf(&mut self, buffer: EndpointBuffer<USB>, size_bits: u16) {
let offset = buffer.offset();
self.out_buf = Some(Mutex::new(buffer));
let descr = self.descr();
descr.addr_rx().set(offset);
descr.count_rx().set(size_bits);
}
pub fn is_in_buf_set(&self) -> bool {
self.in_buf.is_some()
}
pub fn set_in_buf(&mut self, buffer: EndpointBuffer<USB>) {
let offset = buffer.offset();
self.in_buf = Some(Mutex::new(buffer));
let descr = self.descr();
descr.addr_tx().set(offset);
descr.count_tx().set(0);
}
fn descr(&self) -> BufferDescriptor<USB> {
EndpointMemoryAllocator::<USB>::buffer_descriptor(self.index)
}
fn reg(&self) -> &'static usb::EPR {
UsbRegisters::<USB>::ep_register(self.index)
}
pub fn configure(&self, cs: &CriticalSection) {
let ep_type = match self.ep_type {
Some(t) => t,
None => return,
};
self.reg().modify(|_, w| {
Self::set_invariant_values(w);
w.ctr_rx().clear_bit();
w.ep_type().bits(ep_type.bits());
w.ep_kind().clear_bit();
w.ctr_tx().clear_bit();
w.ea().bits(self.index)
});
self.set_stat_rx(
cs,
if self.out_buf.is_some() {
EndpointStatus::Valid
} else {
EndpointStatus::Disabled
},
);
self.set_stat_tx(
cs,
if self.in_buf.is_some() {
EndpointStatus::Nak
} else {
EndpointStatus::Disabled
},
);
}
pub fn write(&self, buf: &[u8]) -> Result<usize> {
interrupt::free(|cs| {
let in_buf = self.in_buf.as_ref().unwrap().borrow(cs);
if buf.len() > in_buf.capacity() {
return Err(UsbError::BufferOverflow);
}
let reg = self.reg();
match reg.read().stat_tx().bits().into() {
EndpointStatus::Valid | EndpointStatus::Disabled => return Err(UsbError::WouldBlock),
_ => {}
};
in_buf.write(buf);
self.descr().count_tx().set(buf.len() as u16);
self.set_stat_tx(cs, EndpointStatus::Valid);
Ok(buf.len())
})
}
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
interrupt::free(|cs| {
let out_buf = self.out_buf.as_ref().unwrap().borrow(cs);
let reg_v = self.reg().read();
let status: EndpointStatus = reg_v.stat_rx().bits().into();
if status == EndpointStatus::Disabled || !reg_v.ctr_rx().bit_is_set() {
return Err(UsbError::WouldBlock);
}
self.clear_ctr_rx(cs);
let count = (self.descr().count_rx().get() & 0x3ff) as usize;
if count > buf.len() {
return Err(UsbError::BufferOverflow);
}
out_buf.read(&mut buf[0..count]);
self.set_stat_rx(cs, EndpointStatus::Valid);
Ok(count)
})
}
pub fn read_reg(&self) -> usb::epr::R {
self.reg().read()
}
fn set_invariant_values(w: &mut usb::epr::W) -> &mut usb::epr::W {
w.ctr_rx().set_bit();
w.dtog_rx().clear_bit();
w.stat_rx().bits(0);
w.ctr_tx().set_bit();
w.dtog_tx().clear_bit();
w.stat_tx().bits(0)
}
pub fn clear_ctr_rx(&self, _cs: &CriticalSection) {
self.reg()
.modify(|_, w| Self::set_invariant_values(w).ctr_rx().clear_bit());
}
pub fn clear_ctr_tx(&self, _cs: &CriticalSection) {
self.reg()
.modify(|_, w| Self::set_invariant_values(w).ctr_tx().clear_bit());
}
pub fn set_stat_rx(&self, _cs: &CriticalSection, status: EndpointStatus) {
self.reg().modify(|r, w| {
Self::set_invariant_values(w)
.stat_rx()
.bits(r.stat_rx().bits() ^ (status as u8))
});
}
pub fn set_stat_tx(&self, _cs: &CriticalSection, status: EndpointStatus) {
self.reg().modify(|r, w| {
Self::set_invariant_values(w)
.stat_tx()
.bits(r.stat_tx().bits() ^ (status as u8))
});
}
}
trait EndpointTypeExt {
fn bits(self) -> u8;
}
impl EndpointTypeExt for EndpointType {
fn bits(self) -> u8 {
const BITS: [u8; 4] = [0b01, 0b10, 0b00, 0b11];
let transfer_type = self.to_bm_attributes() & 0b11;
return BITS[transfer_type as usize];
}
}
#[repr(u8)]
#[derive(PartialEq, Eq, Debug)]
#[allow(unused)]
pub enum EndpointStatus {
Disabled = 0b00,
Stall = 0b01,
Nak = 0b10,
Valid = 0b11,
}
impl From<u8> for EndpointStatus {
fn from(v: u8) -> EndpointStatus {
if v <= 0b11 {
unsafe { mem::transmute(v) }
} else {
EndpointStatus::Disabled
}
}
}