twine_codec/radio/
channel_mask.rs1use core::str::FromStr;
9
10use bitflags::bitflags;
11use bytes::{Buf, BufMut};
12use twine_rs_macros::Tlv;
13use twine_tlv::prelude::*;
14use typed_builder::TypedBuilder;
15
16use crate::TwineCodecError;
17
18bitflags! {
19 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
21 pub struct ChannelPageMask: u8 {
22 const PAGE_0 = 0;
24 }
25
26 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
30 pub struct ChannelMaskBits: u32 {
31 const CHANNEL_0 = 1 << 0;
32 const CHANNEL_1 = 1 << 1;
33 const CHANNEL_2 = 1 << 2;
34 const CHANNEL_3 = 1 << 3;
35 const CHANNEL_4 = 1 << 4;
36 const CHANNEL_5 = 1 << 5;
37 const CHANNEL_6 = 1 << 6;
38 const CHANNEL_7 = 1 << 7;
39 const CHANNEL_8 = 1 << 8;
40 const CHANNEL_9 = 1 << 9;
41 const CHANNEL_10 = 1 << 10;
42 const CHANNEL_11 = 1 << 11;
43 const CHANNEL_12 = 1 << 12;
44 const CHANNEL_13 = 1 << 13;
45 const CHANNEL_14 = 1 << 14;
46 const CHANNEL_15 = 1 << 15;
47 const CHANNEL_16 = 1 << 16;
48 const CHANNEL_17 = 1 << 17;
49 const CHANNEL_18 = 1 << 18;
50 const CHANNEL_19 = 1 << 19;
51 const CHANNEL_20 = 1 << 20;
52 const CHANNEL_21 = 1 << 21;
53 const CHANNEL_22 = 1 << 22;
54 const CHANNEL_23 = 1 << 23;
55 const CHANNEL_24 = 1 << 24;
56 const CHANNEL_25 = 1 << 25;
57 const CHANNEL_26 = 1 << 26;
58 const CHANNEL_27 = 1 << 27;
59 const CHANNEL_28 = 1 << 28;
60 const CHANNEL_29 = 1 << 29;
61 const CHANNEL_30 = 1 << 30;
62 const CHANNEL_31 = 1 << 31;
63 }
64}
65
66impl From<ChannelPageMask> for u8 {
67 fn from(value: ChannelPageMask) -> Self {
68 value.bits()
69 }
70}
71
72impl From<u8> for ChannelPageMask {
73 fn from(value: u8) -> Self {
74 match value {
75 0 => ChannelPageMask::PAGE_0,
76 _ => panic!("Invalid channel page mask: {}", value),
77 }
78 }
79}
80
81#[derive(Copy, Clone, Debug, Eq, PartialEq, Tlv, TypedBuilder)]
88#[tlv(tlv_type = 0x35, tlv_length = 6)]
89pub struct ChannelMask {
90 page: ChannelPageMask,
91 len: u8,
92 mask: ChannelMaskBits,
93}
94
95impl Default for ChannelMask {
96 fn default() -> Self {
97 let mask = ChannelMaskBits::CHANNEL_11
98 | ChannelMaskBits::CHANNEL_12
99 | ChannelMaskBits::CHANNEL_13
100 | ChannelMaskBits::CHANNEL_14
101 | ChannelMaskBits::CHANNEL_15
102 | ChannelMaskBits::CHANNEL_16
103 | ChannelMaskBits::CHANNEL_17
104 | ChannelMaskBits::CHANNEL_18
105 | ChannelMaskBits::CHANNEL_19
106 | ChannelMaskBits::CHANNEL_20
107 | ChannelMaskBits::CHANNEL_21
108 | ChannelMaskBits::CHANNEL_22
109 | ChannelMaskBits::CHANNEL_23
110 | ChannelMaskBits::CHANNEL_24
111 | ChannelMaskBits::CHANNEL_25
112 | ChannelMaskBits::CHANNEL_26;
113
114 ChannelMask {
115 page: ChannelPageMask::PAGE_0,
116 len: 4,
117 mask,
118 }
119 }
120}
121
122impl ChannelMask {
123 pub fn mask(&self) -> u32 {
124 self.mask.bits()
125 }
126}
127
128impl core::fmt::Display for ChannelMask {
129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130 write!(f, "0x{:08x}", self.mask())
131 }
132}
133
134impl FromStr for ChannelMask {
135 type Err = TwineCodecError;
136
137 fn from_str(s: &str) -> Result<Self, Self::Err> {
138 let s = s
139 .strip_prefix("0x")
140 .or_else(|| s.strip_prefix("0X"))
141 .unwrap_or(s);
142 let mask = u32::from_str_radix(s, 16).map_err(|_| TwineCodecError::StringParseError)?;
143 Ok(ChannelMask {
144 page: ChannelPageMask::PAGE_0,
145 len: 4,
146 mask: ChannelMaskBits::from_bits_truncate(mask),
147 })
148 }
149}
150
151impl DecodeTlvValueUnchecked for ChannelMask {
152 fn decode_tlv_value_unchecked(buffer: impl AsRef<[u8]>) -> Self {
153 let mut buffer = buffer.as_ref();
154 let page = buffer.get_u8();
155 let mask_len = buffer.get_u8();
156 let mask_bytes = buffer.get_u32();
157
158 let mask = ChannelMaskBits::from_bits_truncate(mask_bytes.reverse_bits());
162
163 Self {
164 page: page.into(),
165 len: mask_len,
166 mask,
167 }
168 }
169}
170
171impl TryEncodeTlvValue for ChannelMask {
172 fn try_encode_tlv_value(&self, buffer: &mut [u8]) -> Result<usize, twine_tlv::TwineTlvError> {
173 let mut buffer = buffer;
174 buffer.put_u8(self.page.into());
175 buffer.put_u8(self.len);
176 buffer.put_u32(self.mask.bits().reverse_bits());
177 Ok(self.tlv_len())
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn success_default() {
187 let default = ChannelMask::default();
188 assert_eq!(default.page, ChannelPageMask::PAGE_0);
189 assert_eq!(default.len, 4);
190 assert_eq!(default.mask(), 0x07FF_F800);
191 }
192
193 #[test]
194 fn success_decode_tlv() {
195 let tlv_bytes: [u8; 8] = [53, 6, 0, 4, 0, 31, 255, 224];
196 let channel_mask = ChannelMask::decode_tlv_unchecked(tlv_bytes);
197 assert_eq!(channel_mask.page, ChannelPageMask::PAGE_0);
198 assert_eq!(channel_mask.len, 4);
199 assert_eq!(channel_mask.mask(), 0x07FF_F800);
200 }
201
202 #[test]
203 fn success_encode_tlv() {
204 let channel_mask = ChannelMask::default();
205 let mut buffer = [0_u8; 8];
206 let bytes_written = channel_mask
207 .try_encode_tlv(&mut buffer)
208 .expect("Could not encode ChannelMask");
209 assert_eq!(bytes_written, channel_mask.tlv_total_len());
210 let expected_bytes: [u8; 8] = [53, 6, 0, 4, 0, 31, 255, 224];
211 assert_eq!(expected_bytes.as_ref(), &buffer[..bytes_written]);
212 }
213}