diff --git a/src/main.rs b/src/main.rs index d5f8681..2dcf476 100644 --- a/src/main.rs +++ b/src/main.rs @@ -87,10 +87,12 @@ async fn main(_spawner: Spawner) { log::info!("main: setting pins as input"); for i in 0..(pins::N_EXTENDED_PINS + pins::N_REGULAR_PINS) { - log::debug!("main: setting pin {} as input, pull up", i); unwrap(pin_driver.set_input(i as u8)).await; unwrap(pin_driver.set_pull(i as u8, gpio::Pull::Up)).await; } + log::debug!("main: setting pin 0 as output, active low"); + unwrap(pin_driver.set_output(0)).await; + unwrap(pin_driver.write_all(((1 << 40 - 1)) & 0)).await; // these pins are faulty as inputs // unwrap(pin_driver.set_output(7)).await; diff --git a/src/pins.rs b/src/pins.rs index a756577..f46aa78 100644 --- a/src/pins.rs +++ b/src/pins.rs @@ -76,7 +76,8 @@ impl From> for Error { /// "Transparent pins" to consistently interface with a GPIO extender + onboard GPIO ports. /// /// This interface uses a single addressing scheme for all the pins it manages. -/// `ext[0]` is 0-15, `ext[1]` is 16-31, regular pins are 32-63. +/// Extender A is 0-15, Extender B is 16-31, and so on, then all the onboard pins. +/// Port A is in the lower byte and port B is in the upper byte of each extender range. pub struct TransparentPins { addrs: [u8; N_PIN_EXTENDERS], pins: [Flex<'static, AnyPin>; N_REGULAR_PINS], @@ -127,15 +128,35 @@ impl TransparentPins { } } + /// Write all pins from a single 64-bit value. + pub fn write_all(&mut self, val: u64) -> Result<(), Error> { + log::trace!("write_all: called with val {}", val); + for i in 0..N_PIN_EXTENDERS { + // value for this extender + let ext_val = (val >> (i*PINS_PER_EXTENDER)) & ((1 << PINS_PER_EXTENDER) - 1); + extender!(self, i)?.write_gpioab(ext_val as u16)?; + } + for pin in 0..N_REGULAR_PINS { + self.pins[pin].set_level(match (val >> N_EXTENDED_PINS >> pin) & 1 { + 0 => embassy_rp::gpio::Level::Low, + 1 => embassy_rp::gpio::Level::High, + _ => panic!("Invalid level"), + }) + } + + Ok(()) + } + /// Read all pins into a single 64-bit value. - /// - /// For a given extender's range, port B is in the lower byte and port A in the upper byte. pub fn read_all(&mut self) -> Result { log::trace!("read_all: called"); let mut ret: u64 = 0; for i in 0..N_PIN_EXTENDERS { let mut ext = extender!(self, i)?; - ret |= (ext.read_gpioab()? as u64) << (i * PINS_PER_EXTENDER); + let read_val = ext.read_gpioab()? as u64; + // api is wonky (https://github.com/lucazulian/mcp23017/issues/8) + let flipped_val = ((read_val & 0x00ff) << 8) | ((read_val & 0xff00) >> 8); + ret |= flipped_val << (i * PINS_PER_EXTENDER); } for pin in 0..N_REGULAR_PINS { ret |= (self.pins[pin].is_high() as u64) << (N_EXTENDED_PINS + pin); @@ -166,6 +187,7 @@ impl TransparentPins { Ok(()) } + /// Sets a pin as an input. pub fn set_input(&mut self, pin: u8) -> Result<(), Error> { let pin = self.get_pin(pin)?; match pin { @@ -177,6 +199,7 @@ impl TransparentPins { Ok(()) } + /// Sets a pin as an output. pub fn set_output(&mut self, pin: u8) -> Result<(), Error> { let pin = self.get_pin(pin)?; match pin {