chirpstack/lrwn/src/cflist.rs
2023-07-03 12:27:26 +01:00

274 lines
7.2 KiB
Rust

use anyhow::Result;
#[cfg(feature = "serde")]
use serde::Serialize;
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum CFList {
Channels(CFListChannels),
ChannelMask(CFListChannelMasks),
}
impl CFList {
pub fn from_bytes(b: [u8; 16]) -> Result<Self> {
let mut bb: [u8; 15] = [0; 15];
bb.clone_from_slice(&b[..15]);
// match on CFListType.
match b[15] {
0x00 => Ok(CFList::Channels(CFListChannels::from_bytes(bb))),
0x01 => Ok(CFList::ChannelMask(CFListChannelMasks::from_bytes(bb))),
_ => Err(anyhow!("unexpected CFListType")),
}
}
pub fn to_bytes(&self) -> Result<[u8; 16]> {
let mut b: [u8; 16] = [0; 16];
match self {
CFList::Channels(v) => {
b[..15].clone_from_slice(&v.to_bytes()?);
b[15] = 0x00;
}
CFList::ChannelMask(v) => {
b[..15].clone_from_slice(&v.to_bytes()?);
b[15] = 0x01;
}
}
Ok(b)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct CFListChannels([u32; 5]);
impl CFListChannels {
pub fn new(channels: [u32; 5]) -> Self {
CFListChannels(channels)
}
pub fn from_slice(channels: &[u32]) -> Result<Self> {
let mut channels_array: [u32; 5] = [0; 5];
if channels.len() > channels_array.len() {
return Err(anyhow!(
"Max number of channels is {}",
channels_array.len()
));
}
for (i, c) in channels.iter().enumerate() {
channels_array[i] = *c;
}
Ok(Self::new(channels_array))
}
pub fn from_bytes(b: [u8; 15]) -> Self {
let mut channels: [u32; 5] = [0; 5];
for (i, ch) in channels.iter_mut().enumerate() {
let index = i * 3;
*ch = u32::from_le_bytes([b[index], b[index + 1], b[index + 2], 0x00]) * 100;
}
CFListChannels(channels)
}
pub fn to_bytes(&self) -> Result<[u8; 15]> {
let mut b: [u8; 15] = [0; 15];
for (i, f) in self.0.iter().enumerate() {
if f % 100 != 0 {
return Err(anyhow!("frequency must be a multiple of 100"));
}
let f = f / 100;
if f > (1 << 24) - 1 {
return Err(anyhow!("max value of frequency is 2^24-1"));
}
let index = i * 3;
b[index..index + 3].clone_from_slice(&f.to_le_bytes()[..3]);
}
Ok(b)
}
pub fn iter(&self) -> std::slice::Iter<'_, u32> {
self.0.iter()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct CFListChannelMasks(Vec<ChMask>);
impl CFListChannelMasks {
pub fn new(masks: Vec<ChMask>) -> Self {
CFListChannelMasks(masks)
}
pub fn from_bytes(b: [u8; 15]) -> Self {
let b = b[..14].to_vec(); // each mask uses 2 bytes
let mut masks: Vec<ChMask> = Vec::with_capacity(b.len() / 3);
let mut pending: Vec<ChMask> = Vec::with_capacity(b.len() / 2);
for i in (0..b.len()).step_by(2) {
pending.push(ChMask::from_bytes([b[i], b[i + 1]]));
if b[i..i + 2] != vec![0x00, 0x00] {
masks.append(&mut pending);
}
}
CFListChannelMasks(masks)
}
pub fn to_bytes(&self) -> Result<[u8; 15]> {
if self.0.len() > 6 {
return Err(anyhow!("max number of channel-masks is 6"));
}
let mut b: [u8; 15] = [0; 15];
for (i, mask) in self.0.iter().enumerate() {
let index = i * 2;
b[index..index + 2].clone_from_slice(&mask.to_bytes());
}
Ok(b)
}
pub fn iter(&self) -> std::slice::Iter<'_, ChMask> {
self.0.iter()
}
}
/// ChMask encodes the channels usable for uplink access. 0 = channel 1,
/// 15 = channel 16.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ChMask([bool; 16]);
impl ChMask {
const SIZE: usize = 2;
pub fn new(mask: [bool; 16]) -> Self {
ChMask(mask)
}
pub fn set(&mut self, i: usize, v: bool) {
self.0[i] = v
}
pub fn from_slice(mask: &[bool]) -> Result<Self> {
let mut mask_array: [bool; 16] = [false; 16];
if mask.len() > mask_array.len() {
return Err(anyhow!("Max number of masks is {}", mask_array.len()));
}
for (i, m) in mask.iter().enumerate() {
mask_array[i] = *m;
}
Ok(Self::new(mask_array))
}
pub fn from_bytes(b: [u8; Self::SIZE]) -> Self {
let mut mask: [bool; 16] = [false; 16];
let n = u16::from_le_bytes(b);
for (i, m) in mask.iter_mut().enumerate() {
*m = n & (1 << i) != 0;
}
ChMask(mask)
}
pub fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut n: u16 = 0;
for i in 0..16 {
if self.0[i] {
n |= 1 << i;
}
}
n.to_le_bytes()
}
}
impl IntoIterator for ChMask {
type Item = bool;
type IntoIter = std::vec::IntoIter<Self::Item>;
#[allow(clippy::unnecessary_to_owned)]
fn into_iter(self) -> Self::IntoIter {
self.0.to_vec().into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Test {
cflist: CFList,
bytes: [u8; 16],
}
fn tests() -> Vec<Test> {
vec![
Test {
cflist: CFList::ChannelMask(CFListChannelMasks::new(vec![ChMask::new([
true, true, true, true, true, true, true, true, false, false, false, false,
false, false, false, false,
])])),
bytes: [
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01,
],
},
Test {
cflist: CFList::ChannelMask(CFListChannelMasks::new(vec![
ChMask::new([false; 16]),
ChMask::new([
true, true, true, true, true, true, true, true, false, false, false, false,
false, false, false, false,
]),
])),
bytes: [
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01,
],
},
Test {
cflist: CFList::Channels(CFListChannels::new([
867100000, 867300000, 867500000, 867700000, 867900000,
])),
bytes: [
0x18, 0x4f, 0x84, 0xe8, 0x56, 0x84, 0xb8, 0x5e, 0x84, 0x88, 0x66, 0x84, 0x58,
0x6e, 0x84, 0x0,
],
},
]
}
#[test]
fn test_to_bytes() {
for tst in tests() {
assert_eq!(tst.bytes, tst.cflist.to_bytes().unwrap());
}
}
#[test]
fn test_from_bytes() {
for tst in tests() {
assert_eq!(tst.cflist, CFList::from_bytes(tst.bytes).unwrap());
}
}
}