pamoja_lorawan/device/mod.rs
1//! A LoRaWAN Class A end device, without a radio.
2//!
3//! [`EndDevice`] is what a node runs to take part in a network: it joins, chooses a channel
4//! and data rate for each uplink, says when and where to listen for the answer, reads what
5//! comes back, and does what the network's MAC commands ask. It owns no radio and no clock.
6//! Every step takes the time in microseconds and hands back what to put on the air, so the
7//! same logic drives an SX1276 on a microcontroller, an SX1262 on a Linux board, or a test
8//! with no hardware at all.
9//!
10//! One exchange runs like this:
11//!
12//! 1. [`join`](EndDevice::join) or [`send`](EndDevice::send) returns a [`Transmission`]:
13//! the frame, the carrier, the link, the power, and the two receive windows, each timed
14//! from the end of the transmission.
15//! 2. The radio sends it, then listens in the first window and, if nothing for this device
16//! arrived, in the second.
17//! 3. A frame heard in either window goes to [`heard_in`](EndDevice::heard_in), which knows
18//! the window, or to [`heard`](EndDevice::heard). If neither window held one,
19//! [`nothing_heard`](EndDevice::nothing_heard) says whether to send the same frame again,
20//! with [`repeat`](EndDevice::repeat), or move on.
21//!
22//! What it follows, and from where:
23//!
24//! - **Receive windows**: TS001-1.0.4 section 3.3 and RP002-1.0.5 section 3.3, one second and
25//! two after an uplink and five and six after a join request unless the network moves them.
26//! - **Channels and data rates**: the region's plan from `pamoja-lora`, a join accept's
27//! channel list, and `LinkADRReq`, `NewChannelReq` and `DlChannelReq`. A fixed plan answers
28//! each channel on the downlink channel it names, and reads `ChMaskCntl` by its own table.
29//! - **Joining**: a random join channel with the data rate stepping down across attempts, or
30//! on US902-928 and AU915-928 the passes of RP002-1.0.5 section 3.5.2, eight 125 kHz
31//! channels from successive groups and then a 500 kHz one. On CN470-510 the common join
32//! channel that answered puts the device on its plan, section 3.9.2.
33//! - **MAC commands**: every command of TS001-1.0.4 section 5 a device receives, answered in
34//! order, with the four that change how it listens repeated until a downlink arrives.
35//! - **Downlinks**: TS001-1.0.4 section 4, with a frame whose MACPayload is longer than the
36//! receive window's data rate carries discarded, and a repeated counter ignored.
37//! - **Repetition**: NbTrans transmissions of each uplink, stopped by any Class A downlink,
38//! and a retransmission timeout before the next uplink whenever a confirmed one went
39//! unacknowledged.
40//! - **Staying reachable**: the adaptive data rate back-off of [`adr`](crate::adr).
41//! - **Sharing the air**: the region's sub-band duty cycles, the network's `DutyCycleReq`,
42//! and the join back-off of TS001-1.0.4 section 7.
43//! - **Sleeping**: [`save`](EndDevice::save) and [`resume`](EndDevice::resume) carry a joined
44//! device across a loss of power, so a node that sleeps between readings keeps its session,
45//! its counters and everything its network set.
46//! - **Out of a gateway's reach**: [`use_relay`](EndDevice::use_relay) sends through a
47//! LoRaWAN relay, TS011-1.0.1. Each uplink then goes out behind a wake-on-radio frame,
48//! [`Transmission::relay`] says when and with how long a preamble, and a third receive
49//! window carries what the relay forwards back.
50//!
51//! This covers every published plan: the dynamic EU868, EU433, AS923, KR920, IN865 and RU864,
52//! and the fixed US915, AU915 and CN470, the last in all four of its RP002-1.0.5 plans and the
53//! 96-channel plan before them. KR920, CN470, and AS923 where ARIB STD-T108 applies also
54//! require listening before talking, which is the radio's to do.
55//!
56//! # Examples
57//!
58//! A device joins a European network the test plays the part of:
59//!
60//! ```
61//! use pamoja_lora::region::Region;
62//! use pamoja_lorawan::device::{EndDevice, Heard, Settings};
63//! use pamoja_lorawan::{Device, JoinGrant};
64//!
65//! const APP_KEY: [u8; 16] = [0x2B; 16];
66//! let credentials = Device::new([0x11; 8], [0x22; 8], APP_KEY);
67//! let mut device = EndDevice::new(Region::Eu868.plan(), credentials, Settings::new(2, 14))?;
68//!
69//! // The request goes out on a European default channel, and the answer is due five and
70//! // six seconds after it.
71//! let request = device.join(1, 0)?;
72//! assert!([868_100_000, 868_300_000, 868_500_000].contains(&request.frequency_hz));
73//! assert_eq!(request.rx1.delay_us, 5_000_000);
74//! assert_eq!(request.rx2.frequency_hz, 869_525_000);
75//!
76//! // The network's accept arrives in the first window.
77//! let accept = JoinGrant::new(0x01, 0x13, 0x2601_2E43).accept(&APP_KEY, 1);
78//! let heard = device.heard(accept.as_bytes(), 7)?;
79//! assert_eq!(heard, Heard::Joined { dev_addr: 0x2601_2E43 });
80//!
81//! // And the first reading goes out, answered a second after it ends.
82//! let reading = device.send(2, b"21.5", false, 7_000_000)?;
83//! assert_eq!(reading.rx1.delay_us, 1_000_000);
84//! assert!(reading.carries_payload);
85//! # Ok::<(), pamoja_lorawan::device::DeviceError>(())
86//! ```
87
88mod air;
89mod answers;
90mod channels;
91mod commands;
92mod relayed;
93mod state;
94
95pub use channels::{Channel, MAX_CHANNELS};
96pub use relayed::{AckWindow, RelayExchange, RelayStatus, WakeUp, WorNext};
97pub use state::{Saved, StateError, SAVED_LEN};
98
99use pamoja_lora::region::{ChannelBlock, ChannelPlan, JoinSequence, Modulation, PowerReference};
100use pamoja_lora::LinkSettings;
101
102use crate::adr::{Backoff, Standing, Step};
103use crate::defaults::{
104 JOIN_ACCEPT_DELAY1_US, JOIN_ACCEPT_DELAY2_US, MAX_FCNT_GAP, RECEIVE_DELAY1_US,
105 RETRANSMIT_TIMEOUT_MAX_US, RETRANSMIT_TIMEOUT_MIN_US,
106};
107use crate::mac::{MacCommand, FOPTS_MAX};
108use crate::relay::{smart_enable_uplinks, Carrier, RelayState};
109use crate::{
110 Device, FrameHeader, LorawanError, MessageType, PhyPayload, Session, Uplink, Version,
111 MAX_PAYLOAD,
112};
113use air::{Air, Sequence, MAX_SUB_BANDS};
114use answers::Answers;
115use channels::{Channels, MASK_GROUPS};
116use relayed::Relayed;
117
118/// How long a transmission may hold a channel under a dwell time limit, from RP002-1.0.5
119/// section 3.3 and TS001-1.0.4 table 49.
120const DWELL_LIMIT_US: u64 = 400_000;
121
122/// What a device's radio can do, and how it takes part.
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124pub struct Settings {
125 version: Version,
126 adr: bool,
127 min_output_dbm: i8,
128 max_output_dbm: i8,
129 antenna_gain_db: i8,
130 lowest_hz: u32,
131 highest_hz: u32,
132 regional_duty_cycle: bool,
133 behind_repeater: bool,
134 crystal_ppm: u32,
135 seed: u32,
136}
137
138impl Settings {
139 /// Settings for a radio with an output power range.
140 ///
141 /// The rest start as a typical node: TS001-1.0.4, adaptive data rate on, an antenna
142 /// with no gain over its cable, a radio that tunes 137 to 1020 MHz as an SX1276 does,
143 /// the region's duty cycle kept, and no repeater in the path.
144 ///
145 /// # Arguments
146 ///
147 /// * `min_output_dbm` - the lowest power the radio puts out, conducted.
148 /// * `max_output_dbm` - the highest, conducted.
149 ///
150 /// # Returns
151 ///
152 /// The settings.
153 pub const fn new(min_output_dbm: i8, max_output_dbm: i8) -> Settings {
154 Settings {
155 version: Version::V1_0_4,
156 adr: true,
157 min_output_dbm,
158 max_output_dbm,
159 antenna_gain_db: 0,
160 lowest_hz: 137_000_000,
161 highest_hz: 1_020_000_000,
162 regional_duty_cycle: true,
163 behind_repeater: false,
164 crystal_ppm: 20,
165 seed: 0,
166 }
167 }
168
169 /// Sets how far the device's own clock may drift.
170 ///
171 /// It decides how much preamble a wake-on-radio frame needs to still cover a relay's
172 /// scan, TS011-1.0.1 appendix 1. The default is the 20 parts per million of a typical
173 /// temperature-compensated crystal.
174 ///
175 /// # Arguments
176 ///
177 /// * `crystal_ppm` - the accuracy in parts per million.
178 ///
179 /// # Returns
180 ///
181 /// The settings.
182 pub const fn with_crystal_ppm(mut self, crystal_ppm: u32) -> Settings {
183 self.crystal_ppm = crystal_ppm;
184 self
185 }
186
187 /// Follows another revision of the link layer.
188 ///
189 /// # Arguments
190 ///
191 /// * `version` - the revision the network was told this device follows.
192 ///
193 /// # Returns
194 ///
195 /// The settings.
196 pub const fn with_version(mut self, version: Version) -> Settings {
197 self.version = version;
198 self
199 }
200
201 /// Turns adaptive data rate on or off.
202 ///
203 /// With it on, the device sets the ADR bit, takes the data rate and power the network
204 /// chooses, and backs off when the network goes quiet. With it off, the device keeps its
205 /// own data rate and TS001-1.0.4 section 5.2 lets it accept a `LinkADRReq` one field at
206 /// a time.
207 ///
208 /// # Arguments
209 ///
210 /// * `adr` - whether the network manages the data rate.
211 ///
212 /// # Returns
213 ///
214 /// The settings.
215 pub const fn with_adr(mut self, adr: bool) -> Settings {
216 self.adr = adr;
217 self
218 }
219
220 /// Accounts for the antenna and its feed.
221 ///
222 /// Most regions limit radiated power, so a device with a 3 dBi antenna puts out 3 dB less
223 /// than one with a 0 dBi antenna to radiate the same. US902-928 limits conducted power
224 /// instead, and only the gain above the 6 dBi its limit allows for comes off.
225 ///
226 /// # Arguments
227 ///
228 /// * `gain_db` - the antenna gain less the cable and connector losses, in dB.
229 ///
230 /// # Returns
231 ///
232 /// The settings.
233 pub const fn with_antenna_gain(mut self, gain_db: i8) -> Settings {
234 self.antenna_gain_db = gain_db;
235 self
236 }
237
238 /// Sets the frequencies the radio and its front end can use.
239 ///
240 /// A network that asks for a channel or a receive window outside them is told so.
241 ///
242 /// # Arguments
243 ///
244 /// * `lowest_hz` - the lowest usable frequency.
245 /// * `highest_hz` - the highest.
246 ///
247 /// # Returns
248 ///
249 /// The settings.
250 pub const fn with_tuning_range(mut self, lowest_hz: u32, highest_hz: u32) -> Settings {
251 self.lowest_hz = lowest_hz;
252 self.highest_hz = highest_hz;
253 self
254 }
255
256 /// Stops holding the device to the region's sub-band duty cycles.
257 ///
258 /// The regional tables report a limit rather than enforce one, because the operator is
259 /// the one who knows whether a regulation applies where the device stands. The network's
260 /// `DutyCycleReq` and the join back-off still hold.
261 ///
262 /// # Returns
263 ///
264 /// The settings.
265 pub const fn without_regional_duty_cycle(mut self) -> Settings {
266 self.regional_duty_cycle = false;
267 self
268 }
269
270 /// Sizes payloads for a path through a relay, which costs a few bytes of each frame.
271 ///
272 /// # Returns
273 ///
274 /// The settings.
275 pub const fn behind_repeater(mut self) -> Settings {
276 self.behind_repeater = true;
277 self
278 }
279
280 /// Seeds the device's random choices of channel and retry delay.
281 ///
282 /// The device identifier is mixed in, so devices given the same seed still differ.
283 ///
284 /// # Arguments
285 ///
286 /// * `seed` - any value, ideally from a hardware random source.
287 ///
288 /// # Returns
289 ///
290 /// The settings.
291 pub const fn with_seed(mut self, seed: u32) -> Settings {
292 self.seed = seed;
293 self
294 }
295
296 /// Reports whether the radio can tune a frequency.
297 pub(crate) const fn usable(&self, hz: u32) -> bool {
298 hz >= 100_000_000 && hz >= self.lowest_hz && hz <= self.highest_hz
299 }
300}
301
302/// How a device reports its battery when a network asks.
303#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
304pub enum Battery {
305 /// Running from an external supply.
306 External,
307 /// A level from 1, empty, to 254, full. Values outside that range are clamped into it.
308 Level(u8),
309 /// The device cannot measure it.
310 #[default]
311 Unknown,
312}
313
314impl Battery {
315 /// The byte `DevStatusAns` carries, from TS001-1.0.4 table 32.
316 const fn code(self) -> u8 {
317 match self {
318 Battery::External => 0,
319 Battery::Level(level) => {
320 if level == 0 {
321 1
322 } else if level == 255 {
323 254
324 } else {
325 level
326 }
327 }
328 Battery::Unknown => 255,
329 }
330 }
331}
332
333/// A frame to put on the air, and where to listen afterward.
334#[derive(Clone, Copy, Debug, PartialEq, Eq)]
335pub struct Transmission {
336 /// The frame.
337 pub frame: PhyPayload,
338 /// The carrier, in hertz.
339 pub frequency_hz: u32,
340 /// The data rate, as the region numbers them.
341 pub data_rate: u8,
342 /// The LoRa settings that data rate stands for: an eight-symbol preamble, an explicit
343 /// header and a payload CRC, sent with standard IQ.
344 pub link: LinkSettings,
345 /// The power to ask of the radio, conducted, with the antenna gain taken off as the
346 /// region's power limit requires.
347 pub output_dbm: i8,
348 /// How long the frame holds the air, in microseconds.
349 pub airtime_us: u64,
350 /// The first receive window.
351 pub rx1: Window,
352 /// The second, which opens only if nothing for this device arrived in the first.
353 pub rx2: Window,
354 /// Whether the application payload went out in this frame.
355 ///
356 /// It is held back when the answers a device owes the network do not leave room for
357 /// it, since TS001-1.0.4 table 15 sends answers first. Send it again afterward.
358 pub carries_payload: bool,
359 /// The wake-on-radio exchange that goes ahead of this frame under a relay, and the
360 /// window a forwarded downlink comes back in.
361 ///
362 /// With it, the frame goes out at
363 /// [`uplink_start_us`](RelayExchange::uplink_start_us) rather than straight away, and
364 /// the two windows above are still timed from the end of it.
365 pub relay: Option<RelayExchange>,
366}
367
368/// When and where to listen for a downlink.
369#[derive(Clone, Copy, Debug, PartialEq, Eq)]
370pub struct Window {
371 /// How long after the end of the transmission the window opens, in microseconds.
372 pub delay_us: u32,
373 /// The carrier, in hertz.
374 pub frequency_hz: u32,
375 /// The downlink data rate, as the region numbers them.
376 pub data_rate: u8,
377 /// The LoRa settings to listen with: no payload CRC, and inverted IQ, as RP002-1.0.5
378 /// table 112 has for a downlink.
379 pub link: LinkSettings,
380}
381
382/// Which receive window a frame arrived in.
383#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
384pub enum ReceiveWindow {
385 /// The first window, on the uplink's downlink channel.
386 Rx1,
387 /// The second, on the fixed frequency and data rate.
388 Rx2,
389 /// The relay window, which a device under a relay opens last when neither of the other
390 /// two held a downlink for it, TS011-1.0.1 chapter 7.
391 Rxr,
392}
393
394/// What a frame heard in a receive window turned out to be.
395// The delivery holds its payload inline, since the crate runs without an allocator.
396#[allow(clippy::large_enum_variant)]
397#[derive(Clone, Copy, Debug, PartialEq, Eq)]
398pub enum Heard {
399 /// A join accept: the device is on the network.
400 Joined {
401 /// The address the network gave it.
402 dev_addr: u32,
403 },
404 /// A data frame for this device.
405 Data(Delivery),
406}
407
408/// A downlink, read and acted on.
409#[derive(Clone, Copy, Debug, PartialEq, Eq)]
410pub struct Delivery {
411 port: Option<u8>,
412 payload: [u8; MAX_PAYLOAD],
413 len: usize,
414 acknowledged: bool,
415 confirmed: bool,
416 more_pending: bool,
417 link_check: Option<LinkCheck>,
418 device_time: Option<DeviceTime>,
419}
420
421impl Delivery {
422 /// Returns the application port the payload arrived on.
423 ///
424 /// # Returns
425 ///
426 /// The port, or `None` for a frame that carried only MAC commands or nothing.
427 pub fn port(&self) -> Option<u8> {
428 self.port
429 }
430
431 /// Returns the application payload, decrypted.
432 ///
433 /// # Returns
434 ///
435 /// The bytes, empty when the frame carried none for the application.
436 pub fn payload(&self) -> &[u8] {
437 &self.payload[..self.len]
438 }
439
440 /// Reports whether the network acknowledged the confirmed uplink this answered.
441 ///
442 /// # Returns
443 ///
444 /// `true` for an acknowledgment of a confirmed uplink.
445 pub fn acknowledged(&self) -> bool {
446 self.acknowledged
447 }
448
449 /// Reports whether the network asked for this downlink to be acknowledged.
450 ///
451 /// The device sets the acknowledgment on its next uplink by itself. A device with
452 /// nothing to send soon can send an empty frame with
453 /// [`send_empty`](EndDevice::send_empty).
454 ///
455 /// # Returns
456 ///
457 /// `true` for a confirmed downlink.
458 pub fn confirmed(&self) -> bool {
459 self.confirmed
460 }
461
462 /// Reports whether the network has more waiting.
463 ///
464 /// TS001-1.0.4 section 4.3.1.4 lets the device send an uplink as soon as it can to
465 /// collect it.
466 ///
467 /// # Returns
468 ///
469 /// The FPending bit.
470 pub fn more_pending(&self) -> bool {
471 self.more_pending
472 }
473
474 /// Returns the answer to a link check the device asked for.
475 ///
476 /// # Returns
477 ///
478 /// The margin and gateway count, when the downlink carried them.
479 pub fn link_check(&self) -> Option<LinkCheck> {
480 self.link_check
481 }
482
483 /// Returns the answer to a time request the device asked for.
484 ///
485 /// # Returns
486 ///
487 /// The network's time, when the downlink carried it.
488 pub fn device_time(&self) -> Option<DeviceTime> {
489 self.device_time
490 }
491}
492
493/// How well the network heard a link check.
494#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
495pub struct LinkCheck {
496 /// How far above the demodulation floor the best gateway heard it, in dB.
497 pub margin_db: u8,
498 /// How many gateways heard it.
499 pub gateways: u8,
500}
501
502/// The time a network gave a device.
503#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
504pub struct DeviceTime {
505 /// Whole seconds since the GPS epoch, 1980-01-06 00:00:00 UTC, at the end of the uplink
506 /// that asked.
507 pub gps_seconds: u32,
508 /// The fraction of a second, in 256ths.
509 pub fraction: u8,
510}
511
512/// What to do once both receive windows have closed with nothing for the device.
513#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
514pub enum Next {
515 /// Send the same frame again with [`repeat`](EndDevice::repeat), no sooner than this.
516 Repeat {
517 /// The earliest time to send it, in the caller's microseconds.
518 not_before_us: u64,
519 },
520 /// The uplink is finished.
521 Done,
522 /// A confirmed uplink went out every time it may without an acknowledgment.
523 Unacknowledged,
524 /// The join got no answer; join again with a new nonce, no sooner than this.
525 JoinAgain {
526 /// The earliest time to try, in the caller's microseconds.
527 not_before_us: u64,
528 },
529}
530
531/// Why a device could not do what it was asked.
532#[derive(Clone, Copy, Debug, PartialEq, Eq)]
533pub enum DeviceError {
534 /// The plan defines more channels than a device keeps.
535 TooManyChannels {
536 /// The most a device keeps, [`MAX_CHANNELS`].
537 max: usize,
538 },
539 /// A device activated by personalization has nothing to join with.
540 NoCredentials,
541 /// The device has not joined.
542 NotJoined,
543 /// A transmission is still waiting on its receive windows.
544 Busy,
545 /// There is no transmission waiting on its windows or due to repeat.
546 NothingPending,
547 /// The air is not free until this time, in the caller's microseconds.
548 Wait {
549 /// The earliest time to try again.
550 until_us: u64,
551 },
552 /// No enabled channel carries the data rate, and restoring the defaults did not help.
553 NoChannel,
554 /// The data rate is not a LoRa one this device can send or hear.
555 DataRate(u8),
556 /// The payload does not fit a frame at the current data rate.
557 PayloadTooLong {
558 /// The most the frame can carry, in bytes.
559 max: usize,
560 },
561 /// The uplink frame counter has reached its end, and the device has to join again.
562 CounterExhausted,
563 /// The frame did not decode.
564 Frame(LorawanError),
565 /// The frame is addressed to another device.
566 Foreign,
567 /// The frame repeats or precedes the last downlink the device accepted.
568 Replayed,
569 /// The frame is further ahead of the last downlink than LoRaWAN 1.0.3 lets a device
570 /// follow.
571 CounterGap,
572 /// A join accept carries settings the region does not allow, which RP002-1.0.5 has a
573 /// device ignore.
574 Refused,
575 /// A saved state could not be resumed.
576 State(StateError),
577}
578
579impl core::fmt::Display for DeviceError {
580 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
581 match self {
582 DeviceError::TooManyChannels { max } => {
583 write!(
584 f,
585 "the plan defines more than the {max} channels a device keeps"
586 )
587 }
588 DeviceError::NoCredentials => f.write_str("the device has no keys to join with"),
589 DeviceError::NotJoined => f.write_str("the device has not joined a network"),
590 DeviceError::Busy => f.write_str("a transmission is still waiting on its windows"),
591 DeviceError::NothingPending => f.write_str("nothing is waiting on its windows"),
592 DeviceError::Wait { until_us } => write!(f, "the air is not free until {until_us}"),
593 DeviceError::NoChannel => f.write_str("no enabled channel carries the data rate"),
594 DeviceError::DataRate(rate) => write!(f, "DR{rate} is not a LoRa data rate here"),
595 DeviceError::PayloadTooLong { max } => {
596 write!(f, "the payload does not fit; {max} bytes do")
597 }
598 DeviceError::CounterExhausted => f.write_str("the uplink frame counter is spent"),
599 DeviceError::Frame(error) => write!(f, "the frame did not decode: {error}"),
600 DeviceError::Foreign => f.write_str("the frame is for another device"),
601 DeviceError::Replayed => f.write_str("the frame repeats an earlier downlink"),
602 DeviceError::CounterGap => f.write_str("the frame counter jumped too far ahead"),
603 DeviceError::Refused => f.write_str("the join accept carries settings not allowed"),
604 DeviceError::State(error) => write!(f, "the saved state was not resumed: {error}"),
605 }
606 }
607}
608
609impl core::error::Error for DeviceError {}
610
611impl From<LorawanError> for DeviceError {
612 fn from(error: LorawanError) -> DeviceError {
613 DeviceError::Frame(error)
614 }
615}
616
617/// A transmission that has gone out and is waiting on its windows, or is due to repeat.
618// The frame is kept inline to repeat it byte for byte, with no allocator to box it.
619#[allow(clippy::large_enum_variant)]
620#[derive(Clone, Copy, Debug, PartialEq, Eq)]
621enum Pending {
622 Join {
623 dev_nonce: u16,
624 data_rate: u8,
625 join_channel: u16,
626 },
627 Uplink {
628 frame: PhyPayload,
629 data_rate: u8,
630 confirmed: bool,
631 carries_payload: bool,
632 transmissions_left: u8,
633 windows_closed: bool,
634 not_before_us: u64,
635 windows: Windows,
636 },
637}
638
639/// What a pending uplink's receive windows hold a downlink to.
640#[derive(Clone, Copy, Debug, PartialEq, Eq)]
641struct Windows {
642 rx1_data_rate: u8,
643 rx2_data_rate: u8,
644 rxr_data_rate: Option<u8>,
645 rx2_opens_us: u64,
646}
647
648impl Windows {
649 fn of(transmission: &Transmission, now_us: u64) -> Windows {
650 Windows {
651 rx1_data_rate: transmission.rx1.data_rate,
652 rx2_data_rate: transmission.rx2.data_rate,
653 rxr_data_rate: transmission.relay.map(|relay| relay.rxr.data_rate),
654 rx2_opens_us: now_us
655 .saturating_add(transmission.airtime_us)
656 .saturating_add(u64::from(transmission.rx2.delay_us)),
657 }
658 }
659}
660
661/// A LoRaWAN Class A end device.
662///
663/// See the [module documentation](self) for the exchange it runs.
664pub struct EndDevice<'p> {
665 plan: &'p ChannelPlan<'p>,
666 credentials: Option<Device>,
667 settings: Settings,
668 sequence: Sequence,
669 battery: Battery,
670 session: Option<Session>,
671 joined_on: Option<u16>,
672 fcnt_up: u32,
673 fcnt_down: Option<u32>,
674 data_rate: u8,
675 tx_power: u8,
676 nb_trans: u8,
677 rx1_dr_offset: u8,
678 rx2_frequency_hz: u32,
679 rx2_data_rate: u8,
680 rx1_delay_us: u32,
681 max_eirp_dbm: i8,
682 uplink_dwell: bool,
683 downlink_dwell: bool,
684 max_duty_cycle: u8,
685 channels: Channels,
686 answers: Answers,
687 backoff: Backoff,
688 air: Air,
689 pending: Option<Pending>,
690 ack_owed: bool,
691 joins: u32,
692 join_used: [u16; MASK_GROUPS],
693 join_slot: u32,
694 quiet_until_us: u64,
695 relayed: Relayed,
696}
697
698/// A join channel chosen for one attempt, and how the attempt goes out on it.
699#[derive(Clone, Copy, Debug)]
700struct JoinChoice {
701 number: u16,
702 channel: Channel,
703 data_rate: u8,
704 link: LinkSettings,
705 airtime_us: u64,
706 next_slot: u32,
707 restart_cycle: bool,
708}
709
710impl<'p> EndDevice<'p> {
711 /// A device that joins over the air.
712 ///
713 /// # Arguments
714 ///
715 /// * `plan` - the region's channel plan.
716 /// * `credentials` - the device's identifiers and root key.
717 /// * `settings` - what its radio can do.
718 ///
719 /// # Returns
720 ///
721 /// The device, not yet joined.
722 ///
723 /// # Errors
724 ///
725 /// Returns [`DeviceError::TooManyChannels`] for a plan with more default or join channels
726 /// than [`MAX_CHANNELS`].
727 pub fn new(
728 plan: &'p ChannelPlan<'p>,
729 credentials: Device,
730 settings: Settings,
731 ) -> Result<EndDevice<'p>, DeviceError> {
732 let sequence = Sequence::new(settings.seed, &credentials.dev_eui());
733 EndDevice::build(plan, Some(credentials), sequence, settings)
734 }
735
736 /// A device activated by personalization, with its session provisioned.
737 ///
738 /// Such a device never resets its frame counters, TS001-1.0.4 section 4.3.1.5, so a
739 /// device that loses power carries them over with
740 /// [`with_frame_counters`](EndDevice::with_frame_counters).
741 ///
742 /// # Arguments
743 ///
744 /// * `plan` - the region's channel plan.
745 /// * `session` - the address and session keys it was provisioned with.
746 /// * `settings` - what its radio can do.
747 ///
748 /// # Returns
749 ///
750 /// The device, ready to send at its slowest data rate.
751 ///
752 /// # Errors
753 ///
754 /// Returns [`DeviceError::TooManyChannels`] for a plan with more default or join channels
755 /// than [`MAX_CHANNELS`].
756 pub fn personalized(
757 plan: &'p ChannelPlan<'p>,
758 session: Session,
759 settings: Settings,
760 ) -> Result<EndDevice<'p>, DeviceError> {
761 let mut eui = [0u8; 8];
762 eui[..4].copy_from_slice(&session.dev_addr().to_le_bytes());
763 let sequence = Sequence::new(settings.seed, &eui);
764 let mut device = EndDevice::build(plan, None, sequence, settings)?;
765 device.session = Some(session);
766 device.data_rate = device.lowest_data_rate();
767 Ok(device)
768 }
769
770 fn build(
771 plan: &'p ChannelPlan<'p>,
772 credentials: Option<Device>,
773 sequence: Sequence,
774 settings: Settings,
775 ) -> Result<EndDevice<'p>, DeviceError> {
776 let join_channels = if plan.join_plans.is_empty() {
777 plan.join_channels
778 .iter()
779 .map(|block| usize::from(block.count))
780 .sum::<usize>()
781 } else {
782 plan.join_plans
783 .iter()
784 .map(|run| usize::from(run.channels.count))
785 .sum::<usize>()
786 };
787 if usize::from(plan.default_channel_count()) > MAX_CHANNELS || join_channels > MAX_CHANNELS
788 {
789 return Err(DeviceError::TooManyChannels { max: MAX_CHANNELS });
790 }
791 let mut device = EndDevice {
792 plan,
793 credentials,
794 settings,
795 sequence,
796 battery: Battery::Unknown,
797 session: None,
798 joined_on: None,
799 fcnt_up: 0,
800 fcnt_down: None,
801 data_rate: 0,
802 tx_power: 0,
803 nb_trans: 1,
804 rx1_dr_offset: 0,
805 rx2_frequency_hz: plan.rx2_frequency_hz,
806 rx2_data_rate: plan.rx2_data_rate,
807 rx1_delay_us: RECEIVE_DELAY1_US,
808 max_eirp_dbm: plan.default_max_eirp_dbm,
809 uplink_dwell: false,
810 downlink_dwell: false,
811 max_duty_cycle: 0,
812 channels: Channels::defaults(plan),
813 answers: Answers::new(),
814 backoff: Backoff::recommended(settings.version),
815 air: Air::new(),
816 pending: None,
817 ack_owed: false,
818 joins: 0,
819 join_used: [0; MASK_GROUPS],
820 join_slot: 0,
821 quiet_until_us: 0,
822 relayed: Relayed::new(),
823 };
824 device.reset_mac();
825 Ok(device)
826 }
827
828 /// Carries frame counters over from before a restart.
829 ///
830 /// # Arguments
831 ///
832 /// * `up` - the next uplink counter to use.
833 /// * `down` - the last downlink counter accepted, if any was.
834 ///
835 /// # Returns
836 ///
837 /// The device.
838 pub fn with_frame_counters(mut self, up: u32, down: Option<u32>) -> EndDevice<'p> {
839 self.fcnt_up = up;
840 self.fcnt_down = down;
841 self
842 }
843
844 /// Sets what the device reports its battery as, when a network asks.
845 ///
846 /// # Arguments
847 ///
848 /// * `battery` - the level.
849 pub fn set_battery(&mut self, battery: Battery) {
850 self.battery = battery;
851 }
852
853 /// Asks the network, with the next uplink, how well it hears the device.
854 ///
855 /// The answer arrives in a [`Delivery`]'s [`link_check`](Delivery::link_check).
856 pub fn request_link_check(&mut self) {
857 self.answers.request_link_check();
858 }
859
860 /// Asks the network, with the next uplink, for the time.
861 ///
862 /// The answer arrives in a [`Delivery`]'s [`device_time`](Delivery::device_time).
863 pub fn request_device_time(&mut self) {
864 self.answers.request_device_time();
865 }
866
867 /// Reports whether the device is on a network.
868 ///
869 /// # Returns
870 ///
871 /// `true` once joined, or from the start for a personalized device.
872 pub fn is_joined(&self) -> bool {
873 self.session.is_some()
874 }
875
876 /// Returns the address the device is on the network by.
877 ///
878 /// # Returns
879 ///
880 /// The address, or `None` before joining.
881 pub fn dev_addr(&self) -> Option<u32> {
882 self.session.map(|session| session.dev_addr())
883 }
884
885 /// Returns the data rate the next uplink goes out at, before any back-off step.
886 ///
887 /// # Returns
888 ///
889 /// The data rate.
890 pub fn data_rate(&self) -> u8 {
891 self.data_rate
892 }
893
894 /// Returns the next uplink frame counter.
895 ///
896 /// # Returns
897 ///
898 /// The counter a device stores to carry over a restart.
899 pub fn fcnt_up(&self) -> u32 {
900 self.fcnt_up
901 }
902
903 /// Returns the last downlink frame counter accepted.
904 ///
905 /// # Returns
906 ///
907 /// The counter, or `None` before any downlink.
908 pub fn fcnt_down(&self) -> Option<u32> {
909 self.fcnt_down
910 }
911
912 /// Returns how many times each uplink goes out, as the network last set it.
913 ///
914 /// # Returns
915 ///
916 /// NbTrans, from 1 to 15.
917 pub fn transmissions(&self) -> u8 {
918 self.nb_trans
919 }
920
921 /// Returns the channels the device may send on.
922 ///
923 /// # Returns
924 ///
925 /// Each enabled channel with its index.
926 pub fn channels(&self) -> impl Iterator<Item = (usize, Channel)> + '_ {
927 self.channels.enabled()
928 }
929
930 /// Returns the lowest and highest frequency the device transmits or listens on.
931 ///
932 /// A radio that calibrates for a band, as an SX126x does, calibrates for this one, so
933 /// moving between the device's channels and windows needs no calibration in between.
934 ///
935 /// # Returns
936 ///
937 /// The lower and upper frequency in hertz, across every enabled channel's uplink and
938 /// downlink, the join channels and where their accepts arrive, and the second receive
939 /// window.
940 pub fn frequency_span(&self) -> (u32, u32) {
941 let mut low = self.rx2_frequency_hz.min(self.plan.rx2_frequency_hz);
942 let mut high = self.rx2_frequency_hz.max(self.plan.rx2_frequency_hz);
943 let mut take = |hz: u32| {
944 low = low.min(hz);
945 high = high.max(hz);
946 };
947 for (_, channel) in self.channels.enabled() {
948 take(channel.uplink_hz);
949 take(channel.downlink_hz);
950 }
951 let mut number = 0u16;
952 let mut index = 0;
953 while let Some(block) = self.join_block(index) {
954 for offset in 0..block.count {
955 if let Some(hz) = block.frequency_hz(offset) {
956 take(hz);
957 take(self.join_downlink_hz(number, hz));
958 }
959 number = number.saturating_add(1);
960 }
961 index += 1;
962 }
963 (low, high)
964 }
965
966 /// Returns the second receive window's frequency and data rate.
967 ///
968 /// # Returns
969 ///
970 /// The frequency in hertz and the data rate.
971 pub fn rx2(&self) -> (u32, u8) {
972 (self.rx2_frequency_hz, self.rx2_data_rate)
973 }
974
975 /// Returns the delay from the end of an uplink to the first receive window.
976 ///
977 /// # Returns
978 ///
979 /// The delay in microseconds.
980 pub fn receive_delay_us(&self) -> u32 {
981 self.rx1_delay_us
982 }
983
984 /// Builds a join request.
985 ///
986 /// Each attempt picks a join channel at random and a data rate from the fastest the join
987 /// channels carry down to the slowest, one step per attempt and round again, which is
988 /// how TS001-1.0.4 section 6.2.5 asks a device to cover every channel and rate. On a plan
989 /// that joins in octet passes, US902-928 and AU915-928, each attempt instead takes the
990 /// next slot of the pass at the rate its channel carries. The air it takes is held to the
991 /// region's duty cycle and to the join back-off of section 7.
992 ///
993 /// The accept is due on the uplink's frequency in a dynamic plan, on the downlink channel
994 /// a fixed plan answers the join channel on, and on CN470-510 on the frequency table 49
995 /// gives the common join channel, in both windows, as Semtech's LoRaMac-node listens.
996 ///
997 /// # Arguments
998 ///
999 /// * `dev_nonce` - a nonce this device has never used with its join identifier. TS001-1.0.4
1000 /// counts up from zero and keeps the count across restarts; LoRaWAN 1.0.3 draws one at
1001 /// random.
1002 /// * `now_us` - the time, in microseconds.
1003 ///
1004 /// # Returns
1005 ///
1006 /// What to transmit, with the join accept windows.
1007 ///
1008 /// # Errors
1009 ///
1010 /// Returns [`DeviceError::NoCredentials`] for a personalized device,
1011 /// [`DeviceError::Busy`] while a transmission waits on its windows, and
1012 /// [`DeviceError::Wait`] when the air is not free.
1013 pub fn join(&mut self, dev_nonce: u16, now_us: u64) -> Result<Transmission, DeviceError> {
1014 let credentials = self
1015 .credentials
1016 .as_ref()
1017 .ok_or(DeviceError::NoCredentials)?;
1018 if self.pending.is_some() {
1019 return Err(DeviceError::Busy);
1020 }
1021 if now_us < self.quiet_until_us {
1022 return Err(DeviceError::Wait {
1023 until_us: self.quiet_until_us,
1024 });
1025 }
1026
1027 let frame = credentials.join_request(dev_nonce);
1028 let length = frame.as_bytes().len();
1029 let choice = match self.plan.join_sequence {
1030 JoinSequence::Random => self.random_join_channel(length, now_us)?,
1031 JoinSequence::OctetPasses => self.octet_pass_channel(length, now_us)?,
1032 };
1033 let rx2_hz = match self.plan.join_plan(choice.number) {
1034 Some(_) => choice.channel.downlink_hz,
1035 None => self.plan.rx2_frequency_hz,
1036 };
1037 self.relayed.joining(self.joins);
1038 let relay = self.wor_exchange(
1039 Carrier::new(choice.channel.uplink_hz, choice.data_rate),
1040 true,
1041 now_us,
1042 )?;
1043 let started_us = relay.map_or(now_us, |relay| relay.uplink_start_us);
1044 let transmission = self.transmission(
1045 frame,
1046 choice.channel,
1047 choice.data_rate,
1048 choice.link,
1049 choice.airtime_us,
1050 self.tx_power,
1051 Some(rx2_hz),
1052 true,
1053 relay,
1054 )?;
1055
1056 self.air.joined_air(choice.airtime_us);
1057 self.record_air(started_us, choice.airtime_us, choice.channel.uplink_hz);
1058 self.joins = self.joins.wrapping_add(1);
1059 self.join_slot = choice.next_slot;
1060 if choice.restart_cycle {
1061 self.join_used = [0; MASK_GROUPS];
1062 }
1063 let number = usize::from(choice.number);
1064 if number < MAX_CHANNELS {
1065 self.join_used[number / 16] |= 1 << (number % 16);
1066 }
1067 self.pending = Some(Pending::Join {
1068 dev_nonce,
1069 data_rate: choice.data_rate,
1070 join_channel: choice.number,
1071 });
1072 Ok(transmission)
1073 }
1074
1075 /// A join channel at random carrying this attempt's data rate.
1076 fn random_join_channel(
1077 &mut self,
1078 length: usize,
1079 now_us: u64,
1080 ) -> Result<JoinChoice, DeviceError> {
1081 let data_rate = self.join_data_rate()?;
1082 let link = self.uplink_link(data_rate)?;
1083 let airtime_us = link.airtime_us(length);
1084 if let Err(until_us) = self.air.join_allowed(now_us, airtime_us) {
1085 return Err(DeviceError::Wait { until_us });
1086 }
1087
1088 let mut candidates = [None; MAX_CHANNELS];
1089 let mut count = 0;
1090 let mut number = 0u16;
1091 let mut index = 0;
1092 while let Some(block) = self.join_block(index) {
1093 for offset in 0..block.count {
1094 if let Some(hz) = block.frequency_hz(offset) {
1095 if block.min_data_rate <= data_rate
1096 && data_rate <= block.max_data_rate
1097 && self.settings.usable(hz)
1098 && count < MAX_CHANNELS
1099 {
1100 candidates[count] = Some((number, self.join_channel(number, hz, &block)));
1101 count += 1;
1102 }
1103 }
1104 number = number.saturating_add(1);
1105 }
1106 index += 1;
1107 }
1108 let (number, channel) = self.pick(&candidates[..count], now_us)?;
1109 Ok(JoinChoice {
1110 number,
1111 channel,
1112 data_rate,
1113 link,
1114 airtime_us,
1115 next_slot: self.join_slot,
1116 restart_cycle: false,
1117 })
1118 }
1119
1120 /// The next slot of an octet pass over the join channels, RP002-1.0.5 section 3.5.2.
1121 ///
1122 /// The first join block is split into groups of eight, visited in order, and every block
1123 /// after it forms one more slot at the end of the pass. A slot takes a channel no attempt
1124 /// of the current cycle has used, at random within a group and the lowest in the last
1125 /// slot, as the section's example has the 500 kHz channels go 64, 65 and on. The cycle
1126 /// starts over once every channel has gone out, and a slot with no channel the radio can
1127 /// use is passed over.
1128 fn octet_pass_channel(
1129 &mut self,
1130 length: usize,
1131 now_us: u64,
1132 ) -> Result<JoinChoice, DeviceError> {
1133 let blocks = self.plan.join_channels;
1134 let narrow = blocks.first().map_or(0, |block| block.count);
1135 let groups = u32::from(narrow.div_ceil(8));
1136 let total = blocks.iter().map(|block| block.count).sum::<u16>();
1137 let pass = groups + u32::from(total > narrow);
1138 if pass == 0 {
1139 return Err(DeviceError::NoChannel);
1140 }
1141
1142 let mut every = [(0u16, Channel::new(0, 0, 0)); MAX_CHANNELS];
1143 let mut count = 0;
1144 let mut number = 0u16;
1145 for block in blocks {
1146 for offset in 0..block.count {
1147 if let Some(hz) = block.frequency_hz(offset) {
1148 if self.settings.usable(hz)
1149 && self.uplink_link(block.min_data_rate).is_ok()
1150 && self.application_room(block.min_data_rate).is_ok()
1151 && count < MAX_CHANNELS
1152 {
1153 every[count] = (number, self.join_channel(number, hz, block));
1154 count += 1;
1155 }
1156 }
1157 number = number.saturating_add(1);
1158 }
1159 }
1160 let every = &every[..count];
1161 let used = |number: u16| {
1162 let number = usize::from(number);
1163 self.join_used[number / 16] & (1 << (number % 16)) != 0
1164 };
1165 let fresh_cycle = every.iter().all(|(number, _)| used(*number));
1166
1167 for step in 0..pass {
1168 let slot = (self.join_slot + step) % pass;
1169 let in_slot = |number: u16| {
1170 if slot < groups {
1171 u32::from(number) / 8 == slot && number < narrow
1172 } else {
1173 number >= narrow
1174 }
1175 };
1176 let mut candidates = [None; 8];
1177 let mut found = 0;
1178 for &(number, channel) in every {
1179 if in_slot(number) && (fresh_cycle || !used(number)) && found < candidates.len() {
1180 candidates[found] = Some((number, channel));
1181 found += 1;
1182 if slot >= groups {
1183 break;
1184 }
1185 }
1186 }
1187 let Some((_, first)) = candidates[0] else {
1188 continue;
1189 };
1190 let data_rate = first.min_data_rate;
1191 let link = self.uplink_link(data_rate)?;
1192 let airtime_us = link.airtime_us(length);
1193 if let Err(until_us) = self.air.join_allowed(now_us, airtime_us) {
1194 return Err(DeviceError::Wait { until_us });
1195 }
1196 let (number, channel) = self.pick(&candidates[..found], now_us)?;
1197 return Ok(JoinChoice {
1198 number,
1199 channel,
1200 data_rate,
1201 link,
1202 airtime_us,
1203 next_slot: (slot + 1) % pass,
1204 restart_cycle: fresh_cycle,
1205 });
1206 }
1207 Err(DeviceError::NoChannel)
1208 }
1209
1210 /// One block of the channels a join request may go out on, numbered through in order: the
1211 /// join plans' channels where the plan picks a plan by the join channel, and otherwise its
1212 /// join channels.
1213 fn join_block(&self, index: usize) -> Option<ChannelBlock> {
1214 if self.plan.join_plans.is_empty() {
1215 self.plan.join_channels.get(index).copied()
1216 } else {
1217 self.plan.join_plans.get(index).map(|run| run.channels)
1218 }
1219 }
1220
1221 /// A join channel with the downlink its accept arrives on.
1222 fn join_channel(&self, number: u16, hz: u32, block: &ChannelBlock) -> Channel {
1223 let mut channel = Channel::new(hz, block.min_data_rate, block.max_data_rate);
1224 channel.downlink_hz = self.join_downlink_hz(number, hz);
1225 channel
1226 }
1227
1228 /// Where the accept for a join on a numbered join channel arrives.
1229 fn join_downlink_hz(&self, number: u16, hz: u32) -> u32 {
1230 match self.plan.join_plan(number) {
1231 Some((run, offset)) => run.accept_hz(offset).unwrap_or(hz),
1232 None => self.plan.rx1_frequency_hz(number, hz).unwrap_or(hz),
1233 }
1234 }
1235
1236 /// Builds an uplink carrying a payload.
1237 ///
1238 /// The frame takes every answer the device owes the network. If they leave no room for
1239 /// the payload, the answers go alone and [`Transmission::carries_payload`] says the
1240 /// payload waits.
1241 ///
1242 /// # Arguments
1243 ///
1244 /// * `port` - the application port, 1 to 223, or 224 for the certification test port.
1245 /// * `payload` - the application payload.
1246 /// * `confirmed` - whether to ask the network to acknowledge it.
1247 /// * `now_us` - the time, in microseconds.
1248 ///
1249 /// # Returns
1250 ///
1251 /// What to transmit, with its receive windows.
1252 ///
1253 /// # Errors
1254 ///
1255 /// Returns [`DeviceError::NotJoined`] before joining, [`DeviceError::Busy`] while a
1256 /// transmission waits on its windows or its repeats, [`DeviceError::Wait`] when the air
1257 /// is not free, [`DeviceError::PayloadTooLong`] for a payload the data rate cannot carry,
1258 /// and [`DeviceError::Frame`] for port 0, which belongs to MAC commands.
1259 pub fn send(
1260 &mut self,
1261 port: u8,
1262 payload: &[u8],
1263 confirmed: bool,
1264 now_us: u64,
1265 ) -> Result<Transmission, DeviceError> {
1266 if port == 0 {
1267 return Err(DeviceError::Frame(LorawanError::MalformedFrame));
1268 }
1269 self.uplink(Some((port, payload)), confirmed, now_us)
1270 }
1271
1272 /// Builds an uplink with no payload.
1273 ///
1274 /// It carries the answers the device owes, an acknowledgment of a confirmed downlink,
1275 /// or an ADR acknowledgment request, whichever are due.
1276 ///
1277 /// # Arguments
1278 ///
1279 /// * `now_us` - the time, in microseconds.
1280 ///
1281 /// # Returns
1282 ///
1283 /// What to transmit, with its receive windows.
1284 ///
1285 /// # Errors
1286 ///
1287 /// As [`send`](EndDevice::send).
1288 pub fn send_empty(&mut self, now_us: u64) -> Result<Transmission, DeviceError> {
1289 self.uplink(None, false, now_us)
1290 }
1291
1292 /// Reads a frame heard in one of the receive windows of the last transmission, without
1293 /// saying which.
1294 ///
1295 /// A downlink may be as long as the faster of the two windows allows. When the radio
1296 /// knows the window, [`heard_in`](EndDevice::heard_in) holds the frame to that window's
1297 /// own limit, as TS001-1.0.4 section 4.1 asks.
1298 ///
1299 /// # Arguments
1300 ///
1301 /// * `frame` - the bytes the radio received.
1302 /// * `snr_db` - the frame's signal-to-noise ratio, which a `DevStatusAns` reports.
1303 ///
1304 /// # Returns
1305 ///
1306 /// The join, or the downlink read and acted on.
1307 ///
1308 /// # Errors
1309 ///
1310 /// As [`heard_in`](EndDevice::heard_in).
1311 pub fn heard(&mut self, frame: &[u8], snr_db: i8) -> Result<Heard, DeviceError> {
1312 self.heard_frame(None, frame, snr_db, None)
1313 }
1314
1315 /// Reads a frame heard in a given receive window of the last transmission.
1316 ///
1317 /// Under a relay the windows are three: the first two as ever, and then
1318 /// [`ReceiveWindow::Rxr`], which carries whatever the relay forwards back, TS011-1.0.1
1319 /// chapter 7.
1320 ///
1321 /// A frame that is not for this device, does not verify, or is longer than the window's
1322 /// data rate carries leaves the transmission waiting, so the second window still opens.
1323 /// TS001-1.0.4 section 4.1 has a device discard a MACPayload longer than the region's
1324 /// `M` for the data rate it was received at. RP002-1.0.5 has the device hold a downlink
1325 /// to the limit with no dwell time and no repeater, whatever its own settings, so no
1326 /// frame a network may lawfully send is lost.
1327 ///
1328 /// # Arguments
1329 ///
1330 /// * `window` - the window the radio heard the frame in.
1331 /// * `frame` - the bytes the radio received.
1332 /// * `snr_db` - the frame's signal-to-noise ratio, which a `DevStatusAns` reports.
1333 ///
1334 /// # Returns
1335 ///
1336 /// The join, or the downlink read and acted on.
1337 ///
1338 /// # Errors
1339 ///
1340 /// Returns [`DeviceError::NothingPending`] with no transmission waiting,
1341 /// [`DeviceError::Foreign`] for another device's frame, [`DeviceError::Replayed`] and
1342 /// [`DeviceError::CounterGap`] for a counter the device will not accept,
1343 /// [`DeviceError::Refused`] for a join accept with settings the region forbids, and
1344 /// [`DeviceError::Frame`] for a frame that does not decode or is longer than the window
1345 /// carries.
1346 ///
1347 /// # Examples
1348 ///
1349 /// ```
1350 /// use pamoja_lora::region::Region;
1351 /// use pamoja_lorawan::device::{DeviceError, EndDevice, ReceiveWindow, Settings};
1352 /// use pamoja_lorawan::{Downlink, LorawanError, Session};
1353 ///
1354 /// let session = Session::new(0x2601_1BDA, [0x2B; 16], [0x99; 16]);
1355 /// let settings = Settings::new(2, 14);
1356 /// let mut device = EndDevice::personalized(Region::Eu868.plan(), session, settings)?;
1357 ///
1358 /// // A personalized European device starts at DR0, and the second window listens at DR0
1359 /// // too, where a MACPayload holds no more than 59 bytes.
1360 /// device.send(1, b"hi", false, 0)?;
1361 /// let long = session.encode_downlink(&Downlink::new(0, 1, &[0; 60]))?;
1362 /// assert_eq!(
1363 /// device.heard_in(ReceiveWindow::Rx2, long.as_bytes(), 5),
1364 /// Err(DeviceError::Frame(LorawanError::PayloadTooLong)),
1365 /// );
1366 ///
1367 /// let short = session.encode_downlink(&Downlink::new(0, 1, b"ok"))?;
1368 /// assert!(device.heard_in(ReceiveWindow::Rx2, short.as_bytes(), 5).is_ok());
1369 /// # Ok::<(), Box<dyn std::error::Error>>(())
1370 /// ```
1371 pub fn heard_in(
1372 &mut self,
1373 window: ReceiveWindow,
1374 frame: &[u8],
1375 snr_db: i8,
1376 ) -> Result<Heard, DeviceError> {
1377 self.heard_frame(Some(window), frame, snr_db, None)
1378 }
1379
1380 /// Reads a frame as [`heard_in`](EndDevice::heard_in) does, handing the relay commands
1381 /// among its MAC commands to a relay's state in the order they arrived.
1382 pub(crate) fn heard_frame(
1383 &mut self,
1384 window: Option<ReceiveWindow>,
1385 frame: &[u8],
1386 snr_db: i8,
1387 relay: Option<&mut RelayState>,
1388 ) -> Result<Heard, DeviceError> {
1389 match self.pending {
1390 None => Err(DeviceError::NothingPending),
1391 Some(Pending::Join {
1392 dev_nonce,
1393 data_rate,
1394 join_channel,
1395 }) => self.heard_join(frame, dev_nonce, data_rate, join_channel, window),
1396 Some(Pending::Uplink {
1397 windows_closed: true,
1398 ..
1399 }) => Err(DeviceError::NothingPending),
1400 Some(Pending::Uplink {
1401 confirmed, windows, ..
1402 }) => self.heard_data(frame, snr_db, confirmed, windows, window, relay),
1403 }
1404 }
1405
1406 /// Says what comes next once both receive windows closed with nothing for the device.
1407 ///
1408 /// # Arguments
1409 ///
1410 /// * `now_us` - the time the second window closed, in microseconds.
1411 ///
1412 /// # Returns
1413 ///
1414 /// Whether to repeat the frame, join again, or move on.
1415 ///
1416 /// # Errors
1417 ///
1418 /// Returns [`DeviceError::NothingPending`] with no transmission waiting on its windows.
1419 pub fn nothing_heard(&mut self, now_us: u64) -> Result<Next, DeviceError> {
1420 match self.pending {
1421 None
1422 | Some(Pending::Uplink {
1423 windows_closed: true,
1424 ..
1425 }) => Err(DeviceError::NothingPending),
1426 Some(Pending::Join { .. }) => {
1427 self.pending = None;
1428 let wait = self
1429 .sequence
1430 .between(RETRANSMIT_TIMEOUT_MIN_US, RETRANSMIT_TIMEOUT_MAX_US);
1431 let not_before_us = now_us.saturating_add(u64::from(wait));
1432 self.quiet_until_us = not_before_us;
1433 Ok(Next::JoinAgain { not_before_us })
1434 }
1435 Some(Pending::Uplink {
1436 frame,
1437 data_rate,
1438 confirmed,
1439 carries_payload,
1440 transmissions_left,
1441 windows,
1442 ..
1443 }) => {
1444 let not_before_us = if confirmed {
1445 let wait = self
1446 .sequence
1447 .between(RETRANSMIT_TIMEOUT_MIN_US, RETRANSMIT_TIMEOUT_MAX_US);
1448 now_us.saturating_add(u64::from(wait))
1449 } else {
1450 now_us
1451 };
1452 if transmissions_left > 0 {
1453 self.pending = Some(Pending::Uplink {
1454 frame,
1455 data_rate,
1456 confirmed,
1457 carries_payload,
1458 transmissions_left,
1459 windows_closed: true,
1460 not_before_us,
1461 windows,
1462 });
1463 return Ok(Next::Repeat { not_before_us });
1464 }
1465 self.pending = None;
1466 self.relayed
1467 .uplink_unanswered(smart_enable_uplinks(self.relayed.smart_level));
1468 if confirmed {
1469 self.quiet_until_us = not_before_us;
1470 Ok(Next::Unacknowledged)
1471 } else {
1472 Ok(Next::Done)
1473 }
1474 }
1475 }
1476 }
1477
1478 /// Sends the last uplink again, the same frame on a channel chosen afresh.
1479 ///
1480 /// TS001-1.0.4 section 4.3.1.3 has a device hop between repetitions as usual and keep
1481 /// the frame counter, so the frame is byte for byte the one that went out before.
1482 ///
1483 /// # Arguments
1484 ///
1485 /// * `now_us` - the time, in microseconds.
1486 ///
1487 /// # Returns
1488 ///
1489 /// What to transmit, with its receive windows.
1490 ///
1491 /// # Errors
1492 ///
1493 /// Returns [`DeviceError::NothingPending`] with nothing due to repeat, and
1494 /// [`DeviceError::Wait`] before the retransmission timeout or while the air is not free.
1495 pub fn repeat(&mut self, now_us: u64) -> Result<Transmission, DeviceError> {
1496 let Some(Pending::Uplink {
1497 frame,
1498 data_rate,
1499 confirmed,
1500 carries_payload,
1501 transmissions_left,
1502 windows_closed: true,
1503 not_before_us,
1504 ..
1505 }) = self.pending
1506 else {
1507 return Err(DeviceError::NothingPending);
1508 };
1509 if now_us < not_before_us {
1510 return Err(DeviceError::Wait {
1511 until_us: not_before_us,
1512 });
1513 }
1514 let link = self.uplink_link(data_rate)?;
1515 let airtime_us = link.airtime_us(frame.as_bytes().len());
1516 let channels = self.channels;
1517 let channel = self.pick_enabled(&channels, data_rate, now_us)?;
1518 let relay = self.wor_exchange(Carrier::new(channel.uplink_hz, data_rate), false, now_us)?;
1519 let started_us = relay.map_or(now_us, |relay| relay.uplink_start_us);
1520 let transmission = self.transmission(
1521 frame,
1522 channel,
1523 data_rate,
1524 link,
1525 airtime_us,
1526 self.tx_power,
1527 None,
1528 carries_payload,
1529 relay,
1530 )?;
1531 self.record_air(started_us, airtime_us, channel.uplink_hz);
1532 self.pending = Some(Pending::Uplink {
1533 frame,
1534 data_rate,
1535 confirmed,
1536 carries_payload,
1537 transmissions_left: transmissions_left - 1,
1538 windows_closed: false,
1539 not_before_us: 0,
1540 windows: Windows::of(&transmission, started_us),
1541 });
1542 Ok(transmission)
1543 }
1544
1545 fn uplink(
1546 &mut self,
1547 data: Option<(u8, &[u8])>,
1548 confirmed: bool,
1549 now_us: u64,
1550 ) -> Result<Transmission, DeviceError> {
1551 let session = self.session.ok_or(DeviceError::NotJoined)?;
1552 if self.pending.is_some() {
1553 return Err(DeviceError::Busy);
1554 }
1555 if now_us < self.quiet_until_us {
1556 return Err(DeviceError::Wait {
1557 until_us: self.quiet_until_us,
1558 });
1559 }
1560 if self.fcnt_up == u32::MAX {
1561 return Err(DeviceError::CounterExhausted);
1562 }
1563
1564 // Everything the back-off changes is worked out on copies and kept only if the
1565 // frame goes out, so a refusal leaves the count where it was.
1566 let mut data_rate = self.data_rate;
1567 let mut tx_power = self.tx_power;
1568 let mut nb_trans = self.nb_trans;
1569 let mut channels = self.channels;
1570 let mut backoff = self.backoff;
1571 let lowest = self.lowest_data_rate();
1572
1573 let step = if self.settings.adr {
1574 backoff.uplink(Standing {
1575 default_data_rate: data_rate <= lowest,
1576 })
1577 } else {
1578 Step::default()
1579 };
1580 if step.restore_power {
1581 tx_power = 0;
1582 }
1583 if step.lower_data_rate {
1584 data_rate = self.lower(data_rate, lowest);
1585 }
1586 if step.restore_channels {
1587 channels.enable_defaults();
1588 nb_trans = 1;
1589 }
1590 // TS001-1.0.4 section 4.3.1.1: a combination that leaves no usable channel sends
1591 // the device straight back to its default channels at full power.
1592 if !channels.carries(&channels.mask(), data_rate) {
1593 channels.enable_defaults();
1594 tx_power = 0;
1595 if !channels.carries(&channels.mask(), data_rate) {
1596 data_rate = lowest;
1597 }
1598 }
1599
1600 let room = self.application_room(data_rate)?;
1601 if let Some((_, payload)) = data {
1602 if payload.len() > room {
1603 return Err(DeviceError::PayloadTooLong { max: room });
1604 }
1605 }
1606
1607 let owed = self.answers.len();
1608 let payload_len = data.map_or(0, |(_, payload)| payload.len());
1609 let mut fopts = [0u8; FOPTS_MAX];
1610 let mut mac = [0u8; MAX_PAYLOAD];
1611 let (port, body, fopts_len, carries_payload, written) =
1612 if owed <= FOPTS_MAX && owed + payload_len <= room {
1613 let written = self.answers.write(&mut fopts);
1614 (
1615 data.map(|(port, _)| port),
1616 data.map_or(&[][..], |(_, payload)| payload),
1617 written.len,
1618 data.is_some(),
1619 written,
1620 )
1621 } else if owed <= FOPTS_MAX {
1622 let written = self.answers.write(&mut fopts);
1623 (None, &[][..], written.len, false, written)
1624 } else {
1625 let written = self.answers.write(&mut mac[..room]);
1626 (Some(0), &mac[..written.len], 0, false, written)
1627 };
1628
1629 let mut uplink = match port {
1630 Some(port) => Uplink::new(self.fcnt_up, port, body),
1631 None => Uplink::empty(self.fcnt_up),
1632 }
1633 .with_fopts(&fopts[..fopts_len]);
1634 let confirmed = confirmed && carries_payload;
1635 if confirmed {
1636 uplink = uplink.confirmed();
1637 }
1638 if self.settings.adr {
1639 uplink = uplink.with_adr();
1640 }
1641 if step.request_ack {
1642 uplink = uplink.with_adr_ack_req();
1643 }
1644 if self.ack_owed {
1645 uplink = uplink.with_ack();
1646 }
1647 let frame = session.encode_uplink(&uplink)?;
1648
1649 let link = self.uplink_link(data_rate)?;
1650 let airtime_us = link.airtime_us(frame.as_bytes().len());
1651 if self.uplink_dwell && airtime_us > DWELL_LIMIT_US {
1652 return Err(DeviceError::PayloadTooLong { max: room });
1653 }
1654 let channel = self.pick_enabled(&channels, data_rate, now_us)?;
1655 let relay = self.wor_exchange(Carrier::new(channel.uplink_hz, data_rate), false, now_us)?;
1656 let started_us = relay.map_or(now_us, |relay| relay.uplink_start_us);
1657 let transmission = self.transmission(
1658 frame,
1659 channel,
1660 data_rate,
1661 link,
1662 airtime_us,
1663 tx_power,
1664 None,
1665 carries_payload,
1666 relay,
1667 )?;
1668
1669 self.data_rate = data_rate;
1670 self.tx_power = tx_power;
1671 self.nb_trans = nb_trans;
1672 self.channels = channels;
1673 self.backoff = backoff;
1674 self.fcnt_up += 1;
1675 self.answers.sent(written);
1676 self.ack_owed = false;
1677 self.record_air(started_us, airtime_us, channel.uplink_hz);
1678 self.pending = Some(Pending::Uplink {
1679 frame,
1680 data_rate,
1681 confirmed,
1682 carries_payload,
1683 transmissions_left: nb_trans.saturating_sub(1),
1684 windows_closed: false,
1685 not_before_us: 0,
1686 windows: Windows::of(&transmission, started_us),
1687 });
1688 Ok(transmission)
1689 }
1690
1691 fn heard_join(
1692 &mut self,
1693 frame: &[u8],
1694 dev_nonce: u16,
1695 data_rate: u8,
1696 join_channel: u16,
1697 window: Option<ReceiveWindow>,
1698 ) -> Result<Heard, DeviceError> {
1699 let header = FrameHeader::parse(frame)?;
1700 if header.message_type() != MessageType::JoinAccept {
1701 return Err(DeviceError::Frame(LorawanError::UnsupportedMType(
1702 frame[0] & 0xE0,
1703 )));
1704 }
1705 let credentials = self
1706 .credentials
1707 .as_ref()
1708 .ok_or(DeviceError::NoCredentials)?;
1709 let accept = credentials.accept_join(frame, dev_nonce)?;
1710
1711 // RP002-1.0.5 section 3.9.2: the common join channel decides a CN470-510 plan.
1712 let joined_on = self.plan.join_plan(join_channel);
1713 let plan = joined_on.map_or(self.plan, |(run, _)| run.plan);
1714
1715 // RP002-1.0.5 section 3.4.7 and its counterparts: a reserved RX1DROffset in a join
1716 // accept has the accept ignored.
1717 let rx2_is_lora = matches!(
1718 plan.downlink_data_rate(accept.rx2_data_rate())
1719 .map(|rate| rate.modulation),
1720 Some(Modulation::LoRa { .. })
1721 );
1722 if accept.rx1_dr_offset() > plan.max_rx1_data_rate_offset || !rx2_is_lora {
1723 return Err(DeviceError::Refused);
1724 }
1725
1726 // TS001-1.0.4 section 6.2.6: back to the default channels and MAC settings, then the
1727 // accept's own settings, then the channel list as if its commands had arrived, with
1728 // no answers.
1729 self.plan = plan;
1730 self.reset_mac();
1731 if let Some(hz) = joined_on.and_then(|(run, offset)| run.rx2_hz(offset)) {
1732 self.rx2_frequency_hz = hz;
1733 }
1734 self.rx1_dr_offset = accept.rx1_dr_offset();
1735 self.rx2_data_rate = accept.rx2_data_rate();
1736 self.rx1_delay_us = accept.receive_delay_us();
1737 if let Some(list) = accept.cflist() {
1738 let settings = self.settings;
1739 self.channels
1740 .apply_cflist(self.plan, list, |hz| settings.usable(hz));
1741 }
1742 let session = accept.session();
1743 self.session = Some(session);
1744 self.joined_on = joined_on.map(|_| join_channel);
1745 self.fcnt_up = 0;
1746 self.fcnt_down = None;
1747 self.data_rate = if self.channels.carries(&self.channels.mask(), data_rate) {
1748 data_rate
1749 } else {
1750 self.lowest_data_rate()
1751 };
1752 self.relayed.joined(window == Some(ReceiveWindow::Rxr));
1753 self.air.join_done();
1754 self.join_used = [0; MASK_GROUPS];
1755 self.join_slot = 0;
1756 self.pending = None;
1757 self.quiet_until_us = 0;
1758 Ok(Heard::Joined {
1759 dev_addr: session.dev_addr(),
1760 })
1761 }
1762
1763 fn heard_data(
1764 &mut self,
1765 frame: &[u8],
1766 snr_db: i8,
1767 confirmed_uplink: bool,
1768 windows: Windows,
1769 window: Option<ReceiveWindow>,
1770 relay: Option<&mut RelayState>,
1771 ) -> Result<Heard, DeviceError> {
1772 let session = self.session.ok_or(DeviceError::NotJoined)?;
1773 let header = FrameHeader::parse(frame)?;
1774 if !matches!(
1775 header.message_type(),
1776 MessageType::UnconfirmedDown | MessageType::ConfirmedDown
1777 ) {
1778 return Err(DeviceError::Frame(LorawanError::UnsupportedMType(
1779 frame[0] & 0xE0,
1780 )));
1781 }
1782 if header.dev_addr() != Some(session.dev_addr()) {
1783 return Err(DeviceError::Foreign);
1784 }
1785 let limit = |data_rate| {
1786 self.plan
1787 .downlink_max_payload(data_rate, false)
1788 .map(|limit| usize::from(limit.mac_payload))
1789 };
1790 let max_mac_payload = match window {
1791 Some(ReceiveWindow::Rx1) => limit(windows.rx1_data_rate),
1792 Some(ReceiveWindow::Rx2) => limit(windows.rx2_data_rate),
1793 Some(ReceiveWindow::Rxr) => windows.rxr_data_rate.and_then(limit),
1794 None => limit(windows.rx1_data_rate)
1795 .zip(limit(windows.rx2_data_rate))
1796 .map(|(rx1, rx2)| rx1.max(rx2)),
1797 };
1798 if max_mac_payload.is_some_and(|max| frame.len().saturating_sub(5) > max) {
1799 return Err(DeviceError::Frame(LorawanError::PayloadTooLong));
1800 }
1801 let fcnt = self.downlink_counter(header.fcnt().unwrap_or(0))?;
1802 let rx = session.decode(frame, fcnt)?;
1803
1804 self.fcnt_down = Some(fcnt);
1805 self.relayed.heard_downlink();
1806 if window == Some(ReceiveWindow::Rxr) {
1807 self.relayed.heard_on_rxr();
1808 }
1809 self.backoff.downlink();
1810 self.answers.heard_downlink();
1811 self.ack_owed = rx.confirmed();
1812 self.pending = None;
1813 // TS001-1.0.4 section 4.3.1.3: a device still owed an acknowledgment waits out the
1814 // retransmission timeout, counted from the second window, before its next uplink.
1815 self.quiet_until_us = if confirmed_uplink && !rx.ack() {
1816 let wait = self
1817 .sequence
1818 .between(RETRANSMIT_TIMEOUT_MIN_US, RETRANSMIT_TIMEOUT_MAX_US);
1819 windows.rx2_opens_us.saturating_add(u64::from(wait))
1820 } else {
1821 0
1822 };
1823
1824 let mut delivery = Delivery {
1825 port: None,
1826 payload: [0; MAX_PAYLOAD],
1827 len: 0,
1828 acknowledged: confirmed_uplink && rx.ack(),
1829 confirmed: rx.confirmed(),
1830 more_pending: rx.fpending(),
1831 link_check: None,
1832 device_time: None,
1833 };
1834 match rx.fport() {
1835 Some(0) => self.process_commands(rx.payload(), snr_db, &mut delivery, relay),
1836 Some(port) => {
1837 self.process_commands(rx.fopts(), snr_db, &mut delivery, relay);
1838 delivery.port = Some(port);
1839 delivery.len = rx.payload().len();
1840 delivery.payload[..delivery.len].copy_from_slice(rx.payload());
1841 }
1842 None => self.process_commands(rx.fopts(), snr_db, &mut delivery, relay),
1843 }
1844 Ok(Heard::Data(delivery))
1845 }
1846
1847 /// Works the full downlink counter out from the 16 bits a frame carries.
1848 ///
1849 /// TS001-1.0.4 section 4.3.1.5 has the counter only go up and a retransmission of the
1850 /// last downlink ignored. LoRaWAN 1.0.3 also refuses a jump of [`MAX_FCNT_GAP`] or more.
1851 fn downlink_counter(&self, low: u16) -> Result<u32, DeviceError> {
1852 let Some(last) = self.fcnt_down else {
1853 return Ok(u32::from(low));
1854 };
1855 if last as u16 == low {
1856 return Err(DeviceError::Replayed);
1857 }
1858 let mut candidate = (last & !0xFFFF) | u32::from(low);
1859 if candidate < last {
1860 candidate = candidate
1861 .checked_add(0x1_0000)
1862 .ok_or(DeviceError::CounterExhausted)?;
1863 }
1864 if self.settings.version == Version::V1_0_3 && candidate - last >= MAX_FCNT_GAP {
1865 return Err(DeviceError::CounterGap);
1866 }
1867 Ok(candidate)
1868 }
1869
1870 /// Puts every MAC setting back to the region's default, as a join accept does.
1871 fn reset_mac(&mut self) {
1872 self.channels = Channels::defaults(self.plan);
1873 self.tx_power = 0;
1874 self.nb_trans = 1;
1875 self.rx1_dr_offset = 0;
1876 self.rx2_frequency_hz = self.plan.rx2_frequency_hz;
1877 self.rx2_data_rate = self.plan.rx2_data_rate;
1878 self.rx1_delay_us = RECEIVE_DELAY1_US;
1879 self.max_eirp_dbm = self.plan.default_max_eirp_dbm;
1880 // RP002-1.0.5 has AS923 and AU915 devices assume the 400 ms limit until
1881 // `TXParamSetupReq` says otherwise, and no region assume a downlink limit.
1882 self.uplink_dwell = self.plan.tx_param_setup;
1883 self.downlink_dwell = false;
1884 self.max_duty_cycle = 0;
1885 self.answers = Answers::new();
1886 self.backoff = Backoff::recommended(self.settings.version);
1887 self.ack_owed = false;
1888 }
1889
1890 /// The channel plan the device runs on.
1891 pub(crate) const fn plan(&self) -> &'p ChannelPlan<'p> {
1892 self.plan
1893 }
1894
1895 /// Reports whether the radio can tune a frequency.
1896 pub(crate) const fn tunes(&self, hz: u32) -> bool {
1897 self.settings.usable(hz)
1898 }
1899
1900 /// Queues a command the device starts itself, such as a relay's notification, for the
1901 /// next uplink.
1902 ///
1903 /// # Returns
1904 ///
1905 /// `false` if the queue is full.
1906 pub(crate) fn start_command(&mut self, command: MacCommand) -> bool {
1907 self.answers.start(command)
1908 }
1909
1910 /// Reports whether a command the device started, beginning with these bytes, is still
1911 /// to go out.
1912 pub(crate) fn starts_command(&self, prefix: &[u8]) -> bool {
1913 self.answers.starts_with(prefix)
1914 }
1915
1916 /// The default data rate: the slowest LoRa rate a default channel carries, and under a
1917 /// dwell limit the slowest that carries a payload inside it.
1918 fn lowest_data_rate(&self) -> u8 {
1919 (0..16u8)
1920 .find(|rate| {
1921 self.channels.carries(&self.channels.mask(), *rate)
1922 && self.uplink_link(*rate).is_ok()
1923 && self.application_room(*rate).is_ok()
1924 })
1925 .unwrap_or(0)
1926 }
1927
1928 /// The next data rate down by the region's back-off table, never below `lowest`.
1929 fn lower(&self, data_rate: u8, lowest: u8) -> u8 {
1930 let mut next = data_rate;
1931 while let Some(lower) = self.plan.next_backoff_data_rate(next) {
1932 next = lower;
1933 if next <= lowest {
1934 return lowest;
1935 }
1936 if self.uplink_link(next).is_ok() && self.application_room(next).is_ok() {
1937 return next;
1938 }
1939 }
1940 data_rate
1941 }
1942
1943 /// The data rate this join attempt goes out at.
1944 fn join_data_rate(&self) -> Result<u8, DeviceError> {
1945 let mut rates = [0u8; 16];
1946 let mut count = 0;
1947 for rate in (0..16u8).rev() {
1948 let carried = (0..)
1949 .map_while(|index| self.join_block(index))
1950 .any(|block| block.min_data_rate <= rate && rate <= block.max_data_rate);
1951 if carried && self.uplink_link(rate).is_ok() && self.application_room(rate).is_ok() {
1952 rates[count] = rate;
1953 count += 1;
1954 }
1955 }
1956 if count == 0 {
1957 return Err(DeviceError::NoChannel);
1958 }
1959 Ok(rates[self.joins as usize % count])
1960 }
1961
1962 /// The most application payload a data rate carries with no frame options, from the
1963 /// region's payload tables.
1964 pub(crate) fn application_room(&self, data_rate: u8) -> Result<usize, DeviceError> {
1965 let limit = if self.uplink_dwell && self.plan.has_dwell_time_limit {
1966 self.plan.max_payload_dwell_limited(data_rate)
1967 } else {
1968 self.plan
1969 .max_payload(data_rate, self.settings.behind_repeater)
1970 };
1971 let room = limit
1972 .map(|limit| usize::from(limit.application).min(MAX_PAYLOAD))
1973 .ok_or(DeviceError::DataRate(data_rate))?;
1974 Ok(
1975 match self.relayed.enabled.then(|| self.relayed_room()).flatten() {
1976 Some(relayed) => room.min(relayed),
1977 None => room,
1978 },
1979 )
1980 }
1981
1982 /// The LoRa settings of an uplink at a data rate.
1983 fn uplink_link(&self, data_rate: u8) -> Result<LinkSettings, DeviceError> {
1984 match self
1985 .plan
1986 .uplink_data_rate(data_rate)
1987 .map(|rate| rate.modulation)
1988 {
1989 Some(Modulation::LoRa {
1990 spreading_factor,
1991 bandwidth_hz,
1992 }) => Ok(LinkSettings::new(spreading_factor, bandwidth_hz)),
1993 _ => Err(DeviceError::DataRate(data_rate)),
1994 }
1995 }
1996
1997 /// The LoRa settings a receive window listens with.
1998 fn downlink_link(&self, data_rate: u8) -> Result<LinkSettings, DeviceError> {
1999 match self
2000 .plan
2001 .downlink_data_rate(data_rate)
2002 .map(|rate| rate.modulation)
2003 {
2004 Some(Modulation::LoRa {
2005 spreading_factor,
2006 bandwidth_hz,
2007 }) => Ok(LinkSettings::new(spreading_factor, bandwidth_hz).without_crc()),
2008 _ => Err(DeviceError::DataRate(data_rate)),
2009 }
2010 }
2011
2012 /// Picks an enabled channel carrying a data rate whose air is free.
2013 fn pick_enabled(
2014 &mut self,
2015 channels: &Channels,
2016 data_rate: u8,
2017 now_us: u64,
2018 ) -> Result<Channel, DeviceError> {
2019 let mut candidates = [None; MAX_CHANNELS];
2020 let mut count = 0;
2021 for (index, channel) in channels.enabled() {
2022 if channel.carries(data_rate) && self.settings.usable(channel.uplink_hz) {
2023 candidates[count] = Some((index as u16, channel));
2024 count += 1;
2025 }
2026 }
2027 self.pick(&candidates[..count], now_us)
2028 .map(|(_, channel)| channel)
2029 }
2030
2031 /// Picks one of `candidates`, numbered channels, at random among those whose air is free
2032 /// now.
2033 fn pick(
2034 &mut self,
2035 candidates: &[Option<(u16, Channel)>],
2036 now_us: u64,
2037 ) -> Result<(u16, Channel), DeviceError> {
2038 let mut free = 0u32;
2039 let mut earliest = u64::MAX;
2040 for (_, channel) in candidates.iter().flatten() {
2041 let at = self.free_at(channel.uplink_hz);
2042 if at <= now_us {
2043 free += 1;
2044 } else {
2045 earliest = earliest.min(at);
2046 }
2047 }
2048 if free == 0 {
2049 return Err(if earliest == u64::MAX {
2050 DeviceError::NoChannel
2051 } else {
2052 DeviceError::Wait { until_us: earliest }
2053 });
2054 }
2055 let mut choice = self.sequence.below(free);
2056 for (number, channel) in candidates.iter().flatten() {
2057 if self.free_at(channel.uplink_hz) <= now_us {
2058 if choice == 0 {
2059 return Ok((*number, *channel));
2060 }
2061 choice -= 1;
2062 }
2063 }
2064 Err(DeviceError::NoChannel)
2065 }
2066
2067 /// When a frequency's air is next free.
2068 pub(crate) fn free_at(&self, hz: u32) -> u64 {
2069 let sub_band = if self.settings.regional_duty_cycle {
2070 self.air
2071 .sub_band_free_at(self.sub_band(hz).map(|(index, _)| index))
2072 } else {
2073 0
2074 };
2075 sub_band.max(self.air.aggregated_free_at())
2076 }
2077
2078 /// The sub-band a frequency falls in, with its duty cycle.
2079 fn sub_band(&self, hz: u32) -> Option<(usize, u32)> {
2080 self.plan
2081 .sub_bands
2082 .iter()
2083 .enumerate()
2084 .take(MAX_SUB_BANDS)
2085 .find(|(_, band)| band.contains(hz))
2086 .map(|(index, band)| (index, band.duty_cycle_permille))
2087 }
2088
2089 /// Counts a transmission against the duty cycle of the sub-band it went out in.
2090 pub(crate) fn record_air(&mut self, started_us: u64, airtime_us: u64, hz: u32) {
2091 let sub_band = if self.settings.regional_duty_cycle {
2092 self.sub_band(hz)
2093 } else {
2094 None
2095 };
2096 self.air
2097 .transmitted(started_us, airtime_us, sub_band, self.max_duty_cycle);
2098 }
2099
2100 /// The conducted power for a power index on a frequency.
2101 pub(crate) fn output_dbm(&self, hz: u32, tx_power: u8) -> i8 {
2102 let ceiling = self.plan.max_eirp_dbm(hz).min(self.max_eirp_dbm);
2103 let power = self
2104 .plan
2105 .tx_power_dbm(tx_power, self.max_eirp_dbm)
2106 .unwrap_or(ceiling)
2107 .min(ceiling);
2108 self.radio_dbm(power).clamp(
2109 i16::from(self.settings.min_output_dbm),
2110 i16::from(self.settings.max_output_dbm),
2111 ) as i8
2112 }
2113
2114 /// The power to ask of the radio for a power the plan's index names: a radiated power
2115 /// less the antenna's gain, or a conducted one less whatever gain exceeds the plan's
2116 /// allowance.
2117 fn radio_dbm(&self, power: i8) -> i16 {
2118 let gain = i16::from(self.settings.antenna_gain_db);
2119 match self.plan.power_reference {
2120 PowerReference::Eirp => i16::from(power) - gain,
2121 PowerReference::Conducted { gain_allowance_db } => {
2122 i16::from(power) - (gain - i16::from(gain_allowance_db)).max(0)
2123 }
2124 }
2125 }
2126
2127 #[allow(clippy::too_many_arguments)]
2128 fn transmission(
2129 &self,
2130 frame: PhyPayload,
2131 channel: Channel,
2132 data_rate: u8,
2133 link: LinkSettings,
2134 airtime_us: u64,
2135 tx_power: u8,
2136 join_rx2_hz: Option<u32>,
2137 carries_payload: bool,
2138 relay: Option<RelayExchange>,
2139 ) -> Result<Transmission, DeviceError> {
2140 let (delay1, delay2, offset, (rx2_hz, rx2_rate)) = match join_rx2_hz {
2141 Some(hz) => (
2142 JOIN_ACCEPT_DELAY1_US,
2143 JOIN_ACCEPT_DELAY2_US,
2144 0,
2145 (hz, self.plan.rx2_data_rate),
2146 ),
2147 None => (
2148 self.rx1_delay_us,
2149 self.rx1_delay_us.saturating_add(1_000_000),
2150 self.rx1_dr_offset,
2151 (self.rx2_frequency_hz, self.rx2_data_rate),
2152 ),
2153 };
2154 let rx1_rate = if self.downlink_dwell {
2155 self.plan.rx1_data_rate_dwell_limited(data_rate, offset)
2156 } else {
2157 None
2158 }
2159 .or_else(|| self.plan.rx1_data_rate(data_rate, offset))
2160 .ok_or(DeviceError::DataRate(data_rate))?;
2161
2162 Ok(Transmission {
2163 frame,
2164 frequency_hz: channel.uplink_hz,
2165 data_rate,
2166 link,
2167 output_dbm: self.output_dbm(channel.uplink_hz, tx_power),
2168 airtime_us,
2169 rx1: Window {
2170 delay_us: delay1,
2171 frequency_hz: channel.downlink_hz,
2172 data_rate: rx1_rate,
2173 link: self.downlink_link(rx1_rate)?,
2174 },
2175 rx2: Window {
2176 delay_us: delay2,
2177 frequency_hz: rx2_hz,
2178 data_rate: rx2_rate,
2179 link: self.downlink_link(rx2_rate)?,
2180 },
2181 carries_payload,
2182 relay,
2183 })
2184 }
2185}
2186
2187#[cfg(test)]
2188mod relayed_tests;
2189#[cfg(test)]
2190mod tests;