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)]
|
#[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() {
|
||||||
|
|
Loading…
Reference in a new issue