1use packet_encoding::{decodable_enum, Decodable, Encodable};
6
7use crate::{Error, Result};
8
9#[derive(Debug, Clone, PartialEq)]
13pub struct TxLabel(u8);
14
15const MAX_TX_LABEL: u8 = 0xF;
17
18impl TryFrom<u8> for TxLabel {
19 type Error = Error;
20 fn try_from(value: u8) -> Result<Self> {
21 if value > MAX_TX_LABEL {
22 Err(Error::OutOfRange)
23 } else {
24 Ok(TxLabel(value))
25 }
26 }
27}
28
29impl From<&TxLabel> for u8 {
30 fn from(v: &TxLabel) -> u8 {
31 v.0
32 }
33}
34
35impl From<&TxLabel> for usize {
36 fn from(v: &TxLabel) -> usize {
37 v.0 as usize
38 }
39}
40
41#[derive(Debug, Clone, PartialEq)]
46pub(crate) struct ProfileId([u8; 2]);
47
48pub(crate) const AV_REMOTE_PROFILE: &ProfileId = &ProfileId([0x11, 0x0e]);
50
51impl From<[u8; 2]> for ProfileId {
52 fn from(value: [u8; 2]) -> Self {
53 Self(value)
54 }
55}
56
57decodable_enum! {
58 pub enum PacketType<u8, Error, OutOfRange> {
61 Single = 0x00,
62 Start = 0x01,
63 Continue = 0x02,
64 End = 0x03,
65 }
66}
67
68decodable_enum! {
69 pub enum MessageType<u8, Error, OutOfRange> {
72 Command = 0x00,
73 Response = 0x01,
74 }
75}
76
77#[derive(Debug)]
78pub struct Header {
79 label: TxLabel, packet_type: PacketType, message_type: MessageType, invalid_profile_id: bool, num_packets: u8, profile_id: ProfileId, }
86
87impl Header {
88 pub(crate) fn new(
89 label: TxLabel,
90 profile_id: ProfileId,
91 message_type: MessageType,
92 invalid_profile_id: bool,
93 ) -> Header {
94 Header {
95 label,
96 profile_id,
97 message_type,
98 packet_type: PacketType::Single,
99 invalid_profile_id,
100 num_packets: 1,
101 }
102 }
103
104 pub(crate) fn create_response(&self, packet_type: PacketType) -> Header {
106 Header {
107 label: self.label.clone(),
108 profile_id: self.profile_id.clone(),
109 message_type: MessageType::Response,
110 packet_type,
111 invalid_profile_id: false,
112 num_packets: 1,
113 }
114 }
115
116 pub(crate) fn create_invalid_profile_id_response(&self) -> Header {
119 Header {
120 label: self.label.clone(),
121 profile_id: self.profile_id.clone(),
122 message_type: MessageType::Response,
123 packet_type: PacketType::Single,
124 invalid_profile_id: true,
125 num_packets: 1,
126 }
127 }
128
129 pub(crate) fn label(&self) -> &TxLabel {
130 &self.label
131 }
132
133 pub(crate) fn profile_id(&self) -> &ProfileId {
134 &self.profile_id
135 }
136
137 pub fn message_type(&self) -> &MessageType {
138 &self.message_type
139 }
140
141 pub fn packet_type(&self) -> &PacketType {
142 &self.packet_type
143 }
144
145 pub fn is_invalid_profile_id(&self) -> bool {
146 self.invalid_profile_id
147 }
148
149 pub fn is_type(&self, other: &MessageType) -> bool {
151 &self.message_type == other
152 }
153
154 pub fn is_single(&self) -> bool {
155 self.packet_type == PacketType::Single
156 }
157}
158
159impl Decodable for Header {
160 type Error = Error;
161
162 fn decode(bytes: &[u8]) -> Result<Header> {
163 if bytes.len() < 3 {
164 return Err(Error::OutOfRange);
165 }
166 let label = TxLabel::try_from(bytes[0] >> 4)?;
167 let packet_type = PacketType::try_from((bytes[0] >> 2) & 0x3)?;
168 let (id_offset, num_packets) = match packet_type {
169 PacketType::Start => {
170 if bytes.len() < 4 {
171 return Err(Error::OutOfRange);
172 }
173 (2, bytes[1])
174 }
175 _ => (1, 1),
176 };
177
178 let profile_id = ProfileId::from([bytes[id_offset], bytes[id_offset + 1]]);
179 let invalid_profile_id = bytes[0] & 0x1 == 1;
180 let header = Header {
181 label,
182 profile_id,
183 message_type: MessageType::try_from(bytes[0] >> 1 & 0x1)?,
184 packet_type,
185 invalid_profile_id,
186 num_packets,
187 };
188 Ok(header)
189 }
190}
191
192impl Encodable for Header {
193 type Error = Error;
194
195 fn encoded_len(&self) -> usize {
196 match self.packet_type {
197 PacketType::Start => 4,
198 _ => 3,
199 }
200 }
201
202 fn encode(&self, buf: &mut [u8]) -> Result<()> {
203 if buf.len() < self.encoded_len() {
204 return Err(Error::Encoding);
205 }
206 let invalid_profile_id: u8 = if self.invalid_profile_id { 1 } else { 0 };
207 buf[0] = u8::from(&self.label) << 4
208 | u8::from(&self.packet_type) << 2
209 | u8::from(&self.message_type) << 1
210 | invalid_profile_id;
211 let mut buf_idx = 1;
212 if self.packet_type == PacketType::Start {
213 buf[buf_idx] = self.num_packets;
214 buf_idx = 2;
215 }
216 let profile_id = self.profile_id.0;
217 buf[buf_idx] = profile_id[0];
218 buf[buf_idx + 1] = profile_id[1];
219 Ok(())
220 }
221}
222
223#[cfg(test)]
224mod test {
225 use super::*;
226
227 #[test]
228 fn test_header_encode() {
230 let header =
231 Header::new(TxLabel(0), AV_REMOTE_PROFILE.clone(), MessageType::Command, false);
232 assert!(!header.is_invalid_profile_id());
233 assert!(header.is_single());
234 assert!(header.is_type(&MessageType::Command));
235 assert_eq!(TxLabel(0), *header.label());
236 let len = header.encoded_len();
237 assert_eq!(3, len);
238 let mut buf = vec![0; len];
239 assert!(header.encode(&mut buf[..]).is_ok());
240
241 assert_eq!(
242 &[
243 0x00, 0x11, 0x0e, ],
247 &buf[..]
248 );
249 }
250
251 #[test]
252 fn test_header_encode_response() {
254 let header =
255 Header::new(TxLabel(15), AV_REMOTE_PROFILE.clone(), MessageType::Command, false);
256 let header = header.create_response(PacketType::Single);
257 assert!(!header.is_invalid_profile_id());
258 assert!(header.is_single());
259 assert!(header.is_type(&MessageType::Response));
260 assert_eq!(TxLabel(15), *header.label());
261 let len = header.encoded_len();
262 assert_eq!(3, len);
263 let mut buf = vec![0; len];
264 assert!(header.encode(&mut buf[..]).is_ok());
265
266 assert_eq!(
267 &[
268 0xf2, 0x11, 0x0e, ],
272 &buf[..]
273 );
274 }
275
276 #[test]
277 fn test_header_encode_invalid_profile_response() {
279 let header =
280 Header::new(TxLabel(0), AV_REMOTE_PROFILE.clone(), MessageType::Command, false);
281 let header = header.create_invalid_profile_id_response();
282 assert!(header.is_invalid_profile_id());
283 assert!(header.is_single());
284 assert!(header.is_type(&MessageType::Response));
285 assert_eq!(TxLabel(0), *header.label());
286 let len = header.encoded_len();
287 assert_eq!(3, len);
288 let mut buf = vec![0; len];
289 assert!(header.encode(&mut buf[..]).is_ok());
290
291 assert_eq!(
292 &[
293 0x03, 0x11, 0x0e, ],
297 &buf[..]
298 );
299 }
300
301 #[test]
302 fn test_header_decode_invalid_packet_response() {
304 let header = Header::decode(&[
305 0xf3, 0x11, 0x0e, 0x12, 0x34, 0x45, ])
312 .expect("unable to decode header");
313 assert!(header.is_invalid_profile_id());
314 assert!(header.is_single());
315 assert!(header.is_type(&MessageType::Response));
316 assert_eq!(TxLabel(15), *header.label());
317 }
318
319 #[test]
320 fn test_header_decode_command() {
322 let header = Header::decode(&[
323 0x80, 0x11, 0x0e, 0x34, 0x45, ])
329 .expect("unable to decode header");
330 assert!(!header.is_invalid_profile_id());
331 assert!(header.is_single());
332 assert!(header.is_type(&MessageType::Command));
333 assert_eq!(TxLabel(8), *header.label());
334 }
335
336 #[test]
337 fn test_header_decode_invalid() {
339 assert_eq!(
340 Error::OutOfRange,
341 Header::decode(&[
342 0x80, 0x11, ])
346 .unwrap_err()
347 );
348 }
349
350 #[test]
351 fn txlabel_tofrom_u8() {
352 let mut label: Result<TxLabel> = TxLabel::try_from(15);
353 assert!(label.is_ok());
354 assert_eq!(15, u8::from(&label.unwrap()));
355 label = TxLabel::try_from(16);
356 assert_eq!(Err(Error::OutOfRange), label);
357 }
358
359 #[test]
360 fn txlabel_to_usize() {
361 let label = TxLabel::try_from(1).unwrap();
362 assert_eq!(1, usize::from(&label));
363 }
364}