lorawan_device/region/fixed_channel_plans/
mod.rs

1use super::*;
2use core::marker::PhantomData;
3use lorawan::maccommands::ChannelMask;
4
5mod join_channels;
6use join_channels::JoinChannels;
7
8#[cfg(feature = "region-au915")]
9mod au915;
10#[cfg(feature = "region-us915")]
11mod us915;
12
13#[cfg(feature = "region-au915")]
14pub use au915::AU915;
15#[cfg(feature = "region-us915")]
16pub use us915::US915;
17
18seq_macro::seq!(
19    N in 1..=8 {
20        /// Subband definitions used to bias the join process of a fixed channel plan (ie: US915, AU915).
21        /// Each Subband holds 8 channels. eg: subband 1 contains: channels 0-7, subband 2: channels 8-15, etc.
22        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
23        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24        #[repr(usize)]
25        pub enum Subband {
26            #(
27                _~N = N,
28            )*
29        }
30    }
31);
32
33impl From<Subband> for usize {
34    fn from(value: Subband) -> Self {
35        value as usize
36    }
37}
38
39#[derive(Default, Clone)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub(crate) struct FixedChannelPlan<const NUM_DR: usize, F: FixedChannelRegion<NUM_DR>> {
42    last_tx_channel: u8,
43    channel_mask: ChannelMask<9>,
44    _fixed_channel_region: PhantomData<F>,
45    join_channels: JoinChannels,
46}
47
48impl<const D: usize, F: FixedChannelRegion<D>> FixedChannelPlan<D, F> {
49    pub fn set_125k_channels(&mut self, enabled: bool) {
50        let mask = if enabled {
51            0xFF
52        } else {
53            0x00
54        };
55        self.channel_mask.set_bank(0, mask);
56        self.channel_mask.set_bank(1, mask);
57        self.channel_mask.set_bank(2, mask);
58        self.channel_mask.set_bank(3, mask);
59        self.channel_mask.set_bank(4, mask);
60        self.channel_mask.set_bank(5, mask);
61        self.channel_mask.set_bank(6, mask);
62        self.channel_mask.set_bank(7, mask);
63    }
64
65    #[allow(unused)]
66    pub fn get_max_payload_length(datarate: DR, repeater_compatible: bool, dwell_time: bool) -> u8 {
67        F::get_max_payload_length(datarate, repeater_compatible, dwell_time)
68    }
69}
70
71pub(crate) trait FixedChannelRegion<const D: usize>: ChannelRegion<D> {
72    fn uplink_channels() -> &'static [u32; 72];
73    fn downlink_channels() -> &'static [u32; 8];
74    fn get_default_rx2() -> u32;
75    fn get_rx_datarate(tx_datarate: DR, frame: &Frame, window: &Window) -> Datarate;
76    fn get_dbm() -> i8;
77}
78
79impl<const D: usize, F: FixedChannelRegion<D>> RegionHandler for FixedChannelPlan<D, F> {
80    fn process_join_accept<T: AsRef<[u8]>, C>(
81        &mut self,
82        join_accept: &DecryptedJoinAcceptPayload<T, C>,
83    ) {
84        if let Some(CfList::FixedChannel(channel_mask)) = join_accept.c_f_list() {
85            // Reset the join channels state
86            self.join_channels.reset();
87            self.channel_mask = channel_mask;
88        }
89    }
90
91    fn handle_link_adr_channel_mask(
92        &mut self,
93        channel_mask_control: u8,
94        channel_mask: ChannelMask<2>,
95    ) {
96        self.join_channels.reset();
97        match channel_mask_control {
98            0..=4 => {
99                let base_index = channel_mask_control as usize * 2;
100                self.channel_mask.set_bank(base_index, channel_mask.get_index(0));
101                self.channel_mask.set_bank(base_index + 1, channel_mask.get_index(1));
102            }
103            5 => {
104                let channel_mask: u16 =
105                    channel_mask.get_index(0) as u16 | ((channel_mask.get_index(1) as u16) << 8);
106                self.channel_mask.set_bank(0, ((channel_mask & 0b1) * 0xFF) as u8);
107                self.channel_mask.set_bank(1, ((channel_mask & 0b10) * 0xFF) as u8);
108                self.channel_mask.set_bank(2, ((channel_mask & 0b100) * 0xFF) as u8);
109                self.channel_mask.set_bank(3, ((channel_mask & 0b1000) * 0xFF) as u8);
110                self.channel_mask.set_bank(4, ((channel_mask & 0b10000) * 0xFF) as u8);
111                self.channel_mask.set_bank(5, ((channel_mask & 0b100000) * 0xFF) as u8);
112                self.channel_mask.set_bank(6, ((channel_mask & 0b1000000) * 0xFF) as u8);
113                self.channel_mask.set_bank(7, ((channel_mask & 0b10000000) * 0xFF) as u8);
114                self.channel_mask.set_bank(8, ((channel_mask & 0b100000000) * 0xFF) as u8);
115            }
116            6 => {
117                self.set_125k_channels(true);
118            }
119            7 => {
120                self.set_125k_channels(false);
121            }
122            _ => {
123                //RFU
124            }
125        }
126    }
127
128    fn get_tx_dr_and_frequency<RNG: RngCore>(
129        &mut self,
130        rng: &mut RNG,
131        datarate: DR,
132        frame: &Frame,
133    ) -> (Datarate, u32) {
134        match frame {
135            Frame::Join => {
136                let channel = self.join_channels.get_next_channel(rng);
137                let dr = if channel < 64 {
138                    DR::_0
139                } else {
140                    DR::_4
141                };
142                self.last_tx_channel = channel;
143                let data_rate = F::datarates()[dr as usize].clone().unwrap();
144                (data_rate, F::uplink_channels()[channel as usize])
145            }
146            Frame::Data => {
147                // The join bias gets reset after receiving CFList in Join Frame
148                // or ChannelMask in the LinkADRReq in Data Frame.
149                // If it has not been reset yet, we continue to use the bias for the data frames.
150                // We hope to acquire ChannelMask via LinkADRReq.
151                let (data_rate, channel) = if self.join_channels.has_bias_and_not_exhausted() {
152                    let channel = self.join_channels.get_next_channel(rng);
153                    let dr = if channel < 64 {
154                        DR::_0
155                    } else {
156                        DR::_4
157                    };
158                    (F::datarates()[dr as usize].clone().unwrap(), channel)
159                // Alternatively, we will ask JoinChannel logic to determine a channel from the
160                // subband that  the join succeeded on.
161                } else if let Some(channel) = self.join_channels.first_data_channel(rng) {
162                    (F::datarates()[datarate as usize].clone().unwrap(), channel)
163                } else {
164                    // For the data frame, the datarate impacts which channel sets we can choose
165                    // from. If the datarate bandwidth is 500 kHz, we must use
166                    // channels 64-71. Else, we must use 0-63
167                    let datarate = F::datarates()[datarate as usize].clone().unwrap();
168                    if datarate.bandwidth == Bandwidth::_500KHz {
169                        let mut channel = (rng.next_u32() & 0b111) as u8;
170                        // keep selecting a random channel until we find one that is enabled
171                        while !self.channel_mask.is_enabled(channel.into()).unwrap() {
172                            channel = (rng.next_u32() & 0b111) as u8;
173                        }
174                        (datarate, 64 + channel)
175                    } else {
176                        let mut channel = (rng.next_u32() & 0b111111) as u8;
177                        // keep selecting a random channel until we find one that is enabled
178                        while !self.channel_mask.is_enabled(channel.into()).unwrap() {
179                            channel = (rng.next_u32() & 0b111111) as u8;
180                        }
181                        (datarate, channel)
182                    }
183                };
184                self.last_tx_channel = channel;
185                (data_rate, F::uplink_channels()[channel as usize])
186            }
187        }
188    }
189
190    fn get_rx_frequency(&self, _frame: &Frame, window: &Window) -> u32 {
191        let channel = self.last_tx_channel % 8;
192        match window {
193            Window::_1 => F::downlink_channels()[channel as usize],
194            Window::_2 => F::get_default_rx2(),
195        }
196    }
197
198    fn get_dbm(&self) -> i8 {
199        F::get_dbm()
200    }
201
202    fn get_rx_datarate(&self, tx_datarate: DR, frame: &Frame, window: &Window) -> Datarate {
203        F::get_rx_datarate(tx_datarate, frame, window)
204    }
205}