//! 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,
})
}