lrwn/
cflist.rs

1use anyhow::Result;
2#[cfg(feature = "serde")]
3use serde::Serialize;
4
5#[derive(Debug, PartialEq, Eq, Clone)]
6#[cfg_attr(feature = "serde", derive(Serialize))]
7pub enum CFList {
8    Channels(CFListChannels),
9    ChannelMask(CFListChannelMasks),
10}
11
12impl CFList {
13    pub fn from_bytes(b: [u8; 16]) -> Result<Self> {
14        let mut bb: [u8; 15] = [0; 15];
15        bb.clone_from_slice(&b[..15]);
16
17        // match on CFListType.
18        match b[15] {
19            0x00 => Ok(CFList::Channels(CFListChannels::from_bytes(bb))),
20            0x01 => Ok(CFList::ChannelMask(CFListChannelMasks::from_bytes(bb))),
21            _ => Err(anyhow!("unexpected CFListType")),
22        }
23    }
24
25    pub fn to_bytes(&self) -> Result<[u8; 16]> {
26        let mut b: [u8; 16] = [0; 16];
27
28        match self {
29            CFList::Channels(v) => {
30                b[..15].clone_from_slice(&v.to_bytes()?);
31                b[15] = 0x00;
32            }
33            CFList::ChannelMask(v) => {
34                b[..15].clone_from_slice(&v.to_bytes()?);
35                b[15] = 0x01;
36            }
37        }
38
39        Ok(b)
40    }
41}
42
43#[derive(Debug, PartialEq, Eq, Clone)]
44#[cfg_attr(feature = "serde", derive(Serialize))]
45pub struct CFListChannels([u32; 5]);
46
47impl CFListChannels {
48    pub fn new(channels: [u32; 5]) -> Self {
49        CFListChannels(channels)
50    }
51
52    pub fn from_slice(channels: &[u32]) -> Result<Self> {
53        let mut channels_array: [u32; 5] = [0; 5];
54        if channels.len() > channels_array.len() {
55            return Err(anyhow!(
56                "Max number of channels is {}",
57                channels_array.len()
58            ));
59        }
60
61        for (i, c) in channels.iter().enumerate() {
62            channels_array[i] = *c;
63        }
64
65        Ok(Self::new(channels_array))
66    }
67
68    pub fn from_bytes(b: [u8; 15]) -> Self {
69        let mut channels: [u32; 5] = [0; 5];
70
71        for (i, ch) in channels.iter_mut().enumerate() {
72            let index = i * 3;
73            *ch = u32::from_le_bytes([b[index], b[index + 1], b[index + 2], 0x00]) * 100;
74        }
75
76        CFListChannels(channels)
77    }
78
79    pub fn to_bytes(&self) -> Result<[u8; 15]> {
80        let mut b: [u8; 15] = [0; 15];
81
82        for (i, f) in self.0.iter().enumerate() {
83            if f % 100 != 0 {
84                return Err(anyhow!("frequency must be a multiple of 100"));
85            }
86
87            let f = f / 100;
88            if f > (1 << 24) - 1 {
89                return Err(anyhow!("max value of frequency is 2^24-1"));
90            }
91
92            let index = i * 3;
93            b[index..index + 3].clone_from_slice(&f.to_le_bytes()[..3]);
94        }
95
96        Ok(b)
97    }
98
99    pub fn iter(&self) -> std::slice::Iter<'_, u32> {
100        self.0.iter()
101    }
102}
103
104#[derive(Debug, PartialEq, Eq, Clone)]
105#[cfg_attr(feature = "serde", derive(Serialize))]
106pub struct CFListChannelMasks(Vec<ChMask>);
107
108impl CFListChannelMasks {
109    pub fn new(masks: Vec<ChMask>) -> Self {
110        CFListChannelMasks(masks)
111    }
112
113    pub fn from_bytes(b: [u8; 15]) -> Self {
114        let b = b[..14].to_vec(); // each mask uses 2 bytes
115
116        let mut masks: Vec<ChMask> = Vec::with_capacity(b.len() / 3);
117        let mut pending: Vec<ChMask> = Vec::with_capacity(b.len() / 2);
118
119        for i in (0..b.len()).step_by(2) {
120            pending.push(ChMask::from_bytes([b[i], b[i + 1]]));
121
122            if b[i..i + 2] != vec![0x00, 0x00] {
123                masks.append(&mut pending);
124            }
125        }
126
127        CFListChannelMasks(masks)
128    }
129
130    pub fn to_bytes(&self) -> Result<[u8; 15]> {
131        if self.0.len() > 6 {
132            return Err(anyhow!("max number of channel-masks is 6"));
133        }
134
135        let mut b: [u8; 15] = [0; 15];
136
137        for (i, mask) in self.0.iter().enumerate() {
138            let index = i * 2;
139            b[index..index + 2].clone_from_slice(&mask.to_bytes());
140        }
141
142        Ok(b)
143    }
144
145    pub fn iter(&self) -> std::slice::Iter<'_, ChMask> {
146        self.0.iter()
147    }
148}
149
150/// ChMask encodes the channels usable for uplink access. 0 = channel 1,
151/// 15 = channel 16.
152#[derive(Debug, PartialEq, Eq, Clone, Copy)]
153#[cfg_attr(feature = "serde", derive(Serialize))]
154pub struct ChMask([bool; 16]);
155
156impl ChMask {
157    const SIZE: usize = 2;
158
159    pub fn new(mask: [bool; 16]) -> Self {
160        ChMask(mask)
161    }
162
163    pub fn set(&mut self, i: usize, v: bool) {
164        self.0[i] = v
165    }
166
167    pub fn from_slice(mask: &[bool]) -> Result<Self> {
168        let mut mask_array: [bool; 16] = [false; 16];
169
170        if mask.len() > mask_array.len() {
171            return Err(anyhow!("Max number of masks is {}", mask_array.len()));
172        }
173
174        for (i, m) in mask.iter().enumerate() {
175            mask_array[i] = *m;
176        }
177
178        Ok(Self::new(mask_array))
179    }
180
181    pub fn from_bytes(b: [u8; Self::SIZE]) -> Self {
182        let mut mask: [bool; 16] = [false; 16];
183
184        let n = u16::from_le_bytes(b);
185        for (i, m) in mask.iter_mut().enumerate() {
186            *m = n & (1 << i) != 0;
187        }
188
189        ChMask(mask)
190    }
191
192    pub fn to_bytes(&self) -> [u8; Self::SIZE] {
193        let mut n: u16 = 0;
194        for i in 0..16 {
195            if self.0[i] {
196                n |= 1 << i;
197            }
198        }
199
200        n.to_le_bytes()
201    }
202}
203
204impl IntoIterator for ChMask {
205    type Item = bool;
206    type IntoIter = std::vec::IntoIter<Self::Item>;
207
208    #[allow(clippy::unnecessary_to_owned)]
209    fn into_iter(self) -> Self::IntoIter {
210        self.0.to_vec().into_iter()
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217
218    struct Test {
219        cflist: CFList,
220        bytes: [u8; 16],
221    }
222
223    fn tests() -> Vec<Test> {
224        vec![
225            Test {
226                cflist: CFList::ChannelMask(CFListChannelMasks::new(vec![ChMask::new([
227                    true, true, true, true, true, true, true, true, false, false, false, false,
228                    false, false, false, false,
229                ])])),
230                bytes: [
231                    0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232                    0x00, 0x00, 0x01,
233                ],
234            },
235            Test {
236                cflist: CFList::ChannelMask(CFListChannelMasks::new(vec![
237                    ChMask::new([false; 16]),
238                    ChMask::new([
239                        true, true, true, true, true, true, true, true, false, false, false, false,
240                        false, false, false, false,
241                    ]),
242                ])),
243                bytes: [
244                    0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245                    0x00, 0x00, 0x01,
246                ],
247            },
248            Test {
249                cflist: CFList::Channels(CFListChannels::new([
250                    867100000, 867300000, 867500000, 867700000, 867900000,
251                ])),
252                bytes: [
253                    0x18, 0x4f, 0x84, 0xe8, 0x56, 0x84, 0xb8, 0x5e, 0x84, 0x88, 0x66, 0x84, 0x58,
254                    0x6e, 0x84, 0x0,
255                ],
256            },
257        ]
258    }
259
260    #[test]
261    fn test_to_bytes() {
262        for tst in tests() {
263            assert_eq!(tst.bytes, tst.cflist.to_bytes().unwrap());
264        }
265    }
266
267    #[test]
268    fn test_from_bytes() {
269        for tst in tests() {
270            assert_eq!(tst.cflist, CFList::from_bytes(tst.bytes).unwrap());
271        }
272    }
273}