1use packet_encoding::{decodable_enum, Decodable, Encodable};
6
7use crate::{Error, Result};
8
9decodable_enum! {
10 pub enum CommandType<u8, Error, OutOfRange> {
13 Control = 0x00,
14 Status = 0x01,
15 SpecificInquiry = 0x02,
16 Notify = 0x03,
17 GeneralInquiry = 0x04, }
19}
20
21decodable_enum! {
22 pub enum ResponseType<u8, Error, OutOfRange> {
25 NotImplemented = 0x08,
26 Accepted = 0x09,
27 Rejected = 0x0a,
28 InTransition = 0x0b, ImplementedStable = 0x0c,
30 Changed = 0x0d,
31 Interim = 0x0f,
32 }
33}
34
35#[derive(Debug, Copy, Clone, PartialEq)]
36pub enum PacketType {
37 Command(CommandType),
38 Response(ResponseType),
39}
40
41impl PacketType {
42 pub fn try_from(val: u8) -> Result<Self> {
43 if val < 0x08 {
44 Ok(PacketType::Command(CommandType::try_from(val)?))
45 } else {
46 Ok(PacketType::Response(ResponseType::try_from(val)?))
47 }
48 }
49
50 pub fn raw_value(&self) -> u8 {
51 match self {
52 PacketType::Command(x) => u8::from(x),
53 PacketType::Response(x) => u8::from(x),
54 }
55 }
56}
57
58decodable_enum! {
59 pub enum OpCode<u8, Error, OutOfRange> {
62 VendorDependent = 0x00,
63 UnitInfo = 0x30,
64 SubUnitInfo = 0x31,
65 Passthrough = 0x7c,
66 }
67}
68
69decodable_enum! {
70 pub enum SubunitType<u8, Error, OutOfRange> {
73 Panel = 0x09,
74 Unit = 0x1F,
75 }
76}
77
78#[derive(Debug, Clone, PartialEq)]
80pub(crate) struct CompanyId([u8; 3]);
81
82pub(crate) const BT_SIG_COMPANY_ID: CompanyId = CompanyId([0x00, 0x19, 0x58]);
83
84impl TryFrom<&[u8]> for CompanyId {
85 type Error = Error;
86
87 fn try_from(value: &[u8]) -> Result<Self> {
88 if value.len() < 3 {
89 return Err(Error::OutOfRange);
90 }
91 let mut buf: [u8; 3] = [0; 3];
92 buf.copy_from_slice(&value[0..3]);
93 Ok(Self(buf))
94 }
95}
96
97#[derive(Debug)]
99pub struct Header {
100 packet_type: PacketType, subunit_type: u8, subunit_id: u8, op_code: OpCode, company_id: Option<CompanyId>, }
106
107impl Header {
108 pub(crate) fn new(
109 command_type: CommandType,
110 subunit_type: u8,
111 subunit_id: u8,
112 op_code: OpCode,
113 company_id: Option<CompanyId>,
114 ) -> Header {
115 Header {
116 packet_type: PacketType::Command(command_type),
117 subunit_type,
118 subunit_id,
119 op_code,
120 company_id,
121 }
122 }
123
124 pub(crate) fn create_response(&self, response_type: ResponseType) -> Result<Header> {
126 Ok(Header {
127 packet_type: PacketType::Response(response_type),
128 subunit_type: self.subunit_type,
129 subunit_id: self.subunit_id,
130 op_code: self.op_code,
131 company_id: self.company_id.clone(),
132 })
133 }
134
135 pub fn packet_type(&self) -> PacketType {
136 self.packet_type
137 }
138
139 pub fn op_code(&self) -> &OpCode {
140 &self.op_code
141 }
142
143 pub fn subunit_type(&self) -> Option<SubunitType> {
144 match SubunitType::try_from(self.subunit_type) {
145 Ok(x) => Some(x),
146 Err(_) => None,
147 }
148 }
149}
150
151impl Encodable for Header {
152 type Error = Error;
153
154 fn encoded_len(&self) -> usize {
155 if self.op_code == OpCode::VendorDependent {
156 6
157 } else {
158 3
159 }
160 }
161
162 fn encode(&self, buf: &mut [u8]) -> Result<()> {
163 if buf.len() < self.encoded_len() {
164 return Err(Error::Encoding);
165 }
166 buf[0] = self.packet_type.raw_value();
167 buf[1] = (self.subunit_type << 3) | (self.subunit_id & 0x7);
168 buf[2] = u8::from(&self.op_code);
169 if self.op_code == OpCode::VendorDependent {
170 let company_id = match self.company_id {
171 Some(ref x) => <[u8; 3]>::from(x.0),
172 None => return Err(Error::InvalidHeader),
173 };
174 buf[3..6].copy_from_slice(&company_id);
175 }
176 Ok(())
177 }
178}
179
180impl Decodable for Header {
181 type Error = Error;
182
183 fn decode(bytes: &[u8]) -> Result<Header> {
184 if bytes.len() < 3 {
185 return Err(Error::InvalidHeader);
186 }
187 if bytes[0] >> 4 != 0 {
188 return Err(Error::InvalidHeader);
190 }
191
192 let packet_type = PacketType::try_from(bytes[0]).map_err(|_| Error::InvalidHeader)?;
193 let subunit_type = bytes[1] >> 3;
194 let subunit_id = bytes[1] & 0x7;
195 let op_code = OpCode::try_from(bytes[2]).map_err(|_| Error::InvalidHeader)?;
196 let mut company_id = None;
197 if op_code == OpCode::VendorDependent {
198 if bytes.len() < 6 {
199 return Err(Error::InvalidHeader);
200 }
201 company_id = Some(CompanyId::try_from(&bytes[3..6]).map_err(|_| Error::InvalidHeader)?);
202 }
203 Ok(Header { packet_type, subunit_type, subunit_id, op_code, company_id })
204 }
205}
206
207#[cfg(test)]
208mod test {
209 use super::*;
210
211 #[test]
212 fn test_header_encode_vendor_dependent() {
214 let header = Header::new(
215 CommandType::Notify,
216 9,
217 0,
218 OpCode::VendorDependent,
219 Some(BT_SIG_COMPANY_ID),
220 );
221 assert_eq!(Some(SubunitType::Panel), header.subunit_type());
222 assert_eq!(PacketType::Command(CommandType::Notify), header.packet_type());
223 assert_eq!(&OpCode::VendorDependent, header.op_code());
224 let len = header.encoded_len();
225 assert_eq!(6, len);
226 let mut buf = vec![0; len];
227 assert!(header.encode(buf.as_mut_slice()).is_ok());
228
229 assert_eq!(
230 &[
231 0x03, 0x48, 0x00, 0x00, 0x19, 0x58 ],
236 &buf[..]
237 )
238 }
239
240 #[test]
241 fn test_header_encode_passthrough() {
243 let header = Header::new(CommandType::Control, 9, 0, OpCode::Passthrough, None);
244 assert_eq!(header.subunit_type().unwrap(), SubunitType::Panel);
245 assert_eq!(&OpCode::Passthrough, header.op_code());
246 let len = header.encoded_len();
247 assert_eq!(3, len);
248 let mut buf = vec![0; len];
249 assert!(header.encode(&mut buf[..]).is_ok());
250
251 assert_eq!(
252 &[
253 0x00, 0x48, 0x7c, ],
257 &buf[..]
258 )
259 }
260
261 #[test]
262 fn test_header_decode_passthrough_command() {
264 let header = Header::decode(&[
265 0x00, 0x48, 0x7c, 0x12, 0x34, 0x56, 0x67, ])
273 .expect("Error decoding packet");
274
275 assert_eq!(PacketType::Command(CommandType::Control), header.packet_type());
276 assert_eq!(Some(SubunitType::Panel), header.subunit_type());
277 assert_eq!(&OpCode::Passthrough, header.op_code());
278 }
279
280 #[test]
281 fn test_header_decode_passthrough_response() {
283 let header = Header::decode(&[
284 0x09, 0x48, 0x7c, 0x12, 0x34, 0x56, 0x67, ])
292 .expect("Error decoding packet");
293
294 assert_eq!(PacketType::Response(ResponseType::Accepted), header.packet_type());
295 assert_eq!(header.subunit_type().unwrap(), SubunitType::Panel);
296 assert_eq!(&OpCode::Passthrough, header.op_code());
297 }
298
299 #[test]
300 fn test_header_decode_invalid_ctype() {
302 assert_eq!(
303 Header::decode(&[
304 0x05, 0x48, 0x7c, 0x12, 0x34, 0x56, 0x67, ])
312 .unwrap_err(),
313 Error::InvalidHeader
314 );
315 }
316
317 #[test]
318 fn test_header_decode_partial() {
320 assert_eq!(
321 Header::decode(&[
322 0x0c, 0x48, 0x00, ])
327 .unwrap_err(),
328 Error::InvalidHeader
329 );
330 }
331}