Skip to content

Commit 0a0d9cc

Browse files
authored
Merge pull request #1 from jonahbron/restructure
Restructure
2 parents f8e6bcf + 557b15f commit 0a0d9cc

17 files changed

+2062
-782
lines changed

driver_state_machine_diagram.svg

+1
Loading

src/bus/four_wire.rs

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use byteorder::{BigEndian, ByteOrder};
2+
use embedded_hal::digital::v2::OutputPin;
3+
use embedded_hal::spi::FullDuplex;
4+
5+
use crate::bus::{ActiveBus, Bus};
6+
7+
const WRITE_MODE_MASK: u8 = 0b00000_1_00;
8+
9+
pub struct FourWire<ChipSelect: OutputPin> {
10+
cs: ChipSelect,
11+
}
12+
13+
impl<ChipSelect: OutputPin> FourWire<ChipSelect> {
14+
pub fn new(cs: ChipSelect) -> Self {
15+
Self { cs }
16+
}
17+
pub fn release(self) -> ChipSelect {
18+
self.cs
19+
}
20+
}
21+
22+
impl<ChipSelect: OutputPin> Bus for FourWire<ChipSelect> {}
23+
24+
impl<ChipSelect: OutputPin> FourWire<ChipSelect> {
25+
pub fn activate<Spi: FullDuplex<u8>>(self, spi: Spi) -> ActiveFourWire<Spi, ChipSelect> {
26+
ActiveFourWire { cs: self.cs, spi }
27+
}
28+
}
29+
30+
pub struct ActiveFourWire<Spi: FullDuplex<u8>, ChipSelect: OutputPin> {
31+
cs: ChipSelect,
32+
spi: Spi,
33+
}
34+
35+
impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveBus for ActiveFourWire<Spi, ChipSelect> {
36+
type Error = FourWireError<Spi::Error, ChipSelect::Error>;
37+
fn transfer_frame<'a>(
38+
&mut self,
39+
block: u8,
40+
address: u16,
41+
is_write: bool,
42+
data: &'a mut [u8],
43+
) -> Result<&'a mut [u8], Self::Error> {
44+
let mut control_phase = block << 3;
45+
if is_write {
46+
control_phase |= WRITE_MODE_MASK;
47+
}
48+
let data_phase = data;
49+
let mut address_phase = [0u8; 2];
50+
BigEndian::write_u16(&mut address_phase, address);
51+
52+
self.cs
53+
.set_low()
54+
.map_err(|e| FourWireError::ChipSelectError(e))?;
55+
Self::transfer_bytes(&mut self.spi, &mut address_phase)
56+
.and_then(|_| Self::transfer_byte(&mut self.spi, &mut control_phase))
57+
.and_then(|_| Self::transfer_bytes(&mut self.spi, data_phase))
58+
.map_err(|e| FourWireError::SpiError(e))?;
59+
self.cs
60+
.set_high()
61+
.map_err(|e| FourWireError::ChipSelectError(e))?;
62+
63+
Ok(data_phase)
64+
}
65+
}
66+
impl<Spi: FullDuplex<u8>, ChipSelect: OutputPin> ActiveFourWire<Spi, ChipSelect> {
67+
pub fn deactivate(self) -> (FourWire<ChipSelect>, Spi) {
68+
(FourWire::new(self.cs), self.spi)
69+
}
70+
}
71+
72+
#[repr(u8)]
73+
pub enum FourWireError<SpiError, ChipSelectError> {
74+
SpiError(SpiError),
75+
ChipSelectError(ChipSelectError),
76+
}

src/bus/mod.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use embedded_hal::spi::FullDuplex;
2+
3+
mod four_wire;
4+
mod three_wire;
5+
6+
pub use self::four_wire::ActiveFourWire;
7+
pub use self::four_wire::FourWire;
8+
pub use self::three_wire::ActiveThreeWire;
9+
pub use self::three_wire::ThreeWire;
10+
11+
pub trait Bus {}
12+
13+
pub trait ActiveBus {
14+
type Error;
15+
16+
fn transfer_frame<'a>(
17+
&mut self,
18+
block: u8,
19+
address: u16,
20+
is_write: bool,
21+
data: &'a mut [u8],
22+
) -> Result<&'a mut [u8], Self::Error>;
23+
24+
fn transfer_bytes<'a, Spi: FullDuplex<u8>>(
25+
spi: &mut Spi,
26+
bytes: &'a mut [u8],
27+
) -> Result<&'a mut [u8], Spi::Error> {
28+
for byte in bytes.iter_mut() {
29+
Self::transfer_byte(spi, byte)?;
30+
}
31+
Ok(bytes)
32+
}
33+
34+
fn transfer_byte<'a, Spi: FullDuplex<u8>>(
35+
spi: &mut Spi,
36+
byte: &'a mut u8,
37+
) -> Result<&'a mut u8, Spi::Error> {
38+
*byte = block!(spi.send(*byte)).and_then(|_| block!(spi.read()))?;
39+
Ok(byte)
40+
}
41+
}

src/bus/three_wire.rs

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use byteorder::{BigEndian, ByteOrder};
2+
use embedded_hal::spi::FullDuplex;
3+
4+
use crate::bus::{ActiveBus, Bus};
5+
6+
const WRITE_MODE_MASK: u8 = 0b00000_1_0;
7+
8+
const FIXED_DATA_LENGTH_MODE_1: u8 = 0b000000_01;
9+
const FIXED_DATA_LENGTH_MODE_2: u8 = 0b000000_10;
10+
const FIXED_DATA_LENGTH_MODE_4: u8 = 0b000000_11;
11+
12+
pub struct ThreeWire {}
13+
14+
impl ThreeWire {
15+
pub fn new() -> Self {
16+
Self {}
17+
}
18+
}
19+
20+
impl Bus for ThreeWire {}
21+
22+
impl ThreeWire {
23+
pub fn activate<Spi: FullDuplex<u8>>(self, spi: Spi) -> ActiveThreeWire<Spi> {
24+
ActiveThreeWire { spi }
25+
}
26+
}
27+
28+
pub struct ActiveThreeWire<Spi: FullDuplex<u8>> {
29+
spi: Spi,
30+
}
31+
32+
impl<Spi: FullDuplex<u8>> ActiveBus for ActiveThreeWire<Spi> {
33+
type Error = Spi::Error;
34+
35+
/// Transfers a frame with an arbitrary data length in FDM
36+
///
37+
/// This is done by passing chunks of fixed length 4, 2, or 1. For example if a frame looks like this:
38+
///
39+
/// (address 23) 0xF0 0xAB 0x83 0xB2 0x44 0x2C 0xAA
40+
///
41+
/// This will be sent as separate frames in the chunks
42+
///
43+
/// (address 23) 0xF0 0xAB 0x83 0xB2
44+
/// (address 27) 44 2C
45+
/// (address 29) AA
46+
fn transfer_frame<'a>(
47+
&mut self,
48+
block: u8,
49+
mut address: u16,
50+
is_write: bool,
51+
data: &'a mut [u8],
52+
) -> Result<&'a mut [u8], Self::Error> {
53+
let mut control_phase = block << 3;
54+
if is_write {
55+
control_phase |= WRITE_MODE_MASK;
56+
}
57+
58+
let mut data_phase = &mut data[..];
59+
let mut last_length_written: u16;
60+
while data_phase.len() > 0 {
61+
if data_phase.len() >= 4 {
62+
control_phase |= FIXED_DATA_LENGTH_MODE_4;
63+
last_length_written = 4;
64+
} else if data_phase.len() >= 2 {
65+
control_phase |= FIXED_DATA_LENGTH_MODE_2;
66+
last_length_written = 2;
67+
} else {
68+
control_phase |= FIXED_DATA_LENGTH_MODE_1;
69+
last_length_written = 1;
70+
}
71+
72+
let mut address_phase = [0u8; 2];
73+
BigEndian::write_u16(&mut address_phase, address);
74+
Self::transfer_bytes(&mut self.spi, &mut address_phase)
75+
.and_then(|_| Self::transfer_byte(&mut self.spi, &mut control_phase))
76+
.and_then(|_| Self::transfer_bytes(
77+
&mut self.spi,
78+
&mut data_phase[..last_length_written as usize]
79+
))?;
80+
81+
address += last_length_written;
82+
data_phase = &mut data_phase[last_length_written as usize..];
83+
}
84+
Ok(data_phase)
85+
}
86+
}
87+
88+
impl<Spi: FullDuplex<u8>> ActiveThreeWire<Spi> {
89+
pub fn deactivate(self) -> (ThreeWire, Spi) {
90+
(ThreeWire::new(), self.spi)
91+
}
92+
}

src/inactive_w5500.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use bus::{ActiveFourWire, ActiveThreeWire, Bus, FourWire, ThreeWire};
2+
use embedded_hal::digital::v2::OutputPin;
3+
use embedded_hal::spi::FullDuplex;
4+
use network::Network;
5+
use w5500::W5500;
6+
7+
pub struct InactiveW5500<SpiBus: Bus, NetworkImpl: Network> {
8+
bus: SpiBus,
9+
network: NetworkImpl,
10+
}
11+
12+
impl<SpiBus: Bus, NetworkImpl: Network> InactiveW5500<SpiBus, NetworkImpl> {
13+
pub fn new(bus: SpiBus, network: NetworkImpl) -> Self {
14+
Self { bus, network }
15+
}
16+
}
17+
18+
impl<ChipSelect: OutputPin, NetworkImpl: Network> InactiveW5500<FourWire<ChipSelect>, NetworkImpl> {
19+
pub fn activate<Spi: FullDuplex<u8>>(
20+
self,
21+
spi: Spi,
22+
) -> W5500<ActiveFourWire<Spi, ChipSelect>, NetworkImpl> {
23+
W5500::new(self.bus.activate(spi), self.network)
24+
}
25+
}
26+
27+
impl<NetworkImpl: Network> InactiveW5500<ThreeWire, NetworkImpl> {
28+
pub fn activate<Spi: FullDuplex<u8>>(
29+
self,
30+
spi: Spi,
31+
) -> W5500<ActiveThreeWire<Spi>, NetworkImpl> {
32+
W5500::new(self.bus.activate(spi), self.network)
33+
}
34+
}

0 commit comments

Comments
 (0)