Refactoring device state management

This commit is contained in:
Ryan Summers 2024-07-05 13:18:56 +02:00 committed by kellerkindt
commit ec57a2f6f1
4 changed files with 108 additions and 45 deletions

View file

@ -1,4 +1,4 @@
use bit_field::BitArray; use bit_field::BitField;
use crate::bus::{Bus, FourWire, ThreeWire}; use crate::bus::{Bus, FourWire, ThreeWire};
use crate::host::Host; use crate::host::Host;
@ -23,35 +23,93 @@ impl<E> From<E> for ResetError<E> {
} }
} }
pub trait State {
type Host: Host;
fn socket(&mut self) -> Option<Socket>;
fn release_socket(&mut self, socket: Socket);
fn any_allocated(&self) -> bool;
fn host(&self) -> &Self::Host;
}
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DeviceState<HostImpl: Host> { pub struct DeviceState<HostImpl: Host> {
host: HostImpl, host: HostImpl,
sockets: [u8; 1], sockets: u8,
} }
pub struct Device<SpiBus: Bus, HostImpl: Host> { impl<HostImpl: Host> DeviceState<HostImpl> {
pub(crate) bus: SpiBus, pub fn new(host: HostImpl) -> Self {
state: DeviceState<HostImpl>, Self {
} sockets: 0xFF,
impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
pub(crate) fn new(bus: SpiBus, host: HostImpl) -> Self {
Device {
bus,
state: DeviceState {
host, host,
sockets: [0b11111111],
},
} }
} }
}
impl<HostImpl: Host> State for DeviceState<HostImpl> {
type Host = HostImpl;
fn socket(&mut self) -> Option<Socket> {
for index in 0..8 {
if self.sockets.get_bit(index) {
self.sockets.set_bit(index, false);
return Some(Socket::new(index as u8));
}
}
None
}
pub fn get_state(&self) -> &DeviceState<HostImpl> { fn release_socket(&mut self, socket: Socket) {
self.sockets.set_bit(socket.index.into(), true);
}
fn host(&self) -> &Self::Host {
&self.host
}
fn any_allocated(&self) -> bool {
self.sockets != 0xFF
}
}
impl<'a, T: State> State for &'a mut T {
type Host = T::Host;
fn socket(&mut self) -> Option<Socket> {
T::socket(self)
}
fn release_socket(&mut self, socket: Socket) {
T::release_socket(self, socket)
}
fn host(&self) -> &Self::Host {
T::host(self)
}
fn any_allocated(&self) -> bool {
T::any_allocated(self)
}
}
pub struct Device<SpiBus: Bus, StateImpl: State> {
pub(crate) bus: SpiBus,
state: StateImpl,
}
impl<SpiBus: Bus, StateImpl: State> Device<SpiBus, StateImpl> {
pub(crate) fn new(bus: SpiBus, state: StateImpl) -> Self {
Device { bus, state }
}
pub fn get_state(&self) -> &StateImpl {
&self.state &self.state
} }
pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> { pub fn reset(mut self) -> Result<UninitializedDevice<SpiBus>, ResetError<SpiBus::Error>> {
if self.state.sockets != [0b11111111] { if self.state.any_allocated() {
Err(ResetError::SocketsNotReleased) Err(ResetError::SocketsNotReleased)
} else { } else {
self.reset_device()?; self.reset_device()?;
@ -59,23 +117,17 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
} }
} }
pub fn release(self) -> (SpiBus, HostImpl) { pub fn release(self) -> (SpiBus, StateImpl) {
(self.bus, self.state.host) (self.bus, self.state)
} }
pub fn take_socket(&mut self) -> Option<Socket> { 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 { self.state.socket()
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) { pub fn release_socket(&mut self, socket: Socket) {
self.state.sockets.set_bit(socket.index.into(), true); self.state.release_socket(socket)
} }
pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> { pub fn gateway(&mut self) -> Result<Ipv4Addr, SpiBus::Error> {
@ -230,18 +282,25 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
Ok(retry_count_register[0]) Ok(retry_count_register[0])
} }
pub fn deactivate(self) -> (SpiBus, InactiveDevice<HostImpl>) { pub fn deactivate(self) -> (SpiBus, InactiveDevice<StateImpl>) {
(self.bus, InactiveDevice(self.state)) (self.bus, InactiveDevice(self.state))
} }
} }
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InactiveDevice<HostImpl: Host>(DeviceState<HostImpl>); pub struct InactiveDevice<StateImpl: State>(StateImpl);
impl<HostImpl: Host> InactiveDevice<HostImpl> { impl<StateImpl: State> InactiveDevice<StateImpl> {
/// Activates the device by taking ownership /// Activates the device by taking ownership
pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, HostImpl> { pub fn activate<SpiBus: Bus>(self, bus: SpiBus) -> Device<SpiBus, StateImpl> {
Device { bus, state: self.0 } Device { bus, state: self.0 }
} }
pub fn activate_ref<SpiBus: Bus>(&mut self, bus: SpiBus) -> Device<SpiBus, &mut StateImpl> {
Device {
bus,
state: &mut self.0,
}
}
} }

View file

@ -1,4 +1,9 @@
use crate::{bus::Bus, device::Device, host::Host, register::socketn, socket::Socket}; use crate::{
bus::Bus,
device::{Device, State},
register::socketn,
socket::Socket,
};
use embedded_nal::{nb, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, TcpClientStack}; use embedded_nal::{nb, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, TcpClientStack};
@ -200,7 +205,7 @@ impl TcpSocket {
} }
} }
impl<SpiBus: Bus, HostImpl: Host> TcpClientStack for Device<SpiBus, HostImpl> { impl<SpiBus: Bus, StateImpl: State> TcpClientStack for Device<SpiBus, StateImpl> {
type TcpSocket = TcpSocket; type TcpSocket = TcpSocket;
type Error = TcpSocketError<SpiBus::Error>; type Error = TcpSocketError<SpiBus::Error>;

View file

@ -4,8 +4,7 @@ use embedded_nal::{nb, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpClientStac
use crate::{ use crate::{
bus::Bus, bus::Bus,
device::Device, device::{Device, State},
host::Host,
register::socketn::{self, Status}, register::socketn::{self, Status},
socket::Socket, socket::Socket,
}; };
@ -470,10 +469,10 @@ impl<E: Debug> From<NbError<E>> for nb::Error<E> {
} }
} }
impl<SpiBus, HostImpl> UdpClientStack for Device<SpiBus, HostImpl> impl<SpiBus, StateImpl> UdpClientStack for Device<SpiBus, StateImpl>
where where
SpiBus: Bus, SpiBus: Bus,
HostImpl: Host, StateImpl: State,
{ {
type UdpSocket = UdpSocket; type UdpSocket = UdpSocket;
type Error = UdpSocketError<SpiBus::Error>; type Error = UdpSocketError<SpiBus::Error>;
@ -521,10 +520,10 @@ where
} }
} }
impl<SpiBus, HostImpl> UdpFullStack for Device<SpiBus, HostImpl> impl<SpiBus, StateImpl> UdpFullStack for Device<SpiBus, StateImpl>
where where
SpiBus: Bus, SpiBus: Bus,
HostImpl: Host, StateImpl: State,
{ {
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.set_port(&mut self.bus, local_port)?; socket.set_port(&mut self.bus, local_port)?;

View file

@ -2,7 +2,7 @@ use embedded_hal::spi::SpiDevice;
use embedded_nal::Ipv4Addr; use embedded_nal::Ipv4Addr;
use crate::bus::{Bus, FourWire, ThreeWire}; use crate::bus::{Bus, FourWire, ThreeWire};
use crate::device::Device; use crate::device::{Device, DeviceState};
use crate::host::{Dhcp, Host, Manual}; use crate::host::{Dhcp, Host, Manual};
use crate::raw_device::RawDevice; use crate::raw_device::RawDevice;
use crate::{ use crate::{
@ -54,7 +54,7 @@ impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
self, self,
mac: MacAddress, mac: MacAddress,
mode_options: Mode, mode_options: Mode,
) -> Result<Device<SpiBus, Dhcp>, InitializeError<SpiBus::Error>> { ) -> Result<Device<SpiBus, DeviceState<Dhcp>>, InitializeError<SpiBus::Error>> {
let host = Dhcp::new(mac); let host = Dhcp::new(mac);
self.initialize_with_host(host, mode_options) self.initialize_with_host(host, mode_options)
} }
@ -67,7 +67,7 @@ impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
mac: MacAddress, mac: MacAddress,
ip: Ipv4Addr, ip: Ipv4Addr,
mode_options: Mode, mode_options: Mode,
) -> Result<Device<SpiBus, Manual>, InitializeError<SpiBus::Error>> { ) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
let mut ip_bytes = ip.octets(); let mut ip_bytes = ip.octets();
ip_bytes[3] = 1; ip_bytes[3] = 1;
let gateway = Ipv4Addr::from(ip_bytes); let gateway = Ipv4Addr::from(ip_bytes);
@ -82,7 +82,7 @@ impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
gateway: Ipv4Addr, gateway: Ipv4Addr,
subnet: Ipv4Addr, subnet: Ipv4Addr,
mode_options: Mode, mode_options: Mode,
) -> Result<Device<SpiBus, Manual>, InitializeError<SpiBus::Error>> { ) -> Result<Device<SpiBus, DeviceState<Manual>>, InitializeError<SpiBus::Error>> {
let host = Manual::new(mac, ip, gateway, subnet); let host = Manual::new(mac, ip, gateway, subnet);
self.initialize_with_host(host, mode_options) self.initialize_with_host(host, mode_options)
} }
@ -91,7 +91,7 @@ impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
mut self, mut self,
mut host: HostImpl, mut host: HostImpl,
mode_options: Mode, mode_options: Mode,
) -> Result<Device<SpiBus, HostImpl>, InitializeError<SpiBus::Error>> { ) -> Result<Device<SpiBus, DeviceState<HostImpl>>, InitializeError<SpiBus::Error>> {
#[cfg(not(feature = "no-chip-version-assertion"))] #[cfg(not(feature = "no-chip-version-assertion"))]
self.assert_chip_version(0x4)?; self.assert_chip_version(0x4)?;
@ -100,7 +100,7 @@ impl<SpiBus: Bus> UninitializedDevice<SpiBus> {
self.set_mode(mode_options)?; self.set_mode(mode_options)?;
host.refresh(&mut self.bus)?; host.refresh(&mut self.bus)?;
Ok(Device::new(self.bus, host)) Ok(Device::new(self.bus, DeviceState::new(host)))
} }
pub fn initialize_macraw( pub fn initialize_macraw(