use core::borrow::BorrowMut;
use core::mem;
use core::slice;
use usb_device::class_prelude::*;
use usb_device::Result;
use crate::cdc_acm::*;
use crate::buffer::{Buffer, DefaultBufferStore};
pub struct SerialPort<'a, B, RS=DefaultBufferStore, WS=DefaultBufferStore>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
inner: CdcAcmClass<'a, B>,
read_buf: Buffer<RS>,
write_buf: Buffer<WS>,
write_state: WriteState,
}
const SHORT_PACKET_INTERVAL: usize = 10;
enum WriteState {
Idle,
Short,
Full(usize),
}
impl<B> SerialPort<'_, B>
where
B: UsbBus
{
pub fn new(alloc: &UsbBusAllocator<B>)
-> SerialPort<'_, B, DefaultBufferStore, DefaultBufferStore>
{
SerialPort::new_with_store(
alloc,
unsafe { mem::uninitialized() },
unsafe { mem::uninitialized() })
}
}
impl<B, RS, WS> SerialPort<'_, B, RS, WS>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
pub fn new_with_store(alloc: &UsbBusAllocator<B>, read_store: RS, write_store: WS)
-> SerialPort<'_, B, RS, WS>
{
SerialPort {
inner: CdcAcmClass::new(alloc, 64),
read_buf: Buffer::new(read_store),
write_buf: Buffer::new(write_store),
write_state: WriteState::Idle,
}
}
pub fn line_coding(&self) -> &LineCoding { self.inner.line_coding() }
pub fn dtr(&self) -> bool { self.inner.dtr() }
pub fn rts(&self) -> bool { self.inner.rts() }
pub fn write(&mut self, data: &[u8]) -> Result<usize> {
let count = self.write_buf.write(data);
match self.flush() {
Ok(_) | Err(UsbError::WouldBlock) => { },
Err(err) => { return Err(err); },
};
if count == 0 {
Err(UsbError::WouldBlock)
} else {
Ok(count)
}
}
pub fn read(&mut self, data: &mut [u8]) -> Result<usize> {
let buf = &mut self.read_buf;
let inner = &mut self.inner;
buf.write_all(inner.max_packet_size() as usize, |buf_data| {
match inner.read_packet(buf_data) {
Ok(c) => Ok(c),
Err(UsbError::WouldBlock) => Ok(0),
Err(err) => Err(err),
}
})?;
if buf.available_read() == 0 {
return Err(UsbError::WouldBlock);
}
let r = buf.read(data.len(), |buf_data| {
&data[..buf_data.len()].copy_from_slice(buf_data);
Ok(buf_data.len())
});
r
}
pub fn flush(&mut self) -> Result<()> {
let buf = &mut self.write_buf;
let inner = &mut self.inner;
let write_state = &mut self.write_state;
let full_count = match *write_state {
WriteState::Full(c) => c,
_ => 0,
};
if buf.available_read() > 0 {
let max_write_size = if full_count >= SHORT_PACKET_INTERVAL {
inner.max_packet_size() - 1
} else {
inner.max_packet_size()
} as usize;
buf.read(max_write_size, |buf_data| {
inner.write_packet(buf_data)?;
*write_state = if buf_data.len() == inner.max_packet_size() as usize {
WriteState::Full(full_count + 1)
} else {
WriteState::Short
};
Ok(buf_data.len())
})?;
Err(UsbError::WouldBlock)
} else if full_count != 0 {
inner.write_packet(&[])?;
*write_state = WriteState::Short;
Err(UsbError::WouldBlock)
} else {
*write_state = WriteState::Idle;
Ok(())
}
}
}
impl<B, RS, WS> UsbClass<B> for SerialPort<'_, B, RS, WS>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
self.inner.get_configuration_descriptors(writer)
}
fn reset(&mut self) {
self.inner.reset();
self.read_buf.clear();
self.write_buf.clear();
self.write_state = WriteState::Idle;
}
fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
if addr == self.inner.write_ep_address() {
self.flush().ok();
}
}
fn control_in(&mut self, xfer: ControlIn<B>) { self.inner.control_in(xfer); }
fn control_out(&mut self, xfer: ControlOut<B>) { self.inner.control_out(xfer); }
}
impl<B, RS, WS> embedded_hal::serial::Write<u8> for SerialPort<'_, B, RS, WS>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
type Error = UsbError;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
match <SerialPort<'_, B, RS, WS>>::write(self, slice::from_ref(&word)) {
Ok(0) | Err(UsbError::WouldBlock) => Err(nb::Error::WouldBlock),
Ok(_) => Ok(()),
Err(err) => Err(nb::Error::Other(err)),
}
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
match <SerialPort<'_, B, RS, WS>>::flush(self) {
Err(UsbError::WouldBlock) => Err(nb::Error::WouldBlock),
Ok(_) => Ok(()),
Err(err) => Err(nb::Error::Other(err)),
}
}
}
impl<B, RS, WS> embedded_hal::serial::Read<u8> for SerialPort<'_, B, RS, WS>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
type Error = UsbError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let mut buf: u8 = 0;
match <SerialPort<'_, B, RS, WS>>::read(self, slice::from_mut(&mut buf)) {
Ok(0) | Err(UsbError::WouldBlock) => Err(nb::Error::WouldBlock),
Ok(_) => Ok(buf),
Err(err) => Err(nb::Error::Other(err)),
}
}
}