bluetooth_hci/lib.rs
1//! A Bluetooth implementation for embedded systems.
2//!
3//! This crate is a proof-of-concept implementation of the host (application) side of the
4//! [`Bluetooth`] specification. It is still woefully incomplete, and will undoubtedly be redesigned
5//! completely, and potentially split into multiple crates before being stabilized.
6//!
7//! When the documentation refers to a specific section of "the" Bluetooth specification, the same
8//! section applies for all supported versions of the specification. If the versions differ, the
9//! specific version will also be included in the reference.
10//!
11//! # Design
12//!
13//! Like other core embedded crates (e.g, [`embedded-hal`]), this crate uses traits to be agnostic
14//! about the specific Bluetooth module. It provides a default implementation of the HCI for devices
15//! that implement the core [`Controller`] trait. The traits also make use of the [`nb`] crate to
16//! support different asynchronous or synchronous operation modes.
17//!
18//! ## Commands
19//!
20//! The [`host::Hci`] trait defines all of the functions that communicate from the host to the
21//! controller. The [`host::uart::Hci`] trait defines a read function that returns a
22//! [`host::uart::Packet`], which can contain an [`Event`], `AclData` (TODO), or `SyncData`
23//! (TODO). Both of these traits have default implementations in terms of the [`Controller`], so
24//! calling code does not need to implement any commands or event parsing code.
25//!
26//! ## Vendor-specific commands and events
27//!
28//! The [`host::uart::Hci`] trait requires specialization for the type of vendor-specific events
29//! (which implement [`event::VendorEvent`]) and vendor-specific errors. Any vendor-specific
30//! extensions will need to convert byte buffers into the appropriate event type (as defined by the
31//! vendor), but will not need to read data using the [`Controller`]. The Bluetooth standard
32//! provides packet length in a common header, so only complete packets will be passed on to the
33//! vendor code for deserialization.
34//!
35//! There is not yet support for vendor-specific commands. The vendor crate will have to serialize
36//! the command packets directly and write them to the [`Controller`].
37//!
38//! # Reference implementation
39//!
40//! The [`bluenrg`] crate provides a sample implementation for STMicro's BlueNRG Bluetooth
41//! controllers.
42//!
43//! # Ideas for discussion and improvement
44//!
45//! - Add traits to facilitate writing Bluetooth controllers. These controllers would have a host on
46//! one side and a link layer on the other. Separate crate? If so, move common definitions (Status
47//! codes, opcodes, etc.) to a bluetooth-core crate.
48//!
49//! - Add a helper function for vendor-specific commands. This should take care of creating the
50//! header and writing the data to the [`Controller`]. Vendor code should only be responsible for
51//! serializing commands into byte slices.
52//!
53//! - Remove the `cmd_link` and `event_link` modules, and merge `uart` up into `host`. The Bluetooth
54//! spec made it seem like there were devices that do not include the packet type byte at the
55//! beginning of packets, but STMicro's BlueNRG implementation and Nordic's Zephyr implementation
56//! both include it. If there is a controller that does *not* include the packet type, the
57//! `event_link` HCI can always be brought back.
58//!
59//! - Provide config features for different versions of the Bluetooth Specification.
60//!
61//! - Implement all of the specified functions and events.
62//!
63//! - Provide opt-in config features for certain types of commands and events. For example, BlueNRG
64//! devices only implement 40 commands and 14 events, but the spec has around 250 commands and 76
65//! events. It would be nice if unused events could be compiled out. This would be less important
66//! for commands, since those functions would simply never be called, and could be removed by the
67//! linker. This would entail significant work both on the part of the crate authors and on crate
68//! users, who would need to configure the crate appropriately. All combinations of features would
69//! also never be tested; there are simply too many, even if we only provide features for the
70//! events. On the other hand, those features should not interact, so maybe it would be feasible.
71//!
72//! [`Bluetooth`]: https://www.bluetooth.com/specifications/bluetooth-core-specification
73//! [`embedded-hal`]: https://crates.io/crates/embedded-hal
74//! [`nb`]: https://crates.io/crates/nb
75//! [`bluenrg`]: https://github.com/danielgallagher0/bluenrg
76
77#![no_std]
78#![deny(missing_docs)]
79
80#[macro_use]
81extern crate bitflags;
82extern crate byteorder;
83extern crate nb;
84
85#[macro_use]
86mod bitflag_array;
87
88pub mod event;
89pub mod host;
90mod opcode;
91pub mod types;
92
93pub use event::Event;
94pub use opcode::Opcode;
95
96use core::convert::TryFrom;
97use core::fmt::Debug;
98
99/// Interface to the Bluetooth controller from the host's perspective.
100///
101/// The Bluetooth application host must communicate with a controller (which, in turn, communicates
102/// with the link layer) to control the Bluetooth radio. Device crates must implement this trait,
103/// which enables full access to all of the functions and events of the HCI through [`host::Hci`]
104/// and [`host::uart::Hci`], respectively.
105pub trait Controller {
106 /// Enumeration of [`Controller`] errors. These typically will be specializations of
107 /// [`host::uart::Error`] that specify both the vendor-specific error type _and_ a communication
108 /// error type. The communication error type in turn will depend on the bus used to communicate
109 /// with the controller as well as the device crate (e.g., [`linux-embedded-hal::Spidev`] uses
110 /// [`std::io::Error`]).
111 ///
112 /// [`linux-embedded-hal::Spidev`]:
113 /// https://docs.rs/linux-embedded-hal/0.1.1/linux_embedded_hal/struct.Spidev.html
114 /// [`std::io::Error`]: https://doc.rust-lang.org/nightly/std/io/struct.Error.html
115 type Error;
116
117 /// The type of header sent to the controller for HCI commands. Should be either
118 /// [`host::uart::CommandHeader`], [`host::cmd_link::Header`], or
119 /// [`host::event_link::NoCommands`], depending on the controller implementation.
120 type Header;
121
122 /// Type containing vendor-specific extensions for the controller, including vendor-specific
123 /// errors, events, and status codes.
124 type Vendor: Vendor;
125
126 /// Writes the bytes to the controller, in a single transaction if possible. All of `header`
127 /// shall be written, followed by all of `payload`. `write` is allowed to block internally, but
128 /// should return [`nb::Error::WouldBlock`] if the controller is not ready to receive the data.
129 fn write(&mut self, header: &[u8], payload: &[u8]) -> nb::Result<(), Self::Error>;
130
131 /// Reads data from the controller into the provided `buffer`. The length of the buffer
132 /// indicates the number of bytes to read. The implementor must not return bytes in an order
133 /// different from that in which they were received from the controller. For example, the
134 /// implementor may read all available bytes from the controller and maintain them in an
135 /// internal buffer, but `read_into` shall only read the number of bytes requested.
136 ///
137 /// # Example
138 ///
139 /// ```
140 /// // Controller sends:
141 /// // +------+------+------+------+------+------+------+------+
142 /// // | 0x12 | 0x34 | 0x56 | 0x78 | 0x9a | 0xbc | 0xde | 0xf0 |
143 /// // +------+------+------+------+------+------+------+------+
144 ///
145 /// // host calls:
146 ///
147 /// # extern crate nb;
148 /// # extern crate bluetooth_hci;
149 /// # use bluetooth_hci::Controller as HciController;
150 /// # struct Controller;
151 /// # struct Error;
152 /// # struct Header;
153 /// # struct Vendor;
154 /// # impl bluetooth_hci::Vendor for Vendor {
155 /// # type Status = VendorStatus;
156 /// # type Event = VendorEvent;
157 /// # }
158 /// # #[derive(Clone, Debug)]
159 /// # struct VendorStatus;
160 /// # impl std::convert::TryFrom<u8> for VendorStatus {
161 /// # type Error = bluetooth_hci::BadStatusError;
162 /// # fn try_from(value: u8) -> Result<VendorStatus, Self::Error> {
163 /// # Err(bluetooth_hci::BadStatusError::BadValue(value))
164 /// # }
165 /// # }
166 /// # impl std::convert::Into<u8> for VendorStatus {
167 /// # fn into(self) -> u8 {
168 /// # 0
169 /// # }
170 /// # }
171 /// # struct VendorEvent;
172 /// # impl bluetooth_hci::event::VendorEvent for VendorEvent {
173 /// # type Error = Error;
174 /// # type Status = VendorStatus;
175 /// # type ReturnParameters = ReturnParameters;
176 /// # fn new(_buffer: &[u8]) -> Result<Self, bluetooth_hci::event::Error<Self::Error>>
177 /// # where
178 /// # Self: Sized
179 /// # {
180 /// # Ok(VendorEvent{})
181 /// # }
182 /// # }
183 /// # #[derive(Clone, Debug)]
184 /// # struct ReturnParameters;
185 /// # impl bluetooth_hci::event::VendorReturnParameters for ReturnParameters {
186 /// # type Error = Error;
187 /// # fn new(_buffer: &[u8]) -> Result<Self, bluetooth_hci::event::Error<Self::Error>> {
188 /// # Ok(ReturnParameters{})
189 /// # }
190 /// # }
191 /// # impl HciController for Controller {
192 /// # type Error = Error;
193 /// # type Header = Header;
194 /// # type Vendor = Vendor;
195 /// # fn write(&mut self, _header: &[u8], _payload: &[u8]) -> nb::Result<(), Self::Error> {
196 /// # Ok(())
197 /// # }
198 /// # fn read_into(&mut self, _buffer: &mut [u8]) -> nb::Result<(), Self::Error> {
199 /// # Ok(())
200 /// # }
201 /// # fn peek(&mut self, _n: usize) -> nb::Result<u8, Self::Error> {
202 /// # Ok(0)
203 /// # }
204 /// # }
205 /// # fn main() {
206 /// # let mut controller = Controller;
207 /// let mut buffer = [0; 4];
208 /// controller.read_into(&mut buffer[1..]); // read 3 bytes into buffer[1..]
209 ///
210 /// // buffer contains:
211 /// // +------+------+------+------+
212 /// // | 0x00 | 0x12 | 0x34 | 0x56 |
213 /// // +------+------+------+------+
214 ///
215 /// // now the host calls:
216 /// controller.read_into(&mut buffer); // read 4 bytes into buffer
217 ///
218 /// // buffer contains:
219 /// // +------+------+------+------+
220 /// // | 0x78 | 0x9a | 0xbc | 0xde |
221 /// // +------+------+------+------+
222 /// # }
223 /// ```
224 /// If the next call to `read_into` requests more than 1 byte, the controller may return
225 /// [`nb::Error::WouldBlock`], or may attempt to read more data from the controller. If not
226 /// enough data is available from the controller, the implementor shall return
227 /// [`nb::Error::WouldBlock`].
228 fn read_into(&mut self, buffer: &mut [u8]) -> nb::Result<(), Self::Error>;
229
230 /// Looks ahead at the data coming from the Controller without consuming it. Implementors should
231 /// be able to support values of `n` up to 5 to support all potential data types.
232 ///
233 /// `peek(0)` will typically be used to the the packet type (see Bluetooth Spec, Vol 4, Part A,
234 /// Section 2), which will be followed by another peek to determine the amount of data to
235 /// read. For example, the code to read an HCI event looks like this:
236 ///
237 /// ```
238 /// # extern crate nb;
239 /// # extern crate bluetooth_hci;
240 /// # use bluetooth_hci::Controller as HciController;
241 /// # struct Controller;
242 /// # #[derive(Debug)]
243 /// # struct Error;
244 /// # struct Header;
245 /// # struct Vendor;
246 /// # impl bluetooth_hci::Vendor for Vendor {
247 /// # type Status = VendorStatus;
248 /// # type Event = VendorEvent;
249 /// # }
250 /// # #[derive(Clone, Debug)]
251 /// # struct VendorStatus;
252 /// # impl std::convert::TryFrom<u8> for VendorStatus {
253 /// # type Error = bluetooth_hci::BadStatusError;
254 /// # fn try_from(value: u8) -> Result<VendorStatus, Self::Error> {
255 /// # Err(bluetooth_hci::BadStatusError::BadValue(value))
256 /// # }
257 /// # }
258 /// # impl std::convert::Into<u8> for VendorStatus {
259 /// # fn into(self) -> u8 {
260 /// # 0
261 /// # }
262 /// # }
263 /// # struct VendorEvent;
264 /// # impl bluetooth_hci::event::VendorEvent for VendorEvent {
265 /// # type Error = Error;
266 /// # type Status = VendorStatus;
267 /// # type ReturnParameters = ReturnParameters;
268 /// # fn new(_buffer: &[u8]) -> Result<Self, bluetooth_hci::event::Error<Self::Error>>
269 /// # where
270 /// # Self: Sized
271 /// # {
272 /// # Ok(VendorEvent{})
273 /// # }
274 /// # }
275 /// # #[derive(Clone, Debug)]
276 /// # struct ReturnParameters;
277 /// # impl bluetooth_hci::event::VendorReturnParameters for ReturnParameters {
278 /// # type Error = Error;
279 /// # fn new(_buffer: &[u8]) -> Result<Self, bluetooth_hci::event::Error<Self::Error>> {
280 /// # Ok(ReturnParameters{})
281 /// # }
282 /// # }
283 /// # impl HciController for Controller {
284 /// # type Error = Error;
285 /// # type Header = Header;
286 /// # type Vendor = Vendor;
287 /// # fn write(&mut self, _header: &[u8], _payload: &[u8]) -> nb::Result<(), Self::Error> {
288 /// # Ok(())
289 /// # }
290 /// # fn read_into(&mut self, _buffer: &mut [u8]) -> nb::Result<(), Self::Error> {
291 /// # Ok(())
292 /// # }
293 /// # fn peek(&mut self, _n: usize) -> nb::Result<u8, Self::Error> {
294 /// # Ok(0)
295 /// # }
296 /// # }
297 /// # fn main() -> nb::Result<(), Error> {
298 /// # const PACKET_TYPE_HCI_EVENT: u8 = 4;
299 /// # let mut controller = Controller;
300 /// const MAX_EVENT_LENGTH: usize = 255;
301 /// const HEADER_LENGTH: usize = 2;
302 /// let mut buffer = [0; MAX_EVENT_LENGTH + HEADER_LENGTH];
303 /// let packet_type = controller.peek(0)?;
304 /// if packet_type == PACKET_TYPE_HCI_EVENT {
305 /// // Byte 3 has the parameter length in HCI events
306 /// let param_len = controller.peek(3)? as usize;
307 ///
308 /// // We want to consume the full HCI Event packet, and we now know the length.
309 /// controller.read_into(&mut buffer[..HEADER_LENGTH + param_len])?;
310 /// }
311 /// # Ok(())
312 /// # }
313 /// ```
314 fn peek(&mut self, n: usize) -> nb::Result<u8, Self::Error>;
315}
316
317/// Trait defining vendor-specific extensions for the Bluetooth Controller.
318pub trait Vendor {
319 /// Enumeration of vendor-specific status codes.
320 type Status: TryFrom<u8, Error = BadStatusError> + Into<u8> + Clone + Debug;
321
322 /// Enumeration of vendor-specific events.
323 type Event: event::VendorEvent;
324}
325
326/// List of possible error codes, Bluetooth Spec, Vol 2, Part D, Section 2.
327///
328/// Includes an extension point for vendor-specific status codes.
329#[derive(Copy, Clone, Debug, PartialEq)]
330pub enum Status<V> {
331 /// Success
332 Success,
333 /// Unknown HCI Command
334 UnknownCommand,
335 /// Unknown Connection Identifier
336 UnknownConnectionId,
337 /// Hardware Failure
338 HardwareFailure,
339 /// Page Timeout
340 PageTimeout,
341 /// Authentication Failure
342 AuthFailure,
343 /// PIN or Key Missing
344 PinOrKeyMissing,
345 /// Memory Capacity Exceeded
346 OutOfMemory,
347 /// Connection Timeout
348 ConnectionTimeout,
349 /// Connection Limit Exceeded
350 ConnectionLimitExceeeded,
351 /// Synchronous Connection Limit To A Device Exceeded
352 SyncConnectionLimitExceeded,
353 /// Connection Already Exists
354 ConnectionAlreadyExists,
355 /// Command Disallowed
356 CommandDisallowed,
357 /// Connection Rejected due to Limited Resources
358 LimitedResources,
359 /// Connection Rejected Due To Security Reasons
360 ConnectionRejectedSecurity,
361 /// Connection Rejected due to Unacceptable BD_ADDR
362 UnacceptableBdAddr,
363 /// Connection Accept Timeout Exceeded
364 AcceptTimeoutExceeded,
365 /// Unsupported Feature or Parameter Value
366 UnsupportedFeature,
367 /// Invalid HCI Command Parameters
368 InvalidParameters,
369 /// Remote User Terminated Connection
370 RemoteTerminationByUser,
371 /// Remote Device Terminated Connection due to Low Resources
372 RemoteTerminationLowResources,
373 /// Remote Device Terminated Connection due to Power Off
374 RemoteTerminationPowerOff,
375 /// Connection Terminated By Local Host
376 ConnectionTerminatedByHost,
377 /// Repeated Attempts
378 RepeatedAttempts,
379 /// Pairing Not Allowed
380 PairingNotAllowed,
381 /// Unknown LMP PDU
382 UnknownLmpPdu,
383 /// Unsupported Remote Feature / Unsupported LMP Feature
384 UnsupportedRemoteFeature,
385 /// SCO Offset Rejected
386 ScoOffsetRejected,
387 /// SCO Interval Rejected
388 ScoIntervalRejected,
389 /// SCO Air Mode Rejected
390 ScoAirModeRejected,
391 /// Invalid LMP Parameters / Invalid LL Parameters
392 InvalidLmpParameters,
393 /// Unspecified Error
394 UnspecifiedError,
395 /// Unsupported LMP Parameter Value / Unsupported LL Parameter Value
396 UnsupportedLmpParameterValue,
397 /// Role Change Not Allowed
398 RoleChangeNotAllowed,
399 /// LMP Response Timeout / LL Response Timeout
400 LmpResponseTimeout,
401 /// LMP Error Transaction Collision / LL Procedure Collision
402 LmpTransactionCollision,
403 /// LMP PDU Not Allowed
404 LmpPduNotAllowed,
405 /// Encryption Mode Not Acceptable
406 EncryptionModeNotAcceptable,
407 /// Link Key cannot be Changed
408 LinkKeyCannotBeChanged,
409 /// Requested QoS Not Supported
410 RequestedQosNotSupported,
411 /// Instant Passed
412 InstantPassed,
413 /// Pairing With Unit Key Not Supported
414 PairingWithUnitKeyNotSupported,
415 /// Different Transaction Collision
416 DifferentTransactionCollision,
417 /// Reserved for Future Use
418 ReservedforFutureUse,
419 /// QoS Unacceptable Parameter
420 QosUnacceptableParameter,
421 /// QoS Rejected
422 QosRejected,
423 /// Channel Classification Not Supported
424 ChannelClassificationNotSupported,
425 /// Insufficient Security
426 InsufficientSecurity,
427 /// Parameter Out Of Mandatory Range
428 ParameterOutOfMandatoryRange,
429 /// Reserved for Future Use
430 ReservedForFutureUse49,
431 /// Role Switch Pending
432 RoleSwitchPending,
433 /// Reserved for Future Use
434 ReservedForFutureUse51,
435 /// Reserved Slot Violation
436 ReservedSlotViolation,
437 /// Role Switch Failed
438 RoleSwitchFailed,
439 /// Extended Inquiry Response Too Large
440 ExtendedInquiryResponseTooLarge,
441 /// Secure Simple Pairing Not Supported By Host
442 SecureSimplePairingNotSupportedByHost,
443 /// Host Busy - Pairing
444 HostBusyPairing,
445 /// Connection Rejected due to No Suitable Channel Found
446 ConnectionRejectedNoSuitableChannel,
447 /// Controller Busy
448 ControllerBusy,
449 /// Unacceptable Connection Parameters
450 UnacceptableConnectionParameters,
451 /// Advertising Timeout
452 AdvertisingTimeout,
453 /// Connection Terminated due to MIC Failure
454 ConnectionTerminatedMicFailure,
455 /// Connection Failed to be Established
456 ConnectionFailedToEstablish,
457 /// MAC Connection Failed
458 MacConnectionFailed,
459 /// Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging
460 CoarseClockAdjustmentRejectedDraggingAttempted,
461 #[cfg(feature = "version-5-0")]
462 /// Type0 Submap Not Defined
463 ///
464 /// First introduced in version 5.0
465 Type0SubmapNotDefined,
466 #[cfg(feature = "version-5-0")]
467 /// Unknown Advertising Identifier
468 ///
469 /// First introduced in version 5.0
470 UnknownAdvertisingId,
471 #[cfg(feature = "version-5-0")]
472 /// Limit Reached
473 ///
474 /// First introduced in version 5.0
475 LimitReached,
476 #[cfg(feature = "version-5-0")]
477 /// Operation Cancelled by Host
478 ///
479 /// First introduced in version 5.0
480 OperationCancelledByHost,
481 /// Vendor-specific status code
482 Vendor(V),
483}
484
485/// Wrapper enum for errors converting a u8 into a [`Status`].
486pub enum BadStatusError {
487 /// The value does not map to a [`Status`].
488 BadValue(u8),
489}
490
491impl<V> core::convert::TryFrom<u8> for Status<V>
492where
493 V: core::convert::TryFrom<u8>,
494{
495 type Error = V::Error;
496
497 fn try_from(value: u8) -> Result<Status<V>, Self::Error> {
498 match value {
499 0x00 => Ok(Status::Success),
500 0x01 => Ok(Status::UnknownCommand),
501 0x02 => Ok(Status::UnknownConnectionId),
502 0x03 => Ok(Status::HardwareFailure),
503 0x04 => Ok(Status::PageTimeout),
504 0x05 => Ok(Status::AuthFailure),
505 0x06 => Ok(Status::PinOrKeyMissing),
506 0x07 => Ok(Status::OutOfMemory),
507 0x08 => Ok(Status::ConnectionTimeout),
508 0x09 => Ok(Status::ConnectionLimitExceeeded),
509 0x0A => Ok(Status::SyncConnectionLimitExceeded),
510 0x0B => Ok(Status::ConnectionAlreadyExists),
511 0x0C => Ok(Status::CommandDisallowed),
512 0x0D => Ok(Status::LimitedResources),
513 0x0E => Ok(Status::ConnectionRejectedSecurity),
514 0x0F => Ok(Status::UnacceptableBdAddr),
515 0x10 => Ok(Status::AcceptTimeoutExceeded),
516 0x11 => Ok(Status::UnsupportedFeature),
517 0x12 => Ok(Status::InvalidParameters),
518 0x13 => Ok(Status::RemoteTerminationByUser),
519 0x14 => Ok(Status::RemoteTerminationLowResources),
520 0x15 => Ok(Status::RemoteTerminationPowerOff),
521 0x16 => Ok(Status::ConnectionTerminatedByHost),
522 0x17 => Ok(Status::RepeatedAttempts),
523 0x18 => Ok(Status::PairingNotAllowed),
524 0x19 => Ok(Status::UnknownLmpPdu),
525 0x1A => Ok(Status::UnsupportedRemoteFeature),
526 0x1B => Ok(Status::ScoOffsetRejected),
527 0x1C => Ok(Status::ScoIntervalRejected),
528 0x1D => Ok(Status::ScoAirModeRejected),
529 0x1E => Ok(Status::InvalidLmpParameters),
530 0x1F => Ok(Status::UnspecifiedError),
531 0x20 => Ok(Status::UnsupportedLmpParameterValue),
532 0x21 => Ok(Status::RoleChangeNotAllowed),
533 0x22 => Ok(Status::LmpResponseTimeout),
534 0x23 => Ok(Status::LmpTransactionCollision),
535 0x24 => Ok(Status::LmpPduNotAllowed),
536 0x25 => Ok(Status::EncryptionModeNotAcceptable),
537 0x26 => Ok(Status::LinkKeyCannotBeChanged),
538 0x27 => Ok(Status::RequestedQosNotSupported),
539 0x28 => Ok(Status::InstantPassed),
540 0x29 => Ok(Status::PairingWithUnitKeyNotSupported),
541 0x2A => Ok(Status::DifferentTransactionCollision),
542 0x2B => Ok(Status::ReservedforFutureUse),
543 0x2C => Ok(Status::QosUnacceptableParameter),
544 0x2D => Ok(Status::QosRejected),
545 0x2E => Ok(Status::ChannelClassificationNotSupported),
546 0x2F => Ok(Status::InsufficientSecurity),
547 0x30 => Ok(Status::ParameterOutOfMandatoryRange),
548 0x31 => Ok(Status::ReservedForFutureUse49),
549 0x32 => Ok(Status::RoleSwitchPending),
550 0x33 => Ok(Status::ReservedForFutureUse51),
551 0x34 => Ok(Status::ReservedSlotViolation),
552 0x35 => Ok(Status::RoleSwitchFailed),
553 0x36 => Ok(Status::ExtendedInquiryResponseTooLarge),
554 0x37 => Ok(Status::SecureSimplePairingNotSupportedByHost),
555 0x38 => Ok(Status::HostBusyPairing),
556 0x39 => Ok(Status::ConnectionRejectedNoSuitableChannel),
557 0x3A => Ok(Status::ControllerBusy),
558 0x3B => Ok(Status::UnacceptableConnectionParameters),
559 0x3C => Ok(Status::AdvertisingTimeout),
560 0x3D => Ok(Status::ConnectionTerminatedMicFailure),
561 0x3E => Ok(Status::ConnectionFailedToEstablish),
562 0x3F => Ok(Status::MacConnectionFailed),
563 0x40 => Ok(Status::CoarseClockAdjustmentRejectedDraggingAttempted),
564 0x41 => {
565 #[cfg(feature = "version-5-0")]
566 {
567 Ok(Status::Type0SubmapNotDefined)
568 }
569 #[cfg(not(feature = "version-5-0"))]
570 {
571 Ok(Status::Vendor(V::try_from(value)?))
572 }
573 }
574 0x42 => {
575 #[cfg(feature = "version-5-0")]
576 {
577 Ok(Status::UnknownAdvertisingId)
578 }
579 #[cfg(not(feature = "version-5-0"))]
580 {
581 Ok(Status::Vendor(V::try_from(value)?))
582 }
583 }
584 0x43 => {
585 #[cfg(feature = "version-5-0")]
586 {
587 Ok(Status::LimitReached)
588 }
589 #[cfg(not(feature = "version-5-0"))]
590 {
591 Ok(Status::Vendor(V::try_from(value)?))
592 }
593 }
594 0x44 => {
595 #[cfg(feature = "version-5-0")]
596 {
597 Ok(Status::OperationCancelledByHost)
598 }
599 #[cfg(not(feature = "version-5-0"))]
600 {
601 Ok(Status::Vendor(V::try_from(value)?))
602 }
603 }
604 _ => Ok(Status::Vendor(V::try_from(value)?)),
605 }
606 }
607}
608
609impl<V> core::convert::Into<u8> for Status<V>
610where
611 V: core::convert::Into<u8>,
612{
613 fn into(self) -> u8 {
614 match self {
615 Status::Success => 0x00,
616 Status::UnknownCommand => 0x01,
617 Status::UnknownConnectionId => 0x02,
618 Status::HardwareFailure => 0x03,
619 Status::PageTimeout => 0x04,
620 Status::AuthFailure => 0x05,
621 Status::PinOrKeyMissing => 0x06,
622 Status::OutOfMemory => 0x07,
623 Status::ConnectionTimeout => 0x08,
624 Status::ConnectionLimitExceeeded => 0x09,
625 Status::SyncConnectionLimitExceeded => 0x0A,
626 Status::ConnectionAlreadyExists => 0x0B,
627 Status::CommandDisallowed => 0x0C,
628 Status::LimitedResources => 0x0D,
629 Status::ConnectionRejectedSecurity => 0x0E,
630 Status::UnacceptableBdAddr => 0x0F,
631 Status::AcceptTimeoutExceeded => 0x10,
632 Status::UnsupportedFeature => 0x11,
633 Status::InvalidParameters => 0x12,
634 Status::RemoteTerminationByUser => 0x13,
635 Status::RemoteTerminationLowResources => 0x14,
636 Status::RemoteTerminationPowerOff => 0x15,
637 Status::ConnectionTerminatedByHost => 0x16,
638 Status::RepeatedAttempts => 0x17,
639 Status::PairingNotAllowed => 0x18,
640 Status::UnknownLmpPdu => 0x19,
641 Status::UnsupportedRemoteFeature => 0x1A,
642 Status::ScoOffsetRejected => 0x1B,
643 Status::ScoIntervalRejected => 0x1C,
644 Status::ScoAirModeRejected => 0x1D,
645 Status::InvalidLmpParameters => 0x1E,
646 Status::UnspecifiedError => 0x1F,
647 Status::UnsupportedLmpParameterValue => 0x20,
648 Status::RoleChangeNotAllowed => 0x21,
649 Status::LmpResponseTimeout => 0x22,
650 Status::LmpTransactionCollision => 0x23,
651 Status::LmpPduNotAllowed => 0x24,
652 Status::EncryptionModeNotAcceptable => 0x25,
653 Status::LinkKeyCannotBeChanged => 0x26,
654 Status::RequestedQosNotSupported => 0x27,
655 Status::InstantPassed => 0x28,
656 Status::PairingWithUnitKeyNotSupported => 0x29,
657 Status::DifferentTransactionCollision => 0x2A,
658 Status::ReservedforFutureUse => 0x2B,
659 Status::QosUnacceptableParameter => 0x2C,
660 Status::QosRejected => 0x2D,
661 Status::ChannelClassificationNotSupported => 0x2E,
662 Status::InsufficientSecurity => 0x2F,
663 Status::ParameterOutOfMandatoryRange => 0x30,
664 Status::ReservedForFutureUse49 => 0x31,
665 Status::RoleSwitchPending => 0x32,
666 Status::ReservedForFutureUse51 => 0x33,
667 Status::ReservedSlotViolation => 0x34,
668 Status::RoleSwitchFailed => 0x35,
669 Status::ExtendedInquiryResponseTooLarge => 0x36,
670 Status::SecureSimplePairingNotSupportedByHost => 0x37,
671 Status::HostBusyPairing => 0x38,
672 Status::ConnectionRejectedNoSuitableChannel => 0x39,
673 Status::ControllerBusy => 0x3A,
674 Status::UnacceptableConnectionParameters => 0x3B,
675 Status::AdvertisingTimeout => 0x3C,
676 Status::ConnectionTerminatedMicFailure => 0x3D,
677 Status::ConnectionFailedToEstablish => 0x3E,
678 Status::MacConnectionFailed => 0x3F,
679 Status::CoarseClockAdjustmentRejectedDraggingAttempted => 0x40,
680 _ => {
681 #[cfg(feature = "version-5-0")]
682 {
683 match self {
684 Status::Type0SubmapNotDefined => 0x41,
685 Status::UnknownAdvertisingId => 0x42,
686 Status::LimitReached => 0x43,
687 Status::OperationCancelledByHost => 0x44,
688 Status::Vendor(v) => v.into(),
689 _ => 0xFF,
690 }
691 }
692
693 #[cfg(not(feature = "version-5-0"))]
694 {
695 if let Status::Vendor(v) = self {
696 v.into()
697 } else {
698 0xFF
699 }
700 }
701 }
702 }
703 }
704}
705
706/// Newtype for a connection handle.
707#[derive(Clone, Copy, Debug, PartialEq)]
708pub struct ConnectionHandle(pub u16);
709
710/// Newtype for BDADDR.
711#[derive(Copy, Clone, Debug, PartialEq)]
712pub struct BdAddr(pub [u8; 6]);
713
714/// Potential values for BDADDR
715#[derive(Copy, Clone, Debug, PartialEq)]
716pub enum BdAddrType {
717 /// Public address.
718 Public(BdAddr),
719
720 /// Random address.
721 Random(BdAddr),
722}
723
724impl BdAddrType {
725 /// Writes a `BdAddrType` into the given slice. The slice must be exactly the right length (7
726 /// bytes).
727 pub fn copy_into_slice(&self, bytes: &mut [u8]) {
728 assert_eq!(bytes.len(), 7);
729 match *self {
730 BdAddrType::Public(addr) => {
731 bytes[0] = 0;
732 bytes[1..7].copy_from_slice(&addr.0);
733 }
734 BdAddrType::Random(addr) => {
735 bytes[0] = 1;
736 bytes[1..7].copy_from_slice(&addr.0);
737 }
738 }
739 }
740}
741
742/// The BD Address type is not recognized. Includes the unrecognized byte.
743///
744/// See [`to_bd_addr_type`]
745pub struct BdAddrTypeError(pub u8);
746
747/// Wraps a [`BdAddr`] in a [`BdAddrType`].
748///
749/// # Errors
750///
751/// - `bd_addr_type` does not denote an appropriate type. Returns the byte. The address is
752/// discarded.
753pub fn to_bd_addr_type(bd_addr_type: u8, addr: BdAddr) -> Result<BdAddrType, BdAddrTypeError> {
754 match bd_addr_type {
755 0 => Ok(BdAddrType::Public(addr)),
756 1 => Ok(BdAddrType::Random(addr)),
757 _ => Err(BdAddrTypeError(bd_addr_type)),
758 }
759}
760
761bitflags! {
762 /// Bitfield for LE Remote Features.
763 ///
764 /// Fields are defined in Vol 6, Part B, Section 4.6 of the spec. See Table 4.3 (version 4.1)
765 /// or Table 4.4 (version 4.2 and 5.0).
766 #[derive(Default)]
767 pub struct LinkLayerFeature : u64 {
768 /// See section 4.6.1
769 const LE_ENCRYPTION = 1 << 0;
770 /// See section 4.6.2
771 const CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1 << 1;
772 /// See section 4.6.3
773 const EXTENDED_REJECT_INDICATION = 1 << 2;
774 /// See section 4.6.4
775 const PERIPHERAL_INITIATED_FEATURES_EXCHANGE = 1 << 3;
776 /// See section 4.6.5
777 const LE_PING = 1 << 4;
778 /// See section 4.6.6
779 #[cfg(any(feature = "version-4-2", feature = "version-5-0"))]
780 const LE_DATA_PACKET_LENGTH_EXTENSION = 1 << 5;
781 /// See section 4.6.7
782 #[cfg(any(feature = "version-4-2", feature = "version-5-0"))]
783 const LL_PRIVACY = 1 << 6;
784 /// See section 4.6.8
785 #[cfg(any(feature = "version-4-2", feature = "version-5-0"))]
786 const EXTENDED_SCANNER_FILTER_POLICIES = 1 << 7;
787 /// See section 4.6.9
788 #[cfg(feature = "version-5-0")]
789 const LE_2M_PHY = 1 << 8;
790 /// See section 4.6.10
791 #[cfg(feature = "version-5-0")]
792 const STABLE_MODULATION_INDEX_TX = 1 << 9;
793 /// See section 4.6.11
794 #[cfg(feature = "version-5-0")]
795 const STABLE_MODULATION_INDEX_RX = 1 << 10;
796 /// Not in section 4.6
797 #[cfg(feature = "version-5-0")]
798 const LE_CODED_PHY = 1 << 11;
799 /// See section 4.6.12
800 #[cfg(feature = "version-5-0")]
801 const LE_EXTENDED_ADVERTISING = 1 << 12;
802 /// See section 4.6.13
803 #[cfg(feature = "version-5-0")]
804 const LE_PERIODIC_ADVERTISING = 1 << 13;
805 /// See section 4.6.14
806 #[cfg(feature = "version-5-0")]
807 const CHANNEL_SELECTION_ALGORITHM_2 = 1 << 14;
808 /// Not in section 4.6
809 #[cfg(feature = "version-5-0")]
810 const LE_POWER_CLASS_1 = 1 << 15;
811 /// See section 4.6.15
812 #[cfg(feature = "version-5-0")]
813 const MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE = 1 << 16;
814 }
815}
816
817bitflag_array! {
818 /// Channel classifications for the LE Set Host Channel Classification command.
819 ///
820 /// If a flag is set, its classification is "Unknown". If the flag is cleared, it is known
821 /// "bad".
822 #[derive(Copy, Clone, Debug)]
823 pub struct ChannelClassification : 5;
824 pub struct ChannelFlag;
825
826 /// Channel 0 classification not known.
827 const CH_0 = 0, 1 << 0;
828 /// Channel 1 classification not known.
829 const CH_1 = 0, 1 << 1;
830 /// Channel 2 classification not known.
831 const CH_2 = 0, 1 << 2;
832 /// Channel 3 classification not known.
833 const CH_3 = 0, 1 << 3;
834 /// Channel 4 classification not known.
835 const CH_4 = 0, 1 << 4;
836 /// Channel 5 classification not known.
837 const CH_5 = 0, 1 << 5;
838 /// Channel 6 classification not known.
839 const CH_6 = 0, 1 << 6;
840 /// Channel 7 classification not known.
841 const CH_7 = 0, 1 << 7;
842 /// Channel 8 classification not known.
843 const CH_8 = 1, 1 << 0;
844 /// Channel 9 classification not known.
845 const CH_9 = 1, 1 << 1;
846 /// Channel 10 classification not known.
847 const CH_10 = 1, 1 << 2;
848 /// Channel 11 classification not known.
849 const CH_11 = 1, 1 << 3;
850 /// Channel 12 classification not known.
851 const CH_12 = 1, 1 << 4;
852 /// Channel 13 classification not known.
853 const CH_13 = 1, 1 << 5;
854 /// Channel 14 classification not known.
855 const CH_14 = 1, 1 << 6;
856 /// Channel 15 classification not known.
857 const CH_15 = 1, 1 << 7;
858 /// Channel 16 classification not known.
859 const CH_16 = 2, 1 << 0;
860 /// Channel 17 classification not known.
861 const CH_17 = 2, 1 << 1;
862 /// Channel 18 classification not known.
863 const CH_18 = 2, 1 << 2;
864 /// Channel 19 classification not known.
865 const CH_19 = 2, 1 << 3;
866 /// Channel 20 classification not known.
867 const CH_20 = 2, 1 << 4;
868 /// Channel 21 classification not known.
869 const CH_21 = 2, 1 << 5;
870 /// Channel 22 classification not known.
871 const CH_22 = 2, 1 << 6;
872 /// Channel 23 classification not known.
873 const CH_23 = 2, 1 << 7;
874 /// Channel 24 classification not known.
875 const CH_24 = 3, 1 << 0;
876 /// Channel 25 classification not known.
877 const CH_25 = 3, 1 << 1;
878 /// Channel 26 classification not known.
879 const CH_26 = 3, 1 << 2;
880 /// Channel 27 classification not known.
881 const CH_27 = 3, 1 << 3;
882 /// Channel 28 classification not known.
883 const CH_28 = 3, 1 << 4;
884 /// Channel 29 classification not known.
885 const CH_29 = 3, 1 << 5;
886 /// Channel 30 classification not known.
887 const CH_30 = 3, 1 << 6;
888 /// Channel 31 classification not known.
889 const CH_31 = 3, 1 << 7;
890 /// Channel 32 classification not known.
891 const CH_32 = 4, 1 << 0;
892 /// Channel 33 classification not known.
893 const CH_33 = 4, 1 << 1;
894 /// Channel 34 classification not known.
895 const CH_34 = 4, 1 << 2;
896 /// Channel 35 classification not known.
897 const CH_35 = 4, 1 << 3;
898 /// Channel 36 classification not known.
899 const CH_36 = 4, 1 << 4;
900}