diff options
| author | Corey Schuhen <[email protected]> | 2024-02-17 18:10:45 +1000 |
|---|---|---|
| committer | Corey Schuhen <[email protected]> | 2024-02-17 18:26:57 +1000 |
| commit | 91c75c92a0e67c93550a163ae62b22a652bf2012 (patch) | |
| tree | 67105c6f0b044f227f14ed407a9ce7b4d2290635 | |
| parent | 5d8c54fdea752d4a52b33a7f776b436f5934409c (diff) | |
Clean up and prep for buffered IRQ mode.
- Reduce code duplicaiton in read/write methods
- General clean-up
- Prepare for buffered mode
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 347 |
1 files changed, 188 insertions, 159 deletions
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 987748e06..42ce73ded 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -39,14 +39,17 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||
| 39 | 39 | ||
| 40 | let ir = regs.ir().read(); | 40 | let ir = regs.ir().read(); |
| 41 | 41 | ||
| 42 | if ir.tc() { | 42 | { |
| 43 | regs.ir().write(|w| w.set_tc(true)); | 43 | if ir.tc() { |
| 44 | T::state().tx_waker.wake(); | 44 | regs.ir().write(|w| w.set_tc(true)); |
| 45 | } | 45 | } |
| 46 | if ir.tefn() { | ||
| 47 | regs.ir().write(|w| w.set_tefn(true)); | ||
| 48 | } | ||
| 46 | 49 | ||
| 47 | if ir.tefn() { | 50 | match &T::state().tx_mode { |
| 48 | regs.ir().write(|w| w.set_tefn(true)); | 51 | sealed::TxMode::NonBuffered(waker) => waker.wake(), |
| 49 | T::state().tx_waker.wake(); | 52 | } |
| 50 | } | 53 | } |
| 51 | 54 | ||
| 52 | if ir.ped() || ir.pea() { | 55 | if ir.ped() || ir.pea() { |
| @@ -57,15 +60,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | if ir.rfn(0) { | 62 | if ir.rfn(0) { |
| 60 | let fifonr = 0 as usize; | 63 | T::state().rx_mode.on_interrupt::<T>(0); |
| 61 | regs.ir().write(|w| w.set_rfn(fifonr, true)); | ||
| 62 | |||
| 63 | T::state().rx_waker.wake(); | ||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | if ir.rfn(1) { | 66 | if ir.rfn(1) { |
| 67 | regs.ir().write(|w| w.set_rfn(1, true)); | 67 | T::state().rx_mode.on_interrupt::<T>(1); |
| 68 | T::state().rx_waker.wake(); | ||
| 69 | } | 68 | } |
| 70 | } | 69 | } |
| 71 | } | 70 | } |
| @@ -148,7 +147,6 @@ pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { | |||
| 148 | /// Reference to internals. | 147 | /// Reference to internals. |
| 149 | instance: FdcanInstance<'d, T>, | 148 | instance: FdcanInstance<'d, T>, |
| 150 | _mode: PhantomData<M>, | 149 | _mode: PhantomData<M>, |
| 151 | ns_per_timer_tick: u64, // For FDCAN internal timer | ||
| 152 | } | 150 | } |
| 153 | 151 | ||
| 154 | fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { | 152 | fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { |
| @@ -166,23 +164,6 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm | |||
| 166 | } | 164 | } |
| 167 | } | 165 | } |
| 168 | 166 | ||
| 169 | #[cfg(feature = "time")] | ||
| 170 | fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||
| 171 | let now_embassy = embassy_time::Instant::now(); | ||
| 172 | if ns_per_timer_tick == 0 { | ||
| 173 | return now_embassy; | ||
| 174 | } | ||
| 175 | let cantime = { T::regs().tscv().read().tsc() }; | ||
| 176 | let delta = cantime.overflowing_sub(ts_val).0 as u64; | ||
| 177 | let ns = ns_per_timer_tick * delta as u64; | ||
| 178 | now_embassy - embassy_time::Duration::from_nanos(ns) | ||
| 179 | } | ||
| 180 | |||
| 181 | #[cfg(not(feature = "time"))] | ||
| 182 | fn calc_timestamp<T: Instance>(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||
| 183 | ts_val | ||
| 184 | } | ||
| 185 | |||
| 186 | impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { | 167 | impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { |
| 187 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. | 168 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. |
| 188 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. | 169 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. |
| @@ -239,12 +220,10 @@ impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { | |||
| 239 | w.set_eint1(true); // Interrupt Line 1 | 220 | w.set_eint1(true); // Interrupt Line 1 |
| 240 | }); | 221 | }); |
| 241 | 222 | ||
| 242 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(config.frame_transmit); | ||
| 243 | Self { | 223 | Self { |
| 244 | config, | 224 | config, |
| 245 | instance: FdcanInstance(peri), | 225 | instance: FdcanInstance(peri), |
| 246 | _mode: PhantomData::<ConfigMode>, | 226 | _mode: PhantomData::<ConfigMode>, |
| 247 | ns_per_timer_tick, | ||
| 248 | } | 227 | } |
| 249 | } | 228 | } |
| 250 | 229 | ||
| @@ -319,12 +298,14 @@ macro_rules! impl_transition { | |||
| 319 | /// Transition from $from_mode:ident mode to $to_mode:ident mode | 298 | /// Transition from $from_mode:ident mode to $to_mode:ident mode |
| 320 | pub fn $name(self) -> Fdcan<'d, T, $to_mode> { | 299 | pub fn $name(self) -> Fdcan<'d, T, $to_mode> { |
| 321 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); | 300 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); |
| 301 | critical_section::with(|_| unsafe { | ||
| 302 | T::mut_state().ns_per_timer_tick = ns_per_timer_tick; | ||
| 303 | }); | ||
| 322 | T::registers().$func(self.config); | 304 | T::registers().$func(self.config); |
| 323 | let ret = Fdcan { | 305 | let ret = Fdcan { |
| 324 | config: self.config, | 306 | config: self.config, |
| 325 | instance: self.instance, | 307 | instance: self.instance, |
| 326 | _mode: PhantomData::<$to_mode>, | 308 | _mode: PhantomData::<$to_mode>, |
| 327 | ns_per_timer_tick, | ||
| 328 | }; | 309 | }; |
| 329 | ret | 310 | ret |
| 330 | } | 311 | } |
| @@ -357,7 +338,8 @@ where | |||
| 357 | /// Flush one of the TX mailboxes. | 338 | /// Flush one of the TX mailboxes. |
| 358 | pub async fn flush(&self, idx: usize) { | 339 | pub async fn flush(&self, idx: usize) { |
| 359 | poll_fn(|cx| { | 340 | poll_fn(|cx| { |
| 360 | T::state().tx_waker.register(cx.waker()); | 341 | T::state().tx_mode.register(cx.waker()); |
| 342 | |||
| 361 | if idx > 3 { | 343 | if idx > 3 { |
| 362 | panic!("Bad mailbox"); | 344 | panic!("Bad mailbox"); |
| 363 | } | 345 | } |
| @@ -376,39 +358,12 @@ where | |||
| 376 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 358 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 377 | /// transmitted, then tries again. | 359 | /// transmitted, then tries again. |
| 378 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 360 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { |
| 379 | poll_fn(|cx| { | 361 | T::state().tx_mode.write::<T>(frame).await |
| 380 | T::state().tx_waker.register(cx.waker()); | ||
| 381 | |||
| 382 | if let Ok(dropped) = T::registers().write_classic(frame) { | ||
| 383 | return Poll::Ready(dropped); | ||
| 384 | } | ||
| 385 | |||
| 386 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 387 | // to clear. | ||
| 388 | Poll::Pending | ||
| 389 | }) | ||
| 390 | .await | ||
| 391 | } | 362 | } |
| 392 | 363 | ||
| 393 | /// Returns the next received message frame | 364 | /// Returns the next received message frame |
| 394 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 365 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { |
| 395 | poll_fn(|cx| { | 366 | T::state().rx_mode.read::<T>().await |
| 396 | T::state().err_waker.register(cx.waker()); | ||
| 397 | T::state().rx_waker.register(cx.waker()); | ||
| 398 | |||
| 399 | if let Some((msg, ts)) = T::registers().read_classic(0) { | ||
| 400 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||
| 401 | return Poll::Ready(Ok((msg, ts))); | ||
| 402 | } else if let Some((msg, ts)) = T::registers().read_classic(1) { | ||
| 403 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||
| 404 | return Poll::Ready(Ok((msg, ts))); | ||
| 405 | } else if let Some(err) = T::registers().curr_error() { | ||
| 406 | // TODO: this is probably wrong | ||
| 407 | return Poll::Ready(Err(err)); | ||
| 408 | } | ||
| 409 | Poll::Pending | ||
| 410 | }) | ||
| 411 | .await | ||
| 412 | } | 367 | } |
| 413 | 368 | ||
| 414 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 369 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| @@ -416,45 +371,29 @@ where | |||
| 416 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 371 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 417 | /// transmitted, then tries again. | 372 | /// transmitted, then tries again. |
| 418 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | 373 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { |
| 419 | poll_fn(|cx| { | 374 | T::state().tx_mode.write_fd::<T>(frame).await |
| 420 | T::state().tx_waker.register(cx.waker()); | ||
| 421 | |||
| 422 | if let Ok(dropped) = T::registers().write_fd(frame) { | ||
| 423 | return Poll::Ready(dropped); | ||
| 424 | } | ||
| 425 | |||
| 426 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 427 | // to clear. | ||
| 428 | Poll::Pending | ||
| 429 | }) | ||
| 430 | .await | ||
| 431 | } | 375 | } |
| 432 | 376 | ||
| 433 | /// Returns the next received message frame | 377 | /// Returns the next received message frame |
| 434 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 378 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { |
| 435 | poll_fn(|cx| { | 379 | T::state().rx_mode.read_fd::<T>().await |
| 436 | T::state().err_waker.register(cx.waker()); | 380 | } |
| 437 | T::state().rx_waker.register(cx.waker()); | 381 | |
| 438 | 382 | /// Join split rx and tx portions back together | |
| 439 | if let Some((msg, ts)) = T::registers().read_fd(0) { | 383 | pub fn join(tx: FdcanTx<'d, T, M>, rx: FdcanRx<'d, T, M>) -> Self { |
| 440 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | 384 | Fdcan { |
| 441 | return Poll::Ready(Ok((msg, ts))); | 385 | config: tx.config, |
| 442 | } else if let Some((msg, ts)) = T::registers().read_fd(1) { | 386 | //_instance2: T::regs(), |
| 443 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | 387 | instance: tx._instance, |
| 444 | return Poll::Ready(Ok((msg, ts))); | 388 | _mode: rx._mode, |
| 445 | } else if let Some(err) = T::registers().curr_error() { | 389 | } |
| 446 | // TODO: this is probably wrong | ||
| 447 | return Poll::Ready(Err(err)); | ||
| 448 | } | ||
| 449 | Poll::Pending | ||
| 450 | }) | ||
| 451 | .await | ||
| 452 | } | 390 | } |
| 453 | 391 | ||
| 454 | /// Split instance into separate Tx(write) and Rx(read) portions | 392 | /// Split instance into separate Tx(write) and Rx(read) portions |
| 455 | pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) { | 393 | pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) { |
| 456 | ( | 394 | ( |
| 457 | FdcanTx { | 395 | FdcanTx { |
| 396 | config: self.config, | ||
| 458 | _instance: self.instance, | 397 | _instance: self.instance, |
| 459 | _mode: self._mode, | 398 | _mode: self._mode, |
| 460 | }, | 399 | }, |
| @@ -462,10 +401,10 @@ where | |||
| 462 | _instance1: PhantomData::<T>, | 401 | _instance1: PhantomData::<T>, |
| 463 | _instance2: T::regs(), | 402 | _instance2: T::regs(), |
| 464 | _mode: self._mode, | 403 | _mode: self._mode, |
| 465 | ns_per_timer_tick: self.ns_per_timer_tick, | ||
| 466 | }, | 404 | }, |
| 467 | ) | 405 | ) |
| 468 | } | 406 | } |
| 407 | |||
| 469 | } | 408 | } |
| 470 | 409 | ||
| 471 | /// FDCAN Rx only Instance | 410 | /// FDCAN Rx only Instance |
| @@ -474,11 +413,11 @@ pub struct FdcanRx<'d, T: Instance, M: Receive> { | |||
| 474 | _instance1: PhantomData<T>, | 413 | _instance1: PhantomData<T>, |
| 475 | _instance2: &'d crate::pac::can::Fdcan, | 414 | _instance2: &'d crate::pac::can::Fdcan, |
| 476 | _mode: PhantomData<M>, | 415 | _mode: PhantomData<M>, |
| 477 | ns_per_timer_tick: u64, // For FDCAN internal timer | ||
| 478 | } | 416 | } |
| 479 | 417 | ||
| 480 | /// FDCAN Tx only Instance | 418 | /// FDCAN Tx only Instance |
| 481 | pub struct FdcanTx<'d, T: Instance, M: Transmit> { | 419 | pub struct FdcanTx<'d, T: Instance, M: Transmit> { |
| 420 | config: crate::can::fd::config::FdCanConfig, | ||
| 482 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); | 421 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); |
| 483 | _mode: PhantomData<M>, | 422 | _mode: PhantomData<M>, |
| 484 | } | 423 | } |
| @@ -489,18 +428,7 @@ impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { | |||
| 489 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 428 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 490 | /// transmitted, then tries again. | 429 | /// transmitted, then tries again. |
| 491 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 430 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { |
| 492 | poll_fn(|cx| { | 431 | T::state().tx_mode.write::<T>(frame).await |
| 493 | T::state().tx_waker.register(cx.waker()); | ||
| 494 | |||
| 495 | if let Ok(dropped) = T::registers().write_classic(frame) { | ||
| 496 | return Poll::Ready(dropped); | ||
| 497 | } | ||
| 498 | |||
| 499 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 500 | // to clear. | ||
| 501 | Poll::Pending | ||
| 502 | }) | ||
| 503 | .await | ||
| 504 | } | 432 | } |
| 505 | 433 | ||
| 506 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 434 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| @@ -508,80 +436,158 @@ impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { | |||
| 508 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 436 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 509 | /// transmitted, then tries again. | 437 | /// transmitted, then tries again. |
| 510 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | 438 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { |
| 511 | poll_fn(|cx| { | 439 | T::state().tx_mode.write_fd::<T>(frame).await |
| 512 | T::state().tx_waker.register(cx.waker()); | ||
| 513 | |||
| 514 | if let Ok(dropped) = T::registers().write_fd(frame) { | ||
| 515 | return Poll::Ready(dropped); | ||
| 516 | } | ||
| 517 | |||
| 518 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 519 | // to clear. | ||
| 520 | Poll::Pending | ||
| 521 | }) | ||
| 522 | .await | ||
| 523 | } | 440 | } |
| 524 | } | 441 | } |
| 525 | 442 | ||
| 526 | impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { | 443 | impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { |
| 527 | /// Returns the next received message frame | 444 | /// Returns the next received message frame |
| 528 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 445 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { |
| 529 | poll_fn(|cx| { | 446 | T::state().rx_mode.read::<T>().await |
| 530 | T::state().err_waker.register(cx.waker()); | ||
| 531 | T::state().rx_waker.register(cx.waker()); | ||
| 532 | |||
| 533 | if let Some((msg, ts)) = T::registers().read_classic(0) { | ||
| 534 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||
| 535 | return Poll::Ready(Ok((msg, ts))); | ||
| 536 | } else if let Some((msg, ts)) = T::registers().read_classic(1) { | ||
| 537 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||
| 538 | return Poll::Ready(Ok((msg, ts))); | ||
| 539 | } else if let Some(err) = T::registers().curr_error() { | ||
| 540 | // TODO: this is probably wrong | ||
| 541 | return Poll::Ready(Err(err)); | ||
| 542 | } | ||
| 543 | Poll::Pending | ||
| 544 | }) | ||
| 545 | .await | ||
| 546 | } | 447 | } |
| 547 | 448 | ||
| 548 | /// Returns the next received message frame | 449 | /// Returns the next received message frame |
| 549 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 450 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { |
| 550 | poll_fn(|cx| { | 451 | T::state().rx_mode.read_fd::<T>().await |
| 551 | T::state().err_waker.register(cx.waker()); | ||
| 552 | T::state().rx_waker.register(cx.waker()); | ||
| 553 | |||
| 554 | if let Some((msg, ts)) = T::registers().read_fd(0) { | ||
| 555 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||
| 556 | return Poll::Ready(Ok((msg, ts))); | ||
| 557 | } else if let Some((msg, ts)) = T::registers().read_fd(1) { | ||
| 558 | let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||
| 559 | return Poll::Ready(Ok((msg, ts))); | ||
| 560 | } else if let Some(err) = T::registers().curr_error() { | ||
| 561 | // TODO: this is probably wrong | ||
| 562 | return Poll::Ready(Err(err)); | ||
| 563 | } | ||
| 564 | Poll::Pending | ||
| 565 | }) | ||
| 566 | .await | ||
| 567 | } | 452 | } |
| 568 | } | 453 | } |
| 569 | 454 | ||
| 570 | pub(crate) mod sealed { | 455 | pub(crate) mod sealed { |
| 456 | use core::future::poll_fn; | ||
| 457 | use core::task::Poll; | ||
| 458 | |||
| 571 | use embassy_sync::waitqueue::AtomicWaker; | 459 | use embassy_sync::waitqueue::AtomicWaker; |
| 572 | 460 | ||
| 461 | use crate::can::_version::{BusError, Timestamp}; | ||
| 462 | use crate::can::frame::{ClassicFrame, FdFrame}; | ||
| 463 | pub enum RxMode { | ||
| 464 | NonBuffered(AtomicWaker), | ||
| 465 | } | ||
| 466 | |||
| 467 | impl RxMode { | ||
| 468 | pub fn register(&self, arg: &core::task::Waker) { | ||
| 469 | match self { | ||
| 470 | RxMode::NonBuffered(waker) => waker.register(arg), | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | pub fn on_interrupt<T: Instance>(&self, fifonr: usize) { | ||
| 475 | T::regs().ir().write(|w| w.set_rfn(fifonr, true)); | ||
| 476 | match self { | ||
| 477 | RxMode::NonBuffered(waker) => { | ||
| 478 | waker.wake(); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | pub async fn read<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> { | ||
| 484 | poll_fn(|cx| { | ||
| 485 | T::state().err_waker.register(cx.waker()); | ||
| 486 | self.register(cx.waker()); | ||
| 487 | |||
| 488 | if let Some((msg, ts)) = T::registers().read_classic(0) { | ||
| 489 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 490 | return Poll::Ready(Ok((msg, ts))); | ||
| 491 | } else if let Some((msg, ts)) = T::registers().read_classic(1) { | ||
| 492 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 493 | return Poll::Ready(Ok((msg, ts))); | ||
| 494 | } else if let Some(err) = T::registers().curr_error() { | ||
| 495 | // TODO: this is probably wrong | ||
| 496 | return Poll::Ready(Err(err)); | ||
| 497 | } | ||
| 498 | Poll::Pending | ||
| 499 | }) | ||
| 500 | .await | ||
| 501 | } | ||
| 502 | |||
| 503 | pub async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> { | ||
| 504 | poll_fn(|cx| { | ||
| 505 | T::state().err_waker.register(cx.waker()); | ||
| 506 | self.register(cx.waker()); | ||
| 507 | |||
| 508 | if let Some((msg, ts)) = T::registers().read_fd(0) { | ||
| 509 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 510 | return Poll::Ready(Ok((msg, ts))); | ||
| 511 | } else if let Some((msg, ts)) = T::registers().read_fd(1) { | ||
| 512 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 513 | return Poll::Ready(Ok((msg, ts))); | ||
| 514 | } else if let Some(err) = T::registers().curr_error() { | ||
| 515 | // TODO: this is probably wrong | ||
| 516 | return Poll::Ready(Err(err)); | ||
| 517 | } | ||
| 518 | Poll::Pending | ||
| 519 | }) | ||
| 520 | .await | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | pub enum TxMode { | ||
| 525 | NonBuffered(AtomicWaker), | ||
| 526 | } | ||
| 527 | |||
| 528 | impl TxMode { | ||
| 529 | pub fn register(&self, arg: &core::task::Waker) { | ||
| 530 | match self { | ||
| 531 | TxMode::NonBuffered(waker) => { | ||
| 532 | waker.register(arg); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 538 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 539 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 540 | /// transmitted, then tries again. | ||
| 541 | pub async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> { | ||
| 542 | poll_fn(|cx| { | ||
| 543 | self.register(cx.waker()); | ||
| 544 | |||
| 545 | if let Ok(dropped) = T::registers().write_classic(frame) { | ||
| 546 | return Poll::Ready(dropped); | ||
| 547 | } | ||
| 548 | |||
| 549 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 550 | // to clear. | ||
| 551 | Poll::Pending | ||
| 552 | }) | ||
| 553 | .await | ||
| 554 | } | ||
| 555 | |||
| 556 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 557 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 558 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 559 | /// transmitted, then tries again. | ||
| 560 | pub async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> { | ||
| 561 | poll_fn(|cx| { | ||
| 562 | self.register(cx.waker()); | ||
| 563 | |||
| 564 | if let Ok(dropped) = T::registers().write_fd(frame) { | ||
| 565 | return Poll::Ready(dropped); | ||
| 566 | } | ||
| 567 | |||
| 568 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 569 | // to clear. | ||
| 570 | Poll::Pending | ||
| 571 | }) | ||
| 572 | .await | ||
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 573 | pub struct State { | 576 | pub struct State { |
| 574 | pub tx_waker: AtomicWaker, | 577 | pub rx_mode: RxMode, |
| 578 | pub tx_mode: TxMode, | ||
| 579 | pub ns_per_timer_tick: u64, | ||
| 580 | |||
| 575 | pub err_waker: AtomicWaker, | 581 | pub err_waker: AtomicWaker, |
| 576 | pub rx_waker: AtomicWaker, | ||
| 577 | } | 582 | } |
| 578 | 583 | ||
| 579 | impl State { | 584 | impl State { |
| 580 | pub const fn new() -> Self { | 585 | pub const fn new() -> Self { |
| 581 | Self { | 586 | Self { |
| 582 | tx_waker: AtomicWaker::new(), | 587 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), |
| 588 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), | ||
| 589 | ns_per_timer_tick: 0, | ||
| 583 | err_waker: AtomicWaker::new(), | 590 | err_waker: AtomicWaker::new(), |
| 584 | rx_waker: AtomicWaker::new(), | ||
| 585 | } | 591 | } |
| 586 | } | 592 | } |
| 587 | } | 593 | } |
| @@ -593,6 +599,8 @@ pub(crate) mod sealed { | |||
| 593 | fn registers() -> crate::can::fd::peripheral::Registers; | 599 | fn registers() -> crate::can::fd::peripheral::Registers; |
| 594 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram; | 600 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram; |
| 595 | fn state() -> &'static State; | 601 | fn state() -> &'static State; |
| 602 | unsafe fn mut_state() -> &'static mut State; | ||
| 603 | fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; | ||
| 596 | 604 | ||
| 597 | #[cfg(not(stm32h7))] | 605 | #[cfg(not(stm32h7))] |
| 598 | fn configure_msg_ram() {} | 606 | fn configure_msg_ram() {} |
| @@ -694,10 +702,31 @@ macro_rules! impl_fdcan { | |||
| 694 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram { | 702 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram { |
| 695 | &crate::pac::$msg_ram_inst | 703 | &crate::pac::$msg_ram_inst |
| 696 | } | 704 | } |
| 705 | unsafe fn mut_state() -> & 'static mut sealed::State { | ||
| 706 | static mut STATE: sealed::State = sealed::State::new(); | ||
| 707 | & mut STATE | ||
| 708 | } | ||
| 697 | fn state() -> &'static sealed::State { | 709 | fn state() -> &'static sealed::State { |
| 698 | static STATE: sealed::State = sealed::State::new(); | 710 | unsafe { peripherals::$inst::mut_state() } |
| 699 | &STATE | ||
| 700 | } | 711 | } |
| 712 | |||
| 713 | #[cfg(feature = "time")] | ||
| 714 | fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||
| 715 | let now_embassy = embassy_time::Instant::now(); | ||
| 716 | if ns_per_timer_tick == 0 { | ||
| 717 | return now_embassy; | ||
| 718 | } | ||
| 719 | let cantime = { Self::regs().tscv().read().tsc() }; | ||
| 720 | let delta = cantime.overflowing_sub(ts_val).0 as u64; | ||
| 721 | let ns = ns_per_timer_tick * delta as u64; | ||
| 722 | now_embassy - embassy_time::Duration::from_nanos(ns) | ||
| 723 | } | ||
| 724 | |||
| 725 | #[cfg(not(feature = "time"))] | ||
| 726 | fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||
| 727 | ts_val | ||
| 728 | } | ||
| 729 | |||
| 701 | } | 730 | } |
| 702 | 731 | ||
| 703 | impl Instance for peripherals::$inst {} | 732 | impl Instance for peripherals::$inst {} |
