use crate::bus::Bus; use crate::device::{Device, DeviceRefMut}; use crate::host::Host; use crate::register::socketn; use crate::socket::Socket; use core::fmt::Debug; use embedded_nal::{nb, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpClientStack, UdpFullStack}; #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct UdpSocket { socket: Socket, } impl UdpSocket { fn new(socket: Socket) -> Self { UdpSocket { socket } } fn open( &mut self, bus: &mut SpiBus, local_port: u16, ) -> Result<(), SpiBus::Error> { self.socket.command(bus, socketn::Command::Close)?; self.socket.reset_interrupt(bus, socketn::Interrupt::All)?; self.socket.set_source_port(bus, local_port)?; self.socket.set_mode(bus, socketn::Protocol::Udp)?; self.socket.set_interrupt_mask( bus, socketn::Interrupt::SendOk as u8 & socketn::Interrupt::Timeout as u8, )?; self.socket.command(bus, socketn::Command::Open)?; Ok(()) } fn set_destination( &mut self, bus: &mut SpiBus, remote: SocketAddrV4, ) -> Result<(), UdpSocketError> { self.socket.set_destination_ip(bus, *remote.ip())?; self.socket.set_destination_port(bus, remote.port())?; Ok(()) } fn socket_send( &self, bus: &mut SpiBus, send_buffer: &[u8], ) -> NbResult<(), UdpSocketError> { // TODO increase longevity by cycling through buffer, instead of always writing to 0 // TODO ensure write is currently possible self.socket .set_tx_read_pointer(bus, 0) .and_then(|_| bus.write_frame(self.socket.tx_buffer(), 0, send_buffer)) .and_then(|_| { self.socket .set_tx_write_pointer(bus, send_buffer.len() as u16) }) .and_then(|_| self.socket.command(bus, socketn::Command::Send))?; loop { if self.socket.get_tx_read_pointer(bus)? == self.socket.get_tx_write_pointer(bus)? { if self.socket.has_interrupt(bus, socketn::Interrupt::SendOk)? { self.socket .reset_interrupt(bus, socketn::Interrupt::SendOk)?; return Ok(()); } else if self .socket .has_interrupt(bus, socketn::Interrupt::Timeout)? { self.socket .reset_interrupt(bus, socketn::Interrupt::Timeout)?; return Err(NbError::Other(UdpSocketError::WriteTimeout)); } } } } /// Sets a new destination before performing the send operation. fn socket_send_to( &mut self, bus: &mut SpiBus, remote: SocketAddrV4, send_buffer: &[u8], ) -> NbResult<(), UdpSocketError> { self.set_destination(bus, remote)?; self.socket_send(bus, send_buffer) } /// Receive data and mutate the `receive_buffer`. /// /// If [`Interrupt::Receive`] is not set, it will always return [`NbError::WouldBlock`]. fn socket_receive( &mut self, bus: &mut SpiBus, receive_buffer: &mut [u8], ) -> NbResult<(usize, SocketAddr), UdpSocketError> { if !self .socket .has_interrupt(bus, socketn::Interrupt::Receive)? { return Err(NbError::WouldBlock); } /* * Packet frame, as described in W5200 docs section 5.2.2.1 * |<-- read_pointer read_pointer + received_size -->| * | Destination IP Address | Destination Port | Byte Size of DATA | Actual DATA ... | * | --- 4 Bytes --- | --- 2 Bytes --- | --- 2 Bytes --- | .... | */ // TODO loop until RX received size stops changing, or it's larger than // receive_buffer.len() let read_pointer = self.socket.get_rx_read_pointer(bus)?; let mut header = [0u8; 8]; bus.read_frame(self.socket.rx_buffer(), read_pointer, &mut header)?; let remote = SocketAddr::new( IpAddr::V4(Ipv4Addr::new(header[0], header[1], header[2], header[3])), u16::from_be_bytes([header[4], header[5]]), ); let packet_size = u16::from_be_bytes([header[6], header[7]]).into(); let data_read_pointer = read_pointer + 8; // TODO handle buffer overflow bus.read_frame( self.socket.rx_buffer(), data_read_pointer, &mut receive_buffer[0..packet_size], )?; let tx_write_pointer = self.socket.get_tx_write_pointer(bus)?; self.socket .set_rx_read_pointer(bus, tx_write_pointer) .and_then(|_| self.socket.command(bus, socketn::Command::Receive)) .and_then(|_| self.socket.command(bus, socketn::Command::Open))?; self.socket .reset_interrupt(bus, socketn::Interrupt::Receive)?; Ok((packet_size, remote)) } fn socket_close( &self, bus: &mut SpiBus, ) -> Result<(), UdpSocketError> { self.socket.set_mode(bus, socketn::Protocol::Closed)?; self.socket.command(bus, socketn::Command::Close)?; Ok(()) } /// returns the index of the socket #[inline] pub fn index(&self) -> u8 { self.socket.index } } #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum UdpSocketError { NoMoreSockets, UnsupportedAddress, Other(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] E), WriteTimeout, } impl From for UdpSocketError { fn from(error: E) -> UdpSocketError { UdpSocketError::Other(error) } } type NbResult = Result>; enum NbError { Other(E), WouldBlock, } impl From> for NbError> { fn from(error: UdpSocketError) -> NbError> { NbError::Other(error) } } impl From for NbError> { fn from(error: E) -> NbError> { NbError::Other(UdpSocketError::Other(error)) } } impl From> for nb::Error { fn from(error: NbError) -> nb::Error { match error { NbError::Other(e) => nb::Error::Other(e), NbError::WouldBlock => nb::Error::WouldBlock, } } } impl UdpClientStack for Device where SpiBus: Bus, HostImpl: Host, { type UdpSocket = UdpSocket; type Error = UdpSocketError; #[inline] fn socket(&mut self) -> Result { self.as_mut().socket() } #[inline] fn connect( &mut self, socket: &mut Self::UdpSocket, remote: SocketAddr, ) -> Result<(), Self::Error> { self.as_mut().connect(socket, remote) } #[inline] fn send(&mut self, socket: &mut Self::UdpSocket, buffer: &[u8]) -> nb::Result<(), Self::Error> { self.as_mut().send(socket, buffer) } #[inline] fn receive( &mut self, socket: &mut Self::UdpSocket, buffer: &mut [u8], ) -> nb::Result<(usize, SocketAddr), Self::Error> { self.as_mut().receive(socket, buffer) } #[inline] fn close(&mut self, socket: Self::UdpSocket) -> Result<(), Self::Error> { self.as_mut().close(socket) } } impl UdpClientStack for DeviceRefMut<'_, SpiBus, HostImpl> where SpiBus: Bus, HostImpl: Host, { type UdpSocket = UdpSocket; type Error = UdpSocketError; fn socket(&mut self) -> Result { if let Some(socket) = self.take_socket() { Ok(UdpSocket::new(socket)) } else { Err(Self::Error::NoMoreSockets) } } fn connect( &mut self, socket: &mut Self::UdpSocket, remote: SocketAddr, ) -> Result<(), Self::Error> { let SocketAddr::V4(remote) = remote else { return Err(Self::Error::UnsupportedAddress) }; // TODO dynamically select a random port socket.open(&mut self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll. // guaranteed to be random. socket.set_destination(&mut self.bus, remote)?; Ok(()) } fn send(&mut self, socket: &mut Self::UdpSocket, buffer: &[u8]) -> nb::Result<(), Self::Error> { socket.socket_send(&mut self.bus, buffer)?; Ok(()) } fn receive( &mut self, socket: &mut Self::UdpSocket, buffer: &mut [u8], ) -> nb::Result<(usize, SocketAddr), Self::Error> { Ok(socket.socket_receive(&mut self.bus, buffer)?) } fn close(&mut self, socket: Self::UdpSocket) -> Result<(), Self::Error> { socket.socket_close(&mut self.bus)?; self.release_socket(socket.socket); Ok(()) } } impl UdpFullStack for Device where SpiBus: Bus, HostImpl: Host, { #[inline] fn bind(&mut self, socket: &mut Self::UdpSocket, local_port: u16) -> Result<(), Self::Error> { self.as_mut().bind(socket, local_port) } #[inline] fn send_to( &mut self, socket: &mut Self::UdpSocket, remote: SocketAddr, buffer: &[u8], ) -> nb::Result<(), Self::Error> { self.as_mut().send_to(socket, remote, buffer) } } impl UdpFullStack for DeviceRefMut<'_, SpiBus, HostImpl> where SpiBus: Bus, HostImpl: Host, { fn bind(&mut self, socket: &mut Self::UdpSocket, local_port: u16) -> Result<(), Self::Error> { socket.open(&mut self.bus, local_port)?; Ok(()) } fn send_to( &mut self, socket: &mut Self::UdpSocket, remote: SocketAddr, buffer: &[u8], ) -> nb::Result<(), Self::Error> { let SocketAddr::V4(remote) = remote else { return Err(nb::Error::Other(Self::Error::UnsupportedAddress)) }; socket.socket_send_to(&mut self.bus, remote, buffer)?; Ok(()) } }