pamoja_radios/sx1302.rs
1//! Semtech SX1302 and SX1303 concentrators.
2//!
3//! A transceiver listens to one channel at a time. A concentrator listens to eight at once,
4//! across every spreading factor, which is what separates a gateway from a node. That is also
5//! why it is driven differently: the SX126x and SX127x take commands, while this chip is a
6//! map of registers, most of them a few bits inside a byte shared with their neighbors.
7//!
8//! Nothing works until two microcontrollers inside the chip are given firmware. The gain
9//! control one sets the front end, the arbiter shares the radios between the receivers, and
10//! both come up empty, so a concentrator that has been powered but not loaded reports a
11//! healthy version register and hears nothing at all.
12//!
13//! This module carries that as data:
14//!
15//! - [`spi`] - the transfers the chip answers, byte for byte, and how a long write is split.
16//! - [`register`] - where the blocks are and which bits inside a byte each register owns.
17//! - [`chip`] - the version that says a board is answering, and the part number that says
18//! whether it is an SX1302 or an SX1303.
19//! - [`channel`] - the frequencies the receivers listen on, the spreading factors they
20//! look for, and the order all of that is set in.
21//! - [`firmware`] - the order the two microcontrollers are loaded in, and what to check
22//! afterwards.
23//! - [`mcu`] - configuring those two microcontrollers once they are loaded, which is
24//! the other half of bringing one up.
25//! - [`rx`] - the packets the receive buffer holds, and what the receiver made of each.
26//! - [`tx`] - where a payload is written, how far ahead of its window a send starts, and
27//! the three ways a transmission is triggered.
28//! - [`lbt`] - the commands for the SX1261 beside the concentrator, which listens to a
29//! channel before the gateway is allowed to talk on it.
30//! - [`sx1261`] - bringing that radio up, which has to happen before those commands
31//! mean anything to it.
32//! - [`sx1250`] - the front ends the concentrator listens through, which are what a
33//! carrier is tuned to, and the order one is brought up in.
34//! - [`timestamp`] - the counter packets are stamped against and receive windows are
35//! measured from, and how it is widened past a rollover.
36//! - [`bridge`] - the messages that carry all of the above through the microcontroller on
37//! a USB card, which does the SPI on the host's behalf.
38//!
39//! With the `embedded-hal` feature, the [`Sx1302`] driver walks all of that against a real
40//! bus: it resets the board, reads the version, resets the front ends, and gives each
41//! microcontroller its firmware.
42//!
43//! None of it opens a bus, so a frame can be checked against the reference implementation,
44//! or against a capture from a working gateway, with no hardware present.
45//!
46//! The register map, the transfer framing, and the load sequence follow Semtech's
47//! `sx1302_hal`, which is BSD 3-Clause. The notice is on the
48//! [notices page](https://pamoja.molex.cloud/docs/about/notices.html).
49//!
50//! # Examples
51//!
52//! Asking a board what it is, without a bus in sight.
53//!
54//! ```
55//! use pamoja_radios::sx1302::{chip, register, spi};
56//!
57//! // The version register is read like any other: the target, the register's address
58//! // most significant byte first, a dummy byte, and the byte the chip answers in.
59//! let version = register::COMMON_VERSION.address;
60//! let [high, low] = version.to_be_bytes();
61//! let asked = spi::read(spi::TARGET_CONCENTRATOR, version);
62//! assert_eq!(asked, [spi::TARGET_CONCENTRATOR, high, low, 0, 0]);
63//!
64//! // A concentrator that is powered and wired the right way round answers with one value.
65//! assert!(chip::answers(0x10));
66//! assert!(!chip::answers(0x00));
67//!
68//! // The part number takes two transfers, because it lives in one-time programmable memory.
69//! let [select, read] = chip::identify();
70//! assert_eq!(select, chip::Step::Write(register::OTP_BYTE_ADDR, 0xd0));
71//! assert_eq!(read, chip::Step::Read(register::OTP_RD_DATA));
72//!
73//! assert_eq!(chip::Model::of(0x03), chip::Model::Sx1303);
74//! ```
75
76pub mod bridge;
77pub mod channel;
78pub mod chip;
79pub mod firmware;
80pub mod lbt;
81pub mod mcu;
82pub mod register;
83pub mod rx;
84pub mod spi;
85pub mod sx1250;
86pub mod sx1261;
87pub mod timestamp;
88pub mod tx;
89#[cfg(feature = "std")]
90pub mod usb;
91
92#[cfg(feature = "embedded-hal")]
93mod driver;
94#[cfg(feature = "embedded-hal")]
95mod listener;
96
97#[cfg(feature = "embedded-hal")]
98pub use driver::{
99 ConcentratorError, Sx1302, ABORT_POLLS, RADIO_CALIBRATE_US, RADIO_RESET_HOLD_US,
100 RADIO_RESET_SETTLE_US, RESET_HOLD_US,
101};
102#[cfg(feature = "embedded-hal")]
103pub use listener::{ListenerError, Sx1261, COMMAND_WAIT_US, LISTENER_RESET_US};