diff options
| -rw-r--r-- | embassy-net-adin1110/src/lib.rs | 187 |
1 files changed, 165 insertions, 22 deletions
diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index c0a9b44ee..8e5fef701 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs | |||
| @@ -65,14 +65,16 @@ const FSC_LEN: usize = 4; | |||
| 65 | const SPI_HEADER_LEN: usize = 2; | 65 | const SPI_HEADER_LEN: usize = 2; |
| 66 | /// SPI Header CRC length | 66 | /// SPI Header CRC length |
| 67 | const SPI_HEADER_CRC_LEN: usize = 1; | 67 | const SPI_HEADER_CRC_LEN: usize = 1; |
| 68 | /// Frame Header, | 68 | /// SPI Header Trun Around length |
| 69 | const SPI_HEADER_TA_LEN: usize = 1; | ||
| 70 | /// Frame Header length | ||
| 69 | const FRAME_HEADER_LEN: usize = 2; | 71 | const FRAME_HEADER_LEN: usize = 2; |
| 72 | /// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write. | ||
| 73 | const SPI_SPACE_MULTIPULE: usize = 3; | ||
| 70 | 74 | ||
| 71 | // P1 = 0x00, P2 = 0x01 | 75 | // P1 = 0x00, P2 = 0x01 |
| 72 | const PORT_ID_BYTE: u8 = 0x00; | 76 | const PORT_ID_BYTE: u8 = 0x00; |
| 73 | 77 | ||
| 74 | pub type Packet = Vec<u8, { SPI_HEADER_LEN + FRAME_HEADER_LEN + MTU + FSC_LEN + 1 + 4 }>; | ||
| 75 | |||
| 76 | /// Type alias for the embassy-net driver for ADIN1110 | 78 | /// Type alias for the embassy-net driver for ADIN1110 |
| 77 | pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; | 79 | pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; |
| 78 | 80 | ||
| @@ -187,22 +189,24 @@ impl<SPI: SpiDevice> ADIN1110<SPI> { | |||
| 187 | } | 189 | } |
| 188 | 190 | ||
| 189 | /// Read out fifo ethernet packet memory received via the wire. | 191 | /// Read out fifo ethernet packet memory received via the wire. |
| 190 | pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult<usize, SPI::Error> { | 192 | pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult<usize, SPI::Error> { |
| 191 | let mut tx_buf = Vec::<u8, 16>::new(); | 193 | const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN; |
| 194 | const TAIL_LEN: usize = FSC_LEN + SPI_SPACE_MULTIPULE; | ||
| 192 | 195 | ||
| 193 | // Size of the frame, also includes the appednded header. | 196 | let mut tx_buf = Vec::<u8, HEAD_LEN>::new(); |
| 194 | let packet_size = self.read_reg(sr::RX_FSIZE).await? as usize; | ||
| 195 | 197 | ||
| 196 | // Packet read of write to the MAC packet buffer must be a multipul of 4! | 198 | // Size of the frame, also includes the `frame header` and `FSC`. |
| 197 | let read_size = packet_size.next_multiple_of(4); | 199 | let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize; |
| 198 | 200 | ||
| 199 | if packet_size < (SPI_HEADER_LEN + FSC_LEN) { | 201 | if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN { |
| 200 | return Err(AdinError::PACKET_TOO_SMALL); | 202 | return Err(AdinError::PACKET_TOO_SMALL); |
| 201 | } | 203 | } |
| 202 | 204 | ||
| 203 | if read_size > packet.len() { | 205 | let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FSC_LEN; |
| 206 | |||
| 207 | if packet_size > frame.len() { | ||
| 204 | #[cfg(feature = "defmt")] | 208 | #[cfg(feature = "defmt")] |
| 205 | defmt::trace!("MAX: {} WANT: {}", packet.len(), read_size); | 209 | defmt::trace!("MAX: {} WANT: {}", frame.len(), packet_size); |
| 206 | return Err(AdinError::PACKET_TOO_BIG); | 210 | return Err(AdinError::PACKET_TOO_BIG); |
| 207 | } | 211 | } |
| 208 | 212 | ||
| @@ -219,29 +223,28 @@ impl<SPI: SpiDevice> ADIN1110<SPI> { | |||
| 219 | // Turn around byte, TODO: Unknown that this is. | 223 | // Turn around byte, TODO: Unknown that this is. |
| 220 | let _ = tx_buf.push(TURN_AROUND_BYTE); | 224 | let _ = tx_buf.push(TURN_AROUND_BYTE); |
| 221 | 225 | ||
| 222 | let spi_packet = &mut packet[0..read_size]; | 226 | let mut frame_header = [0, 0]; |
| 223 | 227 | let mut fsc_and_extra = [0; TAIL_LEN]; | |
| 224 | assert_eq!(spi_packet.len() & 0x03, 0x00); | ||
| 225 | 228 | ||
| 226 | let mut pkt_header = [0, 0]; | 229 | // Packet read of write to the MAC packet buffer must be a multipul of 4! |
| 227 | let mut fsc = [0, 0, 0, 0]; | 230 | let tail_size = (fifo_frame_size & 0x03) + FSC_LEN; |
| 228 | 231 | ||
| 229 | let mut spi_op = [ | 232 | let mut spi_op = [ |
| 230 | Operation::Write(&tx_buf), | 233 | Operation::Write(&tx_buf), |
| 231 | Operation::Read(&mut pkt_header), | 234 | Operation::Read(&mut frame_header), |
| 232 | Operation::Read(spi_packet), | 235 | Operation::Read(&mut frame[0..packet_size]), |
| 233 | Operation::Read(&mut fsc), | 236 | Operation::Read(&mut fsc_and_extra[0..tail_size]), |
| 234 | ]; | 237 | ]; |
| 235 | 238 | ||
| 236 | self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; | 239 | self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; |
| 237 | 240 | ||
| 238 | Ok(packet_size as usize) | 241 | Ok(packet_size) |
| 239 | } | 242 | } |
| 240 | 243 | ||
| 241 | /// Write to fifo ethernet packet memory send over the wire. | 244 | /// Write to fifo ethernet packet memory send over the wire. |
| 242 | pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { | 245 | pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { |
| 243 | const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; | 246 | const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; |
| 244 | const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + 1; | 247 | const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + SPI_SPACE_MULTIPULE; |
| 245 | 248 | ||
| 246 | if frame.len() < (6 + 6 + 2) { | 249 | if frame.len() < (6 + 6 + 2) { |
| 247 | return Err(AdinError::PACKET_TOO_SMALL); | 250 | return Err(AdinError::PACKET_TOO_SMALL); |
| @@ -1043,4 +1046,144 @@ mod tests { | |||
| 1043 | 1046 | ||
| 1044 | spi.done(); | 1047 | spi.done(); |
| 1045 | } | 1048 | } |
| 1049 | |||
| 1050 | #[futures_test::test] | ||
| 1051 | async fn read_packet_from_fifo_packet_too_big_for_frame_buffer() { | ||
| 1052 | // Configure expectations | ||
| 1053 | let mut expectations = vec![]; | ||
| 1054 | |||
| 1055 | // Read RX_SIZE reg | ||
| 1056 | let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FSC_LEN).unwrap(); | ||
| 1057 | let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); | ||
| 1058 | rx_size_vec.push(crc8(&rx_size_vec)); | ||
| 1059 | |||
| 1060 | expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE])); | ||
| 1061 | expectations.push(SpiTransaction::read_vec(rx_size_vec)); | ||
| 1062 | expectations.push(SpiTransaction::flush()); | ||
| 1063 | |||
| 1064 | let mut spi = SpiMock::new(&expectations); | ||
| 1065 | |||
| 1066 | let cs = CsPinMock::default(); | ||
| 1067 | let delay = MockDelay {}; | ||
| 1068 | let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); | ||
| 1069 | |||
| 1070 | let mut spe = ADIN1110::new(spi_dev, true); | ||
| 1071 | |||
| 1072 | let mut frame = [0; MTU]; | ||
| 1073 | |||
| 1074 | let ret = spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await; | ||
| 1075 | assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG))); | ||
| 1076 | |||
| 1077 | spi.done(); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | #[futures_test::test] | ||
| 1081 | async fn read_packet_from_fifo_packet_too_small() { | ||
| 1082 | // Configure expectations | ||
| 1083 | let mut expectations = vec![]; | ||
| 1084 | |||
| 1085 | // This value is importen for this test! | ||
| 1086 | assert_eq!(ETH_MIN_LEN, 64); | ||
| 1087 | |||
| 1088 | // Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` - 1 | ||
| 1089 | let packet = [0; 64 - FSC_LEN - 1]; | ||
| 1090 | |||
| 1091 | // Read RX_SIZE reg | ||
| 1092 | let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); | ||
| 1093 | let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); | ||
| 1094 | rx_size_vec.push(crc8(&rx_size_vec)); | ||
| 1095 | |||
| 1096 | expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE])); | ||
| 1097 | expectations.push(SpiTransaction::read_vec(rx_size_vec)); | ||
| 1098 | expectations.push(SpiTransaction::flush()); | ||
| 1099 | |||
| 1100 | let mut spi = SpiMock::new(&expectations); | ||
| 1101 | |||
| 1102 | let cs = CsPinMock::default(); | ||
| 1103 | let delay = MockDelay {}; | ||
| 1104 | let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); | ||
| 1105 | |||
| 1106 | let mut spe = ADIN1110::new(spi_dev, true); | ||
| 1107 | |||
| 1108 | let mut frame = [0; MTU]; | ||
| 1109 | |||
| 1110 | let ret = spe.read_fifo(&mut frame).await; | ||
| 1111 | assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL))); | ||
| 1112 | |||
| 1113 | spi.done(); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | #[futures_test::test] | ||
| 1117 | async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() { | ||
| 1118 | let packet_buffer = [0; MTU]; | ||
| 1119 | let mut frame = [0; MTU]; | ||
| 1120 | let mut expectations = std::vec::Vec::with_capacity(16); | ||
| 1121 | |||
| 1122 | // Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` | ||
| 1123 | for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] { | ||
| 1124 | for crc_en in [false, true] { | ||
| 1125 | expectations.clear(); | ||
| 1126 | |||
| 1127 | let packet = &packet_buffer[0..packet_size]; | ||
| 1128 | |||
| 1129 | // Read RX_SIZE reg | ||
| 1130 | let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); | ||
| 1131 | let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); | ||
| 1132 | if crc_en { | ||
| 1133 | rx_size_vec.push(crc8(&rx_size_vec)); | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | // SPI Header with CRC | ||
| 1137 | let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE]; | ||
| 1138 | if !crc_en { | ||
| 1139 | // remove the CRC on idx 2 | ||
| 1140 | rx_fsize.swap_remove(2); | ||
| 1141 | } | ||
| 1142 | expectations.push(SpiTransaction::write_vec(rx_fsize)); | ||
| 1143 | expectations.push(SpiTransaction::read_vec(rx_size_vec)); | ||
| 1144 | expectations.push(SpiTransaction::flush()); | ||
| 1145 | |||
| 1146 | // Read RX reg, SPI Header with CRC | ||
| 1147 | let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE]; | ||
| 1148 | if !crc_en { | ||
| 1149 | // remove the CRC on idx 2 | ||
| 1150 | rx_reg.swap_remove(2); | ||
| 1151 | } | ||
| 1152 | expectations.push(SpiTransaction::write_vec(rx_reg)); | ||
| 1153 | // Frame Header | ||
| 1154 | expectations.push(SpiTransaction::read_vec(vec![0, 0])); | ||
| 1155 | // Packet data | ||
| 1156 | expectations.push(SpiTransaction::read_vec(packet.to_vec())); | ||
| 1157 | |||
| 1158 | let packet_crc = ETH_FSC::new(packet); | ||
| 1159 | |||
| 1160 | let mut tail = std::vec::Vec::<u8>::with_capacity(100); | ||
| 1161 | |||
| 1162 | tail.extend_from_slice(&packet_crc.hton_bytes()); | ||
| 1163 | |||
| 1164 | // Need extra bytes? | ||
| 1165 | let pad = (packet_size + FSC_LEN + FRAME_HEADER_LEN) & 0x03; | ||
| 1166 | if pad != 0 { | ||
| 1167 | // Packet FCS + optinal padding | ||
| 1168 | tail.resize(tail.len() + pad, DONT_CARE_BYTE); | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | expectations.push(SpiTransaction::read_vec(tail)); | ||
| 1172 | expectations.push(SpiTransaction::flush()); | ||
| 1173 | |||
| 1174 | let mut spi = SpiMock::new(&expectations); | ||
| 1175 | |||
| 1176 | let cs = CsPinMock::default(); | ||
| 1177 | let delay = MockDelay {}; | ||
| 1178 | let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); | ||
| 1179 | |||
| 1180 | let mut spe = ADIN1110::new(spi_dev, crc_en); | ||
| 1181 | |||
| 1182 | let ret = spe.read_fifo(&mut frame).await.expect("Error!"); | ||
| 1183 | assert_eq!(ret, packet_size); | ||
| 1184 | |||
| 1185 | spi.done(); | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | } | ||
| 1046 | } | 1189 | } |
