Skip to main content

pamoja_gpio/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3//! On-board bus addressing and pin logic for the pamoja SDK.
4//!
5//! Before a node reaches any network it has to talk to the chips wired to the board it
6//! sits on. Three interfaces cover almost everything cheap hardware uses: I2C for the
7//! dense breakout sensors (a BME280, an INA226, an MPU9250, an SSD1306 screen), SPI for
8//! displays, SD cards, and LoRa radios, and plain GPIO pins for the relays, valves,
9//! buttons, and motion sensors that switch a single line. Each carries a small, exact
10//! piece of logic that is pure arithmetic with no hardware attached, and getting it wrong
11//! is a classic field bug: the wrong I2C address byte, the wrong SPI clock mode, or an
12//! active-low relay driven as if it were active-high.
13//!
14//! This crate is that logic, with no pins toggled and no allocation:
15//!
16//! - [`i2c`] - I2C addressing per the NXP I2C-bus specification (UM10204): the 7-bit
17//!   address byte `(address << 1) | r/w`, the two-byte `11110xx` frame for a 10-bit
18//!   address, and the reserved ranges (`0x00..=0x07` and `0x78..=0x7F`) that leave
19//!   `0x08..=0x77` for real devices, so a bad address is caught before it reaches the bus.
20//! - [`spi`] - the four SPI clock [`Mode`](spi::Mode)s as the `(CPOL, CPHA)` pair every
21//!   datasheet quotes, plus bit order, so "mode 3, MSB first" is a checked value rather
22//!   than two booleans a caller can transpose.
23//! - [`pin`] - the GPIO pin model: physical [`Level`](pin::Level), input pull and output
24//!   drive, the interrupt [`Edge`](pin::Edge), and an active-high/active-low
25//!   [`Polarity`](pin::Polarity) that maps a logical "asserted" onto the physical level,
26//!   so an active-low button or relay is handled by the type rather than by remembering
27//!   to invert.
28//!
29//! Everything is exact integer work over `Copy` values, so the same logic runs on the
30//! smallest microcontroller driving the bus. Clocking the bytes and toggling the lines
31//! themselves arrives with the hardware-I/O layer; this is the addressing-and-mode half
32//! ahead of it.
33//!
34//! # Examples
35//!
36//! ```
37//! use pamoja_gpio::i2c::{Address, Direction};
38//! use pamoja_gpio::pin::{Level, Polarity};
39//! use pamoja_gpio::spi::Mode;
40//!
41//! // A DS3231 real-time clock answers at 7-bit address 0x68; its read frame is one byte.
42//! let rtc = Address::seven_bit(0x68)?;
43//! let mut frame = [0u8; 2];
44//! let n = rtc.write_frame(Direction::Read, &mut frame)?;
45//! assert_eq!(&frame[..n], &[0xD1]); // (0x68 << 1) | 1
46//!
47//! // SPI clock mode 0 is the (CPOL, CPHA) pair (false, false), as a datasheet quotes it.
48//! assert_eq!(Mode::Mode0.cpol_cpha(), (false, false));
49//!
50//! // An active-low relay is energised by driving its pin low.
51//! assert_eq!(Polarity::ActiveLow.level(true), Level::Low);
52//! # Ok::<(), pamoja_gpio::GpioError>(())
53//! ```
54
55pub mod i2c;
56pub mod pin;
57pub mod spi;
58
59mod error;
60
61pub use error::GpioError;