1#![deny(missing_docs)]
47#![deny(unused_results)]
48#![forbid(unsafe_code)]
49#![cfg_attr(not(test), no_std)]
50
51use core::marker::PhantomData;
52use embedded_hal::{blocking::i2c, digital::v2};
53
54pub const DEFAULT_I2C_ADDRESS: u8 = 0x2a;
58
59#[allow(dead_code)]
63#[repr(u8)]
64enum GpioExpanderCommand {
65 Uid = 0,
69
70 Reset,
74
75 ChangeI2CAddress,
79
80 SaveI2CAddress,
84
85 Input,
89
90 InputPullUp,
94
95 InputPullDown,
99
100 Output,
104
105 DigitalRead,
109
110 DigitalWriteHigh,
114
115 DigitalWriteLow,
119
120 PwmWrite,
124
125 AnalogRead,
129
130 PwmFreq,
134
135 AdcSpeed,
139}
140
141#[derive(Debug)]
145pub struct Floating;
146
147#[derive(Debug)]
151pub struct Input;
152
153#[derive(Debug)]
157pub struct Output;
158
159#[derive(Debug)]
163pub struct GpioExpander<MUTEX>(MUTEX);
164
165impl<I2C, ERROR> GpioExpander<shared_bus::NullMutex<Driver<I2C>>>
166where
167 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
168{
169 pub fn new(i2c: I2C, address: Option<u8>) -> Self {
173 Self::with_mutex(i2c, address)
174 }
175}
176
177impl<I2C, MUTEX, ERROR> GpioExpander<MUTEX>
178where
179 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
180 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
181{
182 pub fn with_mutex(i2c: I2C, address: Option<u8>) -> Self {
186 Self(shared_bus::BusMutex::create(Driver::new(
187 i2c,
188 address.unwrap_or(DEFAULT_I2C_ADDRESS),
189 )))
190 }
191
192 pub fn pins(&mut self) -> Pins<I2C, MUTEX, ERROR> {
196 Pins {
197 p00: Pin::new(0, &self.0),
198 p01: Pin::new(1, &self.0),
199 p02: Pin::new(2, &self.0),
200 p03: Pin::new(3, &self.0),
201 p04: Pin::new(4, &self.0),
202 p05: Pin::new(5, &self.0),
203 p06: Pin::new(6, &self.0),
204 p07: Pin::new(7, &self.0),
205 p08: Pin::new(8, &self.0),
206 p09: Pin::new(9, &self.0),
207 }
208 }
209
210 pub fn reset(&mut self) -> Result<(), ERROR> {
214 self.0.lock(|drv| drv.reset())?;
215
216 Ok(())
217 }
218
219 pub fn set_address(&mut self, new_address: u8) -> Result<(), ERROR> {
223 self.0.lock(|drv| drv.set_i2c_address(new_address))?;
224
225 Ok(())
226 }
227
228 pub fn save_address(&mut self) -> Result<(), ERROR> {
232 self.0.lock(|drv| drv.save_i2c_address())?;
233
234 Ok(())
235 }
236}
237
238pub struct Driver<I2C> {
240 i2c: I2C,
241 address: u8,
242}
243
244impl<I2C, ERROR> Driver<I2C>
245where
246 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
247{
248 pub(crate) fn new(i2c: I2C, address: u8) -> Self {
249 Self { i2c, address }
250 }
251
252 pub(crate) fn pin_to_input(&mut self, pin: u8) -> Result<(), ERROR> {
253 let raw_pin_num = (1u16 << pin as u16).to_be_bytes();
254
255 self.i2c.write(
256 self.address,
257 &[
258 GpioExpanderCommand::Input as u8,
259 raw_pin_num[0],
260 raw_pin_num[1],
261 ],
262 )?;
263
264 Ok(())
265 }
266
267 pub(crate) fn pin_to_pull_up_input(&mut self, pin: u8) -> Result<(), ERROR> {
268 let raw_pin_num = (1u16 << pin as u16).to_be_bytes();
269
270 self.i2c.write(
271 self.address,
272 &[
273 GpioExpanderCommand::InputPullUp as u8,
274 raw_pin_num[0],
275 raw_pin_num[1],
276 ],
277 )?;
278
279 Ok(())
280 }
281
282 pub(crate) fn pin_to_pull_down_input(&mut self, pin: u8) -> Result<(), ERROR> {
283 let raw_pin_num = (1u16 << pin as u16).to_be_bytes();
284
285 self.i2c.write(
286 self.address,
287 &[
288 GpioExpanderCommand::InputPullDown as u8,
289 raw_pin_num[0],
290 raw_pin_num[1],
291 ],
292 )?;
293
294 Ok(())
295 }
296
297 pub(crate) fn pin_to_output(&mut self, pin: u8) -> Result<(), ERROR> {
298 let raw_pin_num = (1u16 << pin as u16).to_be_bytes();
299
300 self.i2c.write(
301 self.address,
302 &[
303 GpioExpanderCommand::Output as u8,
304 raw_pin_num[0],
305 raw_pin_num[1],
306 ],
307 )?;
308
309 Ok(())
310 }
311
312 pub(crate) fn digital_read(&mut self, pin: u8) -> Result<bool, ERROR> {
313 let mask = 1u16 << pin as u16;
314
315 let mut read_buf = [0u8; 2];
316 self.i2c
317 .write(self.address, &[GpioExpanderCommand::DigitalRead as u8])?;
318 self.i2c.read(self.address, &mut read_buf)?;
319
320 Ok((u16::from_be_bytes(read_buf) & mask) != 0)
321 }
322
323 pub(crate) fn digital_write(&mut self, pin: u8, value: bool) -> Result<(), ERROR> {
324 let raw_pin_num = (1u16 << pin as u16).to_be_bytes();
325
326 if value {
327 self.i2c.write(
328 self.address,
329 &[
330 GpioExpanderCommand::DigitalWriteHigh as u8,
331 raw_pin_num[0],
332 raw_pin_num[1],
333 ],
334 )?;
335 } else {
336 self.i2c.write(
337 self.address,
338 &[
339 GpioExpanderCommand::DigitalWriteLow as u8,
340 raw_pin_num[0],
341 raw_pin_num[1],
342 ],
343 )?;
344 }
345
346 Ok(())
347 }
348
349 pub(crate) fn analog_read(&mut self, pin: u8) -> Result<u16, ERROR> {
350 let write_buf = [GpioExpanderCommand::AnalogRead as u8, pin];
351 let mut read_buf = [0u8; 2];
352
353 self.i2c
354 .write_read(self.address, &write_buf, &mut read_buf)?;
355
356 Ok(u16::from_be_bytes(read_buf) as u16)
357 }
358
359 pub(crate) fn pwm_write(&mut self, pin: u8, value: u16) -> Result<(), ERROR> {
360 let raw_value: [u8; 2] = value.to_be_bytes();
361
362 self.i2c.write(
363 self.address,
364 &[
365 GpioExpanderCommand::PwmWrite as u8,
366 pin,
367 raw_value[0],
368 raw_value[1],
369 ],
370 )?;
371
372 Ok(())
373 }
374
375 pub(crate) fn reset(&mut self) -> Result<(), ERROR> {
376 self.i2c
377 .write(self.address, &[GpioExpanderCommand::Reset as u8])?;
378
379 Ok(())
380 }
381
382 pub(crate) fn set_i2c_address(&mut self, new_address: u8) -> Result<(), ERROR> {
383 self.i2c.write(
384 self.address,
385 &[GpioExpanderCommand::ChangeI2CAddress as u8, new_address],
386 )?;
387
388 self.address = new_address;
389
390 Ok(())
391 }
392
393 pub(crate) fn save_i2c_address(&mut self) -> Result<(), ERROR> {
394 self.i2c
395 .write(self.address, &[GpioExpanderCommand::SaveI2CAddress as u8])?;
396
397 Ok(())
398 }
399}
400
401pub struct Pins<'a, I2C, MUTEX, ERROR>
405where
406 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
407 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
408{
409 pub p00: Pin<'a, Floating, MUTEX>,
411
412 pub p01: Pin<'a, Floating, MUTEX>,
414
415 pub p02: Pin<'a, Floating, MUTEX>,
417
418 pub p03: Pin<'a, Floating, MUTEX>,
420
421 pub p04: Pin<'a, Floating, MUTEX>,
423
424 pub p05: Pin<'a, Floating, MUTEX>,
426
427 pub p06: Pin<'a, Floating, MUTEX>,
429
430 pub p07: Pin<'a, Floating, MUTEX>,
432
433 pub p08: Pin<'a, Floating, MUTEX>,
435
436 pub p09: Pin<'a, Floating, MUTEX>,
438}
439
440pub struct Pin<'a, MODE, MUTEX> {
442 pin: u8,
443 driver: &'a MUTEX,
444 _mode: PhantomData<MODE>,
445}
446
447impl<'a, MODE, MUTEX, I2C, ERROR> Pin<'a, MODE, MUTEX>
448where
449 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
450 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
451{
452 pub(crate) fn new(pin: u8, driver: &'a MUTEX) -> Self {
453 Self {
454 pin,
455 driver,
456 _mode: PhantomData,
457 }
458 }
459}
460
461impl<'a, MODE, MUTEX, I2C, ERROR> Pin<'a, MODE, MUTEX>
462where
463 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
464 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
465{
466 pub fn into_input(&self) -> Result<Pin<'a, Input, MUTEX>, ERROR> {
470 self.driver.lock(|drv| drv.pin_to_input(self.pin))?;
471
472 Ok(Pin {
473 pin: self.pin,
474 driver: self.driver,
475 _mode: PhantomData,
476 })
477 }
478
479 pub fn into_pull_up_input(&self) -> Result<Pin<'a, Input, MUTEX>, ERROR> {
483 self.driver.lock(|drv| drv.pin_to_pull_up_input(self.pin))?;
484
485 Ok(Pin {
486 pin: self.pin,
487 driver: self.driver,
488 _mode: PhantomData,
489 })
490 }
491
492 pub fn into_pull_down_input(&self) -> Result<Pin<'a, Input, MUTEX>, ERROR> {
496 self.driver
497 .lock(|drv| drv.pin_to_pull_down_input(self.pin))?;
498
499 Ok(Pin {
500 pin: self.pin,
501 driver: self.driver,
502 _mode: PhantomData,
503 })
504 }
505
506 pub fn into_output(&self) -> Result<Pin<'a, Output, MUTEX>, ERROR> {
510 self.driver.lock(|drv| drv.pin_to_output(self.pin))?;
511
512 Ok(Pin {
513 pin: self.pin,
514 driver: self.driver,
515 _mode: PhantomData,
516 })
517 }
518}
519
520impl<'a, MUTEX, I2C, ERROR> Pin<'a, Output, MUTEX>
521where
522 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
523 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
524{
525 pub fn set_pwm(&mut self, value: u16) -> Result<(), ERROR> {
529 self.driver.lock(|drv| drv.pwm_write(self.pin, value))?;
530
531 Ok(())
532 }
533}
534
535impl<'a, MUTEX, I2C, ERROR> v2::OutputPin for Pin<'a, Output, MUTEX>
536where
537 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
538 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
539{
540 type Error = ERROR;
541
542 fn set_high(&mut self) -> Result<(), Self::Error> {
543 self.driver.lock(|drv| drv.digital_write(self.pin, true))?;
544
545 Ok(())
546 }
547
548 fn set_low(&mut self) -> Result<(), Self::Error> {
549 self.driver.lock(|drv| drv.digital_write(self.pin, false))?;
550
551 Ok(())
552 }
553}
554
555impl<'a, MUTEX, I2C, ERROR> v2::StatefulOutputPin for Pin<'a, Output, MUTEX>
556where
557 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
558 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
559{
560 fn is_set_high(&self) -> Result<bool, Self::Error> {
561 self.driver.lock(|drv| drv.digital_read(self.pin))
562 }
563
564 fn is_set_low(&self) -> Result<bool, Self::Error> {
565 let is_set_low = !self.is_set_high()?;
566 Ok(is_set_low)
567 }
568}
569
570impl<'a, MUTEX> v2::toggleable::Default for Pin<'a, Output, MUTEX> where
571 Pin<'a, Output, MUTEX>: embedded_hal::digital::v2::StatefulOutputPin
572{
573}
574
575impl<'a, MUTEX, I2C, ERROR> Pin<'a, Input, MUTEX>
576where
577 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
578 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
579{
580 pub fn get_analog(&self) -> Result<u16, ERROR> {
584 self.driver.lock(|drv| drv.analog_read(self.pin))
585 }
586}
587
588impl<'a, MUTEX, I2C, ERROR> v2::InputPin for Pin<'a, Input, MUTEX>
589where
590 I2C: i2c::WriteRead<Error = ERROR> + i2c::Write<Error = ERROR> + i2c::Read<Error = ERROR>,
591 MUTEX: shared_bus::BusMutex<Bus = Driver<I2C>>,
592{
593 type Error = ERROR;
594
595 fn is_high(&self) -> Result<bool, Self::Error> {
596 self.driver.lock(|drv| drv.digital_read(self.pin))
597 }
598
599 fn is_low(&self) -> Result<bool, Self::Error> {
600 let is_low = !self.is_high()?;
601 Ok(is_low)
602 }
603}
604
605pub mod prelude {
626 pub use embedded_hal::digital::v2::InputPin as _embedded_hal_digital_v2_InputPin;
627 pub use embedded_hal::digital::v2::OutputPin as _embedded_hal_digital_v2_OutputPin;
628 pub use embedded_hal::digital::v2::StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin;
629 pub use embedded_hal::digital::v2::ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin;
630}
631
632#[cfg(test)]
633mod tests {
634 use super::{prelude::*, GpioExpander};
635 use embedded_hal_mock::i2c;
636
637 #[test]
638 fn input() {
639 let expectations = [
640 i2c::Transaction::write(0x2a, vec![0b00000100, 0b00000000, 0b00000001]),
642 i2c::Transaction::write(0x2a, vec![0b00000100, 0b00000000, 0b00000010]),
644 i2c::Transaction::write(0x2a, vec![0b00001000]),
646 i2c::Transaction::read(0x2a, vec![0b00000011, 0b01001111]),
647 i2c::Transaction::write(0x2a, vec![0b00001000]),
649 i2c::Transaction::read(0x2a, vec![0b00000011, 0b01101111]),
650 ];
651 let mut bus = i2c::Mock::new(&expectations);
652
653 let mut expander = GpioExpander::new(bus.clone(), None);
654 let expander_pins = expander.pins();
655
656 let p00 = expander_pins.p00.into_input().unwrap();
657 let p01 = expander_pins.p01.into_input().unwrap();
658 assert!(p00.is_high().unwrap());
659 assert!(!p01.is_low().unwrap());
660
661 bus.done();
662 }
663
664 #[test]
665 fn output() {
666 let expectations = [
667 i2c::Transaction::write(0x2a, vec![0b00000111, 0b00000000, 0b00000001]),
669 i2c::Transaction::write(0x2a, vec![0b00000111, 0b00000000, 0b00000010]),
671 i2c::Transaction::write(0x2a, vec![0b00001001, 0b00000000, 0b00000001]),
673 i2c::Transaction::write(0x2a, vec![0b00001010, 0b00000000, 0b00000010]),
675 ];
676 let mut bus = i2c::Mock::new(&expectations);
677
678 let mut expander = GpioExpander::new(bus.clone(), None);
679 let expander_pins = expander.pins();
680
681 let mut p00 = expander_pins.p00.into_output().unwrap();
682 let mut p01 = expander_pins.p01.into_output().unwrap();
683 p00.set_high().unwrap();
684 p01.set_low().unwrap();
685
686 bus.done();
687 }
688
689 #[test]
690 fn pwm() {
691 let expectations = [
692 i2c::Transaction::write(0x2a, vec![0b00000111, 0b00000000, 0b00000001]),
694 i2c::Transaction::write(0x2a, vec![0b00001011, 0b00000000, 0b00000111, 0b11010000]),
696 ];
697 let mut bus = i2c::Mock::new(&expectations);
698
699 let mut expander = GpioExpander::new(bus.clone(), None);
700 let expander_pins = expander.pins();
701
702 let mut p00 = expander_pins.p00.into_output().unwrap();
703 p00.set_pwm(2000).unwrap();
704
705 bus.done();
706 }
707
708 #[test]
709 fn adc() {
710 let expectations = [
711 i2c::Transaction::write(0x2a, vec![0b00000100, 0b00000000, 0b00000001]),
713 i2c::Transaction::write_read(
715 0x2a,
716 vec![0b00001100, 0b00000000],
717 vec![0b00000110, 0b11101011],
718 ),
719 ];
720 let mut bus = i2c::Mock::new(&expectations);
721
722 let mut expander = GpioExpander::new(bus.clone(), None);
723 let expander_pins = expander.pins();
724
725 let p00 = expander_pins.p00.into_input().unwrap();
726 assert!(p00.get_analog().unwrap() == 1771);
727
728 bus.done();
729 }
730
731 #[test]
732 fn save_address() {
733 let expectations = [
734 i2c::Transaction::write(0x2a, vec![0b00000010, 0b00101010]),
736 i2c::Transaction::write(0x2a, vec![0b00000011]),
738 ];
739 let mut bus = i2c::Mock::new(&expectations);
740
741 let mut expander = GpioExpander::new(bus.clone(), None);
742 expander.set_address(0x2a).unwrap();
743 expander.save_address().unwrap();
744
745 bus.done();
746 }
747
748 #[test]
749 fn reset() {
750 let expectations = [
751 i2c::Transaction::write(0x2a, vec![0b00000111, 0b00000000, 0b00000001]),
753 i2c::Transaction::write(0x2a, vec![0b00001001, 0b00000000, 0b00000001]),
755 i2c::Transaction::write(0x2a, vec![0b00000001]),
757 ];
758 let mut bus = i2c::Mock::new(&expectations);
759
760 let mut expander = GpioExpander::new(bus.clone(), None);
761 let expander_pins = expander.pins();
762
763 let mut p00 = expander_pins.p00.into_output().unwrap();
764 p00.set_high().unwrap();
765
766 expander.reset().unwrap();
767
768 bus.done();
769 }
770}