bt_hci/
event.rs

1//! HCI events [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-d21276b6-83d0-cbc3-8295-6ff23b70a0c5)
2
3use crate::cmd::{Opcode, SyncCmd};
4use crate::param::{
5    param, AuthenticationRequirements, BdAddr, ClockOffset, ClockType, ConnHandle, ConnHandleCompletedPackets,
6    ConnectionLinkType, CoreSpecificationVersion, EncryptionEnabledLevel, Error, FlowDirection, IoCapability, KeyFlag,
7    KeypressNotificationType, LinkKeyType, LinkType, LmpFeatureMask, MaxSlots, Mode, OobDataPresent, PacketType,
8    PageScanRepetitionMode, RemainingBytes, Role, ServiceType, Status,
9};
10use crate::{AsHciBytes, FromHciBytes, FromHciBytesError, ReadHci, ReadHciError};
11
12pub mod le;
13
14use le::LeEvent;
15
16/// A trait for objects which contain the parameters for a specific HCI event
17pub trait EventParams<'a>: FromHciBytes<'a> {
18    /// The event code these parameters are for
19    const EVENT_CODE: u8;
20}
21
22param! {
23    /// The header of an HCI event packet.
24    struct EventPacketHeader {
25        code: u8,
26        params_len: u8,
27    }
28}
29
30macro_rules! events {
31    (
32        $(
33            $(#[$attrs:meta])*
34            struct $name:ident$(<$life:lifetime>)?($code:expr) {
35                $(
36                    $(#[$field_attrs:meta])*
37                    $field:ident: $ty:ty
38                ),*
39                $(,)?
40            }
41        )+
42    ) => {
43        /// An Event HCI packet
44        #[non_exhaustive]
45        #[derive(Debug, Clone, Hash)]
46        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
47        pub enum Event<'a> {
48            $(
49                #[allow(missing_docs)]
50                $name($name$(<$life>)?),
51            )+
52            #[allow(missing_docs)]
53            Le(LeEvent<'a>),
54            /// An event with an unknown code value
55            Unknown {
56                /// The event code
57                code: u8,
58                /// The bytes of the event parameters
59                params: &'a [u8]
60            },
61        }
62
63
64        /// An Event kind
65        #[non_exhaustive]
66        #[derive(Debug, Clone, Copy, Hash, PartialEq)]
67        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
68        pub struct EventKind(pub u8);
69
70        #[allow(non_upper_case_globals)]
71        impl EventKind {
72            $(
73                #[allow(missing_docs)]
74                pub const $name: EventKind = EventKind($code);
75            )+
76            #[allow(missing_docs)]
77            pub const Le: EventKind = EventKind(0x3F);
78        }
79
80        /// An Event HCI packet
81        #[derive(Debug, Clone, Hash)]
82        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
83        pub struct EventPacket<'a> {
84            /// Which kind of event.
85            pub kind: EventKind,
86            /// Event data.
87            pub data: &'a [u8],
88        }
89
90        impl<'a> EventPacket<'a> {
91            fn from_header_hci_bytes(header: EventPacketHeader, data: &'a [u8]) -> Result<Self, FromHciBytesError> {
92                let (kind, data) = EventKind::from_header_hci_bytes(header, data)?;
93                Ok(Self {
94                    kind,
95                    data,
96                })
97            }
98        }
99
100        impl EventKind {
101            fn from_header_hci_bytes(header: EventPacketHeader, data: &[u8]) -> Result<(Self, &[u8]), FromHciBytesError> {
102                let (data, _) = if data.len() < usize::from(header.params_len) {
103                    return Err(FromHciBytesError::InvalidSize);
104                } else {
105                    data.split_at(usize::from(header.params_len))
106                };
107
108                match header.code {
109                    $($code => Ok((Self::$name, data)),)+
110                    0x3e => Ok((Self::Le, data)),
111                    _ => {
112                        Ok((EventKind(header.code), data))
113                    }
114                }
115            }
116        }
117
118        impl<'a> TryFrom<EventPacket<'a>> for Event<'a> {
119            type Error = FromHciBytesError;
120            fn try_from(packet: EventPacket<'a>) -> Result<Self, Self::Error> {
121                match packet.kind {
122                    $(EventKind::$name => Ok(Self::$name($name::from_hci_bytes_complete(packet.data)?)),)+
123                    EventKind::Le => {
124                        Ok(Self::Le(LeEvent::from_hci_bytes_complete(packet.data)?))
125                    }
126                    EventKind(code) => Ok(Self::Unknown { code, params: packet.data }),
127                }
128            }
129        }
130
131        impl<'a> Event<'a> {
132            fn from_header_hci_bytes(header: EventPacketHeader, data: &'a [u8]) -> Result<(Self, &'a [u8]), FromHciBytesError> {
133                let (data, rest) = if data.len() < usize::from(header.params_len) {
134                    return Err(FromHciBytesError::InvalidSize);
135                } else {
136                    data.split_at(usize::from(header.params_len))
137                };
138
139                match header.code {
140                    $($code => $name::from_hci_bytes_complete(data).map(|x| (Self::$name(x), rest)),)+
141                    0x3e => LeEvent::from_hci_bytes_complete(data).map(|x| (Self::Le(x), rest)),
142                    _ => {
143                        Ok((Self::Unknown { code: header.code, params: data }, rest))
144                    }
145                }
146            }
147        }
148
149        $(
150            $(#[$attrs])*
151            #[derive(Debug, Clone, Copy, Hash)]
152            #[cfg_attr(feature = "defmt", derive(defmt::Format))]
153            pub struct $name$(<$life>)? {
154                $(
155                    #[doc = stringify!($field)]
156                    $(#[$field_attrs])*
157                    pub $field: $ty,
158                )*
159            }
160
161            #[automatically_derived]
162            impl<'a> $crate::FromHciBytes<'a> for $name$(<$life>)? {
163                #[allow(unused_variables)]
164                fn from_hci_bytes(data: &'a [u8]) -> Result<(Self, &'a [u8]), $crate::FromHciBytesError> {
165                    let total = 0;
166                    $(
167                        let ($field, data) = <$ty as $crate::FromHciBytes>::from_hci_bytes(data)?;
168                    )*
169                    Ok((Self {
170                        $($field,)*
171                    }, data))
172                }
173            }
174
175            #[automatically_derived]
176            impl<'a> $crate::event::EventParams<'a> for $name$(<$life>)? {
177                const EVENT_CODE: u8 = $code;
178            }
179        )+
180    };
181}
182
183events! {
184    // 0x00 - 0x0f
185
186    /// Inquiry Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-cde759f8-6c4d-2dd4-7053-1657125ded74)
187    struct InquiryComplete(0x01) {
188        status: Status,
189    }
190
191    /// Inquiry Result event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-3467df70-1d7a-73c5-5a3e-8689dba5523f)
192    struct InquiryResult<'a>(0x02) {
193        num_responses: u8,
194        /// All remaining bytes for this event (contains all fields for all responses)
195        bytes: RemainingBytes<'a>,
196    }
197
198    /// Connection Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ebb06dd7-356e-605c-cbc1-d06dc00f1d2b)
199    struct ConnectionComplete(0x03) {
200        status: Status,
201        handle: ConnHandle,
202        bd_addr: BdAddr,
203        link_type: ConnectionLinkType,
204        encryption_enabled: bool,
205    }
206
207    /// Connection Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-3115f164-ffcd-9451-09ef-0ed3809889eb)
208    struct ConnectionRequest(0x04) {
209        bd_addr: BdAddr,
210        class_of_device: [u8; 3],
211        link_type: ConnectionLinkType,
212    }
213
214    /// Disconnection Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-332adb1f-b5ac-5289-82a2-c51a59d533e7)
215    struct DisconnectionComplete(0x05) {
216        status: Status,
217        handle: ConnHandle,
218        reason: Status,
219    }
220
221    /// Authentication Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-00ede464-d351-7076-e82a-d8f4b30ee594)
222    struct AuthenticationComplete(0x06) {
223        status: Status,
224        handle: ConnHandle,
225    }
226
227    /// Remote Name Request Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-1e2ccd32-b73f-7f00-f4ff-25b2235aaf02)
228    struct RemoteNameRequestComplete<'a>(0x07) {
229        status: Status,
230        bd_addr: BdAddr,
231        remote_name: RemainingBytes<'a>, // 248 bytes max, null-terminated string
232    }
233
234    /// Encryption Change (v1) event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-7b7d27f0-1a33-ff57-5b97-7d49a04cea26)
235    struct EncryptionChangeV1(0x08) {
236        status: Status,
237        handle: ConnHandle,
238        enabled: EncryptionEnabledLevel,
239    }
240
241    /// Change Connection Link Key Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-8d639c74-ec4f-24e3-4e39-952ce11fba57)
242    struct ChangeConnectionLinkKeyComplete(0x09) {
243        status: Status,
244        handle: ConnHandle,
245    }
246
247    /// Link Key Type Changed event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9eb2cea6-248a-e017-2c09-2797aba08cbf)
248    struct LinkKeyTypeChanged(0x0a) {
249        status: Status,
250        handle: ConnHandle,
251        key_flag: KeyFlag,
252    }
253
254    /// Read Remote Supported Features Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-e191dc19-453a-d0e0-2317-2406ffc4d512)
255    struct ReadRemoteSupportedFeaturesComplete(0x0b) {
256        status: Status,
257        handle: ConnHandle,
258        lmp_features: LmpFeatureMask,
259    }
260
261    /// Read Remote Version Information Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-81ed98a1-98b1-dae5-a3f5-bb7bc69d39b7)
262    struct ReadRemoteVersionInformationComplete(0x0c) {
263        status: Status,
264        handle: ConnHandle,
265        version: CoreSpecificationVersion,
266        company_id: u16,
267        subversion: u16,
268    }
269
270    /// QoS Setup Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-a4ff46db-e472-dbd3-eaa6-810300dcd1b6)
271    struct QosSetupComplete(0x0d) {
272        status: Status,
273        handle: ConnHandle,
274        unused: u8, // Always 0
275        service_type: ServiceType,
276        token_rate: u32,
277        peak_bandwidth: u32,
278        latency: u32,
279        delay_variation: u32,
280    }
281
282    /// Command Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-76d31a33-1a9e-07bc-87c4-8ebffee065fd)
283    struct CommandComplete<'a>(0x0e) {
284        num_hci_cmd_pkts: u8,
285        cmd_opcode: Opcode,
286        bytes: RemainingBytes<'a>,
287    }
288
289    /// Command Status event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-4d87067c-be74-d2ff-d5c4-86416bf7af91)
290    struct CommandStatus(0x0f) {
291        status: Status,
292        num_hci_cmd_pkts: u8,
293        cmd_opcode: Opcode,
294    }
295
296    // 0x10 - 0x1f
297
298    /// Hardware Error event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-2479a101-ae3b-5b5d-f3d4-4776af39a377)
299    struct HardwareError(0x10) {
300        hardware_code: u8,
301    }
302
303    /// Flush Occurred event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-26be4e2f-f6c3-eb68-ebf4-d11255eb9ec6)
304    struct FlushOccurred(0x11) {
305        handle: ConnHandle,
306    }
307
308    /// Role Change event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ed33ee5b-970f-9664-0c15-3db2b884961a)
309    struct RoleChange(0x12) {
310        status: Status,
311        bd_addr: BdAddr,
312        new_role: Role,
313    }
314
315    /// Number Of Completed Packets event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9ccbff85-45ce-9c0d-6d0c-2e6e5af52b0e)
316    struct NumberOfCompletedPackets<'a>(0x13) {
317        completed_packets: &'a [ConnHandleCompletedPackets],
318    }
319
320    /// Mode Change event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-b277da2e-804e-d956-9395-37eabc7e7b41)
321    struct ModeChange(0x14) {
322        status: Status,
323        handle: ConnHandle,
324        mode: Mode,
325        interval: u16,
326    }
327
328    /// Return Link Keys event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-e0d451f2-4b53-cdf0-efb5-926e08b27cd2)
329    struct ReturnLinkKeys<'a>(0x15) {
330        num_keys: u8,
331        bytes: RemainingBytes<'a>, // bd_addr: Num_Keys × 6 octets, link_key: Num_Keys × 16 octets, always zero
332    }
333
334    /// PIN Code Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-7666987c-9040-9aaa-cad6-96941b46d2b5)
335    struct PinCodeRequest(0x16) {
336        bd_addr: BdAddr,
337    }
338
339    /// Link Key Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-58400663-f69d-a482-13af-ec558a3f4c03)
340    struct LinkKeyRequest(0x17) {
341        bd_addr: BdAddr,
342    }
343
344    /// Link Key Notification event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ef6b7301-ab4b-cce6-1fa4-c053c3cd1585)
345    struct LinkKeyNotification(0x18) {
346        bd_addr: BdAddr,
347        link_key: [u8; 16],
348        key_type: LinkKeyType,
349    }
350
351    /// Loopback Command event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-5f4e8f2c-7b9a-1c8e-8f6d-2e7a4b9c5f8e)
352    struct LoopbackCommand<'a>(0x19) {
353        command_packet: RemainingBytes<'a>,
354    }
355
356    /// Data Buffer Overflow event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-e15e12c7-d29a-8c25-349f-af6206c2ae57)
357    struct DataBufferOverflow(0x1a) {
358        link_type: LinkType,
359    }
360
361    /// Max Slots Change event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-1561feb4-2f2e-4ec1-1db7-57ec1dc436e2)
362    struct MaxSlotsChange(0x1b) {
363        handle: ConnHandle,
364        lmp_max_slots: MaxSlots,
365    }
366
367    /// Read Clock Offset Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-3ab4cf46-7f13-7901-4abb-af026ebee703)
368    struct ReadClockOffsetComplete(0x1c) {
369        status: Status,
370        handle: ConnHandle,
371        clock_offset: ClockOffset,
372    }
373
374    /// Connection Packet Type Changed event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-864f38f0-afde-bd09-09ff-c5bb5fefca62)
375    struct ConnectionPacketTypeChanged(0x1d) {
376        status: Status,
377        handle: ConnHandle,
378        packet_type: PacketType,
379    }
380
381    /// QoS Violation event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-cc019a24-4654-aa9f-dcd3-2a286e7cdd55)
382    struct QosViolation(0x1e) {
383        handle: ConnHandle,
384    }
385
386    // 0x20 - 0x2f
387
388    /// Page Scan Repetition Mode Change event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-a535391f-0ecf-ff2d-dfad-1e61b021c0d6)
389    struct PageScanRepetitionModeChange(0x20) {
390        bd_addr: BdAddr,
391        page_scan_repetition_mode: PageScanRepetitionMode,
392    }
393
394    /// Flow Specification Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-65dffc5b-4c38-ce5c-a618-0d7a3e145012)
395    struct FlowSpecificationComplete(0x21) {
396        status: Status,
397        handle: ConnHandle,
398        unused: u8, // Always 0
399        flow_direction: FlowDirection,
400        service_type: ServiceType,
401        token_rate: u32,
402        token_bucket_size: u32,
403        peak_bandwidth: u32,
404        access_latency: u32,
405    }
406
407    /// Inquiry Result with RSSI event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-c2550565-1c65-a514-6cf0-3d55c8943dab)
408    struct InquiryResultWithRssi<'a>(0x22) {
409        num_responses: u8,
410        /// All remaining bytes for this event (contains all fields for all responses)
411        bytes: RemainingBytes<'a>,
412    }
413
414    /// Read Remote Extended Features Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-6a78850c-d310-761a-74cb-abe8b2ddddd8)
415    struct ReadRemoteExtendedFeaturesComplete(0x23) {
416        status: Status,
417        handle: ConnHandle,
418        page_number: u8,
419        maximum_page_number: u8,
420        extended_lmp_features: LmpFeatureMask,
421    }
422
423    /// Synchronous Connection Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-a625aef5-c3d7-12e9-39e4-b8f3386150bb)
424    struct SynchronousConnectionComplete(0x2c) {
425        status: Status,
426        handle: ConnHandle,
427        bd_addr: BdAddr,
428        link_type: ConnectionLinkType,
429        transmission_interval: u8,
430        retransmission_window: u8,
431        rx_packet_length: u16,
432        tx_packet_length: u16,
433        air_mode: u8,
434    }
435
436    /// Synchronous Connection Changed event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-5774f3c9-81e9-24e6-86a6-6f6935ee8998)
437    struct SynchronousConnectionChanged(0x2d) {
438        status: Status,
439        handle: ConnHandle,
440        transmission_interval: u8,
441        retransmission_window: u8,
442        rx_packet_length: u16,
443        tx_packet_length: u16,
444    }
445
446
447    /// Sniff Subrating event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-4c17aedf-cddf-0844-39cc-3dcfddd34ec0)
448    struct SniffSubrating(0x2e) {
449        status: Status,
450        handle: ConnHandle,
451        max_tx_latency: u16,
452        max_rx_latency: u16,
453        min_remote_timeout: u16,
454        min_local_timeout: u16,
455    }
456
457    /// Extended Inquiry Result event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-e3e8c7bc-2262-14f4-b6f5-2eeb0b25aa4f)
458    struct ExtendedInquiryResult<'a>(0x2f) {
459        num_responses: u8,
460        bd_addr: BdAddr,
461        page_scan_repetition_mode: PageScanRepetitionMode,
462        reserved: u8,
463        class_of_device: [u8; 3],
464        clock_offset: ClockOffset,
465        rssi: i8,
466        eir_data: RemainingBytes<'a>,
467    }
468
469    // 0x30 - 0x3f
470
471    /// Encryption Key Refresh Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-a321123c-83a5-7baf-6971-05edd1241357)
472    struct EncryptionKeyRefreshComplete(0x30) {
473        status: Status,
474        handle: ConnHandle,
475    }
476
477    /// IO Capability Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-343681e1-ca08-8d4c-79c3-e4b2c86ecba1)
478    struct IoCapabilityRequest(0x31) {
479        bd_addr: BdAddr,
480    }
481
482    /// IO Capability Response event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-7f2cf1ee-49ba-de05-5f26-f54925363197)
483    struct IoCapabilityResponse(0x32) {
484        bd_addr: BdAddr,
485        io_capability: IoCapability,
486        oob_data_present: OobDataPresent,
487        authentication_requirements: AuthenticationRequirements,
488    }
489
490    /// User Confirmation Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-e7014a9e-718f-6aa8-d657-35b547e9c5d6)
491    struct UserConfirmationRequest(0x33) {
492        bd_addr: BdAddr,
493        numeric_value: u32,
494    }
495
496    /// User Passkey Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-2f7a60c5-e17f-28f2-699c-e5943e488ec9)
497    struct UserPasskeyRequest(0x34) {
498        bd_addr: BdAddr,
499    }
500
501    /// Remote OOB Data Request event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-c5c5d906-fdde-b062-2bc6-6f5b5de25066)
502    struct RemoteOobDataRequest(0x35) {
503        bd_addr: BdAddr,
504    }
505
506    /// Simple Pairing Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-e07a2674-e7bf-c963-0a41-9a997c940d26)
507    struct SimplePairingComplete(0x36) {
508        status: Status,
509        bd_addr: BdAddr,
510    }
511
512    /// Link Supervision Timeout Changed event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-4d4758a0-eab4-25b8-f05e-2bbdcc6384cc)
513    struct LinkSupervisionTimeoutChanged(0x38) {
514        handle: ConnHandle,
515        link_supervision_timeout: u16,
516    }
517
518    /// Enhanced Flush Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-0102cc4f-0f30-c3cb-fd0a-f70ac2d5ed08)
519    struct EnhancedFlushComplete(0x39) {
520        handle: ConnHandle,
521    }
522
523    /// User Passkey Notification event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-39f61a47-537a-e0d9-4aa4-ccab280ebc99)
524    struct UserPasskeyNotification(0x3b) {
525        bd_addr: BdAddr,
526        passkey: u32,
527    }
528
529    /// Keypress Notification event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-a96ae6b4-2259-c16d-0098-34a5e551284e)
530    struct KeypressNotification(0x3c) {
531        bd_addr: BdAddr,
532        notification_type: KeypressNotificationType,
533    }
534
535    /// Remote Host Supported Features Notification event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ba740ba0-44d8-d028-0a67-1abab648f6dd)
536    struct RemoteHostSupportedFeaturesNotification(0x3d) {
537        bd_addr: BdAddr,
538        features: LmpFeatureMask,
539    }
540
541    // 0x40 - 0x4f
542
543    /// Number Of Completed Data Blocks event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-f8e9efbb-ad3e-9f37-ee61-02a17eb0ba48)
544    struct NumberOfCompletedDataBlocks<'a>(0x48) {
545        total_num_data_blocks: u16,
546        num_of_handles: u8,
547        bytes: RemainingBytes<'a>, // Contains handle + num_completed_packets + num_completed_blocks for each handle
548    }
549
550    /// Triggered Clock Capture event  [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-0f10aa12-6d70-245a-84d9-342508615b28)
551    struct TriggeredClockCapture(0x4e) {
552        handle: ConnHandle,
553        which_clock: ClockType,
554        clock: u32,
555        slot_offset: u16,
556    }
557
558    /// Synchronization Train Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-57849409-0331-57bf-7c23-ed4a14d4ac3d)
559    struct SynchronizationTrainComplete(0x4f) {
560        status: Status,
561    }
562
563    // 0x50 - 0x5f
564
565    /// Synchronization Train Received event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-38436ae8-4bf0-c6cf-9b64-a6d17fac279f)
566    struct SynchronizationTrainReceived(0x50) {
567        status: Status,
568        bd_addr: BdAddr,
569        clock_offset: u32,
570        afh_channel_map: [u8; 10],
571        lt_addr: u8,
572        next_broadcast_instant: u32,
573        connectionless_peripheral_broadcast_interval: u16,
574        service_data: u8,
575    }
576
577    /// Connectionless Peripheral Broadcast Receive event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-3ea779f7-980c-f253-7845-2e9df03eaf3d)
578    struct ConnectionlessPeripheralBroadcastReceive<'a>(0x51) {
579        bd_addr: BdAddr,
580        lt_addr: u8,
581        clock: u32,
582        offset: u32,
583        rx_status: u8,
584        fragment: u8,
585        data_length: u8,
586        data: RemainingBytes<'a>,
587    }
588
589    /// Connectionless Peripheral Broadcast Timeout event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-783a9fcb-1c5c-fcb2-2169-445c9cac9f91)
590    struct ConnectionlessPeripheralBroadcastTimeout(0x52) {
591        bd_addr: BdAddr,
592        lt_addr: u8,
593    }
594
595    /// Truncated Page Complete event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-99bf982f-4155-cdc5-eef4-3a198afd5d09)
596    struct TruncatedPageComplete(0x53) {
597        status: Status,
598        bd_addr: BdAddr,
599    }
600
601    /// Peripheral Page Response Timeout event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-928cc95f-6680-8ee0-b48b-31e97ff7ec4e)
602    struct PeripheralPageResponseTimeout(0x54) {
603    }
604
605    /// Connectionless Peripheral Broadcast Channel Map Change event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-2d2c3fab-5387-79bf-03bf-6a3e3ad410a5)
606    struct ConnectionlessPeripheralBroadcastChannelMapChange(0x55) {
607        channel_map: [u8; 10],
608    }
609
610    /// Inquiry Response Notification event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-4d5e8f2c-7b9a-3c8e-8f6d-2e7a4b9c5f8e)
611    struct InquiryResponseNotification(0x56) {
612        lap: [u8; 3],
613        rssi: i8,
614    }
615
616    /// Authenticated Payload Timeout Expired event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-6cfdff94-ace8-294c-6af9-d90d94653e19)
617    struct AuthenticatedPayloadTimeoutExpired(0x57) {
618        handle: ConnHandle,
619    }
620
621    /// SAM Status Change event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-57dba68a-5205-8c2e-1e2a-9c4d858eb93b)
622    struct SamStatusChange(0x58) {
623        handle: ConnHandle,
624        local_sam_index: u8,
625        local_sam_tx_availability: u8,
626        local_sam_rx_availability: u8,
627        remote_sam_index: u8,
628        remote_sam_tx_availability: u8,
629        remote_sam_rx_availability: u8,
630    }
631
632    /// Encryption Change (v2) event [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-7b7d27f0-1a33-ff57-5b97-7d49a04cea26)
633    struct EncryptionChangeV2(0x59) {
634        status: Status,
635        handle: ConnHandle,
636        encryption_enabled: EncryptionEnabledLevel,
637        encryption_key_size: u8,
638    }
639
640    // 0xf0 - 0xff
641
642    /// HCI Event packet [📖](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-f209cdf7-0496-8bcd-b7e1-500831511378)
643    struct Vendor<'a>(0xff) {
644        params: RemainingBytes<'a>,
645    }
646}
647
648impl<'de> FromHciBytes<'de> for Event<'de> {
649    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
650        let (header, data) = EventPacketHeader::from_hci_bytes(data)?;
651        Self::from_header_hci_bytes(header, data)
652    }
653}
654
655impl<'de> FromHciBytes<'de> for EventPacket<'de> {
656    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
657        let (header, data) = EventPacketHeader::from_hci_bytes(data)?;
658        let pkt = Self::from_header_hci_bytes(header, data)?;
659        Ok((pkt, &[]))
660    }
661}
662
663impl<'de> ReadHci<'de> for EventPacket<'de> {
664    const MAX_LEN: usize = 257;
665
666    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
667        let mut header = [0; 2];
668        reader.read_exact(&mut header)?;
669        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
670        let params_len = usize::from(header.params_len);
671        if buf.len() < params_len {
672            Err(ReadHciError::BufferTooSmall)
673        } else {
674            let (buf, _) = buf.split_at_mut(params_len);
675            reader.read_exact(buf)?;
676            let pkt = Self::from_header_hci_bytes(header, buf)?;
677            Ok(pkt)
678        }
679    }
680
681    async fn read_hci_async<R: embedded_io_async::Read>(
682        mut reader: R,
683        buf: &'de mut [u8],
684    ) -> Result<Self, ReadHciError<R::Error>> {
685        let mut header = [0; 2];
686        reader.read_exact(&mut header).await?;
687        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
688        let params_len = usize::from(header.params_len);
689        if buf.len() < params_len {
690            Err(ReadHciError::BufferTooSmall)
691        } else {
692            let (buf, _) = buf.split_at_mut(params_len);
693            reader.read_exact(buf).await?;
694            let pkt = Self::from_header_hci_bytes(header, buf)?;
695            Ok(pkt)
696        }
697    }
698}
699
700impl<'de> ReadHci<'de> for Event<'de> {
701    const MAX_LEN: usize = 257;
702
703    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
704        let mut header = [0; 2];
705        reader.read_exact(&mut header)?;
706        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
707        let params_len = usize::from(header.params_len);
708        if buf.len() < params_len {
709            Err(ReadHciError::BufferTooSmall)
710        } else {
711            let (buf, _) = buf.split_at_mut(params_len);
712            reader.read_exact(buf)?;
713            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
714            Ok(pkt)
715        }
716    }
717
718    async fn read_hci_async<R: embedded_io_async::Read>(
719        mut reader: R,
720        buf: &'de mut [u8],
721    ) -> Result<Self, ReadHciError<R::Error>> {
722        let mut header = [0; 2];
723        reader.read_exact(&mut header).await?;
724        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
725        let params_len = usize::from(header.params_len);
726        if buf.len() < params_len {
727            Err(ReadHciError::BufferTooSmall)
728        } else {
729            let (buf, _) = buf.split_at_mut(params_len);
730            reader.read_exact(buf).await?;
731            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
732            Ok(pkt)
733        }
734    }
735}
736
737impl CommandComplete<'_> {
738    /// Whether or not this event has a status
739    pub fn has_status(&self) -> bool {
740        self.cmd_opcode != Opcode::UNSOLICITED
741    }
742}
743
744impl<'d> TryFrom<CommandComplete<'d>> for CommandCompleteWithStatus<'d> {
745    type Error = FromHciBytesError;
746    fn try_from(e: CommandComplete<'d>) -> Result<CommandCompleteWithStatus<'d>, Self::Error> {
747        if e.cmd_opcode == Opcode::UNSOLICITED {
748            return Err(FromHciBytesError::InvalidSize);
749        }
750        let bytes = e.bytes.into_inner();
751        let (status, remaining) = Status::from_hci_bytes(bytes)?;
752        let return_param_bytes: RemainingBytes<'d> = RemainingBytes::from_hci_bytes_complete(remaining)?;
753        Ok(Self {
754            num_hci_cmd_pkts: e.num_hci_cmd_pkts,
755            cmd_opcode: e.cmd_opcode,
756            status,
757            return_param_bytes,
758        })
759    }
760}
761
762/// Struct representing a command complete event with status
763#[derive(Debug, Clone, PartialEq, Eq)]
764pub struct CommandCompleteWithStatus<'d> {
765    /// Number of packets complete.
766    pub num_hci_cmd_pkts: u8,
767    /// Command opcode.
768    pub cmd_opcode: Opcode,
769    /// Command status.
770    pub status: Status,
771    /// Return parameters
772    pub return_param_bytes: RemainingBytes<'d>,
773}
774
775impl CommandCompleteWithStatus<'_> {
776    /// Gets the connection handle associated with the command that has completed.
777    ///
778    /// For commands that return the connection handle provided as a parameter as
779    /// their first return parameter, this will be valid even if `status` is an error.
780    pub fn handle<C: SyncCmd>(&self) -> Result<C::Handle, FromHciBytesError> {
781        C::return_handle(&self.return_param_bytes)
782    }
783
784    /// Gets a result with the return parameters for `C` or an `Error` if `status` is
785    /// an error.
786    ///
787    /// # Panics
788    ///
789    /// May panic if `C::OPCODE` is not equal to `self.cmd_opcode`.
790    pub fn to_result<C: SyncCmd>(&self) -> Result<C::Return, Error> {
791        self.status
792            .to_result()
793            .and_then(|_| self.return_params::<C>().or(Err(Error::INVALID_HCI_PARAMETERS)))
794    }
795
796    /// Parses the return parameters for `C` from this event. This may fail if `status`
797    /// is an error.
798    ///
799    /// # Panics
800    ///
801    /// May panic if `C::OPCODE` is not equal to `self.cmd_opcode`.
802    pub fn return_params<C: SyncCmd>(&self) -> Result<C::Return, FromHciBytesError> {
803        assert_eq!(self.cmd_opcode, C::OPCODE);
804        C::Return::from_hci_bytes(&self.return_param_bytes).and_then(|(params, rest)| {
805            if rest.is_empty() {
806                Ok(params)
807            } else {
808                Err(FromHciBytesError::InvalidSize)
809            }
810        })
811    }
812}
813
814/// Struct representing a single parsed inquiry result item
815#[derive(Debug, Clone, PartialEq, Eq)]
816pub struct InquiryResultItem {
817    /// Bluetooth Device Address (BD_ADDR) of the device found
818    pub bd_addr: BdAddr,
819    /// Page scan repetition mode of the device
820    pub page_scan_repetition_mode: Option<PageScanRepetitionMode>,
821    /// Class of device (CoD) of the device found
822    pub class_of_device: Option<[u8; 3]>,
823    /// Clock offset of the device found
824    pub clock_offset: Option<ClockOffset>,
825    /// Received Signal Strength Indicator (RSSI) of the device found
826    /// This field is only present in `InquiryResultWithRssi`
827    pub rssi: Option<i8>,
828}
829
830/// Iterator over inquiry result items
831pub struct InquiryResultIter<'a> {
832    bytes: &'a [u8],
833    num_responses: usize,
834    idx: usize,
835    kind: InquiryResultKind,
836}
837
838/// Kind of inquiry result, indicating whether it includes RSSI or not
839#[derive(Copy, Clone, Debug, PartialEq, Eq)]
840pub enum InquiryResultKind {
841    /// Standard inquiry result without RSSI
842    Standard,
843    /// Inquiry result with RSSI
844    WithRssi,
845}
846
847impl<'a> InquiryResultIter<'a> {
848    /// Creates a new iterator for standard inquiry results
849    pub fn new_standard(bytes: &'a [u8], num_responses: usize) -> Self {
850        InquiryResultIter {
851            bytes,
852            num_responses,
853            idx: 0,
854            kind: InquiryResultKind::Standard,
855        }
856    }
857
858    /// Creates a new iterator for inquiry results with RSSI
859    pub fn new_with_rssi(bytes: &'a [u8], num_responses: usize) -> Self {
860        InquiryResultIter {
861            bytes,
862            num_responses,
863            idx: 0,
864            kind: InquiryResultKind::WithRssi,
865        }
866    }
867}
868
869impl Iterator for InquiryResultIter<'_> {
870    type Item = InquiryResultItem;
871    fn next(&mut self) -> Option<Self::Item> {
872        if self.idx >= self.num_responses {
873            return None;
874        }
875
876        let i = self.idx;
877        let n = self.num_responses;
878
879        let bd_addr_size = n * 6;
880        let page_scan_size = n;
881        let class_size = n * 3;
882        let clock_size = n * 2;
883
884        let reserved_size = match self.kind {
885            InquiryResultKind::Standard => n * 2,
886            InquiryResultKind::WithRssi => n,
887        };
888
889        let bd_addr_off = i * 6;
890        let page_scan_off = bd_addr_size + i;
891        let class_off = bd_addr_size + page_scan_size + reserved_size + i * 3;
892        let clock_off = bd_addr_size + page_scan_size + reserved_size + class_size + i * 2;
893
894        if self.bytes.len() < bd_addr_off + 6 {
895            return None;
896        }
897
898        let bd_addr = BdAddr::new([
899            self.bytes[bd_addr_off],
900            self.bytes[bd_addr_off + 1],
901            self.bytes[bd_addr_off + 2],
902            self.bytes[bd_addr_off + 3],
903            self.bytes[bd_addr_off + 4],
904            self.bytes[bd_addr_off + 5],
905        ]);
906
907        let page_scan_repetition_mode = self
908            .bytes
909            .get(page_scan_off)
910            .and_then(|b| PageScanRepetitionMode::from_hci_bytes(&[*b]).ok().map(|(m, _)| m));
911
912        let class_of_device = self.bytes.get(class_off..class_off + 3).map(|s| [s[0], s[1], s[2]]);
913
914        let clock_offset = self
915            .bytes
916            .get(clock_off..clock_off + 2)
917            .and_then(|s| ClockOffset::from_hci_bytes(s).ok().map(|(c, _)| c));
918
919        let rssi = if self.kind == InquiryResultKind::WithRssi {
920            let rssi_off = bd_addr_size + page_scan_size + reserved_size + class_size + clock_size + i;
921            self.bytes.get(rssi_off).map(|b| *b as i8)
922        } else {
923            None
924        };
925
926        self.idx += 1;
927
928        Some(InquiryResultItem {
929            bd_addr,
930            page_scan_repetition_mode,
931            class_of_device,
932            clock_offset,
933            rssi,
934        })
935    }
936}
937
938/// Inquiry result event containing multiple responses
939impl InquiryResult<'_> {
940    /// Returns an iterator over all valid inquiry result items.
941    pub fn iter(&self) -> InquiryResultIter<'_> {
942        let bytes = self.bytes.as_hci_bytes();
943        let n = self.num_responses as usize;
944        InquiryResultIter::new_standard(bytes, n)
945    }
946}
947
948/// Inquiry result event containing multiple responses with RSSI
949impl InquiryResultWithRssi<'_> {
950    /// Returns an iterator over all valid inquiry result items.
951    pub fn iter(&self) -> InquiryResultIter<'_> {
952        let bytes = self.bytes.as_hci_bytes();
953        let n = self.num_responses as usize;
954        InquiryResultIter::new_with_rssi(bytes, n)
955    }
956}
957
958#[cfg(test)]
959mod tests {
960    use super::*;
961    use crate::cmd::OpcodeGroup;
962    use crate::event::le::LeEventPacket;
963    use crate::param::*;
964
965    #[test]
966    fn test_inquiry_result() {
967        let data = [
968            0x02, // num_responses = 2
969            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // addr 1
970            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // addr 2
971            0x01, 0x02, // R1, R2
972            0x00, 0x00, 0x00, 0x00, // reserved
973            0x20, 0x04, 0x00, 0x30, 0x05, 0x01, // class of device
974            0x34, 0x12, 0x78, 0x56, // clock offsets
975        ];
976        let (inquiry_result, _) = InquiryResult::from_hci_bytes(&data).unwrap();
977
978        let mut iter = inquiry_result.iter();
979
980        let item1 = iter.next().unwrap();
981        assert_eq!(item1.bd_addr.as_hci_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
982        assert_eq!(item1.page_scan_repetition_mode, Some(PageScanRepetitionMode::R1));
983        assert_eq!(item1.class_of_device, Some([0x20, 0x04, 0x00]));
984        assert_eq!(item1.clock_offset.unwrap().as_hci_bytes(), &[0x34, 0x12]);
985        assert_eq!(item1.rssi, None);
986
987        let item2 = iter.next().unwrap();
988        assert_eq!(item2.bd_addr.as_hci_bytes(), &[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
989        assert_eq!(item2.page_scan_repetition_mode, Some(PageScanRepetitionMode::R2));
990        assert_eq!(item2.class_of_device, Some([0x30, 0x05, 0x01]));
991        assert_eq!(item2.clock_offset.unwrap().as_hci_bytes(), &[0x78, 0x56]);
992        assert_eq!(item2.rssi, None);
993        assert!(iter.next().is_none());
994    }
995
996    #[test]
997    fn test_inquiry_result_with_rssi() {
998        let data = [
999            0x02, // num_responses = 2
1000            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // addr 1
1001            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // addr 2
1002            0x01, 0x02, // R1, R2
1003            0x00, 0x00, // reserved
1004            0x20, 0x04, 0x00, 0x30, 0x05, 0x01, // class of device
1005            0x34, 0x12, 0x78, 0x56, // clock offsets
1006            0xF0, 0xE8, // RSSI
1007        ];
1008        let (inquiry_result, _) = InquiryResultWithRssi::from_hci_bytes(&data).unwrap();
1009
1010        let mut iter = inquiry_result.iter();
1011
1012        let item1 = iter.next().unwrap();
1013        assert_eq!(item1.bd_addr.as_hci_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
1014        assert_eq!(item1.page_scan_repetition_mode, Some(PageScanRepetitionMode::R1));
1015        assert_eq!(item1.class_of_device, Some([0x20, 0x04, 0x00]));
1016        assert_eq!(item1.clock_offset.unwrap().as_hci_bytes(), &[0x34, 0x12]);
1017        assert_eq!(item1.rssi, Some(-16));
1018
1019        let item2 = iter.next().unwrap();
1020        assert_eq!(item2.bd_addr.as_hci_bytes(), &[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
1021        assert_eq!(item2.page_scan_repetition_mode, Some(PageScanRepetitionMode::R2));
1022        assert_eq!(item2.class_of_device, Some([0x30, 0x05, 0x01]));
1023        assert_eq!(item2.clock_offset.unwrap().as_hci_bytes(), &[0x78, 0x56]);
1024        assert_eq!(item2.rssi, Some(-24));
1025        assert!(iter.next().is_none());
1026    }
1027
1028    #[test]
1029    fn test_extended_inquiry_result() {
1030        let data = [
1031            0x01, // num_responses = 1
1032            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1033            0x01, // page_scan_repetition_mode (R1)
1034            0x00, // reserved
1035            0x20, 0x04, 0x00, // class_of_device
1036            0x34, 0x12, // clock_offset
1037            0xF0, // rssi (-16)
1038            0x09, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x65, 0x76, // eir_data (sample EIR data)
1039        ];
1040        let (eir_result, _) = ExtendedInquiryResult::from_hci_bytes(&data).unwrap();
1041
1042        assert_eq!(eir_result.num_responses, 1);
1043        assert_eq!(eir_result.bd_addr.as_hci_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
1044        assert_eq!(eir_result.page_scan_repetition_mode, PageScanRepetitionMode::R1);
1045        assert_eq!(eir_result.reserved, 0x00);
1046        assert_eq!(eir_result.class_of_device, [0x20, 0x04, 0x00]);
1047        assert_eq!(eir_result.clock_offset.as_hci_bytes(), &[0x34, 0x12]);
1048        assert_eq!(eir_result.rssi, -16);
1049        assert_eq!(
1050            eir_result.eir_data.as_hci_bytes(),
1051            &[0x09, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x65, 0x76]
1052        );
1053    }
1054
1055    #[test]
1056    fn test_io_capability_request() {
1057        let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1058        let (evt, rest) = IoCapabilityRequest::from_hci_bytes(&data).unwrap();
1059        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1060        assert!(rest.is_empty());
1061    }
1062
1063    #[test]
1064    fn test_user_confirmation_request() {
1065        let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x78, 0x56, 0x34, 0x12];
1066        let (evt, rest) = UserConfirmationRequest::from_hci_bytes(&data).unwrap();
1067        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1068        assert_eq!(evt.numeric_value, 0x1234_5678);
1069        assert!(rest.is_empty());
1070    }
1071
1072    #[test]
1073    fn test_connection_request() {
1074        let data = [
1075            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1076            0x20, 0x04, 0x00, // class_of_device
1077            0x01, // link_type (ACL)
1078        ];
1079        let (evt, rest) = ConnectionRequest::from_hci_bytes(&data).unwrap();
1080        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1081        assert_eq!(evt.class_of_device, [0x20, 0x04, 0x00]);
1082        assert_eq!(evt.link_type, ConnectionLinkType::Acl);
1083        assert!(rest.is_empty());
1084    }
1085
1086    #[test]
1087    fn test_role_change() {
1088        let data = [
1089            0x00, // status (success)
1090            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1091            0x00, // new_role (Central)
1092        ];
1093        let (evt, rest) = RoleChange::from_hci_bytes(&data).unwrap();
1094        assert_eq!(evt.status, Status::SUCCESS);
1095        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1096        assert_eq!(evt.new_role, Role::Central);
1097        assert!(rest.is_empty());
1098    }
1099
1100    #[test]
1101    fn test_simple_pairing_complete() {
1102        let data = [
1103            0x00, // status (success)
1104            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1105        ];
1106        let (evt, rest) = SimplePairingComplete::from_hci_bytes(&data).unwrap();
1107        assert_eq!(evt.status, Status::SUCCESS);
1108        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1109        assert!(rest.is_empty());
1110    }
1111
1112    #[test]
1113    fn test_io_capability_response() {
1114        let data = [
1115            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1116            0x01, // io_capability (DisplayYesNo)
1117            0x00, // oob_data_present (not present)
1118            0x03, // authentication_requirements (MITM Protection Required - General Bonding)
1119        ];
1120        let (evt, rest) = IoCapabilityResponse::from_hci_bytes(&data).unwrap();
1121        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1122        assert_eq!(evt.io_capability, IoCapability::DisplayYesNo);
1123        assert_eq!(evt.oob_data_present, OobDataPresent::NotPresent);
1124        assert_eq!(
1125            evt.authentication_requirements,
1126            AuthenticationRequirements::MitmRequiredDedicatedBonding
1127        );
1128        assert!(rest.is_empty());
1129    }
1130
1131    #[test]
1132    fn test_number_of_completed_data_blocks() {
1133        let data = [
1134            0x00, 0x10, // total_num_data_blocks = 4096
1135            0x02, // num_of_handles = 2
1136            0x01, 0x00, // handle 1
1137            0x02, 0x00, // num_completed_packets for handle 1
1138            0x04, 0x00, // num_completed_blocks for handle 1
1139            0x02, 0x00, // handle 2
1140            0x01, 0x00, // num_completed_packets for handle 2
1141            0x02, 0x00, // num_completed_blocks for handle 2
1142        ];
1143        let (evt, rest) = NumberOfCompletedDataBlocks::from_hci_bytes(&data).unwrap();
1144        assert_eq!(evt.total_num_data_blocks, 4096);
1145        assert_eq!(evt.num_of_handles, 2);
1146        assert_eq!(evt.bytes.as_hci_bytes().len(), 12); // 2 handles * 6 bytes each
1147        assert!(rest.is_empty());
1148    }
1149
1150    #[test]
1151    fn test_connectionless_peripheral_broadcast_receive() {
1152        let data = [
1153            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1154            0x07, // lt_addr
1155            0x12, 0x34, 0x56, 0x78, // clock
1156            0x9A, 0xBC, 0xDE, 0xF0, // offset
1157            0x00, // rx_status (success)
1158            0x01, // fragment
1159            0x04, // data_length
1160            0xAA, 0xBB, 0xCC, 0xDD, // data
1161        ];
1162        let (evt, rest) = ConnectionlessPeripheralBroadcastReceive::from_hci_bytes(&data).unwrap();
1163        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1164        assert_eq!(evt.lt_addr, 0x07);
1165        assert_eq!(evt.clock, 0x78563412);
1166        assert_eq!(evt.offset, 0xF0DEBC9A);
1167        assert_eq!(evt.rx_status, 0x00);
1168        assert_eq!(evt.fragment, 0x01);
1169        assert_eq!(evt.data_length, 0x04);
1170        assert_eq!(evt.data.as_hci_bytes(), &[0xAA, 0xBB, 0xCC, 0xDD]);
1171        assert!(rest.is_empty());
1172    }
1173
1174    #[test]
1175    fn test_connectionless_peripheral_broadcast_timeout() {
1176        let data = [
1177            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1178            0x07, // lt_addr
1179        ];
1180        let (evt, rest) = ConnectionlessPeripheralBroadcastTimeout::from_hci_bytes(&data).unwrap();
1181        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1182        assert_eq!(evt.lt_addr, 0x07);
1183        assert!(rest.is_empty());
1184    }
1185
1186    #[test]
1187    fn test_truncated_page_complete() {
1188        let data = [
1189            0x00, // status (success)
1190            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1191        ];
1192        let (evt, rest) = TruncatedPageComplete::from_hci_bytes(&data).unwrap();
1193        assert_eq!(evt.status, Status::SUCCESS);
1194        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1195        assert!(rest.is_empty());
1196    }
1197
1198    #[test]
1199    fn test_peripheral_page_response_timeout() {
1200        let data = [];
1201        let (_evt, rest) = PeripheralPageResponseTimeout::from_hci_bytes(&data).unwrap();
1202        assert!(rest.is_empty());
1203    }
1204
1205    #[test]
1206    fn test_connectionless_peripheral_broadcast_channel_map_change() {
1207        let data = [
1208            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, // channel_map
1209        ];
1210        let (evt, rest) = ConnectionlessPeripheralBroadcastChannelMapChange::from_hci_bytes(&data).unwrap();
1211        assert_eq!(
1212            evt.channel_map,
1213            [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A]
1214        );
1215        assert!(rest.is_empty());
1216    }
1217
1218    #[test]
1219    fn test_sam_status_change() {
1220        let data = [
1221            0x01, 0x00, // handle
1222            0x02, // local_sam_index
1223            0x03, // local_sam_tx_availability
1224            0x04, // local_sam_rx_availability
1225            0x05, // remote_sam_index
1226            0x06, // remote_sam_tx_availability
1227            0x07, // remote_sam_rx_availability
1228        ];
1229        let (evt, rest) = SamStatusChange::from_hci_bytes(&data).unwrap();
1230        assert_eq!(evt.handle.raw(), 1);
1231        assert_eq!(evt.local_sam_index, 0x02);
1232        assert_eq!(evt.local_sam_tx_availability, 0x03);
1233        assert_eq!(evt.local_sam_rx_availability, 0x04);
1234        assert_eq!(evt.remote_sam_index, 0x05);
1235        assert_eq!(evt.remote_sam_tx_availability, 0x06);
1236        assert_eq!(evt.remote_sam_rx_availability, 0x07);
1237        assert!(rest.is_empty());
1238    }
1239
1240    #[test]
1241    fn convert_error_packet() {
1242        let data = [
1243            0x04, 10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1244            0x20, 0x04, 0x00, // class_of_device
1245            0x01, // link_type (ACL)
1246        ];
1247        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1248        assert!(matches!(event.kind, EventKind::ConnectionRequest));
1249
1250        let Event::ConnectionRequest(evt) = Event::try_from(event).unwrap() else {
1251            unreachable!()
1252        };
1253
1254        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1255        assert_eq!(evt.class_of_device, [0x20, 0x04, 0x00]);
1256        assert_eq!(evt.link_type, ConnectionLinkType::Acl);
1257    }
1258
1259    #[test]
1260    fn convert_le_error_packet() {
1261        let data = [
1262            0x3e, 19, // header
1263            1,  // subevent
1264            0,  // success
1265            1, 0, // handle
1266            0, // role
1267            1, // kind
1268            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1269            0x10, 0x10, // interval
1270            0x00, 0x00, // latency
1271            0x10, 0x10, // supervision timeout
1272            1,    // accuracy
1273        ];
1274        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1275        assert!(matches!(event.kind, EventKind::Le));
1276
1277        let Event::Le(LeEvent::LeConnectionComplete(e)) = Event::try_from(event).unwrap() else {
1278            unreachable!()
1279        };
1280
1281        assert_eq!(e.status, Status::SUCCESS);
1282        assert_eq!(e.handle, ConnHandle::new(1));
1283        assert!(matches!(e.central_clock_accuracy, ClockAccuracy::Ppm250));
1284    }
1285
1286    #[test]
1287    fn parse_le_packet() {
1288        let data = [
1289            0x3e, 19, // header
1290            1,  // subevent
1291            0,  // success
1292            1, 0, // handle
1293            0, // role
1294            1, // kind
1295            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1296            0x10, 0x10, // interval
1297            0x00, 0x00, // latency
1298            0x10, 0x10, // supervision timeout
1299            1,    // accuracy
1300        ];
1301        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1302        assert!(matches!(event.kind, EventKind::Le));
1303        let event = LeEventPacket::from_hci_bytes_complete(event.data).unwrap();
1304        assert!(matches!(
1305            event.kind,
1306            crate::event::le::LeEventKind::LeConnectionComplete
1307        ));
1308        let e = crate::event::le::LeConnectionComplete::from_hci_bytes_complete(event.data).unwrap();
1309
1310        assert_eq!(e.status, Status::SUCCESS);
1311        assert_eq!(e.handle, ConnHandle::new(1));
1312        assert!(matches!(e.central_clock_accuracy, ClockAccuracy::Ppm250));
1313    }
1314
1315    #[test]
1316    fn test_special_command_complete() {
1317        let data = [
1318            0x0e, 3, // header
1319            1, 0, 0, // special command
1320        ];
1321
1322        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1323        assert!(matches!(event.kind, EventKind::CommandComplete));
1324        let event = CommandComplete::from_hci_bytes_complete(event.data).unwrap();
1325        assert_eq!(event.cmd_opcode, Opcode::new(OpcodeGroup::new(0), 0));
1326    }
1327
1328    #[test]
1329    fn test_normal_command_complete() {
1330        let opcode = Opcode::new(OpcodeGroup::LE, 0x000D).to_raw().to_le_bytes();
1331        let data = [
1332            0x0e, 4, // header
1333            1, opcode[0], opcode[1], // special command
1334            0,         // success
1335        ];
1336
1337        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1338        assert!(matches!(event.kind, EventKind::CommandComplete));
1339        let event = CommandComplete::from_hci_bytes_complete(event.data).unwrap();
1340        assert_eq!(event.cmd_opcode, Opcode::new(OpcodeGroup::LE, 0x000d));
1341
1342        let event: CommandCompleteWithStatus = event.try_into().unwrap();
1343        assert_eq!(event.cmd_opcode, Opcode::new(OpcodeGroup::LE, 0x000d));
1344        assert_eq!(Status::SUCCESS, event.status);
1345    }
1346}