Skip to main content

pamoja_gateway/
lib.rs

1//! LoRaWAN gateway protocols for the pamoja SDK.
2//!
3//! A LoRa gateway is a radio with an uplink: it hears packets from every node in range and
4//! hands them to a network server, which hands back the packets to transmit. The protocol
5//! between the two is not LoRaWAN, which is what the packets themselves carry; it is a
6//! separate, deliberately plain exchange of UDP datagrams, and this crate speaks it from
7//! both sides.
8//!
9//! - [`udp`] - the Semtech packet forwarder protocol: the PUSH_DATA and PULL_DATA datagrams a
10//!   gateway sends, the PUSH_ACK, PULL_ACK and PULL_RESP a server answers with, the TX_ACK
11//!   that reports what became of a downlink, and the `rxpk`, `stat`, `txpk` and `txpk_ack`
12//!   objects they carry.
13//! - [`base64`] - the payload encoding of RFC 4648, padded on the way out and read either
14//!   way on the way in, because gateways in the field send both.
15//! - [`time`] - the two timestamp formats the protocol prescribes, to the microsecond for a
16//!   reception and to the second for a gateway's own clock.
17//! - `network`, with the `network` feature - the network side of one site: admitting a join,
18//!   reading an uplink, and working out where and when to answer it.
19//! - `bridge`, with the `bridge` feature - carrying messages between the radio the nodes are
20//!   on and the link that leaves the site, under a prefix that names the site.
21//! - `daemon`, with the `daemon` feature - what a gateway program is told to do, and the
22//!   order a concentrator is brought up and forwarded from.
23//! - [`station`] - the LoRa Basics Station protocol: the discovery request that finds a
24//!   network server, and the messages the websocket carries once one is open.
25//! - [`chirpstack`] - the uplink events a ChirpStack network server publishes on MQTT, read
26//!   into the device, the payload and the gateways that heard it.
27//!
28//! Every datagram is data: the crate builds and parses them, and leaves the socket, the
29//! keepalive, and the scheduling to the program that owns them.
30//!
31//! # Examples
32//!
33//! A gateway forwards a packet it heard, and the server reads it and acknowledges it.
34//!
35//! ```
36//! use pamoja_gateway::udp::{Eui, Packet, PacketKind, Rxpk, Uplink};
37//! use pamoja_lora::LinkSettings;
38//!
39//! // A gateway names itself by its Ethernet address with FF FE in the middle, written
40//! // the way a network server's console shows it.
41//! let gateway = Eui::from_hex("b827ebfffe010203").expect("sixteen hex digits");
42//!
43//! // What its radio heard: a reading at SF7 on 868.1 MHz, and how strongly it arrived.
44//! let heard = Rxpk::new(868_100_000, LinkSettings::new(7, 125_000), b"21.5".to_vec())
45//!     .with_rssi_dbm(-35)
46//!     .with_snr_db(5.1);
47//!
48//! // It forwards the packet with a token of its choosing, which the answer carries back.
49//! let forwarded = Packet::PushData {
50//!     token: 1,
51//!     gateway,
52//!     uplink: Uplink::from(heard),
53//! };
54//! let datagram = forwarded.to_bytes();
55//!
56//! // The server reads back exactly what was sent: who sent it, and what was heard.
57//! let received = Packet::parse(&datagram).expect("a well-formed datagram");
58//! assert_eq!(received, forwarded);
59//! assert_eq!(received.gateway(), Some(gateway));
60//! if let Packet::PushData { uplink, .. } = &received {
61//!     assert_eq!(uplink.packets[0].frequency_hz, 868_100_000);
62//!     assert_eq!(uplink.packets[0].payload, b"21.5");
63//! }
64//!
65//! // And answers with the acknowledgment the protocol owes it, under the same token.
66//! let ack = received.acknowledgment().expect("a PUSH_DATA is acknowledged");
67//! assert_eq!(ack.kind(), PacketKind::PushAck);
68//! assert_eq!(ack.token(), forwarded.token());
69//! ```
70
71pub mod base64;
72#[cfg(feature = "bridge")]
73pub mod bridge;
74pub mod chirpstack;
75#[cfg(feature = "daemon")]
76pub mod daemon;
77#[cfg(feature = "network")]
78pub mod network;
79pub mod station;
80pub mod time;
81pub mod udp;