pamoja/lib.rs
1//! The whole pamoja device SDK in one crate.
2//!
3//! pamoja is one memory-safe Rust core with a crate per capability, so a build
4//! carries only the crates it names. This crate is the other way in: every
5//! capability sits behind a feature, all on by default, so `cargo add pamoja` is
6//! the whole framework, the way `npm install pamoja`, `pip install pamoja`, and
7//! `dotnet add package Pamoja` are in the bindings.
8//!
9//! Each module re-exports the crate of the same name: `pamoja::codec` is
10//! `pamoja-codec`, `pamoja::mqtt` is `pamoja-mqtt`, and `pamoja::core` is
11//! `pamoja-core`, the traits every capability implements. The types, the
12//! documentation, and the examples are those of the crate, so code moves between
13//! `use pamoja::codec::CborCodec` and `use pamoja_codec::CborCodec` with no other change.
14//!
15//! ```toml
16//! [dependencies]
17//! pamoja = "0.1"
18//! ```
19//!
20//! A build that needs only some capabilities names them, and takes on only
21//! their dependencies:
22//!
23//! ```toml
24//! [dependencies]
25//! pamoja = { version = "0.1", default-features = false, features = ["std", "codec", "security"] }
26//! ```
27//!
28//! # Example
29//!
30//! A reading taken off a wire, smoothed, packed for a metered link, and signed so
31//! the gateway that receives it can tell which device sent it, with nothing plugged
32//! in:
33//!
34//! ```
35//! use pamoja::codec::{decode_deltas, encode_deltas};
36//! use pamoja::kit::Smoother;
37//! use pamoja::security::{DeviceIdentity, PublicIdentity};
38//! use pamoja::sensors::ds18b20::{temperature_from_celsius, Resolution, Scratchpad};
39//!
40//! // A stand-in for the thermometer. On a running node these nine bytes arrive from
41//! // the 1-Wire bus; here the library builds what a part at 25.0625 C would send.
42//! let off_the_bus = Scratchpad::new(
43//! temperature_from_celsius(25.0625, Resolution::Bits12),
44//! Resolution::Bits12,
45//! 75,
46//! -10,
47//! )
48//! .to_bytes();
49//!
50//! // The part checksums every read, so a value mangled on a long run is an error
51//! // rather than a plausible temperature a couple of degrees off.
52//! let celsius = Scratchpad::parse(&off_the_bus)
53//! .expect("the checksum matches")
54//! .temperature_celsius();
55//! assert_eq!(celsius, 25.0625);
56//!
57//! // Readings jitter, so smooth them and send a batch rather than one at a time.
58//! let mut smoother = Smoother::new(0.5);
59//! let batch: Vec<i64> = [celsius, celsius + 0.5, celsius + 0.4]
60//! .into_iter()
61//! .map(|sample| (smoother.update(sample) * 100.0).round() as i64)
62//! .collect();
63//! let packed = encode_deltas(&batch);
64//! assert!(packed.len() < batch.len() * 8);
65//!
66//! // Sign the batch. The signature travels with the payload as one message, so a
67//! // gateway holding only the public key gets the payload back once it checks out.
68//! let device = DeviceIdentity::from_seed(&[7u8; 32]);
69//! let message = device.sign_message(&packed);
70//!
71//! let known = PublicIdentity::from_bytes(&device.public().to_bytes())?;
72//! let payload = known.verify_message(&message)?;
73//! assert_eq!(decode_deltas(payload).expect("a valid batch"), batch);
74//! # Ok::<(), pamoja::core::Error>(())
75//! ```
76//!
77//! # Features
78//!
79//! One feature per capability, named as its crate is without the prefix, and all
80//! on by default:
81//!
82//! | Feature | Module | Crate |
83//! | --- | --- | --- |
84//! | (always) | `pamoja::core` | [pamoja-core](https://docs.rs/pamoja-core) |
85//! | `security` | `pamoja::security` | [pamoja-security](https://docs.rs/pamoja-security) |
86//! | `codec` | `pamoja::codec` | [pamoja-codec](https://docs.rs/pamoja-codec) |
87//! | `kit` | `pamoja::kit` | [pamoja-kit](https://docs.rs/pamoja-kit) |
88//! | `serial` | `pamoja::serial` | [pamoja-serial](https://docs.rs/pamoja-serial) |
89//! | `modbus` | `pamoja::modbus` | [pamoja-modbus](https://docs.rs/pamoja-modbus) |
90//! | `can` | `pamoja::can` | [pamoja-can](https://docs.rs/pamoja-can) |
91//! | `gpio` | `pamoja::gpio` | [pamoja-gpio](https://docs.rs/pamoja-gpio) |
92//! | `sensors` | `pamoja::sensors` | [pamoja-sensors](https://docs.rs/pamoja-sensors) |
93//! | `actuators` | `pamoja::actuators` | [pamoja-actuators](https://docs.rs/pamoja-actuators) |
94//! | `lora` | `pamoja::lora` | [pamoja-lora](https://docs.rs/pamoja-lora) |
95//! | `lorawan` | `pamoja::lorawan` | [pamoja-lorawan](https://docs.rs/pamoja-lorawan) |
96//! | `mesh` | `pamoja::mesh` | [pamoja-mesh](https://docs.rs/pamoja-mesh) |
97//! | `routing` | `pamoja::routing` | [pamoja-routing](https://docs.rs/pamoja-routing) |
98//! | `mavlink` | `pamoja::mavlink` | [pamoja-mavlink](https://docs.rs/pamoja-mavlink) |
99//! | `audit` | `pamoja::audit` | [pamoja-audit](https://docs.rs/pamoja-audit) |
100//! | `session` | `pamoja::session` | [pamoja-session](https://docs.rs/pamoja-session) |
101//! | `update` | `pamoja::update` | [pamoja-update](https://docs.rs/pamoja-update) |
102//! | `power` | `pamoja::power` | [pamoja-power](https://docs.rs/pamoja-power) |
103//! | `telemetry` | `pamoja::telemetry` | [pamoja-telemetry](https://docs.rs/pamoja-telemetry) |
104//! | `mqtt` | `pamoja::mqtt` | [pamoja-mqtt](https://docs.rs/pamoja-mqtt) |
105//! | `coap` | `pamoja::coap` | [pamoja-coap](https://docs.rs/pamoja-coap) |
106//! | `loopback` | `pamoja::loopback` | [pamoja-loopback](https://docs.rs/pamoja-loopback) |
107//! | `sync` | `pamoja::sync` | [pamoja-sync](https://docs.rs/pamoja-sync) |
108//! | `ladder` | `pamoja::ladder` | [pamoja-ladder](https://docs.rs/pamoja-ladder) |
109//! | `bus` | `pamoja::bus` | [pamoja-bus](https://docs.rs/pamoja-bus) |
110//! | `sim` | `pamoja::sim` | [pamoja-sim](https://docs.rs/pamoja-sim) |
111//! | `profile` | `pamoja::profile` | [pamoja-profile](https://docs.rs/pamoja-profile) |
112//! | `ros2` | `pamoja::ros2` | [pamoja-ros2](https://docs.rs/pamoja-ros2) |
113//! | `zenoh` | `pamoja::zenoh` | [pamoja-zenoh](https://docs.rs/pamoja-zenoh) |
114//! | `dashboard` (off by default) | `pamoja::dashboard` | [pamoja-dashboard](https://docs.rs/pamoja-dashboard) |
115//!
116//! Six of those capabilities' chapters hold more than one capability, and each has a
117//! feature that turns on exactly its own, so a build can name a domain instead of listing
118//! its parts. They are checked against the capability map, so a new capability cannot fall
119//! out of its group:
120//!
121//! | Group feature | Turns on |
122//! | --- | --- |
123//! | `field-io` | `serial`, `modbus`, `can`, `gpio` |
124//! | `sensing` | `sensors`, `actuators` |
125//! | `radio` | `lora`, `lorawan`, `mesh`, `routing` |
126//! | `trust` | `audit`, `session`, `update`, `power`, `telemetry` |
127//! | `transports` | `mqtt`, `coap`, `loopback`, `sync`, `ladder`, `bus`, `sim` |
128//! | `profiles` | `profile`, `ros2`, `zenoh` |
129//!
130//! ```toml
131//! [dependencies]
132//! pamoja = { version = "0.1", default-features = false, features = ["std", "field-io"] }
133//! ```
134//!
135//! `std`, on by default, turns on the standard-library layer of the crates that
136//! have one (`pamoja-core`, `pamoja-lora`, `pamoja-mavlink`) and implies `alloc`,
137//! which adds the owned channel plans, tables, and message shapes of `pamoja-lora`,
138//! `pamoja-mesh`, `pamoja-routing`, and `pamoja-mavlink`. With both off and only
139//! `no_std` capabilities named, the crate builds for a bare-metal target; CI
140//! compiles it for `thumbv7em-none-eabihf`. The crates keep their finer switches
141//! (the LoRa region set, the kit's helper groups, the MAVLink serial driver), so
142//! depend on the crate itself when you need one of those. `dashboard` adds the
143//! fleet dashboard, a web server, and is off by default.
144
145#![no_std]
146
147pub use pamoja_core as core;
148
149#[cfg(feature = "actuators")]
150pub use pamoja_actuators as actuators;
151#[cfg(feature = "audit")]
152pub use pamoja_audit as audit;
153#[cfg(feature = "bus")]
154pub use pamoja_bus as bus;
155#[cfg(feature = "can")]
156pub use pamoja_can as can;
157#[cfg(feature = "coap")]
158pub use pamoja_coap as coap;
159#[cfg(feature = "codec")]
160pub use pamoja_codec as codec;
161#[cfg(feature = "dashboard")]
162pub use pamoja_dashboard as dashboard;
163#[cfg(feature = "gpio")]
164pub use pamoja_gpio as gpio;
165#[cfg(feature = "kit")]
166pub use pamoja_kit as kit;
167#[cfg(feature = "ladder")]
168pub use pamoja_ladder as ladder;
169#[cfg(feature = "loopback")]
170pub use pamoja_loopback as loopback;
171#[cfg(feature = "lora")]
172pub use pamoja_lora as lora;
173#[cfg(feature = "lorawan")]
174pub use pamoja_lorawan as lorawan;
175#[cfg(feature = "mavlink")]
176pub use pamoja_mavlink as mavlink;
177#[cfg(feature = "mesh")]
178pub use pamoja_mesh as mesh;
179#[cfg(feature = "modbus")]
180pub use pamoja_modbus as modbus;
181#[cfg(feature = "mqtt")]
182pub use pamoja_mqtt as mqtt;
183#[cfg(feature = "power")]
184pub use pamoja_power as power;
185#[cfg(feature = "profile")]
186pub use pamoja_profile as profile;
187#[cfg(feature = "ros2")]
188pub use pamoja_ros2 as ros2;
189#[cfg(feature = "routing")]
190pub use pamoja_routing as routing;
191#[cfg(feature = "security")]
192pub use pamoja_security as security;
193#[cfg(feature = "sensors")]
194pub use pamoja_sensors as sensors;
195#[cfg(feature = "serial")]
196pub use pamoja_serial as serial;
197#[cfg(feature = "session")]
198pub use pamoja_session as session;
199#[cfg(feature = "sim")]
200pub use pamoja_sim as sim;
201#[cfg(feature = "sync")]
202pub use pamoja_sync as sync;
203#[cfg(feature = "telemetry")]
204pub use pamoja_telemetry as telemetry;
205#[cfg(feature = "update")]
206pub use pamoja_update as update;
207#[cfg(feature = "zenoh")]
208pub use pamoja_zenoh as zenoh;