Skip to main content

pamoja_radios/sx1302/
channel.rs

1//! Pointing a concentrator at the channels it listens on.
2//!
3//! A concentrator that has been reset, identified and given firmware still hears nothing. Its
4//! receivers have not been told which intermediate frequencies to listen on, which radio each
5//! takes its samples from, which spreading factors to look for, or that they may run at all.
6//! This is what closes that gap.
7//!
8//! There are ten receivers. Eight take any spreading factor and share a bandwidth fixed in
9//! hardware at 125 kHz. One more is fixed to a single spreading factor and bandwidth, which
10//! is what a network calls its service channel. The last hears frequency shift keying.
11//!
12//! Every frequency here is an offset from the carrier a front end is tuned to, not a carrier
13//! of its own, which is why a plan is described relative to the radio it sits on.
14//!
15//! Nothing here opens a bus. The order is data, so it can be checked against the reference
16//! with no hardware present.
17
18use super::register::{self, Bank, Register};
19use super::tx::{bandwidth_value, Chain};
20
21/// The bandwidth every multi-spreading-factor receiver runs at, in hertz.
22///
23/// It is fixed in hardware. Only the service receiver takes a bandwidth of its own.
24pub const MULTI_BANDWIDTH_HZ: u32 = 125_000;
25
26/// How much spectrum one radio hears in total, in hertz.
27///
28/// A concentrator tunes its radios once and every channel sits inside this window. It is a
29/// property of the radio rather than of the register that carries a channel offset.
30pub const RX_BANDWIDTH_HZ: u32 = 1_600_000;
31
32/// How far from the carrier a channel can sit, in hertz.
33///
34/// Half the radio's window, less half the channel's own width. The register that carries an
35/// offset is thirteen bits and reaches far past this, so a channel beyond it is accepted by
36/// the chip and then hears nothing at all.
37pub const MAX_OFFSET_HZ: i32 = (RX_BANDWIDTH_HZ as i32 - MULTI_BANDWIDTH_HZ as i32) / 2;
38
39/// The sync symbol positions a public network uses.
40const PUBLIC_PEAKS: (u8, u8) = (6, 8);
41
42/// The ones a private network uses, which is also what the chip powers up looking for.
43const PRIVATE_PEAKS: (u8, u8) = (2, 4);
44
45/// How many receivers take any spreading factor.
46pub const MULTI_CHANNELS: usize = 8;
47
48/// The lowest spreading factor a receiver can be asked for.
49pub const MIN_SPREADING_FACTOR: u8 = 5;
50
51/// The highest.
52pub const MAX_SPREADING_FACTOR: u8 = 12;
53
54/// How many preamble symbols a receiver waits for.
55///
56/// Ten covers both cases the chip has to serve at once: twelve at the two lowest spreading
57/// factors and eight above them.
58pub const PREAMBLE_SYMBOLS: u16 = 10;
59
60/// What the channel power reading starts from.
61pub const RSSI_DEFAULT: u8 = 85;
62
63/// How heavily that reading is filtered.
64pub const RSSI_FILTER_ALPHA: u8 = 0x05;
65
66/// Frequency tracking left to the receiver.
67pub const TRACKING_AUTOMATIC: u8 = 0x03;
68
69/// Frequency tracking switched off.
70pub const TRACKING_OFF: u8 = 0x00;
71
72/// Fine timing that follows the drift in a straight line.
73pub const TIMING_LINEAR: u8 = 0x02;
74
75/// Peak selection left to the receiver.
76pub const DFT_PEAK_AUTOMATIC: u8 = 0x03;
77
78/// How many preamble symbols the fixed-rate receiver expects at the usual spreading factors.
79pub const SERVICE_PREAMBLE_SYMBOLS: u16 = 8;
80
81/// How many it expects at the two fastest, which is what end device drivers send there.
82pub const SERVICE_PREAMBLE_SYMBOLS_FAST: u16 = 12;
83
84/// How far above the noise a peak has to be for the fixed-rate receiver to take it.
85pub const SERVICE_PEAK_TO_NOISE: u8 = 52;
86
87/// How many peaks the fixed-rate receiver counts before it believes a preamble.
88pub const SERVICE_PEAK_COUNT: u8 = 7;
89
90/// How many peaks it counts on the second pass.
91pub const SERVICE_SECOND_PEAK_COUNT: u8 = 5;
92
93/// The clock the FSK bit rate is counted against, in hertz.
94pub const FSK_CLOCK_HZ: u32 = 32_000_000;
95
96/// The bit rate a LoRaWAN network runs its frequency shift keying channel at.
97pub const FSK_DEFAULT_BITRATE: u32 = 50_000;
98
99/// The sync word that channel looks for.
100pub const FSK_SYNC_WORD: u64 = 0x00c1_94c1;
101
102/// How many bytes of it there are.
103pub const FSK_SYNC_WORD_LEN: u8 = 3;
104
105/// How wide the FSK receiver listens, which is the setting for a 125 kHz channel.
106pub const FSK_BANDWIDTH_CODE: u8 = 0x03;
107
108/// How many samples the FSK receiver measures a signal level over.
109pub const FSK_RSSI_SAMPLES: u8 = 4;
110
111/// Keeping the bits from settling at one level, which a LoRaWAN FSK channel whitens.
112pub const FSK_WHITENING: u8 = 2;
113
114/// How far the bit timing may drift before a packet is given up on.
115pub const FSK_TOLERANCE: u8 = 10;
116
117/// The longest packet the FSK receiver takes.
118pub const FSK_MAX_PAYLOAD: u8 = 255;
119
120/// How long it waits for one, as the receiver counts it.
121pub const FSK_TIMEOUT: u8 = 128;
122
123/// One of the receivers that takes any spreading factor.
124#[derive(Clone, Copy, Debug, PartialEq, Eq)]
125pub struct Listener {
126    /// How far from the carrier it listens, in hertz, which is signed.
127    pub offset_hz: i32,
128    /// Which radio it takes its samples from.
129    pub chain: Chain,
130    /// Whether it runs at all.
131    pub enabled: bool,
132}
133
134impl Listener {
135    /// A receiver on the first radio, listening this far from the carrier.
136    ///
137    /// # Arguments
138    ///
139    /// * `offset_hz` - how far from the carrier, which is signed.
140    ///
141    /// # Returns
142    ///
143    /// The receiver, enabled.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use pamoja_radios::sx1302::channel::Listener;
149    /// use pamoja_radios::sx1302::tx::Chain;
150    ///
151    /// let channel = Listener::at(-400_000);
152    /// assert_eq!(channel.chain, Chain::A);
153    /// assert!(channel.enabled);
154    /// ```
155    #[must_use]
156    pub const fn at(offset_hz: i32) -> Listener {
157        Listener {
158            offset_hz,
159            chain: Chain::A,
160            enabled: true,
161        }
162    }
163
164    /// The same receiver, on the other radio.
165    ///
166    /// # Arguments
167    ///
168    /// * `chain` - the radio it takes its samples from.
169    ///
170    /// # Returns
171    ///
172    /// The receiver.
173    #[must_use]
174    pub const fn on(mut self, chain: Chain) -> Listener {
175        self.chain = chain;
176        self
177    }
178
179    /// The same receiver, switched off.
180    ///
181    /// # Returns
182    ///
183    /// The receiver, which will neither be clocked nor correlated.
184    #[must_use]
185    pub const fn off(mut self) -> Listener {
186        self.enabled = false;
187        self
188    }
189}
190
191impl Default for Listener {
192    fn default() -> Listener {
193        Listener::at(0).off()
194    }
195}
196
197/// What a receiver is told when the packets it hears carry no header of their own.
198///
199/// A header carries the length, the coding rate, and whether a checksum follows. Without one
200/// the receiver has to be told all three up front, and it hears nothing from a sender that
201/// disagrees with any of them.
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub struct Implicit {
204    /// How long every packet is.
205    pub payload_length: u8,
206    /// The coding rate, as the denominator less four, so 4/5 is 1 and 4/8 is 4.
207    pub coding_rate: u8,
208    /// Whether a checksum follows the payload.
209    pub crc: bool,
210}
211
212/// The receiver fixed to one spreading factor, which is what a network calls its service
213/// channel.
214///
215/// The eight receivers beside it take any spreading factor and share a bandwidth fixed in
216/// hardware at 125 kHz. This one takes exactly one spreading factor and a bandwidth of its
217/// own, which is what lets a network carry a faster rate on a channel of its own.
218#[derive(Clone, Copy, Debug, PartialEq, Eq)]
219pub struct Service {
220    /// How far from the carrier it listens, in hertz, which is signed.
221    pub offset_hz: i32,
222    /// Which radio it takes its samples from.
223    pub chain: Chain,
224    /// The one spreading factor it looks for.
225    pub spreading_factor: u8,
226    /// The bandwidth it runs at, in hertz. It is the only receiver that takes its own.
227    pub bandwidth_hz: u32,
228    /// What it assumes when a packet carries no header, or `None` when packets carry one.
229    pub implicit: Option<Implicit>,
230}
231
232impl Service {
233    /// A service channel on the first radio, at 125 kHz, hearing packets that carry a header.
234    ///
235    /// # Arguments
236    ///
237    /// * `offset_hz` - how far from the carrier it listens, which is signed.
238    /// * `spreading_factor` - the one spreading factor it looks for.
239    ///
240    /// # Returns
241    ///
242    /// The service channel.
243    ///
244    /// # Examples
245    ///
246    /// ```
247    /// use pamoja_radios::sx1302::channel::Service;
248    /// use pamoja_radios::sx1302::tx::Chain;
249    ///
250    /// // The channel a European network runs at its fast rate: SF7 on 250 kHz.
251    /// let service = Service::at(300_000, 7).bandwidth(250_000);
252    /// assert_eq!(service.chain, Chain::A);
253    /// assert!(service.implicit.is_none(), "packets carry their own header");
254    /// ```
255    #[must_use]
256    pub const fn at(offset_hz: i32, spreading_factor: u8) -> Service {
257        Service {
258            offset_hz,
259            chain: Chain::A,
260            spreading_factor,
261            bandwidth_hz: MULTI_BANDWIDTH_HZ,
262            implicit: None,
263        }
264    }
265
266    /// The same channel, on the other radio.
267    ///
268    /// # Arguments
269    ///
270    /// * `chain` - the radio it takes its samples from.
271    ///
272    /// # Returns
273    ///
274    /// The service channel.
275    #[must_use]
276    pub const fn on(mut self, chain: Chain) -> Service {
277        self.chain = chain;
278        self
279    }
280
281    /// The same channel, at a bandwidth of its own.
282    ///
283    /// # Arguments
284    ///
285    /// * `bandwidth_hz` - 125000, 250000, or 500000. Anything else leaves a plan a
286    ///   concentrator refuses rather than one it quietly narrows.
287    ///
288    /// # Returns
289    ///
290    /// The service channel.
291    #[must_use]
292    pub const fn bandwidth(mut self, bandwidth_hz: u32) -> Service {
293        self.bandwidth_hz = bandwidth_hz;
294        self
295    }
296
297    /// The same channel, hearing packets that carry no header.
298    ///
299    /// # Arguments
300    ///
301    /// * `implicit` - what every packet is, since nothing on the air will say.
302    ///
303    /// # Returns
304    ///
305    /// The service channel.
306    #[must_use]
307    pub const fn without_header(mut self, implicit: Implicit) -> Service {
308        self.implicit = Some(implicit);
309        self
310    }
311
312    /// Whether the concentrator can be set to this channel at all.
313    ///
314    /// # Returns
315    ///
316    /// Whether the spreading factor and the bandwidth are ones the chip takes, and the
317    /// offset is one the radio hears.
318    ///
319    /// # Examples
320    ///
321    /// ```
322    /// use pamoja_radios::sx1302::channel::Service;
323    ///
324    /// assert!(Service::at(300_000, 7).bandwidth(250_000).supported());
325    /// assert!(!Service::at(300_000, 7).bandwidth(200_000).supported(), "not a bandwidth");
326    /// assert!(!Service::at(300_000, 13).supported(), "not a spreading factor");
327    /// assert!(!Service::at(900_000, 7).supported(), "past what the radio hears");
328    /// ```
329    #[must_use]
330    pub const fn supported(&self) -> bool {
331        reachable(self.offset_hz)
332            && bandwidth_value(self.bandwidth_hz).is_some()
333            && self.spreading_factor >= MIN_SPREADING_FACTOR
334            && self.spreading_factor <= MAX_SPREADING_FACTOR
335    }
336}
337
338/// The receiver that hears frequency shift keying rather than LoRa.
339///
340/// A LoRaWAN network carries one such channel, faster than any of its LoRa rates and with
341/// none of their reach. It is the tenth receiver, beside the eight and the fixed-rate one,
342/// and like them it is switched on whatever a plan says.
343#[derive(Clone, Copy, Debug, PartialEq, Eq)]
344pub struct Fsk {
345    /// How far from the carrier it listens, in hertz, which is signed.
346    pub offset_hz: i32,
347    /// Which radio it takes its samples from.
348    pub chain: Chain,
349    /// The bit rate, in bits per second.
350    pub bitrate: u32,
351    /// The sync word it matches, in its low bytes.
352    pub sync_word: u64,
353    /// How many bytes of that sync word there are.
354    pub sync_word_len: u8,
355}
356
357impl Fsk {
358    /// A channel on the first radio, at the rate and sync word a LoRaWAN network uses.
359    ///
360    /// # Arguments
361    ///
362    /// * `offset_hz` - how far from the carrier it listens, which is signed.
363    ///
364    /// # Returns
365    ///
366    /// The channel.
367    ///
368    /// # Examples
369    ///
370    /// ```
371    /// use pamoja_radios::sx1302::channel::{Fsk, FSK_DEFAULT_BITRATE};
372    ///
373    /// let channel = Fsk::at(600_000);
374    /// assert_eq!(channel.bitrate, FSK_DEFAULT_BITRATE);
375    /// assert_eq!(channel.sync_word_len, 3);
376    /// ```
377    #[must_use]
378    pub const fn at(offset_hz: i32) -> Fsk {
379        Fsk {
380            offset_hz,
381            chain: Chain::A,
382            bitrate: FSK_DEFAULT_BITRATE,
383            sync_word: FSK_SYNC_WORD,
384            sync_word_len: FSK_SYNC_WORD_LEN,
385        }
386    }
387
388    /// The same channel, on the other radio.
389    ///
390    /// A European network puts this channel at 868.8 MHz, which is further from the carrier
391    /// than one radio hears, so it usually belongs on the second one.
392    ///
393    /// # Arguments
394    ///
395    /// * `chain` - the radio it takes its samples from.
396    ///
397    /// # Returns
398    ///
399    /// The channel.
400    #[must_use]
401    pub const fn on(mut self, chain: Chain) -> Fsk {
402        self.chain = chain;
403        self
404    }
405
406    /// The same channel, at another bit rate.
407    ///
408    /// # Arguments
409    ///
410    /// * `bitrate` - the rate, in bits per second.
411    ///
412    /// # Returns
413    ///
414    /// The channel.
415    #[must_use]
416    pub const fn bitrate(mut self, bitrate: u32) -> Fsk {
417        self.bitrate = bitrate;
418        self
419    }
420
421    /// The same channel, matching another sync word.
422    ///
423    /// # Arguments
424    ///
425    /// * `sync_word` - the word, in the low bytes.
426    /// * `len` - how many bytes of it, up to eight.
427    ///
428    /// # Returns
429    ///
430    /// The channel.
431    #[must_use]
432    pub const fn matching(mut self, sync_word: u64, len: u8) -> Fsk {
433        self.sync_word = sync_word;
434        self.sync_word_len = len;
435        self
436    }
437
438    /// The pattern the receiver is programmed with.
439    ///
440    /// # Returns
441    ///
442    /// The sync word moved into the top of the pattern, which is where the receiver reads it
443    /// from however few bytes it has.
444    ///
445    /// # Examples
446    ///
447    /// ```
448    /// use pamoja_radios::sx1302::channel::Fsk;
449    ///
450    /// // Three bytes sit at the top, not the bottom.
451    /// assert_eq!(Fsk::at(0).pattern(), 0xc194_c100_0000_0000);
452    /// ```
453    #[must_use]
454    pub const fn pattern(&self) -> u64 {
455        let len = if self.sync_word_len > 8 {
456            8
457        } else {
458            self.sync_word_len
459        };
460        self.sync_word << (8 * (8 - len) as u32)
461    }
462
463    /// Whether the concentrator can be set to this channel at all.
464    ///
465    /// # Returns
466    ///
467    /// Whether the offset is one the radio hears, the sync word is between one and eight
468    /// bytes, and the bit rate is one the counter can hold.
469    ///
470    /// # Examples
471    ///
472    /// ```
473    /// use pamoja_radios::sx1302::channel::Fsk;
474    ///
475    /// assert!(Fsk::at(600_000).supported());
476    /// assert!(!Fsk::at(900_000).supported(), "past what the radio hears");
477    /// assert!(!Fsk::at(0).bitrate(100).supported(), "too slow to count");
478    /// assert!(!Fsk::at(0).matching(0, 9).supported(), "longer than the pattern");
479    /// ```
480    #[must_use]
481    pub const fn supported(&self) -> bool {
482        reachable(self.offset_hz)
483            && self.sync_word_len >= 1
484            && self.sync_word_len <= 8
485            && self.bitrate > 0
486            && FSK_CLOCK_HZ / self.bitrate <= u16::MAX as u32
487    }
488}
489
490/// What a concentrator is to listen for.
491#[derive(Clone, Copy, Debug, PartialEq, Eq)]
492pub struct Plan {
493    /// The carrier the first radio is tuned to, in hertz, which every offset is measured
494    /// from.
495    pub carrier_hz: u32,
496    /// The eight receivers that take any spreading factor.
497    pub channels: [Listener; MULTI_CHANNELS],
498    /// Which spreading factors to look for, one bit each counting from
499    /// [`MIN_SPREADING_FACTOR`].
500    pub spreading_factors: u8,
501    /// Whether the network is a public one, which decides the sync word the receivers look
502    /// for. LoRaWAN networks are public; the chip powers up expecting a private one.
503    pub public: bool,
504    /// The receiver fixed to one spreading factor, or `None` to leave it where reset left it.
505    pub service: Option<Service>,
506    /// The receiver that hears frequency shift keying, or `None` to leave it where reset
507    /// left it.
508    pub fsk: Option<Fsk>,
509}
510
511impl Plan {
512    /// A plan on one carrier, listening on these offsets.
513    ///
514    /// # Arguments
515    ///
516    /// * `carrier_hz` - what the radio is tuned to.
517    /// * `offsets_hz` - how far from it each receiver listens. Anything past the eighth is
518    ///   ignored, and any receiver left over is switched off.
519    ///
520    /// # Returns
521    ///
522    /// The plan, looking for every spreading factor.
523    ///
524    /// # Examples
525    ///
526    /// ```
527    /// use pamoja_radios::sx1302::channel::Plan;
528    ///
529    /// // The eight channels a European gateway usually runs, 867.1 MHz through 868.5 MHz.
530    /// // The carrier sits in the middle of them, because a radio only hears so far either
531    /// // side of what it is tuned to.
532    /// let plan = Plan::new(
533    ///     867_800_000,
534    ///     &[-700_000, -500_000, -300_000, -100_000, 100_000, 300_000, 500_000, 700_000],
535    /// );
536    /// assert!(plan.channels[0].enabled);
537    /// assert_eq!(plan.channels[4].offset_hz, 100_000);
538    /// ```
539    #[must_use]
540    pub fn new(carrier_hz: u32, offsets_hz: &[i32]) -> Plan {
541        let mut channels = [Listener::default(); MULTI_CHANNELS];
542        let mut at = 0;
543        while at < MULTI_CHANNELS && at < offsets_hz.len() {
544            channels[at] = Listener::at(offsets_hz[at]);
545            at += 1;
546        }
547        Plan {
548            carrier_hz,
549            channels,
550            spreading_factors: every_spreading_factor(),
551            public: true,
552            service: None,
553            fsk: None,
554        }
555    }
556
557    /// The same plan, on a public network or a private one.
558    ///
559    /// # Arguments
560    ///
561    /// * `public` - whether the network is public. Every LoRaWAN network is.
562    ///
563    /// # Returns
564    ///
565    /// The plan.
566    ///
567    /// # Examples
568    ///
569    /// ```
570    /// use pamoja_radios::sx1302::channel::Plan;
571    ///
572    /// // A plan listens to a public network unless it is told otherwise.
573    /// assert!(Plan::new(867_800_000, &[0]).public);
574    /// assert!(!Plan::new(867_800_000, &[0]).network(false).public);
575    /// ```
576    #[must_use]
577    pub const fn network(mut self, public: bool) -> Plan {
578        self.public = public;
579        self
580    }
581
582    /// The same plan, with the fixed-rate receiver pointed at a channel.
583    ///
584    /// That receiver is switched on whatever a plan says, so one never given a channel
585    /// listens wherever reset left it. This is what gives it somewhere to listen.
586    ///
587    /// # Arguments
588    ///
589    /// * `service` - the channel it runs on.
590    ///
591    /// # Returns
592    ///
593    /// The plan.
594    ///
595    /// # Examples
596    ///
597    /// ```
598    /// use pamoja_radios::sx1302::channel::{Plan, Service};
599    ///
600    /// let plan = Plan::new(867_800_000, &[-300_000])
601    ///     .serving(Service::at(500_000, 7).bandwidth(250_000));
602    /// assert_eq!(plan.service.map(|service| service.spreading_factor), Some(7));
603    /// ```
604    #[must_use]
605    pub const fn serving(mut self, service: Service) -> Plan {
606        self.service = Some(service);
607        self
608    }
609
610    /// The same plan, with the frequency shift keying receiver pointed at a channel.
611    ///
612    /// That receiver is switched on whatever a plan says, so one never given a channel
613    /// listens wherever reset left it, as the fixed-rate one does.
614    ///
615    /// # Arguments
616    ///
617    /// * `fsk` - the channel it runs on.
618    ///
619    /// # Returns
620    ///
621    /// The plan.
622    ///
623    /// # Examples
624    ///
625    /// ```
626    /// use pamoja_radios::sx1302::channel::{Fsk, Plan};
627    /// use pamoja_radios::sx1302::tx::Chain;
628    ///
629    /// let plan = Plan::new(867_800_000, &[-300_000]).hearing(Fsk::at(600_000).on(Chain::B));
630    /// assert_eq!(plan.fsk.map(|fsk| fsk.bitrate), Some(50_000));
631    /// ```
632    #[must_use]
633    pub const fn hearing(mut self, fsk: Fsk) -> Plan {
634        self.fsk = Some(fsk);
635        self
636    }
637
638    /// The same plan, looking only for these spreading factors.
639    ///
640    /// # Arguments
641    ///
642    /// * `wanted` - the spreading factors to look for. Anything outside 5 to 12 is ignored.
643    ///
644    /// # Returns
645    ///
646    /// The plan.
647    ///
648    /// # Examples
649    ///
650    /// ```
651    /// use pamoja_radios::sx1302::channel::Plan;
652    ///
653    /// // A network that only runs the faster half of the range.
654    /// let plan = Plan::new(867_500_000, &[-400_000]).looking_for(&[7, 8, 9]);
655    /// assert_eq!(plan.spreading_factors, 0b0001_1100);
656    /// ```
657    #[must_use]
658    pub fn looking_for(mut self, wanted: &[u8]) -> Plan {
659        let mut mask = 0u8;
660        let mut at = 0;
661        while at < wanted.len() {
662            let spreading_factor = wanted[at];
663            if (MIN_SPREADING_FACTOR..=MAX_SPREADING_FACTOR).contains(&spreading_factor) {
664                mask |= 1 << (spreading_factor - MIN_SPREADING_FACTOR);
665            }
666            at += 1;
667        }
668        self.spreading_factors = mask;
669        self
670    }
671
672    /// Which radio each receiver takes its samples from, one bit per receiver.
673    ///
674    /// # Returns
675    ///
676    /// The mask the chip takes, with a bit set for every receiver on the second radio.
677    ///
678    /// # Examples
679    ///
680    /// ```
681    /// use pamoja_radios::sx1302::channel::Plan;
682    /// use pamoja_radios::sx1302::tx::Chain;
683    ///
684    /// let mut plan = Plan::new(867_500_000, &[0, 0]);
685    /// plan.channels[1] = plan.channels[1].on(Chain::B);
686    /// assert_eq!(plan.radios(), 0b0000_0010);
687    /// ```
688    #[must_use]
689    pub const fn radios(&self) -> u8 {
690        let mut mask = 0u8;
691        let mut at = 0;
692        while at < MULTI_CHANNELS {
693            if matches!(self.channels[at].chain, Chain::B) {
694                mask |= 1 << at;
695            }
696            at += 1;
697        }
698        mask
699    }
700
701    /// Which receivers run, one bit each.
702    ///
703    /// # Returns
704    ///
705    /// The mask the chip takes.
706    ///
707    /// # Examples
708    ///
709    /// ```
710    /// use pamoja_radios::sx1302::channel::Plan;
711    ///
712    /// // Three offsets given, so three receivers run and five do not.
713    /// let plan = Plan::new(867_500_000, &[-400_000, -200_000, 0]);
714    /// assert_eq!(plan.running(), 0b0000_0111);
715    /// ```
716    #[must_use]
717    pub const fn running(&self) -> u8 {
718        let mut mask = 0u8;
719        let mut at = 0;
720        while at < MULTI_CHANNELS {
721            if self.channels[at].enabled {
722                mask |= 1 << at;
723            }
724            at += 1;
725        }
726        mask
727    }
728}
729
730/// Every spreading factor, as the mask the chip takes.
731///
732/// # Returns
733///
734/// A bit for each of the eight, counting from [`MIN_SPREADING_FACTOR`].
735///
736/// # Examples
737///
738/// ```
739/// use pamoja_radios::sx1302::channel::every_spreading_factor;
740///
741/// assert_eq!(every_spreading_factor(), 0xff);
742/// ```
743#[must_use]
744pub const fn every_spreading_factor() -> u8 {
745    0xff
746}
747
748/// Turns an offset from the carrier into the value a channel register takes.
749///
750/// The chip counts in steps of its own, not in hertz: the register is the offset times 32
751/// over 15625, which divides exactly. A negative offset is carried as the low thirteen bits,
752/// which is what the two registers hold between them.
753///
754/// # Arguments
755///
756/// * `offset_hz` - how far from the carrier, which is signed.
757///
758/// # Returns
759///
760/// The value, of which the high five bits and the low eight are written separately.
761///
762/// # Examples
763///
764/// ```
765/// use pamoja_radios::sx1302::channel::offset_value;
766///
767/// // A channel 400 kHz below the carrier.
768/// assert_eq!(offset_value(-400_000), (-819i16) as u16 & 0x1fff);
769///
770/// // And one on it.
771/// assert_eq!(offset_value(0), 0);
772/// ```
773#[must_use]
774pub const fn offset_value(offset_hz: i32) -> u16 {
775    let steps = (offset_hz as i64 * 32 / 15_625) as i32;
776    (steps as u16) & 0x1fff
777}
778
779/// Splits a channel offset into the two bytes its registers take.
780///
781/// # Arguments
782///
783/// * `offset_hz` - how far from the carrier.
784///
785/// # Returns
786///
787/// The high bits and then the low bits.
788///
789/// # Examples
790///
791/// ```
792/// use pamoja_radios::sx1302::channel::offset_bytes;
793///
794/// let [high, low] = offset_bytes(-400_000);
795/// assert_eq!(high, 0x1c);
796/// assert_eq!(low, 0xcd);
797/// ```
798#[must_use]
799pub const fn offset_bytes(offset_hz: i32) -> [u8; 2] {
800    let value = offset_value(offset_hz);
801    [((value >> 8) & 0x1f) as u8, (value & 0xff) as u8]
802}
803
804/// How fast a frequency error turns into a timing one, as a mantissa and a shift.
805///
806/// The receiver corrects timing from the frequency error it measures, and how much it should
807/// correct depends on where the carrier sits: the same error is a larger fraction of a lower
808/// carrier. The chip takes that as a mantissa of at least 2048 and the shift that got it
809/// there.
810///
811/// # Arguments
812///
813/// * `bandwidth_hz` - the bandwidth the receiver runs at.
814/// * `carrier_hz` - what the radio is tuned to.
815///
816/// # Returns
817///
818/// The mantissa and the shift, or `None` for a carrier of zero.
819///
820/// # Examples
821///
822/// ```
823/// use pamoja_radios::sx1302::channel::drift;
824///
825/// // At 125 kHz on 868.1 MHz the ratio starts at 150 and doubles four times to reach 2400.
826/// assert_eq!(drift(125_000, 868_100_000), Some((2400, 4)));
827/// ```
828#[must_use]
829pub const fn drift(bandwidth_hz: u32, carrier_hz: u32) -> Option<(u16, u8)> {
830    if carrier_hz == 0 {
831        return None;
832    }
833    let mut mantissa = (bandwidth_hz as u64) * (1 << 20) / (carrier_hz as u64);
834    let mut shift = 0u8;
835    while mantissa < 2048 {
836        mantissa <<= 1;
837        shift += 1;
838    }
839    Some((mantissa as u16, shift))
840}
841
842/// A step in pointing a concentrator at its channels.
843///
844/// The order is carried as data, so a driver walks it against a bus and a test walks it
845/// against nothing.
846#[derive(Clone, Copy, Debug, PartialEq, Eq)]
847pub enum Step {
848    /// Write a value into one register.
849    Write(Register, u8),
850}
851
852/// The order a concentrator is pointed at its channels in.
853///
854/// The receivers are given their frequencies and radios, then the correlators are tuned and
855/// told which spreading factors to look for, then the demodulators are set up, and only at
856/// the end is anything switched on. Enabling earlier would start receivers that have not been
857/// told where to listen.
858///
859/// # Arguments
860///
861/// * `plan` - what to listen for.
862///
863/// # Returns
864///
865/// The steps, in the order the chip takes them.
866///
867/// # Examples
868///
869/// ```
870/// use pamoja_radios::sx1302::channel::{steps, Plan, Step};
871/// use pamoja_radios::sx1302::register;
872///
873/// let plan = Plan::new(867_500_000, &[-400_000, -200_000, 0]);
874/// let order: Vec<Step> = steps(&plan).collect();
875///
876/// // Nothing is switched on until the end.
877/// let enable = order
878///     .iter()
879///     .position(|step| matches!(step, Step::Write(register, _) if *register == register::COMMON_GLOBAL_ENABLE))
880///     .expect("the receivers are switched on");
881/// assert_eq!(enable, order.len() - 1);
882/// ```
883pub fn steps(plan: &Plan) -> impl Iterator<Item = Step> + '_ {
884    channelizer(plan)
885        .chain(correlators(plan))
886        .chain(demodulators(plan))
887        .chain(syncword(plan))
888        .chain(service(plan))
889        .chain(fsk(plan))
890        .chain(enables())
891}
892
893/// Telling the receivers which network they are listening to.
894///
895/// A LoRa preamble ends in two symbols whose positions say which network a frame belongs to,
896/// and the chip looks for them where it is told. It powers up looking for a private network,
897/// so receivers that are never given this hear nothing from a public one however well
898/// everything else is configured.
899///
900/// The two lowest spreading factors have no public form and always take the private
901/// positions, which is what the reference does.
902fn syncword(plan: &Plan) -> impl Iterator<Item = Step> {
903    let (first, second) = if plan.public {
904        PUBLIC_PEAKS
905    } else {
906        PRIVATE_PEAKS
907    };
908    let (low_first, low_second) = PRIVATE_PEAKS;
909
910    // The fixed-rate receiver follows the network, except at the two fastest spreading
911    // factors, which have no public form however public the network is.
912    let (service_first, service_second) = match plan.service {
913        Some(service) if matches!(service.spreading_factor, 5 | 6) => PRIVATE_PEAKS,
914        _ => (first, second),
915    };
916
917    [
918        Step::Write(register::RX_SYNC_SF5_PEAK1, low_first),
919        Step::Write(register::RX_SYNC_SF5_PEAK2, low_second),
920        Step::Write(register::RX_SYNC_SF6_PEAK1, low_first),
921        Step::Write(register::RX_SYNC_SF6_PEAK2, low_second),
922        Step::Write(register::RX_SYNC_SF7_TO_SF12_PEAK1, first),
923        Step::Write(register::RX_SYNC_SF7_TO_SF12_PEAK2, second),
924        Step::Write(register::SERVICE_SYNC_PEAK1, service_first),
925        Step::Write(register::SERVICE_SYNC_PEAK2, service_second),
926    ]
927    .into_iter()
928}
929
930/// Whether a rate is slow enough to need the low data rate optimization.
931///
932/// A symbol that lasts long enough drifts against the receiver clock before it ends, and the
933/// two ends have to agree to carry fewer bits in it. Which rates those are depends on the
934/// bandwidth as well as the spreading factor.
935///
936/// # Arguments
937///
938/// * `spreading_factor` - the spreading factor.
939/// * `bandwidth_hz` - the bandwidth, in hertz.
940///
941/// # Returns
942///
943/// Whether the optimization is on for that pair.
944///
945/// # Examples
946///
947/// ```
948/// use pamoja_radios::sx1302::channel::low_rate_optimize;
949///
950/// assert!(low_rate_optimize(11, 125_000));
951/// assert!(low_rate_optimize(12, 125_000));
952/// assert!(!low_rate_optimize(10, 125_000));
953///
954/// // The same spreading factor twice as wide halves the symbol, so it is only on at SF12.
955/// assert!(!low_rate_optimize(11, 250_000));
956/// assert!(low_rate_optimize(12, 250_000));
957/// assert!(!low_rate_optimize(12, 500_000));
958/// ```
959#[must_use]
960pub const fn low_rate_optimize(spreading_factor: u8, bandwidth_hz: u32) -> bool {
961    match bandwidth_hz {
962        125_000 => matches!(spreading_factor, 11 | 12),
963        250_000 => spreading_factor == 12,
964        _ => false,
965    }
966}
967
968/// Whether a channel offset is one the radio can actually hear.
969///
970/// # Arguments
971///
972/// * `offset_hz` - how far from the carrier the channel sits.
973///
974/// # Returns
975///
976/// Whether it falls inside the radio's window.
977///
978/// # Examples
979///
980/// ```
981/// use pamoja_radios::sx1302::channel::{reachable, MAX_OFFSET_HZ};
982///
983/// assert_eq!(MAX_OFFSET_HZ, 737_500);
984/// assert!(reachable(700_000));
985///
986/// // The register carries this happily. The radio does not hear it.
987/// assert!(!reachable(1_000_000));
988/// ```
989#[must_use]
990pub const fn reachable(offset_hz: i32) -> bool {
991    offset_hz >= -MAX_OFFSET_HZ && offset_hz <= MAX_OFFSET_HZ
992}
993
994/// Giving each receiver its frequency, its radio, and the gain it reads power against.
995fn channelizer(plan: &Plan) -> impl Iterator<Item = Step> + '_ {
996    let frequencies = (0..MULTI_CHANNELS).flat_map(move |at| {
997        let [high, low] = offset_bytes(plan.channels[at].offset_hz);
998        let [msb, lsb] = register::channel_frequency(at as u8);
999        [Step::Write(msb, high), Step::Write(lsb, low)]
1000    });
1001
1002    [
1003        Step::Write(register::RX_RADIO_SELECT, plan.radios()),
1004        Step::Write(register::RX_RSSI_FILTER_ALPHA, RSSI_FILTER_ALPHA),
1005        Step::Write(register::RX_RSSI_DEFAULT, RSSI_DEFAULT),
1006        Step::Write(register::RX_GAIN_AUTOMATIC, 0x01),
1007        Step::Write(register::RX_GAIN_THRESHOLD_HIGH, 0xff),
1008        Step::Write(register::RX_GAIN_THRESHOLD_LOW, 0x00),
1009        Step::Write(register::RX_GAIN_MAX_ATTENUATION, 15),
1010        Step::Write(register::RX_GAIN_MIN_ATTENUATION, 0),
1011    ]
1012    .into_iter()
1013    .chain(frequencies)
1014}
1015
1016/// Tuning detection for every spreading factor, then saying which to look for.
1017fn correlators(plan: &Plan) -> impl Iterator<Item = Step> + '_ {
1018    let tuned = (MIN_SPREADING_FACTOR..=MAX_SPREADING_FACTOR).flat_map(|spreading_factor| {
1019        let correlator = register::correlator(spreading_factor);
1020        [
1021            Step::Write(correlator.accumulated_ratio, 52),
1022            Step::Write(correlator.peak_ratio, 24),
1023            Step::Write(correlator.peaks, 7),
1024            Step::Write(correlator.second_peaks, 5),
1025        ]
1026    });
1027
1028    tuned.chain([
1029        Step::Write(register::RX_CORRELATOR_FIRST_EDGE, 0xff),
1030        Step::Write(register::RX_CORRELATOR_CLEAR, 0xff),
1031        Step::Write(register::RX_CORRELATOR_SF_ENABLE, plan.spreading_factors),
1032        Step::Write(register::RX_CORRELATOR_CLOCK_ENABLE, plan.running()),
1033    ])
1034}
1035
1036/// Setting up the demodulators behind the correlators.
1037fn demodulators(plan: &Plan) -> impl Iterator<Item = Step> + '_ {
1038    let sync = (0..MULTI_CHANNELS).map(|at| {
1039        // The four receivers on each radio are staggered so they do not all look at once.
1040        let offset = [1u8, 5, 9, 13][at % 4];
1041        Step::Write(register::channel_sync_offset(at as u8), offset)
1042    });
1043
1044    let tracking = (MIN_SPREADING_FACTOR..=MAX_SPREADING_FACTOR).flat_map(|spreading_factor| {
1045        [
1046            Step::Write(
1047                register::frequency_tracking(Bank::Demodulation, spreading_factor),
1048                TRACKING_AUTOMATIC,
1049            ),
1050            Step::Write(
1051                register::frequency_tracking(Bank::Timestamping, spreading_factor),
1052                TRACKING_OFF,
1053            ),
1054        ]
1055    });
1056
1057    let corrections = (MIN_SPREADING_FACTOR..=MAX_SPREADING_FACTOR).map(|spreading_factor| {
1058        // The two slowest spreading factors drift far enough across a symbol to need it.
1059        let correction = u8::from(spreading_factor >= 11);
1060        Step::Write(register::drift_correction(spreading_factor), correction)
1061    });
1062
1063    let (mantissa, shift) = drift(MULTI_BANDWIDTH_HZ, plan.carrier_hz).unwrap_or((2048, 0));
1064    let preamble = PREAMBLE_SYMBOLS.to_be_bytes();
1065
1066    [
1067        Step::Write(register::RX_DC_NOTCH_ENABLE, 0x00),
1068        Step::Write(register::RX_FORCE_DEFAULT_FILTER, 0x01),
1069        Step::Write(register::RX_GAIN_DROP_COMPENSATION, 0x01),
1070        Step::Write(register::RX_GAIN_TARGET_LEVEL, 0x01),
1071        Step::Write(register::MODEM_ENABLE_FULL, 0xff),
1072        Step::Write(register::MODEM_ENABLE_LIMITED, 0xff),
1073        Step::Write(register::RX_MODEM_SYNC_DELTA_MSB, 0),
1074        Step::Write(register::RX_MODEM_SYNC_DELTA_LSB, 126),
1075    ]
1076    .into_iter()
1077    .chain(sync)
1078    .chain(corrections)
1079    .chain([
1080        Step::Write(register::RX_FINE_TIMING_GAIN_AUTO, 3),
1081        Step::Write(register::RX_FINE_TIMING_GAIN_PAYLOAD, 3),
1082        Step::Write(register::RX_FINE_TIMING_INTEGRATE_SF11, 1),
1083        Step::Write(register::RX_FINE_TIMING_INTEGRATE_SF12, 1),
1084        Step::Write(register::RX_FREQUENCY_SYNC_THRESHOLD, 15),
1085    ])
1086    .chain(tracking)
1087    .chain([
1088        Step::Write(register::RX_TIMING_INTEGRATE_SF11, 0),
1089        Step::Write(register::RX_TIMING_INTEGRATE_SF12, 0),
1090        Step::Write(register::RX_TIMING_ROUNDING, 1),
1091        Step::Write(register::RX_TIMING_MODE, TIMING_LINEAR),
1092        Step::Write(register::RX_TIMING_GAIN_AUTO, 0),
1093        Step::Write(register::RX_TIMING_GAIN_PREAMBLE, 6),
1094        Step::Write(register::RX_TIMING_GAIN_PAYLOAD, 2),
1095        Step::Write(register::RX_TIMING_INTEGRAL_AUTO, 0),
1096        Step::Write(register::RX_TIMING_INTEGRAL_PREAMBLE, 1),
1097        Step::Write(register::RX_TIMING_INTEGRAL_PAYLOAD, 0),
1098        Step::Write(register::RX_PREAMBLE_SYMBOLS_MSB, preamble[0]),
1099        Step::Write(register::RX_PREAMBLE_SYMBOLS_LSB, preamble[1]),
1100        Step::Write(
1101            register::RX_DRIFT_MANTISSA_MSB,
1102            ((mantissa >> 8) & 0x0f) as u8,
1103        ),
1104        Step::Write(register::RX_DRIFT_MANTISSA_LSB, (mantissa & 0xff) as u8),
1105        Step::Write(register::RX_DRIFT_EXPONENT, shift),
1106        Step::Write(register::RX_DRIFT_INVERT_SYMBOL_TIME, 1),
1107        Step::Write(register::RX_DFT_PEAK_MODE, DFT_PEAK_AUTOMATIC),
1108    ])
1109}
1110
1111/// Pointing the fixed-rate receiver at its channel, when a plan gives it one.
1112///
1113/// A plan without one writes nothing here, which leaves that receiver switched on and
1114/// listening wherever reset left it.
1115fn service(plan: &Plan) -> impl Iterator<Item = Step> + '_ {
1116    plan.service.into_iter().flat_map(move |service| {
1117        let spreading_factor = service.spreading_factor;
1118        let [high, low] = offset_bytes(service.offset_hz);
1119
1120        // A bandwidth the chip has no encoding for is refused before a plan reaches a bus,
1121        // so this only decides what a plan that never will looks like.
1122        let bandwidth = bandwidth_value(service.bandwidth_hz).unwrap_or(0);
1123
1124        let fast = matches!(spreading_factor, 5 | 6);
1125        let preamble = if fast {
1126            SERVICE_PREAMBLE_SYMBOLS_FAST
1127        } else {
1128            SERVICE_PREAMBLE_SYMBOLS
1129        }
1130        .to_be_bytes();
1131
1132        // A slower spreading factor holds a symbol longer, so timing is corrected harder
1133        // through the preamble and, at the two slowest, accumulated through the payload.
1134        let preamble_gain = match spreading_factor {
1135            5 | 6 => 4,
1136            7..=10 => 6,
1137            _ => 7,
1138        };
1139        let integral_gain = match (spreading_factor, service.bandwidth_hz) {
1140            (5..=10, _) => 0,
1141            (_, 125_000) => 1,
1142            (_, 250_000) => 2,
1143            (_, 500_000) => 3,
1144            _ => 0,
1145        };
1146
1147        let implicit = service.implicit.unwrap_or(Implicit {
1148            payload_length: 0,
1149            coding_rate: 0,
1150            crc: false,
1151        });
1152        let (mantissa, shift) = drift(service.bandwidth_hz, plan.carrier_hz).unwrap_or((2048, 0));
1153
1154        [
1155            Step::Write(register::SERVICE_FREQUENCY_MSB, high),
1156            Step::Write(register::SERVICE_FREQUENCY_LSB, low),
1157            Step::Write(
1158                register::SERVICE_RADIO_SELECT,
1159                u8::from(matches!(service.chain, Chain::B)),
1160            ),
1161            Step::Write(register::SERVICE_DETECT_PEAK_COUNT, SERVICE_PEAK_COUNT),
1162            Step::Write(
1163                register::SERVICE_DETECT_PEAK_COUNT2,
1164                SERVICE_SECOND_PEAK_COUNT,
1165            ),
1166            Step::Write(register::SERVICE_DETECT_USE_GAIN_SYMBOL, 1),
1167            Step::Write(register::SERVICE_FINE_SYNC, u8::from(fast)),
1168            Step::Write(
1169                register::SERVICE_DETECT_PEAK_TO_NOISE,
1170                SERVICE_PEAK_TO_NOISE,
1171            ),
1172            Step::Write(register::SERVICE_DC_NOTCH_ENABLE, 0x00),
1173            Step::Write(register::SERVICE_FORCE_DEFAULT_FIR, 0x01),
1174            Step::Write(register::SERVICE_DAGC_GAIN_DROP_COMP, 0x01),
1175            Step::Write(register::SERVICE_DAGC_TARGET_LEVEL, 0x01),
1176            Step::Write(register::SERVICE_TIMING_GAIN_AUTOMATIC, 0x03),
1177            Step::Write(register::SERVICE_TIMING_GAIN_PAYLOAD, 0x03),
1178            Step::Write(register::SERVICE_TIMING_GAIN_PREAMBLE, preamble_gain),
1179            Step::Write(register::SERVICE_TIMING_GAIN_INTEGRAL, integral_gain),
1180            Step::Write(
1181                register::SERVICE_IMPLICIT_HEADER,
1182                u8::from(service.implicit.is_some()),
1183            ),
1184            Step::Write(register::SERVICE_CRC_ENABLE, u8::from(implicit.crc)),
1185            Step::Write(register::SERVICE_CODING_RATE, implicit.coding_rate),
1186            Step::Write(register::SERVICE_PAYLOAD_LENGTH, implicit.payload_length),
1187            Step::Write(register::SERVICE_SPREADING_FACTOR, spreading_factor),
1188            Step::Write(register::SERVICE_BANDWIDTH, bandwidth),
1189            Step::Write(
1190                register::SERVICE_PPM_OFFSET,
1191                u8::from(low_rate_optimize(spreading_factor, service.bandwidth_hz)),
1192            ),
1193            Step::Write(register::SERVICE_PREAMBLE_MSB, preamble[0]),
1194            Step::Write(register::SERVICE_PREAMBLE_LSB, preamble[1]),
1195            Step::Write(
1196                register::SERVICE_DRIFT_MANTISSA_MSB,
1197                ((mantissa >> 8) & 0x0f) as u8,
1198            ),
1199            Step::Write(
1200                register::SERVICE_DRIFT_MANTISSA_LSB,
1201                (mantissa & 0xff) as u8,
1202            ),
1203            Step::Write(register::SERVICE_DRIFT_EXPONENT, shift),
1204            Step::Write(register::SERVICE_DRIFT_INVERT_SYMBOL_TIME, 1),
1205            Step::Write(register::SERVICE_DAGC_IN_COMP, 1),
1206            Step::Write(register::SERVICE_MODEM_ENABLE, 1),
1207            Step::Write(register::SERVICE_CAD_RX_TX, 1),
1208            Step::Write(register::SERVICE_MODEM_START, 1),
1209            Step::Write(register::SERVICE_DFT_PEAK_MODE, DFT_PEAK_AUTOMATIC),
1210        ]
1211        .into_iter()
1212    })
1213}
1214
1215/// Pointing the frequency shift keying receiver at its channel, when a plan gives it one.
1216fn fsk(plan: &Plan) -> impl Iterator<Item = Step> + '_ {
1217    plan.fsk.into_iter().flat_map(move |fsk| {
1218        let [high, low] = offset_bytes(fsk.offset_hz);
1219
1220        // The rate goes out as how many clocks make a bit, not as the rate itself.
1221        let clocks = (FSK_CLOCK_HZ / fsk.bitrate.max(1)).min(u32::from(u16::MAX)) as u16;
1222
1223        // The pattern is written least significant byte first, into registers that run
1224        // backwards, so a three byte sync word ends up in the last three of them.
1225        let pattern = fsk.pattern();
1226        let sync = (0..register::FSK_SYNC_WORD_BYTES).map(move |byte| {
1227            Step::Write(
1228                register::fsk_sync_word(byte),
1229                (pattern >> (8 * u32::from(byte))) as u8,
1230            )
1231        });
1232
1233        [
1234            Step::Write(register::FSK_FREQUENCY_MSB, high),
1235            Step::Write(register::FSK_FREQUENCY_LSB, low),
1236            Step::Write(
1237                register::FSK_RADIO_SELECT,
1238                u8::from(matches!(fsk.chain, Chain::B)),
1239            ),
1240            Step::Write(
1241                register::FSK_PATTERN_SIZE,
1242                fsk.sync_word_len.saturating_sub(1),
1243            ),
1244            Step::Write(register::FSK_BITRATE_MSB, (clocks >> 8) as u8),
1245            Step::Write(register::FSK_BITRATE_LSB, clocks as u8),
1246            Step::Write(register::FSK_BANDWIDTH_EXPONENT, FSK_BANDWIDTH_CODE),
1247            Step::Write(register::FSK_INVERT_RX, 0),
1248            Step::Write(register::FSK_INVERT_IQ, 0),
1249            Step::Write(register::FSK_RSSI_LENGTH, FSK_RSSI_SAMPLES),
1250            Step::Write(register::FSK_PACKET_MODE, 1),
1251            Step::Write(register::FSK_CRC_ENABLE, 1),
1252            Step::Write(register::FSK_DCFREE_ENCODING, FSK_WHITENING),
1253            Step::Write(register::FSK_CRC_IBM, 0),
1254            Step::Write(register::FSK_ERROR_TOLERANCE, FSK_TOLERANCE),
1255            Step::Write(register::FSK_PAYLOAD_LENGTH, FSK_MAX_PAYLOAD),
1256            Step::Write(register::FSK_NODE_ADDRESS, 0),
1257            Step::Write(register::FSK_BROADCAST_ADDRESS, 0),
1258            Step::Write(register::FSK_AUTO_AFC, 1),
1259            Step::Write(register::FSK_TIMEOUT_MSB, 0),
1260            Step::Write(register::FSK_TIMEOUT_LSB, FSK_TIMEOUT),
1261        ]
1262        .into_iter()
1263        .chain(sync)
1264    })
1265}
1266
1267/// Switching the receivers on, which is the last thing done.
1268fn enables() -> impl Iterator<Item = Step> {
1269    [
1270        Step::Write(register::COMMON_MULTI_MODEM_ENABLE, 0x01),
1271        Step::Write(register::COMMON_SERVICE_MODEM_ENABLE, 0x01),
1272        Step::Write(register::COMMON_FSK_MODEM_ENABLE, 0x01),
1273        Step::Write(register::COMMON_GLOBAL_ENABLE, 0x01),
1274    ]
1275    .into_iter()
1276}
1277
1278#[cfg(test)]
1279mod tests {
1280    use super::*;
1281
1282    /// The eight channels a European gateway usually runs, around one carrier.
1283    ///
1284    /// The carrier sits in the middle of the band rather than at its low end, because a
1285    /// radio only hears so far either side of what it is tuned to.
1286    fn eu868() -> Plan {
1287        Plan::new(
1288            867_800_000,
1289            &[
1290                -700_000, -500_000, -300_000, -100_000, 100_000, 300_000, 500_000, 700_000,
1291            ],
1292        )
1293    }
1294
1295    #[test]
1296    fn the_receivers_are_told_which_network_they_are_on() {
1297        let public: Vec<Step> = steps(&eu868()).collect();
1298        let private: Vec<Step> = steps(&eu868().network(false)).collect();
1299
1300        let written = |order: &[Step], want: register::Register| {
1301            order
1302                .iter()
1303                .find_map(|Step::Write(named, value)| (*named == want).then_some(*value))
1304                .expect("the sync word is written")
1305        };
1306
1307        // A public network moves both sync symbols out. A private one leaves them where the
1308        // chip powers up, which is why a gateway that never writes these hears nothing from
1309        // a public network however well everything else is configured.
1310        assert_eq!(written(&public, register::RX_SYNC_SF7_TO_SF12_PEAK1), 6);
1311        assert_eq!(written(&public, register::RX_SYNC_SF7_TO_SF12_PEAK2), 8);
1312        assert_eq!(written(&private, register::RX_SYNC_SF7_TO_SF12_PEAK1), 2);
1313        assert_eq!(written(&private, register::RX_SYNC_SF7_TO_SF12_PEAK2), 4);
1314
1315        // The two lowest spreading factors have no public form, on either kind of network.
1316        assert_eq!(written(&public, register::RX_SYNC_SF5_PEAK1), 2);
1317        assert_eq!(written(&public, register::RX_SYNC_SF5_PEAK2), 4);
1318        assert_eq!(written(&public, register::RX_SYNC_SF6_PEAK1), 2);
1319        assert_eq!(written(&public, register::RX_SYNC_SF6_PEAK2), 4);
1320    }
1321
1322    #[test]
1323    fn the_sync_word_is_written_before_anything_is_switched_on() {
1324        let order: Vec<Step> = steps(&eu868()).collect();
1325
1326        let sync = order
1327            .iter()
1328            .position(|step| {
1329                matches!(step, Step::Write(named, _) if *named == register::RX_SYNC_SF7_TO_SF12_PEAK1)
1330            })
1331            .expect("the sync word is written");
1332        let enable = order
1333            .iter()
1334            .position(|step| {
1335                matches!(step, Step::Write(named, _) if *named == register::COMMON_GLOBAL_ENABLE)
1336            })
1337            .expect("the receivers are switched on");
1338
1339        assert!(sync < enable);
1340    }
1341
1342    #[test]
1343    fn a_channel_past_the_radio_window_is_not_reachable() {
1344        // Half the radio's window, less half a channel. The plan this file used to carry
1345        // reached a megahertz, which is past it on both counts.
1346        assert_eq!(MAX_OFFSET_HZ, 737_500);
1347        assert!(reachable(MAX_OFFSET_HZ));
1348        assert!(reachable(-MAX_OFFSET_HZ));
1349        assert!(!reachable(MAX_OFFSET_HZ + 1));
1350        assert!(!reachable(800_000));
1351        assert!(!reachable(-1_000_000));
1352
1353        // And every channel the shipped plan uses is inside it.
1354        for listener in &eu868().channels {
1355            assert!(reachable(listener.offset_hz), "{}", listener.offset_hz);
1356        }
1357    }
1358
1359    #[test]
1360    fn an_offset_is_counted_in_chip_steps() {
1361        // Worked out from the ratio rather than from the function: 400000 * 32 / 15625 is
1362        // 819 exactly, and below the carrier it is carried as a negative in thirteen bits.
1363        assert_eq!(offset_value(400_000), 819);
1364        assert_eq!(offset_value(-400_000), 0x1fff - 819 + 1);
1365        assert_eq!(offset_bytes(0), [0x00, 0x00]);
1366    }
1367
1368    #[test]
1369    fn the_drift_reaches_the_range_the_chip_wants() {
1370        // The mantissa starts below 2048 and is doubled until it is not, and the count of
1371        // doublings is what the chip is told.
1372        let (mantissa, shift) = drift(125_000, 868_100_000).expect("a real carrier");
1373        assert_eq!((mantissa, shift), (2400, 4));
1374        assert!(mantissa >= 2048);
1375
1376        // A higher carrier is a smaller ratio, so it takes one more doubling.
1377        let (_, higher) = drift(125_000, 1_500_000_000).expect("a real carrier");
1378        assert!(higher > shift);
1379
1380        assert_eq!(drift(125_000, 0), None);
1381    }
1382
1383    #[test]
1384    fn the_drift_mantissa_fits_the_field_it_is_written_to() {
1385        // The high half goes into four bits, so a mantissa over twelve bits would be cut.
1386        // Every carrier a concentrator runs on has to stay inside that.
1387        for carrier in [433_000_000, 470_000_000, 868_100_000, 915_000_000] {
1388            let (mantissa, _) = drift(MULTI_BANDWIDTH_HZ, carrier).expect("a real carrier");
1389            assert!(mantissa < 4096, "{carrier} gives {mantissa}");
1390        }
1391    }
1392
1393    #[test]
1394    fn a_plan_switches_off_the_receivers_it_was_not_given() {
1395        let plan = Plan::new(867_500_000, &[-400_000, 0]);
1396        assert_eq!(plan.running(), 0b0000_0011);
1397        assert!(!plan.channels[2].enabled);
1398
1399        // And a plan given more than there are receivers takes the first eight.
1400        let full = Plan::new(867_500_000, &[0; 12]);
1401        assert_eq!(full.running(), 0xff);
1402    }
1403
1404    #[test]
1405    fn the_radios_are_read_off_the_receivers() {
1406        let mut plan = eu868();
1407        for at in 4..MULTI_CHANNELS {
1408            plan.channels[at] = plan.channels[at].on(Chain::B);
1409        }
1410        assert_eq!(plan.radios(), 0b1111_0000);
1411    }
1412
1413    #[test]
1414    fn only_the_spreading_factors_asked_for_are_looked_for() {
1415        let plan = eu868().looking_for(&[7, 12]);
1416        assert_eq!(plan.spreading_factors, 0b1000_0100);
1417
1418        // One outside the range is not a bit anywhere.
1419        let odd = eu868().looking_for(&[4, 13]);
1420        assert_eq!(odd.spreading_factors, 0);
1421    }
1422
1423    #[test]
1424    fn nothing_runs_before_it_has_been_told_where_to_listen() {
1425        let plan = eu868();
1426        let order: Vec<Step> = steps(&plan).collect();
1427
1428        let first_frequency = order
1429            .iter()
1430            .position(|step| {
1431                matches!(step, Step::Write(register, _) if register.address == register::channel_frequency(0)[0].address)
1432            })
1433            .expect("the receivers are given their frequencies");
1434        let enable = order
1435            .iter()
1436            .position(|step| {
1437                matches!(step, Step::Write(register, _) if *register == register::COMMON_GLOBAL_ENABLE)
1438            })
1439            .expect("the receivers are switched on");
1440
1441        assert!(first_frequency < enable, "{order:?}");
1442        assert_eq!(enable, order.len() - 1);
1443    }
1444
1445    #[test]
1446    fn every_receiver_is_given_a_frequency_even_when_it_is_off() {
1447        // A receiver that is off still has its registers set, because leaving them at
1448        // whatever they held is how a channel comes back in a strange place later.
1449        let plan = Plan::new(867_500_000, &[-400_000]);
1450        let order: Vec<Step> = steps(&plan).collect();
1451
1452        for channel in 0..MULTI_CHANNELS {
1453            let [msb, _] = register::channel_frequency(channel as u8);
1454            assert!(
1455                order
1456                    .iter()
1457                    .any(|step| matches!(step, Step::Write(register, _) if *register == msb)),
1458                "channel {channel} was left as it was"
1459            );
1460        }
1461    }
1462
1463    #[test]
1464    fn the_correlators_are_tuned_for_every_spreading_factor() {
1465        let order: Vec<Step> = steps(&eu868()).collect();
1466
1467        for spreading_factor in MIN_SPREADING_FACTOR..=MAX_SPREADING_FACTOR {
1468            let correlator = register::correlator(spreading_factor);
1469            assert!(
1470                order.iter().any(|step| {
1471                    matches!(step, Step::Write(register, value) if *register == correlator.accumulated_ratio && *value == 52)
1472                }),
1473                "SF{spreading_factor} was left untuned"
1474            );
1475        }
1476    }
1477
1478    /// What one register was written, out of a whole plan.
1479    fn written(plan: &Plan, want: register::Register) -> Option<u8> {
1480        steps(plan).find_map(|Step::Write(named, value)| (named == want).then_some(value))
1481    }
1482
1483    /// The European plan, with the fast channel a network runs beside it.
1484    fn with_service() -> Plan {
1485        eu868().serving(Service::at(-200_000, 7).bandwidth(250_000))
1486    }
1487
1488    #[test]
1489    fn a_service_channel_is_given_a_frequency_and_a_radio() {
1490        let plan = with_service();
1491        let [high, low] = offset_bytes(-200_000);
1492
1493        assert_eq!(written(&plan, register::SERVICE_FREQUENCY_MSB), Some(high));
1494        assert_eq!(written(&plan, register::SERVICE_FREQUENCY_LSB), Some(low));
1495        assert_eq!(written(&plan, register::SERVICE_RADIO_SELECT), Some(0));
1496        assert_eq!(written(&plan, register::SERVICE_SPREADING_FACTOR), Some(7));
1497        assert_eq!(written(&plan, register::SERVICE_BANDWIDTH), Some(5));
1498        assert_eq!(written(&plan, register::SERVICE_MODEM_START), Some(1));
1499
1500        let other = eu868().serving(Service::at(0, 7).on(Chain::B));
1501        assert_eq!(written(&other, register::SERVICE_RADIO_SELECT), Some(1));
1502    }
1503
1504    #[test]
1505    fn a_plan_without_a_service_channel_leaves_its_rate_alone() {
1506        let plan = eu868();
1507        assert_eq!(plan.service, None);
1508        assert_eq!(written(&plan, register::SERVICE_FREQUENCY_MSB), None);
1509        assert_eq!(written(&plan, register::SERVICE_SPREADING_FACTOR), None);
1510        assert_eq!(written(&plan, register::SERVICE_MODEM_START), None);
1511    }
1512
1513    #[test]
1514    fn the_two_fastest_spreading_factors_stay_private_on_a_public_network() {
1515        // Everything else on a public network moves its sync symbols out.
1516        let fast = eu868().serving(Service::at(0, 5));
1517        assert_eq!(written(&fast, register::SERVICE_SYNC_PEAK1), Some(2));
1518        assert_eq!(written(&fast, register::SERVICE_SYNC_PEAK2), Some(4));
1519        assert_eq!(written(&fast, register::RX_SYNC_SF7_TO_SF12_PEAK1), Some(6));
1520
1521        let slow = eu868().serving(Service::at(0, 7));
1522        assert_eq!(written(&slow, register::SERVICE_SYNC_PEAK1), Some(6));
1523        assert_eq!(written(&slow, register::SERVICE_SYNC_PEAK2), Some(8));
1524
1525        // A private network is private for every receiver.
1526        let private = eu868().network(false).serving(Service::at(0, 7));
1527        assert_eq!(written(&private, register::SERVICE_SYNC_PEAK1), Some(2));
1528    }
1529
1530    #[test]
1531    fn the_fast_spreading_factors_expect_a_longer_preamble() {
1532        let fast = eu868().serving(Service::at(0, 6));
1533        let usual = eu868().serving(Service::at(0, 9));
1534
1535        assert_eq!(written(&fast, register::SERVICE_PREAMBLE_LSB), Some(12));
1536        assert_eq!(written(&usual, register::SERVICE_PREAMBLE_LSB), Some(8));
1537
1538        // They are also the only ones that synchronize finely.
1539        assert_eq!(written(&fast, register::SERVICE_FINE_SYNC), Some(1));
1540        assert_eq!(written(&usual, register::SERVICE_FINE_SYNC), Some(0));
1541    }
1542
1543    #[test]
1544    fn the_low_rate_optimization_follows_the_bandwidth_as_well_as_the_rate() {
1545        let narrow = eu868().serving(Service::at(0, 11));
1546        let wide = eu868().serving(Service::at(0, 11).bandwidth(250_000));
1547
1548        assert_eq!(written(&narrow, register::SERVICE_PPM_OFFSET), Some(1));
1549        assert_eq!(
1550            written(&wide, register::SERVICE_PPM_OFFSET),
1551            Some(0),
1552            "the same spreading factor twice as wide does not need it"
1553        );
1554    }
1555
1556    #[test]
1557    fn a_packet_without_a_header_carries_what_the_header_would_have() {
1558        let explicit = eu868().serving(Service::at(0, 7));
1559        assert_eq!(
1560            written(&explicit, register::SERVICE_IMPLICIT_HEADER),
1561            Some(0)
1562        );
1563        assert_eq!(
1564            written(&explicit, register::SERVICE_PAYLOAD_LENGTH),
1565            Some(0)
1566        );
1567
1568        let implicit = eu868().serving(Service::at(0, 7).without_header(Implicit {
1569            payload_length: 23,
1570            coding_rate: 1,
1571            crc: true,
1572        }));
1573        assert_eq!(
1574            written(&implicit, register::SERVICE_IMPLICIT_HEADER),
1575            Some(1)
1576        );
1577        assert_eq!(
1578            written(&implicit, register::SERVICE_PAYLOAD_LENGTH),
1579            Some(23)
1580        );
1581        assert_eq!(written(&implicit, register::SERVICE_CODING_RATE), Some(1));
1582        assert_eq!(written(&implicit, register::SERVICE_CRC_ENABLE), Some(1));
1583    }
1584
1585    #[test]
1586    fn a_rate_the_receiver_cannot_run_is_refused_rather_than_narrowed() {
1587        assert!(Service::at(0, 7).supported());
1588        assert!(Service::at(0, 12).bandwidth(500_000).supported());
1589
1590        assert!(!Service::at(0, 4).supported(), "below the slowest");
1591        assert!(!Service::at(0, 13).supported(), "past the fastest");
1592        assert!(
1593            !Service::at(0, 7).bandwidth(62_500).supported(),
1594            "not a width"
1595        );
1596        assert!(!Service::at(MAX_OFFSET_HZ + 1, 7).supported(), "not heard");
1597    }
1598
1599    #[test]
1600    fn a_frequency_shift_keying_channel_is_given_a_frequency_and_a_rate() {
1601        let plan = eu868().hearing(Fsk::at(600_000).on(Chain::B));
1602        let [high, low] = offset_bytes(600_000);
1603
1604        assert_eq!(written(&plan, register::FSK_FREQUENCY_MSB), Some(high));
1605        assert_eq!(written(&plan, register::FSK_FREQUENCY_LSB), Some(low));
1606        assert_eq!(written(&plan, register::FSK_RADIO_SELECT), Some(1));
1607
1608        // Fifty thousand bits a second is six hundred and forty clocks a bit.
1609        assert_eq!(written(&plan, register::FSK_BITRATE_MSB), Some(0x02));
1610        assert_eq!(written(&plan, register::FSK_BITRATE_LSB), Some(0x80));
1611    }
1612
1613    #[test]
1614    fn a_plan_without_one_leaves_that_receiver_alone() {
1615        let plan = eu868();
1616        assert_eq!(plan.fsk, None);
1617        assert_eq!(written(&plan, register::FSK_FREQUENCY_MSB), None);
1618        assert_eq!(written(&plan, register::FSK_BITRATE_LSB), None);
1619    }
1620
1621    #[test]
1622    fn the_sync_word_sits_at_the_top_of_the_pattern() {
1623        let plan = eu868().hearing(Fsk::at(600_000));
1624
1625        // Three bytes, in the three registers the pattern ends at, and nothing in the rest.
1626        assert_eq!(written(&plan, register::fsk_sync_word(7)), Some(0xc1));
1627        assert_eq!(written(&plan, register::fsk_sync_word(6)), Some(0x94));
1628        assert_eq!(written(&plan, register::fsk_sync_word(5)), Some(0xc1));
1629        assert_eq!(written(&plan, register::fsk_sync_word(4)), Some(0x00));
1630        assert_eq!(written(&plan, register::fsk_sync_word(0)), Some(0x00));
1631
1632        // How many of them the receiver matches is written as one less.
1633        assert_eq!(written(&plan, register::FSK_PATTERN_SIZE), Some(2));
1634    }
1635
1636    #[test]
1637    fn a_whole_sync_word_fills_every_register() {
1638        let plan = eu868().hearing(Fsk::at(0).matching(0x0102_0304_0506_0708, 8));
1639
1640        assert_eq!(
1641            Fsk::at(0).matching(0x0102_0304_0506_0708, 8).pattern(),
1642            0x0102_0304_0506_0708
1643        );
1644        assert_eq!(written(&plan, register::fsk_sync_word(7)), Some(0x01));
1645        assert_eq!(written(&plan, register::fsk_sync_word(0)), Some(0x08));
1646        assert_eq!(written(&plan, register::FSK_PATTERN_SIZE), Some(7));
1647    }
1648
1649    #[test]
1650    fn the_channel_is_set_up_the_way_the_reference_does() {
1651        let plan = eu868().hearing(Fsk::at(600_000));
1652
1653        assert_eq!(written(&plan, register::FSK_BANDWIDTH_EXPONENT), Some(0x03));
1654        assert_eq!(written(&plan, register::FSK_PACKET_MODE), Some(1));
1655        assert_eq!(written(&plan, register::FSK_CRC_ENABLE), Some(1));
1656        assert_eq!(written(&plan, register::FSK_CRC_IBM), Some(0));
1657        assert_eq!(written(&plan, register::FSK_DCFREE_ENCODING), Some(2));
1658        assert_eq!(written(&plan, register::FSK_RSSI_LENGTH), Some(4));
1659        assert_eq!(written(&plan, register::FSK_ERROR_TOLERANCE), Some(10));
1660        assert_eq!(written(&plan, register::FSK_PAYLOAD_LENGTH), Some(255));
1661        assert_eq!(written(&plan, register::FSK_AUTO_AFC), Some(1));
1662        assert_eq!(written(&plan, register::FSK_TIMEOUT_MSB), Some(0));
1663        assert_eq!(written(&plan, register::FSK_TIMEOUT_LSB), Some(128));
1664    }
1665
1666    #[test]
1667    fn a_channel_the_receiver_cannot_run_is_refused_rather_than_narrowed() {
1668        assert!(Fsk::at(600_000).supported());
1669        assert!(Fsk::at(-MAX_OFFSET_HZ).supported());
1670
1671        assert!(!Fsk::at(900_000).supported(), "past what the radio hears");
1672        assert!(!Fsk::at(0).bitrate(0).supported(), "not a rate");
1673        assert!(
1674            !Fsk::at(0).bitrate(100).supported(),
1675            "too slow for the counter"
1676        );
1677        assert!(
1678            !Fsk::at(0).matching(0, 0).supported(),
1679            "no sync word at all"
1680        );
1681        assert!(
1682            !Fsk::at(0).matching(0, 9).supported(),
1683            "longer than the pattern"
1684        );
1685    }
1686}