use crate::common::atomic_ring_buffer::RingBuffer;
use crate::ll_api::ll_cmd::*;
#[cfg(feature = "_usart_impl")]
use paste::paste;
pub use crate::ll_api::{
UsartDataBits, UsartHwFlowCtrl, UsartId, UsartMode, UsartParity, UsartStopBits,
};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
pub baudrate: u32,
pub data_bits: UsartDataBits,
pub stop_bits: UsartStopBits,
pub parity: UsartParity,
pub hw_flow: UsartHwFlowCtrl,
pub tx_rx_mode: UsartMode,
}
impl Default for Config {
fn default() -> Self {
Self {
baudrate: 115200,
data_bits: UsartDataBits::DataBits8,
stop_bits: UsartStopBits::STOP1,
parity: UsartParity::ParityNone,
hw_flow: UsartHwFlowCtrl::None,
tx_rx_mode: UsartMode::TxRx,
}
}
}
impl Config {
pub fn flags(&self) -> u32 {
let mut flags: u32;
flags = self.data_bits as u32;
flags |= self.stop_bits as u32;
flags |= self.parity as u32;
flags |= self.hw_flow as u32;
flags |= self.tx_rx_mode as u32;
flags
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
Code(i32),
}
pub struct UsartInner {
id: UsartId,
rx_buf: RingBuffer<u8>,
}
#[derive(Clone)]
pub struct Usart<'a> {
inner: &'a UsartInner,
}
impl<'a> Usart<'a> {
pub fn new(usart: &'a UsartInner) -> Self {
Usart { inner: usart }
}
pub fn init(&self, config: &Config) -> i32 {
ll_invoke_inner!(
INVOKE_ID_USART_INIT,
self.inner.id,
config.flags(),
config.baudrate
)
}
pub fn set_rx_buf(&self, rx_buffer: &mut [u8]) {
let len = rx_buffer.len();
unsafe { self.inner.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
}
pub fn blocking_write(&self, buf: &[u8]) -> i32 {
ll_invoke_inner!(
INVOKE_ID_USART_WRITE,
self.inner.id,
buf.as_ptr(),
buf.len()
)
}
pub fn blocking_read(&self, buffer: &mut [u8]) {
let rx_buf = &self.inner.rx_buf;
let mut reader = unsafe { rx_buf.reader() };
for b in buffer {
while rx_buf.is_empty() {}
*b = reader.pop_one().unwrap_or(0);
}
}
pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let rx_buf = &self.inner.rx_buf;
if !rx_buf.is_empty() {
let mut reader = unsafe { rx_buf.reader() };
Ok(reader.pop_one().unwrap_or(0))
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl Drop for Usart<'_> {
fn drop(&mut self) {
ll_invoke_inner!(INVOKE_ID_USART_DEINIT, self.inner.id);
}
}
impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
embedded_io::ErrorKind::Other
}
}
impl embedded_io::ErrorType for Usart<'_> {
type Error = Error;
}
impl<'d> embedded_io::Read for Usart<'_> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.blocking_read(buf);
Ok(buf.len())
}
}
impl embedded_io::Write for Usart<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
let result = self.blocking_write(buf);
if result == 0 {
return Ok(buf.len());
}
return Err(Error::Code(result));
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl embedded_hal_nb::serial::Error for Error {
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
embedded_hal_nb::serial::ErrorKind::Other
}
}
impl<'d> embedded_hal_nb::serial::ErrorType for Usart<'_> {
type Error = Error;
}
impl<'d> embedded_hal_nb::serial::Read for Usart<'_> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.nb_read()
}
}
impl<'d> embedded_hal_nb::serial::Write for Usart<'_> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
let result = self.blocking_write(&[char]);
if result == 0 {
return Ok({});
}
return Err(nb::Error::Other(Error::Code(result)));
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
Ok(())
}
}
#[cfg(feature = "_usart_impl")]
macro_rules! impl_usart {
($USART_id:ident) => {
pub static $USART_id: UsartInner = UsartInner {
id: UsartId::$USART_id,
rx_buf: RingBuffer::new(),
};
paste! {
#[allow(non_snake_case)]
#[no_mangle]
#[inline]
unsafe extern "C" fn [<$USART_id _rx_hook_rs>] (val: u8) {
$USART_id.rx_buf.writer().push_one(val);
}
}
};
}
#[cfg(feature = "USART-0")]
impl_usart!(USART0);
#[cfg(feature = "USART-1")]
impl_usart!(USART1);
#[cfg(feature = "USART-2")]
impl_usart!(USART2);
#[cfg(feature = "USART-3")]
impl_usart!(USART3);
#[cfg(feature = "USART-4")]
impl_usart!(USART4);
#[cfg(feature = "USART-5")]
impl_usart!(USART5);
#[cfg(feature = "USART-6")]
impl_usart!(USART6);
#[cfg(feature = "USART-7")]
impl_usart!(USART7);