1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Fixed data length implementation of the [`Registers`] trait using the
//! [`embedded-hal`] blocking SPI traits.
//!
//! This uses the W5500 fixed data length mode (FDM).
//! In FSM mode the SPI chip select pin is always tied low, and it is not
//! possible to share the bus with other devices.
//!
//! If possible, you should use the [VDM] implementation instead.
//!
//! [`embedded-hal`]: https://github.com/rust-embedded/embedded-hal
//! [`Registers`]: crate::Registers
//! [VDM]: crate::blocking::vdm

use crate::spi::{self, AccessMode};

/// W5500 blocking fixed data length implementation.
///
/// Unlike the VDM implementation there is an intentional lack of a `free`
/// method to prevent you from sharing the bus with other devices.
pub struct W5500<SPI> {
    /// SPI bus.
    spi: SPI,
}

impl<SPI, SpiError> W5500<SPI>
where
    SPI: embedded_hal::blocking::spi::Transfer<u8, Error = SpiError>
        + embedded_hal::blocking::spi::Write<u8, Error = SpiError>,
{
    /// Creates a new `W5500` driver from a SPI peripheral.
    ///
    /// # Example
    ///
    /// ```
    /// # use embedded_hal_mock as hal;
    /// # let spi = hal::spi::Mock::new(&[]);
    /// use w5500_ll::blocking::fdm::W5500;
    ///
    /// let mut w5500: W5500<_> = W5500::new(spi);
    /// ```
    pub fn new(spi: SPI) -> Self {
        W5500 { spi }
    }

    /// Free the SPI bus from the W5500.
    ///
    /// # Example
    ///
    /// ```
    /// # use embedded_hal_mock as hal;
    /// # let spi = hal::spi::Mock::new(&[]);
    /// use w5500_ll::blocking::fdm::W5500;
    ///
    /// let w5500: W5500<_> = W5500::new(spi);
    /// let spi = w5500.free();
    /// ```
    pub fn free(self) -> SPI {
        self.spi
    }
}

impl<SPI, SpiError> crate::Registers for W5500<SPI>
where
    SPI: embedded_hal::blocking::spi::Transfer<u8, Error = SpiError>
        + embedded_hal::blocking::spi::Write<u8, Error = SpiError>,
{
    /// SPI IO error type.
    type Error = SpiError;

    /// Read from the W5500.
    #[allow(clippy::while_let_on_iterator)]
    fn read(&mut self, mut address: u16, block: u8, data: &mut [u8]) -> Result<(), Self::Error> {
        let mut chunks = data.chunks_exact_mut(4);
        while let Some(chunk) = chunks.next() {
            let header = spi::fdm_header_4b(address, block, AccessMode::Read);
            self.spi.write(&header)?;
            self.spi.transfer(chunk)?;
            address = address.wrapping_add(4);
        }
        let mut chunks = chunks.into_remainder().chunks_exact_mut(2);
        while let Some(chunk) = chunks.next() {
            let header = spi::fdm_header_2b(address, block, AccessMode::Read);
            self.spi.write(&header)?;
            self.spi.transfer(chunk)?;
            address = address.wrapping_add(2);
        }
        let mut chunks = chunks.into_remainder().chunks_exact_mut(1);
        while let Some(chunk) = chunks.next() {
            let header = spi::fdm_header_1b(address, block, AccessMode::Read);
            self.spi.write(&header)?;
            self.spi.transfer(chunk)?;
            address = address.wrapping_add(1);
        }

        Ok(())
    }

    /// Write to the W5500.
    #[allow(clippy::while_let_on_iterator)]
    fn write(&mut self, mut address: u16, block: u8, data: &[u8]) -> Result<(), Self::Error> {
        let mut chunks = data.chunks_exact(4);
        while let Some(chunk) = chunks.next() {
            let header = spi::fdm_header_4b(address, block, AccessMode::Write);
            self.spi.write(&header)?;
            self.spi.write(&chunk)?;
            address = address.wrapping_add(4);
        }
        let mut chunks = chunks.remainder().chunks_exact(2);
        while let Some(chunk) = chunks.next() {
            let header = spi::fdm_header_2b(address, block, AccessMode::Write);
            self.spi.write(&header)?;
            self.spi.write(&chunk)?;
            address = address.wrapping_add(2);
        }
        let mut chunks = chunks.remainder().chunks_exact(1);
        while let Some(chunk) = chunks.next() {
            let header = spi::fdm_header_1b(address, block, AccessMode::Write);
            self.spi.write(&header)?;
            self.spi.write(&chunk)?;
            address = address.wrapping_add(1);
        }

        Ok(())
    }
}