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#[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 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
110pub 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}