Add DeviceRefMut that allows device operation without moving ownership
This commit is contained in:
parent
ee415c63f0
commit
d58ab215b1
3 changed files with 208 additions and 55 deletions
27
README.md
27
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 Phase: Sample leading edge
|
||||||
* Clock speed: 33MHz maximum
|
* Clock speed: 33MHz maximum
|
||||||
|
|
||||||
|
Initialization and usage of owned `Device`:
|
||||||
```rust
|
```rust
|
||||||
let mut spi = ...; // SPI interface to use
|
let mut spi = ...; // SPI interface to use
|
||||||
let mut cs : OutputPin = ...; // chip select
|
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),
|
Ipv4Addr::new(192, 168, 86, 79),
|
||||||
Mode::default()
|
Mode::default()
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let socket = device.socket();
|
let socket = device.socket();
|
||||||
socket.connect(
|
socket.connect(
|
||||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 86, 38)), 8000),
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 86, 38)), 8000),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
block!(interface.send(&mut socket, &[104, 101, 108, 108, 111, 10]));
|
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<InactiveDevice<..>> = ...; // maybe: previously initialized device
|
||||||
|
let mut socket: Option<Socket> = ...; // 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
|
## Todo
|
||||||
|
|
||||||
In no particular order, things to do to improve this driver.
|
In no particular order, things to do to improve this driver.
|
||||||
|
|
|
||||||
151
src/device.rs
151
src/device.rs
|
|
@ -8,12 +8,6 @@ use crate::socket::Socket;
|
||||||
use crate::uninitialized_device::UninitializedDevice;
|
use crate::uninitialized_device::UninitializedDevice;
|
||||||
use crate::{register, MacAddress};
|
use crate::{register, MacAddress};
|
||||||
|
|
||||||
pub struct Device<SpiBus: Bus, HostImpl: Host> {
|
|
||||||
pub bus: SpiBus,
|
|
||||||
host: HostImpl,
|
|
||||||
sockets: [u8; 1],
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ResetError<E> {
|
pub enum ResetError<E> {
|
||||||
SocketsNotReleased,
|
SocketsNotReleased,
|
||||||
Other(E),
|
Other(E),
|
||||||
|
|
@ -25,17 +19,29 @@ impl<E> From<E> for ResetError<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct DeviceState<HostImpl: Host> {
|
||||||
|
host: HostImpl,
|
||||||
|
sockets: [u8; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Device<SpiBus: Bus, HostImpl: Host> {
|
||||||
|
bus: SpiBus,
|
||||||
|
state: DeviceState<HostImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
|
impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
|
||||||
pub(crate) fn new(bus: SpiBus, host: HostImpl) -> Self {
|
pub(crate) fn new(bus: SpiBus, host: HostImpl) -> Self {
|
||||||
Device {
|
Device {
|
||||||
bus,
|
bus,
|
||||||
host,
|
state: DeviceState {
|
||||||
sockets: [0b11111111],
|
host,
|
||||||
|
sockets: [0b11111111],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
|
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
|
||||||
if self.sockets != [0b11111111] {
|
if self.state.sockets != [0b11111111] {
|
||||||
Err(ResetError::SocketsNotReleased)
|
Err(ResetError::SocketsNotReleased)
|
||||||
} else {
|
} else {
|
||||||
self.clear_mode()?;
|
self.clear_mode()?;
|
||||||
|
|
@ -51,17 +57,105 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_socket(&mut self) -> Option<Socket> {
|
#[inline]
|
||||||
|
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
|
self.as_mut().gateway()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn subnet_mask(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
|
self.as_mut().subnet_mask()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mac(&mut self) -> Result<MacAddress, SpiBus::Error> {
|
||||||
|
self.as_mut().mac()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ip(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
|
self.as_mut().ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn phy_config(&mut self) -> Result<register::common::PhyConfig, SpiBus::Error> {
|
||||||
|
self.as_mut().phy_config()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn version(&mut self) -> Result<u8, SpiBus::Error> {
|
||||||
|
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<HostImpl>) {
|
||||||
|
(self.bus, InactiveDevice(self.state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, SpiBus: Bus, HostImpl: Host> From<&'a mut Device<SpiBus, HostImpl>>
|
||||||
|
for DeviceRefMut<'a, SpiBus, HostImpl>
|
||||||
|
{
|
||||||
|
fn from(device: &'a mut Device<SpiBus, HostImpl>) -> Self {
|
||||||
|
DeviceRefMut {
|
||||||
|
bus: &mut device.bus,
|
||||||
|
state: &mut device.state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InactiveDevice<HostImpl: Host>(DeviceState<HostImpl>);
|
||||||
|
|
||||||
|
impl<HostImpl: Host> InactiveDevice<HostImpl> {
|
||||||
|
/// Activates the device by ownership
|
||||||
|
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, HostImpl> {
|
||||||
|
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<HostImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SpiBus: Bus, HostImpl: Host> DeviceRefMut<'_, SpiBus, HostImpl> {
|
||||||
|
pub fn take_socket(&mut self) -> Option<Socket> {
|
||||||
// TODO maybe return Future that resolves when release_socket invoked
|
// TODO maybe return Future that resolves when release_socket invoked
|
||||||
for index in 0..8 {
|
for index in 0..8 {
|
||||||
if self.sockets.get_bit(index) {
|
if self.state.sockets.get_bit(index) {
|
||||||
self.sockets.set_bit(index, false);
|
self.state.sockets.set_bit(index, false);
|
||||||
return Some(Socket::new(index as u8));
|
return Some(Socket::new(index as u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn release_socket(&mut self, socket: Socket) {
|
||||||
|
self.state.sockets.set_bit(socket.index.into(), true);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
|
||||||
let mut octets = [0u8; 4];
|
let mut octets = [0u8; 4];
|
||||||
self.bus
|
self.bus
|
||||||
|
|
@ -103,37 +197,4 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
|
||||||
.read_frame(register::COMMON, register::common::VERSION, &mut version)?;
|
.read_frame(register::COMMON, register::common::VERSION, &mut version)?;
|
||||||
Ok(version[0])
|
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<HostImpl>) {
|
|
||||||
(
|
|
||||||
self.bus,
|
|
||||||
InactiveDevice {
|
|
||||||
host: self.host,
|
|
||||||
sockets: self.sockets,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InactiveDevice<HostImpl: Host> {
|
|
||||||
host: HostImpl,
|
|
||||||
sockets: [u8; 1],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<HostImpl: Host> InactiveDevice<HostImpl> {
|
|
||||||
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, HostImpl> {
|
|
||||||
Device {
|
|
||||||
bus,
|
|
||||||
host: self.host,
|
|
||||||
sockets: self.sockets,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
85
src/udp.rs
85
src/udp.rs
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
use crate::device::Device;
|
use crate::device::{Device, DeviceRefMut};
|
||||||
use crate::host::Host;
|
use crate::host::Host;
|
||||||
use crate::register::socketn;
|
use crate::register::socketn;
|
||||||
use crate::socket::Socket;
|
use crate::socket::Socket;
|
||||||
|
|
@ -184,6 +184,48 @@ where
|
||||||
type UdpSocket = UdpSocket;
|
type UdpSocket = UdpSocket;
|
||||||
type Error = UdpSocketError<SpiBus::Error>;
|
type Error = UdpSocketError<SpiBus::Error>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn socket(&mut self) -> Result<Self::UdpSocket, Self::Error> {
|
||||||
|
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<SpiBus, HostImpl> UdpClientStack for DeviceRefMut<'_, SpiBus, HostImpl>
|
||||||
|
where
|
||||||
|
SpiBus: Bus,
|
||||||
|
HostImpl: Host,
|
||||||
|
{
|
||||||
|
type UdpSocket = UdpSocket;
|
||||||
|
type Error = UdpSocketError<SpiBus::Error>;
|
||||||
|
|
||||||
fn socket(&mut self) -> Result<Self::UdpSocket, Self::Error> {
|
fn socket(&mut self) -> Result<Self::UdpSocket, Self::Error> {
|
||||||
if let Some(socket) = self.take_socket() {
|
if let Some(socket) = self.take_socket() {
|
||||||
Ok(UdpSocket::new(socket))
|
Ok(UdpSocket::new(socket))
|
||||||
|
|
@ -199,27 +241,30 @@ where
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
if let SocketAddr::V4(remote) = remote {
|
if let SocketAddr::V4(remote) = remote {
|
||||||
// TODO dynamically select a random port
|
// TODO dynamically select a random port
|
||||||
socket.open(&mut self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll.
|
socket.open(&mut *self.bus, 49849 + u16::from(socket.socket.index))?; // chosen by fair dice roll.
|
||||||
// guaranteed to be random.
|
// guaranteed to be random.
|
||||||
socket.set_destination(&mut self.bus, remote)?;
|
socket.set_destination(self.bus, remote)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Self::Error::UnsupportedAddress)
|
Err(Self::Error::UnsupportedAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(&mut self, socket: &mut Self::UdpSocket, buffer: &[u8]) -> nb::Result<(), Self::Error> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(
|
fn receive(
|
||||||
&mut self,
|
&mut self,
|
||||||
socket: &mut Self::UdpSocket,
|
socket: &mut Self::UdpSocket,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
) -> nb::Result<(usize, SocketAddr), Self::Error> {
|
) -> 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> {
|
fn close(&mut self, socket: Self::UdpSocket) -> Result<(), Self::Error> {
|
||||||
socket.close(&mut self.bus)?;
|
socket.close(self.bus)?;
|
||||||
self.release_socket(socket.socket);
|
self.release_socket(socket.socket);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -230,10 +275,32 @@ where
|
||||||
SpiBus: Bus,
|
SpiBus: Bus,
|
||||||
HostImpl: Host,
|
HostImpl: Host,
|
||||||
{
|
{
|
||||||
|
#[inline]
|
||||||
fn bind(&mut self, socket: &mut Self::UdpSocket, local_port: u16) -> Result<(), Self::Error> {
|
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<SpiBus, HostImpl> 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_to(
|
fn send_to(
|
||||||
&mut self,
|
&mut self,
|
||||||
socket: &mut Self::UdpSocket,
|
socket: &mut Self::UdpSocket,
|
||||||
|
|
@ -241,7 +308,7 @@ where
|
||||||
buffer: &[u8],
|
buffer: &[u8],
|
||||||
) -> nb::Result<(), Self::Error> {
|
) -> nb::Result<(), Self::Error> {
|
||||||
if let SocketAddr::V4(remote) = remote {
|
if let SocketAddr::V4(remote) = remote {
|
||||||
socket.send_to(&mut self.bus, remote, buffer)?;
|
socket.send_to(self.bus, remote, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(nb::Error::Other(Self::Error::UnsupportedAddress))
|
Err(nb::Error::Other(Self::Error::UnsupportedAddress))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue