diff options
| author | chemicstry <[email protected]> | 2023-07-28 14:22:24 +0300 |
|---|---|---|
| committer | chemicstry <[email protected]> | 2023-07-28 14:22:24 +0300 |
| commit | 38b5d1ee2b1319a6f84c8894f05c650bb3630ece (patch) | |
| tree | 11a771f504670c30578f40adc5e1a25bcd520a49 | |
| parent | 44c8db2911f0f9d82e6517e31944777454c4e459 (diff) | |
stm32/can: implement more convenience methods
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 154 |
1 files changed, 116 insertions, 38 deletions
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 8b8244d4f..d4ec23816 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -77,6 +77,7 @@ pub struct Can<'d, T: Instance> { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | #[derive(Debug)] | 79 | #[derive(Debug)] |
| 80 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 80 | pub enum BusError { | 81 | pub enum BusError { |
| 81 | Stuff, | 82 | Stuff, |
| 82 | Form, | 83 | Form, |
| @@ -90,6 +91,22 @@ pub enum BusError { | |||
| 90 | BusWarning, | 91 | BusWarning, |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 94 | #[derive(Debug)] | ||
| 95 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 96 | pub enum TryReadError { | ||
| 97 | /// Bus error | ||
| 98 | BusError(BusError), | ||
| 99 | /// Receive buffer is empty | ||
| 100 | Empty, | ||
| 101 | } | ||
| 102 | |||
| 103 | #[derive(Debug)] | ||
| 104 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 105 | pub enum TryWriteError { | ||
| 106 | /// All transmit mailboxes are full | ||
| 107 | Full, | ||
| 108 | } | ||
| 109 | |||
| 93 | impl<'d, T: Instance> Can<'d, T> { | 110 | impl<'d, T: Instance> Can<'d, T> { |
| 94 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | 111 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. |
| 95 | /// You must call [Can::enable_non_blocking] to use the peripheral. | 112 | /// You must call [Can::enable_non_blocking] to use the peripheral. |
| @@ -175,56 +192,46 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 175 | 192 | ||
| 176 | /// Queues the message to be sent but exerts backpressure | 193 | /// Queues the message to be sent but exerts backpressure |
| 177 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | 194 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 178 | poll_fn(|cx| { | 195 | CanTx { can: &self.can }.write(frame).await |
| 179 | T::state().tx_waker.register(cx.waker()); | 196 | } |
| 180 | if let Ok(status) = self.can.borrow_mut().transmit(frame) { | ||
| 181 | return Poll::Ready(status); | ||
| 182 | } | ||
| 183 | 197 | ||
| 184 | Poll::Pending | 198 | /// Attempts to transmit a frame without blocking. |
| 185 | }) | 199 | /// |
| 186 | .await | 200 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. |
| 201 | pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> { | ||
| 202 | CanTx { can: &self.can }.try_write(frame) | ||
| 187 | } | 203 | } |
| 188 | 204 | ||
| 205 | /// Waits for a specific transmit mailbox to become empty | ||
| 189 | pub async fn flush(&self, mb: bxcan::Mailbox) { | 206 | pub async fn flush(&self, mb: bxcan::Mailbox) { |
| 190 | poll_fn(|cx| { | 207 | CanTx { can: &self.can }.flush(mb).await |
| 191 | T::state().tx_waker.register(cx.waker()); | 208 | } |
| 192 | if T::regs().tsr().read().tme(mb.index()) { | ||
| 193 | return Poll::Ready(()); | ||
| 194 | } | ||
| 195 | 209 | ||
| 196 | Poll::Pending | 210 | /// Waits until any of the transmit mailboxes become empty |
| 197 | }) | 211 | pub async fn flush_any(&self) { |
| 198 | .await; | 212 | CanTx { can: &self.can }.flush_any().await |
| 213 | } | ||
| 214 | |||
| 215 | /// Waits until all of the transmit mailboxes become empty | ||
| 216 | pub async fn flush_all(&self) { | ||
| 217 | CanTx { can: &self.can }.flush_all().await | ||
| 199 | } | 218 | } |
| 200 | 219 | ||
| 201 | /// Returns a tuple of the time the message was received and the message frame | 220 | /// Returns a tuple of the time the message was received and the message frame |
| 202 | pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> { | 221 | pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> { |
| 203 | poll_fn(|cx| { | 222 | CanRx { can: &self.can }.read().await |
| 204 | T::state().err_waker.register(cx.waker()); | 223 | } |
| 205 | if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) { | ||
| 206 | return Poll::Ready(Ok((time, frame))); | ||
| 207 | } else if let Some(err) = self.curr_error() { | ||
| 208 | return Poll::Ready(Err(err)); | ||
| 209 | } | ||
| 210 | 224 | ||
| 211 | Poll::Pending | 225 | /// Attempts to read a can frame without blocking. |
| 212 | }) | 226 | /// |
| 213 | .await | 227 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 228 | pub fn try_read(&mut self) -> Result<(u16, bxcan::Frame), TryReadError> { | ||
| 229 | CanRx { can: &self.can }.try_read() | ||
| 214 | } | 230 | } |
| 215 | 231 | ||
| 216 | fn curr_error(&self) -> Option<BusError> { | 232 | /// Waits while receive queue is empty. |
| 217 | let err = { T::regs().esr().read() }; | 233 | pub async fn wait_not_empty(&mut self) { |
| 218 | if err.boff() { | 234 | CanRx { can: &self.can }.wait_not_empty().await |
| 219 | return Some(BusError::BusOff); | ||
| 220 | } else if err.epvf() { | ||
| 221 | return Some(BusError::BusPassive); | ||
| 222 | } else if err.ewgf() { | ||
| 223 | return Some(BusError::BusWarning); | ||
| 224 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 225 | return Some(err); | ||
| 226 | } | ||
| 227 | None | ||
| 228 | } | 235 | } |
| 229 | 236 | ||
| 230 | unsafe fn receive_fifo(fifo: RxFifo) { | 237 | unsafe fn receive_fifo(fifo: RxFifo) { |
| @@ -386,6 +393,14 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | |||
| 386 | .await | 393 | .await |
| 387 | } | 394 | } |
| 388 | 395 | ||
| 396 | /// Attempts to transmit a frame without blocking. | ||
| 397 | /// | ||
| 398 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | ||
| 399 | pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> { | ||
| 400 | self.can.borrow_mut().transmit(frame).map_err(|_| TryWriteError::Full) | ||
| 401 | } | ||
| 402 | |||
| 403 | /// Waits for a specific transmit mailbox to become empty | ||
| 389 | pub async fn flush(&self, mb: bxcan::Mailbox) { | 404 | pub async fn flush(&self, mb: bxcan::Mailbox) { |
| 390 | poll_fn(|cx| { | 405 | poll_fn(|cx| { |
| 391 | T::state().tx_waker.register(cx.waker()); | 406 | T::state().tx_waker.register(cx.waker()); |
| @@ -397,6 +412,42 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | |||
| 397 | }) | 412 | }) |
| 398 | .await; | 413 | .await; |
| 399 | } | 414 | } |
| 415 | |||
| 416 | /// Waits until any of the transmit mailboxes become empty | ||
| 417 | pub async fn flush_any(&self) { | ||
| 418 | poll_fn(|cx| { | ||
| 419 | T::state().tx_waker.register(cx.waker()); | ||
| 420 | |||
| 421 | let tsr = T::regs().tsr().read(); | ||
| 422 | if tsr.tme(bxcan::Mailbox::Mailbox0.index()) | ||
| 423 | || tsr.tme(bxcan::Mailbox::Mailbox1.index()) | ||
| 424 | || tsr.tme(bxcan::Mailbox::Mailbox2.index()) | ||
| 425 | { | ||
| 426 | return Poll::Ready(()); | ||
| 427 | } | ||
| 428 | |||
| 429 | Poll::Pending | ||
| 430 | }) | ||
| 431 | .await; | ||
| 432 | } | ||
| 433 | |||
| 434 | /// Waits until all of the transmit mailboxes become empty | ||
| 435 | pub async fn flush_all(&self) { | ||
| 436 | poll_fn(|cx| { | ||
| 437 | T::state().tx_waker.register(cx.waker()); | ||
| 438 | |||
| 439 | let tsr = T::regs().tsr().read(); | ||
| 440 | if tsr.tme(bxcan::Mailbox::Mailbox0.index()) | ||
| 441 | && tsr.tme(bxcan::Mailbox::Mailbox1.index()) | ||
| 442 | && tsr.tme(bxcan::Mailbox::Mailbox2.index()) | ||
| 443 | { | ||
| 444 | return Poll::Ready(()); | ||
| 445 | } | ||
| 446 | |||
| 447 | Poll::Pending | ||
| 448 | }) | ||
| 449 | .await; | ||
| 450 | } | ||
| 400 | } | 451 | } |
| 401 | 452 | ||
| 402 | #[allow(dead_code)] | 453 | #[allow(dead_code)] |
| @@ -419,6 +470,33 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | |||
| 419 | .await | 470 | .await |
| 420 | } | 471 | } |
| 421 | 472 | ||
| 473 | /// Attempts to read a CAN frame without blocking. | ||
| 474 | /// | ||
| 475 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 476 | pub fn try_read(&mut self) -> Result<(u16, bxcan::Frame), TryReadError> { | ||
| 477 | if let Ok(envelope) = T::state().rx_queue.try_recv() { | ||
| 478 | return Ok(envelope); | ||
| 479 | } | ||
| 480 | |||
| 481 | if let Some(err) = self.curr_error() { | ||
| 482 | return Err(TryReadError::BusError(err)); | ||
| 483 | } | ||
| 484 | |||
| 485 | Err(TryReadError::Empty) | ||
| 486 | } | ||
| 487 | |||
| 488 | /// Waits while receive queue is empty. | ||
| 489 | pub async fn wait_not_empty(&mut self) { | ||
| 490 | poll_fn(|cx| { | ||
| 491 | if T::state().rx_queue.poll_ready_to_receive(cx) { | ||
| 492 | Poll::Ready(()) | ||
| 493 | } else { | ||
| 494 | Poll::Pending | ||
| 495 | } | ||
| 496 | }) | ||
| 497 | .await | ||
| 498 | } | ||
| 499 | |||
| 422 | fn curr_error(&self) -> Option<BusError> { | 500 | fn curr_error(&self) -> Option<BusError> { |
| 423 | let err = { T::regs().esr().read() }; | 501 | let err = { T::regs().esr().read() }; |
| 424 | if err.boff() { | 502 | if err.boff() { |
