diff --git a/src/raw_device.rs b/src/raw_device.rs index 89c9cd3..fcb90e5 100644 --- a/src/raw_device.rs +++ b/src/raw_device.rs @@ -15,10 +15,22 @@ impl RawDevice { /// # Args /// * `bus` - The bus to communicate with the device. pub(crate) fn new(mut bus: SpiBus) -> Result> { + // Set the raw socket to 16KB RX/TX buffer space. let raw_socket = Socket::new(0); + bus.write_frame(raw_socket.register(), register::socketn::TXBUF_SIZE, &[16])?; + bus.write_frame(raw_socket.register(), register::socketn::RXBUF_SIZE, &[16])?; - // Configure the chip in MACRAW mode with MAC filtering. - let mode: u8 = (1 << 7) | (register::socketn::Protocol::MacRaw as u8); + // Set all socket buffers to 0KB size. + for socket_index in 1..8 { + let socket = Socket::new(socket_index); + bus.write_frame(socket.register(), register::socketn::TXBUF_SIZE, &[0])?; + bus.write_frame(socket.register(), register::socketn::RXBUF_SIZE, &[0])?; + } + + // Configure the chip in MACRAW mode with MAC filtering + Multicast blocking + IPv6 + // Blocking + Broadcast blocking. + let mode: u8 = (1 << 7) | // MAC address filtering + (register::socketn::Protocol::MacRaw as u8); bus.write_frame(raw_socket.register(), register::socketn::MODE, &[mode])?; raw_socket.command(&mut bus, register::socketn::Command::Open)?; @@ -26,6 +38,29 @@ impl RawDevice { Ok(Self { bus, raw_socket }) } + fn read_bytes(&mut self, buffer: &mut [u8], offset: u16) -> Result { + let rx_size = self.raw_socket.get_receive_size(&mut self.bus)? as usize; + + let read_buffer = if rx_size > buffer.len() + offset as usize { + buffer + } else { + &mut buffer[..rx_size - offset as usize] + }; + + let read_pointer = self + .raw_socket + .get_rx_read_pointer(&mut self.bus)? + .wrapping_add(offset); + self.bus + .read_frame(self.raw_socket.rx_buffer(), read_pointer, read_buffer)?; + self.raw_socket.set_rx_read_pointer( + &mut self.bus, + read_pointer.wrapping_add(read_buffer.len() as u16), + )?; + + Ok(read_buffer.len()) + } + /// Read an ethernet frame from the device. /// /// # Args @@ -34,37 +69,41 @@ impl RawDevice { /// # Returns /// The number of bytes read into the provided frame buffer. pub fn read_frame(&mut self, frame: &mut [u8]) -> Result { - if !self - .raw_socket - .has_interrupt(&mut self.bus, register::socketn::Interrupt::Receive)? - { + // Check if there is anything to receive. + let rx_size = self.raw_socket.get_receive_size(&mut self.bus)? as usize; + if rx_size == 0 { return Ok(0); } - let rx_size = self.raw_socket.get_receive_size(&mut self.bus)? as usize; + // The W5500 specifies the size of the received ethernet frame in the first two bytes. + // Refer to https://forum.wiznet.io/t/topic/979/2 for more information. + let expected_frame_size: usize = { + let mut frame_bytes = [0u8; 2]; + assert!(self.read_bytes(&mut frame_bytes[..], 0)? == 2); - let read_buffer = if rx_size > frame.len() { - frame - } else { - &mut frame[..rx_size] + u16::from_be_bytes(frame_bytes) as usize - 2 }; - // Read from the RX ring buffer. - let read_pointer = self.raw_socket.get_rx_read_pointer(&mut self.bus)?; - self.bus - .read_frame(self.raw_socket.rx_buffer(), read_pointer, read_buffer)?; - self.raw_socket.set_rx_read_pointer( - &mut self.bus, - read_pointer.wrapping_add(read_buffer.len() as u16), - )?; + // Read the ethernet frame + let read_buffer = if frame.len() > expected_frame_size { + &mut frame[..expected_frame_size] + } else { + frame + }; + + let received_frame_size = self.read_bytes(read_buffer, 2)?; // Register the reception as complete. self.raw_socket .command(&mut self.bus, register::socketn::Command::Receive)?; - self.raw_socket - .reset_interrupt(&mut self.bus, register::socketn::Interrupt::Receive)?; - Ok(read_buffer.len()) + // If we couldn't read the whole check sequence or if we read less bytes than expected, + // drop the frame. + if received_frame_size < expected_frame_size { + Ok(0) + } else { + Ok(received_frame_size) + } } /// Write an ethernet frame to the device. diff --git a/src/register.rs b/src/register.rs index 5acb049..91b8ea9 100644 --- a/src/register.rs +++ b/src/register.rs @@ -217,6 +217,10 @@ pub mod socketn { pub const DESTINATION_PORT: u16 = 0x10; + pub const RXBUF_SIZE: u16 = 0x1E; + + pub const TXBUF_SIZE: u16 = 0x1F; + pub const TX_FREE_SIZE: u16 = 0x20; pub const TX_DATA_READ_POINTER: u16 = 0x22; diff --git a/src/uninitialized_device.rs b/src/uninitialized_device.rs index 96ab3b1..30c7975 100644 --- a/src/uninitialized_device.rs +++ b/src/uninitialized_device.rs @@ -103,8 +103,13 @@ impl UninitializedDevice { mut self, mac: MacAddress, ) -> Result, InitializeError> { + // Reset the device. + self.bus + .write_frame(register::COMMON, register::common::MODE, &[0x80])?; + self.bus .write_frame(register::COMMON, register::common::MAC, &mac.octets)?; + RawDevice::new(self.bus) }