Skip to content

Commit

Permalink
gpio: Enable access to high pins
Browse files Browse the repository at this point in the history
Closes: #50
  • Loading branch information
chrysn authored and newAM committed May 7, 2024
1 parent d581a6b commit 88f8311
Show file tree
Hide file tree
Showing 2 changed files with 247 additions and 33 deletions.
76 changes: 54 additions & 22 deletions src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::sync::{Arc, Mutex};
#[derive(Debug, Copy, Clone)]
pub(crate) enum Pin {
Lower(u8),
Upper(u8),
}

/// FTDI output pin.
Expand Down Expand Up @@ -36,13 +37,19 @@ where
{
let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex");

let Pin::Lower(idx) = pin;

lock.direction |= 1 << idx;
lock.allocate_pin(idx, PinUse::Output);
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(lock.value, lock.direction)
.send_immediate();
lock.allocate_pin_any(pin, PinUse::Output);

let (byte, idx) = match pin {
Pin::Lower(idx) => (&mut lock.lower, idx),
Pin::Upper(idx) => (&mut lock.upper, idx),
};
byte.direction |= 1 << idx;
let cmd = MpsseCmdBuilder::new();
let cmd = match pin {
Pin::Lower(_) => cmd.set_gpio_lower(byte.value, byte.direction),
Pin::Upper(_) => cmd.set_gpio_upper(byte.value, byte.direction),
}
.send_immediate();
lock.ft.send(cmd.as_slice())?;
}
Ok(OutputPin { mtx, pin })
Expand All @@ -51,15 +58,23 @@ where
pub(crate) fn set(&self, state: bool) -> Result<(), Error<E>> {
let mut lock = self.mtx.lock().expect("Failed to aquire FTDI mutex");

let byte = match self.pin {
Pin::Lower(_) => &mut lock.lower,
Pin::Upper(_) => &mut lock.upper,
};

if state {
lock.value |= self.mask();
byte.value |= self.mask();
} else {
lock.value &= !self.mask();
byte.value &= !self.mask();
};

let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(lock.value, lock.direction)
.send_immediate();
let cmd = MpsseCmdBuilder::new();
let cmd = match self.pin {
Pin::Lower(_) => cmd.set_gpio_lower(byte.value, byte.direction),
Pin::Upper(_) => cmd.set_gpio_upper(byte.value, byte.direction),
}
.send_immediate();
lock.ft.send(cmd.as_slice())?;

Ok(())
Expand All @@ -69,7 +84,10 @@ where
impl<Device: MpsseCmdExecutor> OutputPin<Device> {
/// Convert the GPIO pin index to a pin mask
pub(crate) fn mask(&self) -> u8 {
let Pin::Lower(idx) = self.pin;
let idx = match self.pin {
Pin::Lower(idx) => idx,
Pin::Upper(idx) => idx,
};
1 << idx
}
}
Expand Down Expand Up @@ -142,13 +160,19 @@ where
{
let mut lock = mtx.lock().expect("Failed to aquire FTDI mutex");

let Pin::Lower(idx) = pin;

lock.direction &= !(1 << idx);
lock.allocate_pin(idx, PinUse::Input);
let cmd: MpsseCmdBuilder = MpsseCmdBuilder::new()
.set_gpio_lower(lock.value, lock.direction)
.send_immediate();
lock.allocate_pin_any(pin, PinUse::Input);

let (byte, idx) = match pin {
Pin::Lower(idx) => (&mut lock.lower, idx),
Pin::Upper(idx) => (&mut lock.upper, idx),
};
byte.direction &= !(1 << idx);
let cmd = MpsseCmdBuilder::new();
let cmd = match pin {
Pin::Lower(_) => cmd.set_gpio_lower(byte.value, byte.direction),
Pin::Upper(_) => cmd.set_gpio_upper(byte.value, byte.direction),
}
.send_immediate();
lock.ft.send(cmd.as_slice())?;
}
Ok(InputPin { mtx, pin })
Expand All @@ -158,7 +182,12 @@ where
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();
let cmd = MpsseCmdBuilder::new();
let cmd = match self.pin {
Pin::Lower(_) => cmd.gpio_lower(),
Pin::Upper(_) => cmd.gpio_upper(),
}
.send_immediate();
lock.ft.send(cmd.as_slice())?;
lock.ft.recv(&mut buffer)?;

Expand All @@ -169,7 +198,10 @@ where
impl<Device: MpsseCmdExecutor> InputPin<Device> {
/// Convert the GPIO pin index to a pin mask
pub(crate) fn mask(&self) -> u8 {
let Pin::Lower(idx) = self.pin;
let idx = match self.pin {
Pin::Lower(idx) => idx,
Pin::Upper(idx) => idx,
};
1 << idx
}
}
Expand Down
204 changes: 193 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,8 @@ impl std::fmt::Display for PinUse {
}
}

#[derive(Debug)]
struct FtInner<Device: MpsseCmdExecutor> {
/// FTDI device.
ft: Device,
#[derive(Debug, Default)]
struct GpioByte {
/// GPIO direction.
direction: u8,
/// GPIO value.
Expand All @@ -208,17 +206,58 @@ struct FtInner<Device: MpsseCmdExecutor> {
pins: [Option<PinUse>; 8],
}

#[derive(Debug)]
struct FtInner<Device: MpsseCmdExecutor> {
/// FTDI device.
ft: Device,
lower: GpioByte,
upper: GpioByte,
}

// FtInner deref's into .lower because SPI and I2C code were not adjusted yet to handle the split;
// once those are updated, the Deref implementation can go away again

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> {
/// Allocate a pin for a specific use.
/// Allocate a pin in the lower byte for a specific use.
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.pins[usize::from(idx)] {
if let Some(current) = self.lower.pins[usize::from(idx)] {
panic!(
"Unable to allocate pin {idx} for {purpose}, pin is already allocated for {current}"
"Unable to allocate pin {idx} for {purpose}, pin is already allocated for {current}"
);
} else {
self.pins[usize::from(idx)] = Some(purpose)
self.lower.pins[usize::from(idx)] = Some(purpose)
}
}

/// Allocate a pin for a specific use.
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)
}
}
}
Expand All @@ -227,9 +266,8 @@ impl<Device: MpsseCmdExecutor> From<Device> for FtInner<Device> {
fn from(ft: Device) -> Self {
FtInner {
ft,
direction: 0x00,
value: 0x00,
pins: [None; 8],
lower: Default::default(),
upper: Default::default(),
}
}
}
Expand Down Expand Up @@ -585,4 +623,148 @@ where
pub fn adi7(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Lower(7))
}

/// Aquire the digital output upper pin 0 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c0(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(0))
}

/// Aquire the digital input upper pin 0 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci0(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(0))
}

/// Aquire the digital output upper pin 1 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c1(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(1))
}

/// Aquire the digital input upper pin 1 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci1(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(1))
}

/// Aquire the digital output upper pin 2 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c2(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(2))
}

/// Aquire the digital input upper pin 2 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci2(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(2))
}

/// Aquire the digital output upper pin 3 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c3(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(3))
}

/// Aquire the digital input upper pin 3 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci3(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(3))
}

/// Aquire the digital output upper pin 4 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c4(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(4))
}

/// Aquire the digital input upper pin 4 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci4(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(4))
}

/// Aquire the digital output upper pin 5 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c5(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(5))
}

/// Aquire the digital input upper pin 5 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci5(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(5))
}

/// Aquire the digital output upper pin 6 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c6(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(6))
}

/// Aquire the digital input upper pin 6 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci6(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(6))
}

/// Aquire the digital output upper pin 7 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn c7(&self) -> Result<OutputPin<Device>, Error<E>> {
OutputPin::new(self.mtx.clone(), Pin::Upper(7))
}

/// Aquire the digital input upper pin 7 for the FT232H.
///
/// # Panics
///
/// Panics if the pin is already in-use.
pub fn ci7(&self) -> Result<InputPin<Device>, Error<E>> {
InputPin::new(self.mtx.clone(), Pin::Upper(7))
}
}

0 comments on commit 88f8311

Please sign in to comment.