diff --git a/examples/coex.rs b/examples/coex.rs index 125e2693..85b7a2ef 100644 --- a/examples/coex.rs +++ b/examples/coex.rs @@ -15,7 +15,7 @@ use ble_hci::{ att::Uuid, Ble, HciConnector, }; -use esp_wifi::{ble::controller::BleConnector, current_millis, wifi::utils::Network}; +use esp_wifi::{ble::controller::BleConnector, current_millis, wifi_interface::Network}; use embedded_io::blocking::*; use embedded_svc::wifi::{ diff --git a/examples/dhcp.rs b/examples/dhcp.rs index fee824f2..12a52b7a 100644 --- a/examples/dhcp.rs +++ b/examples/dhcp.rs @@ -21,8 +21,8 @@ use embedded_svc::wifi::{ use esp_backtrace as _; use esp_println::logger::init_logger; use esp_println::{print, println}; -use esp_wifi::wifi::utils::{create_network_interface, Network}; -use esp_wifi::wifi_interface::{timestamp, WifiError}; +use esp_wifi::wifi::utils::{create_network_interface}; +use esp_wifi::wifi_interface::{timestamp, WifiError, Network}; use esp_wifi::{create_network_stack_storage, network_stack_storage}; use esp_wifi::{current_millis, initialize}; use hal::clock::{ClockControl, CpuClock}; diff --git a/src/wifi/utils.rs b/src/wifi/utils.rs index c8440177..e2d09ec7 100644 --- a/src/wifi/utils.rs +++ b/src/wifi/utils.rs @@ -1,10 +1,3 @@ -use core::cell::RefCell; -use embedded_io::blocking::Read; -use embedded_io::blocking::Write; -use embedded_io::Io; -use smoltcp::iface::SocketHandle; -use smoltcp::time::Instant; -use smoltcp::wire::Ipv4Address; use smoltcp::{ iface::{Interface, InterfaceBuilder, Neighbor, NeighborCache, Route, Routes, SocketStorage}, socket::{Dhcpv4Socket, TcpSocket, TcpSocketBuffer}, @@ -94,311 +87,3 @@ pub fn create_network_interface<'a>( ethernet } - -// Following code is not well tested, yet. -// It's currently more or less just here for the DHCP example. -// Might get replaced or improved in future. - -pub struct Network<'a> { - interface: RefCell>, - current_millis_fn: fn() -> u64, - local_port: RefCell, -} - -impl<'a> Network<'a> { - pub fn new( - interface: crate::wifi_interface::Wifi<'a>, - current_millis_fn: fn() -> u64, - ) -> Network { - Self { - interface: RefCell::new(interface), - current_millis_fn, - local_port: RefCell::new(41000), - } - } - - fn with_interface(&self, f: F) -> R - where - F: FnOnce(&mut crate::wifi_interface::Wifi<'a>) -> R, - { - let mut interface = self.interface.borrow_mut(); - f(&mut interface) - } - - pub fn get_socket<'s>(&'s mut self) -> Socket<'s, 'a> - where - 'a: 's, - { - let socket_handle = self.with_interface(|interface| { - let (socket_handle, _) = interface.network_interface().sockets_mut().next().unwrap(); - socket_handle - }); - - Socket { - socket_handle, - network: self, - } - } - - pub fn work(&self) { - loop { - self.with_interface(|interface| interface.poll_dhcp().ok()); - if let Ok(false) = self.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis((self.current_millis_fn)() as i64)) - }) { - break; - } - } - } - - fn next_local_port(&self) -> u16 { - let mut local_port = self.local_port.borrow_mut(); - *local_port += 1; - if *local_port == 65535 { - *local_port = 41000; - } - *local_port - } -} - -pub struct Socket<'s, 'n: 's> { - socket_handle: SocketHandle, - network: &'s Network<'n>, -} - -impl<'s, 'n: 's> Socket<'s, 'n> { - pub fn open<'i>(&'i mut self, addr: Ipv4Address, port: u16) -> Result<(), IoError> - where - 's: 'i, - { - { - self.network.with_interface(|interface| { - let (sock, cx) = interface - .network_interface() - .get_socket_and_context::(self.socket_handle); - let remote_endpoint = (addr, port); - sock.connect(cx, remote_endpoint, self.network.next_local_port()) - .unwrap(); - }); - } - - loop { - let can_send = self.network.with_interface(|interface| { - let sock = interface - .network_interface() - .get_socket::(self.socket_handle); - if sock.can_send() { - true - } else { - false - } - }); - - if can_send { - break; - } - - self.work(); - } - - Ok(()) - } - - pub fn disconnect(&mut self) { - self.network.with_interface(|interface| { - interface - .network_interface() - .get_socket::(self.socket_handle) - .abort(); - }); - - self.work(); - } - - pub fn work(&mut self) { - loop { - self.network - .with_interface(|interface| interface.poll_dhcp().ok()); - if let Ok(false) = self.network.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis( - (self.network.current_millis_fn)() as i64 - )) - }) { - break; - } - } - } -} - -#[derive(Debug)] -pub enum IoError { - Other(smoltcp::Error), - SocketClosed, -} - -impl embedded_io::Error for IoError { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other - } -} - -impl From for IoError { - fn from(e: smoltcp::Error) -> Self { - IoError::Other(e) - } -} - -impl<'s, 'n: 's> Io for Socket<'s, 'n> { - type Error = IoError; -} - -impl<'s, 'n: 's> Read for Socket<'s, 'n> { - fn read(&mut self, buf: &mut [u8]) -> Result { - loop { - self.network.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis( - (self.network.current_millis_fn)() as i64 - )) - .unwrap(); - }); - - let (may_recv, is_open, can_recv) = self.network.with_interface(|interface| { - let socket = interface - .network_interface() - .get_socket::(self.socket_handle); - - (socket.may_recv(), socket.is_open(), socket.can_recv()) - }); - if may_recv { - break; - } - - if !is_open { - return Err(IoError::SocketClosed); - } - - if !can_recv { - return Err(IoError::SocketClosed); - } - } - - loop { - let res = self.network.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis( - (self.network.current_millis_fn)() as i64 - )) - }); - - if let Ok(false) = res { - break; - } - } - - self.network.with_interface(|interface| { - let socket = interface - .network_interface() - .get_socket::(self.socket_handle); - - socket.recv_slice(buf).map_err(|e| IoError::Other(e)) - }) - } -} - -impl<'s, 'n: 's> Write for Socket<'s, 'n> { - fn write(&mut self, buf: &[u8]) -> Result { - loop { - self.network.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis( - (self.network.current_millis_fn)() as i64 - )) - .unwrap(); - }); - - let (may_send, is_open, can_send) = self.network.with_interface(|interface| { - let socket = interface - .network_interface() - .get_socket::(self.socket_handle); - - (socket.may_send(), socket.is_open(), socket.can_send()) - }); - - if may_send { - break; - } - - if !is_open { - return Err(IoError::SocketClosed); - } - - if !can_send { - return Err(IoError::SocketClosed); - } - } - - loop { - let res = self.network.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis( - (self.network.current_millis_fn)() as i64 - )) - }); - - if let Ok(false) = res { - break; - } - } - - let res = self.network.with_interface(|interface| { - let socket = interface - .network_interface() - .get_socket::(self.socket_handle); - - let mut written = 0; - loop { - match socket.send_slice(&buf[written..]) { - Ok(len) => { - written += len; - - if written >= buf.len() { - break Ok(written); - } - - log::info!("not fully written: {}", len); - } - Err(err) => break Err(IoError::Other(err)), - } - } - }); - - res - } - - fn flush(&mut self) -> Result<(), Self::Error> { - loop { - let res = self.network.with_interface(|interface| { - interface - .network_interface() - .poll(Instant::from_millis( - (self.network.current_millis_fn)() as i64 - )) - }); - - if let Ok(false) = res { - break; - } - } - - Ok(()) - } -} diff --git a/src/wifi_interface.rs b/src/wifi_interface.rs index 11b0378b..69c9e79e 100644 --- a/src/wifi_interface.rs +++ b/src/wifi_interface.rs @@ -1,4 +1,7 @@ +use core::cell::RefCell; use core::fmt::Display; +use embedded_io::blocking::{Read, Write}; +use embedded_io::Io; use embedded_svc::ipv4::Ipv4Addr; use embedded_svc::{ @@ -10,9 +13,9 @@ use embedded_svc::{ }; use enumset::EnumSet; use smoltcp::iface::{Interface, SocketHandle}; -use smoltcp::socket::{Dhcpv4Socket, Socket}; +use smoltcp::socket::{Dhcpv4Socket, TcpSocket}; use smoltcp::time::Instant; -use smoltcp::wire::{IpAddress, IpCidr}; +use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address}; use crate::current_millis; use crate::wifi::WifiDevice; @@ -34,7 +37,7 @@ impl<'a> Wifi<'a> { for (handle, socket) in network_interface.sockets_mut() { match socket { - Socket::Dhcpv4(_) => dhcp_socket_handle = Some(handle), + smoltcp::socket::Socket::Dhcpv4(_) => dhcp_socket_handle = Some(handle), _ => {} } } @@ -314,3 +317,311 @@ impl<'a> embedded_svc::wifi::Wifi for Wifi<'a> { pub fn timestamp() -> Instant { Instant::from_millis(current_millis() as i64) } + +// Following code is not well tested, yet. +// It's currently more or less just here for the DHCP example. +// Might get replaced or improved in future. + +pub struct Network<'a> { + interface: RefCell>, + current_millis_fn: fn() -> u64, + local_port: RefCell, +} + +impl<'a> Network<'a> { + pub fn new( + interface: crate::wifi_interface::Wifi<'a>, + current_millis_fn: fn() -> u64, + ) -> Network { + Self { + interface: RefCell::new(interface), + current_millis_fn, + local_port: RefCell::new(41000), + } + } + + fn with_interface(&self, f: F) -> R + where + F: FnOnce(&mut crate::wifi_interface::Wifi<'a>) -> R, + { + let mut interface = self.interface.borrow_mut(); + f(&mut interface) + } + + pub fn get_socket<'s>(&'s mut self) -> Socket<'s, 'a> + where + 'a: 's, + { + let socket_handle = self.with_interface(|interface| { + let (socket_handle, _) = interface.network_interface().sockets_mut().next().unwrap(); + socket_handle + }); + + Socket { + socket_handle, + network: self, + } + } + + pub fn work(&self) { + loop { + self.with_interface(|interface| interface.poll_dhcp().ok()); + if let Ok(false) = self.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis((self.current_millis_fn)() as i64)) + }) { + break; + } + } + } + + fn next_local_port(&self) -> u16 { + let mut local_port = self.local_port.borrow_mut(); + *local_port += 1; + if *local_port == 65535 { + *local_port = 41000; + } + *local_port + } +} + +pub struct Socket<'s, 'n: 's> { + socket_handle: SocketHandle, + network: &'s Network<'n>, +} + +impl<'s, 'n: 's> Socket<'s, 'n> { + pub fn open<'i>(&'i mut self, addr: Ipv4Address, port: u16) -> Result<(), IoError> + where + 's: 'i, + { + { + self.network.with_interface(|interface| { + let (sock, cx) = interface + .network_interface() + .get_socket_and_context::(self.socket_handle); + let remote_endpoint = (addr, port); + sock.connect(cx, remote_endpoint, self.network.next_local_port()) + .unwrap(); + }); + } + + loop { + let can_send = self.network.with_interface(|interface| { + let sock = interface + .network_interface() + .get_socket::(self.socket_handle); + if sock.can_send() { + true + } else { + false + } + }); + + if can_send { + break; + } + + self.work(); + } + + Ok(()) + } + + pub fn disconnect(&mut self) { + self.network.with_interface(|interface| { + interface + .network_interface() + .get_socket::(self.socket_handle) + .abort(); + }); + + self.work(); + } + + pub fn work(&mut self) { + loop { + self.network + .with_interface(|interface| interface.poll_dhcp().ok()); + if let Ok(false) = self.network.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis( + (self.network.current_millis_fn)() as i64 + )) + }) { + break; + } + } + } +} + +#[derive(Debug)] +pub enum IoError { + Other(smoltcp::Error), + SocketClosed, +} + +impl embedded_io::Error for IoError { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl From for IoError { + fn from(e: smoltcp::Error) -> Self { + IoError::Other(e) + } +} + +impl<'s, 'n: 's> Io for Socket<'s, 'n> { + type Error = IoError; +} + +impl<'s, 'n: 's> Read for Socket<'s, 'n> { + fn read(&mut self, buf: &mut [u8]) -> Result { + loop { + self.network.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis( + (self.network.current_millis_fn)() as i64 + )) + .unwrap(); + }); + + let (may_recv, is_open, can_recv) = self.network.with_interface(|interface| { + let socket = interface + .network_interface() + .get_socket::(self.socket_handle); + + (socket.may_recv(), socket.is_open(), socket.can_recv()) + }); + if may_recv { + break; + } + + if !is_open { + return Err(IoError::SocketClosed); + } + + if !can_recv { + return Err(IoError::SocketClosed); + } + } + + loop { + let res = self.network.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis( + (self.network.current_millis_fn)() as i64 + )) + }); + + if let Ok(false) = res { + break; + } + } + + self.network.with_interface(|interface| { + let socket = interface + .network_interface() + .get_socket::(self.socket_handle); + + socket.recv_slice(buf).map_err(|e| IoError::Other(e)) + }) + } +} + +impl<'s, 'n: 's> Write for Socket<'s, 'n> { + fn write(&mut self, buf: &[u8]) -> Result { + loop { + self.network.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis( + (self.network.current_millis_fn)() as i64 + )) + .unwrap(); + }); + + let (may_send, is_open, can_send) = self.network.with_interface(|interface| { + let socket = interface + .network_interface() + .get_socket::(self.socket_handle); + + (socket.may_send(), socket.is_open(), socket.can_send()) + }); + + if may_send { + break; + } + + if !is_open { + return Err(IoError::SocketClosed); + } + + if !can_send { + return Err(IoError::SocketClosed); + } + } + + loop { + let res = self.network.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis( + (self.network.current_millis_fn)() as i64 + )) + }); + + if let Ok(false) = res { + break; + } + } + + let res = self.network.with_interface(|interface| { + let socket = interface + .network_interface() + .get_socket::(self.socket_handle); + + let mut written = 0; + loop { + match socket.send_slice(&buf[written..]) { + Ok(len) => { + written += len; + + if written >= buf.len() { + break Ok(written); + } + + log::info!("not fully written: {}", len); + } + Err(err) => break Err(IoError::Other(err)), + } + } + }); + + res + } + + fn flush(&mut self) -> Result<(), Self::Error> { + loop { + let res = self.network.with_interface(|interface| { + interface + .network_interface() + .poll(Instant::from_millis( + (self.network.current_millis_fn)() as i64 + )) + }); + + if let Ok(false) = res { + break; + } + } + + Ok(()) + } +}