diff --git a/firmware/src/board/softspi.rs b/firmware/src/board/softspi.rs index 8d8e31a..69d3d4c 100644 --- a/firmware/src/board/softspi.rs +++ b/firmware/src/board/softspi.rs @@ -1,5 +1,7 @@ use embedded_hal::spi::FullDuplex; use embedded_hal::digital::v2::{InputPin, OutputPin}; +use embedded_hal::blocking::spi::Transfer; +use embedded_hal::blocking::delay::DelayUs; use nb::Error::WouldBlock; /// Bit-banged SPI @@ -71,6 +73,13 @@ impl SoftSpi { } } } + + pub fn run(&mut self, delay: &'_ F) { + while self.state != State::Idle { + self.tick(); + delay(); + } + } } impl FullDuplex for SoftSpi { @@ -102,3 +111,34 @@ impl FullDuplex for SoftSpi } } } + +pub struct SyncSoftSpi<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: Fn()> { + spi: SoftSpi, + delay: &'d D, +} + +impl<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: Fn()> SyncSoftSpi<'d, SCK, MOSI, MISO, D> { + fn retry(&mut self, f: &F) -> Result + where + F: Fn(&'_ mut SoftSpi) -> Result> + { + loop { + match f(&mut self.spi) { + Ok(r) => return Ok(r), + Err(nb::Error::Other(e)) => return Err(e), + Err(WouldBlock) => self.spi.run(self.delay), + } + } + } +} + +impl<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: Fn()> Transfer for SyncSoftSpi<'d, SCK, MOSI, MISO, D> { + type Error = (); + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + for b in words.iter_mut() { + self.retry(&|spi| spi.send(*b))?; + *b = self.retry(&|spi| spi.read())?; + } + Ok(words) + } +}