Skip to main content

pamoja_lora/region/
plans.rs

1//! The published channel plans, transcribed from RP002-1.0.5.
2//!
3//! Each region is behind its own cargo feature, all on by default, because a
4//! device only ever operates in one region and a microcontroller should not
5//! carry the other nine in flash.
6
7use super::ChannelPlan;
8// The table types follow the regions: a build that selects one band, or none,
9// must not be told it imported types no plan in it uses.
10#[cfg(any(
11    feature = "eu868",
12    feature = "us915",
13    feature = "eu433",
14    feature = "au915",
15    feature = "cn470",
16    feature = "as923",
17    feature = "kr920",
18    feature = "in865",
19    feature = "ru864"
20))]
21use super::{Beacon, ChannelBlock, DataRate, MaxPayload};
22// Only the bands whose regulators cap airtime describe sub-bands; the 900 MHz
23// plans and IN865 leave the table empty.
24#[cfg(any(
25    feature = "eu868",
26    feature = "eu433",
27    feature = "as923",
28    feature = "kr920",
29    feature = "ru864"
30))]
31use super::SubBand;
32
33/// A named regional channel plan.
34///
35/// This is a convenience over [`ChannelPlan`], not the only way to get one: a
36/// deployment on licensed spectrum builds its own plan and every method still
37/// applies. Each variant is behind its own cargo feature.
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39#[non_exhaustive]
40pub enum Region {
41    /// Europe and everywhere else following ETSI EN 300 220, 863-870 MHz.
42    #[cfg(feature = "eu868")]
43    Eu868,
44    /// The United States, Canada, and ITU Region 2, 902-928 MHz.
45    #[cfg(feature = "us915")]
46    Us915,
47    /// The 433 MHz ISM band.
48    #[cfg(feature = "eu433")]
49    Eu433,
50    /// Australia and the countries following it, 915-928 MHz.
51    #[cfg(feature = "au915")]
52    Au915,
53    /// China, 470-510 MHz.
54    #[cfg(feature = "cn470")]
55    Cn470,
56    /// Asia and the Pacific, 923 MHz.
57    #[cfg(feature = "as923")]
58    As923,
59    /// South Korea, 920-923 MHz.
60    #[cfg(feature = "kr920")]
61    Kr920,
62    /// India, 865-867 MHz.
63    #[cfg(feature = "in865")]
64    In865,
65    /// Russia, 864-870 MHz.
66    #[cfg(feature = "ru864")]
67    Ru864,
68}
69
70impl Region {
71    /// Returns the channel plan this region names.
72    ///
73    /// # Returns
74    ///
75    /// The plan, whose tables come straight from RP002-1.0.5.
76    pub const fn plan(self) -> &'static ChannelPlan<'static> {
77        match self {
78            #[cfg(feature = "eu868")]
79            Region::Eu868 => &EU868,
80            #[cfg(feature = "us915")]
81            Region::Us915 => &US915,
82            #[cfg(feature = "eu433")]
83            Region::Eu433 => &EU433,
84            #[cfg(feature = "au915")]
85            Region::Au915 => &AU915,
86            #[cfg(feature = "cn470")]
87            Region::Cn470 => &CN470,
88            #[cfg(feature = "as923")]
89            Region::As923 => &AS923,
90            #[cfg(feature = "kr920")]
91            Region::Kr920 => &KR920,
92            #[cfg(feature = "in865")]
93            Region::In865 => &IN865,
94            #[cfg(feature = "ru864")]
95            Region::Ru864 => &RU864,
96        }
97    }
98
99    /// Returns the specification's name for this region's band.
100    ///
101    /// # Returns
102    ///
103    /// The band name, such as `"EU863-870"`.
104    pub const fn name(self) -> &'static str {
105        self.plan().name
106    }
107
108    /// Returns the short code this region is configured by.
109    ///
110    /// A deployment is set up as `EU868` or `US915`; the band name the
111    /// specification uses, such as `EU863-870`, is what [`name`](Self::name)
112    /// reports. Both identify the same plan.
113    ///
114    /// # Returns
115    ///
116    /// The short code, such as `"EU868"`.
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// # #[cfg(feature = "eu868")] {
122    /// use pamoja_lora::region::Region;
123    ///
124    /// assert_eq!(Region::Eu868.code(), "EU868");
125    /// assert_eq!(Region::Eu868.name(), "EU863-870");
126    /// # }
127    /// ```
128    pub const fn code(self) -> &'static str {
129        match self {
130            #[cfg(feature = "eu868")]
131            Region::Eu868 => "EU868",
132            #[cfg(feature = "us915")]
133            Region::Us915 => "US915",
134            #[cfg(feature = "eu433")]
135            Region::Eu433 => "EU433",
136            #[cfg(feature = "au915")]
137            Region::Au915 => "AU915",
138            #[cfg(feature = "cn470")]
139            Region::Cn470 => "CN470",
140            #[cfg(feature = "as923")]
141            Region::As923 => "AS923",
142            #[cfg(feature = "kr920")]
143            Region::Kr920 => "KR920",
144            #[cfg(feature = "in865")]
145            Region::In865 => "IN865",
146            #[cfg(feature = "ru864")]
147            Region::Ru864 => "RU864",
148        }
149    }
150
151    /// Returns the region a short code names.
152    ///
153    /// The comparison ignores case, and the specification's band name is
154    /// accepted as well, so a plan read back from a device's configuration
155    /// resolves whichever form it was written in.
156    ///
157    /// # Arguments
158    ///
159    /// * `code` - the short code or band name, such as `"EU868"`.
160    ///
161    /// # Returns
162    ///
163    /// The region, or `None` if no region in this build goes by that name.
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// # #[cfg(feature = "us915")] {
169    /// use pamoja_lora::region::Region;
170    ///
171    /// assert_eq!(Region::from_code("us915"), Some(Region::Us915));
172    /// assert_eq!(Region::from_code("US902-928"), Some(Region::Us915));
173    /// assert_eq!(Region::from_code("Atlantis"), None);
174    /// # }
175    /// ```
176    pub fn from_code(code: &str) -> Option<Self> {
177        Self::all().iter().copied().find(|region| {
178            code.eq_ignore_ascii_case(region.code()) || code.eq_ignore_ascii_case(region.name())
179        })
180    }
181
182    /// Returns every region this build carries.
183    ///
184    /// A build that selects only its own region gets a one-element slice, which
185    /// is the point of the per-region features.
186    ///
187    /// # Returns
188    ///
189    /// The compiled-in regions.
190    pub const fn all() -> &'static [Region] {
191        &[
192            #[cfg(feature = "eu868")]
193            Region::Eu868,
194            #[cfg(feature = "us915")]
195            Region::Us915,
196            #[cfg(feature = "eu433")]
197            Region::Eu433,
198            #[cfg(feature = "au915")]
199            Region::Au915,
200            #[cfg(feature = "cn470")]
201            Region::Cn470,
202            #[cfg(feature = "as923")]
203            Region::As923,
204            #[cfg(feature = "kr920")]
205            Region::Kr920,
206            #[cfg(feature = "in865")]
207            Region::In865,
208            #[cfg(feature = "ru864")]
209            Region::Ru864,
210        ]
211    }
212}
213
214// EU863-870, RP002-1.0.5 section 3.4.
215
216/// RP002-1.0.5 Table 10: EU863-870 TX data rate.
217#[cfg(feature = "eu868")]
218static EU868_DATA_RATES: [Option<DataRate>; 14] = [
219    Some(DataRate::lora(12, 125_000, 250)),
220    Some(DataRate::lora(11, 125_000, 440)),
221    Some(DataRate::lora(10, 125_000, 980)),
222    Some(DataRate::lora(9, 125_000, 1_760)),
223    Some(DataRate::lora(8, 125_000, 3_125)),
224    Some(DataRate::lora(7, 125_000, 5_470)),
225    Some(DataRate::lora(7, 250_000, 11_000)),
226    Some(DataRate::fsk(50_000)),
227    Some(DataRate::lr_fhss(1, 3, 137_000, 162)),
228    Some(DataRate::lr_fhss(2, 3, 137_000, 325)),
229    Some(DataRate::lr_fhss(1, 3, 336_000, 162)),
230    Some(DataRate::lr_fhss(2, 3, 336_000, 325)),
231    Some(DataRate::lora(6, 125_000, 9_375)),
232    Some(DataRate::lora(5, 125_000, 15_625)),
233];
234
235/// RP002-1.0.5 Table 15: EU863-870 maximum payload size (repeater compatible).
236#[cfg(feature = "eu868")]
237static EU868_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 14] = [
238    Some(MaxPayload::new(59, 51)),
239    Some(MaxPayload::new(59, 51)),
240    Some(MaxPayload::new(59, 51)),
241    Some(MaxPayload::new(123, 115)),
242    Some(MaxPayload::new(230, 222)),
243    Some(MaxPayload::new(230, 222)),
244    Some(MaxPayload::new(230, 222)),
245    Some(MaxPayload::new(230, 222)),
246    Some(MaxPayload::new(58, 50)),
247    Some(MaxPayload::new(123, 115)),
248    Some(MaxPayload::new(58, 50)),
249    Some(MaxPayload::new(123, 115)),
250    Some(MaxPayload::new(230, 222)),
251    Some(MaxPayload::new(230, 222)),
252];
253
254/// RP002-1.0.5 Table 16: EU863-870 maximum payload size (not repeater compatible).
255#[cfg(feature = "eu868")]
256static EU868_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 14] = [
257    Some(MaxPayload::new(59, 51)),
258    Some(MaxPayload::new(59, 51)),
259    Some(MaxPayload::new(59, 51)),
260    Some(MaxPayload::new(123, 115)),
261    Some(MaxPayload::new(250, 242)),
262    Some(MaxPayload::new(250, 242)),
263    Some(MaxPayload::new(250, 242)),
264    Some(MaxPayload::new(250, 242)),
265    Some(MaxPayload::new(58, 50)),
266    Some(MaxPayload::new(123, 115)),
267    Some(MaxPayload::new(58, 50)),
268    Some(MaxPayload::new(123, 115)),
269    Some(MaxPayload::new(250, 242)),
270    Some(MaxPayload::new(250, 242)),
271];
272
273/// RP002-1.0.5 Table 17: EU863-870 downlink RX1 data rate mapping.
274#[cfg(feature = "eu868")]
275static EU868_RX1: [&[u8]; 14] = [
276    &[0, 0, 0, 0, 0, 0],
277    &[1, 0, 0, 0, 0, 0],
278    &[2, 1, 0, 0, 0, 0],
279    &[3, 2, 1, 0, 0, 0],
280    &[4, 3, 2, 1, 0, 0],
281    &[5, 4, 3, 2, 1, 0],
282    &[6, 5, 4, 3, 2, 1],
283    &[7, 6, 5, 4, 3, 2],
284    &[1, 0, 0, 0, 0, 0],
285    &[2, 1, 0, 0, 0, 0],
286    &[1, 0, 0, 0, 0, 0],
287    &[2, 1, 0, 0, 0, 0],
288    &[12, 5, 4, 3, 2, 1],
289    &[13, 12, 5, 4, 3, 2],
290];
291
292/// RP002-1.0.5 Table 12: EU863-870 data rate back-off.
293#[cfg(feature = "eu868")]
294static EU868_BACKOFF: [Option<u8>; 14] = [
295    None,
296    Some(0),
297    Some(1),
298    Some(2),
299    Some(3),
300    Some(4),
301    Some(5),
302    Some(6),
303    Some(0),
304    Some(8),
305    Some(0),
306    Some(10),
307    Some(5),
308    Some(12),
309];
310
311/// RP002-1.0.5 Table 8 and Table 9: the three default and join channels.
312#[cfg(feature = "eu868")]
313static EU868_CHANNELS: [ChannelBlock; 1] = [ChannelBlock::new(868_100_000, 200_000, 3, 0, 5)];
314
315/// The ETSI sub-bands the default channels fall in.
316///
317/// EN 300 220 divides the band, and the 868.0-868.6 MHz sub-band carrying the
318/// three mandatory channels is limited to 1%. The RX2 downlink frequency sits in
319/// the 869.4-869.65 MHz sub-band, which allows 10% at a higher ceiling.
320#[cfg(feature = "eu868")]
321static EU868_SUB_BANDS: [SubBand; 2] = [
322    SubBand::new(868_000_000, 868_600_000, 10, 16),
323    SubBand::new(869_400_000, 869_650_000, 100, 27),
324];
325
326/// The EU863-870 channel plan, RP002-1.0.5 section 3.4.
327#[cfg(feature = "eu868")]
328pub static EU868: ChannelPlan<'static> = ChannelPlan {
329    name: "EU863-870",
330    uplink_data_rates: &EU868_DATA_RATES,
331    downlink_data_rates: &EU868_DATA_RATES,
332    max_payload_repeater: &EU868_MAX_PAYLOAD_REPEATER,
333    max_payload_direct: &EU868_MAX_PAYLOAD_DIRECT,
334    downlink_max_payload_repeater: &EU868_MAX_PAYLOAD_REPEATER,
335    downlink_max_payload_direct: &EU868_MAX_PAYLOAD_DIRECT,
336    max_payload_dwell_limited: None,
337    join_channels: &EU868_CHANNELS,
338    default_channels: &EU868_CHANNELS,
339    sub_bands: &EU868_SUB_BANDS,
340    default_max_eirp_dbm: 16,
341    tx_power_step_db: 2,
342    max_tx_power_index: 7,
343    rx1_data_rate_offsets: &EU868_RX1,
344    rx1_data_rate_offsets_dwell_limited: None,
345    max_rx1_data_rate_offset: 5,
346    rx2_frequency_hz: 869_525_000,
347    rx2_data_rate: 0,
348    data_rate_backoff: &EU868_BACKOFF,
349    beacon: Beacon {
350        data_rate: 3,
351        frequency_hz: 869_525_000,
352        ping_slot_frequency_hz: 869_525_000,
353    },
354    has_dwell_time_limit: false,
355};
356
357// US902-928, RP002-1.0.5 section 3.5.
358
359/// RP002-1.0.5 Table 19: US902-928 uplink data rates.
360#[cfg(feature = "us915")]
361static US915_UPLINK_DATA_RATES: [Option<DataRate>; 9] = [
362    Some(DataRate::lora(10, 125_000, 980)),
363    Some(DataRate::lora(9, 125_000, 1_760)),
364    Some(DataRate::lora(8, 125_000, 3_125)),
365    Some(DataRate::lora(7, 125_000, 5_470)),
366    Some(DataRate::lora(8, 500_000, 12_500)),
367    Some(DataRate::lr_fhss(1, 3, 1_523_000, 162)),
368    Some(DataRate::lr_fhss(2, 3, 1_523_000, 325)),
369    Some(DataRate::lora(6, 125_000, 9_375)),
370    Some(DataRate::lora(5, 125_000, 15_625)),
371];
372
373/// RP002-1.0.5 Table 20: US902-928 downlink data rates.
374#[cfg(feature = "us915")]
375static US915_DOWNLINK_DATA_RATES: [Option<DataRate>; 15] = [
376    Some(DataRate::lora(5, 500_000, 62_500)),
377    None,
378    None,
379    None,
380    None,
381    None,
382    None,
383    None,
384    Some(DataRate::lora(12, 500_000, 980)),
385    Some(DataRate::lora(11, 500_000, 1_760)),
386    Some(DataRate::lora(10, 500_000, 3_900)),
387    Some(DataRate::lora(9, 500_000, 7_000)),
388    Some(DataRate::lora(8, 500_000, 12_500)),
389    Some(DataRate::lora(7, 500_000, 21_900)),
390    Some(DataRate::lora(6, 500_000, 37_500)),
391];
392
393/// RP002-1.0.5 Table 24: US902-928 uplink maximum payload (repeater compatible).
394#[cfg(feature = "us915")]
395static US915_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 9] = [
396    Some(MaxPayload::new(19, 11)),
397    Some(MaxPayload::new(61, 53)),
398    Some(MaxPayload::new(133, 125)),
399    Some(MaxPayload::new(230, 222)),
400    Some(MaxPayload::new(230, 222)),
401    Some(MaxPayload::new(58, 50)),
402    Some(MaxPayload::new(133, 125)),
403    Some(MaxPayload::new(230, 222)),
404    Some(MaxPayload::new(230, 222)),
405];
406
407/// RP002-1.0.5 Table 25: US902-928 uplink maximum payload (not repeater compatible).
408#[cfg(feature = "us915")]
409static US915_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 9] = [
410    Some(MaxPayload::new(19, 11)),
411    Some(MaxPayload::new(61, 53)),
412    Some(MaxPayload::new(133, 125)),
413    Some(MaxPayload::new(250, 242)),
414    Some(MaxPayload::new(250, 242)),
415    Some(MaxPayload::new(58, 50)),
416    Some(MaxPayload::new(133, 125)),
417    Some(MaxPayload::new(250, 242)),
418    Some(MaxPayload::new(250, 242)),
419];
420
421/// RP002-1.0.5 Table 24: US902-928 downlink maximum payload (repeater compatible).
422#[cfg(feature = "us915")]
423static US915_DOWNLINK_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 15] = [
424    Some(MaxPayload::new(230, 222)),
425    None,
426    None,
427    None,
428    None,
429    None,
430    None,
431    None,
432    Some(MaxPayload::new(61, 53)),
433    Some(MaxPayload::new(137, 129)),
434    Some(MaxPayload::new(230, 222)),
435    Some(MaxPayload::new(230, 222)),
436    Some(MaxPayload::new(230, 222)),
437    Some(MaxPayload::new(230, 222)),
438    Some(MaxPayload::new(230, 222)),
439];
440
441/// RP002-1.0.5 Table 25: US902-928 downlink maximum payload (not repeater compatible).
442#[cfg(feature = "us915")]
443static US915_DOWNLINK_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 15] = [
444    Some(MaxPayload::new(250, 242)),
445    None,
446    None,
447    None,
448    None,
449    None,
450    None,
451    None,
452    Some(MaxPayload::new(61, 53)),
453    Some(MaxPayload::new(137, 129)),
454    Some(MaxPayload::new(250, 242)),
455    Some(MaxPayload::new(250, 242)),
456    Some(MaxPayload::new(250, 242)),
457    Some(MaxPayload::new(250, 242)),
458    Some(MaxPayload::new(250, 242)),
459];
460
461/// RP002-1.0.5 Table 26: US902-928 downlink RX1 data rate mapping.
462#[cfg(feature = "us915")]
463static US915_RX1: [&[u8]; 9] = [
464    &[10, 9, 8, 8],
465    &[11, 10, 9, 8],
466    &[12, 11, 10, 9],
467    &[13, 12, 11, 10],
468    &[13, 13, 12, 11],
469    &[10, 9, 8, 8],
470    &[11, 10, 9, 8],
471    &[14, 13, 12, 11],
472    &[0, 14, 13, 12],
473];
474
475/// RP002-1.0.5 Table 21: US902-928 uplink data rate back-off.
476#[cfg(feature = "us915")]
477static US915_BACKOFF: [Option<u8>; 9] = [
478    None,
479    Some(0),
480    Some(1),
481    Some(2),
482    Some(3),
483    Some(0),
484    Some(5),
485    Some(3),
486    Some(7),
487];
488
489/// The 64 125 kHz channels and the 8 500 kHz channels, RP002-1.0.5 section 3.5.2.
490#[cfg(feature = "us915")]
491static US915_CHANNELS: [ChannelBlock; 2] = [
492    ChannelBlock::new(902_300_000, 200_000, 64, 0, 3),
493    ChannelBlock::new(903_000_000, 1_600_000, 8, 4, 4),
494];
495
496/// The join channels: a random 125 kHz channel at DR0 and a 500 kHz one at DR4.
497#[cfg(feature = "us915")]
498static US915_JOIN_CHANNELS: [ChannelBlock; 2] = [
499    ChannelBlock::new(902_300_000, 200_000, 64, 0, 0),
500    ChannelBlock::new(903_000_000, 1_600_000, 8, 4, 4),
501];
502
503/// The US902-928 channel plan, RP002-1.0.5 section 3.5.
504///
505/// The FCC constrains this band by dwell time rather than duty cycle, so the
506/// plan publishes no sub-band duty limit and
507/// [`duty_cycle_permille`](ChannelPlan::duty_cycle_permille) reports `None`.
508#[cfg(feature = "us915")]
509pub static US915: ChannelPlan<'static> = ChannelPlan {
510    name: "US902-928",
511    uplink_data_rates: &US915_UPLINK_DATA_RATES,
512    downlink_data_rates: &US915_DOWNLINK_DATA_RATES,
513    max_payload_repeater: &US915_MAX_PAYLOAD_REPEATER,
514    max_payload_direct: &US915_MAX_PAYLOAD_DIRECT,
515    downlink_max_payload_repeater: &US915_DOWNLINK_MAX_PAYLOAD_REPEATER,
516    downlink_max_payload_direct: &US915_DOWNLINK_MAX_PAYLOAD_DIRECT,
517    max_payload_dwell_limited: None,
518    join_channels: &US915_JOIN_CHANNELS,
519    default_channels: &US915_CHANNELS,
520    sub_bands: &[],
521    default_max_eirp_dbm: 30,
522    tx_power_step_db: 2,
523    max_tx_power_index: 14,
524    rx1_data_rate_offsets: &US915_RX1,
525    rx1_data_rate_offsets_dwell_limited: None,
526    max_rx1_data_rate_offset: 3,
527    rx2_frequency_hz: 923_300_000,
528    rx2_data_rate: 8,
529    data_rate_backoff: &US915_BACKOFF,
530    beacon: Beacon {
531        data_rate: 8,
532        frequency_hz: 923_300_000,
533        ping_slot_frequency_hz: 923_300_000,
534    },
535    has_dwell_time_limit: true,
536};
537
538// EU433, RP002-1.0.5 section 3.7.
539
540/// RP002-1.0.5 Table 30: EU433 data rate and TXPower.
541#[cfg(feature = "eu433")]
542static EU433_DATA_RATES: [Option<DataRate>; 14] = [
543    Some(DataRate::lora(12, 125_000, 250)),
544    Some(DataRate::lora(11, 125_000, 440)),
545    Some(DataRate::lora(10, 125_000, 980)),
546    Some(DataRate::lora(9, 125_000, 1_760)),
547    Some(DataRate::lora(8, 125_000, 3_125)),
548    Some(DataRate::lora(7, 125_000, 5_470)),
549    Some(DataRate::lora(7, 250_000, 11_000)),
550    Some(DataRate::fsk(50_000)),
551    None,
552    None,
553    None,
554    None,
555    Some(DataRate::lora(6, 125_000, 9_375)),
556    Some(DataRate::lora(5, 125_000, 15_625)),
557];
558
559/// RP002-1.0.5 Table 36: EU433 maximum payload size (repeater compatible).
560#[cfg(feature = "eu433")]
561static EU433_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 14] = [
562    Some(MaxPayload::new(59, 51)),
563    Some(MaxPayload::new(59, 51)),
564    Some(MaxPayload::new(59, 51)),
565    Some(MaxPayload::new(123, 115)),
566    Some(MaxPayload::new(230, 222)),
567    Some(MaxPayload::new(230, 222)),
568    Some(MaxPayload::new(230, 222)),
569    Some(MaxPayload::new(230, 222)),
570    None,
571    None,
572    None,
573    None,
574    Some(MaxPayload::new(230, 222)),
575    Some(MaxPayload::new(230, 222)),
576];
577
578/// RP002-1.0.5 Table 37: EU433 maximum payload size (not repeater compatible).
579#[cfg(feature = "eu433")]
580static EU433_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 14] = [
581    Some(MaxPayload::new(59, 51)),
582    Some(MaxPayload::new(59, 51)),
583    Some(MaxPayload::new(59, 51)),
584    Some(MaxPayload::new(123, 115)),
585    Some(MaxPayload::new(250, 242)),
586    Some(MaxPayload::new(250, 242)),
587    Some(MaxPayload::new(250, 242)),
588    Some(MaxPayload::new(250, 242)),
589    None,
590    None,
591    None,
592    None,
593    Some(MaxPayload::new(250, 242)),
594    Some(MaxPayload::new(250, 242)),
595];
596
597/// RP002-1.0.5 Table 38: EU433 downlink RX1 data rate mapping.
598///
599/// DR8 through DR11 are reserved in this region, so their rows carry the DR0
600/// fallback rather than a mapping the specification does not define.
601#[cfg(feature = "eu433")]
602static EU433_RX1: [&[u8]; 14] = [
603    &[0, 0, 0, 0, 0, 0],
604    &[1, 0, 0, 0, 0, 0],
605    &[2, 1, 0, 0, 0, 0],
606    &[3, 2, 1, 0, 0, 0],
607    &[4, 3, 2, 1, 0, 0],
608    &[5, 4, 3, 2, 1, 0],
609    &[6, 5, 4, 3, 2, 1],
610    &[7, 6, 5, 4, 3, 2],
611    &[0, 0, 0, 0, 0, 0],
612    &[0, 0, 0, 0, 0, 0],
613    &[0, 0, 0, 0, 0, 0],
614    &[0, 0, 0, 0, 0, 0],
615    &[12, 5, 4, 3, 2, 1],
616    &[13, 12, 5, 4, 3, 2],
617];
618
619/// RP002-1.0.5 Table 32: EU433 data rate back-off.
620#[cfg(feature = "eu433")]
621static EU433_BACKOFF: [Option<u8>; 14] = [
622    None,
623    Some(0),
624    Some(1),
625    Some(2),
626    Some(3),
627    Some(4),
628    Some(5),
629    Some(6),
630    None,
631    None,
632    None,
633    None,
634    Some(5),
635    Some(12),
636];
637
638/// RP002-1.0.5 Table 29: the three default and join channels.
639#[cfg(feature = "eu433")]
640static EU433_CHANNELS: [ChannelBlock; 1] = [ChannelBlock::new(433_175_000, 200_000, 3, 0, 5)];
641
642/// The whole EU433 band carries one limit: below 12 dBm EIRP and under 10% duty.
643#[cfg(feature = "eu433")]
644static EU433_SUB_BANDS: [SubBand; 1] = [SubBand::new(433_050_000, 434_790_000, 100, 12)];
645
646/// The EU433 channel plan, RP002-1.0.5 section 3.7.
647#[cfg(feature = "eu433")]
648pub static EU433: ChannelPlan<'static> = ChannelPlan {
649    name: "EU433",
650    uplink_data_rates: &EU433_DATA_RATES,
651    downlink_data_rates: &EU433_DATA_RATES,
652    max_payload_repeater: &EU433_MAX_PAYLOAD_REPEATER,
653    max_payload_direct: &EU433_MAX_PAYLOAD_DIRECT,
654    downlink_max_payload_repeater: &EU433_MAX_PAYLOAD_REPEATER,
655    downlink_max_payload_direct: &EU433_MAX_PAYLOAD_DIRECT,
656    max_payload_dwell_limited: None,
657    join_channels: &EU433_CHANNELS,
658    default_channels: &EU433_CHANNELS,
659    sub_bands: &EU433_SUB_BANDS,
660    default_max_eirp_dbm: 12,
661    tx_power_step_db: 2,
662    max_tx_power_index: 5,
663    rx1_data_rate_offsets: &EU433_RX1,
664    rx1_data_rate_offsets_dwell_limited: None,
665    max_rx1_data_rate_offset: 5,
666    rx2_frequency_hz: 434_665_000,
667    rx2_data_rate: 0,
668    data_rate_backoff: &EU433_BACKOFF,
669    beacon: Beacon {
670        data_rate: 3,
671        frequency_hz: 434_665_000,
672        ping_slot_frequency_hz: 434_665_000,
673    },
674    has_dwell_time_limit: false,
675};
676
677// AU915-928, RP002-1.0.5 section 3.8.
678
679/// RP002-1.0.5 Table 39: AU915-928 uplink data rates.
680#[cfg(feature = "au915")]
681static AU915_UPLINK_DATA_RATES: [Option<DataRate>; 11] = [
682    Some(DataRate::lora(12, 125_000, 250)),
683    Some(DataRate::lora(11, 125_000, 440)),
684    Some(DataRate::lora(10, 125_000, 980)),
685    Some(DataRate::lora(9, 125_000, 1_760)),
686    Some(DataRate::lora(8, 125_000, 3_125)),
687    Some(DataRate::lora(7, 125_000, 5_470)),
688    Some(DataRate::lora(8, 500_000, 12_500)),
689    Some(DataRate::lr_fhss(1, 3, 1_523_000, 162)),
690    None,
691    Some(DataRate::lora(6, 125_000, 9_375)),
692    Some(DataRate::lora(5, 125_000, 15_625)),
693];
694
695/// RP002-1.0.5 Table 40: AU915-928 downlink data rates.
696#[cfg(feature = "au915")]
697static AU915_DOWNLINK_DATA_RATES: [Option<DataRate>; 15] = [
698    Some(DataRate::lora(5, 500_000, 62_500)),
699    None,
700    None,
701    None,
702    None,
703    None,
704    None,
705    None,
706    Some(DataRate::lora(12, 500_000, 980)),
707    Some(DataRate::lora(11, 500_000, 1_760)),
708    Some(DataRate::lora(10, 500_000, 3_900)),
709    Some(DataRate::lora(9, 500_000, 7_000)),
710    Some(DataRate::lora(8, 500_000, 12_500)),
711    Some(DataRate::lora(7, 500_000, 21_900)),
712    Some(DataRate::lora(6, 500_000, 37_500)),
713];
714
715/// RP002-1.0.5 Table 44: AU915-928 uplink maximum payload, no dwell limit.
716#[cfg(feature = "au915")]
717static AU915_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 11] = [
718    Some(MaxPayload::new(59, 51)),
719    Some(MaxPayload::new(59, 51)),
720    Some(MaxPayload::new(59, 51)),
721    Some(MaxPayload::new(123, 115)),
722    Some(MaxPayload::new(230, 222)),
723    Some(MaxPayload::new(230, 222)),
724    Some(MaxPayload::new(230, 222)),
725    Some(MaxPayload::new(58, 50)),
726    None,
727    Some(MaxPayload::new(230, 222)),
728    Some(MaxPayload::new(230, 222)),
729];
730
731/// RP002-1.0.5 Table 45: AU915-928 uplink maximum payload, no dwell limit.
732#[cfg(feature = "au915")]
733static AU915_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 11] = [
734    Some(MaxPayload::new(59, 51)),
735    Some(MaxPayload::new(59, 51)),
736    Some(MaxPayload::new(59, 51)),
737    Some(MaxPayload::new(123, 115)),
738    Some(MaxPayload::new(250, 242)),
739    Some(MaxPayload::new(250, 242)),
740    Some(MaxPayload::new(250, 242)),
741    Some(MaxPayload::new(58, 50)),
742    None,
743    Some(MaxPayload::new(250, 242)),
744    Some(MaxPayload::new(250, 242)),
745];
746
747/// RP002-1.0.5 Table 44: AU915-928 uplink maximum payload under a 400 ms dwell.
748///
749/// The two slowest data rates carry nothing at all inside 400 ms, which is why
750/// a device boots assuming the limit applies until told otherwise.
751#[cfg(feature = "au915")]
752static AU915_MAX_PAYLOAD_DWELL: [Option<MaxPayload>; 11] = [
753    None,
754    None,
755    Some(MaxPayload::new(19, 11)),
756    Some(MaxPayload::new(61, 53)),
757    Some(MaxPayload::new(133, 125)),
758    Some(MaxPayload::new(230, 222)),
759    Some(MaxPayload::new(230, 222)),
760    Some(MaxPayload::new(58, 50)),
761    None,
762    Some(MaxPayload::new(230, 222)),
763    Some(MaxPayload::new(230, 222)),
764];
765
766/// RP002-1.0.5 Table 44: AU915-928 downlink maximum payload (repeater compatible).
767#[cfg(feature = "au915")]
768static AU915_DOWNLINK_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 15] = [
769    Some(MaxPayload::new(230, 222)),
770    None,
771    None,
772    None,
773    None,
774    None,
775    None,
776    None,
777    Some(MaxPayload::new(61, 53)),
778    Some(MaxPayload::new(137, 129)),
779    Some(MaxPayload::new(230, 222)),
780    Some(MaxPayload::new(230, 222)),
781    Some(MaxPayload::new(230, 222)),
782    Some(MaxPayload::new(230, 222)),
783    Some(MaxPayload::new(230, 222)),
784];
785
786/// RP002-1.0.5 Table 45: AU915-928 downlink maximum payload (not repeater compatible).
787#[cfg(feature = "au915")]
788static AU915_DOWNLINK_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 15] = [
789    Some(MaxPayload::new(250, 242)),
790    None,
791    None,
792    None,
793    None,
794    None,
795    None,
796    None,
797    Some(MaxPayload::new(61, 53)),
798    Some(MaxPayload::new(137, 129)),
799    Some(MaxPayload::new(250, 242)),
800    Some(MaxPayload::new(250, 242)),
801    Some(MaxPayload::new(250, 242)),
802    Some(MaxPayload::new(250, 242)),
803    Some(MaxPayload::new(250, 242)),
804];
805
806/// RP002-1.0.5 Table 46: AU915-928 downlink RX1 data rate mapping.
807#[cfg(feature = "au915")]
808static AU915_RX1: [&[u8]; 11] = [
809    &[8, 8, 8, 8, 8, 8],
810    &[9, 8, 8, 8, 8, 8],
811    &[10, 9, 8, 8, 8, 8],
812    &[11, 10, 9, 8, 8, 8],
813    &[12, 11, 10, 9, 8, 8],
814    &[13, 12, 11, 10, 9, 8],
815    &[13, 13, 12, 11, 10, 9],
816    &[9, 8, 8, 8, 8, 8],
817    &[8, 8, 8, 8, 8, 8],
818    &[14, 13, 12, 11, 10, 9],
819    &[0, 14, 13, 12, 11, 10],
820];
821
822/// RP002-1.0.5 Table 41: AU915-928 uplink data rate back-off, no dwell limit.
823#[cfg(feature = "au915")]
824static AU915_BACKOFF: [Option<u8>; 11] = [
825    None,
826    Some(0),
827    Some(1),
828    Some(2),
829    Some(3),
830    Some(4),
831    Some(5),
832    Some(0),
833    None,
834    Some(5),
835    Some(9),
836];
837
838/// The 64 125 kHz uplink channels and the 8 500 kHz ones, section 3.8.2.
839#[cfg(feature = "au915")]
840static AU915_CHANNELS: [ChannelBlock; 2] = [
841    ChannelBlock::new(915_200_000, 200_000, 64, 0, 5),
842    ChannelBlock::new(915_900_000, 1_600_000, 8, 6, 7),
843];
844
845/// The AU915-928 channel plan, RP002-1.0.5 section 3.8.
846///
847/// Australia limits transmissions by dwell time rather than duty cycle, so
848/// [`duty_cycle_permille`](ChannelPlan::duty_cycle_permille) reports nothing and
849/// the dwell-limited payload table is the one that matters until the network
850/// says otherwise.
851#[cfg(feature = "au915")]
852pub static AU915: ChannelPlan<'static> = ChannelPlan {
853    name: "AU915-928",
854    uplink_data_rates: &AU915_UPLINK_DATA_RATES,
855    downlink_data_rates: &AU915_DOWNLINK_DATA_RATES,
856    max_payload_repeater: &AU915_MAX_PAYLOAD_REPEATER,
857    max_payload_direct: &AU915_MAX_PAYLOAD_DIRECT,
858    downlink_max_payload_repeater: &AU915_DOWNLINK_MAX_PAYLOAD_REPEATER,
859    downlink_max_payload_direct: &AU915_DOWNLINK_MAX_PAYLOAD_DIRECT,
860    max_payload_dwell_limited: Some(&AU915_MAX_PAYLOAD_DWELL),
861    join_channels: &AU915_CHANNELS,
862    default_channels: &AU915_CHANNELS,
863    sub_bands: &[],
864    default_max_eirp_dbm: 30,
865    tx_power_step_db: 2,
866    max_tx_power_index: 14,
867    rx1_data_rate_offsets: &AU915_RX1,
868    rx1_data_rate_offsets_dwell_limited: None,
869    max_rx1_data_rate_offset: 5,
870    rx2_frequency_hz: 923_300_000,
871    rx2_data_rate: 8,
872    data_rate_backoff: &AU915_BACKOFF,
873    beacon: Beacon {
874        data_rate: 8,
875        frequency_hz: 923_300_000,
876        ping_slot_frequency_hz: 923_300_000,
877    },
878    has_dwell_time_limit: true,
879};
880
881// CN470-510, RP002-1.0.5 section 3.9.
882
883/// RP002-1.0.5 Table 50: CN470-510 data rate and TXPower.
884#[cfg(feature = "cn470")]
885static CN470_DATA_RATES: [Option<DataRate>; 8] = [
886    Some(DataRate::lora(12, 125_000, 250)),
887    Some(DataRate::lora(11, 125_000, 440)),
888    Some(DataRate::lora(10, 125_000, 980)),
889    Some(DataRate::lora(9, 125_000, 1_760)),
890    Some(DataRate::lora(8, 125_000, 3_125)),
891    Some(DataRate::lora(7, 125_000, 5_470)),
892    Some(DataRate::lora(7, 500_000, 21_900)),
893    Some(DataRate::fsk(50_000)),
894];
895
896/// RP002-1.0.5 Table 54: CN470-510 maximum payload size (repeater compatible).
897///
898/// DR0 carries nothing: at SF12 the one-second transmission limit this band
899/// works under leaves no room for a frame.
900#[cfg(feature = "cn470")]
901static CN470_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 8] = [
902    None,
903    Some(MaxPayload::new(31, 23)),
904    Some(MaxPayload::new(94, 86)),
905    Some(MaxPayload::new(192, 184)),
906    Some(MaxPayload::new(230, 222)),
907    Some(MaxPayload::new(230, 222)),
908    Some(MaxPayload::new(230, 222)),
909    Some(MaxPayload::new(230, 222)),
910];
911
912/// RP002-1.0.5 Table 55: CN470-510 maximum payload size (not repeater compatible).
913#[cfg(feature = "cn470")]
914static CN470_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 8] = [
915    None,
916    Some(MaxPayload::new(31, 23)),
917    Some(MaxPayload::new(94, 86)),
918    Some(MaxPayload::new(192, 184)),
919    Some(MaxPayload::new(250, 242)),
920    Some(MaxPayload::new(250, 242)),
921    Some(MaxPayload::new(250, 242)),
922    Some(MaxPayload::new(250, 242)),
923];
924
925/// RP002-1.0.5 Table 56: CN470-510 downlink RX1 data rate mapping.
926#[cfg(feature = "cn470")]
927static CN470_RX1: [&[u8]; 8] = [
928    &[0, 0, 0, 0, 0, 0],
929    &[1, 1, 1, 1, 1, 1],
930    &[2, 1, 1, 1, 1, 1],
931    &[3, 2, 1, 1, 1, 1],
932    &[4, 3, 2, 1, 1, 1],
933    &[5, 4, 3, 2, 1, 1],
934    &[6, 5, 4, 3, 2, 1],
935    &[7, 6, 5, 4, 3, 2],
936];
937
938/// RP002-1.0.5 Table 51: CN470-510 data rate back-off.
939#[cfg(feature = "cn470")]
940static CN470_BACKOFF: [Option<u8>; 8] = [
941    None,
942    Some(0),
943    Some(1),
944    Some(2),
945    Some(3),
946    Some(4),
947    Some(5),
948    Some(6),
949];
950
951/// The uplink blocks of the 20 MHz antenna, channel plan A, section 3.9.2.
952#[cfg(feature = "cn470")]
953static CN470_CHANNELS: [ChannelBlock; 2] = [
954    ChannelBlock::new(470_300_000, 200_000, 32, 0, 5),
955    ChannelBlock::new(483_900_000, 200_000, 32, 0, 5),
956];
957
958/// The eight common join channels every CN470 plan shares, Table 49.
959#[cfg(feature = "cn470")]
960static CN470_JOIN_CHANNELS: [ChannelBlock; 2] = [
961    ChannelBlock::new(470_900_000, 1_600_000, 4, 0, 5),
962    ChannelBlock::new(504_100_000, 1_600_000, 4, 0, 5),
963];
964
965/// The CN470-510 channel plan, RP002-1.0.5 section 3.9.
966///
967/// This carries the 20 MHz antenna, channel plan A variant. RP002 defines four
968/// (20 MHz and 26 MHz antennas, each with a plan A and B) whose uplink blocks,
969/// RX2 frequency, and beacon frequency differ, and the RX2 frequency also
970/// depends on whether the device joined over the air or was personalized. The
971/// value here is the personalized default for plan A. A deployment on one of the
972/// other variants builds a [`ChannelPlan`] with its own frequencies; everything
973/// else in this plan is common to all four.
974///
975/// Transmissions in this band are limited to one second on one channel at a
976/// time, with listen-before-talk rather than a duty cycle.
977#[cfg(feature = "cn470")]
978pub static CN470: ChannelPlan<'static> = ChannelPlan {
979    name: "CN470-510",
980    uplink_data_rates: &CN470_DATA_RATES,
981    downlink_data_rates: &CN470_DATA_RATES,
982    max_payload_repeater: &CN470_MAX_PAYLOAD_REPEATER,
983    max_payload_direct: &CN470_MAX_PAYLOAD_DIRECT,
984    downlink_max_payload_repeater: &CN470_MAX_PAYLOAD_REPEATER,
985    downlink_max_payload_direct: &CN470_MAX_PAYLOAD_DIRECT,
986    max_payload_dwell_limited: None,
987    join_channels: &CN470_JOIN_CHANNELS,
988    default_channels: &CN470_CHANNELS,
989    sub_bands: &[],
990    default_max_eirp_dbm: 19,
991    tx_power_step_db: 2,
992    max_tx_power_index: 7,
993    rx1_data_rate_offsets: &CN470_RX1,
994    rx1_data_rate_offsets_dwell_limited: None,
995    max_rx1_data_rate_offset: 5,
996    rx2_frequency_hz: 486_900_000,
997    rx2_data_rate: 1,
998    data_rate_backoff: &CN470_BACKOFF,
999    beacon: Beacon {
1000        data_rate: 2,
1001        frequency_hz: 486_900_000,
1002        ping_slot_frequency_hz: 486_900_000,
1003    },
1004    has_dwell_time_limit: false,
1005};
1006
1007// AS923, RP002-1.0.5 section 3.10.
1008
1009/// RP002-1.0.5 Table 67: AS923 data rate.
1010#[cfg(feature = "as923")]
1011static AS923_DATA_RATES: [Option<DataRate>; 14] = [
1012    Some(DataRate::lora(12, 125_000, 250)),
1013    Some(DataRate::lora(11, 125_000, 440)),
1014    Some(DataRate::lora(10, 125_000, 980)),
1015    Some(DataRate::lora(9, 125_000, 1_760)),
1016    Some(DataRate::lora(8, 125_000, 3_125)),
1017    Some(DataRate::lora(7, 125_000, 5_470)),
1018    Some(DataRate::lora(7, 250_000, 11_000)),
1019    Some(DataRate::fsk(50_000)),
1020    None,
1021    None,
1022    None,
1023    None,
1024    Some(DataRate::lora(6, 125_000, 9_375)),
1025    Some(DataRate::lora(5, 125_000, 15_625)),
1026];
1027
1028/// RP002-1.0.5 Table 72: AS923 maximum payload size (repeater compatible).
1029#[cfg(feature = "as923")]
1030static AS923_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 14] = [
1031    Some(MaxPayload::new(59, 51)),
1032    Some(MaxPayload::new(59, 51)),
1033    Some(MaxPayload::new(59, 51)),
1034    Some(MaxPayload::new(123, 115)),
1035    Some(MaxPayload::new(230, 222)),
1036    Some(MaxPayload::new(230, 222)),
1037    Some(MaxPayload::new(230, 222)),
1038    Some(MaxPayload::new(230, 222)),
1039    None,
1040    None,
1041    None,
1042    None,
1043    Some(MaxPayload::new(230, 222)),
1044    Some(MaxPayload::new(230, 222)),
1045];
1046
1047/// RP002-1.0.5 Table 73: AS923 maximum payload size (not repeater compatible).
1048#[cfg(feature = "as923")]
1049static AS923_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 14] = [
1050    Some(MaxPayload::new(59, 51)),
1051    Some(MaxPayload::new(59, 51)),
1052    Some(MaxPayload::new(59, 51)),
1053    Some(MaxPayload::new(123, 115)),
1054    Some(MaxPayload::new(250, 242)),
1055    Some(MaxPayload::new(250, 242)),
1056    Some(MaxPayload::new(250, 242)),
1057    Some(MaxPayload::new(250, 242)),
1058    None,
1059    None,
1060    None,
1061    None,
1062    Some(MaxPayload::new(250, 242)),
1063    Some(MaxPayload::new(250, 242)),
1064];
1065
1066/// RP002-1.0.5 Table 74: AS923 RX1 mapping with no downlink dwell limit.
1067#[cfg(feature = "as923")]
1068static AS923_RX1: [&[u8]; 14] = [
1069    &[0, 0, 0, 0, 0, 0, 1, 2],
1070    &[1, 0, 0, 0, 0, 0, 2, 3],
1071    &[2, 1, 0, 0, 0, 0, 3, 4],
1072    &[3, 2, 1, 0, 0, 0, 4, 5],
1073    &[4, 3, 2, 1, 0, 0, 5, 6],
1074    &[5, 4, 3, 2, 1, 0, 6, 7],
1075    &[6, 5, 4, 3, 2, 1, 7, 7],
1076    &[7, 6, 5, 4, 3, 2, 7, 7],
1077    &[0, 0, 0, 0, 0, 0, 1, 2],
1078    &[0, 0, 0, 0, 0, 0, 1, 2],
1079    &[0, 0, 0, 0, 0, 0, 1, 2],
1080    &[0, 0, 0, 0, 0, 0, 1, 2],
1081    &[12, 5, 4, 3, 2, 1, 13, 13],
1082    &[13, 12, 5, 4, 3, 2, 13, 13],
1083];
1084
1085/// RP002-1.0.5 Table 75: AS923 RX1 mapping under a downlink dwell limit.
1086#[cfg(feature = "as923")]
1087static AS923_RX1_DWELL: [&[u8]; 14] = [
1088    &[2, 2, 2, 2, 2, 2, 2, 2],
1089    &[2, 2, 2, 2, 2, 2, 2, 3],
1090    &[2, 2, 2, 2, 2, 2, 3, 4],
1091    &[3, 2, 2, 2, 2, 2, 4, 5],
1092    &[4, 3, 2, 2, 2, 2, 5, 6],
1093    &[5, 4, 3, 2, 2, 2, 6, 7],
1094    &[6, 5, 4, 3, 2, 2, 7, 7],
1095    &[7, 6, 5, 4, 3, 2, 7, 7],
1096    &[2, 2, 2, 2, 2, 2, 2, 2],
1097    &[2, 2, 2, 2, 2, 2, 2, 2],
1098    &[2, 2, 2, 2, 2, 2, 2, 2],
1099    &[2, 2, 2, 2, 2, 2, 2, 2],
1100    &[12, 5, 4, 3, 2, 2, 13, 13],
1101    &[13, 12, 5, 4, 3, 2, 13, 13],
1102];
1103
1104/// RP002-1.0.5 Table 69: AS923 data rate back-off.
1105#[cfg(feature = "as923")]
1106static AS923_BACKOFF: [Option<u8>; 14] = [
1107    None,
1108    Some(0),
1109    Some(1),
1110    Some(2),
1111    Some(3),
1112    Some(4),
1113    Some(5),
1114    Some(6),
1115    None,
1116    None,
1117    None,
1118    None,
1119    Some(5),
1120    Some(12),
1121];
1122
1123/// RP002-1.0.5 Table 65: the two default channels, at the AS923-1 offset of zero.
1124#[cfg(feature = "as923")]
1125static AS923_CHANNELS: [ChannelBlock; 1] = [ChannelBlock::new(923_200_000, 200_000, 2, 0, 5)];
1126
1127/// The AS923 band is duty-cycle limited to 1% on its default channels.
1128#[cfg(feature = "as923")]
1129static AS923_SUB_BANDS: [SubBand; 1] = [SubBand::new(923_000_000, 923_500_000, 10, 16)];
1130
1131/// The AS923 channel plan, RP002-1.0.5 section 3.10.
1132///
1133/// AS923 is four plans rather than one: every frequency here is the AS923-1
1134/// value, and AS923-2, AS923-3, and AS923-4 shift each of them by a fixed
1135/// `AS923_FREQ_OFFSET_HZ`. Everything that is not a frequency is common to all
1136/// four, so a deployment on another group copies this plan and adds its offset
1137/// to the channel, RX2, and beacon frequencies.
1138///
1139/// Japan reaches this band through ARIB STD-T108, which imposes a listen-before-
1140/// talk obligation this plan does not model.
1141#[cfg(feature = "as923")]
1142pub static AS923: ChannelPlan<'static> = ChannelPlan {
1143    name: "AS923",
1144    uplink_data_rates: &AS923_DATA_RATES,
1145    downlink_data_rates: &AS923_DATA_RATES,
1146    max_payload_repeater: &AS923_MAX_PAYLOAD_REPEATER,
1147    max_payload_direct: &AS923_MAX_PAYLOAD_DIRECT,
1148    downlink_max_payload_repeater: &AS923_MAX_PAYLOAD_REPEATER,
1149    downlink_max_payload_direct: &AS923_MAX_PAYLOAD_DIRECT,
1150    max_payload_dwell_limited: None,
1151    join_channels: &AS923_CHANNELS,
1152    default_channels: &AS923_CHANNELS,
1153    sub_bands: &AS923_SUB_BANDS,
1154    default_max_eirp_dbm: 16,
1155    tx_power_step_db: 2,
1156    max_tx_power_index: 7,
1157    rx1_data_rate_offsets: &AS923_RX1,
1158    rx1_data_rate_offsets_dwell_limited: Some(&AS923_RX1_DWELL),
1159    max_rx1_data_rate_offset: 7,
1160    rx2_frequency_hz: 923_200_000,
1161    rx2_data_rate: 2,
1162    data_rate_backoff: &AS923_BACKOFF,
1163    beacon: Beacon {
1164        data_rate: 3,
1165        frequency_hz: 923_400_000,
1166        ping_slot_frequency_hz: 923_400_000,
1167    },
1168    has_dwell_time_limit: true,
1169};
1170
1171// KR920-923, RP002-1.0.5 section 3.11.
1172
1173/// RP002-1.0.5 Table 80: KR920-923 TX data rate.
1174#[cfg(feature = "kr920")]
1175static KR920_DATA_RATES: [Option<DataRate>; 14] = [
1176    Some(DataRate::lora(12, 125_000, 250)),
1177    Some(DataRate::lora(11, 125_000, 440)),
1178    Some(DataRate::lora(10, 125_000, 980)),
1179    Some(DataRate::lora(9, 125_000, 1_760)),
1180    Some(DataRate::lora(8, 125_000, 3_125)),
1181    Some(DataRate::lora(7, 125_000, 5_470)),
1182    None,
1183    None,
1184    None,
1185    None,
1186    None,
1187    None,
1188    Some(DataRate::lora(6, 125_000, 9_375)),
1189    Some(DataRate::lora(5, 125_000, 15_625)),
1190];
1191
1192/// RP002-1.0.5 Table 85: KR920-923 maximum payload size (repeater compatible).
1193#[cfg(feature = "kr920")]
1194static KR920_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 14] = [
1195    Some(MaxPayload::new(59, 51)),
1196    Some(MaxPayload::new(59, 51)),
1197    Some(MaxPayload::new(59, 51)),
1198    Some(MaxPayload::new(123, 115)),
1199    Some(MaxPayload::new(230, 222)),
1200    Some(MaxPayload::new(230, 222)),
1201    None,
1202    None,
1203    None,
1204    None,
1205    None,
1206    None,
1207    Some(MaxPayload::new(230, 222)),
1208    Some(MaxPayload::new(230, 222)),
1209];
1210
1211/// RP002-1.0.5 Table 86: KR920-923 maximum payload size (not repeater compatible).
1212#[cfg(feature = "kr920")]
1213static KR920_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 14] = [
1214    Some(MaxPayload::new(59, 51)),
1215    Some(MaxPayload::new(59, 51)),
1216    Some(MaxPayload::new(59, 51)),
1217    Some(MaxPayload::new(123, 115)),
1218    Some(MaxPayload::new(250, 242)),
1219    Some(MaxPayload::new(250, 242)),
1220    None,
1221    None,
1222    None,
1223    None,
1224    None,
1225    None,
1226    Some(MaxPayload::new(250, 242)),
1227    Some(MaxPayload::new(250, 242)),
1228];
1229
1230/// RP002-1.0.5 Table 87: KR920-923 downlink RX1 data rate mapping.
1231#[cfg(feature = "kr920")]
1232static KR920_RX1: [&[u8]; 14] = [
1233    &[0, 0, 0, 0, 0, 0],
1234    &[1, 0, 0, 0, 0, 0],
1235    &[2, 1, 0, 0, 0, 0],
1236    &[3, 2, 1, 0, 0, 0],
1237    &[4, 3, 2, 1, 0, 0],
1238    &[5, 4, 3, 2, 1, 0],
1239    &[0, 0, 0, 0, 0, 0],
1240    &[0, 0, 0, 0, 0, 0],
1241    &[0, 0, 0, 0, 0, 0],
1242    &[0, 0, 0, 0, 0, 0],
1243    &[0, 0, 0, 0, 0, 0],
1244    &[0, 0, 0, 0, 0, 0],
1245    &[12, 5, 4, 3, 2, 1],
1246    &[13, 12, 5, 4, 3, 2],
1247];
1248
1249/// RP002-1.0.5 Table 82: KR920-923 data rate back-off.
1250#[cfg(feature = "kr920")]
1251static KR920_BACKOFF: [Option<u8>; 14] = [
1252    None,
1253    Some(0),
1254    Some(1),
1255    Some(2),
1256    Some(3),
1257    Some(4),
1258    None,
1259    None,
1260    None,
1261    None,
1262    None,
1263    None,
1264    Some(5),
1265    Some(12),
1266];
1267
1268/// RP002-1.0.5 Tables 78 and 79: the three default and join channels.
1269#[cfg(feature = "kr920")]
1270static KR920_CHANNELS: [ChannelBlock; 1] = [ChannelBlock::new(922_100_000, 200_000, 3, 0, 5)];
1271
1272/// RP002-1.0.5 Table 77: the band's power ceiling steps at 922.1 MHz.
1273///
1274/// Korea publishes no duty cycle for this band; the two sub-bands differ only in
1275/// how much power they allow, so the limit reported here is the ceiling.
1276#[cfg(feature = "kr920")]
1277static KR920_SUB_BANDS: [SubBand; 2] = [
1278    SubBand::new(920_900_000, 921_900_000, 1000, 10),
1279    SubBand::new(922_100_000, 923_300_000, 1000, 14),
1280];
1281
1282/// The KR920-923 channel plan, RP002-1.0.5 section 3.11.
1283#[cfg(feature = "kr920")]
1284pub static KR920: ChannelPlan<'static> = ChannelPlan {
1285    name: "KR920-923",
1286    uplink_data_rates: &KR920_DATA_RATES,
1287    downlink_data_rates: &KR920_DATA_RATES,
1288    max_payload_repeater: &KR920_MAX_PAYLOAD_REPEATER,
1289    max_payload_direct: &KR920_MAX_PAYLOAD_DIRECT,
1290    downlink_max_payload_repeater: &KR920_MAX_PAYLOAD_REPEATER,
1291    downlink_max_payload_direct: &KR920_MAX_PAYLOAD_DIRECT,
1292    max_payload_dwell_limited: None,
1293    join_channels: &KR920_CHANNELS,
1294    default_channels: &KR920_CHANNELS,
1295    sub_bands: &KR920_SUB_BANDS,
1296    default_max_eirp_dbm: 14,
1297    tx_power_step_db: 2,
1298    max_tx_power_index: 7,
1299    rx1_data_rate_offsets: &KR920_RX1,
1300    rx1_data_rate_offsets_dwell_limited: None,
1301    max_rx1_data_rate_offset: 5,
1302    rx2_frequency_hz: 921_900_000,
1303    rx2_data_rate: 0,
1304    data_rate_backoff: &KR920_BACKOFF,
1305    beacon: Beacon {
1306        data_rate: 3,
1307        frequency_hz: 923_100_000,
1308        ping_slot_frequency_hz: 923_100_000,
1309    },
1310    has_dwell_time_limit: false,
1311};
1312
1313// IN865, RP002-1.0.5 section 3.12.
1314
1315/// RP002-1.0.5 Table 91: IN865 TX data rate.
1316#[cfg(feature = "in865")]
1317static IN865_DATA_RATES: [Option<DataRate>; 14] = [
1318    Some(DataRate::lora(12, 125_000, 250)),
1319    Some(DataRate::lora(11, 125_000, 440)),
1320    Some(DataRate::lora(10, 125_000, 980)),
1321    Some(DataRate::lora(9, 125_000, 1_760)),
1322    Some(DataRate::lora(8, 125_000, 3_125)),
1323    Some(DataRate::lora(7, 125_000, 5_470)),
1324    None,
1325    Some(DataRate::fsk(50_000)),
1326    None,
1327    None,
1328    None,
1329    None,
1330    Some(DataRate::lora(6, 125_000, 9_375)),
1331    Some(DataRate::lora(5, 125_000, 15_625)),
1332];
1333
1334/// RP002-1.0.5 Table 96: IN865 maximum payload size (repeater compatible).
1335#[cfg(feature = "in865")]
1336static IN865_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 14] = [
1337    Some(MaxPayload::new(59, 51)),
1338    Some(MaxPayload::new(59, 51)),
1339    Some(MaxPayload::new(59, 51)),
1340    Some(MaxPayload::new(123, 115)),
1341    Some(MaxPayload::new(230, 222)),
1342    Some(MaxPayload::new(230, 222)),
1343    None,
1344    Some(MaxPayload::new(230, 222)),
1345    None,
1346    None,
1347    None,
1348    None,
1349    Some(MaxPayload::new(230, 222)),
1350    Some(MaxPayload::new(230, 222)),
1351];
1352
1353/// RP002-1.0.5 Table 97: IN865 maximum payload size (not repeater compatible).
1354#[cfg(feature = "in865")]
1355static IN865_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 14] = [
1356    Some(MaxPayload::new(59, 51)),
1357    Some(MaxPayload::new(59, 51)),
1358    Some(MaxPayload::new(59, 51)),
1359    Some(MaxPayload::new(123, 115)),
1360    Some(MaxPayload::new(250, 242)),
1361    Some(MaxPayload::new(250, 242)),
1362    None,
1363    Some(MaxPayload::new(250, 242)),
1364    None,
1365    None,
1366    None,
1367    None,
1368    Some(MaxPayload::new(250, 242)),
1369    Some(MaxPayload::new(250, 242)),
1370];
1371
1372/// RP002-1.0.5 Table 98: IN865 downlink RX1 data rate mapping.
1373///
1374/// India is one of the regions that allows all eight RX1 data-rate offsets.
1375#[cfg(feature = "in865")]
1376static IN865_RX1: [&[u8]; 14] = [
1377    &[0, 0, 0, 0, 0, 0, 1, 2],
1378    &[1, 0, 0, 0, 0, 0, 2, 3],
1379    &[2, 1, 0, 0, 0, 0, 3, 4],
1380    &[3, 2, 1, 0, 0, 0, 4, 5],
1381    &[4, 3, 2, 1, 0, 0, 5, 5],
1382    &[5, 4, 3, 2, 1, 0, 5, 7],
1383    &[0, 0, 0, 0, 0, 0, 1, 2],
1384    &[7, 5, 5, 4, 3, 2, 7, 7],
1385    &[0, 0, 0, 0, 0, 0, 1, 2],
1386    &[0, 0, 0, 0, 0, 0, 1, 2],
1387    &[0, 0, 0, 0, 0, 0, 1, 2],
1388    &[0, 0, 0, 0, 0, 0, 1, 2],
1389    &[12, 5, 4, 3, 2, 1, 13, 13],
1390    &[13, 12, 5, 4, 3, 2, 13, 13],
1391];
1392
1393/// RP002-1.0.5 Table 93: IN865 data rate back-off.
1394#[cfg(feature = "in865")]
1395static IN865_BACKOFF: [Option<u8>; 14] = [
1396    None,
1397    Some(0),
1398    Some(1),
1399    Some(2),
1400    Some(3),
1401    Some(4),
1402    None,
1403    Some(5),
1404    None,
1405    None,
1406    None,
1407    None,
1408    Some(5),
1409    Some(12),
1410];
1411
1412/// RP002-1.0.5 Tables 89 and 90: the three default and join channels.
1413///
1414/// These are not evenly spaced, so each is its own single-channel block.
1415#[cfg(feature = "in865")]
1416static IN865_CHANNELS: [ChannelBlock; 3] = [
1417    ChannelBlock::new(865_062_500, 0, 1, 0, 5),
1418    ChannelBlock::new(865_402_500, 0, 1, 0, 5),
1419    ChannelBlock::new(865_985_000, 0, 1, 0, 5),
1420];
1421
1422/// The IN865 channel plan, RP002-1.0.5 section 3.12.
1423///
1424/// The published ceiling is 29.2 dBm EIRP, reported here as the whole decibel
1425/// below it so a caller reading this as a limit is never over the real one.
1426#[cfg(feature = "in865")]
1427pub static IN865: ChannelPlan<'static> = ChannelPlan {
1428    name: "IN865",
1429    uplink_data_rates: &IN865_DATA_RATES,
1430    downlink_data_rates: &IN865_DATA_RATES,
1431    max_payload_repeater: &IN865_MAX_PAYLOAD_REPEATER,
1432    max_payload_direct: &IN865_MAX_PAYLOAD_DIRECT,
1433    downlink_max_payload_repeater: &IN865_MAX_PAYLOAD_REPEATER,
1434    downlink_max_payload_direct: &IN865_MAX_PAYLOAD_DIRECT,
1435    max_payload_dwell_limited: None,
1436    join_channels: &IN865_CHANNELS,
1437    default_channels: &IN865_CHANNELS,
1438    sub_bands: &[],
1439    default_max_eirp_dbm: 29,
1440    tx_power_step_db: 2,
1441    max_tx_power_index: 10,
1442    rx1_data_rate_offsets: &IN865_RX1,
1443    rx1_data_rate_offsets_dwell_limited: None,
1444    max_rx1_data_rate_offset: 7,
1445    rx2_frequency_hz: 866_550_000,
1446    rx2_data_rate: 2,
1447    data_rate_backoff: &IN865_BACKOFF,
1448    beacon: Beacon {
1449        data_rate: 4,
1450        frequency_hz: 866_550_000,
1451        ping_slot_frequency_hz: 866_550_000,
1452    },
1453    has_dwell_time_limit: false,
1454};
1455
1456// RU864-870, RP002-1.0.5 section 3.13.
1457
1458/// RP002-1.0.5 Table 102: RU864-870 TX data rate.
1459#[cfg(feature = "ru864")]
1460static RU864_DATA_RATES: [Option<DataRate>; 14] = [
1461    Some(DataRate::lora(12, 125_000, 250)),
1462    Some(DataRate::lora(11, 125_000, 440)),
1463    Some(DataRate::lora(10, 125_000, 980)),
1464    Some(DataRate::lora(9, 125_000, 1_760)),
1465    Some(DataRate::lora(8, 125_000, 3_125)),
1466    Some(DataRate::lora(7, 125_000, 5_470)),
1467    Some(DataRate::lora(7, 250_000, 11_000)),
1468    Some(DataRate::fsk(50_000)),
1469    None,
1470    None,
1471    None,
1472    None,
1473    Some(DataRate::lora(6, 125_000, 9_375)),
1474    Some(DataRate::lora(5, 125_000, 15_625)),
1475];
1476
1477/// RP002-1.0.5 Table 107: RU864-870 maximum payload size (repeater compatible).
1478#[cfg(feature = "ru864")]
1479static RU864_MAX_PAYLOAD_REPEATER: [Option<MaxPayload>; 14] = [
1480    Some(MaxPayload::new(59, 51)),
1481    Some(MaxPayload::new(59, 51)),
1482    Some(MaxPayload::new(59, 51)),
1483    Some(MaxPayload::new(123, 115)),
1484    Some(MaxPayload::new(230, 222)),
1485    Some(MaxPayload::new(230, 222)),
1486    Some(MaxPayload::new(230, 222)),
1487    Some(MaxPayload::new(230, 222)),
1488    None,
1489    None,
1490    None,
1491    None,
1492    Some(MaxPayload::new(230, 222)),
1493    Some(MaxPayload::new(230, 222)),
1494];
1495
1496/// RP002-1.0.5 Table 108: RU864-870 maximum payload size (not repeater compatible).
1497#[cfg(feature = "ru864")]
1498static RU864_MAX_PAYLOAD_DIRECT: [Option<MaxPayload>; 14] = [
1499    Some(MaxPayload::new(59, 51)),
1500    Some(MaxPayload::new(59, 51)),
1501    Some(MaxPayload::new(59, 51)),
1502    Some(MaxPayload::new(123, 115)),
1503    Some(MaxPayload::new(250, 242)),
1504    Some(MaxPayload::new(250, 242)),
1505    Some(MaxPayload::new(250, 242)),
1506    Some(MaxPayload::new(250, 242)),
1507    None,
1508    None,
1509    None,
1510    None,
1511    Some(MaxPayload::new(250, 242)),
1512    Some(MaxPayload::new(250, 242)),
1513];
1514
1515/// RP002-1.0.5 Table 109: RU864-870 downlink RX1 data rate mapping.
1516#[cfg(feature = "ru864")]
1517static RU864_RX1: [&[u8]; 14] = [
1518    &[0, 0, 0, 0, 0, 0],
1519    &[1, 0, 0, 0, 0, 0],
1520    &[2, 1, 0, 0, 0, 0],
1521    &[3, 2, 1, 0, 0, 0],
1522    &[4, 3, 2, 1, 0, 0],
1523    &[5, 4, 3, 2, 1, 0],
1524    &[6, 5, 4, 3, 2, 1],
1525    &[7, 6, 5, 4, 3, 2],
1526    &[0, 0, 0, 0, 0, 0],
1527    &[0, 0, 0, 0, 0, 0],
1528    &[0, 0, 0, 0, 0, 0],
1529    &[0, 0, 0, 0, 0, 0],
1530    &[12, 5, 4, 3, 2, 1],
1531    &[13, 12, 5, 4, 3, 2],
1532];
1533
1534/// RP002-1.0.5 Table 104: RU864-870 data rate back-off.
1535#[cfg(feature = "ru864")]
1536static RU864_BACKOFF: [Option<u8>; 14] = [
1537    None,
1538    Some(0),
1539    Some(1),
1540    Some(2),
1541    Some(3),
1542    Some(4),
1543    Some(5),
1544    Some(6),
1545    None,
1546    None,
1547    None,
1548    None,
1549    Some(5),
1550    Some(12),
1551];
1552
1553/// RP002-1.0.5 Tables 100 and 101: the two default and join channels.
1554#[cfg(feature = "ru864")]
1555static RU864_CHANNELS: [ChannelBlock; 1] = [ChannelBlock::new(868_900_000, 200_000, 2, 0, 5)];
1556
1557/// The Russian band carries a 1% duty cycle on its default channels.
1558#[cfg(feature = "ru864")]
1559static RU864_SUB_BANDS: [SubBand; 1] = [SubBand::new(868_700_000, 869_200_000, 10, 16)];
1560
1561/// The RU864-870 channel plan, RP002-1.0.5 section 3.13.
1562#[cfg(feature = "ru864")]
1563pub static RU864: ChannelPlan<'static> = ChannelPlan {
1564    name: "RU864-870",
1565    uplink_data_rates: &RU864_DATA_RATES,
1566    downlink_data_rates: &RU864_DATA_RATES,
1567    max_payload_repeater: &RU864_MAX_PAYLOAD_REPEATER,
1568    max_payload_direct: &RU864_MAX_PAYLOAD_DIRECT,
1569    downlink_max_payload_repeater: &RU864_MAX_PAYLOAD_REPEATER,
1570    downlink_max_payload_direct: &RU864_MAX_PAYLOAD_DIRECT,
1571    max_payload_dwell_limited: None,
1572    join_channels: &RU864_CHANNELS,
1573    default_channels: &RU864_CHANNELS,
1574    sub_bands: &RU864_SUB_BANDS,
1575    default_max_eirp_dbm: 16,
1576    tx_power_step_db: 2,
1577    max_tx_power_index: 7,
1578    rx1_data_rate_offsets: &RU864_RX1,
1579    rx1_data_rate_offsets_dwell_limited: None,
1580    max_rx1_data_rate_offset: 5,
1581    rx2_frequency_hz: 869_100_000,
1582    rx2_data_rate: 0,
1583    data_rate_backoff: &RU864_BACKOFF,
1584    beacon: Beacon {
1585        data_rate: 3,
1586        frequency_hz: 869_100_000,
1587        ping_slot_frequency_hz: 868_900_000,
1588    },
1589    has_dwell_time_limit: false,
1590};