diff --git a/src/nal_tcp_client.rs b/src/nal_tcp_client.rs index e8b09af..12de105 100644 --- a/src/nal_tcp_client.rs +++ b/src/nal_tcp_client.rs @@ -1,109 +1,190 @@ -use embedded_nal::{TcpStack, Mode, SocketAddr}; -use embedded_nal::SocketAddr::{V4, V6}; +use core::cell::RefCell; +use nb; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; -use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder}; -use smoltcp::socket::SocketSet; -use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer}; -use smoltcp::time::{Duration, Instant}; -use smoltcp::Error; +use heapless::{consts, Vec}; -use nb::Error as nbError; -use core::cell; +use stm32h7_ethernet as ethernet; +use smoltcp as net; -const BUFFER_SIZE: usize = 2048; -pub static mut TX_STORAGE: &'static mut [u8] = &mut [0; BUFFER_SIZE]; -pub static mut RX_STORAGE: &'static mut [u8] = &mut [0; BUFFER_SIZE]; +use cortex_m_semihosting::hprintln; -/* - * Struct for a TCP socket - * TODO: Consider handling all sockets in this struct - */ -pub struct NalTcpClient {} +use minimq::embedded_nal; -// impl NalTcpClient { -// pub fn new(socket: &'a mut TcpSocket<'a>) -> Self { +#[derive(Debug)] +pub enum NetworkError { + NoSocket, + ConnectionFailure, + ReadFailure, + WriteFailure, +} -// NalTcpClient { -// socket, -// } -// } -// } +pub struct NetStorage { + pub ip_addrs: [net::wire::IpCidr; 1], + pub neighbor_cache: [Option<(net::wire::IpAddress, net::iface::Neighbor)>; 8], +} -impl<'a> TcpStack for &'a NalTcpClient{ - // The type returned when we create a new TCP socket - type TcpSocket = smoltcp::socket::TcpSocket<'a>; - // The type returned when we have an error - type Error = Error; +pub type NetworkInterface = + net::iface::EthernetInterface<'static, 'static, 'static, ethernet::EthernetDMA<'static>>; - // Open a new TCP socket. The socket starts in the unconnected state. - fn open(&self, mode: Mode) -> Result { - let tx_buffer = unsafe { TcpSocketBuffer::new(&mut TX_STORAGE[..]) }; - let rx_buffer = unsafe { TcpSocketBuffer::new(&mut RX_STORAGE[..]) }; - let mut socket = TcpSocket::new(rx_buffer, tx_buffer); - if let Mode::Timeout(dur) = mode { - socket.set_timeout(Some(Duration::from_millis(dur.into()))); +// TODO: The network stack likely needs a time-tracking mechanic here to support +// blocking/nonblocking/timeout based operations. +pub struct NetworkStack<'a, 'b, 'c, 'n> { + network_interface: &'n mut NetworkInterface, + sockets: RefCell>, + next_port: RefCell, + unused_handles: RefCell>, +} + +impl<'a, 'b, 'c, 'n> NetworkStack<'a, 'b, 'c, 'n> { + pub fn new( + interface: &'n mut NetworkInterface, + sockets: net::socket::SocketSet<'a, 'b, 'c>, + ) -> Self { + let mut unused_handles: Vec = Vec::new(); + for socket in sockets.iter() { + unused_handles.push(socket.handle()).unwrap(); + } + + NetworkStack { + network_interface: interface, + sockets: RefCell::new(sockets), + next_port: RefCell::new(49152), + unused_handles: RefCell::new(unused_handles), } - Ok(socket) } - // Connect to the given remote host and port. - fn connect( - &self, - mut socket: Self::TcpSocket, - remote: SocketAddr, - ) -> Result { - let result = match remote { - V4(v4_addr) => { - let ip_addr = v4_addr.ip().octets(); - socket.connect((IpAddress::v4(ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]), v4_addr.port()), 49500) - }, - V6(v6_addr) => { - let ip_addr = v6_addr.ip().segments(); - socket.connect((IpAddress::v6(ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], - ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]), v6_addr.port()), 49500) + pub fn update(&mut self, time: u32) -> bool { + match self.network_interface.poll( + &mut self.sockets.borrow_mut(), + net::time::Instant::from_millis(time as i64), + ) { + Ok(changed) => changed == false, + Err(e) => { + hprintln!("{:?}", e); + true } - }; - match result { - Ok(_) => Ok(socket), - Err(_e) => Err(_e), } } - /// Check if this socket is connected - fn is_connected(&self, socket: &Self::TcpSocket) -> Result { - Ok(socket.is_active()) - } + fn get_ephemeral_port(&self) -> u16 { + // Get the next ephemeral port + let current_port = self.next_port.borrow().clone(); - /// Write to the stream. Returns the number of bytes written is returned - /// (which may be less than `buffer.len()`), or an error. - fn write(&self, socket: &mut Self::TcpSocket, buffer: &[u8]) -> nb::Result { - if socket.can_send() { - socket.send_slice(buffer).map_err(nbError::Other) - } else { - Err(nbError::Other(Error::Illegal)) - } - } + let (next, wrap) = self.next_port.borrow().overflowing_add(1); + *self.next_port.borrow_mut() = if wrap { 49152 } else { next }; - /// Read from the stream. Returns `Ok(n)`, which means `n` bytes of - /// data have been received and they have been placed in - /// `&buffer[0..n]`, or an error. - fn read( - &self, - socket: &mut Self::TcpSocket, - buffer: &mut [u8], - ) -> nb::Result { - if socket.can_recv() { - socket.recv_slice(buffer).map_err(nbError::Other) - } else { - Err(nbError::Other(Error::Illegal)) - } - } - - /// Close an existing TCP socket. - fn close(&self, mut socket: Self::TcpSocket) -> Result<(), Self::Error> { - socket.close(); - Ok(()) + return current_port; } } +impl<'a, 'b, 'c, 'n> embedded_nal::TcpStack for NetworkStack<'a, 'b, 'c, 'n> { + type TcpSocket = net::socket::SocketHandle; + type Error = NetworkError; + + fn open(&self, _mode: embedded_nal::Mode) -> Result { + // TODO: Handle mode? + match self.unused_handles.borrow_mut().pop() { + Some(handle) => { + // Abort any active connections on the handle. + let mut sockets = self.sockets.borrow_mut(); + let internal_socket: &mut net::socket::TcpSocket = &mut *sockets.get(handle); + internal_socket.abort(); + + Ok(handle) + } + None => Err(NetworkError::NoSocket), + } + } + + fn connect( + &self, + socket: Self::TcpSocket, + remote: embedded_nal::SocketAddr, + ) -> Result { + // TODO: Handle socket mode? + + let mut sockets = self.sockets.borrow_mut(); + let internal_socket: &mut net::socket::TcpSocket = &mut *sockets.get(socket); + + // If we're already in the process of connecting, ignore the request silently. + if internal_socket.is_open() { + return Ok(socket); + } + + match remote.ip() { + embedded_nal::IpAddr::V4(addr) => { + let address = { + let octets = addr.octets(); + net::wire::Ipv4Address::new(octets[0], octets[1], octets[2], octets[3]) + }; + internal_socket + .connect((address, remote.port()), self.get_ephemeral_port()) + .map_err(|_| NetworkError::ConnectionFailure)?; + } + embedded_nal::IpAddr::V6(addr) => { + let address = { + let octets = addr.segments(); + net::wire::Ipv6Address::new( + octets[0], octets[1], octets[2], octets[3], octets[4], octets[5], + octets[6], octets[7], + ) + }; + internal_socket + .connect((address, remote.port()), self.get_ephemeral_port()) + .map_err(|_| NetworkError::ConnectionFailure)?; + } + }; + + Ok(socket) + } + + fn is_connected(&self, socket: &Self::TcpSocket) -> Result { + let mut sockets = self.sockets.borrow_mut(); + let socket: &mut net::socket::TcpSocket = &mut *sockets.get(*socket); + + Ok(socket.may_send() && socket.may_recv()) + } + + fn write(&self, socket: &mut Self::TcpSocket, buffer: &[u8]) -> nb::Result { + // TODO: Handle the socket mode. + + let mut sockets = self.sockets.borrow_mut(); + let socket: &mut net::socket::TcpSocket = &mut *sockets.get(*socket); + + let result = socket.send_slice(buffer); + + match result { + Ok(num_bytes) => Ok(num_bytes), + Err(_) => Err(nb::Error::Other(NetworkError::WriteFailure)), + } + } + + fn read( + &self, + socket: &mut Self::TcpSocket, + buffer: &mut [u8], + ) -> nb::Result { + // TODO: Handle the socket mode. + + let mut sockets = self.sockets.borrow_mut(); + let socket: &mut net::socket::TcpSocket = &mut *sockets.get(*socket); + + let result = socket.recv_slice(buffer); + + match result { + Ok(num_bytes) => Ok(num_bytes), + Err(_) => Err(nb::Error::Other(NetworkError::ReadFailure)), + } + } + + fn close(&self, socket: Self::TcpSocket) -> Result<(), Self::Error> { + // TODO: Free the ephemeral port in use by the socket. + + let mut sockets = self.sockets.borrow_mut(); + let internal_socket: &mut net::socket::TcpSocket = &mut *sockets.get(socket); + internal_socket.close(); + + self.unused_handles.borrow_mut().push(socket).unwrap(); + Ok(()) + } +} \ No newline at end of file