use crate::{FtInner, PinUse};
use libftd2xx::{ClockBitsIn, ClockBitsOut, FtdiCommon, MpsseCmdBuilder, TimeoutError};
use std::{cell::RefCell, error::Error, fmt, sync::Mutex};
const SCL: u8 = 1 << 0;
const SDA: u8 = 1 << 1;
const BITS_IN: ClockBitsIn = ClockBitsIn::MsbPos;
const BITS_OUT: ClockBitsOut = ClockBitsOut::MsbNeg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum I2cError {
Timeout(TimeoutError),
Nak,
}
impl From<TimeoutError> for I2cError {
fn from(to: TimeoutError) -> Self {
I2cError::Timeout(to)
}
}
impl fmt::Display for I2cError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
I2cError::Timeout(to) => write!(f, "{}", to),
I2cError::Nak => write!(f, "ACK not recieved from slave"),
}
}
}
impl Error for I2cError {}
#[derive(Debug)]
pub struct I2c<'a, Device> {
mtx: &'a Mutex<RefCell<FtInner<Device>>>,
start_stop_cmds: u8,
fast: bool,
}
impl<'a, Device: FtdiCommon> I2c<'a, Device> {
pub(crate) fn new(mtx: &Mutex<RefCell<FtInner<Device>>>) -> Result<I2c<Device>, TimeoutError> {
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);
inner.direction &= !0x07;
inner.value &= !0x07;
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(inner.value, inner.direction)
.enable_3phase_data_clocking()
.send_immediate();
inner.ft.write_all(cmd.as_slice())?;
Ok(I2c {
mtx,
start_stop_cmds: 3,
fast: false,
})
}
pub fn set_stop_start_len(&mut self, start_stop_cmds: u8) {
self.start_stop_cmds = start_stop_cmds
}
pub fn set_fast(&mut self, fast: bool) {
self.fast = fast
}
fn read_fast(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cError> {
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 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)
}
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(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, (address << 1) | 1, 8)
.set_gpio_lower(inner.value, SCL | inner.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)
.clock_bits_in(BITS_IN, 8);
if idx == buffer.len() - 1 {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x80, 1)
} else {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x00, 1)
}
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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(inner.value, inner.direction)
.send_immediate();
inner.ft.write_all(&mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
inner.ft.read_all(buffer)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
Ok(())
}
fn read_slow(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cError> {
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 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)
}
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(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, (address << 1) | 1, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
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)
.clock_bits_in(BITS_IN, 8);
if idx == buffer.len() - 1 {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x80, 1)
} else {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x00, 1)
}
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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(inner.value, inner.direction)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
inner.ft.read_all(buffer)?;
Ok(())
}
fn write_fast(&mut self, addr: u8, bytes: &[u8]) -> Result<(), I2cError> {
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 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)
}
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(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, addr << 1, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1);
for byte in bytes.iter() {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, *byte, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1);
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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(inner.value, inner.direction)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: Vec<u8> = vec![0; 1 + bytes.len()];
inner.ft.read_all(ack_buf.as_mut_slice())?;
if ack_buf.iter().any(|&ack| (ack & 0b1) != 0x00) {
Err(I2cError::Nak)
} else {
Ok(())
}
}
fn write_slow(&mut self, addr: u8, bytes: &[u8]) -> Result<(), I2cError> {
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 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)
}
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(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, addr << 1, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
for (idx, byte) in bytes.iter().enumerate() {
let mut mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, *byte, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1);
if idx == bytes.len() - 1 {
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd =
mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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(inner.value, inner.direction)
}
mpsse_cmd = mpsse_cmd.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
}
Ok(())
}
fn write_read_fast(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), I2cError> {
assert!(!bytes.is_empty(), "bytes must be a non-empty slice");
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 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)
}
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(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, address << 1, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1);
for byte in bytes {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, *byte, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1);
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd =
mpsse_cmd.set_gpio_lower(inner.value | SCL | SDA, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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
.clock_bits_out(BITS_OUT, (address << 1) | 1, 8)
.set_gpio_lower(inner.value, SCL | inner.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)
.clock_bits_in(BITS_IN, 8);
if idx == buffer.len() - 1 {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x80, 1)
} else {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x00, 1)
}
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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(inner.value, inner.direction)
.send_immediate();
inner.ft.write_all(&mpsse_cmd.as_slice())?;
let mut ack_buf: Vec<u8> = vec![0; 2 + bytes.len()];
inner.ft.read_all(&mut ack_buf)?;
inner.ft.read_all(buffer)?;
if ack_buf.iter().any(|&ack| (ack & 0b1) != 0x00) {
Err(I2cError::Nak)
} else {
Ok(())
}
}
fn write_read_slow(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), I2cError> {
assert!(!bytes.is_empty(), "bytes must be a non-empty slice");
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 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)
}
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(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, address << 1, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
for byte in bytes {
let mpsse_cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, *byte, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
}
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)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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
.clock_bits_out(BITS_OUT, (address << 1) | 1, 8)
.set_gpio_lower(inner.value, SCL | inner.direction)
.clock_bits_in(BITS_IN, 1)
.send_immediate();
inner.ft.write_all(mpsse_cmd.as_slice())?;
let mut ack_buf: [u8; 1] = [0; 1];
inner.ft.read_all(&mut ack_buf)?;
if (ack_buf[0] & 0b1) != 0x00 {
return Err(I2cError::Nak);
}
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)
.clock_bits_in(BITS_IN, 8);
if idx == buffer.len() - 1 {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x80, 1)
} else {
mpsse_cmd = mpsse_cmd
.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
.clock_bits_out(BITS_OUT, 0x00, 1)
}
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value, SCL | SDA | inner.direction)
}
for _ in 0..self.start_stop_cmds {
mpsse_cmd = mpsse_cmd.set_gpio_lower(inner.value | SCL, SCL | SDA | inner.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(inner.value, inner.direction)
.send_immediate();
inner.ft.write_all(&mpsse_cmd.as_slice())?;
inner.ft.read_all(buffer)?;
Ok(())
}
}
impl<'a, Device: FtdiCommon> embedded_hal::blocking::i2c::Read for I2c<'a, Device> {
type Error = I2cError;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
if self.fast {
self.read_fast(address, buffer)
} else {
self.read_slow(address, buffer)
}
}
}
impl<'a, Device: FtdiCommon> embedded_hal::blocking::i2c::Write for I2c<'a, Device> {
type Error = I2cError;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
if self.fast {
self.write_fast(addr, bytes)
} else {
self.write_slow(addr, bytes)
}
}
}
impl<'a, Device: FtdiCommon> embedded_hal::blocking::i2c::WriteRead for I2c<'a, Device> {
type Error = I2cError;
fn write_read(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Self::Error> {
if self.fast {
self.write_read_fast(address, bytes, buffer)
} else {
self.write_read_slow(address, bytes, buffer)
}
}
}