206 lines
8.0 KiB
Rust
206 lines
8.0 KiB
Rust
use super::*;
|
|
use core::marker::PhantomData;
|
|
use lorawan::maccommands::ChannelMask;
|
|
|
|
mod join_channels;
|
|
use join_channels::JoinChannels;
|
|
|
|
#[cfg(feature = "region-au915")]
|
|
mod au915;
|
|
#[cfg(feature = "region-us915")]
|
|
mod us915;
|
|
|
|
#[cfg(feature = "region-au915")]
|
|
pub use au915::AU915;
|
|
#[cfg(feature = "region-us915")]
|
|
pub use us915::US915;
|
|
|
|
seq_macro::seq!(
|
|
N in 1..=8 {
|
|
/// Subband definitions used to bias the join process of a fixed channel plan (ie: US915, AU915).
|
|
/// Each Subband holds 8 channels. eg: subband 1 contains: channels 0-7, subband 2: channels 8-15, etc.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
#[repr(usize)]
|
|
pub enum Subband {
|
|
#(
|
|
_~N = N,
|
|
)*
|
|
}
|
|
}
|
|
);
|
|
|
|
impl From<Subband> for usize {
|
|
fn from(value: Subband) -> Self {
|
|
value as usize
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Clone)]
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
pub(crate) struct FixedChannelPlan<const NUM_DR: usize, F: FixedChannelRegion<NUM_DR>> {
|
|
last_tx_channel: u8,
|
|
channel_mask: ChannelMask<9>,
|
|
_fixed_channel_region: PhantomData<F>,
|
|
join_channels: JoinChannels,
|
|
}
|
|
|
|
impl<const D: usize, F: FixedChannelRegion<D>> FixedChannelPlan<D, F> {
|
|
pub fn set_125k_channels(&mut self, enabled: bool) {
|
|
let mask = if enabled {
|
|
0xFF
|
|
} else {
|
|
0x00
|
|
};
|
|
self.channel_mask.set_bank(0, mask);
|
|
self.channel_mask.set_bank(1, mask);
|
|
self.channel_mask.set_bank(2, mask);
|
|
self.channel_mask.set_bank(3, mask);
|
|
self.channel_mask.set_bank(4, mask);
|
|
self.channel_mask.set_bank(5, mask);
|
|
self.channel_mask.set_bank(6, mask);
|
|
self.channel_mask.set_bank(7, mask);
|
|
}
|
|
|
|
#[allow(unused)]
|
|
pub fn get_max_payload_length(datarate: DR, repeater_compatible: bool, dwell_time: bool) -> u8 {
|
|
F::get_max_payload_length(datarate, repeater_compatible, dwell_time)
|
|
}
|
|
}
|
|
|
|
pub(crate) trait FixedChannelRegion<const D: usize>: ChannelRegion<D> {
|
|
fn uplink_channels() -> &'static [u32; 72];
|
|
fn downlink_channels() -> &'static [u32; 8];
|
|
fn get_default_rx2() -> u32;
|
|
fn get_rx_datarate(tx_datarate: DR, frame: &Frame, window: &Window) -> Datarate;
|
|
fn get_dbm() -> i8;
|
|
}
|
|
|
|
impl<const D: usize, F: FixedChannelRegion<D>> RegionHandler for FixedChannelPlan<D, F> {
|
|
fn process_join_accept<T: AsRef<[u8]>, C>(
|
|
&mut self,
|
|
join_accept: &DecryptedJoinAcceptPayload<T, C>,
|
|
) {
|
|
if let Some(CfList::FixedChannel(channel_mask)) = join_accept.c_f_list() {
|
|
// Reset the join channels state
|
|
self.join_channels.reset();
|
|
self.channel_mask = channel_mask;
|
|
}
|
|
}
|
|
|
|
fn handle_link_adr_channel_mask(
|
|
&mut self,
|
|
channel_mask_control: u8,
|
|
channel_mask: ChannelMask<2>,
|
|
) {
|
|
self.join_channels.reset();
|
|
match channel_mask_control {
|
|
0..=4 => {
|
|
let base_index = channel_mask_control as usize * 2;
|
|
self.channel_mask.set_bank(base_index, channel_mask.get_index(0));
|
|
self.channel_mask.set_bank(base_index + 1, channel_mask.get_index(1));
|
|
}
|
|
5 => {
|
|
let channel_mask: u16 =
|
|
channel_mask.get_index(0) as u16 | ((channel_mask.get_index(1) as u16) << 8);
|
|
self.channel_mask.set_bank(0, ((channel_mask & 0b1) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(1, ((channel_mask & 0b10) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(2, ((channel_mask & 0b100) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(3, ((channel_mask & 0b1000) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(4, ((channel_mask & 0b10000) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(5, ((channel_mask & 0b100000) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(6, ((channel_mask & 0b1000000) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(7, ((channel_mask & 0b10000000) * 0xFF) as u8);
|
|
self.channel_mask.set_bank(8, ((channel_mask & 0b100000000) * 0xFF) as u8);
|
|
}
|
|
6 => {
|
|
self.set_125k_channels(true);
|
|
}
|
|
7 => {
|
|
self.set_125k_channels(false);
|
|
}
|
|
_ => {
|
|
//RFU
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_tx_dr_and_frequency<RNG: RngCore>(
|
|
&mut self,
|
|
rng: &mut RNG,
|
|
datarate: DR,
|
|
frame: &Frame,
|
|
) -> (Datarate, u32) {
|
|
match frame {
|
|
Frame::Join => {
|
|
let channel = self.join_channels.get_next_channel(rng);
|
|
let dr = if channel < 64 {
|
|
DR::_0
|
|
} else {
|
|
DR::_4
|
|
};
|
|
self.last_tx_channel = channel;
|
|
let data_rate = F::datarates()[dr as usize].clone().unwrap();
|
|
(data_rate, F::uplink_channels()[channel as usize])
|
|
}
|
|
Frame::Data => {
|
|
// The join bias gets reset after receiving CFList in Join Frame
|
|
// or ChannelMask in the LinkADRReq in Data Frame.
|
|
// If it has not been reset yet, we continue to use the bias for the data frames.
|
|
// We hope to acquire ChannelMask via LinkADRReq.
|
|
let (data_rate, channel) = if self.join_channels.has_bias_and_not_exhausted() {
|
|
let channel = self.join_channels.get_next_channel(rng);
|
|
let dr = if channel < 64 {
|
|
DR::_0
|
|
} else {
|
|
DR::_4
|
|
};
|
|
(F::datarates()[dr as usize].clone().unwrap(), channel)
|
|
// Alternatively, we will ask JoinChannel logic to determine a channel from the
|
|
// subband that the join succeeded on.
|
|
} else if let Some(channel) = self.join_channels.first_data_channel(rng) {
|
|
(F::datarates()[datarate as usize].clone().unwrap(), channel)
|
|
} else {
|
|
// For the data frame, the datarate impacts which channel sets we can choose
|
|
// from. If the datarate bandwidth is 500 kHz, we must use
|
|
// channels 64-71. Else, we must use 0-63
|
|
let datarate = F::datarates()[datarate as usize].clone().unwrap();
|
|
if datarate.bandwidth == Bandwidth::_500KHz {
|
|
let mut channel = (rng.next_u32() & 0b111) as u8;
|
|
// keep selecting a random channel until we find one that is enabled
|
|
while !self.channel_mask.is_enabled(channel.into()).unwrap() {
|
|
channel = (rng.next_u32() & 0b111) as u8;
|
|
}
|
|
(datarate, 64 + channel)
|
|
} else {
|
|
let mut channel = (rng.next_u32() & 0b111111) as u8;
|
|
// keep selecting a random channel until we find one that is enabled
|
|
while !self.channel_mask.is_enabled(channel.into()).unwrap() {
|
|
channel = (rng.next_u32() & 0b111111) as u8;
|
|
}
|
|
(datarate, channel)
|
|
}
|
|
};
|
|
self.last_tx_channel = channel;
|
|
(data_rate, F::uplink_channels()[channel as usize])
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_rx_frequency(&self, _frame: &Frame, window: &Window) -> u32 {
|
|
let channel = self.last_tx_channel % 8;
|
|
match window {
|
|
Window::_1 => F::downlink_channels()[channel as usize],
|
|
Window::_2 => F::get_default_rx2(),
|
|
}
|
|
}
|
|
|
|
fn get_dbm(&self) -> i8 {
|
|
F::get_dbm()
|
|
}
|
|
|
|
fn get_rx_datarate(&self, tx_datarate: DR, frame: &Frame, window: &Window) -> Datarate {
|
|
F::get_rx_datarate(tx_datarate, frame, window)
|
|
}
|
|
}
|