#![no_std] use stm32h7xx_hal::{ hal::{ digital::v2::{ InputPin, OutputPin, }, blocking::spi::Transfer, spi::FullDuplex, }, pac, prelude::*, spi, }; use core::cell; use cortex_m; use cortex_m::asm::nop; use cortex_m_semihosting::hprintln; use nb::block; pub mod spi_slave; use crate::spi_slave::{SPISlave, Parts}; /* * Enum for structuring error */ #[derive(Debug)] pub enum Error { SPI(E), CSError, GetRefMutDataError, } /* * Basic structure for CPLD signal multiplexing */ #[derive(Debug)] pub struct CPLDData { pub(crate) spi: SPI, pub(crate) chip_select: (CS0, CS1, CS2), } #[derive(Debug)] pub struct CPLD { pub(crate) data: cell::RefCell>, } pub trait SelectChip { type Error; fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error>; } impl SelectChip for CPLDData where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, { type Error = Error; fn select_chip(&mut self, chip: u8) -> Result<(), Self::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 trait DoOnGetRefMutData { fn do_on_get_ref_mut_data( &self, f: impl FnOnce(cell::RefMut>) -> Result>, ) -> Result>; } impl DoOnGetRefMutData for CPLD { fn do_on_get_ref_mut_data( &self, f: impl FnOnce(cell::RefMut>) -> Result>, ) -> Result> { let dev = self .data .try_borrow_mut() .map_err(|_| Error::GetRefMutDataError)?; f(dev) } } impl Transfer for CPLD where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { self.do_on_get_ref_mut_data(move |mut dev| dev.spi.transfer(words).map_err(Error::SPI)) } } impl CPLD where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, { // Constructor for CPLD pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2)) -> Self { // Init data let data = CPLDData { spi, chip_select, }; // Init CPLD CPLD { data: cell::RefCell::new(data), } } // Destroy the wrapper, return the CPLD data pub fn destroy(self) -> (SPI, (CS0, CS1, CS2)) { let cpld = self.data.into_inner(); (cpld.spi, cpld.chip_select) } // Split SPI into chips, wrapped by Parts struct pub fn split<'a>(&'a self) -> Parts<'a, CPLD, SPI, CS0, CS1, CS2> { Parts::new(&self) } // Select Chip pub fn select_chip(&mut self, channel: u8) -> Result<(), Error> { self.do_on_get_ref_mut_data(|mut dev| dev.select_chip(channel)) } }