use crate::urukul::Error; use crate::spi_slave::Parts; use embedded_hal::{ digital::v2::OutputPin, blocking::spi::Transfer, }; use core::cell; /* * Basic structure for CPLD signal multiplexing */ #[derive(Debug)] pub struct CPLDData { pub(crate) spi: SPI, pub(crate) chip_select: (CS0, CS1, CS2), pub(crate) io_update: GPIO, } #[derive(Debug)] pub struct CPLD { pub(crate) data: cell::RefCell>, } impl CPLDData where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, GPIO: OutputPin, { pub(crate) fn select_chip(&mut self, chip: u8) -> Result<(), Error> { match chip & (1 << 0) { 0 => self.chip_select.0.set_low(), _ => self.chip_select.0.set_high(), }.map_err(|_| Error::CSError)?; match chip & (1 << 1) { 0 => self.chip_select.1.set_low(), _ => self.chip_select.1.set_high(), }.map_err(|_| Error::CSError)?; match chip & (1 << 2) { 0 => self.chip_select.2.set_low(), _ => self.chip_select.2.set_high(), }.map_err(|_| Error::CSError)?; Ok(()) } pub(crate) fn issue_io_update(&mut self) -> Result<(), Error> { self.io_update.set_high().map_err(|_| Error::IOUpdateError)?; self.io_update.set_low().map_err(|_| Error::IOUpdateError) } } impl Transfer for CPLD where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, GPIO: OutputPin, { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { self.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?.spi.transfer(words).map_err(Error::SPI) } } impl CPLD where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, GPIO: OutputPin { // Constructor for CPLD pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2), io_update: GPIO) -> Self { // Init data let data = CPLDData { spi, chip_select, io_update, }; // Init CPLD CPLD { data: cell::RefCell::new(data), } } // Destroy the wrapper, return the CPLD data pub fn destroy(self) -> (SPI, (CS0, CS1, CS2), GPIO) { let cpld = self.data.into_inner(); (cpld.spi, cpld.chip_select, cpld.io_update) } // Split SPI into chips, wrapped by Parts struct pub fn split<'a>(&'a self) -> Parts<'a, SPI, CS0, CS1, CS2, GPIO> { Parts::new(&self) } }