pamoja-lorawan 0.1.17

LoRaWAN 1.0.x MAC framing for pamoja: build and parse data-frame PHYPayloads with the message integrity code and payload encryption the spec mandates, plus the over-the-air-activation join exchange, so a long-range node speaks LoRaWAN, no_std and allocation-free. The secured-packet half ahead of the radio driver.
Documentation
#![cfg_attr(not(test), no_std)]

//! LoRaWAN 1.0.x MAC framing for the pamoja SDK.
//!
//! LoRaWAN is how a low-power node reaches a network kilometres away over a license-free
//! radio, which is why it is the SDK's first-class answer for rural and remote reach. The
//! [`pamoja-lora`](https://docs.rs/pamoja-lora) crate gives the link budget, the exact
//! time a transmission spends on air; this crate gives the bytes that go in it: the
//! secured LoRaWAN frame.
//!
//! A LoRaWAN frame is not just a payload with an address. The standard wraps every frame
//! in two cryptographic guarantees, because a long-range public-band link is wide open: a
//! message integrity code keyed to the network proves the frame is authentic and intact,
//! and the payload is encrypted to the application so only its owner can read it. This
//! crate builds and verifies exactly that, with no radio and no allocation:
//!
//! - [`Session`] - an activated device's address and session keys. It [encodes](Session::encode_uplink)
//!   an uplink or downlink data frame, encrypting the payload and appending the MIC, and
//!   [decodes](Session::decode) one received, verifying the MIC before decrypting.
//! - [`Uplink`] and [`Downlink`] - the data frame to send, built up from the fields a
//!   sender sets (confirmed, adaptive data rate, acknowledgement, frame options).
//! - [`RxData`] - a decoded frame: its header fields and its recovered payload.
//! - [`Device`] - the root credentials for over-the-air activation: it builds the
//!   join-request a device broadcasts and turns the network's join-accept into a ready
//!   [`Session`], deriving the session keys the spec prescribes.
//! - [`JoinRequest`] and [`JoinGrant`] - the other half of that exchange, so a deployment
//!   can run its own network instead of joining someone else's: verify the request a
//!   device sent, then grant it an address and sign the reply. Both sides derive the same
//!   session keys from the same nonces, with no key ever on the air.
//! - [`FrameHeader`] - what a frame says about itself before any key is involved: its
//!   message type, the device address, and the counter. A receiver holding many sessions
//!   reads this first to find the one a frame belongs to, then decodes.
//!
//! The cryptography is the LoRaWAN construction over AES-128: an AES-CMAC MIC and an
//! AES keystream for the payload, with the device address and frame counter folded into
//! both so a frame cannot be lifted out of its place in the stream. Driving the radio
//! arrives with the hardware-I/O layer; this is the secured-packet half ahead of it.
//!
//! # Examples
//!
//! ```
//! use pamoja_lorawan::{Session, Uplink};
//!
//! // A node activated with a device address and its two session keys.
//! let session = Session::new(0x2601_1BDA, [0x2B; 16], [0x99; 16]);
//!
//! // Encode a confirmed uplink reading; the payload is encrypted and the MIC appended.
//! let frame = session
//!     .encode_uplink(&Uplink::new(42, 1, b"temp=4.8").confirmed())
//!     .unwrap();
//!
//! // The network, holding the same session, verifies and decrypts it.
//! let rx = session.decode(frame.as_bytes(), 42).unwrap();
//! assert!(rx.confirmed());
//! assert_eq!(rx.payload(), b"temp=4.8");
//! ```

mod crypto;
mod error;
mod frame;
mod header;
mod join;
mod network;
mod session;

pub use error::LorawanError;
pub use frame::{Direction, PhyPayload, MAX_FRAME, MAX_PAYLOAD};
pub use header::{FrameHeader, MessageType};
pub use join::{Device, JoinAccept};
pub use network::{JoinGrant, JoinRequest};
pub use session::{Downlink, RxData, Session, Uplink};