bluenrg 0.1.0

Interface to ST Micro BlueNRG Bluetooth radios
Documentation
//! Vendor-specific events for BlueNRG controllers.
//!
//! The BlueNRG implementation defines several additional events that are packaged as
//! vendor-specific events by the Bluetooth HCI. This module defines those events and functions to
//! deserialize buffers into them.
extern crate bluetooth_hci as hci;

pub mod command;

use byteorder::{ByteOrder, LittleEndian};
use core::cmp::PartialEq;
use core::convert::{TryFrom, TryInto};
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::mem;
use core::time::Duration;

pub use hci::types::{ConnectionInterval, ConnectionIntervalError};
pub use hci::{BdAddr, BdAddrType, ConnectionHandle};

/// Vendor-specific events for the BlueNRG-MS controllers.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Copy, Debug)]
pub enum BlueNRGEvent {
    /// When the BlueNRG-MS firmware is started normally, it gives this event to the user to
    /// indicate the system has started.
    HalInitialized(ResetReason),

    /// If the host fails to read events from the controller quickly enough, the controller will
    /// generate this event. This event is never lost; it is inserted as soon as space is available
    /// in the Tx queue.
    #[cfg(feature = "ms")]
    EventsLost(EventFlags),

    /// The fault data event is automatically sent after the
    /// [HalInitialized](BlueNRGEvent::HalInitialized) event in case of [NMI or Hard
    /// fault](ResetReason::Crash).
    #[cfg(feature = "ms")]
    CrashReport(FaultData),

    /// This event is generated by the controller when the limited discoverable mode ends due to
    /// timeout (180 seconds).
    GapLimitedDiscoverableTimeout,

    /// This event is generated when the pairing process has completed successfully or a pairing
    /// procedure timeout has occurred or the pairing has failed.  This is to notify the application
    /// that we have paired with a remote device so that it can take further actions or to notify
    /// that a timeout has occurred so that the upper layer can decide to disconnect the link.
    GapPairingComplete(GapPairingComplete),

    /// This event is generated by the Security manager to the application when a pass key is
    /// required for pairing.  When this event is received, the application has to respond with the
    /// `gap_pass_key_response` command.
    GapPassKeyRequest(ConnectionHandle),

    /// This event is generated by the Security manager to the application when the application has
    /// set that authorization is required for reading/writing of attributes. This event will be
    /// generated as soon as the pairing is complete. When this event is received,
    /// `gap_authorization_response` command should be used by the application.
    GapAuthorizationRequest(ConnectionHandle),

    /// This event is generated when the peripheral security request is successfully sent to the
    /// central device.
    GapPeripheralSecurityInitiated,

    /// This event is generated on the peripheral when a `gap_peripheral_security_request` is called
    /// to reestablish the bond with the central device but the central device has lost the
    /// bond. When this event is received, the upper layer has to issue the command
    /// `gap_allow_rebond` in order to allow the peripheral to continue the pairing process with the
    /// central device. On the central device, this event is raised when `gap_send_pairing_request`
    /// is called to reestablish a bond with a peripheral but the peripheral has lost the bond. In
    /// order to create a new bond the central device has to launch `gap_send_pairing_request` with
    /// `force_rebond` set to `true`.
    GapBondLost,

    /// The event is given by the GAP layer to the upper layers when a device is discovered during
    /// scanning as a consequence of one of the GAP procedures started by the upper layers.
    GapDeviceFound(GapDeviceFound),

    /// This event is sent by the GAP to the upper layers when a procedure previously started has
    /// been terminated by the upper layer or has completed for any other reason
    GapProcedureComplete(GapProcedureComplete),

    /// This event is sent only by a privacy enabled peripheral. The event is sent to the upper
    /// layers when the peripheral is unsuccessful in resolving the resolvable address of the peer
    /// device after connecting to it.
    #[cfg(feature = "ms")]
    GapAddressNotResolved(ConnectionHandle),

    /// This event is generated when the reconnection address is generated during the general
    /// connection establishment procedure. The same address is set to the peer device also as a
    /// part of the general connection establishment procedure. In order to make use of the
    /// reconnection address the next time while connecting to the bonded peripheral, the
    /// application needs to set its own address as well as the peer address to which it wants to
    /// connect to this reconnection address.
    #[cfg(not(feature = "ms"))]
    GapReconnectionAddress(BdAddr),

    /// This event is generated when the central device responds to the L2CAP connection update
    /// request packet. For more info see
    /// [ConnectionParameterUpdateResponse](crate::l2cap::ConnectionParameterUpdateResponse)
    /// and CommandReject in Bluetooth Core v4.0 spec.
    L2CapConnectionUpdateResponse(L2CapConnectionUpdateResponse),

    /// This event is generated when the central device does not respond to the connection update
    /// request within 30 seconds.
    L2CapProcedureTimeout(ConnectionHandle),

    /// The event is given by the L2CAP layer when a connection update request is received from the
    /// peripheral. The application has to respond by calling
    /// [`l2cap_connection_parameter_update_response`](crate::l2cap::Commands::connection_parameter_update_response).
    L2CapConnectionUpdateRequest(L2CapConnectionUpdateRequest),

    /// This event is generated to the application by the ATT server when a client modifies any
    /// attribute on the server, as consequence of one of the following ATT procedures:
    /// - write without response
    /// - signed write without response
    /// - write characteristic value
    /// - write long characteristic value
    /// - reliable write
    GattAttributeModified(GattAttributeModified),

    /// This event is generated when a ATT client procedure completes either with error or
    /// successfully.
    GattProcedureTimeout(ConnectionHandle),

    /// This event is generated in response to an Exchange MTU request.
    AttExchangeMtuResponse(AttExchangeMtuResponse),

    /// This event is generated in response to a Find Information Request. See Find Information
    /// Response in Bluetooth Core v4.0 spec.
    AttFindInformationResponse(AttFindInformationResponse),

    /// This event is generated in response to a Find By Type Value Request.
    AttFindByTypeValueResponse(AttFindByTypeValueResponse),

    /// This event is generated in response to a Read by Type Request.
    AttReadByTypeResponse(AttReadByTypeResponse),

    /// This event is generated in response to a Read Request.
    AttReadResponse(AttReadResponse),

    /// This event is generated in response to a Read Blob Request. The value in the response is the
    /// partial value starting from the offset in the request. See the Bluetooth Core v4.1 spec, Vol
    /// 3, section 3.4.4.5 and 3.4.4.6.
    AttReadBlobResponse(AttReadResponse),

    /// This event is generated in response to a Read Multiple Request. The value in the response is
    /// the set of values requested from the request. See the Bluetooth Core v4.1 spec, Vol 3,
    /// section 3.4.4.7 and 3.4.4.8.
    AttReadMultipleResponse(AttReadResponse),

    /// This event is generated in response to a Read By Group Type Request. See the Bluetooth Core
    /// v4.1 spec, Vol 3, section 3.4.4.9 and 3.4.4.10.
    AttReadByGroupTypeResponse(AttReadByGroupTypeResponse),

    /// This event is generated in response to a Prepare Write Request. See the Bluetooth Core v4.1
    /// spec, Vol 3, Part F, section 3.4.6.1 and 3.4.6.2
    AttPrepareWriteResponse(AttPrepareWriteResponse),

    /// This event is generated in response to an Execute Write Request. See the Bluetooth Core v4.1
    /// spec, Vol 3, Part F, section 3.4.6.3 and 3.4.6.4
    AttExecuteWriteResponse(ConnectionHandle),

    /// This event is generated when an indication is received from the server.
    GattIndication(AttributeValue),

    /// This event is generated when an notification is received from the server.
    GattNotification(AttributeValue),

    /// This event is generated when a GATT client procedure completes either with error or
    /// successfully.
    GattProcedureComplete(GattProcedureComplete),

    /// This event is generated when an Error Response is received from the server. The error
    /// response can be given by the server at the end of one of the GATT discovery procedures. This
    /// does not mean that the procedure ended with an error, but this error event is part of the
    /// procedure itself.
    AttErrorResponse(AttErrorResponse),

    /// This event can be generated during a "Discover Characteristics by UUID" procedure or a "Read
    /// using Characteristic UUID" procedure. The attribute value will be a service declaration as
    /// defined in Bluetooth Core v4.0 spec, Vol 3, Part G, section 3.3.1), when a "Discover
    /// Characteristics By UUID" has been started. It will be the value of the Characteristic if a
    /// "Read using Characteristic UUID" has been performed.
    ///
    /// See the Bluetooth Core v4.1 spec, Vol 3, Part G, section 4.6.2 (discover characteristics by
    /// UUID), and section 4.8.2 (read using characteristic using UUID).
    GattDiscoverOrReadCharacteristicByUuidResponse(AttributeValue),

    /// This event is given to the application when a write request, write command or signed write
    /// command is received by the server from the client. This event will be given to the
    /// application only if the event bit for this event generation is set when the characteristic
    /// was added. When this event is received, the application has to check whether the value being
    /// requested for write is allowed to be written and respond with a GATT Write Response. If the
    /// write is rejected by the application, then the value of the attribute will not be
    /// modified. In case of a write request, an error response will be sent to the client, with the
    /// error code as specified by the application. In case of write/signed write commands, no
    /// response is sent to the client but the attribute is not modified.
    ///
    /// See the Bluetooth Core v4.1 spec, Vol 3, Part F, section 3.4.5.
    AttWritePermitRequest(AttributeValue),

    /// This event is given to the application when a read request or read blob request is received
    /// by the server from the client. This event will be given to the application only if the event
    /// bit for this event generation is set when the characteristic was added. On receiving this
    /// event, the application can update the value of the handle if it desires and when done it has
    /// to use the [`allow_read`](crate::gatt::Commands::allow_read) command to indicate to the
    /// stack that it can send the response to the client.
    ///
    /// See the Bluetooth Core v4.1 spec, Vol 3, Part F, section 3.4.4.
    AttReadPermitRequest(AttReadPermitRequest),

    /// This event is given to the application when a read multiple request or read by type request
    /// is received by the server from the client. This event will be given to the application only
    /// if the event bit for this event generation is set when the characteristic was added.  On
    /// receiving this event, the application can update the values of the handles if it desires and
    /// when done it has to send the [`allow_read`](crate::gatt::Commands::allow_read) command to
    /// indicate to the stack that it can send the response to the client.
    ///
    /// See the Bluetooth Core v4.1 spec, Vol 3, Part F, section 3.4.4.
    AttReadMultiplePermitRequest(AttReadMultiplePermitRequest),

    /// This event is raised when the number of available TX buffers is above a threshold TH (TH =
    /// 2).  The event will be given only if a previous ACI command returned with
    /// [InsufficientResources](AttError::InsufficientResources).  On receiving this event, the
    /// application can continue to send notifications by calling `gatt_update_char_value`.
    #[cfg(feature = "ms")]
    GattTxPoolAvailable(GattTxPoolAvailable),

    /// This event is raised on the server when the client confirms the reception of an indication.
    #[cfg(feature = "ms")]
    GattServerConfirmation(ConnectionHandle),

    /// This event is given to the application when a prepare write request is received by the
    /// server from the client. This event will be given to the application only if the event bit
    /// for this event generation is set when the characteristic was added.  When this event is
    /// received, the application has to check whether the value being requested for write is
    /// allowed to be written and respond with the command `gatt_write_response`.  Based on the
    /// response from the application, the attribute value will be modified by the stack.  If the
    /// write is rejected by the application, then the value of the attribute will not be modified
    /// and an error response will be sent to the client, with the error code as specified by the
    /// application.
    #[cfg(feature = "ms")]
    AttPrepareWritePermitRequest(AttPrepareWritePermitRequest),
}

/// Enumeration of vendor-specific status codes.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum Status {
    /// The command cannot be executed due to the current state of the device.
    Failed = 0x41,
    /// Some parameters are invalid.
    InvalidParameters = 0x42,
    /// It is not allowed to start the procedure (e.g. another the procedure is ongoing or cannot be
    /// started on the given handle).
    NotAllowed = 0x46,
    /// Unexpected error.
    Error = 0x47,
    /// The address was not resolved.
    AddressNotResolved = 0x48,
    /// Failed to read from flash.
    FlashReadFailed = 0x49,
    /// Failed to write to flash.
    FlashWriteFailed = 0x4A,
    /// Failed to erase flash.
    FlashEraseFailed = 0x4B,
    /// Invalid CID
    InvalidCid = 0x50,
    /// Timer is not valid
    TimerNotValidLayer = 0x54,
    /// Insufficient resources to create the timer
    TimerInsufficientResources = 0x55,
    /// Connection signature resolving key (CSRK) is not found.
    CsrkNotFound = 0x5A,
    /// Identity resolving key (IRK) is not found
    IrkNotFound = 0x5B,
    /// The device is not in the security database.
    DeviceNotFoundInDatabase = 0x5C,
    /// The security database is full.
    SecurityDatabaseFull = 0x5D,
    /// The device is not bonded.
    DeviceNotBonded = 0x5E,
    /// The device is blacklisted.
    DeviceInBlacklist = 0x5F,
    /// The handle (service, characteristic, or descriptor) is invalid.
    InvalidHandle = 0x60,
    /// A parameter is invalid
    InvalidParameter = 0x61,
    /// The characteristic handle is not part of the service.
    OutOfHandle = 0x62,
    /// The operation is invalid
    InvalidOperation = 0x63,
    /// Insufficient resources to complete the operation.
    InsufficientResources = 0x64,
    /// The encryption key size is too small
    InsufficientEncryptionKeySize = 0x65,
    /// The characteristic already exists.
    CharacteristicAlreadyExists = 0x66,
    /// Returned when no valid slots are available (e.g. when there are no available state
    /// machines).
    NoValidSlot = 0x82,
    /// Returned when a scan window shorter than minimum allowed value has been requested
    /// (i.e. 2ms). The Rust API should prevent this error from occurring.
    ScanWindowTooShort = 0x83,
    /// Returned when the maximum requested interval to be allocated is shorter then the current
    /// anchor period and a there is no submultiple for the current anchor period that is between
    /// the minimum and the maximum requested intervals.
    NewIntervalFailed = 0x84,
    /// Returned when the maximum requested interval to be allocated is greater than the current
    /// anchor period and there is no multiple of the anchor period that is between the minimum and
    /// the maximum requested intervals.
    IntervalTooLarge = 0x85,
    /// Returned when the current anchor period or a new one can be found that is compatible to the
    /// interval range requested by the new slot but the maximum available length that can be
    /// allocated is less than the minimum requested slot length.
    LengthFailed = 0x86,
    /// MCU Library timed out.
    Timeout = 0xFF,
    /// MCU library: profile already initialized.
    ProfileAlreadyInitialized = 0xF0,
    /// MCU library: A parameter was null.
    NullParameter = 0xF1,
}

impl TryFrom<u8> for Status {
    type Error = hci::BadStatusError;

    fn try_from(value: u8) -> Result<Self, <Self as TryFrom<u8>>::Error> {
        match value {
            0x41 => Ok(Status::Failed),
            0x42 => Ok(Status::InvalidParameters),
            0x46 => Ok(Status::NotAllowed),
            0x47 => Ok(Status::Error),
            0x48 => Ok(Status::AddressNotResolved),
            0x49 => Ok(Status::FlashReadFailed),
            0x4A => Ok(Status::FlashWriteFailed),
            0x4B => Ok(Status::FlashEraseFailed),
            0x50 => Ok(Status::InvalidCid),
            0x54 => Ok(Status::TimerNotValidLayer),
            0x55 => Ok(Status::TimerInsufficientResources),
            0x5A => Ok(Status::CsrkNotFound),
            0x5B => Ok(Status::IrkNotFound),
            0x5C => Ok(Status::DeviceNotFoundInDatabase),
            0x5D => Ok(Status::SecurityDatabaseFull),
            0x5E => Ok(Status::DeviceNotBonded),
            0x5F => Ok(Status::DeviceInBlacklist),
            0x60 => Ok(Status::InvalidHandle),
            0x61 => Ok(Status::InvalidParameter),
            0x62 => Ok(Status::OutOfHandle),
            0x63 => Ok(Status::InvalidOperation),
            0x64 => Ok(Status::InsufficientResources),
            0x65 => Ok(Status::InsufficientEncryptionKeySize),
            0x66 => Ok(Status::CharacteristicAlreadyExists),
            0x82 => Ok(Status::NoValidSlot),
            0x83 => Ok(Status::ScanWindowTooShort),
            0x84 => Ok(Status::NewIntervalFailed),
            0x85 => Ok(Status::IntervalTooLarge),
            0x86 => Ok(Status::LengthFailed),
            0xFF => Ok(Status::Timeout),
            0xF0 => Ok(Status::ProfileAlreadyInitialized),
            0xF1 => Ok(Status::NullParameter),
            _ => Err(hci::BadStatusError::BadValue(value)),
        }
    }
}

impl Into<u8> for Status {
    fn into(self) -> u8 {
        self as u8
    }
}

/// Enumeration of potential errors when sending commands or deserializing events.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BlueNRGError {
    /// The event is not recoginized. Includes the unknown opcode.
    UnknownEvent(u16),

    /// For the [HalInitialized](BlueNRGEvent::HalInitialized) event: the reset reason was not
    /// recognized. Includes the unrecognized byte.
    UnknownResetReason(u8),

    /// For the [EventsLost](BlueNRGEvent::EventsLost) event: The event included unrecognized event
    /// flags. Includes the entire bitfield.
    #[cfg(feature = "ms")]
    BadEventFlags(u64),

    /// For the [CrashReport](BlueNRGEvent::CrashReport) event: The crash reason was not
    /// recognized. Includes the unrecognized byte.
    #[cfg(feature = "ms")]
    UnknownCrashReason(u8),

    /// For the [GAP Pairing Complete](BlueNRGEvent::GapPairingComplete) event: The status was not
    /// recognized. Includes the unrecognized byte.
    BadGapPairingStatus(u8),

    /// For the [GAP Device Found](BlueNRGEvent::GapDeviceFound) event: the type of event was not
    /// recognized. Includes the unrecognized byte.
    BadGapDeviceFoundEvent(u8),

    /// For the [GAP Device Found](BlueNRGEvent::GapDeviceFound) event: the type of BDADDR was not
    /// recognized. Includes the unrecognized byte.
    BadGapBdAddrType(u8),

    /// For the [GAP Procedure Complete](BlueNRGEvent::GapProcedureComplete) event: The procedure
    /// code was not recognized. Includes the unrecognized byte.
    BadGapProcedure(u8),

    /// For the [GAP Procedure Complete](BlueNRGEvent::GapProcedureComplete) event: The procedure
    /// status was not recognized. Includes the unrecognized byte.
    BadGapProcedureStatus(u8),

    /// For any L2CAP event: The event data length did not match the expected length. The first
    /// field is the required length, and the second is the actual length.
    BadL2CapDataLength(u8, u8),

    /// For any L2CAP event: The L2CAP length did not match the expected length. The first field is
    /// the required length, and the second is the actual length.
    BadL2CapLength(u16, u16),

    /// For any L2CAP response event: The L2CAP command was rejected, but the rejection reason was
    /// not recognized. Includes the unknown value.
    BadL2CapRejectionReason(u16),

    /// For the [L2CAP Connection Update Response](BlueNRGEvent::L2CapConnectionUpdateResponse)
    /// event: The code byte did not indicate either Rejected or Updated. Includes the invalid byte.
    BadL2CapConnectionResponseCode(u8),

    /// For the [L2CAP Connection Update Response](BlueNRGEvent::L2CapConnectionUpdateResponse)
    /// event: The command was accepted, but the result was not recognized. It did not indicate the
    /// parameters were either updated or rejected. Includes the unknown value.
    BadL2CapConnectionResponseResult(u16),

    /// For the [L2CAP Connection Update Request](BlueNRGEvent::L2CapConnectionUpdateRequest) event:
    /// The provided connection interval is invalid. Includes the underlying error.
    BadConnectionInterval(ConnectionIntervalError),

    /// For the [L2CAP Connection Update Request](BlueNRGEvent::L2CapConnectionUpdateRequest) event:
    /// The provided interval is invalid. Potential errors:
    /// - Either the minimum or maximum is out of range. The minimum value for either is 7.5 ms, and
    ///   the maximum is 4 s.
    /// - The min is greater than the max
    ///
    /// See the Bluetooth specification, Vol 3, Part A, Section 4.20. Versions 4.1, 4.2 and 5.0.
    ///
    /// Inclues the provided minimum and maximum, respectively.
    BadL2CapConnectionUpdateRequestInterval(Duration, Duration),

    /// For the [L2CAP Connection Update Request](BlueNRGEvent::L2CapConnectionUpdateRequest) event:
    /// The provided connection latency is invalid. The maximum value for connection latency is
    /// defined in terms of the timeout and maximum connection interval.
    /// - `connIntervalMax = Interval Max`
    /// - `connSupervisionTimeout = Timeout`
    /// - `maxConnLatency = min(500, ((connSupervisionTimeout / (2 * connIntervalMax)) - 1))`
    ///
    /// See the Bluetooth specification, Vol 3, Part A, Section 4.20. Versions 4.1, 4.2 and 5.0.
    ///
    /// Inclues the provided value and maximum allowed value, respectively.
    BadL2CapConnectionUpdateRequestLatency(u16, u16),

    /// For the [L2CAP Connection Update Request](BlueNRGEvent::L2CapConnectionUpdateRequest) event:
    /// The provided timeout is invalid. The timeout field shall have a value in the range of 100 ms
    /// to 32 seconds (inclusive).
    ///
    /// See the Bluetooth specification, Vol 3, Part A, Section 4.20. Versions 4.1, 4.2 and 5.0.
    ///
    /// Inclues the provided value.
    BadL2CapConnectionUpdateRequestTimeout(Duration),

    /// For the [ATT Find Information Response](BlueNRGEvent::AttFindInformationResponse) event: The
    /// format code is invalid. Includes the unrecognized byte.
    BadAttFindInformationResponseFormat(u8),

    /// For the [ATT Find Information Response](BlueNRGEvent::AttFindInformationResponse) event: The
    /// format code indicated 16-bit UUIDs, but the packet ends with a partial pair.
    AttFindInformationResponsePartialPair16,

    /// For the [ATT Find Information Response](BlueNRGEvent::AttFindInformationResponse) event: The
    /// format code indicated 128-bit UUIDs, but the packet ends with a partial pair.
    AttFindInformationResponsePartialPair128,

    /// For the [ATT Find by Type Value Response](BlueNRGEvent::AttFindByTypeValueResponse) event:
    /// The packet ends with a partial attribute pair.
    AttFindByTypeValuePartial,

    /// For the [ATT Read by Type Response](BlueNRGEvent::AttReadByTypeResponse) event: The packet
    /// ends with a partial attribute handle-value pair.
    AttReadByTypeResponsePartial,

    /// For the [ATT Read by Group Type Response](BlueNRGEvent::AttReadByGroupTypeResponse) event:
    /// The packet ends with a partial attribute data group.
    AttReadByGroupTypeResponsePartial,

    /// For the [GATT Procedure Complete](BlueNRGEvent::GattProcedureComplete) event: The status
    /// code was not recognized. Includes the unrecognized byte.
    BadGattProcedureStatus(u8),

    /// For the [ATT Error Response](BlueNRGEvent::AttErrorResponse) event: The request opcode was
    /// not recognized. Includes the unrecognized byte.
    BadAttRequestOpcode(u8),

    /// For the [ATT Error Response](BlueNRGEvent::AttErrorResponse) event: The error code was not
    /// recognized. Includes the unrecognized byte.
    BadAttError(u8),

    /// For the [ATT Read Multiple Permit Request](BlueNRGEvent::AttReadMultiplePermitRequest)
    /// event: The packet ends with a partial attribute handle.
    AttReadMultiplePermitRequestPartial,

    /// For the [HAL Read Config Data](crate::hal::Commands::read_config_data) command complete
    /// [event](command::ReturnParameters::HalReadConfigData): The returned value has a length that
    /// does not correspond to a requested parameter. Known lengths are 1, 2, 6, or 16. Includes the
    /// number of bytes returned.
    BadConfigParameterLength(usize),

    /// For the [HAL Get Link Status](crate::hal::Commands::get_link_status) command complete
    /// [event](command::ReturnParameters::HalGetLinkStatus): One of the bytes representing a link
    /// state does not represent a known link state. Returns the unknown value.
    UnknownLinkState(u8),

    /// For the [GAP Get Security Level](crate::gap::Commands::get_security_level) command complete
    /// [event](command::ReturnParameters::GapGetSecurityLevel): One of the boolean values
    /// ([`mitm_protection_required`](command::GapSecurityLevel::mitm_protection_required),
    /// [`bonding_required`](command::GapSecurityLevel::bonding_required), or
    /// [`out_of_band_data_present`](command::GapSecurityLevel::out_of_band_data_present)) was
    /// neither 0 nor 1. The unknown value is provided.
    BadBooleanValue(u8),

    /// For the [GAP Get Security Level](crate::gap::Commands::get_security_level) command complete
    /// [event](command::ReturnParameters::GapGetSecurityLevel): the pass key requirement field was
    /// an invalid value. The unknown byte is provided.
    BadPassKeyRequirement(u8),

    /// For the [GAP Get Bonded Devices](crate::gap::Commands::get_bonded_devices) command complete
    /// [event](command::ReturnParameters::GapGetBondedDevices): the packat was not long enough to
    /// contain the number of addresses it claimed to contain.
    PartialBondedDeviceAddress,

    /// For the [GAP Get Bonded Devices](crate::gap::Commands::get_bonded_devices) command complete
    /// [event](command::ReturnParameters::GapGetBondedDevices): one of the address type bytes was
    /// invalid. Includes the invalid byte.
    BadBdAddrType(u8),
}

macro_rules! require_len {
    ($left:expr, $right:expr) => {
        if $left.len() != $right {
            return Err(hci::event::Error::BadLength($left.len(), $right));
        }
    };
}

macro_rules! require_len_at_least {
    ($left:expr, $right:expr) => {
        if $left.len() < $right {
            return Err(hci::event::Error::BadLength($left.len(), $right));
        }
    };
}

fn first_16<T>(buffer: &[T]) -> &[T] {
    if buffer.len() < 16 {
        &buffer
    } else {
        &buffer[..16]
    }
}

impl hci::event::VendorEvent for BlueNRGEvent {
    type Error = BlueNRGError;
    type ReturnParameters = command::ReturnParameters;
    type Status = Status;

    fn new(buffer: &[u8]) -> Result<Self, hci::event::Error<BlueNRGError>> {
        require_len_at_least!(buffer, 2);

        let event_code = LittleEndian::read_u16(&buffer[0..=1]);
        match event_code {
            0x0001 => Ok(BlueNRGEvent::HalInitialized(to_hal_initialized(buffer)?)),
            0x0002 => {
                #[cfg(feature = "ms")]
                {
                    Ok(BlueNRGEvent::EventsLost(to_lost_event(buffer)?))
                }

                #[cfg(not(feature = "ms"))]
                {
                    Err(hci::event::Error::Vendor(BlueNRGError::UnknownEvent(
                        event_code,
                    )))
                }
            }
            0x0003 => {
                #[cfg(feature = "ms")]
                {
                    Ok(BlueNRGEvent::CrashReport(to_crash_report(buffer)?))
                }

                #[cfg(not(feature = "ms"))]
                {
                    Err(hci::event::Error::Vendor(BlueNRGError::UnknownEvent(
                        event_code,
                    )))
                }
            }
            0x0400 => Ok(BlueNRGEvent::GapLimitedDiscoverableTimeout),
            0x0401 => Ok(BlueNRGEvent::GapPairingComplete(to_gap_pairing_complete(
                buffer,
            )?)),
            0x0402 => Ok(BlueNRGEvent::GapPassKeyRequest(to_conn_handle(buffer)?)),
            0x0403 => Ok(BlueNRGEvent::GapAuthorizationRequest(to_conn_handle(
                buffer,
            )?)),
            0x0404 => Ok(BlueNRGEvent::GapPeripheralSecurityInitiated),
            0x0405 => Ok(BlueNRGEvent::GapBondLost),
            0x0406 => Ok(BlueNRGEvent::GapDeviceFound(to_gap_device_found(buffer)?)),
            0x0407 => Ok(BlueNRGEvent::GapProcedureComplete(
                to_gap_procedure_complete(buffer)?,
            )),
            0x0408 => {
                #[cfg(feature = "ms")]
                {
                    Ok(BlueNRGEvent::GapAddressNotResolved(to_conn_handle(buffer)?))
                }

                #[cfg(not(feature = "ms"))]
                {
                    Ok(BlueNRGEvent::GapReconnectionAddress(
                        to_gap_reconnection_address(buffer)?,
                    ))
                }
            }
            0x0800 => Ok(BlueNRGEvent::L2CapConnectionUpdateResponse(
                to_l2cap_connection_update_response(buffer)?,
            )),
            0x0801 => Ok(BlueNRGEvent::L2CapProcedureTimeout(
                to_l2cap_procedure_timeout(buffer)?,
            )),
            0x0802 => Ok(BlueNRGEvent::L2CapConnectionUpdateRequest(
                to_l2cap_connection_update_request(buffer)?,
            )),
            0x0C01 => Ok(BlueNRGEvent::GattAttributeModified(
                to_gatt_attribute_modified(buffer)?,
            )),
            0x0C02 => Ok(BlueNRGEvent::GattProcedureTimeout(to_conn_handle(buffer)?)),
            0x0C03 => Ok(BlueNRGEvent::AttExchangeMtuResponse(
                to_att_exchange_mtu_resp(buffer)?,
            )),
            0x0C04 => Ok(BlueNRGEvent::AttFindInformationResponse(
                to_att_find_information_response(buffer)?,
            )),
            0x0C05 => Ok(BlueNRGEvent::AttFindByTypeValueResponse(
                to_att_find_by_value_type_response(buffer)?,
            )),
            0x0C06 => Ok(BlueNRGEvent::AttReadByTypeResponse(
                to_att_read_by_type_response(buffer)?,
            )),
            0x0C07 => Ok(BlueNRGEvent::AttReadResponse(to_att_read_response(buffer)?)),
            0x0C08 => Ok(BlueNRGEvent::AttReadBlobResponse(to_att_read_response(
                buffer,
            )?)),
            0x0C09 => Ok(BlueNRGEvent::AttReadMultipleResponse(to_att_read_response(
                buffer,
            )?)),
            0x0C0A => Ok(BlueNRGEvent::AttReadByGroupTypeResponse(
                to_att_read_by_group_type_response(buffer)?,
            )),
            0x0C0C => Ok(BlueNRGEvent::AttPrepareWriteResponse(
                to_att_prepare_write_response(buffer)?,
            )),
            0x0C0D => Ok(BlueNRGEvent::AttExecuteWriteResponse(to_conn_handle(
                buffer,
            )?)),
            0x0C0E => Ok(BlueNRGEvent::GattIndication(to_attribute_value(buffer)?)),
            0x0C0F => Ok(BlueNRGEvent::GattNotification(to_attribute_value(buffer)?)),
            0x0C10 => Ok(BlueNRGEvent::GattProcedureComplete(
                to_gatt_procedure_complete(buffer)?,
            )),
            0x0C11 => Ok(BlueNRGEvent::AttErrorResponse(to_att_error_response(
                buffer,
            )?)),
            0x0C12 => Ok(
                BlueNRGEvent::GattDiscoverOrReadCharacteristicByUuidResponse(to_attribute_value(
                    buffer,
                )?),
            ),
            0x0C13 => Ok(BlueNRGEvent::AttWritePermitRequest(
                to_write_permit_request(buffer)?,
            )),
            0x0C14 => Ok(BlueNRGEvent::AttReadPermitRequest(
                to_att_read_permit_request(buffer)?,
            )),
            0x0C15 => Ok(BlueNRGEvent::AttReadMultiplePermitRequest(
                to_att_read_multiple_permit_request(buffer)?,
            )),
            0x0C16 => {
                #[cfg(feature = "ms")]
                {
                    Ok(BlueNRGEvent::GattTxPoolAvailable(
                        to_gatt_tx_pool_available(buffer)?,
                    ))
                }

                #[cfg(not(feature = "ms"))]
                {
                    Err(hci::event::Error::Vendor(BlueNRGError::UnknownEvent(
                        event_code,
                    )))
                }
            }
            0x0C17 => {
                #[cfg(feature = "ms")]
                {
                    Ok(BlueNRGEvent::GattServerConfirmation(to_conn_handle(
                        buffer,
                    )?))
                }

                #[cfg(not(feature = "ms"))]
                {
                    Err(hci::event::Error::Vendor(BlueNRGError::UnknownEvent(
                        event_code,
                    )))
                }
            }
            0x0C18 => {
                #[cfg(feature = "ms")]
                {
                    Ok(BlueNRGEvent::AttPrepareWritePermitRequest(
                        to_att_prepare_write_permit_request(buffer)?,
                    ))
                }

                #[cfg(not(feature = "ms"))]
                {
                    Err(hci::event::Error::Vendor(BlueNRGError::UnknownEvent(
                        event_code,
                    )))
                }
            }
            _ => Err(hci::event::Error::Vendor(BlueNRGError::UnknownEvent(
                event_code,
            ))),
        }
    }
}

/// Potential reasons the controller sent the [`HalInitialized`](BlueNRGEvent::HalInitialized)
/// event.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ResetReason {
    /// Firmware started properly
    Normal,
    /// Updater mode entered because of updater_start command
    Updater,
    /// Updater mode entered because of a bad BLUE flag
    UpdaterBadFlag,
    /// Updater mode entered with IRQ pin
    UpdaterPin,
    /// Reset caused by watchdog
    Watchdog,
    /// Reset due to lockup
    Lockup,
    /// Brownout reset
    Brownout,
    /// Reset caused by a crash (NMI or Hard Fault)
    Crash,
    /// Reset caused by an ECC error
    EccError,
}

impl TryFrom<u8> for ResetReason {
    type Error = BlueNRGError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            1 => Ok(ResetReason::Normal),
            2 => Ok(ResetReason::Updater),
            3 => Ok(ResetReason::UpdaterBadFlag),
            4 => Ok(ResetReason::UpdaterPin),
            5 => Ok(ResetReason::Watchdog),
            6 => Ok(ResetReason::Lockup),
            7 => Ok(ResetReason::Brownout),
            8 => Ok(ResetReason::Crash),
            9 => Ok(ResetReason::EccError),
            _ => Err(BlueNRGError::UnknownResetReason(value)),
        }
    }
}

/// Convert a buffer to the `HalInitialized` `BlueNRGEvent`.
///
/// # Errors
///
/// - Returns a `BadLength` HCI error if the buffer is not exactly 3 bytes long
///
/// - Returns a `UnknownResetReason` BlueNRG error if the reset reason is not recognized.
fn to_hal_initialized(buffer: &[u8]) -> Result<ResetReason, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 3);

    Ok(buffer[2].try_into().map_err(hci::event::Error::Vendor)?)
}

#[cfg(feature = "ms")]
bitflags! {
    /// Bitfield for the [Events Lost](BlueNRGEvent::EventsLost) event. Each bit indicates a
    /// different type of event that was not handled.
    #[derive(Default)]
    pub struct EventFlags: u64 {
        /// HCI Event: [Disconnection complete](hci::event::Event::DisconnectionComplete).
        const DISCONNECTION_COMPLETE = 1 << 0;
        /// HCI Event: [Encryption change](hci::event::Event::EncryptionChange).
        const ENCRYPTION_CHANGE = 1 << 1;
        /// HCI Event: [Read Remote Version
        /// Complete](hci::event::Event::ReadRemoteVersionInformationComplete).
        const READ_REMOTE_VERSION_COMPLETE = 1 << 2;
        /// HCI Event: [Command Complete](hci::event::Event::CommandComplete).
        const COMMAND_COMPLETE = 1 << 3;
        /// HCI Event: [Command Status](hci::event::Event::CommandStatus).
        const COMMAND_STATUS = 1 << 4;
        /// HCI Event: [Hardware Error](hci::event::Event::HardwareError).
        const HARDWARE_ERROR = 1 << 5;
        /// HCI Event: [Number of completed packets](hci::event::Event::NumberOfCompletedPackets).
        const NUMBER_OF_COMPLETED_PACKETS = 1 << 6;
        /// HCI Event: [Encryption key refresh
        /// complete](hci::event::Event::EncryptionKeyRefreshComplete).
        const ENCRYPTION_KEY_REFRESH = 1 << 7;
        /// BlueNRG-MS Event: [HAL Initialized](BlueNRGEvent::HalInitialized).
        const HAL_INITIALIZED = 1 << 8;
        /// BlueNRG Event: [GAP Set Limited Discoverable
        /// complete](BlueNRGEvent::GapLimitedDiscoverableTimeout).
        const GAP_LIMITED_DISCOVERABLE_TIMEOUT = 1 << 9;
        /// BlueNRG Event: [GAP Pairing complete](BlueNRGEvent::GapPairingComplete).
        const GAP_PAIRING_COMPLETE = 1 << 10;
        /// BlueNRG Event: [GAP Pass Key Request](BlueNRGEvent::GapPassKeyRequest).
        const GAP_PASS_KEY_REQUEST = 1 << 11;
        /// BlueNRG Event: [GAP Authorization Request](BlueNRGEvent::GapAuthorizationRequest).
        const GAP_AUTHORIZATION_REQUEST = 1 << 12;
        /// BlueNRG Event: [GAP Peripheral Security
        /// Initiated](BlueNRGEvent::GapPeripheralSecurityInitiated).
        const GAP_PERIPHERAL_SECURITY_INITIATED = 1 << 13;
        /// BlueNRG Event: [GAP Bond Lost](BlueNRGEvent::GapBondLost).
        const GAP_BOND_LOST = 1 << 14;
        /// BlueNRG Event: [GAP Procedure complete](BlueNRGEvent::GapProcedureComplete).
        const GAP_PROCEDURE_COMPLETE = 1 << 15;
        /// BlueNRG-MS Event: [GAP Address Not Resolved](BlueNRGEvent::GapAddressNotResolved).
        const GAP_ADDRESS_NOT_RESOLVED = 1 << 16;
        /// BlueNRG Event: [L2Cap Connection Update
        /// Response](BlueNRGEvent::L2CapConnectionUpdateResponse).
        const L2CAP_CONNECTION_UPDATE_RESPONSE = 1 << 17;
        /// BlueNRG Event: [L2Cap Procedure Timeout](BlueNRGEvent::L2CapProcedureTimeout).
        const L2CAP_PROCEDURE_TIMEOUT = 1 << 18;
        /// BlueNRG Event: [L2Cap Connection Update
        /// Request](BlueNRGEvent::L2CapConnectionUpdateRequest).
        const L2CAP_CONNECTION_UPDATE_REQUEST = 1 << 19;
        /// BlueNRG Event: [GATT Attribute modified](BlueNRGEvent::GattAttributeModified).
        const GATT_ATTRIBUTE_MODIFIED = 1 << 20;
        /// BlueNRG Event: [GATT timeout](BlueNRGEvent::GattProcedureTimeout).
        const GATT_PROCEDURE_TIMEOUT = 1 << 21;
        /// BlueNRG Event: [Exchange MTU Response](BlueNRGEvent::AttExchangeMtuResponse).
        const ATT_EXCHANGE_MTU_RESPONSE = 1 << 22;
        /// BlueNRG Event: [Find information response](BlueNRGEvent::AttFindInformationResponse).
        const ATT_FIND_INFORMATION_RESPONSE = 1 << 23;
        /// BlueNRG Event: [Find by type value response](BlueNRGEvent::AttFindByTypeValueResponse).
        const ATT_FIND_BY_TYPE_VALUE_RESPONSE = 1 << 24;
        /// BlueNRG Event: [Find read by type response](BlueNRGEvent::AttReadByTypeResponse).
        const ATT_READ_BY_TYPE_RESPONSE = 1 << 25;
        /// BlueNRG Event: [Read response](BlueNRGEvent::AttReadResponse).
        const ATT_READ_RESPONSE = 1 << 26;
        /// BlueNRG Event: [Read blob response](BlueNRGEvent::AttReadBlobResponse).
        const ATT_READ_BLOB_RESPONSE = 1 << 27;
        /// BlueNRG Event: [Read multiple response](BlueNRGEvent::AttReadMultipleResponse).
        const ATT_READ_MULTIPLE_RESPONSE = 1 << 28;
        /// BlueNRG Event: [Read by group type response](BlueNRGEvent::AttReadByGroupTypeResponse).
        const ATT_READ_BY_GROUP_TYPE_RESPONSE = 1 << 29;
        /// BlueNRG Event: ATT Write Response
        const ATT_WRITE_RESPONSE = 1 << 30;
        /// BlueNRG Event: [Prepare Write Response](BlueNRGEvent::AttPrepareWriteResponse).
        const ATT_PREPARE_WRITE_RESPONSE = 1 << 31;
        /// BlueNRG Event: [Execute write response](BlueNRGEvent::AttExecuteWriteResponse).
        const ATT_EXECUTE_WRITE_RESPONSE = 1 << 32;
        /// BlueNRG Event: [Indication received](BlueNRGEvent::GattIndication) from server.
        const GATT_INDICATION = 1 << 33;
        /// BlueNRG Event: [Notification received](BlueNRGEvent::GattNotification) from server.
        const GATT_NOTIFICATION = 1 << 34;
        /// BlueNRG Event: [GATT Procedure complete](BlueNRGEvent::GattProcedureComplete).
        const GATT_PROCEDURE_COMPLETE = 1 << 35;
        /// BlueNRG Event: [Error response received from server](BlueNRGEvent::AttErrorResponse).
        const GATT_ERROR_RESPONSE = 1 << 36;
        /// BlueNRG Event: [Response](BlueNRGEvent::GattDiscoverOrReadCharacteristicByUuidResponse)
        /// to either "Discover Characteristic by UUID" or "Read Characteristic by UUID" request
        const GATT_DISCOVER_OR_READ_CHARACTERISTIC_BY_UUID_RESPONSE = 1 << 37;
        /// BlueNRG Event: [Write request received](BlueNRGEvent::AttWritePermitRequest) by server.
        const GATT_WRITE_PERMIT_REQUEST = 1 << 38;
        /// BlueNRG Event: [Read request received](BlueNRGEvent::AttReadPermitRequest) by server.
        const GATT_READ_PERMIT_REQUEST = 1 << 39;
        /// BlueNRG Event: [Read multiple request
        /// received](BlueNRGEvent::AttReadMultiplePermitRequest) by server.
        const GATT_READ_MULTIPLE_PERMIT_REQUEST = 1 << 40;
        /// BlueNRG-MS Event: [TX Pool available](BlueNRGEvent::GattTxPoolAvailable) event missed.
        const GATT_TX_POOL_AVAILABLE = 1 << 41;
        /// BlueNRG-MS Event: [Server confirmation](BlueNRGEvent::GattServerConfirmation).
        const GATT_SERVER_RX_CONFIRMATION = 1 << 42;
        /// BlueNRG-MS Event: [Prepare write permit
        /// request](BlueNRGEvent::AttPrepareWritePermitRequest).
        const GATT_PREPARE_WRITE_PERMIT_REQUEST = 1 << 43;
        /// BlueNRG-MS Event: Link Layer [connection
        /// complete](hci::event::Event::LeConnectionComplete).
        const LINK_LAYER_CONNECTION_COMPLETE = 1 << 44;
        /// BlueNRG-MS Event: Link Layer [advertising
        /// report](hci::event::Event::LeAdvertisingReport).
        const LINK_LAYER_ADVERTISING_REPORT = 1 << 45;
        /// BlueNRG-MS Event: Link Layer [connection update
        /// complete](hci::event::Event::LeConnectionUpdateComplete).
        const LINK_LAYER_CONNECTION_UPDATE_COMPLETE = 1 << 46;
        /// BlueNRG-MS Event: Link Layer [read remote used
        /// features](hci::event::Event::LeReadRemoteUsedFeaturesComplete).
        const LINK_LAYER_READ_REMOTE_USED_FEATURES = 1 << 47;
        /// BlueNRG-MS Event: Link Layer [long-term key
        /// request](hci::event::Event::LeLongTermKeyRequest).
        const LINK_LAYER_LTK_REQUEST = 1 << 48;
    }
}

/// Convert a buffer to the `EventsLost` `BlueNRGEvent`.
///
/// # Errors
///
/// - Returns a `BadLength` HCI error if the buffer is not exactly 10 bytes long
/// - Returns [`BadEventFlags`](BlueNRGError::BadEventFlags) if a bit is set that does not represent
///   a lost event.
#[cfg(feature = "ms")]
fn to_lost_event(buffer: &[u8]) -> Result<EventFlags, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 10);

    let bits = LittleEndian::read_u64(&buffer[2..]);
    EventFlags::from_bits(bits)
        .ok_or_else(|| hci::event::Error::Vendor(BlueNRGError::BadEventFlags(bits)))
}

// The maximum length of [`FaultData::debug_data`]. The maximum length of an event is 255 bytes,
// and the non-variable data of the event takes up 40 bytes.
#[cfg(feature = "ms")]
const MAX_DEBUG_DATA_LEN: usize = 215;

/// Specific reason for the fault reported with [`FaultData`].
#[cfg(feature = "ms")]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CrashReason {
    /// The controller reset because an assertion failed.
    Assertion,
    /// The controller reset because of an NMI fault.
    NmiFault,
    /// The controller reset because of a hard fault.
    HardFault,
}

#[cfg(feature = "ms")]
impl TryFrom<u8> for CrashReason {
    type Error = BlueNRGError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(CrashReason::Assertion),

            // The documentation is conflicting for the numeric value of NMI Fault. The
            // CubeExpansion source code says 1, but the user manual says 6.
            1 | 6 => Ok(CrashReason::NmiFault),

            // The documentation is conflicting for the numeric value of hard Fault. The
            // CubeExpansion source code says 2, but the user manual says 7.
            2 | 7 => Ok(CrashReason::HardFault),
            _ => Err(BlueNRGError::UnknownCrashReason(value)),
        }
    }
}

/// Fault data reported after a crash.
#[cfg(feature = "ms")]
#[derive(Clone, Copy)]
pub struct FaultData {
    /// Fault reason.
    pub reason: CrashReason,

    /// MCP SP register
    pub sp: u32,
    /// MCU R0 register
    pub r0: u32,
    /// MCU R1 register
    pub r1: u32,
    /// MCU R2 register
    pub r2: u32,
    /// MCU R3 register
    pub r3: u32,
    /// MCU R12 register
    pub r12: u32,
    /// MCU LR register
    pub lr: u32,
    /// MCU PC register
    pub pc: u32,
    /// MCU xPSR register
    pub xpsr: u32,

    // Number of valid bytes in debug_data
    debug_data_len: usize,

    // Additional crash dump data
    debug_data_buf: [u8; MAX_DEBUG_DATA_LEN],
}

#[cfg(feature = "ms")]
impl Debug for FaultData {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "FaultData {{ reason: {:?}, sp: {:x}, r0: {:x}, r1: {:x}, r2: {:x}, r3: {:x}, ",
            self.reason, self.sp, self.r0, self.r1, self.r2, self.r3
        )?;
        write!(
            f,
            "r12: {:x}, lr: {:x}, pc: {:x}, xpsr: {:x}, debug_data: [",
            self.r12, self.lr, self.pc, self.xpsr
        )?;
        for byte in self.debug_data() {
            write!(f, " {:x}", byte)?;
        }
        write!(f, " ] }}")
    }
}

#[cfg(feature = "ms")]
impl FaultData {
    /// Returns the valid debug data.
    pub fn debug_data(&self) -> &[u8] {
        &self.debug_data_buf[..self.debug_data_len]
    }
}

#[cfg(feature = "ms")]
fn to_crash_report(buffer: &[u8]) -> Result<FaultData, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 40);

    let debug_data_len = buffer[39] as usize;
    require_len!(buffer, 40 + debug_data_len);

    let mut fault_data = FaultData {
        reason: buffer[2].try_into().map_err(hci::event::Error::Vendor)?,
        sp: LittleEndian::read_u32(&buffer[3..]),
        r0: LittleEndian::read_u32(&buffer[7..]),
        r1: LittleEndian::read_u32(&buffer[11..]),
        r2: LittleEndian::read_u32(&buffer[15..]),
        r3: LittleEndian::read_u32(&buffer[19..]),
        r12: LittleEndian::read_u32(&buffer[23..]),
        lr: LittleEndian::read_u32(&buffer[27..]),
        pc: LittleEndian::read_u32(&buffer[31..]),
        xpsr: LittleEndian::read_u32(&buffer[35..]),
        debug_data_len,
        debug_data_buf: [0; MAX_DEBUG_DATA_LEN],
    };
    fault_data.debug_data_buf[..debug_data_len].copy_from_slice(&buffer[40..]);

    Ok(fault_data)
}

macro_rules! require_l2cap_event_data_len {
    ($left:expr, $right:expr) => {
        let actual = $left[4];
        if actual != $right {
            return Err(hci::event::Error::Vendor(BlueNRGError::BadL2CapDataLength(
                actual, $right,
            )));
        }
    };
}

macro_rules! require_l2cap_len {
    ($actual:expr, $expected:expr) => {
        if $actual != $expected {
            return Err(hci::event::Error::Vendor(BlueNRGError::BadL2CapLength(
                $actual, $expected,
            )));
        }
    };
}

/// This event is generated when the central device responds to the L2CAP connection update request
/// packet.
///
/// For more info see connection parameter update response and command reject in Bluetooth Core v4.0
/// spec.
#[derive(Copy, Clone, Debug)]
pub struct L2CapConnectionUpdateResponse {
    /// The connection handle related to the event
    pub conn_handle: ConnectionHandle,

    /// The result of the update request, including details about the result.
    pub result: L2CapConnectionUpdateResult,
}

/// Reasons why an L2CAP command was rejected. see the Bluetooth specification, v4.1, Vol 3, Part A,
/// Section 4.1.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum L2CapRejectionReason {
    /// The controller sent an unknown command.
    CommandNotUnderstood,
    /// When multiple commands are included in an L2CAP packet and the packet exceeds the signaling
    /// MTU (MTUsig) of the receiver, a single Command Reject packet shall be sent in response.
    SignalingMtuExceeded,
    /// Invalid CID in request
    InvalidCid,
}

impl TryFrom<u16> for L2CapRejectionReason {
    type Error = BlueNRGError;

    fn try_from(value: u16) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(L2CapRejectionReason::CommandNotUnderstood),
            1 => Ok(L2CapRejectionReason::SignalingMtuExceeded),
            2 => Ok(L2CapRejectionReason::InvalidCid),
            _ => Err(BlueNRGError::BadL2CapRejectionReason(value)),
        }
    }
}

/// Potential results that can be used in the L2CAP connection update response.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum L2CapConnectionUpdateResult {
    /// The update request was rejected. The code indicates the reason for the rejection.
    CommandRejected(L2CapRejectionReason),

    /// The L2CAP connection update response is valid. The code indicates if the parameters were
    /// rejected.
    ParametersRejected,

    /// The L2CAP connection update response is valid. The code indicates if the parameters were
    /// updated.
    ParametersUpdated,
}

fn to_l2cap_connection_update_accepted_result(
    value: u16,
) -> Result<L2CapConnectionUpdateResult, BlueNRGError> {
    match value {
        0x0000 => Ok(L2CapConnectionUpdateResult::ParametersUpdated),
        0x0001 => Ok(L2CapConnectionUpdateResult::ParametersRejected),
        _ => Err(BlueNRGError::BadL2CapConnectionResponseResult(value)),
    }
}

fn extract_l2cap_connection_update_response_result(
    buffer: &[u8],
) -> Result<L2CapConnectionUpdateResult, BlueNRGError> {
    match buffer[5] {
        0x01 => Ok(L2CapConnectionUpdateResult::CommandRejected(
            LittleEndian::read_u16(&buffer[9..]).try_into()?,
        )),
        0x13 => to_l2cap_connection_update_accepted_result(LittleEndian::read_u16(&buffer[9..])),
        _ => Err(BlueNRGError::BadL2CapConnectionResponseCode(buffer[5])),
    }
}

fn to_l2cap_connection_update_response(
    buffer: &[u8],
) -> Result<L2CapConnectionUpdateResponse, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 11);
    require_l2cap_event_data_len!(buffer, 6);
    require_l2cap_len!(LittleEndian::read_u16(&buffer[7..]), 2);

    Ok(L2CapConnectionUpdateResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        result: extract_l2cap_connection_update_response_result(buffer)
            .map_err(hci::event::Error::Vendor)?,
    })
}

/// This event is generated when the central device does not respond to the connection update
/// request within 30 seconds.
#[derive(Copy, Clone, Debug)]
pub struct L2CapProcedureTimeout {
    /// The connection handle related to the event.
    pub conn_handle: ConnectionHandle,
}

fn to_l2cap_procedure_timeout(
    buffer: &[u8],
) -> Result<ConnectionHandle, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 5);
    require_l2cap_event_data_len!(buffer, 0);

    Ok(ConnectionHandle(LittleEndian::read_u16(&buffer[2..])))
}

/// The event is given by the L2CAP layer when a connection update request is received from the
/// peripheral.
///
/// The application has to respond by calling
/// [`l2cap_connection_parameter_update_response`](crate::l2cap::Commands::connection_parameter_update_response).
///
/// Defined in Vol 3, Part A, section 4.20 of the Bluetooth specification.
#[derive(Copy, Clone, Debug)]
pub struct L2CapConnectionUpdateRequest {
    /// Handle of the connection for which the connection update request has been received.  The
    /// [same handle](crate::l2cap::ConnectionParameterUpdateResponse::conn_handle) has to be
    /// returned while responding to the event with the command
    /// [`l2cap_connection_parameter_update_response`](crate::l2cap::Commands::connection_parameter_update_response).
    pub conn_handle: ConnectionHandle,

    /// This is the identifier which associates the request to the response. The [same
    /// identifier](crate::l2cap::ConnectionParameterUpdateResponse::identifier) has to be returned
    /// by the upper layer in the command
    /// [`l2cap_connection_parameter_update_response`](crate::l2cap::Commands::connection_parameter_update_response).
    pub identifier: u8,

    /// Defines the range of the connection interval, the latency, and the supervision timeout.
    pub conn_interval: ConnectionInterval,
}

fn to_l2cap_connection_update_request(
    buffer: &[u8],
) -> Result<L2CapConnectionUpdateRequest, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 16);
    require_l2cap_event_data_len!(buffer, 11);
    require_l2cap_len!(LittleEndian::read_u16(&buffer[6..]), 8);

    let interval = ConnectionInterval::from_bytes(&buffer[8..16])
        .map_err(BlueNRGError::BadConnectionInterval)
        .map_err(hci::event::Error::Vendor)?;

    Ok(L2CapConnectionUpdateRequest {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        identifier: buffer[5],
        conn_interval: interval,
    })
}

/// This event is generated when the pairing process has completed successfully or a pairing
/// procedure timeout has occurred or the pairing has failed. This is to notify the application that
/// we have paired with a remote device so that it can take further actions or to notify that a
/// timeout has occurred so that the upper layer can decide to disconnect the link.
#[derive(Copy, Clone, Debug)]
pub struct GapPairingComplete {
    /// Connection handle on which the pairing procedure completed
    pub conn_handle: ConnectionHandle,

    /// Reason the pairing is complete.
    pub status: GapPairingStatus,
}

/// Reasons the [GAP Pairing Complete](BlueNRGEvent::GapPairingComplete) event was generated.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GapPairingStatus {
    /// Pairing with a remote device was successful.
    Success,
    /// The SMP timeout has elapsed and no further SMP commands will be processed until
    /// reconnection.
    Timeout,
    /// The pairing failed with the remote device.
    Failed,
}

impl TryFrom<u8> for GapPairingStatus {
    type Error = BlueNRGError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(GapPairingStatus::Success),
            1 => Ok(GapPairingStatus::Timeout),
            2 => Ok(GapPairingStatus::Failed),
            _ => Err(BlueNRGError::BadGapPairingStatus(value)),
        }
    }
}

fn to_gap_pairing_complete(
    buffer: &[u8],
) -> Result<GapPairingComplete, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 5);
    Ok(GapPairingComplete {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        status: buffer[4].try_into().map_err(hci::event::Error::Vendor)?,
    })
}

fn to_conn_handle(buffer: &[u8]) -> Result<ConnectionHandle, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 4);
    Ok(ConnectionHandle(LittleEndian::read_u16(&buffer[2..])))
}

/// The event is given by the GAP layer to the upper layers when a device is discovered during
/// scanning as a consequence of one of the GAP procedures started by the upper layers.
#[derive(Copy, Clone, Debug)]
pub struct GapDeviceFound {
    /// Type of event
    pub event: GapDeviceFoundEvent,

    /// Address of the peer device found during scanning
    pub bdaddr: BdAddrType,

    // Length of significant data
    data_len: usize,

    // Advertising or scan response data.
    data_buf: [u8; 31],

    /// Received signal strength indicator (range: -127 - 20).
    pub rssi: Option<i8>,
}

impl GapDeviceFound {
    /// Returns the valid scan response data.
    pub fn data(&self) -> &[u8] {
        &self.data_buf[..self.data_len]
    }
}

pub use hci::event::AdvertisementEvent as GapDeviceFoundEvent;

fn to_gap_device_found(buffer: &[u8]) -> Result<GapDeviceFound, hci::event::Error<BlueNRGError>> {
    const RSSI_UNAVAILABLE: i8 = 127;

    require_len_at_least!(buffer, 12);

    let data_len = buffer[10] as usize;
    require_len!(buffer, 12 + data_len);

    let rssi = unsafe { mem::transmute::<u8, i8>(buffer[buffer.len() - 1]) };

    let mut addr = BdAddr([0; 6]);
    addr.0.copy_from_slice(&buffer[4..10]);
    let mut event = GapDeviceFound {
        event: buffer[2].try_into().map_err(|e| {
            if let hci::event::Error::BadLeAdvertisementType(code) = e {
                hci::event::Error::Vendor(BlueNRGError::BadGapDeviceFoundEvent(code))
            } else {
                unreachable!()
            }
        })?,
        bdaddr: hci::to_bd_addr_type(buffer[3], addr)
            .map_err(|e| hci::event::Error::Vendor(BlueNRGError::BadGapBdAddrType(e.0)))?,
        data_len,
        data_buf: [0; 31],
        rssi: if rssi == RSSI_UNAVAILABLE {
            None
        } else {
            Some(rssi)
        },
    };
    event.data_buf[..event.data_len].copy_from_slice(&buffer[11..buffer.len() - 1]);

    Ok(event)
}

/// This event is sent by the GAP to the upper layers when a procedure previously started has been
/// terminated by the upper layer or has completed for any other reason
#[derive(Copy, Clone, Debug)]
pub struct GapProcedureComplete {
    /// Type of procedure that completed
    pub procedure: GapProcedure,
    /// Status of the procedure
    pub status: GapProcedureStatus,
}

/// Maximum length of the name returned in the [`NameDiscovery`](GapProcedure::NameDiscovery)
/// procedure.
pub const MAX_NAME_LEN: usize = 248;

/// Newtype for the name buffer returned after successful
/// [`NameDiscovery`](GapProcedure::NameDiscovery).
#[derive(Copy, Clone)]
pub struct NameBuffer(pub [u8; MAX_NAME_LEN]);

impl Debug for NameBuffer {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        first_16(&self.0).fmt(f)
    }
}

impl PartialEq<NameBuffer> for NameBuffer {
    fn eq(&self, other: &Self) -> bool {
        if self.0.len() != other.0.len() {
            return false;
        }

        for (a, b) in self.0.iter().zip(other.0.iter()) {
            if a != b {
                return false;
            }
        }

        true
    }
}

/// Procedures whose completion may be reported by
/// [`GapProcedureComplete`](BlueNRGEvent::GapProcedureComplete).
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GapProcedure {
    /// See Vol 3, Part C, section 9.2.5.
    LimitedDiscovery,
    /// See Vol 3, Part C, section 9.2.6.
    GeneralDiscovery,
    /// See Vol 3, Part C, section 9.2.7. Contains the number of valid bytes and buffer with enough
    /// space for the maximum length of the name that can be retuned.
    NameDiscovery(usize, NameBuffer),
    /// See Vol 3, Part C, section 9.3.5.
    AutoConnectionEstablishment,
    /// See Vol 3, Part C, section 9.3.6. Contains the reconnection address.
    GeneralConnectionEstablishment(BdAddr),
    /// See Vol 3, Part C, section 9.3.7.
    SelectiveConnectionEstablishment,
    /// See Vol 3, Part C, section 9.3.8.
    DirectConnectionEstablishment,
}

/// Possible results of a [GAP procedure](BlueNRGEvent::GapProcedureComplete).
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GapProcedureStatus {
    /// BLE Status Success.
    Success,
    /// BLE Status Failed.
    Failed,
    /// Procedure failed due to authentication requirements.
    AuthFailure,
}

impl TryFrom<u8> for GapProcedureStatus {
    type Error = BlueNRGError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0x00 => Ok(GapProcedureStatus::Success),
            0x41 => Ok(GapProcedureStatus::Failed),
            0x05 => Ok(GapProcedureStatus::AuthFailure),
            _ => Err(BlueNRGError::BadGapProcedureStatus(value)),
        }
    }
}

fn to_gap_procedure_complete(
    buffer: &[u8],
) -> Result<GapProcedureComplete, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 4);

    let procedure = match buffer[2] {
        0x01 => GapProcedure::LimitedDiscovery,
        0x02 => GapProcedure::GeneralDiscovery,
        0x04 => {
            require_len_at_least!(buffer, 5);
            let name_len = buffer.len() - 4;
            let mut name = NameBuffer([0; MAX_NAME_LEN]);
            name.0[..name_len].copy_from_slice(&buffer[4..]);

            GapProcedure::NameDiscovery(name_len, name)
        }
        0x08 => GapProcedure::AutoConnectionEstablishment,
        0x10 => {
            require_len!(buffer, 10);
            let mut addr = BdAddr([0; 6]);
            addr.0.copy_from_slice(&buffer[4..10]);
            GapProcedure::GeneralConnectionEstablishment(addr)
        }
        0x20 => GapProcedure::SelectiveConnectionEstablishment,
        0x40 => GapProcedure::DirectConnectionEstablishment,
        _ => {
            return Err(hci::event::Error::Vendor(BlueNRGError::BadGapProcedure(
                buffer[2],
            )));
        }
    };

    Ok(GapProcedureComplete {
        procedure,
        status: buffer[3].try_into().map_err(hci::event::Error::Vendor)?,
    })
}

#[cfg(not(feature = "ms"))]
fn to_gap_reconnection_address(buffer: &[u8]) -> Result<BdAddr, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 8);
    let mut addr = BdAddr([0; 6]);
    addr.0.copy_from_slice(&buffer[2..]);
    Ok(addr)
}

/// This event is generated to the application by the ATT server when a client modifies any
/// attribute on the server, as consequence of one of the following ATT procedures:
/// - write without response
/// - signed write without response
/// - write characteristic value
/// - write long characteristic value
/// - reliable write
#[derive(Copy, Clone)]
pub struct GattAttributeModified {
    /// The connection handle which modified the attribute
    pub conn_handle: ConnectionHandle,
    ///  Handle of the attribute that was modified
    pub attr_handle: AttributeHandle,

    /// Offset of the reported value inside the attribute.
    #[cfg(feature = "ms")]
    pub offset: usize,

    /// If the entire value of the attribute does not fit inside a single GattAttributeModified
    /// event, this is true to notify that other GattAttributeModified events will follow to report
    /// the remaining value.
    #[cfg(feature = "ms")]
    pub continued: bool,

    /// Number of valid bytes in |data|.
    data_len: usize,
    /// The new attribute value, starting from the given offset. If compiling with "ms" support, the
    /// offset is 0.
    data_buf: [u8; MAX_ATTRIBUTE_LEN],
}

impl GattAttributeModified {
    /// Returns the valid attribute data returned by the ATT attribute modified event as a slice of
    /// bytes.
    pub fn data(&self) -> &[u8] {
        &self.data_buf[..self.data_len]
    }
}

/// Newtype for an attribute handle. These handles are IDs, not general integers, and should not be
/// manipulated as such.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct AttributeHandle(pub u16);

// Defines the maximum length of a ATT attribute value field. This is determined by the max packet
// size (255) less the minimum number of bytes used by other fields in any packet.
const MAX_ATTRIBUTE_LEN: usize = 248;

impl Debug for GattAttributeModified {
    #[cfg(feature = "ms")]
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{conn_handle: {:?}, attr_handle: {:?}, offset: {}, continued: {}, data: {:?}}}",
            self.conn_handle,
            self.attr_handle,
            self.offset,
            self.continued,
            first_16(self.data()),
        )
    }

    #[cfg(not(feature = "ms"))]
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{conn_handle: {:?}, attr_handle: {:?}, data: {:?}}}",
            self.conn_handle,
            self.attr_handle,
            first_16(self.data()),
        )
    }
}

#[cfg(feature = "ms")]
fn to_gatt_attribute_modified(
    buffer: &[u8],
) -> Result<GattAttributeModified, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 9);

    let data_len = buffer[6] as usize;
    require_len!(buffer, 9 + data_len);

    let mut data = [0; MAX_ATTRIBUTE_LEN];
    data[..data_len].copy_from_slice(&buffer[9..]);

    let offset_field = LittleEndian::read_u16(&buffer[7..]);
    Ok(GattAttributeModified {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attr_handle: AttributeHandle(LittleEndian::read_u16(&buffer[4..])),
        offset: (offset_field & 0x7FFF) as usize,
        continued: (offset_field & 0x8000) > 0,
        data_len,
        data_buf: data,
    })
}

#[cfg(not(feature = "ms"))]
fn to_gatt_attribute_modified(
    buffer: &[u8],
) -> Result<GattAttributeModified, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 7);

    let data_len = buffer[6] as usize;
    require_len!(buffer, 7 + data_len);

    let mut data = [0; MAX_ATTRIBUTE_LEN];
    data[..data_len].copy_from_slice(&buffer[7..]);

    Ok(GattAttributeModified {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attr_handle: AttributeHandle(LittleEndian::read_u16(&buffer[4..])),
        data_len,
        data_buf: data,
    })
}

/// This event is generated in response to an Exchange MTU request.
#[derive(Copy, Clone, Debug)]
pub struct AttExchangeMtuResponse {
    ///  The connection handle related to the response.
    pub conn_handle: ConnectionHandle,

    /// Attribute server receive MTU size.
    pub server_rx_mtu: usize,
}

fn to_att_exchange_mtu_resp(
    buffer: &[u8],
) -> Result<AttExchangeMtuResponse, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 7);
    Ok(AttExchangeMtuResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        server_rx_mtu: LittleEndian::read_u16(&buffer[5..]) as usize,
    })
}

/// This event is generated in response to a Find Information Request. See Find Information Response
/// in Bluetooth Core v4.0 spec.
#[derive(Copy, Clone, Debug)]
pub struct AttFindInformationResponse {
    /// The connection handle related to the response
    pub conn_handle: ConnectionHandle,
    /// The Find Information Response shall have complete handle-UUID pairs. Such pairs shall not be
    /// split across response packets; this also implies that a handleUUID pair shall fit into a
    /// single response packet. The handle-UUID pairs shall be returned in ascending order of
    /// attribute handles.
    handle_uuid_pairs: HandleUuidPairs,
}

impl AttFindInformationResponse {
    /// The Find Information Response shall have complete handle-UUID pairs. Such pairs shall not be
    /// split across response packets; this also implies that a handleUUID pair shall fit into a
    /// single response packet. The handle-UUID pairs shall be returned in ascending order of
    /// attribute handles.
    pub fn handle_uuid_pair_iter(&self) -> HandleUuidPairIterator {
        match self.handle_uuid_pairs {
            HandleUuidPairs::Format16(count, ref data) => {
                HandleUuidPairIterator::Format16(HandleUuid16PairIterator {
                    data,
                    count,
                    next_index: 0,
                })
            }
            HandleUuidPairs::Format128(count, ref data) => {
                HandleUuidPairIterator::Format128(HandleUuid128PairIterator {
                    data,
                    count,
                    next_index: 0,
                })
            }
        }
    }
}

// Assuming a maximum HCI packet size of 255, these are the maximum number of handle-UUID pairs for
// each format that can be in one packet.  Formats cannot be mixed in a single packet.
//
// Packets have 6 other bytes of data preceding the handle-UUID pairs.
//
// max = floor((255 - 6) / pair_length)
const MAX_FORMAT16_PAIR_COUNT: usize = 62;
const MAX_FORMAT128_PAIR_COUNT: usize = 13;

/// One format of the handle-UUID pairs in the [`AttFindInformationResponse`] event. The UUIDs are
/// 16 bits.
#[derive(Copy, Clone, Debug)]
pub struct HandleUuid16Pair {
    /// Attribute handle
    pub handle: AttributeHandle,
    /// Attribute UUID
    pub uuid: Uuid16,
}

/// One format of the handle-UUID pairs in the [`AttFindInformationResponse`] event. The UUIDs are
/// 128 bits.
#[derive(Copy, Clone, Debug)]
pub struct HandleUuid128Pair {
    /// Attribute handle
    pub handle: AttributeHandle,
    /// Attribute UUID
    pub uuid: Uuid128,
}

/// Newtype for the 16-bit UUID buffer.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Uuid16(pub u16);

/// Newtype for the 128-bit UUID buffer.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Uuid128(pub [u8; 16]);

#[derive(Copy, Clone)]
enum HandleUuidPairs {
    Format16(usize, [HandleUuid16Pair; MAX_FORMAT16_PAIR_COUNT]),
    Format128(usize, [HandleUuid128Pair; MAX_FORMAT128_PAIR_COUNT]),
}

impl Debug for HandleUuidPairs {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{{")?;
        match *self {
            HandleUuidPairs::Format16(count, pairs) => {
                for handle_uuid_pair in &pairs[..count] {
                    write!(
                        f,
                        "{{{:?}, {:?}}}",
                        handle_uuid_pair.handle, handle_uuid_pair.uuid
                    )?
                }
            }
            HandleUuidPairs::Format128(count, pairs) => {
                for handle_uuid_pair in &pairs[..count] {
                    write!(
                        f,
                        "{{{:?}, {:?}}}",
                        handle_uuid_pair.handle, handle_uuid_pair.uuid
                    )?
                }
            }
        }
        write!(f, "}}")
    }
}

/// Possible iterators over handle-UUID pairs that can be returnedby the [ATT find information
/// response](AttFindInformationResponse). All pairs from the same event have the same format.
pub enum HandleUuidPairIterator<'a> {
    /// The event contains 16-bit UUIDs.
    Format16(HandleUuid16PairIterator<'a>),
    /// The event contains 128-bit UUIDs.
    Format128(HandleUuid128PairIterator<'a>),
}

/// Iterator over handle-UUID pairs for 16-bit UUIDs.
pub struct HandleUuid16PairIterator<'a> {
    data: &'a [HandleUuid16Pair; MAX_FORMAT16_PAIR_COUNT],
    count: usize,
    next_index: usize,
}

impl<'a> Iterator for HandleUuid16PairIterator<'a> {
    type Item = HandleUuid16Pair;
    fn next(&mut self) -> Option<Self::Item> {
        if self.next_index >= self.count {
            return None;
        }

        let index = self.next_index;
        self.next_index += 1;
        Some(self.data[index])
    }
}

/// Iterator over handle-UUID pairs for 128-bit UUIDs.
pub struct HandleUuid128PairIterator<'a> {
    data: &'a [HandleUuid128Pair; MAX_FORMAT128_PAIR_COUNT],
    count: usize,
    next_index: usize,
}

impl<'a> Iterator for HandleUuid128PairIterator<'a> {
    type Item = HandleUuid128Pair;
    fn next(&mut self) -> Option<Self::Item> {
        if self.next_index >= self.count {
            return None;
        }

        let index = self.next_index;
        self.next_index += 1;
        Some(self.data[index])
    }
}

fn to_att_find_information_response(
    buffer: &[u8],
) -> Result<AttFindInformationResponse, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 6);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    Ok(AttFindInformationResponse {
        conn_handle: to_conn_handle(buffer)?,
        handle_uuid_pairs: match buffer[5] {
            1 => to_handle_uuid16_pairs(&buffer[6..]).map_err(hci::event::Error::Vendor)?,
            2 => to_handle_uuid128_pairs(&buffer[6..]).map_err(hci::event::Error::Vendor)?,
            _ => {
                return Err(hci::event::Error::Vendor(
                    BlueNRGError::BadAttFindInformationResponseFormat(buffer[5]),
                ));
            }
        },
    })
}

fn to_handle_uuid16_pairs(buffer: &[u8]) -> Result<HandleUuidPairs, BlueNRGError> {
    const PAIR_LEN: usize = 4;
    if buffer.len() % PAIR_LEN != 0 {
        return Err(BlueNRGError::AttFindInformationResponsePartialPair16);
    }

    let count = buffer.len() / PAIR_LEN;
    let mut pairs = [HandleUuid16Pair {
        handle: AttributeHandle(0),
        uuid: Uuid16(0),
    }; MAX_FORMAT16_PAIR_COUNT];
    for (i, pair) in pairs.iter_mut().enumerate().take(count) {
        let index = i * PAIR_LEN;
        pair.handle = AttributeHandle(LittleEndian::read_u16(&buffer[index..]));
        pair.uuid = Uuid16(LittleEndian::read_u16(&buffer[2 + index..]));
    }

    Ok(HandleUuidPairs::Format16(count, pairs))
}

fn to_handle_uuid128_pairs(buffer: &[u8]) -> Result<HandleUuidPairs, BlueNRGError> {
    const PAIR_LEN: usize = 18;
    if buffer.len() % PAIR_LEN != 0 {
        return Err(BlueNRGError::AttFindInformationResponsePartialPair128);
    }

    let count = buffer.len() / PAIR_LEN;
    let mut pairs = [HandleUuid128Pair {
        handle: AttributeHandle(0),
        uuid: Uuid128([0; 16]),
    }; MAX_FORMAT128_PAIR_COUNT];
    for (i, pair) in pairs.iter_mut().enumerate().take(count) {
        let index = i * PAIR_LEN;
        let next_index = (i + 1) * PAIR_LEN;
        pair.handle = AttributeHandle(LittleEndian::read_u16(&buffer[index..]));
        pair.uuid.0.copy_from_slice(&buffer[2 + index..next_index]);
    }

    Ok(HandleUuidPairs::Format128(count, pairs))
}

/// This event is generated in response to a Find By Type Value Request.
#[derive(Copy, Clone)]
pub struct AttFindByTypeValueResponse {
    /// The connection handle related to the response.
    pub conn_handle: ConnectionHandle,

    /// The number of valid pairs that follow.
    handle_pair_count: usize,

    /// Handles Information List as defined in Bluetooth Core v4.1 spec.
    handles: [HandleInfoPair; MAX_HANDLE_INFO_PAIR_COUNT],
}

impl AttFindByTypeValueResponse {
    /// Returns an iterator over the Handles Information List as defined in Bluetooth Core v4.1
    /// spec.
    pub fn handle_pairs_iter(&self) -> HandleInfoPairIterator {
        HandleInfoPairIterator {
            event: &self,
            next_index: 0,
        }
    }
}

impl Debug for AttFindByTypeValueResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{{.conn_handle = {:?}, ", self.conn_handle)?;
        for handle_pair in self.handle_pairs_iter() {
            write!(f, "{:?}", handle_pair)?;
        }
        write!(f, "}}")
    }
}

// Assuming a maximum HCI packet size of 255, these are the maximum number of handle pairs that can
// be in one packet.
//
// Packets have 5 other bytes of data preceding the handle-UUID pairs.
//
// max = floor((255 - 5) / 4)
const MAX_HANDLE_INFO_PAIR_COUNT: usize = 62;

/// Simple container for the handle information returned in [`AttFindByTypeValueResponse`].
#[derive(Copy, Clone, Debug)]
pub struct HandleInfoPair {
    /// Attribute handle
    pub attribute: AttributeHandle,
    /// Group End handle
    pub group_end: GroupEndHandle,
}

/// Newtype for Group End handles
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct GroupEndHandle(pub u16);

/// Iterator into valid [`HandleInfoPair`] structs returned in the [ATT Find By Type Value
/// Response](AttFindByTypeValueResponse) event.
pub struct HandleInfoPairIterator<'a> {
    event: &'a AttFindByTypeValueResponse,
    next_index: usize,
}

impl<'a> Iterator for HandleInfoPairIterator<'a> {
    type Item = HandleInfoPair;

    fn next(&mut self) -> Option<Self::Item> {
        if self.next_index >= self.event.handle_pair_count {
            return None;
        }

        let index = self.next_index;
        self.next_index += 1;
        Some(self.event.handles[index])
    }
}

fn to_att_find_by_value_type_response(
    buffer: &[u8],
) -> Result<AttFindByTypeValueResponse, hci::event::Error<BlueNRGError>> {
    const PAIR_LEN: usize = 4;

    require_len_at_least!(buffer, 5);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    let pair_buffer = &buffer[5..];
    if pair_buffer.len() % PAIR_LEN != 0 {
        return Err(hci::event::Error::Vendor(
            BlueNRGError::AttFindByTypeValuePartial,
        ));
    }

    let count = pair_buffer.len() / PAIR_LEN;
    let mut pairs = [HandleInfoPair {
        attribute: AttributeHandle(0),
        group_end: GroupEndHandle(0),
    }; MAX_HANDLE_INFO_PAIR_COUNT];
    for (i, pair) in pairs.iter_mut().enumerate().take(count) {
        let index = i * PAIR_LEN;
        pair.attribute = AttributeHandle(LittleEndian::read_u16(&pair_buffer[index..]));
        pair.group_end = GroupEndHandle(LittleEndian::read_u16(&pair_buffer[2 + index..]));
    }
    Ok(AttFindByTypeValueResponse {
        conn_handle: to_conn_handle(buffer)?,
        handle_pair_count: count,
        handles: pairs,
    })
}

/// This event is generated in response to a Read By Type Request.
#[derive(Copy, Clone)]
pub struct AttReadByTypeResponse {
    /// The connection handle related to the response.
    pub conn_handle: ConnectionHandle,

    // Number of valid bytes in `handle_value_pair_buf`
    data_len: usize,
    // Length of each value in `handle_value_pair_buf`
    value_len: usize,
    // Raw data of the response. Contains 2 octets for the attribute handle followed by `value_len`
    // octets of value data. These pairs repeat for `data_len` bytes.
    handle_value_pair_buf: [u8; MAX_HANDLE_VALUE_PAIR_BUF_LEN],
}

// The maximum amount of data in the buffer is the max HCI packet size (255) less the other data in
// the packet.
const MAX_HANDLE_VALUE_PAIR_BUF_LEN: usize = 249;

impl Debug for AttReadByTypeResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{{.conn_handle = {:?}, ", self.conn_handle)?;
        for handle_value_pair in self.handle_value_pair_iter() {
            write!(
                f,
                "{{handle: {:?}, value: {:?}}}",
                handle_value_pair.handle,
                first_16(handle_value_pair.value)
            )?;
        }
        write!(f, "}}")
    }
}

impl AttReadByTypeResponse {
    /// Return an iterator over all valid handle-value pairs returned with the response.
    pub fn handle_value_pair_iter(&self) -> HandleValuePairIterator {
        HandleValuePairIterator {
            event: &self,
            index: 0,
        }
    }
}

/// Iterator over the valid handle-value pairs returned with the [ATT Read by Type
/// response](AttReadByTypeResponse).
pub struct HandleValuePairIterator<'a> {
    event: &'a AttReadByTypeResponse,
    index: usize,
}

impl<'a> Iterator for HandleValuePairIterator<'a> {
    type Item = HandleValuePair<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.event.data_len {
            return None;
        }

        let handle_index = self.index;
        let value_index = self.index + 2;
        self.index += 2 + self.event.value_len;
        let next_index = self.index;
        Some(HandleValuePair {
            handle: AttributeHandle(LittleEndian::read_u16(
                &self.event.handle_value_pair_buf[handle_index..],
            )),
            value: &self.event.handle_value_pair_buf[value_index..next_index],
        })
    }
}

/// A single handle-value pair returned by the [ATT Read by Type response](AttReadByTypeResponse).
pub struct HandleValuePair<'a> {
    /// Attribute handle
    pub handle: AttributeHandle,
    /// Attribute value. The caller must interpret the value correctly, depending on the expected
    /// type of the attribute.
    pub value: &'a [u8],
}

fn to_att_read_by_type_response(
    buffer: &[u8],
) -> Result<AttReadByTypeResponse, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 6);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    let handle_value_pair_len = buffer[5] as usize;
    let handle_value_pair_buf = &buffer[6..];
    if handle_value_pair_buf.len() % handle_value_pair_len != 0 {
        return Err(hci::event::Error::Vendor(
            BlueNRGError::AttReadByTypeResponsePartial,
        ));
    }

    let mut full_handle_value_pair_buf = [0; MAX_HANDLE_VALUE_PAIR_BUF_LEN];
    full_handle_value_pair_buf[..handle_value_pair_buf.len()]
        .copy_from_slice(&handle_value_pair_buf);

    Ok(AttReadByTypeResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        data_len: handle_value_pair_buf.len(),
        value_len: handle_value_pair_len - 2,
        handle_value_pair_buf: full_handle_value_pair_buf,
    })
}

/// This event is generated in response to a Read Request.
#[derive(Copy, Clone)]
pub struct AttReadResponse {
    /// The connection handle related to the response.
    pub conn_handle: ConnectionHandle,

    /// The number of valid bytes in the value buffer.
    value_len: usize,

    /// Buffer containing the value data.
    value_buf: [u8; MAX_READ_RESPONSE_LEN],
}

// The maximum amount of data in the buffer is the max HCI packet size (255) less the other data in
// the packet.
const MAX_READ_RESPONSE_LEN: usize = 250;

impl Debug for AttReadResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{.conn_handle = {:?}, value = {:?}}}",
            self.conn_handle,
            first_16(self.value())
        )
    }
}

impl AttReadResponse {
    /// Returns the valid part of the value data.
    pub fn value(&self) -> &[u8] {
        &self.value_buf[..self.value_len]
    }
}

fn to_att_read_response(buffer: &[u8]) -> Result<AttReadResponse, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 5);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    let mut value_buf = [0; MAX_READ_RESPONSE_LEN];
    value_buf[..data_len].copy_from_slice(&buffer[5..]);

    Ok(AttReadResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        value_len: data_len,
        value_buf,
    })
}

/// This event is generated in response to a Read By Group Type Request. See the Bluetooth Core v4.1
/// spec, Vol 3, section 3.4.4.9 and 3.4.4.10.
#[derive(Copy, Clone)]
pub struct AttReadByGroupTypeResponse {
    ///  The connection handle related to the response.
    pub conn_handle: ConnectionHandle,

    // Number of valid bytes in `attribute_data_buf`
    data_len: usize,

    // Length of the attribute data group in `attribute_data_buf`, including the attribute and group
    // end handles.
    attribute_group_len: usize,

    // List of attribute data which is a repetition of:
    // 1. 2 octets for attribute handle.
    // 2. 2 octets for end group handle.
    // 3. (attribute_group_len - 4) octets for attribute value.
    attribute_data_buf: [u8; MAX_ATTRIBUTE_DATA_BUF_LEN],
}

// The maximum amount of data in the buffer is the max HCI packet size (255) less the other data in
// the packet.
const MAX_ATTRIBUTE_DATA_BUF_LEN: usize = 249;

impl AttReadByGroupTypeResponse {
    /// Create and return an iterator for the attribute data returned with the response.
    pub fn attribute_data_iter(&self) -> AttributeDataIterator {
        AttributeDataIterator {
            event: self,
            next_index: 0,
        }
    }
}

impl Debug for AttReadByGroupTypeResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{{.conn_handle = {:?}, ", self.conn_handle)?;
        for attribute_data in self.attribute_data_iter() {
            write!(
                f,
                "{{.attribute_handle = {:?}, .group_end_handle = {:?}, .value = {:?}}}",
                attribute_data.attribute_handle,
                attribute_data.group_end_handle,
                first_16(attribute_data.value)
            )?;
        }
        write!(f, "}}")
    }
}

/// Iterator over the attribute data returned in the [`AttReadByGroupTypeResponse`].
pub struct AttributeDataIterator<'a> {
    event: &'a AttReadByGroupTypeResponse,
    next_index: usize,
}

impl<'a> Iterator for AttributeDataIterator<'a> {
    type Item = AttributeData<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.next_index >= self.event.data_len {
            return None;
        }

        let attr_handle_index = self.next_index;
        let group_end_index = 2 + attr_handle_index;
        let value_index = 2 + group_end_index;
        self.next_index += self.event.attribute_group_len;
        Some(AttributeData {
            attribute_handle: AttributeHandle(LittleEndian::read_u16(
                &self.event.attribute_data_buf[attr_handle_index..],
            )),
            group_end_handle: GroupEndHandle(LittleEndian::read_u16(
                &self.event.attribute_data_buf[group_end_index..],
            )),
            value: &self.event.attribute_data_buf[value_index..self.next_index],
        })
    }
}

/// Attribute data returned in the [`AttReadByGroupTypeResponse`] event.
pub struct AttributeData<'a> {
    /// Attribute handle
    pub attribute_handle: AttributeHandle,
    /// Group end handle
    pub group_end_handle: GroupEndHandle,
    /// Attribute value
    pub value: &'a [u8],
}

fn to_att_read_by_group_type_response(
    buffer: &[u8],
) -> Result<AttReadByGroupTypeResponse, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 6);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    let attribute_group_len = buffer[5] as usize;

    if buffer[6..].len() % attribute_group_len != 0 {
        return Err(hci::event::Error::Vendor(
            BlueNRGError::AttReadByGroupTypeResponsePartial,
        ));
    }

    let mut attribute_data_buf = [0; MAX_ATTRIBUTE_DATA_BUF_LEN];
    attribute_data_buf[..data_len - 1].copy_from_slice(&buffer[6..]);
    Ok(AttReadByGroupTypeResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        data_len: data_len - 1, // lose 1 byte to attribute_group_len
        attribute_group_len,
        attribute_data_buf,
    })
}

/// This event is generated in response to a Prepare Write Request. See the Bluetooth Core v4.1
/// spec, Vol 3, Part F, section 3.4.6.1 and 3.4.6.2
#[derive(Copy, Clone)]
pub struct AttPrepareWriteResponse {
    /// The connection handle related to the response.
    pub conn_handle: ConnectionHandle,
    /// The handle of the attribute to be written.
    pub attribute_handle: AttributeHandle,
    /// The offset of the first octet to be written.
    pub offset: usize,

    /// Number of valid bytes in |value_buf|
    value_len: usize,
    value_buf: [u8; MAX_WRITE_RESPONSE_VALUE_LEN],
}

// The maximum amount of data in the buffer is the max HCI packet size (255) less the other data in
// the packet.
const MAX_WRITE_RESPONSE_VALUE_LEN: usize = 246;

impl Debug for AttPrepareWriteResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{.conn_handle = {:?}, .attribute_handle = {:?}, .offset = {}, .value = {:?}}}",
            self.conn_handle,
            self.attribute_handle,
            self.offset,
            first_16(self.value())
        )
    }
}

impl AttPrepareWriteResponse {
    /// Returns the partial value of the attribute to be written.
    pub fn value(&self) -> &[u8] {
        &self.value_buf[..self.value_len]
    }
}

fn to_att_prepare_write_response(
    buffer: &[u8],
) -> Result<AttPrepareWriteResponse, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 9);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    let value_len = data_len - 4;
    let mut value_buf = [0; MAX_WRITE_RESPONSE_VALUE_LEN];
    value_buf[..value_len].copy_from_slice(&buffer[9..]);
    Ok(AttPrepareWriteResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attribute_handle: AttributeHandle(LittleEndian::read_u16(&buffer[5..])),
        offset: LittleEndian::read_u16(&buffer[7..]) as usize,
        value_len,
        value_buf,
    })
}

/// Defines the attribute value returned by a [GATT Indication](BlueNRGEvent::GattIndication) or
/// [GATT Notification](BlueNRGEvent::GattNotification) event.
#[derive(Copy, Clone)]
pub struct AttributeValue {
    /// The connection handle related to the event.
    pub conn_handle: ConnectionHandle,
    /// The handle of the attribute.
    pub attribute_handle: AttributeHandle,

    // Number of valid bytes in value_buf
    value_len: usize,
    // Current value of the attribute. Only the first value_len bytes are valid.
    value_buf: [u8; MAX_ATTRIBUTE_VALUE_LEN],
}

// The maximum amount of data in the buffer is the max HCI packet size (255) less the other data in
// the packet.
const MAX_ATTRIBUTE_VALUE_LEN: usize = 248;

impl Debug for AttributeValue {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{.conn_handle = {:?}, .attribute_handle = {:?}, .value = {:?}}}",
            self.conn_handle,
            self.attribute_handle,
            first_16(self.value())
        )
    }
}

impl AttributeValue {
    /// Returns the current value of the attribute.
    pub fn value(&self) -> &[u8] {
        &self.value_buf[..self.value_len]
    }
}

fn to_attribute_value(buffer: &[u8]) -> Result<AttributeValue, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 7);

    let data_len = buffer[4] as usize;
    require_len!(buffer, 5 + data_len);

    let value_len = data_len - 2;
    let mut value_buf = [0; MAX_ATTRIBUTE_VALUE_LEN];
    value_buf[..value_len].copy_from_slice(&buffer[7..]);
    Ok(AttributeValue {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attribute_handle: AttributeHandle(LittleEndian::read_u16(&buffer[5..])),
        value_len,
        value_buf,
    })
}

fn to_write_permit_request(
    buffer: &[u8],
) -> Result<AttributeValue, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 7);

    let data_len = buffer[6] as usize;
    require_len!(buffer, 7 + data_len);

    let value_len = data_len;
    let mut value_buf = [0; MAX_ATTRIBUTE_VALUE_LEN];
    value_buf[..value_len].copy_from_slice(&buffer[7..]);
    Ok(AttributeValue {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attribute_handle: AttributeHandle(LittleEndian::read_u16(&buffer[4..])),
        value_len,
        value_buf,
    })
}

/// This event is generated when a GATT client procedure completes either with error or
/// successfully.
#[derive(Copy, Clone, Debug)]
pub struct GattProcedureComplete {
    /// The connection handle for which the GATT procedure has completed.
    pub conn_handle: ConnectionHandle,

    /// Indicates whether the procedure completed with [error](GattProcedureStatus::Failed) or was
    /// [successful](GattProcedureStatus::Success).
    pub status: GattProcedureStatus,
}

/// Allowed status codes for the [GATT Procedure Complete](BlueNRGEvent::GattProcedureComplete)
/// event.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GattProcedureStatus {
    /// BLE Status Success
    Success,
    /// BLE Status Failed
    Failed,
}

impl TryFrom<u8> for GattProcedureStatus {
    type Error = BlueNRGError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0x00 => Ok(GattProcedureStatus::Success),
            0x41 => Ok(GattProcedureStatus::Failed),
            _ => Err(BlueNRGError::BadGattProcedureStatus(value)),
        }
    }
}

fn to_gatt_procedure_complete(
    buffer: &[u8],
) -> Result<GattProcedureComplete, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 6);

    Ok(GattProcedureComplete {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        status: buffer[5].try_into().map_err(hci::event::Error::Vendor)?,
    })
}

/// The Error Response is used to state that a given request cannot be performed, and to provide the
/// reason. See the Bluetooth Core Specification, v4.1, Vol 3, Part F, Section 3.4.1.1.
#[derive(Copy, Clone, Debug)]
pub struct AttErrorResponse {
    /// The connection handle related to the event.
    pub conn_handle: ConnectionHandle,
    /// The request that generated this error response.
    pub request: AttRequest,
    ///The attribute handle that generated this error response.
    pub attribute_handle: AttributeHandle,
    /// The reason why the request has generated an error response.
    pub error: AttError,
}

/// Potential error codes for the [ATT Error Response](BlueNRGEvent::AttErrorResponse). See Table
/// 3.3 in the Bluetooth Core Specification, v4.1, Vol 3, Part F, Section 3.4.1.1 and The Bluetooth
/// Core Specification Supplement, Table 1.1.
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AttError {
    /// The attribute handle given was not valid on this server.
    InvalidHandle = 0x01,
    /// The attribute cannot be read.
    ReadNotPermitted = 0x02,
    /// The attribute cannot be written.
    WriteNotPermitted = 0x03,
    /// The attribute PDU was invalid.
    InvalidPdu = 0x04,
    /// The attribute requires authentication before it can be read or written.
    InsufficientAuthentication = 0x05,
    /// Attribute server does not support the request received from the client.
    RequestNotSupported = 0x06,
    /// Offset specified was past the end of the attribute.
    InvalidOffset = 0x07,
    /// The attribute requires authorization before it can be read or written.
    InsufficientAuthorization = 0x08,
    /// Too many prepare writes have been queued.
    PrepareQueueFull = 0x09,
    /// No attribute found within the given attribute handle range.
    AttributeNotFound = 0x0A,
    /// The attribute cannot be read or written using the Read Blob Request.
    AttributeNotLong = 0x0B,
    /// The Encryption Key Size used for encrypting this link is insufficient.
    InsufficientEncryptionKeySize = 0x0C,
    /// The attribute value length is invalid for the operation.
    InvalidAttributeValueLength = 0x0D,
    /// The attribute request that was requested has encountered an error that was unlikely, and
    /// therefore could not be completed as requested.
    UnlikelyError = 0x0E,
    /// The attribute requires encryption before it can be read or written.
    InsufficientEncryption = 0x0F,
    /// The attribute type is not a supported grouping attribute as defined by a higher layer
    /// specification.
    UnsupportedGroupType = 0x10,
    /// Insufficient Resources to complete the request.
    InsufficientResources = 0x11,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x80 = 0x80,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x81 = 0x81,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x82 = 0x82,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x83 = 0x83,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x84 = 0x84,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x85 = 0x85,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x86 = 0x86,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x87 = 0x87,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x88 = 0x88,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x89 = 0x89,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x8A = 0x8A,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x8B = 0x8B,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x8C = 0x8C,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x8D = 0x8D,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x8E = 0x8E,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x8F = 0x8F,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x90 = 0x90,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x91 = 0x91,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x92 = 0x92,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x93 = 0x93,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x94 = 0x94,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x95 = 0x95,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x96 = 0x96,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x97 = 0x97,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x98 = 0x98,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x99 = 0x99,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x9A = 0x9A,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x9B = 0x9B,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x9C = 0x9C,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x9D = 0x9D,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x9E = 0x9E,
    /// Application error code defined by a higher layer specification.
    ApplicationError0x9F = 0x9F,
    /// The requested write operation cannot be fulfilled for reasons other than permissions.
    WriteRequestRejected = 0xFC,
    /// A Client Characteristic Configuration descriptor is not configured according to the
    /// requirements of the profile or service.
    ClientCharacteristicConfigurationDescriptorImproperlyConfigured = 0xFD,
    /// A profile or service request cannot be serviced because an operation that has been
    /// previously triggered is still in progress.
    ProcedureAlreadyInProgress = 0xFE,
    /// An attribute value is out of range as defined by a profile or service specification.
    OutOfRange = 0xFF,
}

impl TryFrom<u8> for AttError {
    type Error = u8;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0x01 => Ok(AttError::InvalidHandle),
            0x02 => Ok(AttError::ReadNotPermitted),
            0x03 => Ok(AttError::WriteNotPermitted),
            0x04 => Ok(AttError::InvalidPdu),
            0x05 => Ok(AttError::InsufficientAuthentication),
            0x06 => Ok(AttError::RequestNotSupported),
            0x07 => Ok(AttError::InvalidOffset),
            0x08 => Ok(AttError::InsufficientAuthorization),
            0x09 => Ok(AttError::PrepareQueueFull),
            0x0A => Ok(AttError::AttributeNotFound),
            0x0B => Ok(AttError::AttributeNotLong),
            0x0C => Ok(AttError::InsufficientEncryptionKeySize),
            0x0D => Ok(AttError::InvalidAttributeValueLength),
            0x0E => Ok(AttError::UnlikelyError),
            0x0F => Ok(AttError::InsufficientEncryption),
            0x10 => Ok(AttError::UnsupportedGroupType),
            0x11 => Ok(AttError::InsufficientResources),
            0x80 => Ok(AttError::ApplicationError0x80),
            0x81 => Ok(AttError::ApplicationError0x81),
            0x82 => Ok(AttError::ApplicationError0x82),
            0x83 => Ok(AttError::ApplicationError0x83),
            0x84 => Ok(AttError::ApplicationError0x84),
            0x85 => Ok(AttError::ApplicationError0x85),
            0x86 => Ok(AttError::ApplicationError0x86),
            0x87 => Ok(AttError::ApplicationError0x87),
            0x88 => Ok(AttError::ApplicationError0x88),
            0x89 => Ok(AttError::ApplicationError0x89),
            0x8A => Ok(AttError::ApplicationError0x8A),
            0x8B => Ok(AttError::ApplicationError0x8B),
            0x8C => Ok(AttError::ApplicationError0x8C),
            0x8D => Ok(AttError::ApplicationError0x8D),
            0x8E => Ok(AttError::ApplicationError0x8E),
            0x8F => Ok(AttError::ApplicationError0x8F),
            0x90 => Ok(AttError::ApplicationError0x90),
            0x91 => Ok(AttError::ApplicationError0x91),
            0x92 => Ok(AttError::ApplicationError0x92),
            0x93 => Ok(AttError::ApplicationError0x93),
            0x94 => Ok(AttError::ApplicationError0x94),
            0x95 => Ok(AttError::ApplicationError0x95),
            0x96 => Ok(AttError::ApplicationError0x96),
            0x97 => Ok(AttError::ApplicationError0x97),
            0x98 => Ok(AttError::ApplicationError0x98),
            0x99 => Ok(AttError::ApplicationError0x99),
            0x9A => Ok(AttError::ApplicationError0x9A),
            0x9B => Ok(AttError::ApplicationError0x9B),
            0x9C => Ok(AttError::ApplicationError0x9C),
            0x9D => Ok(AttError::ApplicationError0x9D),
            0x9E => Ok(AttError::ApplicationError0x9E),
            0x9F => Ok(AttError::ApplicationError0x9F),
            0xFC => Ok(AttError::WriteRequestRejected),
            0xFD => Ok(AttError::ClientCharacteristicConfigurationDescriptorImproperlyConfigured),
            0xFE => Ok(AttError::ProcedureAlreadyInProgress),
            0xFF => Ok(AttError::OutOfRange),
            _ => Err(value),
        }
    }
}

/// Possible ATT requests.  See Table 3.37 in the Bluetooth Core Spec v4.1, Vol 3, Part F, Section
/// 3.4.8.
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AttRequest {
    /// Section 3.4.1.1
    ErrorResponse = 0x01,
    /// Section 3.4.2.1
    ExchangeMtuRequest = 0x02,
    /// Section 3.4.2.2
    ExchangeMtuResponse = 0x03,
    /// Section 3.4.3.1
    FindInformationRequest = 0x04,
    /// Section 3.4.3.2
    FindInformationResponse = 0x05,
    /// Section 3.4.3.3
    FindByTypeValueRequest = 0x06,
    /// Section 3.4.3.4
    FindByTypeValueResponse = 0x07,
    /// Section 3.4.4.1
    ReadByTypeRequest = 0x08,
    /// Section 3.4.4.2
    ReadByTypeResponse = 0x09,
    /// Section 3.4.4.3
    ReadRequest = 0x0A,
    /// Section 3.4.4.4
    ReadResponse = 0x0B,
    /// Section 3.4.4.5
    ReadBlobRequest = 0x0C,
    /// Section 3.4.4.6
    ReadBlobResponse = 0x0D,
    /// Section 3.4.4.7
    ReadMultipleRequest = 0x0E,
    /// Section 3.4.4.8
    ReadMultipleResponse = 0x0F,
    /// Section 3.4.4.9
    ReadByGroupTypeRequest = 0x10,
    /// Section 3.4.4.10
    ReadByGroupTypeResponse = 0x11,
    /// Section 3.4.5.1
    WriteRequest = 0x12,
    /// Section 3.4.5.2
    WriteResponse = 0x13,
    /// Section 3.4.5.3
    WriteCommand = 0x52,
    /// Section 3.4.5.4
    SignedWriteCommand = 0xD2,
    /// Section 3.4.6.1
    PrepareWriteRequest = 0x16,
    /// Section 3.4.6.2
    PrepareWriteResponse = 0x17,
    /// Section 3.4.6.3
    ExecuteWriteRequest = 0x18,
    /// Section 3.4.6.4
    ExecuteWriteResponse = 0x19,
    /// Section 3.4.7.1
    HandleValueNotification = 0x1B,
    /// Section 3.4.7.2
    HandleValueIndication = 0x1D,
    /// Section 3.4.7.3
    HandleValueConfirmation = 0x1E,
}

impl TryFrom<u8> for AttRequest {
    type Error = BlueNRGError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0x01 => Ok(AttRequest::ErrorResponse),
            0x02 => Ok(AttRequest::ExchangeMtuRequest),
            0x03 => Ok(AttRequest::ExchangeMtuResponse),
            0x04 => Ok(AttRequest::FindInformationRequest),
            0x05 => Ok(AttRequest::FindInformationResponse),
            0x06 => Ok(AttRequest::FindByTypeValueRequest),
            0x07 => Ok(AttRequest::FindByTypeValueResponse),
            0x08 => Ok(AttRequest::ReadByTypeRequest),
            0x09 => Ok(AttRequest::ReadByTypeResponse),
            0x0A => Ok(AttRequest::ReadRequest),
            0x0B => Ok(AttRequest::ReadResponse),
            0x0C => Ok(AttRequest::ReadBlobRequest),
            0x0D => Ok(AttRequest::ReadBlobResponse),
            0x0E => Ok(AttRequest::ReadMultipleRequest),
            0x0F => Ok(AttRequest::ReadMultipleResponse),
            0x10 => Ok(AttRequest::ReadByGroupTypeRequest),
            0x11 => Ok(AttRequest::ReadByGroupTypeResponse),
            0x12 => Ok(AttRequest::WriteRequest),
            0x13 => Ok(AttRequest::WriteResponse),
            0x52 => Ok(AttRequest::WriteCommand),
            0xD2 => Ok(AttRequest::SignedWriteCommand),
            0x16 => Ok(AttRequest::PrepareWriteRequest),
            0x17 => Ok(AttRequest::PrepareWriteResponse),
            0x18 => Ok(AttRequest::ExecuteWriteRequest),
            0x19 => Ok(AttRequest::ExecuteWriteResponse),
            0x1B => Ok(AttRequest::HandleValueNotification),
            0x1D => Ok(AttRequest::HandleValueIndication),
            0x1E => Ok(AttRequest::HandleValueConfirmation),
            _ => Err(BlueNRGError::BadAttRequestOpcode(value)),
        }
    }
}

fn to_att_error_response(
    buffer: &[u8],
) -> Result<AttErrorResponse, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 9);
    Ok(AttErrorResponse {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        request: buffer[5].try_into().map_err(hci::event::Error::Vendor)?,
        attribute_handle: AttributeHandle(LittleEndian::read_u16(&buffer[6..])),
        error: buffer[8]
            .try_into()
            .map_err(BlueNRGError::BadAttError)
            .map_err(hci::event::Error::Vendor)?,
    })
}

/// This event is given to the application when a read request or read blob request is received by
/// the server from the client. This event will be given to the application only if the event bit
/// for this event generation is set when the characteristic was added. On receiving this event, the
/// application can update the value of the handle if it desires and when done it has to use the
/// [`allow_read`](crate::gatt::Commands::allow_read) command to indicate to the stack that it can
/// send the response to the client.
///
/// See the Bluetooth Core v4.1 spec, Vol 3, Part F, section 3.4.4.
#[derive(Copy, Clone, Debug)]
pub struct AttReadPermitRequest {
    /// Handle of the connection on which there was the request to read the attribute
    pub conn_handle: ConnectionHandle,

    /// The handle of the attribute that has been requested by the client to be read.
    pub attribute_handle: AttributeHandle,

    /// Contains the offset from which the read has been requested.
    pub offset: usize,
}

fn to_att_read_permit_request(
    buffer: &[u8],
) -> Result<AttReadPermitRequest, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 9);
    Ok(AttReadPermitRequest {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attribute_handle: AttributeHandle(LittleEndian::read_u16(&buffer[4..])),
        offset: LittleEndian::read_u16(&buffer[7..]) as usize,
    })
}

/// This event is given to the application when a read multiple request or read by type request is
/// received by the server from the client. This event will be given to the application only if the
/// event bit for this event generation is set when the characteristic was added.  On receiving this
/// event, the application can update the values of the handles if it desires and when done it has
/// to send the `gatt_allow_read` command to indicate to the stack that it can send the response to
/// the client.
///
/// See the Bluetooth Core v4.1 spec, Vol 3, Part F, section 3.4.4.
#[derive(Copy, Clone)]
pub struct AttReadMultiplePermitRequest {
    /// Handle of the connection which requested to read the attribute.
    pub conn_handle: ConnectionHandle,

    /// Number of valid handles in handles_buf
    handles_len: usize,
    /// Attribute handles returned by the ATT Read Multiple Permit Request. Only the first
    /// `handles_len` handles are valid.
    handles_buf: [AttributeHandle; MAX_ATTRIBUTE_HANDLE_BUFFER_LEN],
}

// The maximum number of handles in the buffer is the max HCI packet size (255) less the other data in
// the packet divided by the length of an attribute handle (2).
const MAX_ATTRIBUTE_HANDLE_BUFFER_LEN: usize = 125;

impl Debug for AttReadMultiplePermitRequest {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{.conn_handle = {:?}, .handles = {:?}",
            self.conn_handle,
            first_16(self.handles())
        )
    }
}

impl AttReadMultiplePermitRequest {
    /// Returns the valid attribute handles returned by the ATT Read Multiple Permit Request event.
    pub fn handles(&self) -> &[AttributeHandle] {
        &self.handles_buf[..self.handles_len]
    }
}

fn to_att_read_multiple_permit_request(
    buffer: &[u8],
) -> Result<AttReadMultiplePermitRequest, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 5);

    let data_len = buffer[4] as usize;
    if data_len % 2 != 0 {
        return Err(hci::event::Error::Vendor(
            BlueNRGError::AttReadMultiplePermitRequestPartial,
        ));
    }

    let handle_len = data_len / 2;
    let mut handles = [AttributeHandle(0); MAX_ATTRIBUTE_HANDLE_BUFFER_LEN];
    for (i, handle) in handles.iter_mut().enumerate().take(handle_len) {
        let index = 5 + 2 * i;
        *handle = AttributeHandle(LittleEndian::read_u16(&buffer[index..]));
    }

    Ok(AttReadMultiplePermitRequest {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        handles_len: handle_len,
        handles_buf: handles,
    })
}

/// This event is raised when the number of available TX buffers is above a threshold TH (TH = 2).
/// The event will be given only if a previous ACI command returned with
/// [`InsufficientResources`](AttError::InsufficientResources).
#[cfg(feature = "ms")]
#[derive(Copy, Clone, Debug)]
pub struct GattTxPoolAvailable {
    /// Connection handle on which the GATT procedure is running.
    pub conn_handle: ConnectionHandle,
    /// Indicates the number of elements available in the attrTxPool List.
    pub available_buffers: usize,
}

#[cfg(feature = "ms")]
fn to_gatt_tx_pool_available(
    buffer: &[u8],
) -> Result<GattTxPoolAvailable, hci::event::Error<BlueNRGError>> {
    require_len!(buffer, 6);
    Ok(GattTxPoolAvailable {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        available_buffers: LittleEndian::read_u16(&buffer[4..]) as usize,
    })
}

/// This event is given to the application when a prepare write request is received by the server
/// from the client.
///
/// This event will be given to the application only if the event bit for this event generation is
/// set when the characteristic was added.  When this event is received, the application has to
/// check whether the value being requested for write is allowed to be written and respond with the
/// command `gatt_write_response`.  Based on the response from the application, the attribute value
/// will be modified by the stack.  If the write is rejected by the application, then the value of
/// the attribute will not be modified and an error response will be sent to the client, with the
/// error code as specified by the application.
#[cfg(feature = "ms")]
#[derive(Copy, Clone)]
pub struct AttPrepareWritePermitRequest {
    /// Connection handle on which the GATT procedure is running.
    pub conn_handle: ConnectionHandle,
    /// The handle of the attribute to be written.
    pub attribute_handle: AttributeHandle,
    /// The offset of the first octet to be written.
    pub offset: usize,

    // Number of valid bytes in `value_buf`
    value_len: usize,
    // The data to be written. Only the first `value_len` bytes are valid.
    value_buf: [u8; MAX_PREPARE_WRITE_PERMIT_REQ_VALUE_LEN],
}

// The maximum number of bytes in the buffer is the max HCI packet size (255) less the other data in
// the packet.
#[cfg(feature = "ms")]
const MAX_PREPARE_WRITE_PERMIT_REQ_VALUE_LEN: usize = 246;

#[cfg(feature = "ms")]
impl Debug for AttPrepareWritePermitRequest {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "{{.conn_handle = {:?}, .attribute_handle = {:?}, .offset = {:?}, .value = {:?}",
            self.conn_handle,
            self.attribute_handle,
            self.offset,
            first_16(self.value())
        )
    }
}

#[cfg(feature = "ms")]
impl AttPrepareWritePermitRequest {
    /// Returns the data to be written.
    pub fn value(&self) -> &[u8] {
        &self.value_buf[..self.value_len]
    }
}

#[cfg(feature = "ms")]
fn to_att_prepare_write_permit_request(
    buffer: &[u8],
) -> Result<AttPrepareWritePermitRequest, hci::event::Error<BlueNRGError>> {
    require_len_at_least!(buffer, 9);

    let data_len = buffer[8] as usize;
    require_len!(buffer, 9 + data_len);

    let mut value_buf = [0; MAX_PREPARE_WRITE_PERMIT_REQ_VALUE_LEN];
    value_buf[..data_len].copy_from_slice(&buffer[9..]);
    Ok(AttPrepareWritePermitRequest {
        conn_handle: ConnectionHandle(LittleEndian::read_u16(&buffer[2..])),
        attribute_handle: AttributeHandle(LittleEndian::read_u16(&buffer[4..])),
        offset: LittleEndian::read_u16(&buffer[6..]) as usize,
        value_len: data_len,
        value_buf,
    })
}