bt_avctp/avc/
types.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use packet_encoding::{decodable_enum, Decodable, Encodable};
6
7use crate::{Error, Result};
8
9decodable_enum! {
10    /// AV/C Command and Response types.
11    /// See AV/C General Specification Section 5.3.1 and 5.3.2
12    pub enum CommandType<u8, Error, OutOfRange> {
13        Control = 0x00,
14        Status = 0x01,
15        SpecificInquiry = 0x02,
16        Notify = 0x03,
17        GeneralInquiry = 0x04, // Unused with bt?
18    }
19}
20
21decodable_enum! {
22    /// AV/C Command and Response types.
23    /// See AV/C General Specification Section 5.3.1 and 5.3.2
24    pub enum ResponseType<u8, Error, OutOfRange> {
25        NotImplemented = 0x08,
26        Accepted = 0x09,
27        Rejected = 0x0a,
28        InTransition = 0x0b, // Unused with bt?
29        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    /// AV/C Op Codes
60    /// See AV/C General Specification Section 5.3.1
61    pub enum OpCode<u8, Error, OutOfRange> {
62        VendorDependent = 0x00,
63        UnitInfo = 0x30,
64        SubUnitInfo = 0x31,
65        Passthrough = 0x7c,
66    }
67}
68
69decodable_enum! {
70    /// Most common subunits from the AV/C General Specification in AVRCP
71    /// All AVRCP commands are transacted on the panel subunit according to the Panel Specification
72    pub enum SubunitType<u8, Error, OutOfRange> {
73        Panel = 0x09,
74        Unit = 0x1F,
75    }
76}
77
78/// An AVC Vendor Company Identifier
79#[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/// AVC Command and Response frames use the same layout with different command values
98#[derive(Debug)]
99pub struct Header {
100    packet_type: PacketType,       // byte 0, bit 3..0
101    subunit_type: u8,              // byte 1, bit 7..3
102    subunit_id: u8,                // byte 1, bit 2..0
103    op_code: OpCode,               // byte 2
104    company_id: Option<CompanyId>, // byte 3-5 (only vendor dependent packets)
105}
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    /// Creates a new Header with all the same fields but with a new response command type
125    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            // Upper 4 bits should be zero.
189            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    /// Test Header vendor dependent encoding
213    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, // notify
232                0x48, // panel subunit_type 9 (<< 3), subunit_id 0
233                0x00, // op code vendor dependent
234                0x00, 0x19, 0x58 // bit sig company id
235            ],
236            &buf[..]
237        )
238    }
239
240    #[test]
241    /// Test Header passthrough encoding
242    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, // control
254                0x48, // panel subunit_type 9 (<< 3), subunit_id 0
255                0x7c, // op code passthrough
256            ],
257            &buf[..]
258        )
259    }
260
261    #[test]
262    /// Test Header decoding
263    fn test_header_decode_passthrough_command() {
264        let header = Header::decode(&[
265            0x00, // control
266            0x48, // panel subunit_type 9 (<< 3), subunit_id 0
267            0x7c, // op code passthrough
268            0x12, // body should be ignored
269            0x34, // body should be ignored
270            0x56, // body should be ignored
271            0x67, // body should be ignored
272        ])
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    /// Test Header decoding
282    fn test_header_decode_passthrough_response() {
283        let header = Header::decode(&[
284            0x09, // accepted
285            0x48, // panel subunit_type 9 (<< 3), subunit_id 0
286            0x7c, // op code passthrough
287            0x12, // body should be ignored
288            0x34, // body should be ignored
289            0x56, // body should be ignored
290            0x67, // body should be ignored
291        ])
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    /// Test Header decoding
301    fn test_header_decode_invalid_ctype() {
302        assert_eq!(
303            Header::decode(&[
304                0x05, // invalid CType
305                0x48, // panel subunit_type 9 (<< 3), subunit_id 0
306                0x7c, // op code passthrough
307                0x12, // body should be ignored
308                0x34, // body should be ignored
309                0x56, // body should be ignored
310                0x67, // body should be ignored
311            ])
312            .unwrap_err(),
313            Error::InvalidHeader
314        );
315    }
316
317    #[test]
318    /// Test Header decoding
319    fn test_header_decode_partial() {
320        assert_eq!(
321            Header::decode(&[
322                0x0c, // stable
323                0x48, // panel subunit_type 9 (<< 3), subunit_id 0
324                0x00, // op vendor dependent
325                      // missing company id
326            ])
327            .unwrap_err(),
328            Error::InvalidHeader
329        );
330    }
331}