bt_common/
core.rs

1// Copyright 2023 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
5/// Traits and utilities to handle length-type-value structures.
6pub mod ltv;
7
8use crate::packet_encoding::{Encodable, Error as PacketError};
9use std::str::FromStr;
10
11/// Bluetooth Device Address that uniquely identifies the device
12/// to another Bluetooth device.
13/// See Core spec v5.3 Vol 2, Part B section 1.2.
14pub type Address = [u8; 6];
15
16/// See Core spec v5.3 Vol 3, Part C section 15.1.1.
17#[repr(u8)]
18#[derive(Clone, Copy, Debug, PartialEq)]
19pub enum AddressType {
20    Public = 0x00,
21    Random = 0x01,
22}
23
24impl AddressType {
25    pub const BYTE_SIZE: usize = 1;
26}
27
28impl TryFrom<u8> for AddressType {
29    type Error = PacketError;
30
31    fn try_from(value: u8) -> Result<Self, Self::Error> {
32        match value {
33            0x00 => Ok(Self::Public),
34            0x01 => Ok(Self::Random),
35            _ => Err(PacketError::OutOfRange),
36        }
37    }
38}
39
40impl FromStr for AddressType {
41    type Err = PacketError;
42
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        match s {
45            "Public" => Ok(AddressType::Public),
46            "Random" => Ok(AddressType::Random),
47            _ => Err(PacketError::InvalidParameter(format!("invalid address type: {s}"))),
48        }
49    }
50}
51
52/// Advertising Set ID which is 1 byte long.
53#[derive(Debug, Clone, Copy, PartialEq)]
54pub struct AdvertisingSetId(pub u8);
55
56impl AdvertisingSetId {
57    // Byte size if this is to be encoded.
58    pub const BYTE_SIZE: usize = 1;
59}
60
61/// SyncInfo Interval value which is 2 bytes long.
62#[derive(Debug, Clone, Copy, PartialEq)]
63pub struct PaInterval(pub u16);
64
65impl PaInterval {
66    pub const BYTE_SIZE: usize = 2;
67    pub const UNKNOWN_VALUE: u16 = 0xFFFF;
68
69    pub const fn unknown() -> Self {
70        Self(Self::UNKNOWN_VALUE)
71    }
72}
73
74impl Encodable for PaInterval {
75    type Error = PacketError;
76
77    /// Encodees the PaInterval to 2 byte value using little endian encoding.
78    fn encode(&self, buf: &mut [u8]) -> core::result::Result<(), Self::Error> {
79        if buf.len() < Self::BYTE_SIZE {
80            return Err(PacketError::BufferTooSmall);
81        }
82        buf[0..Self::BYTE_SIZE].copy_from_slice(&self.0.to_le_bytes());
83        Ok(())
84    }
85
86    fn encoded_len(&self) -> core::primitive::usize {
87        Self::BYTE_SIZE
88    }
89}
90
91/// Coding Format as defined by the Assigned Numbers Document. Section 2.11.
92/// Referenced in the Core Spec 5.3, Volume 4, Part E, Section 7 as well as
93/// various other profile specifications.
94#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
95pub enum CodingFormat {
96    MuLawLog,
97    ALawLog,
98    Cvsd,
99    Transparent,
100    LinearPcm,
101    Msbc,
102    Lc3,
103    G729a,
104    VendorSpecific,
105    Unrecognized(u8),
106}
107
108impl From<u8> for CodingFormat {
109    fn from(value: u8) -> Self {
110        match value {
111            0x00 => Self::MuLawLog,
112            0x01 => Self::ALawLog,
113            0x02 => Self::Cvsd,
114            0x03 => Self::Transparent,
115            0x04 => Self::LinearPcm,
116            0x05 => Self::Msbc,
117            0x06 => Self::Lc3,
118            0x07 => Self::G729a,
119            0xFF => Self::VendorSpecific,
120            x => Self::Unrecognized(x),
121        }
122    }
123}
124
125impl From<CodingFormat> for u8 {
126    fn from(value: CodingFormat) -> Self {
127        match value {
128            CodingFormat::MuLawLog => 0x00,
129            CodingFormat::ALawLog => 0x01,
130            CodingFormat::Cvsd => 0x02,
131            CodingFormat::Transparent => 0x03,
132            CodingFormat::LinearPcm => 0x04,
133            CodingFormat::Msbc => 0x05,
134            CodingFormat::Lc3 => 0x06,
135            CodingFormat::G729a => 0x07,
136            CodingFormat::VendorSpecific => 0xFF,
137            CodingFormat::Unrecognized(x) => x,
138        }
139    }
140}
141
142impl core::fmt::Display for CodingFormat {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        match self {
145            CodingFormat::MuLawLog => write!(f, "ยต-law log"),
146            CodingFormat::ALawLog => write!(f, "A-law log"),
147            CodingFormat::Cvsd => write!(f, "CVSD"),
148            CodingFormat::Transparent => write!(f, "Transparent"),
149            CodingFormat::LinearPcm => write!(f, "Linear PCM"),
150            CodingFormat::Msbc => write!(f, "mSBC"),
151            CodingFormat::Lc3 => write!(f, "LC3"),
152            CodingFormat::G729a => write!(f, "G.729A"),
153            CodingFormat::VendorSpecific => write!(f, "Vendor Specific"),
154            CodingFormat::Unrecognized(x) => write!(f, "Unrecognized ({x})"),
155        }
156    }
157}
158
159/// Codec_ID communicated by a basic audio profile service/role.
160#[derive(Debug, Clone, PartialEq)]
161pub enum CodecId {
162    /// From the Assigned Numbers. Format will not be
163    /// `CodingFormat::VendorSpecific`
164    Assigned(CodingFormat),
165    VendorSpecific {
166        company_id: crate::CompanyId,
167        vendor_specific_codec_id: u16,
168    },
169}
170
171impl CodecId {
172    pub const BYTE_SIZE: usize = 5;
173}
174
175impl crate::packet_encoding::Decodable for CodecId {
176    type Error = crate::packet_encoding::Error;
177
178    fn decode(buf: &[u8]) -> (core::result::Result<Self, Self::Error>, usize) {
179        if buf.len() < 5 {
180            return (Err(crate::packet_encoding::Error::UnexpectedDataLength), buf.len());
181        }
182        let format = buf[0].into();
183        if format != CodingFormat::VendorSpecific {
184            // Maybe don't ignore the company and vendor id, and check if they are wrong.
185            return (Ok(Self::Assigned(format)), 5);
186        }
187        let company_id = u16::from_le_bytes([buf[1], buf[2]]).into();
188        let vendor_specific_codec_id = u16::from_le_bytes([buf[3], buf[4]]);
189        (Ok(Self::VendorSpecific { company_id, vendor_specific_codec_id }), 5)
190    }
191}
192
193impl Encodable for CodecId {
194    type Error = PacketError;
195
196    fn encoded_len(&self) -> core::primitive::usize {
197        Self::BYTE_SIZE
198    }
199
200    fn encode(&self, buf: &mut [u8]) -> core::result::Result<(), Self::Error> {
201        if buf.len() < Self::BYTE_SIZE {
202            return Err(Self::Error::BufferTooSmall);
203        }
204        match self {
205            CodecId::Assigned(format) => {
206                buf[0] = (*format).into();
207                buf[1..5].fill(0);
208            }
209            CodecId::VendorSpecific { company_id, vendor_specific_codec_id } => {
210                buf[0] = 0xFF;
211                [buf[1], buf[2]] = u16::from(*company_id).to_le_bytes();
212                [buf[3], buf[4]] = vendor_specific_codec_id.to_le_bytes();
213            }
214        }
215        Ok(())
216    }
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
220pub enum Phy {
221    /// LE 1M PHY
222    Le1m,
223    /// LE 2M PHY
224    Le2m,
225    /// LE Coded PHY
226    LeCoded,
227}
228
229#[cfg(test)]
230mod tests {
231    use crate::packet_encoding::Decodable;
232
233    use super::*;
234    use std::str::FromStr;
235
236    #[test]
237    fn address_type_from_str() {
238        let addr_type = AddressType::from_str("Public").expect("should succeed");
239        assert_eq!(addr_type, AddressType::Public);
240        let addr_type = AddressType::from_str("Random").expect("should succeed");
241        assert_eq!(addr_type, AddressType::Random);
242        AddressType::from_str("invalid").expect_err("should fail");
243    }
244
245    #[test]
246    fn encode_pa_interval() {
247        let mut buf = [0; PaInterval::BYTE_SIZE];
248        let interval = PaInterval(0x1004);
249
250        interval.encode(&mut buf[..]).expect("should succeed");
251        assert_eq!(buf, [0x04, 0x10]);
252    }
253
254    #[test]
255    fn encode_pa_interval_fails() {
256        let mut buf = [0; 1]; // Not enough buffer space.
257        let interval = PaInterval(0x1004);
258
259        interval.encode(&mut buf[..]).expect_err("should fail");
260    }
261
262    #[test]
263    fn decode_codec_id() {
264        let assigned = [0x01, 0x00, 0x00, 0x00, 0x00];
265        let (codec_id, _) = CodecId::decode(&assigned[..]);
266        assert_eq!(codec_id, Ok(CodecId::Assigned(CodingFormat::ALawLog)));
267
268        let vendor_specific = [0xFF, 0x36, 0xFD, 0x11, 0x22];
269        let (codec_id, _) = CodecId::decode(&vendor_specific[..]);
270        assert_eq!(
271            codec_id,
272            Ok(CodecId::VendorSpecific {
273                company_id: (0xFD36 as u16).into(),
274                vendor_specific_codec_id: 0x2211
275            })
276        );
277    }
278
279    #[test]
280    fn encode_codec_id() {
281        let assigned = [0x01, 0x00, 0x00, 0x00, 0x00];
282        let (codec_id, _) = CodecId::decode(&assigned[..]);
283        assert_eq!(codec_id, Ok(CodecId::Assigned(CodingFormat::ALawLog)));
284
285        let vendor_specific = [0xFF, 0x36, 0xFD, 0x11, 0x22];
286        let (codec_id, _) = CodecId::decode(&vendor_specific[..]);
287        assert_eq!(
288            codec_id,
289            Ok(CodecId::VendorSpecific {
290                company_id: (0xFD36 as u16).into(),
291                vendor_specific_codec_id: 0x2211
292            })
293        );
294    }
295}