use crate::buffer::{Buffer, DefaultBufferStore};
use crate::cdc_acm::*;
use core::borrow::BorrowMut;
use core::slice;
use usb_device::class_prelude::*;
use usb_device::descriptor::lang_id::LangID;
use usb_device::Result;
pub struct SerialPort<'a, B, RS = DefaultBufferStore, WS = DefaultBufferStore>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
inner: CdcAcmClass<'a, B>,
pub(crate) read_buf: Buffer<RS>,
pub(crate) write_buf: Buffer<WS>,
write_state: WriteState,
}
const SHORT_PACKET_INTERVAL: usize = 10;
enum WriteState {
Idle,
Short,
Full(usize),
}
impl<'a, B> SerialPort<'a, B>
where
B: UsbBus,
{
pub fn new<'alloc: 'a>(
alloc: &'alloc UsbBusAllocator<B>,
) -> SerialPort<'a, B, DefaultBufferStore, DefaultBufferStore> {
Self::new_with_interface_names(alloc, None, None)
}
pub fn new_with_interface_names<'alloc: 'a>(
alloc: &'alloc UsbBusAllocator<B>,
comm_if_name: Option<&'static str>,
data_if_name: Option<&'static str>,
) -> SerialPort<'a, B, DefaultBufferStore, DefaultBufferStore> {
SerialPort::new_with_store_and_interface_names(
alloc,
DefaultBufferStore::default(),
DefaultBufferStore::default(),
comm_if_name,
data_if_name,
)
}
}
impl<'a, B, RS, WS> SerialPort<'a, B, RS, WS>
where
B: UsbBus,
RS: BorrowMut<[u8]>,
WS: BorrowMut<[u8]>,
{
pub fn new_with_store<'alloc: 'a>(
alloc: &'alloc UsbBusAllocator<B>,
read_store: RS,
write_store: WS,
) -> SerialPort<'a, B, RS, WS> {
Self::new_with_store_and_interface_names(alloc, read_store, write_store, None, None)
}
pub fn new_with_store_and_interface_names<'alloc: 'a>(
alloc: &'alloc UsbBusAllocator<B>,
read_store: RS,
write_store: WS,
comm_if_name: Option<&'static str>,
data_if_name: Option<&'static str>,
) -> SerialPort<'a, B, RS, WS> {
SerialPort {
inner: CdcAcmClass::new_with_interface_names(alloc, 64, comm_if_name, data_if_name),
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(crate) fn poll(&mut self) -> Result<()> {
let Self {
inner, read_buf, ..
} = self;
read_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),
}
})?;
Ok(())
}
pub fn read(&mut self, data: &mut [u8]) -> Result<usize> {
self.poll()?;
if self.read_buf.available_read() == 0 {
return Err(UsbError::WouldBlock);
}
self.read_buf.read(data.len(), |buf_data| {
data[..buf_data.len()].copy_from_slice(buf_data);
Ok(buf_data.len())
})
}
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 get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> {
self.inner.get_string(index, lang_id)
}
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)),
}
}
}