#![forbid(missing_docs)]
#![forbid(unsafe_code)]
pub use eh0;
pub use eh1;
pub use ftdi_mpsse;
#[cfg(feature = "ftdi")]
pub use ftdi;
#[cfg(feature = "libftd2xx")]
pub use libftd2xx;
mod delay;
mod error;
mod gpio;
mod i2c;
mod spi;
pub use crate::error::{Error, ErrorKind};
pub use delay::Delay;
pub use gpio::{InputPin, OutputPin};
pub use i2c::I2c;
pub use spi::{Spi, SpiDevice};
use gpio::Pin;
use ftdi_mpsse::{MpsseCmdExecutor, MpsseSettings};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Copy)]
enum PinUse {
I2c,
Spi,
Output,
Input,
}
impl std::fmt::Display for PinUse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PinUse::I2c => write!(f, "I2C"),
PinUse::Spi => write!(f, "SPI"),
PinUse::Output => write!(f, "OUTPUT"),
PinUse::Input => write!(f, "INPUT"),
}
}
}
#[derive(Debug, Default)]
struct GpioByte {
direction: u8,
value: u8,
pins: [Option<PinUse>; 8],
}
#[derive(Debug)]
struct FtInner<Device: MpsseCmdExecutor> {
ft: Device,
lower: GpioByte,
upper: GpioByte,
}
impl<Device: MpsseCmdExecutor> core::ops::Deref for FtInner<Device> {
type Target = GpioByte;
fn deref(&self) -> &GpioByte {
&self.lower
}
}
impl<Device: MpsseCmdExecutor> core::ops::DerefMut for FtInner<Device> {
fn deref_mut(&mut self) -> &mut GpioByte {
&mut self.lower
}
}
impl<Device: MpsseCmdExecutor> FtInner<Device> {
pub fn allocate_pin(&mut self, idx: u8, purpose: PinUse) {
assert!(idx < 8, "Pin index {idx} is out of range 0 - 7");
if let Some(current) = self.lower.pins[usize::from(idx)] {
panic!(
"Unable to allocate pin {idx} for {purpose}, pin is already allocated for {current}"
);
} else {
self.lower.pins[usize::from(idx)] = Some(purpose)
}
}
pub fn allocate_pin_any(&mut self, pin: Pin, purpose: PinUse) {
let (byte, idx) = match pin {
Pin::Lower(idx) => (&mut self.lower, idx),
Pin::Upper(idx) => (&mut self.upper, idx),
};
assert!(idx < 8, "Pin index {idx} is out of range 0 - 7");
if let Some(current) = byte.pins[usize::from(idx)] {
panic!(
"Unable to allocate pin {idx} for {purpose}, pin is already allocated for {current}"
);
} else {
byte.pins[usize::from(idx)] = Some(purpose)
}
}
}
impl<Device: MpsseCmdExecutor> From<Device> for FtInner<Device> {
fn from(ft: Device) -> Self {
FtInner {
ft,
lower: Default::default(),
upper: Default::default(),
}
}
}
#[derive(Debug)]
pub struct FtHal<Device: MpsseCmdExecutor> {
mtx: Arc<Mutex<FtInner<Device>>>,
}
impl<Device, E> FtHal<Device>
where
Device: MpsseCmdExecutor<Error = E>,
E: std::error::Error,
Error<E>: From<E>,
{
pub fn init_default(device: Device) -> Result<FtHal<Device>, Error<E>> {
let settings: MpsseSettings = MpsseSettings {
clock_frequency: Some(100_000),
..Default::default()
};
Ok(FtHal::init(device, &settings)?)
}
pub fn init_freq(device: Device, freq: u32) -> Result<FtHal<Device>, Error<E>> {
let settings: MpsseSettings = MpsseSettings {
clock_frequency: Some(freq),
..Default::default()
};
Ok(FtHal::init(device, &settings)?)
}
pub fn init(mut device: Device, mpsse_settings: &MpsseSettings) -> Result<FtHal<Device>, E> {
device.init(mpsse_settings)?;
Ok(FtHal {
mtx: Arc::new(Mutex::new(device.into())),
})
}
}
impl<Device, E> FtHal<Device>
where
Device: MpsseCmdExecutor<Error = E>,
E: std::error::Error,
Error<E>: From<E>,
{
pub fn with_device<T, F>(&mut self, mut f: F) -> T
where
F: FnMut(&mut Device) -> T,
{
let mut inner = self.mtx.lock().expect("Failed to aquire FTDI mutex");
let result: T = f(&mut inner.ft);
result
}
pub fn spi(&self) -> Result<Spi<Device>, Error<E>> {
Spi::new(self.mtx.clone())
}
pub fn spi_device(&self, cs_idx: u8) -> Result<SpiDevice<Device>, Error<E>> {
SpiDevice::new(self.mtx.clone(), cs_idx)
}
pub fn i2c(&self) -> Result<I2c<Device>, Error<E>> {
I2c::new(self.mtx.clone())
}
pub fn ad0(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(0))
}
pub fn adi0(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(0))
}
pub fn ad1(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(1))
}
pub fn adi1(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(1))
}
pub fn ad2(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(2))
}
pub fn adi2(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(2))
}
pub fn ad3(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(3))
}
pub fn adi3(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(3))
}
pub fn ad4(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(4))
}
pub fn adi4(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(4))
}
pub fn ad5(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(5))
}
pub fn adi5(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(5))
}
pub fn ad6(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(6))
}
pub fn adi6(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(6))
}
pub fn ad7(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Lower(7))
}
pub fn adi7(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(7))
}
pub fn c0(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(0))
}
pub fn ci0(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(0))
}
pub fn c1(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(1))
}
pub fn ci1(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(1))
}
pub fn c2(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(2))
}
pub fn ci2(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(2))
}
pub fn c3(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(3))
}
pub fn ci3(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(3))
}
pub fn c4(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(4))
}
pub fn ci4(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(4))
}
pub fn c5(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(5))
}
pub fn ci5(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(5))
}
pub fn c6(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(6))
}
pub fn ci6(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(6))
}
pub fn c7(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(7))
}
pub fn ci7(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(7))
}
}