Init
This commit is contained in:
205
lorawan-device-patch/src/region/fixed_channel_plans/mod.rs
Normal file
205
lorawan-device-patch/src/region/fixed_channel_plans/mod.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user