use super::*;
use core::marker::PhantomData;
#[cfg(any(
feature = "region-as923-1",
feature = "region-as923-2",
feature = "region-as923-3",
feature = "region-as923-4"
))]
mod as923;
#[cfg(feature = "region-eu433")]
mod eu433;
#[cfg(feature = "region-eu868")]
mod eu868;
#[cfg(feature = "region-in865")]
mod in865;
#[cfg(feature = "region-as923-1")]
pub(crate) use as923::AS923_1;
#[cfg(feature = "region-as923-2")]
pub(crate) use as923::AS923_2;
#[cfg(feature = "region-as923-3")]
pub(crate) use as923::AS923_3;
#[cfg(feature = "region-as923-4")]
pub(crate) use as923::AS923_4;
#[cfg(feature = "region-eu433")]
pub(crate) use eu433::EU433;
#[cfg(feature = "region-eu868")]
pub(crate) use eu868::EU868;
#[cfg(feature = "region-in865")]
pub(crate) use in865::IN865;
#[derive(Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub(crate) struct DynamicChannelPlan<
const NUM_JOIN_CHANNELS: usize,
const NUM_DATARATES: usize,
R: DynamicChannelRegion<NUM_JOIN_CHANNELS, NUM_DATARATES>,
> {
additional_channels: [Option<u32>; 5],
channel_mask: ChannelMask<9>,
last_tx_channel: u8,
_fixed_channel_region: PhantomData<R>,
rx1_offset: usize,
rx2_dr: usize,
}
impl<
const NUM_JOIN_CHANNELS: usize,
const NUM_DATARATES: usize,
R: DynamicChannelRegion<NUM_JOIN_CHANNELS, NUM_DATARATES>,
> DynamicChannelPlan<NUM_JOIN_CHANNELS, NUM_DATARATES, R>
{
fn get_channel(&self, channel: usize) -> Option<u32> {
if channel < NUM_JOIN_CHANNELS {
Some(R::join_channels()[channel])
} else {
self.additional_channels[channel - NUM_JOIN_CHANNELS]
}
}
fn highest_additional_channel_index_plus_one(&self) -> usize {
let mut index_plus_one = 0;
for (i, channel) in self.additional_channels.iter().enumerate() {
if channel.is_some() {
index_plus_one = i + 1;
}
}
index_plus_one
}
fn get_random_in_range<RNG: RngCore>(&self, rng: &mut RNG) -> usize {
let range = self.highest_additional_channel_index_plus_one() + NUM_JOIN_CHANNELS;
let cm = if range > 16 {
0b11111
} else if range > 8 {
0b1111
} else {
0b111
};
(rng.next_u32() as usize) & cm
}
pub fn get_max_payload_length(datarate: DR, repeater_compatible: bool, dwell_time: bool) -> u8 {
R::get_max_payload_length(datarate, repeater_compatible, dwell_time)
}
}
pub(crate) trait DynamicChannelRegion<const NUM_JOIN_CHANNELS: usize, const NUM_DATARATES: usize>:
ChannelRegion<NUM_DATARATES>
{
fn join_channels() -> [u32; NUM_JOIN_CHANNELS];
fn get_default_rx2() -> u32;
}
impl<
const NUM_JOIN_CHANNELS: usize,
const NUM_DATARATES: usize,
R: DynamicChannelRegion<NUM_JOIN_CHANNELS, NUM_DATARATES>,
> RegionHandler for DynamicChannelPlan<NUM_JOIN_CHANNELS, NUM_DATARATES, R>
{
fn process_join_accept<T: AsRef<[u8]>, C>(
&mut self,
join_accept: &DecryptedJoinAcceptPayload<T, C>,
) {
match join_accept.c_f_list() {
Some(CfList::DynamicChannel(cf_list)) => {
for (index, freq) in cf_list.iter().enumerate() {
let value = freq.value();
if value != 0 {
self.additional_channels[index] = Some(value);
} else {
self.additional_channels[index] = None;
}
}
}
Some(CfList::FixedChannel(_cf_list)) => {
}
None => {}
}
}
fn handle_link_adr_channel_mask(
&mut self,
channel_mask_control: u8,
channel_mask: ChannelMask<2>,
) {
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 => {
for i in 0..8 {
self.channel_mask.set_bank(i, 0xFF);
}
}
_ => {
}
}
}
fn get_tx_dr_and_frequency<RNG: RngCore>(
&mut self,
rng: &mut RNG,
datarate: DR,
frame: &Frame,
) -> (Datarate, u32) {
match frame {
Frame::Join => {
let mut channel = (rng.next_u32() & 0b111) as u8;
while channel as usize >= NUM_JOIN_CHANNELS {
channel = (rng.next_u32() & 0b111) as u8;
}
self.last_tx_channel = channel;
(
R::datarates()[datarate as usize].clone().unwrap(),
R::join_channels()[channel as usize],
)
}
Frame::Data => {
let mut channel = self.get_random_in_range(rng);
loop {
if self.channel_mask.is_enabled(channel).unwrap() {
if let Some(freq) = self.get_channel(channel) {
self.last_tx_channel = channel as u8;
return (R::datarates()[datarate as usize].clone().unwrap(), freq);
}
}
channel = self.get_random_in_range(rng)
}
}
}
}
fn get_rx_frequency(&self, _frame: &Frame, window: &Window) -> u32 {
match window {
Window::_1 => self.get_channel(self.last_tx_channel as usize).unwrap(),
Window::_2 => R::get_default_rx2(),
}
}
fn get_rx_datarate(&self, tx_datarate: DR, _frame: &Frame, window: &Window) -> Datarate {
let datarate = match window {
Window::_1 => tx_datarate as usize + self.rx1_offset,
Window::_2 => self.rx2_dr,
};
R::datarates()[datarate].clone().unwrap()
}
}