diff --git a/CHANGELOG.md b/CHANGELOG.md index b120bfd..f4d15ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - Added re-exports for `libftd2xx` and `ftdi` when the respective feature is used. +- Added `embedded-hal` version `1.0.0-alpha.8` trait implementations for: + - GPIOs + - Delay + - SPI + +### Changed +- Changed the `embedded-hal` version `0.2` re-export name from `embedded-hal` to + `eh0` to differentiate from `embedded-hal` version `1.0.0-alpha.8`. ## [0.11.0] - 2022-01-18 ### Added diff --git a/Cargo.toml b/Cargo.toml index c6336b2..81cb4bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,17 +16,19 @@ libftd2xx-static = ["libftd2xx/static"] default = [] [dependencies] -nb = "^1" -embedded-hal = { version = "~0.2.4", features = ["unproven"] } -ftdi-mpsse = "^0.1" -libftd2xx = { version = "0.32.0", optional = true } +eh0 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] } +eh1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } ftdi = { version = "0.1.3", optional = true } +ftdi-mpsse = "0.1" +libftd2xx = { version = "0.32", optional = true } +nb = "1" [dev-dependencies] -version-sync = "~0.9.2" -spi-memory = "0.2.0" +cfg-if = "1" eeprom24x = "0.5.0" lm75 = "0.2.0" +spi-memory = "0.2.0" +version-sync = "0.9.2" [badges] maintenance = { status = "experimental" } diff --git a/examples/at24c04.rs b/examples/at24c04.rs index 3ad79be..7807588 100644 --- a/examples/at24c04.rs +++ b/examples/at24c04.rs @@ -4,21 +4,19 @@ use ftdi_embedded_hal as hal; use std::thread::sleep; use std::time::Duration; -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); - fn main() { - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6014) - .interface(ftdi::Interface::A) - .open() - .unwrap(); - - #[cfg(feature = "libftd2xx")] - let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6014) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + } else if #[cfg(feature = "libftd2xx")] { + let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_freq(device, 400_000).unwrap(); let i2c = hal.i2c().unwrap(); diff --git a/examples/blink.rs b/examples/blink.rs index 364071c..6cade54 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -1,25 +1,23 @@ -use embedded_hal::digital::v2::OutputPin; +use eh0::digital::v2::OutputPin; use ftdi_embedded_hal as hal; use std::{thread::sleep, time::Duration}; const NUM_BLINK: usize = 10; const SLEEP_DURATION: Duration = Duration::from_millis(500); -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); - fn main() { - #[cfg(feature = "libftd2xx")] - let device: libftd2xx::Ft232h = libftd2xx::Ftdi::new().unwrap().try_into().unwrap(); - - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6014) - .interface(ftdi::Interface::A) - .open() - .unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6014) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + } else if #[cfg(feature = "libftd2xx")] { + let device: libftd2xx::Ft232h = libftd2xx::Ftdi::new().unwrap().try_into().unwrap(); + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_default(device).unwrap(); let mut output_pin = hal.ad3().unwrap(); diff --git a/examples/bme280.rs b/examples/bme280.rs index 642ea3d..f016324 100644 --- a/examples/bme280.rs +++ b/examples/bme280.rs @@ -7,24 +7,22 @@ //! * https://www.adafruit.com/product/4399 //! * https://www.adafruit.com/product/4472 -use embedded_hal::prelude::*; +use eh0::prelude::*; use ftdi_embedded_hal as hal; -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); - fn main() { - #[cfg(feature = "libftd2xx")] - let device: libftd2xx::Ft232h = libftd2xx::Ftdi::new().unwrap().try_into().unwrap(); - - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6014) - .interface(ftdi::Interface::A) - .open() - .unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6014) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + } else if #[cfg(feature = "libftd2xx")] { + let device: libftd2xx::Ft232h = libftd2xx::Ftdi::new().unwrap().try_into().unwrap(); + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_default(device).unwrap(); let mut i2c = hal.i2c().unwrap(); diff --git a/examples/input.rs b/examples/input.rs index 9102092..329288a 100644 --- a/examples/input.rs +++ b/examples/input.rs @@ -1,24 +1,22 @@ -use embedded_hal::digital::v2::InputPin; +use eh0::digital::v2::InputPin; use ftdi_embedded_hal as hal; use std::{thread::sleep, time::Duration}; const SLEEP_DURATION: Duration = Duration::from_millis(500); -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); - fn main() { - #[cfg(feature = "libftd2xx")] - let device: libftd2xx::Ft232h = libftd2xx::Ftdi::new().unwrap().try_into().unwrap(); - - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6014) - .interface(ftdi::Interface::A) - .open() - .unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6014) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + } else if #[cfg(feature = "libftd2xx")] { + let device: libftd2xx::Ft232h = libftd2xx::Ftdi::new().unwrap().try_into().unwrap(); + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_default(device).unwrap(); diff --git a/examples/lm75.rs b/examples/lm75.rs index 8278e93..16b2247 100644 --- a/examples/lm75.rs +++ b/examples/lm75.rs @@ -3,21 +3,19 @@ use lm75::{Address, Lm75}; use std::thread::sleep; use std::time::Duration; -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); - fn main() { - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6014) - .interface(ftdi::Interface::A) - .open() - .unwrap(); - - #[cfg(feature = "libftd2xx")] - let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6014) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + } else if #[cfg(feature = "libftd2xx")] { + let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_freq(device, 400_000).unwrap(); let i2c = hal.i2c().unwrap(); diff --git a/examples/spi-flash.rs b/examples/spi-flash.rs index d9174ef..70e135b 100644 --- a/examples/spi-flash.rs +++ b/examples/spi-flash.rs @@ -4,23 +4,23 @@ use spi_memory::series25::Flash; use std::thread::sleep; use std::time::Duration; -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); - const LINE: u32 = 0x10; fn main() { - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6014) - .interface(ftdi::Interface::A) - .open() - .unwrap(); - - #[cfg(feature = "libftd2xx")] - let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6014) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + let data: [u8; 8] = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; + } else if #[cfg(feature = "libftd2xx")] { + let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + let data: [u8; 8] = [0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70]; + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_freq(device, 1_000_000).unwrap(); let spi = hal.spi().unwrap(); @@ -31,11 +31,6 @@ fn main() { let id = flash.read_jedec_id().unwrap(); println!("JEDEC ID: {:?}", id); - #[cfg(feature = "libftd2xx")] - let data: [u8; 8] = [0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70]; - #[cfg(feature = "ftdi")] - let data: [u8; 8] = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]; - let addrs: [u32; 5] = [0, LINE, 2 * LINE, 3 * LINE, 4 * LINE]; let zero: [u8; 8] = [0; 8]; let mut bytes_w: [u8; 8] = [0; 8]; diff --git a/examples/ws2812.rs b/examples/ws2812.rs index 97e1afb..5b46021 100644 --- a/examples/ws2812.rs +++ b/examples/ws2812.rs @@ -1,23 +1,21 @@ -use embedded_hal::blocking::spi::Write; +use eh0::blocking::spi::Write; use ftdi_embedded_hal as hal; use std::thread::sleep; use std::time::Duration; -#[cfg(all(feature = "ftdi", feature = "libftd2xx"))] -compile_error!("features 'ftdi' and 'libftd2xx' cannot be enabled at the same time"); - -#[cfg(not(any(feature = "ftdi", feature = "libftd2xx")))] -compile_error!("one of features 'ftdi' and 'libftdi2xx' shall be enabled"); - fn main() { - #[cfg(feature = "libftd2xx")] - let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A").unwrap(); - - #[cfg(feature = "ftdi")] - let device = ftdi::find_by_vid_pid(0x0403, 0x6010) - .interface(ftdi::Interface::A) - .open() - .unwrap(); + cfg_if::cfg_if! { + if #[cfg(feature = "ftdi")] { + let device = ftdi::find_by_vid_pid(0x0403, 0x6010) + .interface(ftdi::Interface::A) + .open() + .unwrap(); + } else if #[cfg(feature = "libftd2xx")] { + let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A").unwrap(); + } else { + compile_error!("one of features 'ftdi' and 'libftd2xx' shall be enabled"); + } + } let hal = hal::FtHal::init_freq(device, 3_000_000).unwrap(); let mut spi = hal.spi().unwrap(); diff --git a/src/delay.rs b/src/delay.rs index 23f579b..9ec37f0 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,4 +1,5 @@ -//! Implementation of the [`embedded_hal::blocking::delay`] traits. +//! Implementation of the [`eh0::blocking::delay`] and [`eh1::delay::blocking`] +//! traits. /// Delay structure. /// @@ -31,15 +32,29 @@ impl Default for Delay { } } -macro_rules! impl_delay_for { +impl eh1::delay::blocking::DelayUs for Delay { + type Error = std::convert::Infallible; + + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + std::thread::sleep(std::time::Duration::from_micros(us.into())); + Ok(()) + } + + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + std::thread::sleep(std::time::Duration::from_millis(ms.into())); + Ok(()) + } +} + +macro_rules! impl_eh0_delay_for { ($UXX:ty) => { - impl embedded_hal::blocking::delay::DelayMs<$UXX> for Delay { + impl eh0::blocking::delay::DelayMs<$UXX> for Delay { fn delay_ms(&mut self, ms: $UXX) { std::thread::sleep(std::time::Duration::from_millis(ms.into())) } } - impl embedded_hal::blocking::delay::DelayUs<$UXX> for Delay { + impl eh0::blocking::delay::DelayUs<$UXX> for Delay { fn delay_us(&mut self, us: $UXX) { std::thread::sleep(std::time::Duration::from_micros(us.into())) } @@ -47,7 +62,7 @@ macro_rules! impl_delay_for { }; } -impl_delay_for!(u8); -impl_delay_for!(u16); -impl_delay_for!(u32); -impl_delay_for!(u64); +impl_eh0_delay_for!(u8); +impl_eh0_delay_for!(u16); +impl_eh0_delay_for!(u32); +impl_eh0_delay_for!(u64); diff --git a/src/gpio.rs b/src/gpio.rs index c3142de..398348f 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,8 +1,7 @@ use crate::error::Error; use crate::{FtInner, PinUse}; use ftdi_mpsse::{MpsseCmdBuilder, MpsseCmdExecutor}; -use std::result::Result; -use std::{cell::RefCell, sync::Mutex}; +use std::sync::{Arc, Mutex}; /// FTDI output pin. /// @@ -13,7 +12,7 @@ use std::{cell::RefCell, sync::Mutex}; #[derive(Debug)] pub struct OutputPin<'a, Device: MpsseCmdExecutor> { /// Parent FTDI device. - mtx: &'a Mutex>>, + mtx: &'a Arc>>, /// GPIO pin index. 0-7 for the FT232H. idx: u8, } @@ -25,34 +24,33 @@ where Error: From, { pub(crate) fn new( - mtx: &'a Mutex>>, + mtx: &'a Arc>>, idx: u8, ) -> Result, Error> { - let lock = mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); - inner.direction |= 1 << idx; - inner.allocate_pin(idx, PinUse::Output); + let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex"); + + lock.direction |= 1 << idx; + lock.allocate_pin(idx, PinUse::Output); let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(cmd.as_slice())?; + lock.ft.send(cmd.as_slice())?; Ok(OutputPin { mtx, idx }) } pub(crate) fn set(&self, state: bool) -> Result<(), Error> { - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); if state { - inner.value |= self.mask(); + lock.value |= self.mask(); } else { - inner.value &= !self.mask(); + lock.value &= !self.mask(); }; let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(cmd.as_slice())?; + lock.ft.send(cmd.as_slice())?; Ok(()) } @@ -65,7 +63,31 @@ impl<'a, Device: MpsseCmdExecutor> OutputPin<'a, Device> { } } -impl<'a, Device, E> embedded_hal::digital::v2::OutputPin for OutputPin<'a, Device> +impl<'a, Device, E> eh1::digital::ErrorType for OutputPin<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + type Error = Error; +} + +impl<'a, Device, E> eh1::digital::blocking::OutputPin for OutputPin<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn set_low(&mut self) -> Result<(), Error> { + self.set(false) + } + + fn set_high(&mut self) -> Result<(), Error> { + self.set(true) + } +} + +impl<'a, Device, E> eh0::digital::v2::OutputPin for OutputPin<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, @@ -91,7 +113,7 @@ where #[derive(Debug)] pub struct InputPin<'a, Device: MpsseCmdExecutor> { /// Parent FTDI device. - mtx: &'a Mutex>>, + mtx: &'a Arc>>, /// GPIO pin index. 0-7 for the FT232H. idx: u8, } @@ -103,28 +125,27 @@ where Error: From, { pub(crate) fn new( - mtx: &'a Mutex>>, + mtx: &'a Arc>>, idx: u8, ) -> Result, Error> { - let lock = mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); - inner.direction &= !(1 << idx); - inner.allocate_pin(idx, PinUse::Input); + let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex"); + + lock.direction &= !(1 << idx); + lock.allocate_pin(idx, PinUse::Input); let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(cmd.as_slice())?; + lock.ft.send(cmd.as_slice())?; Ok(InputPin { mtx, idx }) } pub(crate) fn get(&self) -> Result> { - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); let mut buffer = [0u8; 1]; let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new().gpio_lower().send_immediate(); - inner.ft.send(cmd.as_slice())?; - inner.ft.recv(&mut buffer)?; + lock.ft.send(cmd.as_slice())?; + lock.ft.recv(&mut buffer)?; Ok((buffer[0] & self.mask()) != 0) } @@ -137,7 +158,31 @@ impl<'a, Device: MpsseCmdExecutor> InputPin<'a, Device> { } } -impl<'a, Device, E> embedded_hal::digital::v2::InputPin for InputPin<'a, Device> +impl<'a, Device, E> eh1::digital::ErrorType for InputPin<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + type Error = Error; +} + +impl<'a, Device, E> eh1::digital::blocking::InputPin for InputPin<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn is_high(&self) -> Result { + self.get() + } + + fn is_low(&self) -> Result { + self.get().map(|res| !res) + } +} + +impl<'a, Device, E> eh0::digital::v2::InputPin for InputPin<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, diff --git a/src/i2c.rs b/src/i2c.rs index 9653c68..6c28cb6 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -2,8 +2,7 @@ use crate::error::Error; use crate::error::ErrorKind::I2cNoAck; use crate::{FtInner, PinUse}; use ftdi_mpsse::{ClockBitsIn, ClockBitsOut, MpsseCmdBuilder, MpsseCmdExecutor}; -use std::result::Result; -use std::{cell::RefCell, sync::Mutex}; +use std::sync::{Arc, Mutex}; /// SCL bitmask const SCL: u8 = 1 << 0; @@ -21,7 +20,7 @@ const BITS_OUT: ClockBitsOut = ClockBitsOut::MsbNeg; #[derive(Debug)] pub struct I2c<'a, Device: MpsseCmdExecutor> { /// Parent FTDI device. - mtx: &'a Mutex>>, + mtx: &'a Arc>>, /// Length of the start, repeated start, and stop conditions. /// /// The units for these are dimensionless number of MPSSE commands. @@ -37,17 +36,17 @@ where E: std::error::Error, Error: From, { - pub(crate) fn new(mtx: &Mutex>>) -> Result, Error> { - let lock = mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); - inner.allocate_pin(0, PinUse::I2c); - inner.allocate_pin(1, PinUse::I2c); - inner.allocate_pin(2, PinUse::I2c); + pub(crate) fn new(mtx: &Arc>>) -> Result, Error> { + let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex"); + + lock.allocate_pin(0, PinUse::I2c); + lock.allocate_pin(1, PinUse::I2c); + lock.allocate_pin(2, PinUse::I2c); // clear direction and value of first 3 pins - inner.direction &= !0x07; - inner.value &= !0x07; + lock.direction &= !0x07; + lock.value &= !0x07; // AD0: SCL // AD1: SDA (master out) // AD2: SDA (master in) @@ -55,10 +54,10 @@ where // set GPIO pins to new state let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .enable_3phase_data_clocking() .send_immediate(); - inner.ft.send(cmd.as_slice())?; + lock.ft.send(cmd.as_slice())?; Ok(I2c { mtx, @@ -127,66 +126,63 @@ where fn read_fast(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { assert!(!buffer.is_empty(), "buffer must be a non-empty slice"); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); // ST let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD+R - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, (address << 1) | 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); for idx in 0..buffer.len() { // Bn mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 8); if idx == buffer.len() - 1 { // NMAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x80, 1) } else { // MAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x00, 1) } } // SP for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // Idle - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; - inner.ft.recv(buffer)?; + lock.ft.recv(&mut ack_buf)?; + lock.ft.recv(buffer)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); @@ -198,31 +194,29 @@ where fn read_slow(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { assert!(!buffer.is_empty(), "buffer must be a non-empty slice"); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); // ST let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD+R - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, (address << 1) | 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; + lock.ft.recv(&mut ack_buf)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); } @@ -231,40 +225,39 @@ where for idx in 0..buffer.len() { // Bn mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 8); if idx == buffer.len() - 1 { // NMAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x80, 1) } else { // MAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x00, 1) } } // SP for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // Idle - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; - inner.ft.recv(buffer)?; + lock.ft.send(mpsse_cmd.as_slice())?; + lock.ft.recv(buffer)?; Ok(()) } @@ -272,57 +265,55 @@ where fn write_fast(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { assert!(!bytes.is_empty(), "bytes must be a non-empty slice"); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); // ST for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD+W - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, addr << 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); for byte in bytes.iter() { mpsse_cmd = mpsse_cmd // Bi - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, *byte, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); } // SP for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // Idle - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: Vec = vec![0; 1 + bytes.len()]; - inner.ft.recv(ack_buf.as_mut_slice())?; + lock.ft.recv(ack_buf.as_mut_slice())?; if ack_buf.iter().any(|&ack| (ack & 0b1) != 0x00) { Err(Error::Hal(I2cNoAck)) } else { @@ -333,31 +324,29 @@ where fn write_slow(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { assert!(!bytes.is_empty(), "bytes must be a non-empty slice"); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); // ST let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(SCL | SDA | inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(SCL | SDA | lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(SCL | inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(SCL | lock.value, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD+W - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, addr << 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; + lock.ft.recv(&mut ack_buf)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); } @@ -365,36 +354,36 @@ where for (idx, byte) in bytes.iter().enumerate() { let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() // Bi - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, *byte, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); // last byte if idx == bytes.len() - 1 { // SP for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = + mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } // Idle - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, lock.direction) } mpsse_cmd = mpsse_cmd.send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; + lock.ft.recv(&mut ack_buf)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); } @@ -414,95 +403,91 @@ where // lock at the start to prevent GPIO from being modified while we build // the MPSSE command - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); // ST for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD + W - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, address << 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); for byte in bytes { mpsse_cmd = mpsse_cmd // Oi - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, *byte, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); } // SR for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD + R .clock_bits_out(BITS_OUT, (address << 1) | 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1); for idx in 0..buffer.len() { mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 8); if idx == buffer.len() - 1 { // NMAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x80, 1) } else { // MAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x00, 1) } } // SP for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // Idle - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: Vec = vec![0; 2 + bytes.len()]; - inner.ft.recv(&mut ack_buf)?; - inner.ft.recv(buffer)?; + lock.ft.recv(&mut ack_buf)?; + lock.ft.recv(buffer)?; if ack_buf.iter().any(|&ack| (ack & 0b1) != 0x00) { Err(Error::Hal(I2cNoAck)) @@ -522,31 +507,29 @@ where // lock at the start to prevent GPIO from being modified while we build // the MPSSE command - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); // ST let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD + W - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, address << 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; + lock.ft.recv(&mut ack_buf)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); } @@ -554,16 +537,16 @@ where for byte in bytes { let mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() // Oi - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, *byte, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; + lock.ft.recv(&mut ack_buf)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); } @@ -572,27 +555,26 @@ where // SR let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // SAD + R .clock_bits_out(BITS_OUT, (address << 1) | 1, 8) // SAK - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 1) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; + lock.ft.send(mpsse_cmd.as_slice())?; let mut ack_buf: [u8; 1] = [0; 1]; - inner.ft.recv(&mut ack_buf)?; + lock.ft.recv(&mut ack_buf)?; if (ack_buf[0] & 0b1) != 0x00 { return Err(Error::Hal(I2cNoAck)); } @@ -600,46 +582,45 @@ where let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new(); for idx in 0..buffer.len() { mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | inner.direction) + .set_gpio_lower(lock.value, SCL | lock.direction) .clock_bits_in(BITS_IN, 8); if idx == buffer.len() - 1 { // NMAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x80, 1) } else { // MAK mpsse_cmd = mpsse_cmd - .set_gpio_lower(inner.value, SCL | SDA | inner.direction) + .set_gpio_lower(lock.value, SCL | SDA | lock.direction) .clock_bits_out(BITS_OUT, 0x00, 1) } } // SP for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL, SCL | SDA | lock.direction) } for _ in 0..self.start_stop_cmds { - mpsse_cmd = - mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction) + mpsse_cmd = mpsse_cmd.set_gpio_lower(lock.value | SCL | SDA, SCL | SDA | lock.direction) } mpsse_cmd = mpsse_cmd // Idle - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(mpsse_cmd.as_slice())?; - inner.ft.recv(buffer)?; + lock.ft.send(mpsse_cmd.as_slice())?; + lock.ft.recv(buffer)?; Ok(()) } } -impl<'a, Device, E> embedded_hal::blocking::i2c::Read for I2c<'a, Device> +impl<'a, Device, E> eh0::blocking::i2c::Read for I2c<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, @@ -656,7 +637,7 @@ where } } -impl<'a, Device, E> embedded_hal::blocking::i2c::Write for I2c<'a, Device> +impl<'a, Device, E> eh0::blocking::i2c::Write for I2c<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, @@ -673,7 +654,7 @@ where } } -impl<'a, Device, E> embedded_hal::blocking::i2c::WriteRead for I2c<'a, Device> +impl<'a, Device, E> eh0::blocking::i2c::WriteRead for I2c<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, diff --git a/src/lib.rs b/src/lib.rs index d163beb..ca5e91a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,7 +142,8 @@ #![forbid(missing_docs)] #![forbid(unsafe_code)] -pub use embedded_hal; +pub use eh0; +pub use eh1; pub use ftdi_mpsse; #[cfg(feature = "ftdi")] @@ -161,10 +162,10 @@ use crate::error::Error; pub use delay::Delay; pub use gpio::{InputPin, OutputPin}; pub use i2c::I2c; -pub use spi::Spi; +pub use spi::{Spi, SpiDevice}; use ftdi_mpsse::{MpsseCmdExecutor, MpsseSettings}; -use std::{cell::RefCell, sync::Mutex}; +use std::sync::{Arc, Mutex}; /// State tracker for each pin on the FTDI chip. #[derive(Debug, Clone, Copy)] @@ -228,7 +229,7 @@ impl From for FtInner { /// FTxxx device. #[derive(Debug)] pub struct FtHal { - mtx: Mutex>>, + mtx: Arc>>, } impl FtHal @@ -333,7 +334,7 @@ where device.init(mpsse_settings)?; Ok(FtHal { - mtx: Mutex::new(RefCell::new(device.into())), + mtx: Arc::new(Mutex::new(device.into())), }) } } @@ -372,6 +373,36 @@ where Spi::new(&self.mtx) } + /// Aquire the SPI peripheral with a chip select pin. + /// + /// This is specific to embedded-hal version 1. + /// + /// Pin assignments: + /// * AD0 => SCK + /// * AD1 => MOSI + /// * AD2 => MISO + /// + /// # Panics + /// + /// Panics if pin 0, 1, 2 or the CS pin are already in use. + /// + /// # Example + /// + /// ```no_run + /// use ftdi_embedded_hal as hal; + /// + /// # #[cfg(feature = "libftd2xx")] + /// # { + /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?; + /// let hal = hal::FtHal::init_freq(device, 3_000_000)?; + /// let spi = hal.spi_device(3)?; + /// # } + /// # Ok::<(), std::boxed::Box>(()) + /// ``` + pub fn spi_device(&self, cs_idx: u8) -> Result, Error> { + SpiDevice::new(&self.mtx, cs_idx) + } + /// Aquire the I2C peripheral for the FT232H. /// /// Pin assignments: diff --git a/src/spi.rs b/src/spi.rs index 022dd99..530c5d1 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1,19 +1,13 @@ use crate::error::Error; use crate::{FtInner, PinUse}; -use embedded_hal::spi::Polarity; use ftdi_mpsse::{ClockData, ClockDataOut, MpsseCmdBuilder, MpsseCmdExecutor}; -use std::result::Result; -use std::{cell::RefCell, sync::Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; -/// FTDI SPI interface. +/// FTDI SPI polarity. /// -/// This is created by calling [`FtHal::spi`]. -/// -/// [`FtHal::spi`]: crate::FtHal::spi -#[derive(Debug)] -pub struct Spi<'a, Device: MpsseCmdExecutor> { - /// Parent FTDI device. - mtx: &'a Mutex>>, +/// This is a helper type to support multiple embedded-hal versions simultaneously. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Polarity { /// MPSSE command used to clock data in and out simultaneously. /// /// This is set by [`Spi::set_clock_polarity`]. @@ -24,34 +18,86 @@ pub struct Spi<'a, Device: MpsseCmdExecutor> { clk_out: ClockDataOut, } +impl From for Polarity { + fn from(cpol: eh0::spi::Polarity) -> Self { + match cpol { + eh0::spi::Polarity::IdleLow => Polarity { + clk: ClockData::MsbPosIn, + clk_out: ClockDataOut::MsbNeg, + }, + eh0::spi::Polarity::IdleHigh => Polarity { + clk: ClockData::MsbNegIn, + clk_out: ClockDataOut::MsbPos, + }, + } + } +} + +impl From for Polarity { + fn from(cpol: eh1::spi::Polarity) -> Self { + match cpol { + eh1::spi::Polarity::IdleLow => Polarity { + clk: ClockData::MsbPosIn, + clk_out: ClockDataOut::MsbNeg, + }, + eh1::spi::Polarity::IdleHigh => Polarity { + clk: ClockData::MsbNegIn, + clk_out: ClockDataOut::MsbPos, + }, + } + } +} + +impl Default for Polarity { + fn default() -> Self { + Self { + clk: ClockData::MsbPosIn, + clk_out: ClockDataOut::MsbNeg, + } + } +} + +/// FTDI SPI bus. +/// +/// In embedded-hal version 1 this represents an exclusive SPI bus. +/// +/// This is created by calling [`FtHal::spi`]. +/// +/// [`FtHal::spi`]: crate::FtHal::spi +#[derive(Debug)] +pub struct Spi<'a, Device: MpsseCmdExecutor> { + /// Parent FTDI device. + mtx: &'a Arc>>, + /// SPI polarity + pol: Polarity, +} + impl<'a, Device, E> Spi<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, Error: From, { - pub(crate) fn new(mtx: &Mutex>>) -> Result, Error> { - 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); + pub(crate) fn new(mtx: &Arc>>) -> Result, Error> { + let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.allocate_pin(0, PinUse::Spi); + lock.allocate_pin(1, PinUse::Spi); + lock.allocate_pin(2, PinUse::Spi); // clear direction of first 3 pins - inner.direction &= !0x07; + lock.direction &= !0x07; // set SCK (AD0) and MOSI (AD1) as output pins - inner.direction |= 0x03; + lock.direction |= 0x03; // set GPIO pins to new state let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .set_gpio_lower(inner.value, inner.direction) + .set_gpio_lower(lock.value, lock.direction) .send_immediate(); - inner.ft.send(cmd.as_slice())?; + lock.ft.send(cmd.as_slice())?; Ok(Spi { mtx, - clk: ClockData::MsbPosIn, - clk_out: ClockDataOut::MsbNeg, + pol: Default::default(), }) } @@ -62,7 +108,7 @@ where /// # Example /// /// ```no_run - /// use embedded_hal::spi::Polarity; + /// use eh1::spi::Polarity; /// use ftdi_embedded_hal as hal; /// /// # #[cfg(feature = "libftd2xx")] @@ -76,19 +122,12 @@ where /// ``` /// /// [SPI mode]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Mode_numbers - 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), - }; - - // destructuring assignments are unstable - self.clk = clk; - self.clk_out = clk_out + pub fn set_clock_polarity>(&mut self, cpol: P) { + self.pol = cpol.into() } } -impl<'a, Device, E> embedded_hal::blocking::spi::Write for Spi<'a, Device> +impl<'a, Device, E> eh0::blocking::spi::Write for Spi<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, @@ -98,19 +137,17 @@ where fn write(&mut self, words: &[u8]) -> Result<(), Error> { let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .clock_data_out(self.clk_out, words) + .clock_data_out(self.pol.clk_out, words) .send_immediate(); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); - - inner.ft.send(cmd.as_slice())?; + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.ft.send(cmd.as_slice())?; Ok(()) } } -impl<'a, Device, E> embedded_hal::blocking::spi::Transfer for Spi<'a, Device> +impl<'a, Device, E> eh0::blocking::spi::Transfer for Spi<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, @@ -120,19 +157,18 @@ where fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Error> { let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .clock_data(self.clk, words) + .clock_data(self.pol.clk, words) .send_immediate(); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); - inner.ft.send(cmd.as_slice())?; - inner.ft.recv(words)?; + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.ft.send(cmd.as_slice())?; + lock.ft.recv(words)?; Ok(words) } } -impl<'a, Device, E> embedded_hal::spi::FullDuplex for Spi<'a, Device> +impl<'a, Device, E> eh0::spi::FullDuplex for Spi<'a, Device> where Device: MpsseCmdExecutor, E: std::error::Error, @@ -143,13 +179,11 @@ where fn read(&mut self) -> nb::Result> { let mut buf: [u8; 1] = [0]; let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .clock_data(self.clk, &buf) + .clock_data(self.pol.clk, &buf) .send_immediate(); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); - - match inner.ft.xfer(cmd.as_slice(), &mut buf) { + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + match lock.ft.xfer(cmd.as_slice(), &mut buf) { Ok(()) => Ok(buf[0]), Err(e) => Err(nb::Error::Other(Error::from(e))), } @@ -157,15 +191,381 @@ where fn send(&mut self, byte: u8) -> nb::Result<(), Error> { let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() - .clock_data_out(self.clk_out, &[byte]) + .clock_data_out(self.pol.clk_out, &[byte]) + .send_immediate(); + + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + match lock.ft.send(cmd.as_slice()) { + Ok(()) => Ok(()), + Err(e) => Err(nb::Error::Other(Error::from(e))), + } + } +} + +impl eh1::spi::Error for Error +where + E: std::error::Error, + Error: From, +{ + fn kind(&self) -> eh1::spi::ErrorKind { + eh1::spi::ErrorKind::Other + } +} + +impl<'a, Device, E> eh1::spi::ErrorType for Spi<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + type Error = Error; +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBusFlush for Spi<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBusWrite for Spi<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn write(&mut self, words: &[u8]) -> Result<(), Error> { + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .clock_data_out(self.pol.clk_out, words) + .send_immediate(); + + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.ft.send(cmd.as_slice())?; + + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBusRead for Spi<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + let data_out: Vec = vec![0; words.len()]; + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .clock_data(self.pol.clk, &data_out) .send_immediate(); - let lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); - let mut inner = lock.borrow_mut(); + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.ft.send(cmd.as_slice())?; + lock.ft.recv(words)?; + + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBus for Spi<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .clock_data(self.pol.clk, words) + .send_immediate(); + + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + + lock.ft.send(cmd.as_slice())?; + lock.ft.recv(words)?; + + Ok(()) + } + + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .clock_data(self.pol.clk, write) + .send_immediate(); + + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.ft.send(cmd.as_slice())?; + lock.ft.recv(read)?; + + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::nb::FullDuplex for Spi<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn read(&mut self) -> nb::Result> { + let mut buf: [u8; 1] = [0]; + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .clock_data(self.pol.clk, &buf) + .send_immediate(); + + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + match lock.ft.xfer(cmd.as_slice(), &mut buf) { + Ok(()) => Ok(buf[0]), + Err(e) => Err(nb::Error::Other(Error::from(e))), + } + } + + fn write(&mut self, byte: u8) -> nb::Result<(), Error> { + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .clock_data_out(self.pol.clk_out, &[byte]) + .send_immediate(); - match inner.ft.send(cmd.as_slice()) { + let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex"); + match lock.ft.send(cmd.as_slice()) { Ok(()) => Ok(()), Err(e) => Err(nb::Error::Other(Error::from(e))), } } } + +pub struct SpiDeviceBus<'a, Device: MpsseCmdExecutor> { + lock: MutexGuard<'a, FtInner>, + pol: Polarity, +} + +impl<'a, Device, E> eh1::spi::ErrorType for SpiDeviceBus<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + type Error = Error; +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBusFlush for SpiDeviceBus<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBusRead for SpiDeviceBus<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + self.lock.ft.xfer( + MpsseCmdBuilder::new() + .clock_data(self.pol.clk, words) + .send_immediate() + .as_slice(), + words, + )?; + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBusWrite for SpiDeviceBus<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.lock.ft.send( + MpsseCmdBuilder::new() + .clock_data_out(self.pol.clk_out, words) + .send_immediate() + .as_slice(), + )?; + Ok(()) + } +} + +impl<'a, Device, E> eh1::spi::blocking::SpiBus for SpiDeviceBus<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + self.lock.ft.xfer( + MpsseCmdBuilder::new() + .clock_data(self.pol.clk, write) + .send_immediate() + .as_slice(), + read, + )?; + Ok(()) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + self.lock.ft.xfer( + MpsseCmdBuilder::new() + .clock_data(self.pol.clk, words) + .send_immediate() + .as_slice(), + words, + )?; + Ok(()) + } +} + +/// FTDI SPI device, a SPI bus with chip select pin. +/// +/// This is created by calling [`FtHal::spi_device`]. +/// +/// This is specific to embedded-hal version 1. +/// +/// [`FtHal::spi_device`]: crate::FtHal::spi_device +#[derive(Debug)] +pub struct SpiDevice<'a, Device: MpsseCmdExecutor> { + /// Parent FTDI device. + mtx: &'a Arc>>, + /// SPI polarity + pol: Polarity, + /// Chip select pin index. 0-7 for the FT232H. + cs_idx: u8, +} + +impl<'a, Device, E> SpiDevice<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + pub(crate) fn new( + mtx: &'a Arc>>, + cs_idx: u8, + ) -> Result, Error> { + let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex"); + lock.allocate_pin(0, PinUse::Spi); + lock.allocate_pin(1, PinUse::Spi); + lock.allocate_pin(2, PinUse::Spi); + lock.allocate_pin(cs_idx, PinUse::Output); + + let cs_mask: u8 = 1 << cs_idx; + + // clear direction of first 3 pins and CS + lock.direction &= !(0x07 | cs_mask); + // set SCK (AD0) and MOSI (AD1), and CS as output pins + lock.direction |= 0x03 | cs_mask; + + // set GPIO pins to new state + let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new() + .set_gpio_lower(lock.value, lock.direction) + .send_immediate(); + lock.ft.send(cmd.as_slice())?; + + Ok(Self { + mtx, + pol: Default::default(), + cs_idx, + }) + } + + pub(crate) fn cs_mask(&self) -> u8 { + 1 << self.cs_idx + } + + /// Set the SPI clock polarity. + /// + /// FTD2XX devices only supports [SPI mode] 0 and 2, clock phase is fixed. + /// + /// # Example + /// + /// ```no_run + /// use eh1::spi::Polarity; + /// use ftdi_embedded_hal as hal; + /// + /// # #[cfg(feature = "libftd2xx")] + /// # { + /// let device = libftd2xx::Ft2232h::with_description("Dual RS232-HS A")?; + /// let hal = hal::FtHal::init_freq(device, 3_000_000)?; + /// let mut spi = hal.spi_device(3)?; + /// spi.set_clock_polarity(Polarity::IdleLow); + /// # } + /// # Ok::<(), std::boxed::Box>(()) + /// ``` + /// + /// [SPI mode]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Mode_numbers + pub fn set_clock_polarity>(&mut self, cpol: P) { + self.pol = cpol.into() + } +} + +impl<'a, Device, E> eh1::spi::ErrorType for SpiDevice<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + type Error = Error; +} + +impl<'a, Device, E> eh1::spi::blocking::SpiDevice for SpiDevice<'a, Device> +where + Device: MpsseCmdExecutor, + E: std::error::Error, + Error: From, +{ + type Bus = SpiDeviceBus<'a, Device>; + + fn transaction( + &mut self, + f: impl FnOnce(&mut Self::Bus) -> Result::Error>, + ) -> Result { + // lock the bus + let mut lock: MutexGuard> = + self.mtx.lock().expect("Failed to aquire FTDI mutex"); + let direction: u8 = lock.direction; + + // assert the chip select pin + let value_cs_asserted: u8 = lock.value & !self.cs_mask(); + lock.ft.send( + MpsseCmdBuilder::new() + .set_gpio_lower(value_cs_asserted, direction) + .send_immediate() + .as_slice(), + )?; + + // call f with an exclusive reference to the bus + let mut bus: SpiDeviceBus = SpiDeviceBus { + lock, + pol: self.pol, + }; + let bus_result = f(&mut bus); + + // flush the bus + { + use eh1::spi::blocking::SpiBusFlush; + bus.flush()?; + } + + let mut lock: MutexGuard> = bus.lock; + + // deassert the chip select pin + let value_cs_deasserted: u8 = lock.value | self.cs_mask(); + lock.ft.send( + MpsseCmdBuilder::new() + .set_gpio_lower(value_cs_deasserted, direction) + .send_immediate() + .as_slice(), + )?; + + // unlocking the bus is implicit via Drop + bus_result + } +}