use core::ops::Deref;
use bbqueue::{BBBuffer, Consumer, Producer};
use nrf52840_hal::{usbd::{Usbd, UsbPeripheral}, pac::USBD};
use usb_device::{device::UsbDevice, UsbError};
use usbd_serial::SerialPort;
use heapless::{LinearMap, Deque, Vec};
use crate::alloc::{HeapArray, HEAP};
use postcard::{CobsAccumulator, FeedResult};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Chunk {
port: u16,
buf: Vec<u8, 128>,
}
const USB_BUF_SZ: usize = 4096;
static UART_INC: BBBuffer<USB_BUF_SZ> = BBBuffer::new();
static UART_OUT: BBBuffer<USB_BUF_SZ> = BBBuffer::new();
pub type AUsbPeripheral = Usbd<UsbPeripheral<'static>>;
pub type AUsbDevice = UsbDevice<'static, AUsbPeripheral>;
pub type ASerialPort = SerialPort<'static, AUsbPeripheral>;
pub struct UsbUartIsr {
dev: AUsbDevice,
ser: ASerialPort,
out: Consumer<'static, USB_BUF_SZ>,
inc: Producer<'static, USB_BUF_SZ>,
}
impl UsbUartIsr {
pub fn poll(&mut self) {
self.dev.poll(&mut [&mut self.ser]);
if let Ok(rgr) = self.out.read() {
match self.ser.write(&rgr) {
Ok(sz) if sz > 0 => {
rgr.release(sz);
},
Ok(_) | Err(UsbError::WouldBlock) => {
}
Err(_) => defmt::panic!("Usb Error Write!"),
}
}
if let Ok(mut wgr) = self.inc.grant_max_remaining(128) {
match self.ser.read(&mut wgr) {
Ok(sz) if sz > 0 => {
wgr.commit(sz);
},
Ok(_) | Err(UsbError::WouldBlock) => {
}
Err(_) => defmt::panic!("Usb Error Read!"),
}
}
}
}
pub struct UsbUartSys {
out: Producer<'static, USB_BUF_SZ>,
inc: Consumer<'static, USB_BUF_SZ>,
acc: CobsAccumulator<256>,
ports: LinearMap<u16, Deque<HeapArray<u8>, 16>, 8>,
}
pub struct UsbUartParts {
pub isr: UsbUartIsr,
pub sys: UsbUartSys,
}
pub fn setup_usb_uart(dev: AUsbDevice, ser: ASerialPort) -> Result<UsbUartParts, ()> {
let (inc_prod, inc_cons) = UART_INC.try_split().map_err(drop)?;
let (out_prod, out_cons) = UART_OUT.try_split().map_err(drop)?;
let mut ports = LinearMap::new();
ports.insert(0, Deque::new()).ok();
Ok(UsbUartParts {
isr: UsbUartIsr {
dev,
ser,
out: out_cons,
inc: inc_prod,
},
sys: UsbUartSys {
out: out_prod,
inc: inc_cons,
acc: CobsAccumulator::new(),
ports,
}
})
}
impl crate::traits::Serial for UsbUartSys {
fn register_port(&mut self, port: u16) -> Result<(), ()> {
if self.ports.contains_key(&port) {
return Err(());
}
self.ports.insert(port, Deque::new()).map_err(drop)?;
defmt::println!("Registered port {=u16}!", port);
Ok(())
}
fn release_port(&mut self, port: u16) -> Result<(), ()> {
if port == 0 {
return Err(());
}
if self.ports.remove(&port).is_some() {
Ok(())
} else {
Err(())
}
}
fn process(&mut self) {
while let Ok(rgr) = self.inc.read() {
let mut window = rgr.deref();
let rec_len = rgr.len();
while !window.is_empty() {
match self.acc.feed::<Chunk>(window) {
FeedResult::Consumed => {
window = &[];
},
FeedResult::OverFull(rem) => {
defmt::println!("Overfull error!");
window = rem;
},
FeedResult::DeserError(rem) => {
defmt::println!("Chunk deser error!");
window = rem;
},
FeedResult::Success { data, remaining } => {
window = remaining;
let failed = self.ports
.get_mut(&data.port)
.and_then(|dq| {
let mut hp = HEAP.try_lock()?;
let habox = hp.alloc_box_array(0u8, data.buf.len()).ok()?;
Some((dq, habox))
})
.and_then(|(dq, mut habox)| {
habox.copy_from_slice(&data.buf);
dq.push_back(habox).ok()
}).is_none();
if failed && self.ports.contains_key(&data.port) {
defmt::println!("Failed to receive message for serial port {=u16}. Discarding.", data.port);
}
},
}
}
rgr.release(rec_len);
}
}
fn recv<'a>(&mut self, port: u16, buf: &'a mut [u8]) -> Result<&'a mut [u8], ()> {
self.process();
let deq = self.ports.get_mut(&port).ok_or(())?;
let mut used = 0;
let buflen = buf.len();
while used < buf.len() {
let msg = match deq.pop_front() {
None => {
return Ok(&mut buf[..used]);
}
Some(msg) => msg,
};
let avail = buflen - used;
if msg.len() <= avail {
buf[used..][..msg.len()].copy_from_slice(&msg);
used += msg.len();
} else {
let (now, later) = msg.split_at(avail);
buf[used..].copy_from_slice(now);
let mut hp = defmt::unwrap!(HEAP.try_lock());
let mut habox = defmt::unwrap!(hp.alloc_box_array(0u8, later.len()).ok());
habox.copy_from_slice(later);
deq.push_front(habox).ok();
used += avail;
}
}
Ok(buf)
}
fn send<'a>(&mut self, port: u16, buf: &'a [u8]) -> Result<(), &'a [u8]> {
if !self.ports.contains_key(&port) {
defmt::println!("Unregistered port: {=u16}", port);
return Err(buf);
}
let mut used = 0;
for ch in buf.chunks(128) {
let mut dunk = Vec::new();
dunk.extend_from_slice(ch).ok();
let msg = Chunk { port, buf: dunk };
match self.out.grant_exact(256) {
Ok(mut wgr) => {
let enc_used = postcard::to_slice_cobs(&msg, &mut wgr).unwrap().len();
wgr.commit(enc_used);
used += ch.len();
},
Err(_) => {
return Err(&buf[..used]);
},
}
}
Ok(())
}
}
pub fn enable_usb_interrupts(usbd: &USBD) {
usbd.intenset.write(|w| {
w.endepin0().set_bit();
w.endepin1().set_bit();
w.endepin2().set_bit();
w.endepin3().set_bit();
w.endepin4().set_bit();
w.endepin5().set_bit();
w.endepin6().set_bit();
w.endepin7().set_bit();
w.endepout0().set_bit();
w.endepout1().set_bit();
w.endepout2().set_bit();
w.endepout3().set_bit();
w.endepout4().set_bit();
w.endepout5().set_bit();
w.endepout6().set_bit();
w.endepout7().set_bit();
w.ep0datadone().set_bit();
w.ep0setup().set_bit();
w.sof().set_bit();
w.usbevent().set_bit();
w.usbreset().set_bit();
w
});
}