Skip to main content

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, ExtendedLmpFeatures, FlowDirection,
7    IoCapability, KeyFlag, KeypressNotificationType, LinkKeyType, LinkType, LmpFeatureMask, MaxSlots, Mode,
8    OobDataPresent, PacketType, 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(0x3e);
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                Ok((EventKind(header.code), data))
109            }
110        }
111
112        impl<'a> TryFrom<EventPacket<'a>> for Event<'a> {
113            type Error = FromHciBytesError;
114            fn try_from(packet: EventPacket<'a>) -> Result<Self, Self::Error> {
115                match packet.kind {
116                    $(EventKind::$name => Ok(Self::$name($name::from_hci_bytes_complete(packet.data)?)),)+
117                    EventKind::Le => {
118                        Ok(Self::Le(LeEvent::from_hci_bytes_complete(packet.data)?))
119                    }
120                    EventKind(code) => Ok(Self::Unknown { code, params: packet.data }),
121                }
122            }
123        }
124
125        impl<'a> Event<'a> {
126            fn from_header_hci_bytes(header: EventPacketHeader, data: &'a [u8]) -> Result<(Self, &'a [u8]), FromHciBytesError> {
127                let (data, rest) = if data.len() < usize::from(header.params_len) {
128                    return Err(FromHciBytesError::InvalidSize);
129                } else {
130                    data.split_at(usize::from(header.params_len))
131                };
132
133                match header.code {
134                    $($code => $name::from_hci_bytes_complete(data).map(|x| (Self::$name(x), rest)),)+
135                    0x3e => LeEvent::from_hci_bytes_complete(data).map(|x| (Self::Le(x), rest)),
136                    _ => {
137                        Ok((Self::Unknown { code: header.code, params: data }, rest))
138                    }
139                }
140            }
141        }
142
143        $(
144            $(#[$attrs])*
145            #[derive(Debug, Clone, Copy, Hash)]
146            #[cfg_attr(feature = "defmt", derive(defmt::Format))]
147            pub struct $name$(<$life>)? {
148                $(
149                    #[doc = stringify!($field)]
150                    $(#[$field_attrs])*
151                    pub $field: $ty,
152                )*
153            }
154
155            #[automatically_derived]
156            impl<'a> $crate::FromHciBytes<'a> for $name$(<$life>)? {
157                #[allow(unused_variables)]
158                fn from_hci_bytes(data: &'a [u8]) -> Result<(Self, &'a [u8]), $crate::FromHciBytesError> {
159                    let total = 0;
160                    $(
161                        let ($field, data) = <$ty as $crate::FromHciBytes>::from_hci_bytes(data)?;
162                    )*
163                    Ok((Self {
164                        $($field,)*
165                    }, data))
166                }
167            }
168
169            #[automatically_derived]
170            impl<'a> $crate::event::EventParams<'a> for $name$(<$life>)? {
171                const EVENT_CODE: u8 = $code;
172            }
173        )+
174    };
175}
176
177events! {
178    // 0x00 - 0x0f
179
180    /// 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)
181    struct InquiryComplete(0x01) {
182        status: Status,
183    }
184
185    /// 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)
186    struct InquiryResult<'a>(0x02) {
187        num_responses: u8,
188        /// All remaining bytes for this event (contains all fields for all responses)
189        bytes: RemainingBytes<'a>,
190    }
191
192    /// 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)
193    struct ConnectionComplete(0x03) {
194        status: Status,
195        handle: ConnHandle,
196        bd_addr: BdAddr,
197        link_type: ConnectionLinkType,
198        encryption_enabled: bool,
199    }
200
201    /// 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)
202    struct ConnectionRequest(0x04) {
203        bd_addr: BdAddr,
204        class_of_device: [u8; 3],
205        link_type: ConnectionLinkType,
206    }
207
208    /// 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)
209    struct DisconnectionComplete(0x05) {
210        status: Status,
211        handle: ConnHandle,
212        reason: Status,
213    }
214
215    /// 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)
216    struct AuthenticationComplete(0x06) {
217        status: Status,
218        handle: ConnHandle,
219    }
220
221    /// 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)
222    struct RemoteNameRequestComplete<'a>(0x07) {
223        status: Status,
224        bd_addr: BdAddr,
225        remote_name: RemainingBytes<'a>, // 248 bytes max, null-terminated string
226    }
227
228    /// 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)
229    struct EncryptionChangeV1(0x08) {
230        status: Status,
231        handle: ConnHandle,
232        enabled: EncryptionEnabledLevel,
233    }
234
235    /// 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)
236    struct ChangeConnectionLinkKeyComplete(0x09) {
237        status: Status,
238        handle: ConnHandle,
239    }
240
241    /// 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)
242    struct LinkKeyTypeChanged(0x0a) {
243        status: Status,
244        handle: ConnHandle,
245        key_flag: KeyFlag,
246    }
247
248    /// 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)
249    struct ReadRemoteSupportedFeaturesComplete(0x0b) {
250        status: Status,
251        handle: ConnHandle,
252        lmp_features: LmpFeatureMask,
253    }
254
255    /// 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)
256    struct ReadRemoteVersionInformationComplete(0x0c) {
257        status: Status,
258        handle: ConnHandle,
259        version: CoreSpecificationVersion,
260        company_id: u16,
261        subversion: u16,
262    }
263
264    /// 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)
265    struct QosSetupComplete(0x0d) {
266        status: Status,
267        handle: ConnHandle,
268        unused: u8, // Always 0
269        service_type: ServiceType,
270        token_rate: u32,
271        peak_bandwidth: u32,
272        latency: u32,
273        delay_variation: u32,
274    }
275
276    /// 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)
277    struct CommandComplete<'a>(0x0e) {
278        num_hci_cmd_pkts: u8,
279        cmd_opcode: Opcode,
280        bytes: RemainingBytes<'a>,
281    }
282
283    /// 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)
284    struct CommandStatus(0x0f) {
285        status: Status,
286        num_hci_cmd_pkts: u8,
287        cmd_opcode: Opcode,
288    }
289
290    // 0x10 - 0x1f
291
292    /// 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)
293    struct HardwareError(0x10) {
294        hardware_code: u8,
295    }
296
297    /// 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)
298    struct FlushOccurred(0x11) {
299        handle: ConnHandle,
300    }
301
302    /// 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)
303    struct RoleChange(0x12) {
304        status: Status,
305        bd_addr: BdAddr,
306        new_role: Role,
307    }
308
309    /// 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)
310    struct NumberOfCompletedPackets<'a>(0x13) {
311        completed_packets: &'a [ConnHandleCompletedPackets],
312    }
313
314    /// 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)
315    struct ModeChange(0x14) {
316        status: Status,
317        handle: ConnHandle,
318        mode: Mode,
319        interval: u16,
320    }
321
322    /// 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)
323    struct ReturnLinkKeys<'a>(0x15) {
324        num_keys: u8,
325        bytes: RemainingBytes<'a>, // bd_addr: Num_Keys × 6 octets, link_key: Num_Keys × 16 octets, always zero
326    }
327
328    /// 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)
329    struct PinCodeRequest(0x16) {
330        bd_addr: BdAddr,
331    }
332
333    /// 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)
334    struct LinkKeyRequest(0x17) {
335        bd_addr: BdAddr,
336    }
337
338    /// 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)
339    struct LinkKeyNotification(0x18) {
340        bd_addr: BdAddr,
341        link_key: [u8; 16],
342        key_type: LinkKeyType,
343    }
344
345    /// 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)
346    struct LoopbackCommand<'a>(0x19) {
347        command_packet: RemainingBytes<'a>,
348    }
349
350    /// 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)
351    struct DataBufferOverflow(0x1a) {
352        link_type: LinkType,
353    }
354
355    /// 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)
356    struct MaxSlotsChange(0x1b) {
357        handle: ConnHandle,
358        lmp_max_slots: MaxSlots,
359    }
360
361    /// 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)
362    struct ReadClockOffsetComplete(0x1c) {
363        status: Status,
364        handle: ConnHandle,
365        clock_offset: ClockOffset,
366    }
367
368    /// 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)
369    struct ConnectionPacketTypeChanged(0x1d) {
370        status: Status,
371        handle: ConnHandle,
372        packet_type: PacketType,
373    }
374
375    /// 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)
376    struct QosViolation(0x1e) {
377        handle: ConnHandle,
378    }
379
380    // 0x20 - 0x2f
381
382    /// 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)
383    struct PageScanRepetitionModeChange(0x20) {
384        bd_addr: BdAddr,
385        page_scan_repetition_mode: PageScanRepetitionMode,
386    }
387
388    /// 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)
389    struct FlowSpecificationComplete(0x21) {
390        status: Status,
391        handle: ConnHandle,
392        unused: u8, // Always 0
393        flow_direction: FlowDirection,
394        service_type: ServiceType,
395        token_rate: u32,
396        token_bucket_size: u32,
397        peak_bandwidth: u32,
398        access_latency: u32,
399    }
400
401    /// 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)
402    struct InquiryResultWithRssi<'a>(0x22) {
403        num_responses: u8,
404        /// All remaining bytes for this event (contains all fields for all responses)
405        bytes: RemainingBytes<'a>,
406    }
407
408    /// 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)
409    struct ReadRemoteExtendedFeaturesComplete(0x23) {
410        status: Status,
411        handle: ConnHandle,
412        extended_lmp_features: ExtendedLmpFeatures,
413    }
414
415    /// 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)
416    struct SynchronousConnectionComplete(0x2c) {
417        status: Status,
418        handle: ConnHandle,
419        bd_addr: BdAddr,
420        link_type: ConnectionLinkType,
421        transmission_interval: u8,
422        retransmission_window: u8,
423        rx_packet_length: u16,
424        tx_packet_length: u16,
425        air_mode: u8,
426    }
427
428    /// 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)
429    struct SynchronousConnectionChanged(0x2d) {
430        status: Status,
431        handle: ConnHandle,
432        transmission_interval: u8,
433        retransmission_window: u8,
434        rx_packet_length: u16,
435        tx_packet_length: u16,
436    }
437
438
439    /// 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)
440    struct SniffSubrating(0x2e) {
441        status: Status,
442        handle: ConnHandle,
443        max_tx_latency: u16,
444        max_rx_latency: u16,
445        min_remote_timeout: u16,
446        min_local_timeout: u16,
447    }
448
449    /// 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)
450    struct ExtendedInquiryResult<'a>(0x2f) {
451        num_responses: u8,
452        bd_addr: BdAddr,
453        page_scan_repetition_mode: PageScanRepetitionMode,
454        reserved: u8,
455        class_of_device: [u8; 3],
456        clock_offset: ClockOffset,
457        rssi: i8,
458        eir_data: RemainingBytes<'a>,
459    }
460
461    // 0x30 - 0x3f
462
463    /// 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)
464    struct EncryptionKeyRefreshComplete(0x30) {
465        status: Status,
466        handle: ConnHandle,
467    }
468
469    /// 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)
470    struct IoCapabilityRequest(0x31) {
471        bd_addr: BdAddr,
472    }
473
474    /// 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)
475    struct IoCapabilityResponse(0x32) {
476        bd_addr: BdAddr,
477        io_capability: IoCapability,
478        oob_data_present: OobDataPresent,
479        authentication_requirements: AuthenticationRequirements,
480    }
481
482    /// 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)
483    struct UserConfirmationRequest(0x33) {
484        bd_addr: BdAddr,
485        numeric_value: u32,
486    }
487
488    /// 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)
489    struct UserPasskeyRequest(0x34) {
490        bd_addr: BdAddr,
491    }
492
493    /// 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)
494    struct RemoteOobDataRequest(0x35) {
495        bd_addr: BdAddr,
496    }
497
498    /// 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)
499    struct SimplePairingComplete(0x36) {
500        status: Status,
501        bd_addr: BdAddr,
502    }
503
504    /// 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)
505    struct LinkSupervisionTimeoutChanged(0x38) {
506        handle: ConnHandle,
507        link_supervision_timeout: u16,
508    }
509
510    /// 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)
511    struct EnhancedFlushComplete(0x39) {
512        handle: ConnHandle,
513    }
514
515    /// 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)
516    struct UserPasskeyNotification(0x3b) {
517        bd_addr: BdAddr,
518        passkey: u32,
519    }
520
521    /// 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)
522    struct KeypressNotification(0x3c) {
523        bd_addr: BdAddr,
524        notification_type: KeypressNotificationType,
525    }
526
527    /// 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)
528    struct RemoteHostSupportedFeaturesNotification(0x3d) {
529        bd_addr: BdAddr,
530        features: LmpFeatureMask,
531    }
532
533    // 0x40 - 0x4f
534
535    /// 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)
536    struct NumberOfCompletedDataBlocks<'a>(0x48) {
537        total_num_data_blocks: u16,
538        num_of_handles: u8,
539        bytes: RemainingBytes<'a>, // Contains handle + num_completed_packets + num_completed_blocks for each handle
540    }
541
542    /// 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)
543    struct TriggeredClockCapture(0x4e) {
544        handle: ConnHandle,
545        which_clock: ClockType,
546        clock: u32,
547        slot_offset: u16,
548    }
549
550    /// 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)
551    struct SynchronizationTrainComplete(0x4f) {
552        status: Status,
553    }
554
555    // 0x50 - 0x5f
556
557    /// 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)
558    struct SynchronizationTrainReceived(0x50) {
559        status: Status,
560        bd_addr: BdAddr,
561        clock_offset: u32,
562        afh_channel_map: [u8; 10],
563        lt_addr: u8,
564        next_broadcast_instant: u32,
565        connectionless_peripheral_broadcast_interval: u16,
566        service_data: u8,
567    }
568
569    /// 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)
570    struct ConnectionlessPeripheralBroadcastReceive<'a>(0x51) {
571        bd_addr: BdAddr,
572        lt_addr: u8,
573        clock: u32,
574        offset: u32,
575        rx_status: u8,
576        fragment: u8,
577        data_length: u8,
578        data: RemainingBytes<'a>,
579    }
580
581    /// 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)
582    struct ConnectionlessPeripheralBroadcastTimeout(0x52) {
583        bd_addr: BdAddr,
584        lt_addr: u8,
585    }
586
587    /// 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)
588    struct TruncatedPageComplete(0x53) {
589        status: Status,
590        bd_addr: BdAddr,
591    }
592
593    /// 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)
594    struct PeripheralPageResponseTimeout(0x54) {
595    }
596
597    /// 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)
598    struct ConnectionlessPeripheralBroadcastChannelMapChange(0x55) {
599        channel_map: [u8; 10],
600    }
601
602    /// 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)
603    struct InquiryResponseNotification(0x56) {
604        lap: [u8; 3],
605        rssi: i8,
606    }
607
608    /// 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)
609    struct AuthenticatedPayloadTimeoutExpired(0x57) {
610        handle: ConnHandle,
611    }
612
613    /// 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)
614    struct SamStatusChange(0x58) {
615        handle: ConnHandle,
616        local_sam_index: u8,
617        local_sam_tx_availability: u8,
618        local_sam_rx_availability: u8,
619        remote_sam_index: u8,
620        remote_sam_tx_availability: u8,
621        remote_sam_rx_availability: u8,
622    }
623
624    /// 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)
625    struct EncryptionChangeV2(0x59) {
626        status: Status,
627        handle: ConnHandle,
628        encryption_enabled: EncryptionEnabledLevel,
629        encryption_key_size: u8,
630    }
631
632    // 0xf0 - 0xff
633
634    /// 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)
635    struct Vendor<'a>(0xff) {
636        params: RemainingBytes<'a>,
637    }
638}
639
640impl<'de> FromHciBytes<'de> for Event<'de> {
641    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
642        let (header, data) = EventPacketHeader::from_hci_bytes(data)?;
643        Self::from_header_hci_bytes(header, data)
644    }
645}
646
647impl<'de> FromHciBytes<'de> for EventPacket<'de> {
648    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
649        let (header, data) = EventPacketHeader::from_hci_bytes(data)?;
650        let pkt = Self::from_header_hci_bytes(header, data)?;
651        Ok((pkt, &[]))
652    }
653}
654
655impl<'de> ReadHci<'de> for EventPacket<'de> {
656    const MAX_LEN: usize = 257;
657
658    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
659        let mut header = [0; 2];
660        reader.read_exact(&mut header)?;
661        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
662        let params_len = usize::from(header.params_len);
663        if buf.len() < params_len {
664            Err(ReadHciError::BufferTooSmall)
665        } else {
666            let (buf, _) = buf.split_at_mut(params_len);
667            reader.read_exact(buf)?;
668            let pkt = Self::from_header_hci_bytes(header, buf)?;
669            Ok(pkt)
670        }
671    }
672
673    async fn read_hci_async<R: embedded_io_async::Read>(
674        mut reader: R,
675        buf: &'de mut [u8],
676    ) -> Result<Self, ReadHciError<R::Error>> {
677        let mut header = [0; 2];
678        reader.read_exact(&mut header).await?;
679        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
680        let params_len = usize::from(header.params_len);
681        if buf.len() < params_len {
682            Err(ReadHciError::BufferTooSmall)
683        } else {
684            let (buf, _) = buf.split_at_mut(params_len);
685            reader.read_exact(buf).await?;
686            let pkt = Self::from_header_hci_bytes(header, buf)?;
687            Ok(pkt)
688        }
689    }
690}
691
692impl<'de> ReadHci<'de> for Event<'de> {
693    const MAX_LEN: usize = 257;
694
695    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
696        let mut header = [0; 2];
697        reader.read_exact(&mut header)?;
698        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
699        let params_len = usize::from(header.params_len);
700        if buf.len() < params_len {
701            Err(ReadHciError::BufferTooSmall)
702        } else {
703            let (buf, _) = buf.split_at_mut(params_len);
704            reader.read_exact(buf)?;
705            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
706            Ok(pkt)
707        }
708    }
709
710    async fn read_hci_async<R: embedded_io_async::Read>(
711        mut reader: R,
712        buf: &'de mut [u8],
713    ) -> Result<Self, ReadHciError<R::Error>> {
714        let mut header = [0; 2];
715        reader.read_exact(&mut header).await?;
716        let (header, _) = EventPacketHeader::from_hci_bytes(&header)?;
717        let params_len = usize::from(header.params_len);
718        if buf.len() < params_len {
719            Err(ReadHciError::BufferTooSmall)
720        } else {
721            let (buf, _) = buf.split_at_mut(params_len);
722            reader.read_exact(buf).await?;
723            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
724            Ok(pkt)
725        }
726    }
727}
728
729impl CommandComplete<'_> {
730    /// Whether or not this event has a status
731    pub fn has_status(&self) -> bool {
732        self.cmd_opcode != Opcode::UNSOLICITED
733    }
734}
735
736impl<'d> TryFrom<CommandComplete<'d>> for CommandCompleteWithStatus<'d> {
737    type Error = FromHciBytesError;
738    fn try_from(e: CommandComplete<'d>) -> Result<CommandCompleteWithStatus<'d>, Self::Error> {
739        if e.cmd_opcode == Opcode::UNSOLICITED {
740            return Err(FromHciBytesError::InvalidSize);
741        }
742        let bytes = e.bytes.into_inner();
743        let (status, remaining) = Status::from_hci_bytes(bytes)?;
744        let return_param_bytes: RemainingBytes<'d> = RemainingBytes::from_hci_bytes_complete(remaining)?;
745        Ok(Self {
746            num_hci_cmd_pkts: e.num_hci_cmd_pkts,
747            cmd_opcode: e.cmd_opcode,
748            status,
749            return_param_bytes,
750        })
751    }
752}
753
754/// Struct representing a command complete event with status
755#[derive(Debug, Clone, PartialEq, Eq)]
756pub struct CommandCompleteWithStatus<'d> {
757    /// Number of packets complete.
758    pub num_hci_cmd_pkts: u8,
759    /// Command opcode.
760    pub cmd_opcode: Opcode,
761    /// Command status.
762    pub status: Status,
763    /// Return parameters
764    pub return_param_bytes: RemainingBytes<'d>,
765}
766
767impl CommandCompleteWithStatus<'_> {
768    /// Gets the connection handle associated with the command that has completed.
769    ///
770    /// For commands that return the connection handle provided as a parameter as
771    /// their first return parameter, this will be valid even if `status` is an error.
772    pub fn handle<C: SyncCmd>(&self) -> Result<C::Handle, FromHciBytesError> {
773        C::return_handle(&self.return_param_bytes)
774    }
775
776    /// Gets a result with the return parameters for `C` or an `Error` if `status` is
777    /// an error.
778    ///
779    /// # Panics
780    ///
781    /// May panic if `C::OPCODE` is not equal to `self.cmd_opcode`.
782    pub fn to_result<C: SyncCmd>(&self) -> Result<C::Return, Error> {
783        self.status
784            .to_result()
785            .and_then(|_| self.return_params::<C>().or(Err(Error::INVALID_HCI_PARAMETERS)))
786    }
787
788    /// Parses the return parameters for `C` from this event. This may fail if `status`
789    /// is an error.
790    ///
791    /// # Panics
792    ///
793    /// May panic if `C::OPCODE` is not equal to `self.cmd_opcode`.
794    pub fn return_params<C: SyncCmd>(&self) -> Result<C::Return, FromHciBytesError> {
795        assert_eq!(self.cmd_opcode, C::OPCODE);
796        C::Return::from_hci_bytes(&self.return_param_bytes).and_then(|(params, rest)| {
797            if rest.is_empty() {
798                Ok(params)
799            } else {
800                Err(FromHciBytesError::InvalidSize)
801            }
802        })
803    }
804}
805
806/// Struct representing a single parsed inquiry result item
807#[derive(Debug, Clone, PartialEq, Eq)]
808pub struct InquiryResultItem {
809    /// Bluetooth Device Address (BD_ADDR) of the device found
810    pub bd_addr: BdAddr,
811    /// Page scan repetition mode of the device
812    pub page_scan_repetition_mode: Option<PageScanRepetitionMode>,
813    /// Class of device (CoD) of the device found
814    pub class_of_device: Option<[u8; 3]>,
815    /// Clock offset of the device found
816    pub clock_offset: Option<ClockOffset>,
817    /// Received Signal Strength Indicator (RSSI) of the device found
818    /// This field is only present in `InquiryResultWithRssi`
819    pub rssi: Option<i8>,
820}
821
822/// Iterator over inquiry result items
823pub struct InquiryResultIter<'a> {
824    bytes: &'a [u8],
825    num_responses: usize,
826    idx: usize,
827    kind: InquiryResultKind,
828}
829
830/// Kind of inquiry result, indicating whether it includes RSSI or not
831#[derive(Copy, Clone, Debug, PartialEq, Eq)]
832pub enum InquiryResultKind {
833    /// Standard inquiry result without RSSI
834    Standard,
835    /// Inquiry result with RSSI
836    WithRssi,
837}
838
839impl<'a> InquiryResultIter<'a> {
840    /// Creates a new iterator for standard inquiry results
841    pub fn new_standard(bytes: &'a [u8], num_responses: usize) -> Self {
842        InquiryResultIter {
843            bytes,
844            num_responses,
845            idx: 0,
846            kind: InquiryResultKind::Standard,
847        }
848    }
849
850    /// Creates a new iterator for inquiry results with RSSI
851    pub fn new_with_rssi(bytes: &'a [u8], num_responses: usize) -> Self {
852        InquiryResultIter {
853            bytes,
854            num_responses,
855            idx: 0,
856            kind: InquiryResultKind::WithRssi,
857        }
858    }
859}
860
861impl Iterator for InquiryResultIter<'_> {
862    type Item = InquiryResultItem;
863    fn next(&mut self) -> Option<Self::Item> {
864        if self.idx >= self.num_responses {
865            return None;
866        }
867
868        let i = self.idx;
869        let n = self.num_responses;
870
871        let bd_addr_size = n * 6;
872        let page_scan_size = n;
873        let class_size = n * 3;
874        let clock_size = n * 2;
875
876        let reserved_size = match self.kind {
877            InquiryResultKind::Standard => n * 2,
878            InquiryResultKind::WithRssi => n,
879        };
880
881        let bd_addr_off = i * 6;
882        let page_scan_off = bd_addr_size + i;
883        let class_off = bd_addr_size + page_scan_size + reserved_size + i * 3;
884        let clock_off = bd_addr_size + page_scan_size + reserved_size + class_size + i * 2;
885
886        if self.bytes.len() < bd_addr_off + 6 {
887            return None;
888        }
889
890        let bd_addr = BdAddr::new([
891            self.bytes[bd_addr_off],
892            self.bytes[bd_addr_off + 1],
893            self.bytes[bd_addr_off + 2],
894            self.bytes[bd_addr_off + 3],
895            self.bytes[bd_addr_off + 4],
896            self.bytes[bd_addr_off + 5],
897        ]);
898
899        let page_scan_repetition_mode = self
900            .bytes
901            .get(page_scan_off)
902            .and_then(|b| PageScanRepetitionMode::from_hci_bytes(&[*b]).ok().map(|(m, _)| m));
903
904        let class_of_device = self.bytes.get(class_off..class_off + 3).map(|s| [s[0], s[1], s[2]]);
905
906        let clock_offset = self
907            .bytes
908            .get(clock_off..clock_off + 2)
909            .and_then(|s| ClockOffset::from_hci_bytes(s).ok().map(|(c, _)| c));
910
911        let rssi = if self.kind == InquiryResultKind::WithRssi {
912            let rssi_off = bd_addr_size + page_scan_size + reserved_size + class_size + clock_size + i;
913            self.bytes.get(rssi_off).map(|b| *b as i8)
914        } else {
915            None
916        };
917
918        self.idx += 1;
919
920        Some(InquiryResultItem {
921            bd_addr,
922            page_scan_repetition_mode,
923            class_of_device,
924            clock_offset,
925            rssi,
926        })
927    }
928}
929
930/// Inquiry result event containing multiple responses
931impl InquiryResult<'_> {
932    /// Returns an iterator over all valid inquiry result items.
933    pub fn iter(&self) -> InquiryResultIter<'_> {
934        let bytes = self.bytes.as_hci_bytes();
935        let n = self.num_responses as usize;
936        InquiryResultIter::new_standard(bytes, n)
937    }
938}
939
940/// Inquiry result event containing multiple responses with RSSI
941impl InquiryResultWithRssi<'_> {
942    /// Returns an iterator over all valid inquiry result items.
943    pub fn iter(&self) -> InquiryResultIter<'_> {
944        let bytes = self.bytes.as_hci_bytes();
945        let n = self.num_responses as usize;
946        InquiryResultIter::new_with_rssi(bytes, n)
947    }
948}
949
950#[cfg(test)]
951mod tests {
952    use super::*;
953    use crate::cmd::OpcodeGroup;
954    use crate::event::le::LeEventPacket;
955    use crate::param::*;
956
957    #[test]
958    fn test_inquiry_result() {
959        let data = [
960            0x02, // num_responses = 2
961            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // addr 1
962            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // addr 2
963            0x01, 0x02, // R1, R2
964            0x00, 0x00, 0x00, 0x00, // reserved
965            0x20, 0x04, 0x00, 0x30, 0x05, 0x01, // class of device
966            0x34, 0x12, 0x78, 0x56, // clock offsets
967        ];
968        let (inquiry_result, _) = InquiryResult::from_hci_bytes(&data).unwrap();
969
970        let mut iter = inquiry_result.iter();
971
972        let item1 = iter.next().unwrap();
973        assert_eq!(item1.bd_addr.as_hci_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
974        assert_eq!(item1.page_scan_repetition_mode, Some(PageScanRepetitionMode::R1));
975        assert_eq!(item1.class_of_device, Some([0x20, 0x04, 0x00]));
976        assert_eq!(item1.clock_offset.unwrap().as_hci_bytes(), &[0x34, 0x12]);
977        assert_eq!(item1.rssi, None);
978
979        let item2 = iter.next().unwrap();
980        assert_eq!(item2.bd_addr.as_hci_bytes(), &[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
981        assert_eq!(item2.page_scan_repetition_mode, Some(PageScanRepetitionMode::R2));
982        assert_eq!(item2.class_of_device, Some([0x30, 0x05, 0x01]));
983        assert_eq!(item2.clock_offset.unwrap().as_hci_bytes(), &[0x78, 0x56]);
984        assert_eq!(item2.rssi, None);
985        assert!(iter.next().is_none());
986    }
987
988    #[test]
989    fn test_inquiry_result_with_rssi() {
990        let data = [
991            0x02, // num_responses = 2
992            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // addr 1
993            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // addr 2
994            0x01, 0x02, // R1, R2
995            0x00, 0x00, // reserved
996            0x20, 0x04, 0x00, 0x30, 0x05, 0x01, // class of device
997            0x34, 0x12, 0x78, 0x56, // clock offsets
998            0xF0, 0xE8, // RSSI
999        ];
1000        let (inquiry_result, _) = InquiryResultWithRssi::from_hci_bytes(&data).unwrap();
1001
1002        let mut iter = inquiry_result.iter();
1003
1004        let item1 = iter.next().unwrap();
1005        assert_eq!(item1.bd_addr.as_hci_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
1006        assert_eq!(item1.page_scan_repetition_mode, Some(PageScanRepetitionMode::R1));
1007        assert_eq!(item1.class_of_device, Some([0x20, 0x04, 0x00]));
1008        assert_eq!(item1.clock_offset.unwrap().as_hci_bytes(), &[0x34, 0x12]);
1009        assert_eq!(item1.rssi, Some(-16));
1010
1011        let item2 = iter.next().unwrap();
1012        assert_eq!(item2.bd_addr.as_hci_bytes(), &[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
1013        assert_eq!(item2.page_scan_repetition_mode, Some(PageScanRepetitionMode::R2));
1014        assert_eq!(item2.class_of_device, Some([0x30, 0x05, 0x01]));
1015        assert_eq!(item2.clock_offset.unwrap().as_hci_bytes(), &[0x78, 0x56]);
1016        assert_eq!(item2.rssi, Some(-24));
1017        assert!(iter.next().is_none());
1018    }
1019
1020    #[test]
1021    fn test_extended_inquiry_result() {
1022        let data = [
1023            0x01, // num_responses = 1
1024            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1025            0x01, // page_scan_repetition_mode (R1)
1026            0x00, // reserved
1027            0x20, 0x04, 0x00, // class_of_device
1028            0x34, 0x12, // clock_offset
1029            0xF0, // rssi (-16)
1030            0x09, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x65, 0x76, // eir_data (sample EIR data)
1031        ];
1032        let (eir_result, _) = ExtendedInquiryResult::from_hci_bytes(&data).unwrap();
1033
1034        assert_eq!(eir_result.num_responses, 1);
1035        assert_eq!(eir_result.bd_addr.as_hci_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
1036        assert_eq!(eir_result.page_scan_repetition_mode, PageScanRepetitionMode::R1);
1037        assert_eq!(eir_result.reserved, 0x00);
1038        assert_eq!(eir_result.class_of_device, [0x20, 0x04, 0x00]);
1039        assert_eq!(eir_result.clock_offset.as_hci_bytes(), &[0x34, 0x12]);
1040        assert_eq!(eir_result.rssi, -16);
1041        assert_eq!(
1042            eir_result.eir_data.as_hci_bytes(),
1043            &[0x09, 0x08, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x65, 0x76]
1044        );
1045    }
1046
1047    #[test]
1048    fn test_io_capability_request() {
1049        let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1050        let (evt, rest) = IoCapabilityRequest::from_hci_bytes(&data).unwrap();
1051        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1052        assert!(rest.is_empty());
1053    }
1054
1055    #[test]
1056    fn test_user_confirmation_request() {
1057        let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x78, 0x56, 0x34, 0x12];
1058        let (evt, rest) = UserConfirmationRequest::from_hci_bytes(&data).unwrap();
1059        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1060        assert_eq!(evt.numeric_value, 0x1234_5678);
1061        assert!(rest.is_empty());
1062    }
1063
1064    #[test]
1065    fn test_connection_request() {
1066        let data = [
1067            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1068            0x20, 0x04, 0x00, // class_of_device
1069            0x01, // link_type (ACL)
1070        ];
1071        let (evt, rest) = ConnectionRequest::from_hci_bytes(&data).unwrap();
1072        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1073        assert_eq!(evt.class_of_device, [0x20, 0x04, 0x00]);
1074        assert_eq!(evt.link_type, ConnectionLinkType::Acl);
1075        assert!(rest.is_empty());
1076    }
1077
1078    #[test]
1079    fn test_role_change() {
1080        let data = [
1081            0x00, // status (success)
1082            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1083            0x00, // new_role (Central)
1084        ];
1085        let (evt, rest) = RoleChange::from_hci_bytes(&data).unwrap();
1086        assert_eq!(evt.status, Status::SUCCESS);
1087        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1088        assert_eq!(evt.new_role, Role::Central);
1089        assert!(rest.is_empty());
1090    }
1091
1092    #[test]
1093    fn test_simple_pairing_complete() {
1094        let data = [
1095            0x00, // status (success)
1096            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1097        ];
1098        let (evt, rest) = SimplePairingComplete::from_hci_bytes(&data).unwrap();
1099        assert_eq!(evt.status, Status::SUCCESS);
1100        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1101        assert!(rest.is_empty());
1102    }
1103
1104    #[test]
1105    fn test_io_capability_response() {
1106        let data = [
1107            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1108            0x01, // io_capability (DisplayYesNo)
1109            0x00, // oob_data_present (not present)
1110            0x03, // authentication_requirements (MITM Protection Required - General Bonding)
1111        ];
1112        let (evt, rest) = IoCapabilityResponse::from_hci_bytes(&data).unwrap();
1113        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1114        assert_eq!(evt.io_capability, IoCapability::DisplayYesNo);
1115        assert_eq!(evt.oob_data_present, OobDataPresent::NotPresent);
1116        assert_eq!(
1117            evt.authentication_requirements,
1118            AuthenticationRequirements::MitmRequiredDedicatedBonding
1119        );
1120        assert!(rest.is_empty());
1121    }
1122
1123    #[test]
1124    fn test_number_of_completed_data_blocks() {
1125        let data = [
1126            0x00, 0x10, // total_num_data_blocks = 4096
1127            0x02, // num_of_handles = 2
1128            0x01, 0x00, // handle 1
1129            0x02, 0x00, // num_completed_packets for handle 1
1130            0x04, 0x00, // num_completed_blocks for handle 1
1131            0x02, 0x00, // handle 2
1132            0x01, 0x00, // num_completed_packets for handle 2
1133            0x02, 0x00, // num_completed_blocks for handle 2
1134        ];
1135        let (evt, rest) = NumberOfCompletedDataBlocks::from_hci_bytes(&data).unwrap();
1136        assert_eq!(evt.total_num_data_blocks, 4096);
1137        assert_eq!(evt.num_of_handles, 2);
1138        assert_eq!(evt.bytes.as_hci_bytes().len(), 12); // 2 handles * 6 bytes each
1139        assert!(rest.is_empty());
1140    }
1141
1142    #[test]
1143    fn test_connectionless_peripheral_broadcast_receive() {
1144        let data = [
1145            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1146            0x07, // lt_addr
1147            0x12, 0x34, 0x56, 0x78, // clock
1148            0x9A, 0xBC, 0xDE, 0xF0, // offset
1149            0x00, // rx_status (success)
1150            0x01, // fragment
1151            0x04, // data_length
1152            0xAA, 0xBB, 0xCC, 0xDD, // data
1153        ];
1154        let (evt, rest) = ConnectionlessPeripheralBroadcastReceive::from_hci_bytes(&data).unwrap();
1155        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1156        assert_eq!(evt.lt_addr, 0x07);
1157        assert_eq!(evt.clock, 0x78563412);
1158        assert_eq!(evt.offset, 0xF0DEBC9A);
1159        assert_eq!(evt.rx_status, 0x00);
1160        assert_eq!(evt.fragment, 0x01);
1161        assert_eq!(evt.data_length, 0x04);
1162        assert_eq!(evt.data.as_hci_bytes(), &[0xAA, 0xBB, 0xCC, 0xDD]);
1163        assert!(rest.is_empty());
1164    }
1165
1166    #[test]
1167    fn test_connectionless_peripheral_broadcast_timeout() {
1168        let data = [
1169            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1170            0x07, // lt_addr
1171        ];
1172        let (evt, rest) = ConnectionlessPeripheralBroadcastTimeout::from_hci_bytes(&data).unwrap();
1173        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1174        assert_eq!(evt.lt_addr, 0x07);
1175        assert!(rest.is_empty());
1176    }
1177
1178    #[test]
1179    fn test_truncated_page_complete() {
1180        let data = [
1181            0x00, // status (success)
1182            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1183        ];
1184        let (evt, rest) = TruncatedPageComplete::from_hci_bytes(&data).unwrap();
1185        assert_eq!(evt.status, Status::SUCCESS);
1186        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1187        assert!(rest.is_empty());
1188    }
1189
1190    #[test]
1191    fn test_peripheral_page_response_timeout() {
1192        let data = [];
1193        let (_evt, rest) = PeripheralPageResponseTimeout::from_hci_bytes(&data).unwrap();
1194        assert!(rest.is_empty());
1195    }
1196
1197    #[test]
1198    fn test_connectionless_peripheral_broadcast_channel_map_change() {
1199        let data = [
1200            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, // channel_map
1201        ];
1202        let (evt, rest) = ConnectionlessPeripheralBroadcastChannelMapChange::from_hci_bytes(&data).unwrap();
1203        assert_eq!(
1204            evt.channel_map,
1205            [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A]
1206        );
1207        assert!(rest.is_empty());
1208    }
1209
1210    #[test]
1211    fn test_sam_status_change() {
1212        let data = [
1213            0x01, 0x00, // handle
1214            0x02, // local_sam_index
1215            0x03, // local_sam_tx_availability
1216            0x04, // local_sam_rx_availability
1217            0x05, // remote_sam_index
1218            0x06, // remote_sam_tx_availability
1219            0x07, // remote_sam_rx_availability
1220        ];
1221        let (evt, rest) = SamStatusChange::from_hci_bytes(&data).unwrap();
1222        assert_eq!(evt.handle.raw(), 1);
1223        assert_eq!(evt.local_sam_index, 0x02);
1224        assert_eq!(evt.local_sam_tx_availability, 0x03);
1225        assert_eq!(evt.local_sam_rx_availability, 0x04);
1226        assert_eq!(evt.remote_sam_index, 0x05);
1227        assert_eq!(evt.remote_sam_tx_availability, 0x06);
1228        assert_eq!(evt.remote_sam_rx_availability, 0x07);
1229        assert!(rest.is_empty());
1230    }
1231
1232    #[test]
1233    fn convert_error_packet() {
1234        let data = [
1235            0x04, 10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1236            0x20, 0x04, 0x00, // class_of_device
1237            0x01, // link_type (ACL)
1238        ];
1239        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1240        assert!(matches!(event.kind, EventKind::ConnectionRequest));
1241
1242        let Event::ConnectionRequest(evt) = Event::try_from(event).unwrap() else {
1243            unreachable!()
1244        };
1245
1246        assert_eq!(evt.bd_addr.raw(), [1, 2, 3, 4, 5, 6]);
1247        assert_eq!(evt.class_of_device, [0x20, 0x04, 0x00]);
1248        assert_eq!(evt.link_type, ConnectionLinkType::Acl);
1249    }
1250
1251    #[test]
1252    fn convert_le_error_packet() {
1253        let data = [
1254            0x3e, 19, // header
1255            1,  // subevent
1256            0,  // success
1257            1, 0, // handle
1258            0, // role
1259            1, // kind
1260            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1261            0x10, 0x10, // interval
1262            0x00, 0x00, // latency
1263            0x10, 0x10, // supervision timeout
1264            1,    // accuracy
1265        ];
1266        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1267        assert!(matches!(event.kind, EventKind::Le));
1268
1269        let Event::Le(LeEvent::LeConnectionComplete(e)) = Event::try_from(event).unwrap() else {
1270            unreachable!()
1271        };
1272
1273        assert_eq!(e.status, Status::SUCCESS);
1274        assert_eq!(e.handle, ConnHandle::new(1));
1275        assert!(matches!(e.central_clock_accuracy, ClockAccuracy::Ppm250));
1276    }
1277
1278    #[test]
1279    fn parse_le_packet() {
1280        let data = [
1281            0x3e, 19, // header
1282            1,  // subevent
1283            0,  // success
1284            1, 0, // handle
1285            0, // role
1286            1, // kind
1287            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // bd_addr
1288            0x10, 0x10, // interval
1289            0x00, 0x00, // latency
1290            0x10, 0x10, // supervision timeout
1291            1,    // accuracy
1292        ];
1293        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1294        assert!(matches!(event.kind, EventKind::Le));
1295        let event = LeEventPacket::from_hci_bytes_complete(event.data).unwrap();
1296        assert!(matches!(
1297            event.kind,
1298            crate::event::le::LeEventKind::LeConnectionComplete
1299        ));
1300        let e = crate::event::le::LeConnectionComplete::from_hci_bytes_complete(event.data).unwrap();
1301
1302        assert_eq!(e.status, Status::SUCCESS);
1303        assert_eq!(e.handle, ConnHandle::new(1));
1304        assert!(matches!(e.central_clock_accuracy, ClockAccuracy::Ppm250));
1305    }
1306
1307    #[test]
1308    fn test_special_command_complete() {
1309        let data = [
1310            0x0e, 3, // header
1311            1, 0, 0, // special command
1312        ];
1313
1314        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1315        assert!(matches!(event.kind, EventKind::CommandComplete));
1316        let event = CommandComplete::from_hci_bytes_complete(event.data).unwrap();
1317        assert_eq!(event.cmd_opcode, Opcode::new(OpcodeGroup::new(0), 0));
1318    }
1319
1320    #[test]
1321    fn test_normal_command_complete() {
1322        let opcode = Opcode::new(OpcodeGroup::LE, 0x000D).to_raw().to_le_bytes();
1323        let data = [
1324            0x0e, 4, // header
1325            1, opcode[0], opcode[1], // special command
1326            0,         // success
1327        ];
1328
1329        let event = EventPacket::from_hci_bytes_complete(&data).unwrap();
1330        assert!(matches!(event.kind, EventKind::CommandComplete));
1331        let event = CommandComplete::from_hci_bytes_complete(event.data).unwrap();
1332        assert_eq!(event.cmd_opcode, Opcode::new(OpcodeGroup::LE, 0x000d));
1333
1334        let event: CommandCompleteWithStatus = event.try_into().unwrap();
1335        assert_eq!(event.cmd_opcode, Opcode::new(OpcodeGroup::LE, 0x000d));
1336        assert_eq!(Status::SUCCESS, event.status);
1337    }
1338}