From 8d43fb4da4712dd9bb5a2ae343168e536c2b3129 Mon Sep 17 00:00:00 2001
From: Corey Schuhen <cschuhen@gmail.com>
Date: Wed, 27 Mar 2024 19:43:19 +1000
Subject: [PATCH] CAN: Use the same testing code for BXCAN and FDCAN h/w.

---
 tests/stm32/src/bin/can.rs        |  50 +++-----
 tests/stm32/src/bin/can_common.rs | 112 +++++++++++++++++
 tests/stm32/src/bin/fdcan.rs      | 195 ++++++------------------------
 3 files changed, 163 insertions(+), 194 deletions(-)
 create mode 100644 tests/stm32/src/bin/can_common.rs

diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index c08c69a3b..74d84c42f 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -6,17 +6,19 @@
 #[path = "../common.rs"]
 mod common;
 use common::*;
-use defmt::assert;
 use embassy_executor::Spawner;
 use embassy_stm32::bind_interrupts;
 use embassy_stm32::can::bx::filter::Mask32;
-use embassy_stm32::can::bx::{Fifo, Frame, StandardId};
+use embassy_stm32::can::bx::Fifo;
 use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
 use embassy_stm32::gpio::{Input, Pull};
 use embassy_stm32::peripherals::CAN1;
-use embassy_time::{Duration, Instant};
+use embassy_time::Duration;
 use {defmt_rtt as _, panic_probe as _};
 
+mod can_common;
+use can_common::*;
+
 bind_interrupts!(struct Irqs {
     CAN1_RX0 => Rx0InterruptHandler<CAN1>;
     CAN1_RX1 => Rx1InterruptHandler<CAN1>;
@@ -29,6 +31,11 @@ async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(config());
     info!("Hello World!");
 
+    let options = TestOptions {
+        max_latency: Duration::from_micros(1200),
+        max_buffered: 2,
+    };
+
     let can = peri!(p, CAN);
     let tx = peri!(p, CAN_TX);
     let mut rx = peri!(p, CAN_RX);
@@ -58,40 +65,13 @@ async fn main(_spawner: Spawner) {
 
     info!("Can configured");
 
-    let mut i: u8 = 0;
-    loop {
-        let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
+    run_can_tests(&mut can, &options).await;
 
-        info!("Transmitting frame...");
-        let tx_ts = Instant::now();
-        can.write(&tx_frame).await;
-
-        let envelope = can.read().await.unwrap();
-        info!("Frame received!");
-
-        info!("loopback time {}", envelope.ts);
-        info!("loopback frame {=u8}", envelope.frame.data()[0]);
-
-        let latency = envelope.ts.saturating_duration_since(tx_ts);
-        info!("loopback latency {} us", latency.as_micros());
-
-        // Theoretical minimum latency is 55us, actual is usually ~80us
-        const MIN_LATENCY: Duration = Duration::from_micros(50);
-        const MAX_LATENCY: Duration = Duration::from_micros(150);
-        assert!(
-            MIN_LATENCY <= latency && latency <= MAX_LATENCY,
-            "{} <= {} <= {}",
-            MIN_LATENCY,
-            latency,
-            MAX_LATENCY
-        );
-
-        i += 1;
-        if i > 10 {
-            break;
-        }
-    }
+    // Test again with a split
+    let (mut tx, mut rx) = can.split();
+    run_split_can_tests(&mut tx, &mut rx, &options).await;
 
     info!("Test OK");
+
     cortex_m::asm::bkpt();
 }
diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs
new file mode 100644
index 000000000..4b39269cc
--- /dev/null
+++ b/tests/stm32/src/bin/can_common.rs
@@ -0,0 +1,112 @@
+use defmt::{assert, *};
+use embassy_stm32::can;
+use embassy_time::{Duration, Instant};
+
+#[derive(Clone, Copy, Debug)]
+pub struct TestOptions {
+    pub max_latency: Duration,
+    pub max_buffered: u8,
+}
+
+pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
+    let mut i: u8 = 0;
+    loop {
+        //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap();
+        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
+
+        //info!("Transmitting frame...");
+        let tx_ts = Instant::now();
+        can.write(&tx_frame).await;
+
+        let (frame, timestamp) = can.read().await.unwrap().parts();
+        //info!("Frame received!");
+
+        // Check data.
+        assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
+
+        //info!("loopback time {}", timestamp);
+        //info!("loopback frame {=u8}", frame.data()[0]);
+        let latency = timestamp.saturating_duration_since(tx_ts);
+        info!("loopback latency {} us", latency.as_micros());
+
+        // Theoretical minimum latency is 55us, actual is usually ~80us
+        const MIN_LATENCY: Duration = Duration::from_micros(50);
+        // Was failing at 150 but we are not getting a real time stamp. I'm not
+        // sure if there are other delays
+        assert!(
+            MIN_LATENCY <= latency && latency <= options.max_latency,
+            "{} <= {} <= {}",
+            MIN_LATENCY,
+            latency,
+            options.max_latency
+        );
+
+        i += 1;
+        if i > 5 {
+            break;
+        }
+    }
+
+    // Below here, check that we can receive from both FIFO0 and FIFO1
+    // Above we configured FIFO1 for extended ID packets. There are only 3 slots
+    // in each FIFO so make sure we write enough to fill them both up before reading.
+    for i in 0..options.max_buffered {
+        // Try filling up the RX FIFO0 buffers
+        //let tx_frame = if 0 != (i & 0x01) {
+        let tx_frame = if i < options.max_buffered / 2 {
+            info!("Transmitting standard frame {}", i);
+            can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap()
+        } else {
+            info!("Transmitting extended frame {}", i);
+            can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap()
+        };
+        can.write(&tx_frame).await;
+    }
+
+    // Try and receive all 6 packets
+    for _i in 0..options.max_buffered {
+        let (frame, _ts) = can.read().await.unwrap().parts();
+        match frame.id() {
+            embedded_can::Id::Extended(_id) => {
+                info!("Extended received! {}", frame.data()[0]);
+                //info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
+            }
+            embedded_can::Id::Standard(_id) => {
+                info!("Standard received! {}", frame.data()[0]);
+                //info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
+            }
+        }
+    }
+}
+
+pub async fn run_split_can_tests<'d, T: can::Instance>(
+    tx: &mut can::CanTx<'d, T>,
+    rx: &mut can::CanRx<'d, T>,
+    options: &TestOptions,
+) {
+    for i in 0..options.max_buffered {
+        // Try filling up the RX FIFO0 buffers
+        //let tx_frame = if 0 != (i & 0x01) {
+        let tx_frame = if i < options.max_buffered / 2 {
+            info!("Transmitting standard frame {}", i);
+            can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap()
+        } else {
+            info!("Transmitting extended frame {}", i);
+            can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap()
+        };
+        tx.write(&tx_frame).await;
+    }
+
+    // Try and receive all 6 packets
+    for _i in 0..options.max_buffered {
+        let (frame, _ts) = rx.read().await.unwrap().parts();
+        match frame.id() {
+            embedded_can::Id::Extended(_id) => {
+                info!("Extended received! {}", frame.data()[0]);
+            }
+            embedded_can::Id::Standard(_id) => {
+                info!("Standard received! {}", frame.data()[0]);
+            }
+        }
+    }
+}
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index bddfa7684..27bdd038a 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -6,13 +6,15 @@
 #[path = "../common.rs"]
 mod common;
 use common::*;
-use defmt::assert;
 use embassy_executor::Spawner;
 use embassy_stm32::peripherals::*;
 use embassy_stm32::{bind_interrupts, can, Config};
-use embassy_time::{Duration, Instant};
+use embassy_time::Duration;
 use {defmt_rtt as _, panic_probe as _};
 
+mod can_common;
+use can_common::*;
+
 bind_interrupts!(struct Irqs2 {
     FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
     FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
@@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 {
     FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
 });
 
-struct TestOptions {
-    config: Config,
-    max_latency: Duration,
-    second_fifo_working: bool,
-}
-
 #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
-fn options() -> TestOptions {
+fn options() -> (Config, TestOptions) {
     use embassy_stm32::rcc;
     info!("H75 config");
     let mut c = config();
@@ -38,15 +34,17 @@ fn options() -> TestOptions {
         mode: rcc::HseMode::Oscillator,
     });
     c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
-    TestOptions {
-        config: c,
-        max_latency: Duration::from_micros(1200),
-        second_fifo_working: false,
-    }
+    (
+        c,
+        TestOptions {
+            max_latency: Duration::from_micros(1200),
+            max_buffered: 3,
+        },
+    )
 }
 
 #[cfg(any(feature = "stm32h7a3zi"))]
-fn options() -> TestOptions {
+fn options() -> (Config, TestOptions) {
     use embassy_stm32::rcc;
     info!("H7a config");
     let mut c = config();
@@ -55,29 +53,33 @@ fn options() -> TestOptions {
         mode: rcc::HseMode::Oscillator,
     });
     c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
-    TestOptions {
-        config: c,
-        max_latency: Duration::from_micros(1200),
-        second_fifo_working: false,
-    }
+    (
+        c,
+        TestOptions {
+            max_latency: Duration::from_micros(1200),
+            max_buffered: 3,
+        },
+    )
 }
 
 #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
-fn options() -> TestOptions {
+fn options() -> (Config, TestOptions) {
     info!("G4 config");
-    TestOptions {
-        config: config(),
-        max_latency: Duration::from_micros(500),
-        second_fifo_working: true,
-    }
+    (
+        config(),
+        TestOptions {
+            max_latency: Duration::from_micros(500),
+            max_buffered: 6,
+        },
+    )
 }
 
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     //let peripherals = embassy_stm32::init(config());
 
-    let options = options();
-    let peripherals = embassy_stm32::init(options.config);
+    let (config, options) = options();
+    let peripherals = embassy_stm32::init(config);
 
     let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
     let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
@@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) {
     let mut can = can.into_internal_loopback_mode();
     let mut can2 = can2.into_internal_loopback_mode();
 
+    run_can_tests(&mut can, &options).await;
+    run_can_tests(&mut can2, &options).await;
+
     info!("CAN Configured");
 
-    let mut i: u8 = 0;
-    loop {
-        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
-
-        info!("Transmitting frame...");
-        let tx_ts = Instant::now();
-        can.write(&tx_frame).await;
-
-        let (frame, timestamp) = can.read().await.unwrap().parts();
-        info!("Frame received!");
-
-        // Check data.
-        assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
-
-        info!("loopback time {}", timestamp);
-        info!("loopback frame {=u8}", frame.data()[0]);
-        let latency = timestamp.saturating_duration_since(tx_ts);
-        info!("loopback latency {} us", latency.as_micros());
-
-        // Theoretical minimum latency is 55us, actual is usually ~80us
-        const MIN_LATENCY: Duration = Duration::from_micros(50);
-        // Was failing at 150 but we are not getting a real time stamp. I'm not
-        // sure if there are other delays
-        assert!(
-            MIN_LATENCY <= latency && latency <= options.max_latency,
-            "{} <= {} <= {}",
-            MIN_LATENCY,
-            latency,
-            options.max_latency
-        );
-
-        i += 1;
-        if i > 10 {
-            break;
-        }
-    }
-
-    let mut i: u8 = 0;
-    loop {
-        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
-
-        info!("Transmitting frame...");
-        let tx_ts = Instant::now();
-        can2.write(&tx_frame).await;
-
-        let (frame, timestamp) = can2.read().await.unwrap().parts();
-        info!("Frame received!");
-
-        //print_regs().await;
-        // Check data.
-        assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
-
-        info!("loopback time {}", timestamp);
-        info!("loopback frame {=u8}", frame.data()[0]);
-        let latency = timestamp.saturating_duration_since(tx_ts);
-        info!("loopback latency {} us", latency.as_micros());
-
-        // Theoretical minimum latency is 55us, actual is usually ~80us
-        const MIN_LATENCY: Duration = Duration::from_micros(50);
-        // Was failing at 150 but we are not getting a real time stamp. I'm not
-        // sure if there are other delays
-        assert!(
-            MIN_LATENCY <= latency && latency <= options.max_latency,
-            "{} <= {} <= {}",
-            MIN_LATENCY,
-            latency,
-            options.max_latency
-        );
-
-        i += 1;
-        if i > 10 {
-            break;
-        }
-    }
-
-    let max_buffered = if options.second_fifo_working { 6 } else { 3 };
-
-    // Below here, check that we can receive from both FIFO0 and FIFO0
-    // Above we configured FIFO1 for extended ID packets. There are only 3 slots
-    // in each FIFO so make sure we write enough to fill them both up before reading.
-    for i in 0..3 {
-        // Try filling up the RX FIFO0 buffers with standard packets
-        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
-        info!("Transmitting frame {}", i);
-        can.write(&tx_frame).await;
-    }
-    for i in 3..max_buffered {
-        // Try filling up the RX FIFO0 buffers with extended packets
-        let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
-        info!("Transmitting frame {}", i);
-        can.write(&tx_frame).await;
-    }
-
-    // Try and receive all 6 packets
-    for i in 0..max_buffered {
-        let (frame, _ts) = can.read().await.unwrap().parts();
-        match frame.id() {
-            embedded_can::Id::Extended(id) => {
-                info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
-            }
-            embedded_can::Id::Standard(id) => {
-                info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
-            }
-        }
-    }
-
     // Test again with a split
     let (mut tx, mut rx) = can.split();
-    for i in 0..3 {
-        // Try filling up the RX FIFO0 buffers with standard packets
-        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
-        info!("Transmitting frame {}", i);
-        tx.write(&tx_frame).await;
-    }
-    for i in 3..max_buffered {
-        // Try filling up the RX FIFO0 buffers with extended packets
-        let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
-        info!("Transmitting frame {}", i);
-        tx.write(&tx_frame).await;
-    }
-
-    // Try and receive all 6 packets
-    for i in 0..max_buffered {
-        let (frame, _ts) = rx.read().await.unwrap().parts();
-        match frame.id() {
-            embedded_can::Id::Extended(id) => {
-                info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
-            }
-            embedded_can::Id::Standard(id) => {
-                info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
-            }
-        }
-    }
+    let (mut tx2, mut rx2) = can2.split();
+    run_split_can_tests(&mut tx, &mut rx, &options).await;
+    run_split_can_tests(&mut tx2, &mut rx2, &options).await;
 
     info!("Test OK");
     cortex_m::asm::bkpt();