w5500_ll/eh0/
fdm.rs

1//! Fixed data length implementation of the [`Registers`] trait using the
2//! [`embedded-hal`] blocking SPI trait.
3//!
4//! This uses the W5500 fixed data length mode (FDM).
5//! In FSM mode the SPI chip select pin is always tied low, and it is not
6//! possible to share the bus with other devices.
7//!
8//! If possible, you should use the [VDM] implementation instead.
9//!
10//! [`embedded-hal`]: https://github.com/rust-embedded/embedded-hal
11//! [`Registers`]: crate::Registers
12//! [VDM]: crate::eh0::vdm
13
14use crate::spi::{self, AccessMode};
15
16/// W5500 blocking fixed data length implementation.
17///
18/// Unlike the VDM implementation there is an intentional lack of a `free`
19/// method to prevent you from sharing the bus with other devices.
20#[derive(Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct W5500<SPI> {
23    /// SPI bus.
24    spi: SPI,
25}
26
27impl<SPI, SpiError> W5500<SPI>
28where
29    SPI: eh0::blocking::spi::Transfer<u8, Error = SpiError>
30        + eh0::blocking::spi::Write<u8, Error = SpiError>,
31{
32    /// Creates a new `W5500` driver from a SPI peripheral.
33    ///
34    /// # Example
35    ///
36    /// ```
37    /// # use ehm::eh0 as hal;
38    /// # let spi = hal::spi::Mock::new(&[]);
39    /// use w5500_ll::eh0::fdm::W5500;
40    ///
41    /// let mut w5500: W5500<_> = W5500::new(spi);
42    /// # w5500.free().done();
43    /// ```
44    #[inline]
45    pub fn new(spi: SPI) -> Self {
46        W5500 { spi }
47    }
48
49    /// Free the SPI bus from the W5500.
50    ///
51    /// # Example
52    ///
53    /// ```
54    /// # use ehm::eh0 as hal;
55    /// # let spi = hal::spi::Mock::new(&[]);
56    /// use w5500_ll::eh0::fdm::W5500;
57    ///
58    /// let w5500: W5500<_> = W5500::new(spi);
59    /// let mut spi = w5500.free();
60    /// # spi.done();
61    /// ```
62    #[inline]
63    pub fn free(self) -> SPI {
64        self.spi
65    }
66}
67
68impl<SPI, SpiError> crate::Registers for W5500<SPI>
69where
70    SPI: eh0::blocking::spi::Transfer<u8, Error = SpiError>
71        + eh0::blocking::spi::Write<u8, Error = SpiError>,
72{
73    /// SPI IO error type.
74    type Error = SpiError;
75
76    /// Read from the W5500.
77    #[allow(clippy::while_let_on_iterator)]
78    fn read(&mut self, mut address: u16, block: u8, data: &mut [u8]) -> Result<(), Self::Error> {
79        let mut chunks = data.chunks_exact_mut(4);
80        while let Some(chunk) = chunks.next() {
81            let header = spi::fdm_header_4b(address, block, AccessMode::Read);
82            self.spi.write(&header)?;
83            self.spi.transfer(chunk)?;
84            address = address.wrapping_add(4);
85        }
86        let mut chunks = chunks.into_remainder().chunks_exact_mut(2);
87        while let Some(chunk) = chunks.next() {
88            let header = spi::fdm_header_2b(address, block, AccessMode::Read);
89            self.spi.write(&header)?;
90            self.spi.transfer(chunk)?;
91            address = address.wrapping_add(2);
92        }
93        let mut chunks = chunks.into_remainder().chunks_exact_mut(1);
94        while let Some(chunk) = chunks.next() {
95            let header = spi::fdm_header_1b(address, block, AccessMode::Read);
96            self.spi.write(&header)?;
97            self.spi.transfer(chunk)?;
98            address = address.wrapping_add(1);
99        }
100
101        Ok(())
102    }
103
104    /// Write to the W5500.
105    #[allow(clippy::while_let_on_iterator)]
106    fn write(&mut self, mut address: u16, block: u8, data: &[u8]) -> Result<(), Self::Error> {
107        let mut chunks = data.chunks_exact(4);
108        while let Some(chunk) = chunks.next() {
109            let header = spi::fdm_header_4b(address, block, AccessMode::Write);
110            self.spi.write(&header)?;
111            self.spi.write(chunk)?;
112            address = address.wrapping_add(4);
113        }
114        let mut chunks = chunks.remainder().chunks_exact(2);
115        while let Some(chunk) = chunks.next() {
116            let header = spi::fdm_header_2b(address, block, AccessMode::Write);
117            self.spi.write(&header)?;
118            self.spi.write(chunk)?;
119            address = address.wrapping_add(2);
120        }
121        let mut chunks = chunks.remainder().chunks_exact(1);
122        while let Some(chunk) = chunks.next() {
123            let header = spi::fdm_header_1b(address, block, AccessMode::Write);
124            self.spi.write(&header)?;
125            self.spi.write(chunk)?;
126            address = address.wrapping_add(1);
127        }
128
129        Ok(())
130    }
131}