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
use core::future::Future;

/// SPI transfer
pub trait AsyncTransfer {
    /// Transfer error
    type Error;
    /// Transfer future for polling on completion
    type TransferFuture<'f>: Future<Output = Result<(), Self::Error>>;

    /// Sends bytes to the slave. Returns the bytes received from the slave
    fn async_transfer<'a>(&'a mut self, data: &'a mut [u8]) -> Self::TransferFuture<'a>;
}

/// SPI write
pub trait AsyncWrite {
    /// Write error
    type Error;
    /// Write future for polling on completion
    type WriteFuture<'f>: Future<Output = Result<(), Self::Error>>;

    /// Sends bytes to the slave, ignoring all the incoming bytes
    fn async_write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'_>;
}

/// SPI write (iterator version)
pub trait AsyncWriteIter {
    /// Write error
    type Error;
    /// Write future for polling on completion
    type WriteIterFuture<'f>: Future<Output = Result<(), Self::Error>>;

    /// Sends bytes to the slave, ignoring all the incoming bytes
    fn async_write_iter<'a>(
        &'a mut self,
        data: &'a mut dyn Iterator<Item = u8>,
    ) -> Self::WriteIterFuture<'_>;
}

pub mod transfer {
    use super::AsyncTransfer;
    use core::future::Future;
    use core::pin::Pin;
    use core::task::{Context, Poll};

    /// Marker trait to opt into default async transfer implementation
    ///
    /// Implementers of `embedded-hal::spi::FullDuplex<u8>` can implement this marker trait
    /// for their type. Doing so will automatically provide the default
    /// implementation of [`spi::AsyncTransfer`] for the type.
    ///
    /// [`spi::AsyncTransfer`]: ../trait.AsyncTransfer.html
    pub trait Default: embedded_hal::spi::FullDuplex<u8> {}

    impl<S: Default + 'static> AsyncTransfer for S {
        type Error = S::Error;
        type TransferFuture<'f> = DefaultTransferFuture<'f, S>;

        fn async_transfer<'a>(&'a mut self, data: &'a mut [u8]) -> Self::TransferFuture<'a> {
            DefaultTransferFuture {
                spi: self,
                data,
                offset: 0,
                state: State::Sending,
            }
        }
    }

    enum State {
        Sending,
        Receiving,
    }

    pub struct DefaultTransferFuture<'a, S> {
        spi: &'a mut S,
        data: &'a mut [u8],
        offset: usize,
        state: State,
    }

    impl<'a, S: Default> Future for DefaultTransferFuture<'a, S> {
        type Output = Result<(), S::Error>;

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            while self.offset < self.data.len() {
                match self.state {
                    State::Sending => {
                        let byte = self.data[self.offset];
                        match self.spi.send(byte) {
                            Ok(()) => {
                                self.state = State::Receiving;
                                continue;
                            }
                            Err(nb::Error::Other(e)) => {
                                return Poll::Ready(Err(e));
                            }
                            Err(nb::Error::WouldBlock) => {
                                cx.waker().wake_by_ref();
                                return Poll::Pending;
                            }
                        }
                    }
                    State::Receiving => match self.spi.read() {
                        Ok(byte) => {
                            let offset = self.offset;
                            self.data[offset] = byte;
                            self.offset += 1;
                            self.state = State::Sending;
                            continue;
                        }
                        Err(nb::Error::Other(e)) => {
                            return Poll::Ready(Err(e));
                        }
                        Err(nb::Error::WouldBlock) => {
                            cx.waker().wake_by_ref();
                            return Poll::Pending;
                        }
                    },
                }
            }
            Poll::Ready(Ok(()))
        }
    }
}