use crate::comm::Interface;
use crate::register::Register;
use embedded_hal::blocking::spi;
use embedded_hal::digital::v2::OutputPin;
use embedded_hal_02 as embedded_hal;
use heapless::Vec;
pub struct DummyNSS;
pub struct DummyDelay;
pub struct SpiInterface<SPI, NSS, D> {
spi: SPI,
nss: NSS,
delay: D,
}
#[derive(Debug, PartialEq)]
pub enum Error<E> {
Spi(E),
Gpio,
BufferTooLarge,
}
impl<E, SPI> SpiInterface<SPI, DummyNSS, DummyDelay>
where
SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
{
pub fn new(spi: SPI) -> Self {
Self {
spi,
nss: DummyNSS {},
delay: DummyDelay {},
}
}
}
impl<SPI, D> SpiInterface<SPI, DummyNSS, D> {
pub fn with_nss<NSS: OutputPin>(self, nss: NSS) -> SpiInterface<SPI, NSS, D> {
SpiInterface {
spi: self.spi,
nss,
delay: self.delay,
}
}
}
impl<SPI, NSS> SpiInterface<SPI, NSS, DummyDelay> {
pub fn with_delay<D: FnMut()>(self, delay: D) -> SpiInterface<SPI, NSS, D> {
SpiInterface {
spi: self.spi,
nss: self.nss,
delay,
}
}
}
impl<SPI, NSS, D> SpiInterface<SPI, NSS, D> {
pub fn release(self) -> (SPI, NSS) {
(self.spi, self.nss)
}
}
impl<E, SPI, NSS, D> Interface for SpiInterface<SPI, NSS, D>
where
SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
SpiInterface<SPI, NSS, D>: WrapTransfer<E>,
{
type Error = Error<E>;
fn read(&mut self, reg: Register) -> Result<u8, Self::Error> {
let mut buffer = [((reg as u8) << 1) | 0x80, 0];
self.wrap_transfer(|mfr| {
let buffer = mfr.spi.transfer(&mut buffer).map_err(Error::Spi)?;
Ok(buffer[1])
})
}
fn read_many<'b>(&mut self, reg: Register, buf: &'b mut [u8]) -> Result<&'b [u8], Self::Error> {
let mut vec = Vec::<u8, 65>::new();
let n = buf.len();
for _ in 0..n {
vec.push(((reg as u8) << 1) | 0x80)
.map_err(|_| Error::BufferTooLarge)?;
}
vec.push(0).map_err(|_| Error::BufferTooLarge)?;
self.wrap_transfer(move |mfr| {
let res = mfr.spi.transfer(vec.as_mut()).map_err(Error::Spi)?;
for (idx, slot) in res[1..].iter().enumerate() {
if idx >= n {
break;
}
buf[idx] = *slot;
}
Ok(&*buf)
})
}
fn write(&mut self, reg: Register, val: u8) -> Result<(), Self::Error> {
self.wrap_transfer(|mfr| mfr.spi.write(&[(reg as u8) << 1, val]).map_err(Error::Spi))
}
fn write_many(&mut self, reg: Register, bytes: &[u8]) -> Result<(), Self::Error> {
self.wrap_transfer(|mfr| {
let mut vec = Vec::<u8, 65>::new();
vec.push((reg as u8) << 1)
.map_err(|_| Error::BufferTooLarge)?;
vec.extend_from_slice(bytes)
.map_err(|_| Error::BufferTooLarge)?;
mfr.spi.write(vec.as_slice()).map_err(Error::Spi)?;
Ok(())
})
}
}
pub trait WrapTransfer<E> {
fn wrap_transfer<F, T>(&mut self, f: F) -> Result<T, Error<E>>
where
F: FnOnce(&mut Self) -> Result<T, Error<E>>;
}
#[doc(hidden)]
impl<E, SPI> WrapTransfer<E> for SpiInterface<SPI, DummyNSS, DummyDelay>
where
SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
{
fn wrap_transfer<F, T>(&mut self, f: F) -> Result<T, Error<E>>
where
F: FnOnce(&mut Self) -> Result<T, Error<E>>,
{
f(self)
}
}
#[doc(hidden)]
impl<E, SPI, D> WrapTransfer<E> for SpiInterface<SPI, DummyNSS, D>
where
SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
D: FnMut(),
{
fn wrap_transfer<F, T>(&mut self, f: F) -> Result<T, Error<E>>
where
F: FnOnce(&mut Self) -> Result<T, Error<E>>,
{
let result = f(self);
(self.delay)();
result
}
}
#[doc(hidden)]
impl<E, SPI, NSS> WrapTransfer<E> for SpiInterface<SPI, NSS, DummyDelay>
where
SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
NSS: OutputPin,
{
fn wrap_transfer<F, T>(&mut self, f: F) -> Result<T, Error<E>>
where
F: FnOnce(&mut Self) -> Result<T, Error<E>>,
{
self.nss.set_low().map_err(|_| Error::<E>::Gpio)?;
let result = f(self);
self.nss.set_high().map_err(|_| Error::<E>::Gpio)?;
result
}
}
#[doc(hidden)]
impl<E, SPI, NSS, D> WrapTransfer<E> for SpiInterface<SPI, NSS, D>
where
SPI: spi::Transfer<u8, Error = E> + spi::Write<u8, Error = E>,
NSS: OutputPin,
D: FnMut(),
{
fn wrap_transfer<F, T>(&mut self, f: F) -> Result<T, Error<E>>
where
F: FnOnce(&mut Self) -> Result<T, Error<E>>,
{
self.nss.set_low().map_err(|_| Error::<E>::Gpio)?;
let result = f(self);
self.nss.set_high().map_err(|_| Error::<E>::Gpio)?;
(self.delay)();
result
}
}
#[cfg(test)]
mod test {
use crate::comm::eh02::spi::SpiInterface;
use crate::comm::Interface;
use embedded_hal_mock::eh0::spi::{Mock as SpiMock, Transaction as SpiTransaction};
#[test]
pub fn test_read() {
let expectations = [SpiTransaction::transfer(
[0x96, 0x00].to_vec(),
[0x11, 0x37].to_vec(),
)];
let spi = SpiMock::new(&expectations);
let mut spi_clone = spi.clone();
assert_eq!(
SpiInterface::new(spi).read(crate::register::Register::WaterLevelReg),
Ok(0x37)
);
spi_clone.done();
}
#[test]
pub fn test_write() {
let expectations = [SpiTransaction::write([0x42, 0xfd].to_vec())];
let spi = SpiMock::new(&expectations);
let mut spi_clone = spi.clone();
SpiInterface::new(spi)
.write(crate::register::Register::CRCResultRegHigh, 0xfd)
.unwrap();
spi_clone.done();
}
#[test]
pub fn test_write_many() {
let expectations = [SpiTransaction::write(
[0x4E, 0xca, 0xfe, 0xf0, 0x0d].to_vec(),
)];
let spi = SpiMock::new(&expectations);
let mut spi_clone = spi.clone();
SpiInterface::new(spi)
.write_many(crate::register::Register::GsNReg, &[0xca, 0xfe, 0xf0, 0x0d])
.unwrap();
spi_clone.done();
}
#[test]
pub fn test_read_many_2() {
let expectations = [SpiTransaction::transfer(
[0xAA, 0xAA, 0x00].to_vec(),
[0x69, 0x12, 0x23].to_vec(),
)];
let spi = SpiMock::new(&expectations);
let mut spi_clone = spi.clone();
let mut buffer = [0u8; 2];
SpiInterface::new(spi)
.read_many(crate::register::Register::TxASKReg, &mut buffer)
.unwrap();
assert_eq!(buffer, [0x12, 0x23]);
spi_clone.done();
}
#[test]
pub fn test_read_many_3() {
let expectations = [SpiTransaction::transfer(
[0xAA, 0xAA, 0xAA, 0x00].to_vec(),
[0x69, 0x12, 0x23, 0x34].to_vec(),
)];
let spi = SpiMock::new(&expectations);
let mut spi_clone = spi.clone();
let mut buffer = [0u8; 3];
SpiInterface::new(spi)
.read_many(crate::register::Register::TxASKReg, &mut buffer)
.unwrap();
assert_eq!(buffer, [0x12, 0x23, 0x34]);
spi_clone.done();
}
}