Validate FCS in fifo_read() and refactor tests.

Adding TestHarnass to declutter the tests.
Also added a test for FCS and SPI_CRC.
This commit is contained in:
René van Dorst 2023-08-26 01:29:06 +02:00
parent 7f7256050c
commit 13a0be6289
3 changed files with 307 additions and 175 deletions

View file

@ -257,29 +257,30 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
0x2D02_EF8D, 0x2D02_EF8D,
]; ];
/// Generate Ethernet Frame Check Sequence
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug)] #[derive(Debug)]
pub struct ETH_FSC(pub u32); pub struct ETH_FCS(pub u32);
impl ETH_FSC { impl ETH_FCS {
pub const CRC32_OK: u32 = 0x2144_df1c; pub const CRC32_OK: u32 = 0x2144_df1c;
#[must_use] #[must_use]
pub fn new(data: &[u8]) -> Self { pub fn new(data: &[u8]) -> Self {
let fsc = data.iter().fold(u32::MAX, |crc, byte| { let fcs = data.iter().fold(u32::MAX, |crc, byte| {
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
}) ^ u32::MAX; }) ^ u32::MAX;
Self(fsc) Self(fcs)
} }
#[must_use] #[must_use]
pub fn update(self, data: &[u8]) -> Self { pub fn update(self, data: &[u8]) -> Self {
let fsc = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
}) ^ u32::MAX; }) ^ u32::MAX;
Self(fsc) Self(fcs)
} }
#[must_use] #[must_use]
@ -319,24 +320,24 @@ mod tests {
]; ];
// Packet A // Packet A
let own_crc = ETH_FSC::new(&packet_a[0..60]); let own_crc = ETH_FCS::new(&packet_a[0..60]);
let crc_bytes = own_crc.hton_bytes(); let crc_bytes = own_crc.hton_bytes();
println!("{:08x} {:02x?}", own_crc.0, crc_bytes); println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
assert_eq!(&crc_bytes, &packet_a[60..64]); assert_eq!(&crc_bytes, &packet_a[60..64]);
let own_crc = ETH_FSC::new(packet_a); let own_crc = ETH_FCS::new(packet_a);
println!("{:08x}", own_crc.0); println!("{:08x}", own_crc.0);
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
// Packet B // Packet B
let own_crc = ETH_FSC::new(&packet_b[0..60]); let own_crc = ETH_FCS::new(&packet_b[0..60]);
let crc_bytes = own_crc.hton_bytes(); let crc_bytes = own_crc.hton_bytes();
println!("{:08x} {:02x?}", own_crc.0, crc_bytes); println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
assert_eq!(&crc_bytes, &packet_b[60..64]); assert_eq!(&crc_bytes, &packet_b[60..64]);
let own_crc = ETH_FSC::new(packet_b); let own_crc = ETH_FCS::new(packet_b);
println!("{:08x}", own_crc.0); println!("{:08x}", own_crc.0);
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
} }
#[test] #[test]
@ -349,9 +350,9 @@ mod tests {
]; ];
let (part_a, part_b) = full_data.split_at(16); let (part_a, part_b) = full_data.split_at(16);
let crc_partially = ETH_FSC::new(part_a).update(part_b); let crc_partially = ETH_FCS::new(part_a).update(part_b);
let crc_full = ETH_FSC::new(full_data); let crc_full = ETH_FCS::new(full_data);
assert_eq!(crc_full.0, crc_partially.0); assert_eq!(crc_full.0, crc_partially.0);
} }

View file

@ -13,7 +13,7 @@ mod phy;
mod regs; mod regs;
use ch::driver::LinkState; use ch::driver::LinkState;
pub use crc32::ETH_FSC; pub use crc32::ETH_FCS;
use crc8::crc8; use crc8::crc8;
use embassy_futures::select::{select, Either}; use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch; use embassy_net_driver_channel as ch;
@ -35,16 +35,22 @@ pub const PHYID: u32 = 0x0283_BC91;
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum AdinError<E> { pub enum AdinError<E> {
/// SPI-BUS Error
Spi(E), Spi(E),
SENDERROR, /// Ethernet FCS error
READERROR, FCS,
CRC, /// SPI Header CRC error
SPI_CRC,
/// Received or sended ethernet packet is too big
PACKET_TOO_BIG, PACKET_TOO_BIG,
/// Received or sended ethernet packet is too small
PACKET_TOO_SMALL, PACKET_TOO_SMALL,
/// MDIO transaction timeout
MDIO_ACC_TIMEOUT, MDIO_ACC_TIMEOUT,
} }
pub type AEResult<T, SPIError> = core::result::Result<T, AdinError<SPIError>>; pub type AEResult<T, SPIError> = core::result::Result<T, AdinError<SPIError>>;
/// Internet PHY address
pub const MDIO_PHY_ADDR: u8 = 0x01; pub const MDIO_PHY_ADDR: u8 = 0x01;
/// Maximum Transmission Unit /// Maximum Transmission Unit
@ -59,9 +65,9 @@ const TURN_AROUND_BYTE: u8 = 0x00;
/// Packet minimal frame/packet length /// Packet minimal frame/packet length
const ETH_MIN_LEN: usize = 64; const ETH_MIN_LEN: usize = 64;
/// Ethernet `Frame Check Sequence` length /// Ethernet `Frame Check Sequence` length
const FSC_LEN: usize = 4; const FCS_LEN: usize = 4;
/// Packet minimal frame/packet length without `Frame Check Sequence` length /// Packet minimal frame/packet length without `Frame Check Sequence` length
const ETH_MIN_WITHOUT_FSC_LEN: usize = ETH_MIN_LEN - FSC_LEN; const ETH_MIN_WITHOUT_FCS_LEN: usize = ETH_MIN_LEN - FCS_LEN;
/// SPI Header, contains SPI action and register id. /// SPI Header, contains SPI action and register id.
const SPI_HEADER_LEN: usize = 2; const SPI_HEADER_LEN: usize = 2;
@ -74,7 +80,7 @@ const FRAME_HEADER_LEN: usize = 2;
/// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write. /// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write.
const SPI_SPACE_MULTIPULE: usize = 3; const SPI_SPACE_MULTIPULE: usize = 3;
// P1 = 0x00, P2 = 0x01 /// P1 = 0x00, P2 = 0x01
const PORT_ID_BYTE: u8 = 0x00; const PORT_ID_BYTE: u8 = 0x00;
/// Type alias for the embassy-net driver for ADIN1110 /// Type alias for the embassy-net driver for ADIN1110
@ -100,12 +106,18 @@ pub struct ADIN1110<SPI> {
spi: SPI, spi: SPI,
/// Enable CRC on SPI transfer. /// Enable CRC on SPI transfer.
/// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled. /// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled.
crc: bool, spi_crc: bool,
/// Append FCS by the application of transmit packet, false = FCS is appended by the MAC, true = FCS appended by the application.
append_fcs_on_tx: bool,
} }
impl<SPI: SpiDevice> ADIN1110<SPI> { impl<SPI: SpiDevice> ADIN1110<SPI> {
pub fn new(spi: SPI, crc: bool) -> Self { pub fn new(spi: SPI, spi_crc: bool, append_fcs_on_tx: bool) -> Self {
Self { spi, crc } Self {
spi,
spi_crc,
append_fcs_on_tx,
}
} }
pub async fn read_reg(&mut self, reg: sr) -> AEResult<u32, SPI::Error> { pub async fn read_reg(&mut self, reg: sr) -> AEResult<u32, SPI::Error> {
@ -116,7 +128,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
spi_hdr.set_addr(reg); spi_hdr.set_addr(reg);
let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
if self.crc { if self.spi_crc {
// Add CRC for header data // Add CRC for header data
let _ = tx_buf.push(crc8(&tx_buf)); let _ = tx_buf.push(crc8(&tx_buf));
} }
@ -126,16 +138,16 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
let mut rx_buf = [0; 5]; let mut rx_buf = [0; 5];
let spi_read_len = if self.crc { rx_buf.len() } else { rx_buf.len() - 1 }; let spi_read_len = if self.spi_crc { rx_buf.len() } else { rx_buf.len() - 1 };
let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])]; let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])];
self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
if self.crc { if self.spi_crc {
let crc = crc8(&rx_buf[0..4]); let crc = crc8(&rx_buf[0..4]);
if crc != rx_buf[4] { if crc != rx_buf[4] {
return Err(AdinError::CRC); return Err(AdinError::SPI_CRC);
} }
} }
@ -156,7 +168,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
spi_hdr.set_addr(reg); spi_hdr.set_addr(reg);
let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
if self.crc { if self.spi_crc {
// Add CRC for header data // Add CRC for header data
let _ = tx_buf.push(crc8(&tx_buf)); let _ = tx_buf.push(crc8(&tx_buf));
} }
@ -164,7 +176,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
let val = value.to_be_bytes(); let val = value.to_be_bytes();
let _ = tx_buf.extend_from_slice(val.as_slice()); let _ = tx_buf.extend_from_slice(val.as_slice());
if self.crc { if self.spi_crc {
// Add CRC for header data // Add CRC for header data
let _ = tx_buf.push(crc8(val.as_slice())); let _ = tx_buf.push(crc8(val.as_slice()));
} }
@ -193,18 +205,18 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
/// Read out fifo ethernet packet memory received via the wire. /// Read out fifo ethernet packet memory received via the wire.
pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult<usize, SPI::Error> { pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult<usize, SPI::Error> {
const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN; const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN;
const TAIL_LEN: usize = FSC_LEN + SPI_SPACE_MULTIPULE; const TAIL_LEN: usize = FCS_LEN + SPI_SPACE_MULTIPULE;
let mut tx_buf = Vec::<u8, HEAD_LEN>::new(); let mut tx_buf = Vec::<u8, HEAD_LEN>::new();
// Size of the frame, also includes the `frame header` and `FSC`. // Size of the frame, also includes the `frame header` and `FCS`.
let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize; let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize;
if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN { if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN {
return Err(AdinError::PACKET_TOO_SMALL); return Err(AdinError::PACKET_TOO_SMALL);
} }
let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FSC_LEN; let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FCS_LEN;
if packet_size > frame.len() { if packet_size > frame.len() {
#[cfg(feature = "defmt")] #[cfg(feature = "defmt")]
@ -217,7 +229,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
spi_hdr.set_addr(sr::RX); spi_hdr.set_addr(sr::RX);
let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
if self.crc { if self.spi_crc {
// Add CRC for header data // Add CRC for header data
let _ = tx_buf.push(crc8(&tx_buf)); let _ = tx_buf.push(crc8(&tx_buf));
} }
@ -226,27 +238,36 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
let _ = tx_buf.push(TURN_AROUND_BYTE); let _ = tx_buf.push(TURN_AROUND_BYTE);
let mut frame_header = [0, 0]; let mut frame_header = [0, 0];
let mut fsc_and_extra = [0; TAIL_LEN]; let mut fcs_and_extra = [0; TAIL_LEN];
// Packet read of write to the MAC packet buffer must be a multipul of 4! // Packet read of write to the MAC packet buffer must be a multipul of 4!
let tail_size = (fifo_frame_size & 0x03) + FSC_LEN; let tail_size = (fifo_frame_size & 0x03) + FCS_LEN;
let mut spi_op = [ let mut spi_op = [
Operation::Write(&tx_buf), Operation::Write(&tx_buf),
Operation::Read(&mut frame_header), Operation::Read(&mut frame_header),
Operation::Read(&mut frame[0..packet_size]), Operation::Read(&mut frame[0..packet_size]),
Operation::Read(&mut fsc_and_extra[0..tail_size]), Operation::Read(&mut fcs_and_extra[0..tail_size]),
]; ];
self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
// According to register `CONFIG2`, bit 5 `CRC_APPEND` discription:
// "Similarly, on receive, the CRC32 is forwarded with the frame to the host where the host must verify it is correct."
// The application must allways check the FCS. It seems that the MAC/PHY has no option to handle this.
let fcs_calc = ETH_FCS::new(&frame[0..packet_size]);
if fcs_calc.hton_bytes() == fcs_and_extra[0..4] {
Ok(packet_size) Ok(packet_size)
} else {
Err(AdinError::FCS)
}
} }
/// Write to fifo ethernet packet memory send over the wire. /// Write to fifo ethernet packet memory send over the wire.
pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> {
const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN;
const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + SPI_SPACE_MULTIPULE; const TAIL_LEN: usize = ETH_MIN_LEN - FCS_LEN + FCS_LEN + SPI_SPACE_MULTIPULE;
if frame.len() < (6 + 6 + 2) { if frame.len() < (6 + 6 + 2) {
return Err(AdinError::PACKET_TOO_SMALL); return Err(AdinError::PACKET_TOO_SMALL);
@ -269,7 +290,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice())
.map_err(|_e| AdinError::PACKET_TOO_BIG)?; .map_err(|_e| AdinError::PACKET_TOO_BIG)?;
if self.crc { if self.spi_crc {
// Add CRC for header data // Add CRC for header data
head_data head_data
.push(crc8(&head_data[0..2])) .push(crc8(&head_data[0..2]))
@ -281,18 +302,22 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
.extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice())
.map_err(|_e| AdinError::PACKET_TOO_BIG)?; .map_err(|_e| AdinError::PACKET_TOO_BIG)?;
let mut frame_fcs = ETH_FSC::new(frame);
// ADIN1110 MAC and PHY don´t accept ethernet packet smaller than 64 bytes. // ADIN1110 MAC and PHY don´t accept ethernet packet smaller than 64 bytes.
// So padded the data minus the FCS, FCS is automatilly added to by the MAC. // So padded the data minus the FCS, FCS is automatilly added to by the MAC.
if frame.len() < ETH_MIN_WITHOUT_FSC_LEN { if frame.len() < ETH_MIN_WITHOUT_FCS_LEN {
let _ = tail_data.resize(ETH_MIN_WITHOUT_FSC_LEN - frame.len(), 0x00); let _ = tail_data.resize(ETH_MIN_WITHOUT_FCS_LEN - frame.len(), 0x00);
}
// Append FCS by the application
if self.append_fcs_on_tx {
let mut frame_fcs = ETH_FCS::new(frame);
if !tail_data.is_empty() {
frame_fcs = frame_fcs.update(&tail_data); frame_fcs = frame_fcs.update(&tail_data);
} }
// Add ethernet FCS only over the ethernet packet.
// Only usefull when `CONFIG0`, `Transmit Frame Check Sequence Validation Enable` bit is enabled.
let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice()); let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice());
}
// len = frame_size + optional padding + 2 bytes Frame header // len = frame_size + optional padding + 2 bytes Frame header
let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN; let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN;
@ -583,7 +608,8 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
spi_dev: SPI, spi_dev: SPI,
int: INT, int: INT,
mut reset: RST, mut reset: RST,
crc: bool, spi_crc: bool,
append_fcs_on_tx: bool,
) -> (Device<'_>, Runner<'_, SPI, INT, RST>) { ) -> (Device<'_>, Runner<'_, SPI, INT, RST>) {
use crate::regs::{IMask0, IMask1}; use crate::regs::{IMask0, IMask1};
@ -602,7 +628,7 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
Timer::after(Duration::from_millis(50)).await; Timer::after(Duration::from_millis(50)).await;
// Create device // Create device
let mut mac = ADIN1110::new(spi_dev, crc); let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
// Check PHYID // Check PHYID
let id = mac.read_reg(sr::PHYID).await.unwrap(); let id = mac.read_reg(sr::PHYID).await.unwrap();
@ -630,18 +656,15 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
.unwrap(); .unwrap();
} }
// Check if the FCS is valid in the TX path.
let tx_fsc_validation_enable = true;
// Config0 // Config0
let mut config0 = Config0(0x0000_0006); let mut config0 = Config0(0x0000_0006);
config0.set_txfcsve(tx_fsc_validation_enable); config0.set_txfcsve(mac.append_fcs_on_tx);
mac.write_reg(sr::CONFIG0, config0.0).await.unwrap(); mac.write_reg(sr::CONFIG0, config0.0).await.unwrap();
// Config2 // Config2
let mut config2 = Config2(0x0000_0800); let mut config2 = Config2(0x0000_0800);
// crc_append must be disable if tx_fsc_validation_enable is true! // crc_append must be disable if tx_fcs_validation_enable is true!
config2.set_crc_append(!tx_fsc_validation_enable); config2.set_crc_append(!mac.append_fcs_on_tx);
mac.write_reg(sr::CONFIG2, config2.0).await.unwrap(); mac.write_reg(sr::CONFIG2, config2.0).await.unwrap();
// Pin Mux Config 1 // Pin Mux Config 1
@ -721,6 +744,7 @@ mod tests {
use embedded_hal_1::digital::{ErrorType, OutputPin}; use embedded_hal_1::digital::{ErrorType, OutputPin};
use embedded_hal_async::delay::DelayUs; use embedded_hal_async::delay::DelayUs;
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_hal_mock::common::Generic;
use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction}; use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -759,6 +783,30 @@ mod tests {
} }
} }
struct TestHarnass {
spe: ADIN1110<ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay>>,
spi: Generic<SpiTransaction>,
}
impl TestHarnass {
pub fn new(expectations: &[SpiTransaction], spi_crc: bool, append_fcs_on_tx: bool) -> Self {
let cs = CsPinMock::default();
let delay = MockDelay {};
let spi = SpiMock::new(expectations);
let spi_dev: ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay> =
ExclusiveDevice::new(spi.clone(), cs, delay);
let spe: ADIN1110<
ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay>,
> = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
Self { spe, spi }
}
pub fn done(&mut self) {
self.spi.done();
}
}
#[futures_test::test] #[futures_test::test]
async fn mac_read_registers_without_crc() { async fn mac_read_registers_without_crc() {
// Configure expectations // Configure expectations
@ -772,22 +820,20 @@ mod tests {
SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]), SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]),
SpiTransaction::flush(), SpiTransaction::flush(),
]; ];
let mut spi = SpiMock::new(&expectations);
let cs = CsPinMock::default(); // Create TestHarnass
let delay = MockDelay {}; let mut th = TestHarnass::new(&expectations, false, true);
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, false);
// Read PHIID // Read PHIID
let val = spe.read_reg(sr::PHYID).await.expect("Error"); let val = th.spe.read_reg(sr::PHYID).await.expect("Error");
assert_eq!(val, 0x0283_BC91); assert_eq!(val, 0x0283_BC91);
// Read CAPAVILITY // Read CAPAVILITY
let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error");
assert_eq!(val, 0x0000_06C3); assert_eq!(val, 0x0000_06C3);
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -803,26 +849,23 @@ mod tests {
SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]), SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]),
SpiTransaction::flush(), SpiTransaction::flush(),
]; ];
let mut spi = SpiMock::new(&expectations);
let cs = CsPinMock::default(); // Create TestHarnass
let delay = MockDelay {}; let mut th = TestHarnass::new(&expectations, true, true);
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true);
assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215); assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215);
assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57); assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57);
// Read PHIID // Read PHIID
let val = spe.read_reg(sr::PHYID).await.expect("Error"); let val = th.spe.read_reg(sr::PHYID).await.expect("Error");
assert_eq!(val, 0x0283_BC91); assert_eq!(val, 0x0283_BC91);
// Read CAPAVILITY // Read CAPAVILITY
let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error");
assert_eq!(val, 0x0000_06C3); assert_eq!(val, 0x0000_06C3);
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -832,18 +875,15 @@ mod tests {
SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]), SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]),
SpiTransaction::flush(), SpiTransaction::flush(),
]; ];
let mut spi = SpiMock::new(&expectations);
let cs = CsPinMock::default(); // Create TestHarnass
let delay = MockDelay {}; let mut th = TestHarnass::new(&expectations, false, true);
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, false);
// Write reg: 0x1FFF // Write reg: 0x1FFF
assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -854,17 +894,14 @@ mod tests {
SpiTransaction::flush(), SpiTransaction::flush(),
]; ];
// Basic test init block // Create TestHarnass
let mut spi = SpiMock::new(&expectations); let mut th = TestHarnass::new(&expectations, true, true);
let cs = CsPinMock::default();
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true);
// Write reg: 0x1FFF // Write reg: 0x1FFF
assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -885,7 +922,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100); let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// Padding // Padding
if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
tail.resize(padding_len, 0x00); tail.resize(padding_len, 0x00);
} }
// Packet FCS + optinal padding // Packet FCS + optinal padding
@ -894,17 +931,49 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations); // Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
let cs = CsPinMock::default(); assert!(th.spe.write_fifo(&packet).await.is_ok());
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true); // Mark end of the SPI test.
th.done();
}
assert!(spe.write_fifo(&packet).await.is_ok()); #[futures_test::test]
async fn write_packet_to_fifo_minimal_with_crc_without_fcs() {
// Configure expectations
let mut expectations = vec![];
spi.done(); // Write TX_SIZE reg
expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 62, 186]));
expectations.push(SpiTransaction::flush());
// Write TX reg.
// SPI Header + optional CRC + Frame Header
expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0]));
// Packet data
let packet = [0xFF_u8; 60];
expectations.push(SpiTransaction::write_vec(packet.to_vec()));
let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// Padding
if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
tail.resize(padding_len, 0x00);
}
// Packet FCS + optinal padding
tail.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE]);
expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush());
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, false);
assert!(th.spe.write_fifo(&packet).await.is_ok());
// Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -926,7 +995,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100); let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// Padding // Padding
if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
tail.resize(padding_len, 0x00); tail.resize(padding_len, 0x00);
} }
// Packet FCS + optinal padding // Packet FCS + optinal padding
@ -935,17 +1004,13 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations); // Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
let cs = CsPinMock::default(); assert!(th.spe.write_fifo(&packet).await.is_ok());
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true); // Mark end of the SPI test.
th.done();
assert!(spe.write_fifo(&packet).await.is_ok());
spi.done();
} }
#[futures_test::test] #[futures_test::test]
@ -958,24 +1023,23 @@ mod tests {
// Max packet size = MAX_BUFF - FRAME_HEADER_LEN // Max packet size = MAX_BUFF - FRAME_HEADER_LEN
let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1]; let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1];
let mut spi = SpiMock::new(&expectations); // Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
let cs = CsPinMock::default();
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true);
// minimal // minimal
assert!(matches!( assert!(matches!(
spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await, th.spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await,
Err(AdinError::PACKET_TOO_SMALL) Err(AdinError::PACKET_TOO_SMALL)
)); ));
// max + 1 // max + 1
assert!(matches!(spe.write_fifo(&packet).await, Err(AdinError::PACKET_TOO_BIG))); assert!(matches!(
th.spe.write_fifo(&packet).await,
Err(AdinError::PACKET_TOO_BIG)
));
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -999,7 +1063,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100); let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// Padding // Padding
if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
tail.resize(padding_len, 0x00); tail.resize(padding_len, 0x00);
} }
// Packet FCS + optinal padding // Packet FCS + optinal padding
@ -1008,17 +1072,13 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations); // Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
let cs = CsPinMock::default(); assert!(th.spe.write_fifo(&packet).await.is_ok());
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true); // Mark end of the SPI test.
th.done();
assert!(spe.write_fifo(&packet).await.is_ok());
spi.done();
} }
#[futures_test::test] #[futures_test::test]
@ -1042,7 +1102,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100); let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// Padding // Padding
if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
tail.resize(padding_len, 0x00); tail.resize(padding_len, 0x00);
} }
// Packet FCS + optinal padding // Packet FCS + optinal padding
@ -1051,17 +1111,13 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations); // Create TestHarnass
let mut th = TestHarnass::new(&expectations, false, true);
let cs = CsPinMock::default(); assert!(th.spe.write_fifo(&packet).await.is_ok());
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, false); // Mark end of the SPI test.
th.done();
assert!(spe.write_fifo(&packet).await.is_ok());
spi.done();
} }
#[futures_test::test] #[futures_test::test]
@ -1070,7 +1126,7 @@ mod tests {
let mut expectations = vec![]; let mut expectations = vec![];
// Read RX_SIZE reg // Read RX_SIZE reg
let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FSC_LEN).unwrap(); let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FCS_LEN).unwrap();
let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
rx_size_vec.push(crc8(&rx_size_vec)); rx_size_vec.push(crc8(&rx_size_vec));
@ -1078,20 +1134,16 @@ mod tests {
expectations.push(SpiTransaction::read_vec(rx_size_vec)); expectations.push(SpiTransaction::read_vec(rx_size_vec));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations);
let cs = CsPinMock::default();
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true);
let mut frame = [0; MTU]; let mut frame = [0; MTU];
let ret = spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await; // Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
let ret = th.spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await;
assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG))); assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG)));
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
@ -1102,11 +1154,11 @@ mod tests {
// This value is importen for this test! // This value is importen for this test!
assert_eq!(ETH_MIN_LEN, 64); assert_eq!(ETH_MIN_LEN, 64);
// Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` - 1 // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN` - 1
let packet = [0; 64 - FSC_LEN - 1]; let packet = [0; 64 - FCS_LEN - 1];
// Read RX_SIZE reg // Read RX_SIZE reg
let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
rx_size_vec.push(crc8(&rx_size_vec)); rx_size_vec.push(crc8(&rx_size_vec));
@ -1114,37 +1166,29 @@ mod tests {
expectations.push(SpiTransaction::read_vec(rx_size_vec)); expectations.push(SpiTransaction::read_vec(rx_size_vec));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations);
let cs = CsPinMock::default();
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, true);
let mut frame = [0; MTU]; let mut frame = [0; MTU];
let ret = spe.read_fifo(&mut frame).await; // Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
let ret = th.spe.read_fifo(&mut frame).await;
assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL))); assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL)));
spi.done(); // Mark end of the SPI test.
th.done();
} }
#[futures_test::test] #[futures_test::test]
async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() { async fn read_packet_from_fifo_packet_corrupted_fcs() {
let packet_buffer = [0; MTU];
let mut frame = [0; MTU]; let mut frame = [0; MTU];
let mut expectations = std::vec::Vec::with_capacity(16); // Configure expectations
let mut expectations = vec![];
// Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` let packet = [0xDE; 60];
for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] { let crc_en = true;
for crc_en in [false, true] {
expectations.clear();
let packet = &packet_buffer[0..packet_size];
// Read RX_SIZE reg // Read RX_SIZE reg
let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
if crc_en { if crc_en {
rx_size_vec.push(crc8(&rx_size_vec)); rx_size_vec.push(crc8(&rx_size_vec));
@ -1172,14 +1216,18 @@ mod tests {
// Packet data // Packet data
expectations.push(SpiTransaction::read_vec(packet.to_vec())); expectations.push(SpiTransaction::read_vec(packet.to_vec()));
let packet_crc = ETH_FSC::new(packet); let packet_crc = ETH_FCS::new(&packet);
let mut tail = std::vec::Vec::<u8>::with_capacity(100); let mut tail = std::vec::Vec::<u8>::with_capacity(100);
tail.extend_from_slice(&packet_crc.hton_bytes()); tail.extend_from_slice(&packet_crc.hton_bytes());
// increase last byte with 1.
if let Some(crc) = tail.last_mut() {
*crc = crc.wrapping_add(1);
}
// Need extra bytes? // Need extra bytes?
let pad = (packet_size + FSC_LEN + FRAME_HEADER_LEN) & 0x03; let pad = (packet.len() + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
if pad != 0 { if pad != 0 {
// Packet FCS + optinal padding // Packet FCS + optinal padding
tail.resize(tail.len() + pad, DONT_CARE_BYTE); tail.resize(tail.len() + pad, DONT_CARE_BYTE);
@ -1188,19 +1236,102 @@ mod tests {
expectations.push(SpiTransaction::read_vec(tail)); expectations.push(SpiTransaction::read_vec(tail));
expectations.push(SpiTransaction::flush()); expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations); // Create TestHarnass
let mut th = TestHarnass::new(&expectations, crc_en, false);
let cs = CsPinMock::default(); let ret = th.spe.read_fifo(&mut frame).await.expect_err("Error!");
let delay = MockDelay {}; assert!(matches!(ret, AdinError::FCS));
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let mut spe = ADIN1110::new(spi_dev, crc_en); // Mark end of the SPI test.
th.done();
}
let ret = spe.read_fifo(&mut frame).await.expect("Error!"); #[futures_test::test]
async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() {
let packet_buffer = [0; MTU];
let mut frame = [0; MTU];
let mut expectations = std::vec::Vec::with_capacity(16);
// Packet data, size = `ETH_MIN_LEN` - `FCS_LEN`
for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] {
for crc_en in [false, true] {
expectations.clear();
let packet = &packet_buffer[0..packet_size];
// Read RX_SIZE reg
let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
if crc_en {
rx_size_vec.push(crc8(&rx_size_vec));
}
// SPI Header with CRC
let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE];
if !crc_en {
// remove the CRC on idx 2
rx_fsize.swap_remove(2);
}
expectations.push(SpiTransaction::write_vec(rx_fsize));
expectations.push(SpiTransaction::read_vec(rx_size_vec));
expectations.push(SpiTransaction::flush());
// Read RX reg, SPI Header with CRC
let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE];
if !crc_en {
// remove the CRC on idx 2
rx_reg.swap_remove(2);
}
expectations.push(SpiTransaction::write_vec(rx_reg));
// Frame Header
expectations.push(SpiTransaction::read_vec(vec![0, 0]));
// Packet data
expectations.push(SpiTransaction::read_vec(packet.to_vec()));
let packet_crc = ETH_FCS::new(packet);
let mut tail = std::vec::Vec::<u8>::with_capacity(100);
tail.extend_from_slice(&packet_crc.hton_bytes());
// Need extra bytes?
let pad = (packet_size + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
if pad != 0 {
// Packet FCS + optinal padding
tail.resize(tail.len() + pad, DONT_CARE_BYTE);
}
expectations.push(SpiTransaction::read_vec(tail));
expectations.push(SpiTransaction::flush());
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, crc_en, false);
let ret = th.spe.read_fifo(&mut frame).await.expect("Error!");
assert_eq!(ret, packet_size); assert_eq!(ret, packet_size);
spi.done(); // Mark end of the SPI test.
th.done();
} }
} }
} }
#[futures_test::test]
async fn spi_crc_error() {
// Configure expectations
let expectations = vec![
SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]),
SpiTransaction::read_vec(vec![0x00, 0x00, 0x00, 0x00, 0xDD]),
SpiTransaction::flush(),
];
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, false);
let ret = th.spe.read_reg(sr::RX_FSIZE).await;
assert!(matches!(dbg!(ret), Err(AdinError::SPI_CRC)));
// Mark end of the SPI test.
th.done();
}
} }

View file

@ -174,7 +174,7 @@ bitfield! {
pub sdf_detect_src, set_sdf_detect_src : 7; pub sdf_detect_src, set_sdf_detect_src : 7;
/// Statistics Clear on Reading /// Statistics Clear on Reading
pub stats_clr_on_rd, set_stats_clr_on_rd : 6; pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
/// Enable CRC Append /// Enable SPI CRC
pub crc_append, set_crc_append : 5; pub crc_append, set_crc_append : 5;
/// Admit Frames with IFG Errors on Port 1 (P1) /// Admit Frames with IFG Errors on Port 1 (P1)
pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4; pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;