From 8d33b56a917e9d932647db1d0823d06e14d92a2f Mon Sep 17 00:00:00 2001 From: Chris Moos Date: Tue, 4 Aug 2020 22:55:04 -0700 Subject: [PATCH 1/4] Add a ReadWriteInterface for displays. --- src/lib.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2f53a37..fc02633 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ pub enum DisplayError { InvalidFormatError, /// Unable to write to bus BusWriteError, + // Unable to read from bus + BusReadError, /// Unable to assert or de-assert data/command switching signal DCError, /// Unable to assert chip select signal @@ -57,3 +59,74 @@ pub trait WriteOnlyDataCommand { /// Send pixel data to display fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError>; } + +#[derive(Clone, Debug)] +pub enum WriteMode { + Data, + Command, +} + +pub trait ReadWriteInterface { + fn write(&mut self, mode: WriteMode, buf: &[DataFormat]) -> Result<(), DisplayError> { + self.write_iter(mode, &mut buf.into_iter()) + } + + fn read(&mut self, buf: &mut [DataFormat]) -> Result<(), DisplayError> { + let mut n = 0; + self.read_stream(&mut |b| { + if n == buf.len() { + return false; + } + buf[n] = b; + n += 1; + true + }) + } + + fn read_stream(&mut self, f: &mut dyn FnMut(DataFormat) -> bool) -> Result<(), DisplayError>; + + fn write_iter( + &mut self, + mode: WriteMode, + iter: &mut dyn Iterator, + ) -> Result<(), DisplayError>; +} + +pub struct ReadIterator<'a, DataFormat> { + rw: &'a mut dyn ReadWriteInterface, +} + +impl<'a, DataFormat> ReadIterator<'a, DataFormat> { + fn new(rw: &'a mut dyn ReadWriteInterface) -> ReadIterator<'a, DataFormat> { + ReadIterator { rw: rw } + } +} + +impl<'a, DataFormat> Iterator for ReadIterator<'a, DataFormat> +where + DataFormat: Default, +{ + type Item = Result; + fn next(&mut self) -> Option { + let mut next: DataFormat = Default::default(); + match self.rw.read_stream(&mut |b| { + next = b; + false + }) { + Ok(_) => Some(Ok(next)), + Err(e) => Some(Err(e)), + } + } +} + +impl<'a, DataFormat> IntoIterator for &'a mut dyn ReadWriteInterface +where + DataFormat: Default, +{ + type Item = Result; + type IntoIter = ReadIterator<'a, DataFormat>; + + fn into_iter(self) -> Self::IntoIter { + ReadIterator::new(self) + } +} From 5831269da25eacbdde3b49a3ecc3972b54f33dcd Mon Sep 17 00:00:00 2001 From: Chris Moos Date: Fri, 7 Aug 2020 15:47:43 -0700 Subject: [PATCH 2/4] Seperate read/write to separate traits. Move to `v2` module. --- src/lib.rs | 71 +----------------------------------------------- src/v2.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 70 deletions(-) create mode 100644 src/v2.rs diff --git a/src/lib.rs b/src/lib.rs index fc02633..616f0c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,73 +60,4 @@ pub trait WriteOnlyDataCommand { fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError>; } -#[derive(Clone, Debug)] -pub enum WriteMode { - Data, - Command, -} - -pub trait ReadWriteInterface { - fn write(&mut self, mode: WriteMode, buf: &[DataFormat]) -> Result<(), DisplayError> { - self.write_iter(mode, &mut buf.into_iter()) - } - - fn read(&mut self, buf: &mut [DataFormat]) -> Result<(), DisplayError> { - let mut n = 0; - self.read_stream(&mut |b| { - if n == buf.len() { - return false; - } - buf[n] = b; - n += 1; - true - }) - } - - fn read_stream(&mut self, f: &mut dyn FnMut(DataFormat) -> bool) -> Result<(), DisplayError>; - - fn write_iter( - &mut self, - mode: WriteMode, - iter: &mut dyn Iterator, - ) -> Result<(), DisplayError>; -} - -pub struct ReadIterator<'a, DataFormat> { - rw: &'a mut dyn ReadWriteInterface, -} - -impl<'a, DataFormat> ReadIterator<'a, DataFormat> { - fn new(rw: &'a mut dyn ReadWriteInterface) -> ReadIterator<'a, DataFormat> { - ReadIterator { rw: rw } - } -} - -impl<'a, DataFormat> Iterator for ReadIterator<'a, DataFormat> -where - DataFormat: Default, -{ - type Item = Result; - fn next(&mut self) -> Option { - let mut next: DataFormat = Default::default(); - match self.rw.read_stream(&mut |b| { - next = b; - false - }) { - Ok(_) => Some(Ok(next)), - Err(e) => Some(Err(e)), - } - } -} - -impl<'a, DataFormat> IntoIterator for &'a mut dyn ReadWriteInterface -where - DataFormat: Default, -{ - type Item = Result; - type IntoIter = ReadIterator<'a, DataFormat>; - - fn into_iter(self) -> Self::IntoIter { - ReadIterator::new(self) - } -} +pub mod v2; diff --git a/src/v2.rs b/src/v2.rs new file mode 100644 index 0000000..9004c4e --- /dev/null +++ b/src/v2.rs @@ -0,0 +1,79 @@ +use crate::DisplayError; + +#[derive(Clone, Debug)] +pub enum WriteMode { + Data, + Command, +} +pub trait WriteInterface { + fn write(&mut self, mode: WriteMode, buf: &[DataFormat]) -> Result<(), DisplayError> { + self.write_iter(mode, &mut buf.into_iter()) + } + + fn write_iter( + &mut self, + mode: WriteMode, + iter: &mut dyn Iterator, + ) -> Result<(), DisplayError>; +} + +pub trait ReadInterface { + fn read(&mut self, buf: &mut [DataFormat]) -> Result<(), DisplayError> { + let mut n = 0; + self.read_stream(&mut |b| { + if n == buf.len() { + return false; + } + buf[n] = b; + n += 1; + true + }) + } + + fn read_stream(&mut self, f: &mut dyn FnMut(DataFormat) -> bool) -> Result<(), DisplayError>; +} + +pub trait ReadWriteInterface: ReadInterface + WriteInterface {} +impl ReadWriteInterface for T where + T: ReadInterface + WriteInterface +{ +} + +pub struct ReadIterator<'a, DataFormat> { + reader: &'a mut dyn ReadInterface, +} + +impl<'a, DataFormat> ReadIterator<'a, DataFormat> { + fn new(reader: &'a mut dyn ReadInterface) -> ReadIterator<'a, DataFormat> { + ReadIterator { reader: reader } + } +} + +impl<'a, DataFormat> Iterator for ReadIterator<'a, DataFormat> +where + DataFormat: Default, +{ + type Item = Result; + fn next(&mut self) -> Option { + let mut next: DataFormat = Default::default(); + match self.reader.read_stream(&mut |b| { + next = b; + false + }) { + Ok(_) => Some(Ok(next)), + Err(e) => Some(Err(e)), + } + } +} + +impl<'a, DataFormat> IntoIterator for &'a mut dyn ReadInterface +where + DataFormat: Default, +{ + type Item = Result; + type IntoIter = ReadIterator<'a, DataFormat>; + + fn into_iter(self) -> Self::IntoIter { + ReadIterator::new(self) + } +} From 99205d188b7b833b334b70bc3af455810d0b8901 Mon Sep 17 00:00:00 2001 From: Chris Moos Date: Sat, 8 Aug 2020 23:05:46 -0700 Subject: [PATCH 3/4] Add `write_stream` method. After testing, a closure performs much better than an Iterator, probably due to dynamic dispatch. Iterator performance can be improved if we know the concrete type of the Iterator, but would require passing more types through the chain. --- src/v2.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/v2.rs b/src/v2.rs index 9004c4e..1a6eef8 100644 --- a/src/v2.rs +++ b/src/v2.rs @@ -5,6 +5,7 @@ pub enum WriteMode { Data, Command, } + pub trait WriteInterface { fn write(&mut self, mode: WriteMode, buf: &[DataFormat]) -> Result<(), DisplayError> { self.write_iter(mode, &mut buf.into_iter()) @@ -14,6 +15,14 @@ pub trait WriteInterface { &mut self, mode: WriteMode, iter: &mut dyn Iterator, + ) -> Result<(), DisplayError> { + self.write_stream(mode, &mut || iter.next()) + } + + fn write_stream<'a>( + &mut self, + mode: WriteMode, + func: &mut dyn FnMut() -> Option<&'a DataFormat>, ) -> Result<(), DisplayError>; } From f65344a3012d39febff5e9c07ac96dda61b4d541 Mon Sep 17 00:00:00 2001 From: Chris Moos Date: Sun, 9 Aug 2020 20:58:59 -0700 Subject: [PATCH 4/4] Add ReadInterface and WriteInterface support for SPI. --- spi/Cargo.toml | 2 +- spi/src/lib.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/spi/Cargo.toml b/spi/Cargo.toml index b6013af..b55ca54 100644 --- a/spi/Cargo.toml +++ b/spi/Cargo.toml @@ -19,5 +19,5 @@ all-features = true [dependencies] embedded-hal = "0.2.3" -display-interface = "0.4" +display-interface = { git = "https://github.com/chrismoos/display-interface", branch = "rw-interface"} byte-slice-cast = { version = "0.3.5", default-features = false } diff --git a/spi/src/lib.rs b/spi/src/lib.rs index 632ad25..2a35ae6 100644 --- a/spi/src/lib.rs +++ b/spi/src/lib.rs @@ -5,6 +5,7 @@ use embedded_hal as hal; use hal::digital::v2::OutputPin; +use display_interface::v2::{ReadInterface, WriteInterface, WriteMode}; use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; fn send_u8>( @@ -133,6 +134,95 @@ where } } +impl ReadInterface for SPIInterface +where + SPI: hal::spi::FullDuplex, + DC: OutputPin, + CS: OutputPin, +{ + fn read_stream(&mut self, f: &mut dyn FnMut(u8) -> bool) -> Result<(), DisplayError> { + // Assert chip select pin + self.cs.set_low().map_err(|_| DisplayError::CSError)?; + + // 1 = data for reads + self.dc.set_high().map_err(|_| DisplayError::DCError)?; + + loop { + let b = self.spi.read().map_err(|_| DisplayError::BusReadError)?; + if !f(b) { + break; + } + } + + // Deassert chip select pin + self.cs.set_high().map_err(|_| DisplayError::CSError) + } +} + +impl WriteInterface for SPIInterface +where + SPI: hal::blocking::spi::Write, + DC: OutputPin, + CS: OutputPin, +{ + fn write(&mut self, mode: WriteMode, buf: &[u8]) -> Result<(), DisplayError> { + // Assert chip select pin + self.cs.set_low().map_err(|_| DisplayError::CSError)?; + + // 1 = data, 0 = command + match mode { + WriteMode::Command => { + self.dc.set_low().map_err(|_| DisplayError::DCError)?; + } + WriteMode::Data => { + self.dc.set_high().map_err(|_| DisplayError::DCError)?; + } + } + + self.spi + .write(buf) + .map_err(|_| DisplayError::BusWriteError)?; + + // Deassert chip select pin + self.cs.set_high().map_err(|_| DisplayError::CSError) + } + + fn write_stream<'a>( + &mut self, + mode: WriteMode, + func: &mut dyn FnMut() -> Option<&'a u8>, + ) -> Result<(), DisplayError> { + // Assert chip select pin + self.cs.set_low().map_err(|_| DisplayError::CSError)?; + + // 1 = data, 0 = command + match mode { + WriteMode::Command => { + self.dc.set_low().map_err(|_| DisplayError::DCError)?; + } + WriteMode::Data => { + self.dc.set_high().map_err(|_| DisplayError::DCError)?; + } + } + + loop { + match func() { + Some(b) => { + self.spi + .write(&[*b]) + .map_err(|_| DisplayError::BusWriteError)?; + } + None => { + break; + } + } + } + + // Deassert chip select pin + self.cs.set_high().map_err(|_| DisplayError::CSError) + } +} + impl WriteOnlyDataCommand for SPIInterface where SPI: hal::blocking::spi::Write,