aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-esp-hosted/src/iface.rs
blob: 1f57851e053fef816bc8465006cef5a4b1718ebc (plain)
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
use embassy_time::Timer;
use embedded_hal::digital::InputPin;
use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::SpiDevice;

/// Physical interface trait for communicating with the ESP chip.
pub trait Interface {
    /// Wait for the HANDSHAKE signal indicating the ESP is ready for a new transaction.
    async fn wait_for_handshake(&mut self);

    /// Wait for the READY signal indicating the ESP has data to send.
    async fn wait_for_ready(&mut self);

    /// Perform a SPI transfer, exchanging data with the ESP chip.
    async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]);
}

/// Standard SPI interface.
///
/// This interface is what's implemented in the upstream `esp-hosted-fg` firmware. It uses:
/// - An `SpiDevice` for SPI communication (CS is handled by the device)
/// - A handshake pin that signals when the ESP is ready for a new transaction
/// - A ready pin that indicates when the ESP has data to send
pub struct SpiInterface<SPI, IN> {
    spi: SPI,
    handshake: IN,
    ready: IN,
}

impl<SPI, IN> SpiInterface<SPI, IN>
where
    SPI: SpiDevice,
    IN: InputPin + Wait,
{
    /// Create a new SpiInterface.
    pub fn new(spi: SPI, handshake: IN, ready: IN) -> Self {
        Self { spi, handshake, ready }
    }
}

impl<SPI, IN> Interface for SpiInterface<SPI, IN>
where
    SPI: SpiDevice,
    IN: InputPin + Wait,
{
    async fn wait_for_handshake(&mut self) {
        self.handshake.wait_for_high().await.unwrap();
    }

    async fn wait_for_ready(&mut self) {
        self.ready.wait_for_high().await.unwrap();
    }

    async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) {
        self.spi.transfer(rx, tx).await.unwrap();

        // The esp-hosted firmware deasserts the HANDSHAKE pin a few us AFTER ending the SPI transfer
        // If we check it again too fast, we'll see it's high from the previous transfer, and if we send it
        // data it will get lost.
        Timer::after_micros(100).await;
    }
}