Merge pull request #1701 from chemicstry/bxcan_methods2

stm32/can: implement more convenience methods
This commit is contained in:
Dario Nieuwenhuis 2023-07-28 11:44:30 +00:00 committed by GitHub
commit 8d8c642845
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -77,6 +77,7 @@ pub struct Can<'d, T: Instance> {
} }
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BusError { pub enum BusError {
Stuff, Stuff,
Form, Form,
@ -90,6 +91,22 @@ pub enum BusError {
BusWarning, BusWarning,
} }
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TryReadError {
/// Bus error
BusError(BusError),
/// Receive buffer is empty
Empty,
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TryWriteError {
/// All transmit mailboxes are full
Full,
}
impl<'d, T: Instance> Can<'d, T> { impl<'d, T: Instance> Can<'d, T> {
/// Creates a new Bxcan instance, keeping the peripheral in sleep mode. /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
/// You must call [Can::enable_non_blocking] to use the peripheral. /// You must call [Can::enable_non_blocking] to use the peripheral.
@ -175,56 +192,46 @@ impl<'d, T: Instance> Can<'d, T> {
/// Queues the message to be sent but exerts backpressure /// Queues the message to be sent but exerts backpressure
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
poll_fn(|cx| { CanTx { can: &self.can }.write(frame).await
T::state().tx_waker.register(cx.waker());
if let Ok(status) = self.can.borrow_mut().transmit(frame) {
return Poll::Ready(status);
}
Poll::Pending
})
.await
} }
pub async fn flush(&self, mb: bxcan::Mailbox) { /// Attempts to transmit a frame without blocking.
poll_fn(|cx| { ///
T::state().tx_waker.register(cx.waker()); /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
if T::regs().tsr().read().tme(mb.index()) { pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> {
return Poll::Ready(()); CanTx { can: &self.can }.try_write(frame)
} }
Poll::Pending /// Waits for a specific transmit mailbox to become empty
}) pub async fn flush(&self, mb: bxcan::Mailbox) {
.await; CanTx { can: &self.can }.flush(mb).await
}
/// Waits until any of the transmit mailboxes become empty
pub async fn flush_any(&self) {
CanTx { can: &self.can }.flush_any().await
}
/// Waits until all of the transmit mailboxes become empty
pub async fn flush_all(&self) {
CanTx { can: &self.can }.flush_all().await
} }
/// Returns a tuple of the time the message was received and the message frame /// Returns a tuple of the time the message was received and the message frame
pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> { pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
poll_fn(|cx| { CanRx { can: &self.can }.read().await
T::state().err_waker.register(cx.waker());
if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) {
return Poll::Ready(Ok((time, frame)));
} else if let Some(err) = self.curr_error() {
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
} }
fn curr_error(&self) -> Option<BusError> { /// Attempts to read a can frame without blocking.
let err = { T::regs().esr().read() }; ///
if err.boff() { /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
return Some(BusError::BusOff); pub fn try_read(&mut self) -> Result<(u16, bxcan::Frame), TryReadError> {
} else if err.epvf() { CanRx { can: &self.can }.try_read()
return Some(BusError::BusPassive); }
} else if err.ewgf() {
return Some(BusError::BusWarning); /// Waits while receive queue is empty.
} else if let Some(err) = err.lec().into_bus_err() { pub async fn wait_not_empty(&mut self) {
return Some(err); CanRx { can: &self.can }.wait_not_empty().await
}
None
} }
unsafe fn receive_fifo(fifo: RxFifo) { unsafe fn receive_fifo(fifo: RxFifo) {
@ -386,6 +393,14 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
.await .await
} }
/// Attempts to transmit a frame without blocking.
///
/// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> {
self.can.borrow_mut().transmit(frame).map_err(|_| TryWriteError::Full)
}
/// Waits for a specific transmit mailbox to become empty
pub async fn flush(&self, mb: bxcan::Mailbox) { pub async fn flush(&self, mb: bxcan::Mailbox) {
poll_fn(|cx| { poll_fn(|cx| {
T::state().tx_waker.register(cx.waker()); T::state().tx_waker.register(cx.waker());
@ -397,6 +412,42 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
}) })
.await; .await;
} }
/// Waits until any of the transmit mailboxes become empty
pub async fn flush_any(&self) {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
let tsr = T::regs().tsr().read();
if tsr.tme(bxcan::Mailbox::Mailbox0.index())
|| tsr.tme(bxcan::Mailbox::Mailbox1.index())
|| tsr.tme(bxcan::Mailbox::Mailbox2.index())
{
return Poll::Ready(());
}
Poll::Pending
})
.await;
}
/// Waits until all of the transmit mailboxes become empty
pub async fn flush_all(&self) {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
let tsr = T::regs().tsr().read();
if tsr.tme(bxcan::Mailbox::Mailbox0.index())
&& tsr.tme(bxcan::Mailbox::Mailbox1.index())
&& tsr.tme(bxcan::Mailbox::Mailbox2.index())
{
return Poll::Ready(());
}
Poll::Pending
})
.await;
}
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -419,6 +470,33 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
.await .await
} }
/// Attempts to read a CAN frame without blocking.
///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<(u16, bxcan::Frame), TryReadError> {
if let Ok(envelope) = T::state().rx_queue.try_recv() {
return Ok(envelope);
}
if let Some(err) = self.curr_error() {
return Err(TryReadError::BusError(err));
}
Err(TryReadError::Empty)
}
/// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) {
poll_fn(|cx| {
if T::state().rx_queue.poll_ready_to_receive(cx) {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await
}
fn curr_error(&self) -> Option<BusError> { fn curr_error(&self) -> Option<BusError> {
let err = { T::regs().esr().read() }; let err = { T::regs().esr().read() };
if err.boff() { if err.boff() {