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

/// SPI transfer
pub trait AsyncTransfer {
    /// Write error
    type Error;
    /// Write byte future for polling on completion
    type TransferFuture<'t>: 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>;
}

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

    /// 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<'t> = DefaultTransferFuture<'t, 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(()))
        }
    }
}