diff --git a/Cargo.toml b/Cargo.toml index 46c718a..d9cf6b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,46 +13,30 @@ license = "BSD-2-Clause" volatile-register = "0.2" aligned = "0.3" embedded-hal = "0.2" -smoltcp = { version = "0.7.0", default-features = false, features = [ "socket-raw", "proto-ipv4", "proto-ipv6" ], optional = true } -# Dependencies for NAL -embedded-time = { version = "0.10.1", optional = true } -embedded-nal = { version = "0.1.0", optional = true } -heapless = { version = "0.5.6", optional = true } +smoltcp = { version = "0.7.0", default-features = false, features = [ "socket-raw", "proto-ipv4", + "proto-ipv6", "socket-tcp", "ethernet"], optional = true } +cortex-m = {version = "0.5", optional = true } + # Optional dependencies for building examples -stm32f4xx-hal = { version = "0.8", optional = true } -cortex-m = { version = "0.5", optional = true } -cortex-m-rt = { version = "0.6", optional = true } -cortex-m-rtic = { version = "0.5.3", optional = true } -panic-itm = { version = "0.4", optional = true } -log = { version = "0.4", optional = true } +[dev-dependencies] +stm32f4xx-hal = { version = "0.8", features = ["stm32f407", "rt"] } +cortex-m-rt = "0.6" +cortex-m-rtic = "0.5.3" +panic-itm = "0.4" +log = "0.4" [features] smoltcp-phy = ["smoltcp"] -nal = [ - "embedded-time", "embedded-nal", "heapless", - "smoltcp-phy", "smoltcp/socket-tcp", "smoltcp/ethernet" -] cortex-m-cpu = ["cortex-m"] -# Example-based features -smoltcp-examples = [ - "smoltcp-phy", "smoltcp/socket-tcp", "smoltcp/ethernet" -] -tx_stm32f407 = [ - "stm32f4xx-hal/stm32f407", "stm32f4xx-hal/rt", "cortex-m", "cortex-m-rtic", "cortex-m-cpu", - "panic-itm", "log" -] -tcp_stm32f407 = [ - "stm32f4xx-hal/stm32f407", "stm32f4xx-hal/rt", "cortex-m", "cortex-m-rt", "cortex-m-rtic", - "cortex-m-cpu", "smoltcp-examples", "panic-itm", "log"] default = [] [[example]] name = "tx_stm32f407" -required-features = ["tx_stm32f407"] +required-features = ["smoltcp", "cortex-m-cpu"] [[example]] name = "tcp_stm32f407" -required-features = ["tcp_stm32f407"] +required-features = ["smoltcp", "cortex-m-cpu"] [profile.release] codegen-units = 1 diff --git a/src/lib.rs b/src/lib.rs index 014bf25..efb720f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,9 +12,6 @@ pub mod tx; #[cfg(feature = "smoltcp")] pub mod smoltcp_phy; -#[cfg(feature = "nal")] -pub mod nal; - /// Max raw frame array size pub const RAW_FRAME_LENGTH_MAX: usize = 1518; diff --git a/src/nal.rs b/src/nal.rs deleted file mode 100644 index f0d6dc5..0000000 --- a/src/nal.rs +++ /dev/null @@ -1,309 +0,0 @@ -use core::cell::RefCell; -use core::convert::TryInto; -use embedded_hal::{blocking::spi::Transfer, digital::v2::OutputPin}; -use embedded_nal as nal; -pub use embedded_time as time; -use heapless::{consts, Vec}; -use nal::nb; -use smoltcp as net; -use time::duration::*; - -#[derive(Debug)] -pub enum NetworkError { - NoSocket, - ConnectionFailure, - ReadFailure, - WriteFailure, - Unsupported, - TimeFault, -} - -pub type NetworkInterface = net::iface::EthernetInterface< - 'static, - crate::smoltcp_phy::SmoltcpDevice>, ->; - -pub struct NetworkStack<'a, SPI, NSS, IntClock> -where - SPI: 'static + Transfer, - NSS: 'static + OutputPin, - IntClock: time::Clock, -{ - network_interface: RefCell>, - sockets: RefCell>, - next_port: RefCell, - unused_handles: RefCell>, - time_ms: RefCell, - last_update_instant: RefCell>>, - clock: IntClock, - connection_timeout_ms: u32, -} - -impl<'a, SPI, NSS, IntClock> NetworkStack<'a, SPI, NSS, IntClock> -where - SPI: Transfer, - NSS: OutputPin, - IntClock: time::Clock, -{ - pub fn new( - interface: NetworkInterface, - sockets: net::socket::SocketSet<'a>, - clock: IntClock, - connection_timeout_ms: u32, - ) -> Self { - let mut unused_handles: Vec = Vec::new(); - for socket in sockets.iter() { - unused_handles.push(socket.handle()).unwrap(); - } - NetworkStack { - network_interface: RefCell::new(interface), - sockets: RefCell::new(sockets), - next_port: RefCell::new(49152), - unused_handles: RefCell::new(unused_handles), - time_ms: RefCell::new(0), - last_update_instant: RefCell::new(None), - clock, - connection_timeout_ms, - } - } - - // Initiate or advance the timer, and return the duration in ms as u32. - fn update(&self) -> Result { - let mut duration_ms: u32 = 0; - // Check if it is the first time the stack has updated the time itself - let now = match *self.last_update_instant.borrow() { - // If it is the first time, do not advance time - // Simply store the current instant to initiate time updating - None => self.clock.try_now().map_err(|_| NetworkError::TimeFault)?, - // If it was updated before, advance time and update last_update_instant - Some(instant) => { - // Calculate elapsed time - let now = self.clock.try_now().map_err(|_| NetworkError::TimeFault)?; - let mut duration = now.checked_duration_since(&instant); - // Normally, the wrapping clock should produce a valid duration. - // However, if `now` is earlier than `instant` (e.g. because the main - // application cannot get a valid epoch time during initialisation, - // we should still produce a duration that is just 1ms. - if duration.is_none() { - self.time_ms.replace(0); - duration = Some( - Milliseconds(1_u32) - .to_generic::(IntClock::SCALING_FACTOR) - .map_err(|_| NetworkError::TimeFault)?, - ); - } - let duration_ms_time: Milliseconds = duration - .unwrap() - .try_into() - .map_err(|_| NetworkError::TimeFault)?; - duration_ms = *duration_ms_time.integer(); - // Adjust duration into ms (note: decimal point truncated) - self.advance_time(duration_ms); - now - } - }; - self.last_update_instant.replace(Some(now)); - Ok(duration_ms) - } - - fn advance_time(&self, duration_ms: u32) { - let time = self.time_ms.borrow().wrapping_add(duration_ms); - self.time_ms.replace(time); - } - - // Poll on the smoltcp interface - fn poll(&self) -> Result { - match self.network_interface.borrow_mut().poll( - &mut self.sockets.borrow_mut(), - net::time::Instant::from_millis(*self.time_ms.borrow() as u32), - ) { - Ok(changed) => Ok(!changed), - Err(_e) => Ok(true), - } - } - - fn get_ephemeral_port(&self) -> u16 { - // Get the next ephemeral port - let current_port = self.next_port.borrow().clone(); - let (next, wrap) = self.next_port.borrow().overflowing_add(1); - *self.next_port.borrow_mut() = if wrap { 49152 } else { next }; - return current_port; - } -} -impl<'a, SPI, NSS, IntClock> nal::TcpStack for NetworkStack<'a, SPI, NSS, IntClock> -where - SPI: Transfer, - NSS: OutputPin, - IntClock: time::Clock, -{ - type TcpSocket = net::socket::SocketHandle; - type Error = NetworkError; - fn open(&self, _mode: nal::Mode) -> Result { - match self.unused_handles.borrow_mut().pop() { - Some(handle) => { - // Abort any active connections on the handle. - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(handle); - socket.abort(); - Ok(handle) - } - None => Err(NetworkError::NoSocket), - } - } - - fn connect( - &self, - handle: Self::TcpSocket, - remote: nal::SocketAddr, - ) -> Result { - { - // If the socket has already been connected, ignore the connection - // request silently. - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(handle); - if socket.state() == net::socket::TcpState::Established { - return Ok(handle); - } - } - - { - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(handle); - // abort() instead of close() prevents TcpSocket::connect() from - // raising an error - socket.abort(); - match remote.ip() { - nal::IpAddr::V4(addr) => { - let address = net::wire::Ipv4Address::from_bytes(&addr.octets()[..]); - socket - .connect((address, remote.port()), self.get_ephemeral_port()) - .map_err(|_| NetworkError::ConnectionFailure)?; - net::wire::IpAddress::Ipv4(address) - } - nal::IpAddr::V6(addr) => { - let address = net::wire::Ipv6Address::from_parts(&addr.segments()[..]); - socket - .connect((address, remote.port()), self.get_ephemeral_port()) - .map_err(|_| NetworkError::ConnectionFailure)?; - net::wire::IpAddress::Ipv6(address) - } - } - }; - // Blocking connect - // Loop to wait until the socket is staying established or closed, - // or the connection attempt has timed out. - let mut timeout_ms: u32 = 0; - loop { - { - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(handle); - // TCP state at ESTABLISHED means there is connection, so - // simply return the socket. - if socket.state() == net::socket::TcpState::Established { - return Ok(handle); - } - // TCP state at CLOSED implies that the remote rejected connection; - // In this case, abort the connection, and then return the socket - // for re-connection in the future. - if socket.state() == net::socket::TcpState::Closed { - socket.abort(); - // TODO: Return Err(), but would require changes in quartiq/minimq - return Ok(handle); - } - } - - // Any TCP states other than CLOSED and ESTABLISHED are considered - // "transient", so this function should keep waiting and let smoltcp poll - // (e.g. for handling echo reqeust/reply) at the same time. - timeout_ms += self.update()?; - self.poll()?; - - // Time out, and return the socket for re-connection in the future. - if timeout_ms > self.connection_timeout_ms { - // TODO: Return Err(), but would require changes in quartiq/minimq - return Ok(handle); - } - } - } - - fn is_connected(&self, handle: &Self::TcpSocket) -> Result { - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(*handle); - Ok(socket.state() == net::socket::TcpState::Established) - } - - fn write(&self, handle: &mut Self::TcpSocket, buffer: &[u8]) -> nb::Result { - let mut write_error = false; - let mut non_queued_bytes = &buffer[..]; - while non_queued_bytes.len() != 0 { - let result = { - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(*handle); - let result = socket.send_slice(non_queued_bytes); - result - }; - match result { - Ok(num_bytes) => { - // If the buffer is completely filled, close the socket and - // return an error - if num_bytes == 0 { - write_error = true; - break; - } - // In case the buffer is filled up, push bytes into ethernet driver - if num_bytes != non_queued_bytes.len() { - self.update()?; - self.poll()?; - } - // Process the unwritten bytes again, if any - non_queued_bytes = &non_queued_bytes[num_bytes..] - } - Err(_) => { - write_error = true; - break; - } - } - } - if write_error { - // Close the socket to push it back to the array, for - // re-opening the socket in the future - self.close(*handle)?; - return Err(nb::Error::Other(NetworkError::WriteFailure)); - } - Ok(buffer.len()) - } - - fn read( - &self, - handle: &mut Self::TcpSocket, - buffer: &mut [u8], - ) -> nb::Result { - // Enqueue received bytes into the TCP socket buffer - self.update()?; - self.poll()?; - { - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(*handle); - let result = socket.recv_slice(buffer); - match result { - Ok(num_bytes) => return Ok(num_bytes), - Err(_) => {} - } - } - // Close the socket to push it back to the array, for - // re-opening the socket in the future - self.close(*handle)?; - Err(nb::Error::Other(NetworkError::ReadFailure)) - } - - fn close(&self, handle: Self::TcpSocket) -> Result<(), Self::Error> { - let mut sockets = self.sockets.borrow_mut(); - let socket: &mut net::socket::TcpSocket = &mut *sockets.get(handle); - socket.close(); - let mut unused_handles = self.unused_handles.borrow_mut(); - if unused_handles.iter().find(|&x| *x == handle).is_none() { - unused_handles.push(handle).unwrap(); - } - Ok(()) - } -}