diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index a41fedca7..a3474f70a 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -273,6 +273,15 @@ impl ETH_FSC { Self(fsc) } + #[must_use] + pub fn update(self, data: &[u8]) -> Self { + let fsc = 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) + } + #[must_use] pub fn crc_ok(&self) -> bool { self.0 == Self::CRC32_OK @@ -329,4 +338,21 @@ mod tests { println!("{:08x}", own_crc.0); assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); } + + #[test] + fn crc32_update() { + let full_data = &[ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00, + 0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78, + 0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c, + ]; + + let (part_a, part_b) = full_data.split_at(16); + let crc_partially = ETH_FSC::new(part_a).update(part_b); + + let crc_full = ETH_FSC::new(full_data); + + assert_eq!(crc_full.0, crc_partially.0); + } } diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 8b81065c5..c0a9b44ee 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -61,13 +61,17 @@ const ETH_MIN_LEN: usize = 64; /// Ethernet `Frame Check Sequence` length const FSC_LEN: usize = 4; +/// SPI Header, contains SPI action and register id. +const SPI_HEADER_LEN: usize = 2; +/// SPI Header CRC length +const SPI_HEADER_CRC_LEN: usize = 1; +/// Frame Header, const FRAME_HEADER_LEN: usize = 2; -const WR_HEADER_LEN: usize = 2; // P1 = 0x00, P2 = 0x01 const PORT_ID_BYTE: u8 = 0x00; -pub type Packet = Vec; +pub type Packet = Vec; /// Type alias for the embassy-net driver for ADIN1110 pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; @@ -192,7 +196,13 @@ impl ADIN1110 { // Packet read of write to the MAC packet buffer must be a multipul of 4! let read_size = packet_size.next_multiple_of(4); - if packet_size < (FRAME_HEADER_LEN + FSC_LEN) || read_size > packet.len() { + if packet_size < (SPI_HEADER_LEN + FSC_LEN) { + return Err(AdinError::PACKET_TOO_SMALL); + } + + if read_size > packet.len() { + #[cfg(feature = "defmt")] + defmt::trace!("MAX: {} WANT: {}", packet.len(), read_size); return Err(AdinError::PACKET_TOO_BIG); } @@ -209,16 +219,18 @@ impl ADIN1110 { // Turn around byte, TODO: Unknown that this is. let _ = tx_buf.push(TURN_AROUND_BYTE); - let spi_packet = &mut packet[0..read_size as usize]; + let spi_packet = &mut packet[0..read_size]; assert_eq!(spi_packet.len() & 0x03, 0x00); let mut pkt_header = [0, 0]; + let mut fsc = [0, 0, 0, 0]; let mut spi_op = [ Operation::Write(&tx_buf), Operation::Read(&mut pkt_header), Operation::Read(spi_packet), + Operation::Read(&mut fsc), ]; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; @@ -228,80 +240,86 @@ impl ADIN1110 { /// Write to fifo ethernet packet memory send over the wire. pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { - let header_len = self.header_write_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 + 1; - let mut packet = Packet::new(); + if frame.len() < (6 + 6 + 2) { + return Err(AdinError::PACKET_TOO_SMALL); + } + if frame.len() > (MAX_BUFF - FRAME_HEADER_LEN) { + return Err(AdinError::PACKET_TOO_BIG); + } + + // SPI HEADER + [OPTIONAL SPI CRC] + FRAME HEADER + let mut head_data = Vec::::new(); + // [OPTIONAL PAD DATA] + FCS + [OPTINAL BYTES MAKE SPI FRAME EVEN] + let mut tail_data = Vec::::new(); let mut spi_hdr = SpiHeader(0); spi_hdr.set_control(true); spi_hdr.set_write(true); spi_hdr.set_addr(sr::TX); - packet + head_data .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) .map_err(|_e| AdinError::PACKET_TOO_BIG)?; if self.crc { // Add CRC for header data - packet - .push(crc8(&packet[0..2])) + head_data + .push(crc8(&head_data[0..2])) .map_err(|_| AdinError::PACKET_TOO_BIG)?; } // Add port number, ADIN1110 its fixed to zero/P1, but for ADIN2111 has two ports. - packet + head_data .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) .map_err(|_e| AdinError::PACKET_TOO_BIG)?; - // Copy packet data to spi buffer. - packet - .extend_from_slice(frame) - .map_err(|_e| AdinError::PACKET_TOO_BIG)?; + let mut frame_fcs = ETH_FSC::new(frame); - // Pad data up to ETH_MIN_LEN - FCS_LEN - for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN + header_len) { - let _ = packet.push(0x00); + // 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 let Some(pad_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(frame.len()) { + let _ = tail_data.resize(pad_len, 0x00); + frame_fcs = frame_fcs.update(&tail_data); } - // add ethernet FCS only over the ethernet packet. - let crc = ETH_FSC::new(&packet[header_len..]); - let _ = packet.extend_from_slice(crc.hton_bytes().as_slice()); + // 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 send_len = - u32::try_from(packet.len() - header_len + FRAME_HEADER_LEN).map_err(|_| AdinError::PACKET_TOO_BIG)?; + // len = frame_size + optional padding + 2 bytes Frame header + let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN; + let spi_pad_len = send_len_orig.next_multiple_of(4); + let send_len = u32::try_from(send_len_orig).map_err(|_| AdinError::PACKET_TOO_BIG)?; // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes! - while packet.len() & 0x3 != 0 { - let _ = packet.push(DONT_CARE_BYTE); + if spi_pad_len != send_len_orig { + let spi_pad_len = spi_pad_len - send_len_orig; + let _ = tail_data.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE, DONT_CARE_BYTE][..spi_pad_len]); } #[cfg(feature = "defmt")] defmt::trace!( - "TX: hdr {} [{}] {:02x} SIZE: {}", - header_len, - packet.len(), - &packet, + "TX: hdr {} [{}] {:02x}-{:02x}-{:02x} SIZE: {}", + head_data.len(), + frame.len(), + head_data.as_slice(), + frame, + tail_data.as_slice(), send_len, ); self.write_reg(sr::TX_FSIZE, send_len).await?; - // Spi packet must be half word / even length - if send_len & 1 != 0 { - let _ = packet.push(0x00); - } + let mut transaction = [ + Operation::Write(head_data.as_slice()), + Operation::Write(frame), + Operation::Write(tail_data.as_slice()), + ]; - self.spi.write(&packet).await.map_err(AdinError::Spi) - } - - pub fn header_write_len(&self) -> usize { - // u16 + [CRC] + PORT - WR_HEADER_LEN + FRAME_HEADER_LEN + usize::from(self.crc) - } - - pub fn header_len_read(&self) -> usize { - // u16 + [CRC] + u8 - WR_HEADER_LEN + 1 + usize::from(self.crc) + self.spi.transaction(&mut transaction).await.map_err(AdinError::Spi) } /// Programs the mac address in the mac filters. @@ -815,12 +833,12 @@ mod tests { SpiTransaction::write_vec(vec![0xA0, 0x09, 39, 0x12, 0x34, 0x56, 0x78, 28]), SpiTransaction::flush(), ]; - let mut spi = SpiMock::new(&expectations); + // 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); // Write reg: 0x1FFF @@ -829,389 +847,31 @@ mod tests { spi.done(); } - // #[test] - // fn write_packet_to_fifo_less_64b_with_crc() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(136), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(66), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(201), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(ETH_MIN_LEN, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..65 { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[8, 137, 18, 4] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, true); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_less_64b_no_crc() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(66), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(ETH_MIN_LEN, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len() as u32..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[8, 137, 18, 4] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_1500b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x05), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0xDE), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(1500, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[212, 114, 18, 50] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_65b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(67), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(65, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[54, 117, 221, 220] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_66b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(68), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(66, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[97, 167, 100, 29] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_67b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(69), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(67, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[228, 218, 170, 232] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - #[futures_test::test] - async fn write_packet_to_fifo_arp_46bytes() { + async fn write_packet_to_fifo_minimal_with_crc() { // Configure expectations let mut expectations = vec![]; - let mut packet = Packet::new(); - //arp packet; - packet - .extend_from_slice(&[ - 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, - 154, 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, - ]) - .unwrap(); - - let mut spi_packet = Packet::new(); - // Write TX_SIZE reg expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201])); expectations.push(SpiTransaction::flush()); // Write TX reg. - // Header - spi_packet.extend_from_slice(&[160, 49, 143, 0, 0]).unwrap(); + // SPI Header + optional CRC + Frame Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0])); // Packet data - spi_packet.extend_from_slice(&packet).unwrap(); - // Packet padding up to 60 (ETH_MIN_LEN - FCS) - for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN) { - spi_packet.push(0x00).unwrap(); - } - // Packet FCS - spi_packet.extend_from_slice(&[147, 149, 213, 68]).unwrap(); + let packet = [0xFF_u8; 60]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); - // SPI HEADER Padding of u32 - let spi_packet_len = spi_packet.len(); - for _ in spi_packet_len..spi_packet_len.next_multiple_of(4) { - spi_packet.push(0x00).unwrap(); + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); } + // Packet FCS + optinal padding + tail.extend_from_slice(&[77, 241, 140, 244, DONT_CARE_BYTE, DONT_CARE_BYTE]); - expectations.push(SpiTransaction::write_vec(spi_packet.to_vec())); + expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::flush()); let mut spi = SpiMock::new(&expectations); @@ -1226,4 +886,161 @@ mod tests { spi.done(); } + + #[futures_test::test] + async fn write_packet_to_fifo_max_mtu_with_crc() { + assert_eq!(MTU, 1514); + // Configure expectations + let mut expectations = vec![]; + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 5, 240, 159])); + 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 = [0xAA_u8; MTU]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[49, 196, 205, 160]); + + expectations.push(SpiTransaction::write_vec(tail)); + 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); + + assert!(spe.write_fifo(&packet).await.is_ok()); + + spi.done(); + } + + #[futures_test::test] + async fn write_packet_to_fifo_invalid_lengths() { + assert_eq!(MTU, 1514); + + // Configure expectations + let expectations = vec![]; + + // 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); + + // minimal + assert!(matches!( + 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))); + + spi.done(); + } + + #[futures_test::test] + async fn write_packet_to_fifo_arp_46bytes_with_crc() { + // Configure expectations + let mut expectations = vec![]; + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0])); + // Packet data + let packet = [ + 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, 154, + 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, + ]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[147, 149, 213, 68, DONT_CARE_BYTE, DONT_CARE_BYTE]); + + expectations.push(SpiTransaction::write_vec(tail)); + 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); + + assert!(spe.write_fifo(&packet).await.is_ok()); + + spi.done(); + } + + #[futures_test::test] + async fn write_packet_to_fifo_arp_46bytes_without_crc() { + // Configure expectations + let mut expectations = vec![]; + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 0, 0, 0, 66])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // SPI Header + Frame Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 0, 0])); + // Packet data + let packet = [ + 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, 154, + 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, + ]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[147, 149, 213, 68, DONT_CARE_BYTE, DONT_CARE_BYTE]); + + expectations.push(SpiTransaction::write_vec(tail)); + 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, false); + + assert!(spe.write_fifo(&packet).await.is_ok()); + + spi.done(); + } }