diff --git a/README.md b/README.md index f72eeb6..ba57530 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ of the SPI implementation. It must be set up to work as the W5500 chip requires * Clock Phase: Sample leading edge * Clock speed: 33MHz maximum +Initialization and usage of owned `Device`: ```rust let mut spi = ...; // SPI interface to use let mut cs : OutputPin = ...; // chip select @@ -40,14 +41,38 @@ of the SPI implementation. It must be set up to work as the W5500 chip requires Ipv4Addr::new(192, 168, 86, 79), Mode::default() ).unwrap(); + let socket = device.socket(); socket.connect( SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 86, 38)), 8000), ).unwrap(); block!(interface.send(&mut socket, &[104, 101, 108, 108, 111, 10])); - interface.close(socket); + device.close(socket); + + // optional + let (spi_bus, inactive_device) = device.deactivate(); ``` +Usage of borrowed SPI-Bus and previously initialized `Device`: +```rust + let mut spi = ...; // SPI interface to use + let mut cs: OutputPin = ...; // chip select + + let mut device: Option> = ...; // maybe: previously initialized device + let mut socket: Option = ...; // maybe: previously opened socket + + if let (Some(socket), Some(device)) = (socket.as_mut(), device.as_mut()) { + let mut buffer = [0u8; 1024]; + match device + // scoped activation & usage of the SPI bus without move + .activate_ref(&mut FourWireRef::new(&mut spi, &mut cs)) + .receive(socket, &mut buffer) + { + Ok(..) => todo!(), + Err(..) => todo!(), + } + } +``` ## Todo In no particular order, things to do to improve this driver. diff --git a/src/device.rs b/src/device.rs index c1fd47b..f3b9e14 100644 --- a/src/device.rs +++ b/src/device.rs @@ -8,12 +8,6 @@ use crate::socket::Socket; use crate::uninitialized_device::UninitializedDevice; use crate::{register, MacAddress}; -pub struct Device { - pub bus: SpiBus, - host: HostImpl, - sockets: [u8; 1], -} - pub enum ResetError { SocketsNotReleased, Other(E), @@ -25,17 +19,29 @@ impl From for ResetError { } } +pub(crate) struct DeviceState { + host: HostImpl, + sockets: [u8; 1], +} + +pub struct Device { + bus: SpiBus, + state: DeviceState, +} + impl Device { pub(crate) fn new(bus: SpiBus, host: HostImpl) -> Self { Device { bus, - host, - sockets: [0b11111111], + state: DeviceState { + host, + sockets: [0b11111111], + }, } } pub fn reset(mut self) -> Result, ResetError> { - if self.sockets != [0b11111111] { + if self.state.sockets != [0b11111111] { Err(ResetError::SocketsNotReleased) } else { self.clear_mode()?; @@ -51,17 +57,105 @@ impl Device { Ok(()) } - pub(crate) fn take_socket(&mut self) -> Option { + #[inline] + pub fn gateway(&mut self) -> Result { + self.as_mut().gateway() + } + + #[inline] + pub fn subnet_mask(&mut self) -> Result { + self.as_mut().subnet_mask() + } + + #[inline] + pub fn mac(&mut self) -> Result { + self.as_mut().mac() + } + + #[inline] + pub fn ip(&mut self) -> Result { + self.as_mut().ip() + } + + #[inline] + pub fn phy_config(&mut self) -> Result { + self.as_mut().phy_config() + } + + #[inline] + pub fn version(&mut self) -> Result { + self.as_mut().version() + } + + #[inline] + pub(crate) fn as_mut(&mut self) -> DeviceRefMut<'_, SpiBus, HostImpl> { + DeviceRefMut { + bus: &mut self.bus, + state: &mut self.state, + } + } + + pub fn release(self) -> (SpiBus, HostImpl) { + (self.bus, self.state.host) + } + + pub fn deactivate(self) -> (SpiBus, InactiveDevice) { + (self.bus, InactiveDevice(self.state)) + } +} + +impl<'a, SpiBus: Bus, HostImpl: Host> From<&'a mut Device> + for DeviceRefMut<'a, SpiBus, HostImpl> +{ + fn from(device: &'a mut Device) -> Self { + DeviceRefMut { + bus: &mut device.bus, + state: &mut device.state, + } + } +} + +pub struct InactiveDevice(DeviceState); + +impl InactiveDevice { + /// Activates the device by ownership + pub fn activate(self, bus: SpiBus) -> Device { + Device { bus, state: self.0 } + } + + /// Activates the device by borrowing + pub fn activate_ref<'a, SpiBus: Bus>( + &'a mut self, + bus: &'a mut SpiBus, + ) -> DeviceRefMut<'a, SpiBus, HostImpl> { + DeviceRefMut { + bus, + state: &mut self.0, + } + } +} + +pub struct DeviceRefMut<'a, SpiBus: Bus, HostImpl: Host> { + pub(crate) bus: &'a mut SpiBus, + state: &'a mut DeviceState, +} + +impl DeviceRefMut<'_, SpiBus, HostImpl> { + pub fn take_socket(&mut self) -> Option { // TODO maybe return Future that resolves when release_socket invoked for index in 0..8 { - if self.sockets.get_bit(index) { - self.sockets.set_bit(index, false); + if self.state.sockets.get_bit(index) { + self.state.sockets.set_bit(index, false); return Some(Socket::new(index as u8)); } } None } + pub fn release_socket(&mut self, socket: Socket) { + self.state.sockets.set_bit(socket.index.into(), true); + } + pub fn gateway(&mut self) -> Result { let mut octets = [0u8; 4]; self.bus @@ -103,37 +197,4 @@ impl Device { .read_frame(register::COMMON, register::common::VERSION, &mut version)?; Ok(version[0]) } - - pub(crate) fn release_socket(&mut self, socket: Socket) { - self.sockets.set_bit(socket.index.into(), true); - } - - pub fn release(self) -> (SpiBus, HostImpl) { - (self.bus, self.host) - } - - pub fn deactivate(self) -> (SpiBus, InactiveDevice) { - ( - self.bus, - InactiveDevice { - host: self.host, - sockets: self.sockets, - }, - ) - } -} - -pub struct InactiveDevice { - host: HostImpl, - sockets: [u8; 1], -} - -impl InactiveDevice { - pub fn activate(self, bus: SpiBus) -> Device { - Device { - bus, - host: self.host, - sockets: self.sockets, - } - } } diff --git a/src/udp.rs b/src/udp.rs index 5008e22..8b1d9b7 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -1,5 +1,5 @@ use crate::bus::Bus; -use crate::device::Device; +use crate::device::{Device, DeviceRefMut}; use crate::host::Host; use crate::register::socketn; use crate::socket::Socket; @@ -184,6 +184,48 @@ where 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)) @@ -199,27 +241,30 @@ where ) -> Result<(), Self::Error> { if let SocketAddr::V4(remote) = remote { // 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)?; + socket.open(&mut *self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll. + // guaranteed to be random. + socket.set_destination(self.bus, remote)?; Ok(()) } else { Err(Self::Error::UnsupportedAddress) } } + fn send(&mut self, socket: &mut Self::UdpSocket, buffer: &[u8]) -> nb::Result<(), Self::Error> { - socket.send(&mut self.bus, buffer)?; + socket.send(self.bus, buffer)?; Ok(()) } + fn receive( &mut self, socket: &mut Self::UdpSocket, buffer: &mut [u8], ) -> nb::Result<(usize, SocketAddr), Self::Error> { - Ok(socket.receive(&mut self.bus, buffer)?) + Ok(socket.receive(self.bus, buffer)?) } + fn close(&mut self, socket: Self::UdpSocket) -> Result<(), Self::Error> { - socket.close(&mut self.bus)?; + socket.close(self.bus)?; self.release_socket(socket.socket); Ok(()) } @@ -230,10 +275,32 @@ where SpiBus: Bus, HostImpl: Host, { + #[inline] fn bind(&mut self, socket: &mut Self::UdpSocket, local_port: u16) -> Result<(), Self::Error> { - socket.open(&mut self.bus, local_port)?; + 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(self.bus, local_port)?; Ok(()) } + fn send_to( &mut self, socket: &mut Self::UdpSocket, @@ -241,7 +308,7 @@ where buffer: &[u8], ) -> nb::Result<(), Self::Error> { if let SocketAddr::V4(remote) = remote { - socket.send_to(&mut self.bus, remote, buffer)?; + socket.send_to(self.bus, remote, buffer)?; Ok(()) } else { Err(nb::Error::Other(Self::Error::UnsupportedAddress))