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,
];
/// Generate Ethernet Frame Check Sequence
#[allow(non_camel_case_types)]
#[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;
#[must_use]
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;
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
}) ^ u32::MAX;
Self(fsc)
Self(fcs)
}
#[must_use]
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;
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
}) ^ u32::MAX;
Self(fsc)
Self(fcs)
}
#[must_use]
@ -319,24 +320,24 @@ mod tests {
];
// 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();
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
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);
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
// 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();
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
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);
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
}
#[test]
@ -349,9 +350,9 @@ mod tests {
];
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);
}

View file

@ -13,7 +13,7 @@ mod phy;
mod regs;
use ch::driver::LinkState;
pub use crc32::ETH_FSC;
pub use crc32::ETH_FCS;
use crc8::crc8;
use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch;
@ -35,16 +35,22 @@ pub const PHYID: u32 = 0x0283_BC91;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(non_camel_case_types)]
pub enum AdinError<E> {
/// SPI-BUS Error
Spi(E),
SENDERROR,
READERROR,
CRC,
/// Ethernet FCS error
FCS,
/// SPI Header CRC error
SPI_CRC,
/// Received or sended ethernet packet is too big
PACKET_TOO_BIG,
/// Received or sended ethernet packet is too small
PACKET_TOO_SMALL,
/// MDIO transaction timeout
MDIO_ACC_TIMEOUT,
}
pub type AEResult<T, SPIError> = core::result::Result<T, AdinError<SPIError>>;
/// Internet PHY address
pub const MDIO_PHY_ADDR: u8 = 0x01;
/// Maximum Transmission Unit
@ -59,9 +65,9 @@ const TURN_AROUND_BYTE: u8 = 0x00;
/// Packet minimal frame/packet length
const ETH_MIN_LEN: usize = 64;
/// 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
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.
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.
const SPI_SPACE_MULTIPULE: usize = 3;
// P1 = 0x00, P2 = 0x01
/// P1 = 0x00, P2 = 0x01
const PORT_ID_BYTE: u8 = 0x00;
/// Type alias for the embassy-net driver for ADIN1110
@ -100,12 +106,18 @@ pub struct ADIN1110<SPI> {
spi: SPI,
/// Enable CRC on SPI transfer.
/// 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> {
pub fn new(spi: SPI, crc: bool) -> Self {
Self { spi, crc }
pub fn new(spi: SPI, spi_crc: bool, append_fcs_on_tx: bool) -> Self {
Self {
spi,
spi_crc,
append_fcs_on_tx,
}
}
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);
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
let _ = tx_buf.push(crc8(&tx_buf));
}
@ -126,16 +138,16 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
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])];
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]);
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);
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
let _ = tx_buf.push(crc8(&tx_buf));
}
@ -164,7 +176,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
let val = value.to_be_bytes();
let _ = tx_buf.extend_from_slice(val.as_slice());
if self.crc {
if self.spi_crc {
// Add CRC for header data
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.
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 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();
// 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;
if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN {
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() {
#[cfg(feature = "defmt")]
@ -217,7 +229,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
spi_hdr.set_addr(sr::RX);
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
let _ = tx_buf.push(crc8(&tx_buf));
}
@ -226,27 +238,36 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
let _ = tx_buf.push(TURN_AROUND_BYTE);
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!
let tail_size = (fifo_frame_size & 0x03) + FSC_LEN;
let tail_size = (fifo_frame_size & 0x03) + FCS_LEN;
let mut spi_op = [
Operation::Write(&tx_buf),
Operation::Read(&mut frame_header),
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)?;
// 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)
} else {
Err(AdinError::FCS)
}
}
/// Write to fifo ethernet packet memory send over the wire.
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 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) {
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())
.map_err(|_e| AdinError::PACKET_TOO_BIG)?;
if self.crc {
if self.spi_crc {
// Add CRC for header data
head_data
.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())
.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.
// So padded the data minus the FCS, FCS is automatilly added to by the MAC.
if frame.len() < ETH_MIN_WITHOUT_FSC_LEN {
let _ = tail_data.resize(ETH_MIN_WITHOUT_FSC_LEN - frame.len(), 0x00);
if frame.len() < ETH_MIN_WITHOUT_FCS_LEN {
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);
}
// 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());
}
// len = frame_size + optional padding + 2 bytes Frame header
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,
int: INT,
mut reset: RST,
crc: bool,
spi_crc: bool,
append_fcs_on_tx: bool,
) -> (Device<'_>, Runner<'_, SPI, INT, RST>) {
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;
// 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
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();
}
// Check if the FCS is valid in the TX path.
let tx_fsc_validation_enable = true;
// Config0
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();
// Config2
let mut config2 = Config2(0x0000_0800);
// crc_append must be disable if tx_fsc_validation_enable is true!
config2.set_crc_append(!tx_fsc_validation_enable);
// crc_append must be disable if tx_fcs_validation_enable is true!
config2.set_crc_append(!mac.append_fcs_on_tx);
mac.write_reg(sr::CONFIG2, config2.0).await.unwrap();
// Pin Mux Config 1
@ -721,6 +744,7 @@ mod tests {
use embedded_hal_1::digital::{ErrorType, OutputPin};
use embedded_hal_async::delay::DelayUs;
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_hal_mock::common::Generic;
use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
#[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]
async fn mac_read_registers_without_crc() {
// Configure expectations
@ -772,22 +820,20 @@ mod tests {
SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]),
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, false);
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, false, true);
// 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);
// 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);
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
@ -803,26 +849,23 @@ mod tests {
SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]),
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);
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215);
assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57);
// 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);
// 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);
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
@ -832,18 +875,15 @@ mod tests {
SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]),
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, false);
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, false, true);
// 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]
@ -854,17 +894,14 @@ mod tests {
SpiTransaction::flush(),
];
// Basic test init block
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);
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
// 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]
@ -885,7 +922,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// 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);
}
// Packet FCS + optinal padding
@ -894,17 +931,49 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush());
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);
assert!(th.spe.write_fifo(&packet).await.is_ok());
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]
@ -926,7 +995,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// 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);
}
// Packet FCS + optinal padding
@ -935,17 +1004,13 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush());
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);
assert!(th.spe.write_fifo(&packet).await.is_ok());
let mut spe = ADIN1110::new(spi_dev, true);
assert!(spe.write_fifo(&packet).await.is_ok());
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
@ -958,24 +1023,23 @@ mod tests {
// Max packet size = MAX_BUFF - FRAME_HEADER_LEN
let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1];
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);
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, true, true);
// minimal
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)
));
// 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]
@ -999,7 +1063,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// 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);
}
// Packet FCS + optinal padding
@ -1008,17 +1072,13 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush());
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);
assert!(th.spe.write_fifo(&packet).await.is_ok());
let mut spe = ADIN1110::new(spi_dev, true);
assert!(spe.write_fifo(&packet).await.is_ok());
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
@ -1042,7 +1102,7 @@ mod tests {
let mut tail = std::vec::Vec::<u8>::with_capacity(100);
// 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);
}
// Packet FCS + optinal padding
@ -1051,17 +1111,13 @@ mod tests {
expectations.push(SpiTransaction::write_vec(tail));
expectations.push(SpiTransaction::flush());
let mut spi = SpiMock::new(&expectations);
// Create TestHarnass
let mut th = TestHarnass::new(&expectations, false, true);
let cs = CsPinMock::default();
let delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
assert!(th.spe.write_fifo(&packet).await.is_ok());
let mut spe = ADIN1110::new(spi_dev, false);
assert!(spe.write_fifo(&packet).await.is_ok());
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
@ -1070,7 +1126,7 @@ mod tests {
let mut expectations = vec![];
// 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();
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::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 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)));
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
@ -1102,11 +1154,11 @@ mod tests {
// This value is importen for this test!
assert_eq!(ETH_MIN_LEN, 64);
// Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` - 1
let packet = [0; 64 - FSC_LEN - 1];
// Packet data, size = `ETH_MIN_LEN` - `FCS_LEN` - 1
let packet = [0; 64 - FCS_LEN - 1];
// 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();
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::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 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)));
spi.done();
// Mark end of the SPI test.
th.done();
}
#[futures_test::test]
async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() {
let packet_buffer = [0; MTU];
async fn read_packet_from_fifo_packet_corrupted_fcs() {
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`
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];
let packet = [0xDE; 60];
let crc_en = true;
// 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();
if crc_en {
rx_size_vec.push(crc8(&rx_size_vec));
@ -1172,14 +1216,18 @@ mod tests {
// Packet data
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);
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?
let pad = (packet_size + FSC_LEN + FRAME_HEADER_LEN) & 0x03;
let pad = (packet.len() + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
if pad != 0 {
// Packet FCS + optinal padding
tail.resize(tail.len() + pad, DONT_CARE_BYTE);
@ -1188,19 +1236,102 @@ mod tests {
expectations.push(SpiTransaction::read_vec(tail));
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 delay = MockDelay {};
let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
let ret = th.spe.read_fifo(&mut frame).await.expect_err("Error!");
assert!(matches!(ret, AdinError::FCS));
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);
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;
/// Statistics Clear on Reading
pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
/// Enable CRC Append
/// Enable SPI CRC
pub crc_append, set_crc_append : 5;
/// Admit Frames with IFG Errors on Port 1 (P1)
pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;