From d0f5792028075922e975053966be1a8b8c317c22 Mon Sep 17 00:00:00 2001 From: Jonah Dahlquist Date: Tue, 10 Sep 2019 09:15:48 -0500 Subject: [PATCH] Added Packet struct and beginnings of packet reading --- src/register.rs | 9 +++++ src/socket/mod.rs | 17 ++++++++ src/udp/mod.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++ src/udp/packet.rs | 66 ++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 src/udp/packet.rs diff --git a/src/register.rs b/src/register.rs index 4cf59e0..1a72f20 100644 --- a/src/register.rs +++ b/src/register.rs @@ -54,4 +54,13 @@ pub mod socketn { } pub const SOURCE_PORT: u16 = 0x04; + + pub const INTERRUPT_MASK: u16 = 0x2C; + pub mod interrupt_mask { + pub const RECEIVE: u8 = 0b100; + } + + pub const RECEIVED_SIZE: u16 = 0x26; + + pub const RX_DATA_POINTER: u16 = 0x28; } diff --git a/src/socket/mod.rs b/src/socket/mod.rs index e561a1e..48f5c3c 100644 --- a/src/socket/mod.rs +++ b/src/socket/mod.rs @@ -37,6 +37,23 @@ pub trait Socket { block!(bus.transfer_frame(self.register(), socketn::SOURCE_PORT, true, &mut data))?; Ok(()) } + fn has_received( + &self, + bus: &mut SpiBus, + ) -> Result { + let mut data = [0u8]; + block!(bus.transfer_frame(self.register(), socketn::INTERRUPT_MASK, true, &mut data))?; + Ok(data[0] & socketn::interrupt_mask::RECEIVE != 0) + } + + fn get_packet_address( + &self, + bus: &mut SpiBus, + ) -> Result { + let mut data = [0u8; 2]; + block!(bus.transfer_frame(self.register(), socketn::RX_DATA_POINTER, true, &mut data))?; + Ok(BigEndian::read_u16(&data)) + } } pub type OwnedSockets = ( diff --git a/src/udp/mod.rs b/src/udp/mod.rs index 2b31075..dc9403f 100644 --- a/src/udp/mod.rs +++ b/src/udp/mod.rs @@ -1,11 +1,15 @@ mod inactive_udp_socket; +mod packet; +use byteorder::{BigEndian, ByteOrder}; +use crate::IpAddress; use crate::bus::ActiveBus; use crate::network::Network; use crate::socket::OwnedSockets; use crate::socket::Socket; use crate::udp::inactive_udp_socket::InactiveUdpSocket; use crate::w5500::W5500; +use crate::udp::packet::UdpPacket; use register::socketn; pub struct UdpSocket<'a, SpiBus: ActiveBus, NetworkImpl: Network, SocketImpl: Socket> { @@ -38,6 +42,103 @@ impl<'a, SpiBus: ActiveBus, NetworkImpl: Network, SocketImpl: Socket> }) } + /// Returns a UDP packet if one is available. Will return `None` if no UDP packets are in the socket's buffer + pub fn receive(mut self) -> Result>, SpiBus::Error> { + if !self.socket.has_received(&mut self.bus)? { + Ok(None) + } else { + Ok(Some(UdpPacket::new(self)?)) + } + } + + fn block_until_receive_size_known(&mut self) -> Result { + loop { + let mut sample_0 = [0u8; 2]; + block!(self.bus.transfer_frame(self.socket.register(), socketn::RECEIVED_SIZE, false, &mut sample_0))?; + let mut sample_1 = [0u8; 2]; + block!(self.bus.transfer_frame(self.socket.register(), socketn::RECEIVED_SIZE, false, &mut sample_1))?; + if sample_0 == sample_1 && sample_0[0] >= 8 { + break Ok(BigEndian::read_u16(&sample_0)); + } + } + } + +// /// Sends a UDP packet to the specified IP and port, and blocks until it is sent +// fn blocking_send( +// &mut self, +// host: &IpAddress, +// host_port: u16, +// data: &[u8], +// ) -> Result<(), Self::Error> { +// let (w5500, UdpSocket(socket)) = self; + +// { +// let local_port = w5500.read_u16(socket.at(SocketRegister::LocalPort))?; +// let local_port = local_port.to_be_bytes(); +// let host_port = host_port.to_be_bytes(); + +// w5500.write_to( +// socket.at(SocketRegister::LocalPort), +// &[ +// local_port[0], +// local_port[1], // local port u16 +// 0x00, +// 0x00, +// 0x00, +// 0x00, +// 0x00, +// 0x00, // destination mac +// host.address[0], +// host.address[1], +// host.address[2], +// host.address[3], // target IP +// host_port[0], +// host_port[1], // destination port (5354) +// ], +// )?; +// } + +// let data_length = data.len() as u16; +// { +// let data_length = data_length.to_be_bytes(); + +// // TODO why write [0x00, 0x00] at TxReadPointer at all? +// // TODO Is TxWritePointer not sufficient enough? +// w5500.write_to( +// socket.at(SocketRegister::TxReadPointer), +// &[0x00, 0x00, data_length[0], data_length[1]], +// ); +// } + +// w5500.write_to( +// socket.tx_register_at(0x00_00), +// &data[..data_length as usize], +// )?; + +// w5500.write_to( +// socket.at(SocketRegister::Command), +// &[SocketCommand::Send as u8], +// )?; + +// for _ in 0..0xFFFF { +// // wait until sent +// if w5500.is_interrupt_set(*socket, Interrupt::SendOk)? { +// w5500.reset_interrupt(*socket, Interrupt::SendOk)?; +// break; +// } +// } +// // restore listen state +// w5500.write_to( +// socket.at(SocketRegister::Mode), +// &[ +// Protocol::UDP as u8, // Socket Mode Register +// SocketCommand::Open as u8, // Socket Command Register +// ], +// )?; +// Ok(()) +// } + + pub fn deactivate( self, ) -> ( diff --git a/src/udp/packet.rs b/src/udp/packet.rs new file mode 100644 index 0000000..95fd2d0 --- /dev/null +++ b/src/udp/packet.rs @@ -0,0 +1,66 @@ +use crate::udp::UdpSocket; +use crate::network::Network; +use crate::bus::ActiveBus; +use crate::socket::Socket; +use crate::IpAddress; +use byteorder::{BigEndian, ByteOrder}; + +pub struct UdpPacket { + udp_socket: UdpSocket, + address: IpAddress, + remote_port: u16, + size: u16, + read_pointer: u16, +} + +impl<'a, SpiBus: ActiveBus, NetworkImpl: Network, SocketImpl: Socket> UdpPacket> +{ + pub fn new(mut udp_socket: UdpSocket<'a, SpiBus, NetworkImpl, SocketImpl>) -> Result { + let receive_size = udp_socket.block_until_receive_size_known()? - 8; + // |<-- read_pointer read_pointer + received_size -->| + // |Destination IP Address | Destination Port | Byte Size of DATA | Actual DATA ... | + // | --- 4 Bytes --- | --- 2 Bytes --- | --- 2 Bytes --- | .... | + let read_pointer = udp_socket.socket.get_packet_address(&mut udp_socket.bus)?; + let mut header = [0u8; 8]; + block!(udp_socket.bus.transfer_frame(udp_socket.socket.rx_buffer(), read_pointer, false, &mut header))?; + Ok(UdpPacket { + udp_socket, + address: IpAddress::new(header[0], header[1], header[2], header[3]), + remote_port: BigEndian::read_u16(&header[4..5]), + size: receive_size, + read_pointer, + }) + } + + pub fn get_remote_port(&self) -> u16 { + self.remote_port + } + + pub fn get_address(&self) -> IpAddress { + self.address + } + + pub fn read(&self) { + // TODO read a byte upon every invocation + // w5500.read_from( + // socket.rx_register_at(read_pointer + 8), + // &mut destination[..data_length], + // )?; + } + + pub fn close(self) -> UdpSocket<'a, SpiBus, NetworkImpl, SocketImpl> { + // TODO reset read pointer etc + + // // reset + // w5500.write_u16( + // socket.at(SocketRegister::RxReadPointer), + // read_pointer + receive_size as u16, + // )?; + // w5500.write_u8( + // socket.at(SocketRegister::Command), + // SocketCommand::Recv as u8, + // )?; + // TODO return Socket + self.udp_socket + } +}