pamoja_hal/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2
3//! The bus layer for the pamoja SDK.
4//!
5//! Every part a node talks to sits on a bus: I2C for the dense breakout sensors, SPI
6//! for displays and radios, a GPIO line for a relay or a button, 1-Wire for a
7//! waterproof thermometer on a long cable. The drivers in
8//! [`pamoja-sensors`](https://docs.rs/pamoja-sensors) and
9//! [`pamoja-actuators`](https://docs.rs/pamoja-actuators) are written against traits
10//! rather than against a board, and this crate is where those traits come from and
11//! where the buses that implement them live:
12//!
13//! - [`i2c`], [`spi`], [`digital`], and [`delay`] are the `embedded-hal` 1.0 traits,
14//! re-exported so a driver and the code that opens its bus name one thing. Any HAL
15//! that implements them drives every pamoja part unchanged: `embassy-rp` on an
16//! RP2040, `esp-hal` on an ESP32, the Linux backends below on a Raspberry Pi.
17//! - [`onewire`] is the bus `embedded-hal` does not define: the 1-Wire protocol a
18//! DS18B20 speaks, bit-banged over any open-drain pin and a delay, with the reset
19//! and presence handshake, the ROM commands, and the search that enumerates a bus.
20//! - [`script`] plays a part's side of a conversation: an I2C bus that checks each
21//! transfer against a script and answers with the bytes a real part would send, a
22//! pin that records what it was driven to, and a delay that records how long it was
23//! asked to wait. A driver is tested against the datasheet's own sequence with
24//! nothing plugged in.
25//! - [`sim`] is a part that is not there, answering from a register map in whatever
26//! order a driver reads and writes it, so a driver runs before the hardware arrives.
27//! - `linux` (feature `linux`, Linux only) opens the kernel's `/dev/i2c-*`,
28//! `/dev/spidev*`, and GPIO character devices as those same traits, so a gateway
29//! reads a sensor with one call and no glue.
30//! - `bus` (feature `std`) is one I2C bus that a program and every driver on it share,
31//! over the kernel's adapter, simulated parts, or a script, with a delay that sleeps
32//! only when real parts are on the other end. It is what a language binding hands a
33//! driver.
34//! - `port` (feature `std`) is one serial port shared the same way, over the kernel's
35//! serial device, a looped line, a null-modem pair, a simulated device, or a script,
36//! with reads that wait for real bytes and only count the wait anywhere else.
37//!
38//! # Examples
39//!
40//! A script stands in for a BME280 answering the first thing a driver asks it: its chip
41//! id, which register `0xD0` holds as `0x60` on every BME280 (datasheet section 5.4.1).
42//! A driver that asked for anything else would be refused with the transfer the part
43//! expected.
44//!
45//! ```
46//! use pamoja_hal::i2c::I2c;
47//! use pamoja_hal::script::{I2cScript, I2cStep};
48//!
49//! const BME280: u8 = 0x76;
50//! const CHIP_ID_REGISTER: u8 = 0xD0;
51//! const BME280_CHIP_ID: u8 = 0x60;
52//!
53//! let mut bus = I2cScript::new([I2cStep::write_read(
54//! BME280,
55//! [CHIP_ID_REGISTER],
56//! [BME280_CHIP_ID],
57//! )]);
58//! let mut id = [0u8; 1];
59//! bus.write_read(BME280, &[CHIP_ID_REGISTER], &mut id)?;
60//! assert_eq!(id, [BME280_CHIP_ID]);
61//! assert!(bus.done(), "every transfer the part expected has happened");
62//! # Ok::<(), pamoja_hal::script::ScriptError>(())
63//! ```
64
65#[cfg(feature = "alloc")]
66extern crate alloc;
67
68pub use embedded_hal;
69pub use embedded_hal::{delay, digital, i2c, spi};
70
71#[cfg(feature = "std")]
72pub mod bus;
73#[cfg(all(feature = "linux", target_os = "linux"))]
74pub mod linux;
75pub mod onewire;
76#[cfg(feature = "std")]
77pub mod port;
78#[cfg(feature = "alloc")]
79pub mod script;
80pub mod sim;