use crate::{FtInner, PinUse};
use embedded_hal::spi::Polarity;
use libftd2xx::{ClockData, ClockDataOut, FtdiCommon, MpsseCmdBuilder, TimeoutError};
use std::{cell::RefCell, sync::Mutex};
#[derive(Debug)]
pub struct Spi<'a, Device> {
mtx: &'a Mutex<RefCell<FtInner<Device>>>,
clk: ClockData,
clk_out: ClockDataOut,
}
impl<'a, Device: FtdiCommon> Spi<'a, Device> {
pub(crate) fn new(mtx: &Mutex<RefCell<FtInner<Device>>>) -> Result<Spi<Device>, TimeoutError> {
let lock = mtx.lock().expect("Failed to aquire FTDI mutex");
let mut inner = lock.borrow_mut();
inner.allocate_pin(0, PinUse::Spi);
inner.allocate_pin(1, PinUse::Spi);
inner.allocate_pin(2, PinUse::Spi);
inner.direction &= !0x07;
inner.direction |= 0x03;
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(inner.value, inner.direction)
.send_immediate();
inner.ft.write_all(cmd.as_slice())?;
Ok(Spi {
mtx,
clk: ClockData::MsbPosIn,
clk_out: ClockDataOut::MsbNeg,
})
}
pub fn set_clock_polarity(&mut self, cpol: Polarity) {
let (clk, clk_out) = match cpol {
Polarity::IdleLow => (ClockData::MsbPosIn, ClockDataOut::MsbNeg),
Polarity::IdleHigh => (ClockData::MsbNegIn, ClockDataOut::MsbPos),
};
self.clk = clk;
self.clk_out = clk_out
}
}
impl<'a, Device: FtdiCommon> embedded_hal::blocking::spi::Write<u8> for Spi<'a, Device> {
type Error = TimeoutError;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.clock_data_out(self.clk_out, words)
.send_immediate();
let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");
let mut inner = lock.borrow_mut();
inner.ft.write_all(cmd.as_slice())
}
}
impl<'a, Device: FtdiCommon> embedded_hal::blocking::spi::Transfer<u8> for Spi<'a, Device> {
type Error = TimeoutError;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.clock_data(self.clk, words)
.send_immediate();
let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");
let mut inner = lock.borrow_mut();
inner.ft.write_all(cmd.as_slice())?;
inner.ft.read_all(words)?;
Ok(words)
}
}
impl<'a, Device: FtdiCommon> embedded_hal::spi::FullDuplex<u8> for Spi<'a, Device> {
type Error = TimeoutError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let mut buf: [u8; 1] = [0];
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.clock_data(self.clk, &buf)
.send_immediate();
let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");
let mut inner = lock.borrow_mut();
inner.ft.write_all(cmd.as_slice())?;
inner.ft.read_all(&mut buf)?;
Ok(buf[0])
}
fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.clock_data_out(self.clk_out, &[byte])
.send_immediate();
let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");
let mut inner = lock.borrow_mut();
inner.ft.write_all(cmd.as_slice())?;
Ok(())
}
}