w5500/bus/
three_wire.rs

1#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]
2
3use core::fmt;
4use embedded_hal::spi::{ErrorType, Operation, SpiBus};
5
6use crate::bus::Bus;
7
8const WRITE_MODE_MASK: u8 = 0b00000_1_0;
9
10const FIXED_DATA_LENGTH_MODE_1: u8 = 0b000000_01;
11const FIXED_DATA_LENGTH_MODE_2: u8 = 0b000000_10;
12const FIXED_DATA_LENGTH_MODE_4: u8 = 0b000000_11;
13
14// TODO This name is not ideal, should be renamed to FDM
15#[derive(Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct ThreeWire<SPI> {
18    spi: SPI,
19}
20
21impl<SPI> ThreeWire<SPI> {
22    pub fn new(spi: SPI) -> Self {
23        Self { spi }
24    }
25
26    pub fn release(self) -> SPI {
27        self.spi
28    }
29}
30
31impl<SPI: SpiBus> Bus for ThreeWire<SPI> {
32    type Error = <SPI as ErrorType>::Error;
33
34    /// Transfers a frame with an arbitrary data length in FDM
35    ///
36    /// This is done by passing chunks of fixed length 4, 2, or 1.  For example if a frame looks like this:
37    ///
38    /// (address 23) 0xF0 0xAB 0x83 0xB2 0x44 0x2C 0xAA
39    ///
40    /// This will be sent as separate frames in the chunks
41    ///
42    /// (address 23) 0xF0 0xAB 0x83 0xB2
43    /// (address 27) 44 2C
44    /// (address 29) AA
45    fn read_frame(
46        &mut self,
47        block: u8,
48        mut address: u16,
49        data: &mut [u8],
50    ) -> Result<(), Self::Error> {
51        let mut control_phase = block << 3;
52
53        let mut data_phase = data;
54        let mut last_length_written: u16;
55        while !data_phase.is_empty() {
56            if data_phase.len() >= 4 {
57                control_phase |= FIXED_DATA_LENGTH_MODE_4;
58                last_length_written = 4;
59            } else if data_phase.len() >= 2 {
60                control_phase |= FIXED_DATA_LENGTH_MODE_2;
61                last_length_written = 2;
62            } else {
63                control_phase |= FIXED_DATA_LENGTH_MODE_1;
64                last_length_written = 1;
65            }
66
67            let address_phase = address.to_be_bytes();
68            self.spi
69                .write(&address_phase)
70                .and_then(|_| self.spi.write(&[control_phase]))?;
71            self.spi
72                .transfer_in_place(&mut data_phase[..last_length_written as usize])?;
73
74            address += last_length_written;
75            data_phase = &mut data_phase[last_length_written as usize..];
76        }
77        Ok(())
78    }
79
80    fn write_frame(&mut self, block: u8, mut address: u16, data: &[u8]) -> Result<(), Self::Error> {
81        let mut control_phase = (block << 3) | WRITE_MODE_MASK;
82
83        let mut data_phase = data;
84        let mut last_length_written: u16;
85        while !data_phase.is_empty() {
86            if data_phase.len() >= 4 {
87                control_phase |= FIXED_DATA_LENGTH_MODE_4;
88                last_length_written = 4;
89            } else if data_phase.len() >= 2 {
90                control_phase |= FIXED_DATA_LENGTH_MODE_2;
91                last_length_written = 2;
92            } else {
93                control_phase |= FIXED_DATA_LENGTH_MODE_1;
94                last_length_written = 1;
95            }
96
97            let address_phase = address.to_be_bytes();
98            self.spi
99                .write(&address_phase)
100                .and_then(|_| self.spi.write(&[control_phase]))
101                .and_then(|_| self.spi.write(&data_phase[..last_length_written as usize]))?;
102
103            address += last_length_written;
104            data_phase = &data_phase[last_length_written as usize..];
105        }
106        Ok(())
107    }
108}
109
110// Must use map_err, ambiguity prevents From from being implemented
111pub enum ThreeWireError<TransferError, WriteError> {
112    TransferError(TransferError),
113    WriteError(WriteError),
114}
115
116impl<TransferError, WriteError> fmt::Debug for ThreeWireError<TransferError, WriteError> {
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        write!(
119            f,
120            "ThreeWireError::{}",
121            match self {
122                Self::TransferError(_) => "TransferError",
123                Self::WriteError(_) => "WriteError",
124            }
125        )
126    }
127}