• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::derive::{Read, Write};
16 use crate::reader::{Read, Reader};
17 use crate::writer::{pack, Write, Writer};
18 
19 /// HCI Command, as defined in Part E - 5.4.1
20 #[derive(Debug)]
21 pub enum Command {
22     /// 7.3.2 Reset Command
23     Reset(Reset),
24     /// 7.8.97 LE Set CIG Parameters
25     LeSetCigParameters(LeSetCigParameters),
26     /// 7.8.99 LE Create CIS
27     LeCreateCis(LeCreateCis),
28     /// 7.8.100 LE Remove CIG
29     LeRemoveCig(LeRemoveCig),
30     /// 7.8.103 LE Create BIG
31     LeCreateBig(LeCreateBig),
32     /// 7.8.109 LE Setup ISO Data Path
33     LeSetupIsoDataPath(LeSetupIsoDataPath),
34     /// 7.8.110 LE Remove ISO Data Path
35     LeRemoveIsoDataPath(LeRemoveIsoDataPath),
36     /// Unknown command
37     Unknown(OpCode),
38 }
39 
40 /// HCI Command Return Parameters
41 #[derive(Debug, Read, Write)]
42 pub enum ReturnParameters {
43     /// 7.3.2 Reset Command
44     Reset(ResetComplete),
45     /// 7.8.2 LE Read Buffer Size [V1]
46     LeReadBufferSizeV1(LeReadBufferSizeV1Complete),
47     /// 7.8.2 LE Read Buffer Size [V2]
48     LeReadBufferSizeV2(LeReadBufferSizeV2Complete),
49     /// 7.8.97 LE Set CIG Parameters
50     LeSetCigParameters(LeSetCigParametersComplete),
51     /// 7.8.100 LE Remove CIG
52     LeRemoveCig(LeRemoveCigComplete),
53     /// 7.8.109 LE Setup ISO Data Path
54     LeSetupIsoDataPath(LeIsoDataPathComplete),
55     /// 7.8.110 LE Remove ISO Data Path
56     LeRemoveIsoDataPath(LeIsoDataPathComplete),
57     /// Unknown command
58     Unknown(OpCode),
59 }
60 
61 impl Command {
62     /// Read an HCI Command packet
from_bytes(data: &[u8]) -> Result<Self, Option<OpCode>>63     pub fn from_bytes(data: &[u8]) -> Result<Self, Option<OpCode>> {
64         fn parse_packet(data: &[u8]) -> Option<(OpCode, Reader)> {
65             let mut r = Reader::new(data);
66             let opcode = r.read()?;
67             let len = r.read_u8()? as usize;
68             Some((opcode, Reader::new(r.get(len)?)))
69         }
70 
71         let Some((opcode, mut r)) = parse_packet(data) else {
72             return Err(None);
73         };
74         Self::dispatch_read(opcode, &mut r).ok_or(Some(opcode))
75     }
76 
dispatch_read(opcode: OpCode, r: &mut Reader) -> Option<Command>77     fn dispatch_read(opcode: OpCode, r: &mut Reader) -> Option<Command> {
78         Some(match opcode {
79             Reset::OPCODE => Self::Reset(r.read()?),
80             LeSetCigParameters::OPCODE => Self::LeSetCigParameters(r.read()?),
81             LeCreateCis::OPCODE => Self::LeCreateCis(r.read()?),
82             LeRemoveCig::OPCODE => Self::LeRemoveCig(r.read()?),
83             LeCreateBig::OPCODE => Self::LeCreateBig(r.read()?),
84             LeSetupIsoDataPath::OPCODE => Self::LeSetupIsoDataPath(r.read()?),
85             LeRemoveIsoDataPath::OPCODE => Self::LeRemoveIsoDataPath(r.read()?),
86             opcode => Self::Unknown(opcode),
87         })
88     }
89 
to_bytes<T: CommandOpCode + Write>(command: &T) -> Vec<u8>90     fn to_bytes<T: CommandOpCode + Write>(command: &T) -> Vec<u8> {
91         let mut w = Writer::new(Vec::with_capacity(3 + 255));
92         w.write(&T::OPCODE);
93         w.write_u8(0);
94         w.write(command);
95 
96         let mut vec = w.into_vec();
97         vec[2] = (vec.len() - 3).try_into().unwrap();
98         vec
99     }
100 }
101 
102 /// OpCode of HCI Command, as defined in Part E - 5.4.1
103 #[derive(Debug, Clone, Copy, PartialEq)]
104 pub struct OpCode(u16);
105 
106 impl OpCode {
107     /// OpCode from OpCode Group Field (OGF) and OpCode Command Field (OCF).
from(ogf: u16, ocf: u16) -> Self108     pub const fn from(ogf: u16, ocf: u16) -> Self {
109         Self(pack!((ocf, 10), (ogf, 6)))
110     }
111 }
112 
113 impl From<u16> for OpCode {
from(v: u16) -> Self114     fn from(v: u16) -> Self {
115         OpCode(v)
116     }
117 }
118 
119 impl Read for OpCode {
read(r: &mut Reader) -> Option<Self>120     fn read(r: &mut Reader) -> Option<Self> {
121         Some(r.read_u16()?.into())
122     }
123 }
124 
125 impl Write for OpCode {
write(&self, w: &mut Writer)126     fn write(&self, w: &mut Writer) {
127         w.write_u16(self.0)
128     }
129 }
130 
131 /// Define command OpCode
132 pub trait CommandOpCode {
133     /// OpCode of the command
134     const OPCODE: OpCode;
135 }
136 
137 /// Build command from definition
138 pub trait CommandToBytes: CommandOpCode + Write {
139     /// Output the HCI Command packet
to_bytes(&self) -> Vec<u8> where Self: Sized + CommandOpCode + Write140     fn to_bytes(&self) -> Vec<u8>
141     where
142         Self: Sized + CommandOpCode + Write;
143 }
144 
145 pub use defs::*;
146 
147 #[allow(missing_docs)]
148 #[rustfmt::skip]
149 mod defs {
150 
151 use super::*;
152 use crate::derive::CommandToBytes;
153 use crate::status::*;
154 
155 #[cfg(test)]
156 use crate::{Event, EventToBytes};
157 
158 
159 // 7.3.2 Reset Command
160 
161 impl CommandOpCode for Reset {
162     const OPCODE: OpCode = OpCode::from(0x03, 0x003);
163 }
164 
165 #[derive(Debug, Read, Write, CommandToBytes)]
166 pub struct Reset {}
167 
168 #[derive(Debug, Read, Write)]
169 pub struct ResetComplete {
170     pub status: Status,
171 }
172 
173 #[test]
test_reset()174 fn test_reset() {
175     let dump = [0x03, 0x0c, 0x00];
176     let Ok(Command::Reset(c)) = Command::from_bytes(&dump) else { panic!() };
177     assert_eq!(c.to_bytes(), &dump[..]);
178 }
179 
180 #[test]
test_reset_complete()181 fn test_reset_complete() {
182     let dump = [0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00];
183     let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
184     let ReturnParameters::Reset(ref p) = e.return_parameters else { panic!() };
185     assert_eq!(p.status, Status::Success);
186     assert_eq!(e.to_bytes(), &dump[..]);
187 }
188 
189 
190 // 7.8.2 LE Read Buffer Size
191 
192 impl CommandOpCode for LeReadBufferSizeV1 {
193     const OPCODE: OpCode = OpCode::from(0x08, 0x002);
194 }
195 
196 #[derive(Debug)]
197 pub struct LeReadBufferSizeV1;
198 
199 #[derive(Debug, Read, Write)]
200 pub struct LeReadBufferSizeV1Complete {
201     pub status: Status,
202     pub le_acl_data_packet_length: u16,
203     pub total_num_le_acl_data_packets: u8,
204 }
205 
206 #[test]
test_le_read_buffer_size_v1_complete()207 fn test_le_read_buffer_size_v1_complete() {
208     let dump = [0x0e, 0x07, 0x01, 0x02, 0x20, 0x00, 0xfb, 0x00, 0x0f];
209     let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
210     let ReturnParameters::LeReadBufferSizeV1(ref p) = e.return_parameters else { panic!() };
211     assert_eq!(p.status, Status::Success);
212     assert_eq!(p.le_acl_data_packet_length, 251);
213     assert_eq!(p.total_num_le_acl_data_packets, 15);
214     assert_eq!(e.to_bytes(), &dump[..]);
215 }
216 
217 impl CommandOpCode for LeReadBufferSizeV2 {
218     const OPCODE: OpCode = OpCode::from(0x08, 0x060);
219 }
220 
221 #[derive(Debug)]
222 pub struct LeReadBufferSizeV2;
223 
224 #[derive(Debug, Read, Write)]
225 pub struct LeReadBufferSizeV2Complete {
226     pub status: Status,
227     pub le_acl_data_packet_length: u16,
228     pub total_num_le_acl_data_packets: u8,
229     pub iso_data_packet_length: u16,
230     pub total_num_iso_data_packets: u8,
231 }
232 
233 #[test]
test_le_read_buffer_size_v2_complete()234 fn test_le_read_buffer_size_v2_complete() {
235     let dump = [0x0e, 0x0a, 0x01, 0x60, 0x20, 0x00, 0xfb, 0x00, 0x0f, 0xfd, 0x03, 0x18];
236     let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
237     let ReturnParameters::LeReadBufferSizeV2(ref p) = e.return_parameters else { panic!() };
238     assert_eq!(p.status, Status::Success);
239     assert_eq!(p.le_acl_data_packet_length, 251);
240     assert_eq!(p.total_num_le_acl_data_packets, 15);
241     assert_eq!(p.iso_data_packet_length, 1021);
242     assert_eq!(p.total_num_iso_data_packets, 24);
243     assert_eq!(e.to_bytes(), &dump[..]);
244 }
245 
246 
247 // 7.8.97 LE Set CIG Parameters
248 
249 impl CommandOpCode for LeSetCigParameters {
250     const OPCODE: OpCode = OpCode::from(0x08, 0x062);
251 }
252 
253 #[derive(Debug, Read, Write, CommandToBytes)]
254 pub struct LeSetCigParameters {
255     pub cig_id: u8,
256     #[N(3)] pub sdu_interval_c_to_p: u32,
257     #[N(3)] pub sdu_interval_p_to_c: u32,
258     pub worst_case_sca: u8,
259     pub packing: u8,
260     pub framing: u8,
261     pub max_transport_latency_c_to_p: u16,
262     pub max_transport_latency_p_to_c: u16,
263     pub cis: Vec<LeCisInCigParameters>,
264 }
265 
266 #[derive(Debug, Read, Write)]
267 pub struct LeCisInCigParameters {
268     pub cis_id: u8,
269     pub max_sdu_c_to_p: u16,
270     pub max_sdu_p_to_c: u16,
271     pub phy_c_to_p: u8,
272     pub phy_p_to_c: u8,
273     pub rtn_c_to_p: u8,
274     pub rtn_p_to_c: u8,
275 }
276 
277 #[test]
test_le_set_cig_parameters()278 fn test_le_set_cig_parameters() {
279     let dump = [
280         0x62, 0x20, 0x21, 0x01, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x64, 0x00, 0x05,
281         0x00, 0x02, 0x00, 0x78, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0d, 0x00, 0x01, 0x78, 0x00, 0x00, 0x00,
282         0x02, 0x03, 0x0d, 0x00
283     ];
284     let Ok(Command::LeSetCigParameters(c)) = Command::from_bytes(&dump) else { panic!() };
285     assert_eq!(c.cig_id, 0x01);
286     assert_eq!(c.sdu_interval_c_to_p, 10_000);
287     assert_eq!(c.sdu_interval_p_to_c, 0);
288     assert_eq!(c.worst_case_sca, 1);
289     assert_eq!(c.packing, 0);
290     assert_eq!(c.framing, 0);
291     assert_eq!(c.max_transport_latency_c_to_p, 100);
292     assert_eq!(c.max_transport_latency_p_to_c, 5);
293     assert_eq!(c.cis.len(), 2);
294     assert_eq!(c.cis[0].cis_id, 0);
295     assert_eq!(c.cis[0].max_sdu_c_to_p, 120);
296     assert_eq!(c.cis[0].max_sdu_p_to_c, 0);
297     assert_eq!(c.cis[0].phy_c_to_p, 0x02);
298     assert_eq!(c.cis[0].phy_p_to_c, 0x03);
299     assert_eq!(c.cis[0].rtn_c_to_p, 13);
300     assert_eq!(c.cis[0].rtn_p_to_c, 0);
301     assert_eq!(c.cis[1].cis_id, 1);
302     assert_eq!(c.cis[1].max_sdu_c_to_p, 120);
303     assert_eq!(c.cis[1].max_sdu_p_to_c, 0);
304     assert_eq!(c.cis[1].phy_c_to_p, 0x02);
305     assert_eq!(c.cis[1].phy_p_to_c, 0x03);
306     assert_eq!(c.cis[1].rtn_c_to_p, 13);
307     assert_eq!(c.cis[1].rtn_p_to_c, 0);
308     assert_eq!(c.to_bytes(), &dump[..]);
309 }
310 
311 #[derive(Debug, Read, Write)]
312 pub struct LeSetCigParametersComplete {
313     pub status: Status,
314     pub cig_id: u8,
315     pub connection_handles: Vec<u16>,
316 }
317 
318 #[test]
test_le_set_cig_parameters_complete()319 fn test_le_set_cig_parameters_complete() {
320     let dump = [0x0e, 0x0a, 0x01, 0x62, 0x20, 0x00, 0x01, 0x02, 0x60, 0x00, 0x61, 0x00];
321     let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
322     let ReturnParameters::LeSetCigParameters(ref p) = e.return_parameters else { panic!() };
323     assert_eq!(p.status, Status::Success);
324     assert_eq!(p.cig_id, 1);
325     assert_eq!(p.connection_handles.len(), 2);
326     assert_eq!(p.connection_handles[0], 0x60);
327     assert_eq!(p.connection_handles[1], 0x61);
328     assert_eq!(e.to_bytes(), &dump[..]);
329 }
330 
331 
332 // 7.8.99 LE Create CIS
333 
334 impl CommandOpCode for LeCreateCis {
335     const OPCODE: OpCode = OpCode::from(0x08, 0x064);
336 }
337 
338 #[derive(Debug, Read, Write, CommandToBytes)]
339 pub struct LeCreateCis {
340     pub connection_handles: Vec<CisAclConnectionHandle>,
341 }
342 
343 #[derive(Debug, Read, Write)]
344 pub struct CisAclConnectionHandle {
345     pub cis: u16,
346     pub acl: u16,
347 }
348 
349 #[test]
test_le_create_cis()350 fn test_le_create_cis () {
351     let dump = [0x64, 0x20, 0x09, 0x02, 0x60, 0x00, 0x40, 0x00, 0x61, 0x00, 0x41, 0x00];
352     let Ok(Command::LeCreateCis(c)) = Command::from_bytes(&dump) else { panic!() };
353     assert_eq!(c.connection_handles.len(), 2);
354     assert_eq!(c.connection_handles[0].cis, 0x60);
355     assert_eq!(c.connection_handles[0].acl, 0x40);
356     assert_eq!(c.connection_handles[1].cis, 0x61);
357     assert_eq!(c.connection_handles[1].acl, 0x41);
358     assert_eq!(c.to_bytes(), &dump[..]);
359 }
360 
361 
362 // 7.8.100 LE Remove CIG
363 
364 impl CommandOpCode for LeRemoveCig {
365     const OPCODE: OpCode = OpCode::from(0x08, 0x065);
366 }
367 
368 #[derive(Debug, Read, Write, CommandToBytes)]
369 pub struct LeRemoveCig {
370     pub cig_id: u8,
371 }
372 
373 #[derive(Debug, Read, Write)]
374 pub struct LeRemoveCigComplete {
375     pub status: Status,
376     pub cig_id: u8,
377 }
378 
379 #[test]
test_le_remove_cig()380 fn test_le_remove_cig() {
381     let dump = [0x65, 0x20, 0x01, 0x01];
382     let Ok(Command::LeRemoveCig(c)) = Command::from_bytes(&dump) else { panic!() };
383     assert_eq!(c.cig_id, 0x01);
384     assert_eq!(c.to_bytes(), &dump[..]);
385 }
386 
387 #[test]
test_le_remove_cig_complete()388 fn test_le_remove_cig_complete() {
389     let dump = [0x0e, 0x05, 0x01, 0x65, 0x20, 0x00, 0x01];
390     let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
391     let ReturnParameters::LeRemoveCig(ref p) = e.return_parameters else { panic!() };
392     assert_eq!(p.status, Status::Success);
393     assert_eq!(p.cig_id, 0x01);
394     assert_eq!(e.to_bytes(), &dump[..]);
395 }
396 
397 
398 // 7.8.103 LE Create BIG
399 
400 impl CommandOpCode for LeCreateBig {
401     const OPCODE: OpCode = OpCode::from(0x08, 0x068);
402 }
403 
404 #[derive(Debug, Read, Write, CommandToBytes)]
405 pub struct LeCreateBig {
406     pub big_handle: u8,
407     pub advertising_handle: u8,
408     pub num_bis: u8,
409     #[N(3)] pub sdu_interval: u32,
410     pub max_sdu: u16,
411     pub max_transport_latency: u16,
412     pub rtn: u8,
413     pub phy: u8,
414     pub packing: u8,
415     pub framing: u8,
416     pub encryption: u8,
417     pub broadcast_code: [u8; 16],
418 }
419 
420 #[test]
test_le_create_big()421 fn test_le_create_big() {
422     let dump = [
423         0x68, 0x20, 0x1f, 0x00, 0x00, 0x02, 0x10, 0x27, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x04, 0x02, 0x00,
424         0x00, 0x01, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32,
425         0x33, 0x34
426     ];
427     let Ok(Command::LeCreateBig(c)) = Command::from_bytes(&dump) else { panic!() };
428     assert_eq!(c.big_handle, 0x00);
429     assert_eq!(c.advertising_handle, 0x00);
430     assert_eq!(c.num_bis, 2);
431     assert_eq!(c.sdu_interval, 10_000);
432     assert_eq!(c.max_sdu, 120);
433     assert_eq!(c.max_transport_latency, 60);
434     assert_eq!(c.rtn, 4);
435     assert_eq!(c.phy, 0x02);
436     assert_eq!(c.packing, 0x00);
437     assert_eq!(c.framing, 0x00);
438     assert_eq!(c.encryption, 1);
439     assert_eq!(c.broadcast_code, [
440         0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
441         0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34
442     ]);
443     assert_eq!(c.to_bytes(), &dump[..]);
444 }
445 
446 
447 // 7.8.109 LE Setup ISO Data Path
448 
449 impl CommandOpCode for LeSetupIsoDataPath {
450     const OPCODE: OpCode = OpCode::from(0x08, 0x06e);
451 }
452 
453 #[derive(Clone, Debug, Read, Write, CommandToBytes)]
454 pub struct LeSetupIsoDataPath {
455     pub connection_handle: u16,
456     pub data_path_direction: LeDataPathDirection,
457     pub data_path_id: u8,
458     pub codec_id: LeCodecId,
459     #[N(3)] pub controller_delay: u32,
460     pub codec_configuration: Vec<u8>,
461 }
462 
463 #[derive(Clone, Debug, PartialEq, Read, Write)]
464 pub enum LeDataPathDirection {
465     Input = 0x00,
466     Output = 0x01,
467 }
468 
469 #[derive(Clone, Debug, Read, Write)]
470 pub struct LeCodecId {
471     pub coding_format: CodingFormat,
472     pub company_id: u16,
473     pub vendor_id: u16,
474 }
475 
476 #[derive(Clone, Debug, PartialEq, Read, Write)]
477 pub enum CodingFormat {
478     ULawLog = 0x00,
479     ALawLog = 0x01,
480     Cvsd = 0x02,
481     Transparent = 0x03,
482     LinearPcm = 0x04,
483     MSbc = 0x05,
484     Lc3 = 0x06,
485     G729A = 0x07,
486     VendorSpecific = 0xff,
487 }
488 
489 #[derive(Debug, Read, Write)]
490 pub struct LeIsoDataPathComplete {
491     pub status: Status,
492     pub connection_handle: u16,
493 }
494 
495 #[test]
test_le_setup_iso_data_path()496 fn test_le_setup_iso_data_path() {
497     let dump = [
498         0x6e, 0x20, 0x0d, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
499     ];
500     let Ok(Command::LeSetupIsoDataPath(c)) = Command::from_bytes(&dump) else { panic!() };
501     assert_eq!(c.connection_handle, 0x60);
502     assert_eq!(c.data_path_direction, LeDataPathDirection::Input);
503     assert_eq!(c.data_path_id, 0x00);
504     assert_eq!(c.codec_id.coding_format, CodingFormat::Transparent);
505     assert_eq!(c.codec_id.company_id, 0);
506     assert_eq!(c.codec_id.vendor_id, 0);
507     assert_eq!(c.controller_delay, 0);
508     assert_eq!(c.codec_configuration.len(), 0);
509     assert_eq!(c.to_bytes(), &dump[..]);
510 }
511 
512 #[test]
test_le_setup_iso_data_path_complete()513 fn test_le_setup_iso_data_path_complete() {
514     let dump = [0x0e, 0x06, 0x01, 0x6e, 0x20, 0x00, 0x60, 0x00];
515     let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
516     let ReturnParameters::LeSetupIsoDataPath(ref p) = e.return_parameters else { panic!() };
517     assert_eq!(p.status, Status::Success);
518     assert_eq!(p.connection_handle, 0x60);
519     assert_eq!(e.to_bytes(), &dump[..]);
520 }
521 
522 
523 // 7.8.110 LE Remove ISO Data Path
524 
525 impl CommandOpCode for LeRemoveIsoDataPath {
526     const OPCODE: OpCode = OpCode::from(0x08, 0x06f);
527 }
528 
529 #[derive(Debug, Read, Write, CommandToBytes)]
530 pub struct LeRemoveIsoDataPath {
531     pub connection_handle: u16,
532     pub data_path_direction: u8,
533 }
534 
535 #[test]
test_le_remove_iso_data_path()536 fn test_le_remove_iso_data_path() {
537     let dump = [0x6f, 0x20, 0x03, 0x60, 0x00, 0x01];
538     let Ok(Command::LeRemoveIsoDataPath(c)) = Command::from_bytes(&dump) else { panic!() };
539     assert_eq!(c.connection_handle, 0x60);
540     assert_eq!(c.data_path_direction, 0x01);
541     assert_eq!(c.to_bytes(), &dump[..]);
542 }
543 
544 }
545