1use crate::error::Error;
8use crate::payload_util::require_exact_len;
9use alloc::vec::Vec;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13#[repr(u8)]
14#[allow(missing_docs)]
15pub enum BuzzerTone {
16 None = 0x00,
18 Off = 0x01,
19 Default = 0x02,
20}
21
22impl BuzzerTone {
23 pub const fn from_byte(b: u8) -> Self {
25 match b {
26 0x00 => Self::None,
27 0x01 => Self::Off,
28 _ => Self::Default,
29 }
30 }
31
32 pub const fn as_byte(self) -> u8 {
34 self as u8
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct BuzzerControl {
41 pub reader: u8,
43 pub tone: BuzzerTone,
45 pub on_time: u8,
47 pub off_time: u8,
49 pub count: u8,
51}
52
53impl BuzzerControl {
54 pub fn encode(&self) -> Result<Vec<u8>, Error> {
56 Ok(alloc::vec![
57 self.reader,
58 self.tone.as_byte(),
59 self.on_time,
60 self.off_time,
61 self.count,
62 ])
63 }
64
65 pub fn decode(data: &[u8]) -> Result<Self, Error> {
67 require_exact_len(data, 5, 0x6A)?;
68 Ok(Self {
69 reader: data[0],
70 tone: BuzzerTone::from_byte(data[1]),
71 on_time: data[2],
72 off_time: data[3],
73 count: data[4],
74 })
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn roundtrip() {
84 let body = BuzzerControl {
85 reader: 0x00,
86 tone: BuzzerTone::Default,
87 on_time: 5,
88 off_time: 5,
89 count: 3,
90 };
91 let bytes = body.encode().unwrap();
92 assert_eq!(bytes, [0x00, 0x02, 5, 5, 3]);
93 assert_eq!(BuzzerControl::decode(&bytes).unwrap(), body);
94 }
95
96 #[test]
97 fn decode_rejects_wrong_length() {
98 assert!(matches!(
99 BuzzerControl::decode(&[0; 4]),
100 Err(Error::PayloadLength { code: 0x6A, .. })
101 ));
102 }
103
104 #[test]
105 fn unknown_tone_decodes_to_default() {
106 assert_eq!(BuzzerTone::from_byte(0x99), BuzzerTone::Default);
107 }
108}