Merge pull request #1701 from chemicstry/bxcan_methods2
stm32/can: implement more convenience methods
This commit is contained in:
commit
8d8c642845
1 changed files with 119 additions and 41 deletions
|
@ -77,6 +77,7 @@ pub struct Can<'d, T: Instance> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BusError {
|
||||
Stuff,
|
||||
Form,
|
||||
|
@ -90,6 +91,22 @@ pub enum BusError {
|
|||
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> {
|
||||
/// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
|
||||
/// 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
|
||||
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
if let Ok(status) = self.can.borrow_mut().transmit(frame) {
|
||||
return Poll::Ready(status);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
CanTx { can: &self.can }.write(frame).await
|
||||
}
|
||||
|
||||
pub async fn flush(&self, mb: bxcan::Mailbox) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
if T::regs().tsr().read().tme(mb.index()) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
/// 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> {
|
||||
CanTx { can: &self.can }.try_write(frame)
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: bxcan::Mailbox) {
|
||||
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
|
||||
pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
|
||||
poll_fn(|cx| {
|
||||
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
|
||||
CanRx { can: &self.can }.read().await
|
||||
}
|
||||
|
||||
fn curr_error(&self) -> Option<BusError> {
|
||||
let err = { T::regs().esr().read() };
|
||||
if err.boff() {
|
||||
return Some(BusError::BusOff);
|
||||
} else if err.epvf() {
|
||||
return Some(BusError::BusPassive);
|
||||
} else if err.ewgf() {
|
||||
return Some(BusError::BusWarning);
|
||||
} else if let Some(err) = err.lec().into_bus_err() {
|
||||
return Some(err);
|
||||
}
|
||||
None
|
||||
/// 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> {
|
||||
CanRx { can: &self.can }.try_read()
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
CanRx { can: &self.can }.wait_not_empty().await
|
||||
}
|
||||
|
||||
unsafe fn receive_fifo(fifo: RxFifo) {
|
||||
|
@ -386,6 +393,14 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
|
|||
.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) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
|
@ -397,6 +412,42 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
|
|||
})
|
||||
.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)]
|
||||
|
@ -419,6 +470,33 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
|
|||
.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> {
|
||||
let err = { T::regs().esr().read() };
|
||||
if err.boff() {
|
||||
|
|
Loading…
Reference in a new issue