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};
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Copy, Debug)]
pub enum BlueNRGEvent {
HalInitialized(ResetReason),
#[cfg(feature = "ms")]
EventsLost(EventFlags),
#[cfg(feature = "ms")]
CrashReport(FaultData),
GapLimitedDiscoverableTimeout,
GapPairingComplete(GapPairingComplete),
GapPassKeyRequest(ConnectionHandle),
GapAuthorizationRequest(ConnectionHandle),
GapPeripheralSecurityInitiated,
GapBondLost,
GapDeviceFound(GapDeviceFound),
GapProcedureComplete(GapProcedureComplete),
#[cfg(feature = "ms")]
GapAddressNotResolved(ConnectionHandle),
#[cfg(not(feature = "ms"))]
GapReconnectionAddress(BdAddr),
L2CapConnectionUpdateResponse(L2CapConnectionUpdateResponse),
L2CapProcedureTimeout(ConnectionHandle),
L2CapConnectionUpdateRequest(L2CapConnectionUpdateRequest),
GattAttributeModified(GattAttributeModified),
GattProcedureTimeout(ConnectionHandle),
AttExchangeMtuResponse(AttExchangeMtuResponse),
AttFindInformationResponse(AttFindInformationResponse),
AttFindByTypeValueResponse(AttFindByTypeValueResponse),
AttReadByTypeResponse(AttReadByTypeResponse),
AttReadResponse(AttReadResponse),
AttReadBlobResponse(AttReadResponse),
AttReadMultipleResponse(AttReadResponse),
AttReadByGroupTypeResponse(AttReadByGroupTypeResponse),
AttPrepareWriteResponse(AttPrepareWriteResponse),
AttExecuteWriteResponse(ConnectionHandle),
GattIndication(AttributeValue),
GattNotification(AttributeValue),
GattProcedureComplete(GattProcedureComplete),
AttErrorResponse(AttErrorResponse),
GattDiscoverOrReadCharacteristicByUuidResponse(AttributeValue),
AttWritePermitRequest(AttributeValue),
AttReadPermitRequest(AttReadPermitRequest),
AttReadMultiplePermitRequest(AttReadMultiplePermitRequest),
#[cfg(feature = "ms")]
GattTxPoolAvailable(GattTxPoolAvailable),
#[cfg(feature = "ms")]
GattServerConfirmation(ConnectionHandle),
#[cfg(feature = "ms")]
AttPrepareWritePermitRequest(AttPrepareWritePermitRequest),
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum Status {
Failed = 0x41,
InvalidParameters = 0x42,
NotAllowed = 0x46,
Error = 0x47,
AddressNotResolved = 0x48,
FlashReadFailed = 0x49,
FlashWriteFailed = 0x4A,
FlashEraseFailed = 0x4B,
InvalidCid = 0x50,
TimerNotValidLayer = 0x54,
TimerInsufficientResources = 0x55,
CsrkNotFound = 0x5A,
IrkNotFound = 0x5B,
DeviceNotFoundInDatabase = 0x5C,
SecurityDatabaseFull = 0x5D,
DeviceNotBonded = 0x5E,
DeviceInBlacklist = 0x5F,
InvalidHandle = 0x60,
InvalidParameter = 0x61,
OutOfHandle = 0x62,
InvalidOperation = 0x63,
InsufficientResources = 0x64,
InsufficientEncryptionKeySize = 0x65,
CharacteristicAlreadyExists = 0x66,
NoValidSlot = 0x82,
ScanWindowTooShort = 0x83,
NewIntervalFailed = 0x84,
IntervalTooLarge = 0x85,
LengthFailed = 0x86,
Timeout = 0xFF,
ProfileAlreadyInitialized = 0xF0,
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
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BlueNRGError {
UnknownEvent(u16),
UnknownResetReason(u8),
#[cfg(feature = "ms")]
BadEventFlags(u64),
#[cfg(feature = "ms")]
UnknownCrashReason(u8),
BadGapPairingStatus(u8),
BadGapDeviceFoundEvent(u8),
BadGapBdAddrType(u8),
BadGapProcedure(u8),
BadGapProcedureStatus(u8),
BadL2CapDataLength(u8, u8),
BadL2CapLength(u16, u16),
BadL2CapRejectionReason(u16),
BadL2CapConnectionResponseCode(u8),
BadL2CapConnectionResponseResult(u16),
BadConnectionInterval(ConnectionIntervalError),
BadL2CapConnectionUpdateRequestInterval(Duration, Duration),
BadL2CapConnectionUpdateRequestLatency(u16, u16),
BadL2CapConnectionUpdateRequestTimeout(Duration),
BadAttFindInformationResponseFormat(u8),
AttFindInformationResponsePartialPair16,
AttFindInformationResponsePartialPair128,
AttFindByTypeValuePartial,
AttReadByTypeResponsePartial,
AttReadByGroupTypeResponsePartial,
BadGattProcedureStatus(u8),
BadAttRequestOpcode(u8),
BadAttError(u8),
AttReadMultiplePermitRequestPartial,
BadConfigParameterLength(usize),
UnknownLinkState(u8),
BadBooleanValue(u8),
BadPassKeyRequirement(u8),
PartialBondedDeviceAddress,
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,
))),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ResetReason {
Normal,
Updater,
UpdaterBadFlag,
UpdaterPin,
Watchdog,
Lockup,
Brownout,
Crash,
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)),
}
}
}
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! {
#[derive(Default)]
pub struct EventFlags: u64 {
const DISCONNECTION_COMPLETE = 1 << 0;
const ENCRYPTION_CHANGE = 1 << 1;
const READ_REMOTE_VERSION_COMPLETE = 1 << 2;
const COMMAND_COMPLETE = 1 << 3;
const COMMAND_STATUS = 1 << 4;
const HARDWARE_ERROR = 1 << 5;
const NUMBER_OF_COMPLETED_PACKETS = 1 << 6;
const ENCRYPTION_KEY_REFRESH = 1 << 7;
const HAL_INITIALIZED = 1 << 8;
const GAP_LIMITED_DISCOVERABLE_TIMEOUT = 1 << 9;
const GAP_PAIRING_COMPLETE = 1 << 10;
const GAP_PASS_KEY_REQUEST = 1 << 11;
const GAP_AUTHORIZATION_REQUEST = 1 << 12;
const GAP_PERIPHERAL_SECURITY_INITIATED = 1 << 13;
const GAP_BOND_LOST = 1 << 14;
const GAP_PROCEDURE_COMPLETE = 1 << 15;
const GAP_ADDRESS_NOT_RESOLVED = 1 << 16;
const L2CAP_CONNECTION_UPDATE_RESPONSE = 1 << 17;
const L2CAP_PROCEDURE_TIMEOUT = 1 << 18;
const L2CAP_CONNECTION_UPDATE_REQUEST = 1 << 19;
const GATT_ATTRIBUTE_MODIFIED = 1 << 20;
const GATT_PROCEDURE_TIMEOUT = 1 << 21;
const ATT_EXCHANGE_MTU_RESPONSE = 1 << 22;
const ATT_FIND_INFORMATION_RESPONSE = 1 << 23;
const ATT_FIND_BY_TYPE_VALUE_RESPONSE = 1 << 24;
const ATT_READ_BY_TYPE_RESPONSE = 1 << 25;
const ATT_READ_RESPONSE = 1 << 26;
const ATT_READ_BLOB_RESPONSE = 1 << 27;
const ATT_READ_MULTIPLE_RESPONSE = 1 << 28;
const ATT_READ_BY_GROUP_TYPE_RESPONSE = 1 << 29;
const ATT_WRITE_RESPONSE = 1 << 30;
const ATT_PREPARE_WRITE_RESPONSE = 1 << 31;
const ATT_EXECUTE_WRITE_RESPONSE = 1 << 32;
const GATT_INDICATION = 1 << 33;
const GATT_NOTIFICATION = 1 << 34;
const GATT_PROCEDURE_COMPLETE = 1 << 35;
const GATT_ERROR_RESPONSE = 1 << 36;
const GATT_DISCOVER_OR_READ_CHARACTERISTIC_BY_UUID_RESPONSE = 1 << 37;
const GATT_WRITE_PERMIT_REQUEST = 1 << 38;
const GATT_READ_PERMIT_REQUEST = 1 << 39;
const GATT_READ_MULTIPLE_PERMIT_REQUEST = 1 << 40;
const GATT_TX_POOL_AVAILABLE = 1 << 41;
const GATT_SERVER_RX_CONFIRMATION = 1 << 42;
const GATT_PREPARE_WRITE_PERMIT_REQUEST = 1 << 43;
const LINK_LAYER_CONNECTION_COMPLETE = 1 << 44;
const LINK_LAYER_ADVERTISING_REPORT = 1 << 45;
const LINK_LAYER_CONNECTION_UPDATE_COMPLETE = 1 << 46;
const LINK_LAYER_READ_REMOTE_USED_FEATURES = 1 << 47;
const LINK_LAYER_LTK_REQUEST = 1 << 48;
}
}
#[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)))
}
#[cfg(feature = "ms")]
const MAX_DEBUG_DATA_LEN: usize = 215;
#[cfg(feature = "ms")]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CrashReason {
Assertion,
NmiFault,
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),
1 | 6 => Ok(CrashReason::NmiFault),
2 | 7 => Ok(CrashReason::HardFault),
_ => Err(BlueNRGError::UnknownCrashReason(value)),
}
}
}
#[cfg(feature = "ms")]
#[derive(Clone, Copy)]
pub struct FaultData {
pub reason: CrashReason,
pub sp: u32,
pub r0: u32,
pub r1: u32,
pub r2: u32,
pub r3: u32,
pub r12: u32,
pub lr: u32,
pub pc: u32,
pub xpsr: u32,
debug_data_len: usize,
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 {
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,
)));
}
};
}
#[derive(Copy, Clone, Debug)]
pub struct L2CapConnectionUpdateResponse {
pub conn_handle: ConnectionHandle,
pub result: L2CapConnectionUpdateResult,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum L2CapRejectionReason {
CommandNotUnderstood,
SignalingMtuExceeded,
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)),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum L2CapConnectionUpdateResult {
CommandRejected(L2CapRejectionReason),
ParametersRejected,
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)?,
})
}
#[derive(Copy, Clone, Debug)]
pub struct L2CapProcedureTimeout {
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..])))
}
#[derive(Copy, Clone, Debug)]
pub struct L2CapConnectionUpdateRequest {
pub conn_handle: ConnectionHandle,
pub identifier: u8,
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,
})
}
#[derive(Copy, Clone, Debug)]
pub struct GapPairingComplete {
pub conn_handle: ConnectionHandle,
pub status: GapPairingStatus,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GapPairingStatus {
Success,
Timeout,
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..])))
}
#[derive(Copy, Clone, Debug)]
pub struct GapDeviceFound {
pub event: GapDeviceFoundEvent,
pub bdaddr: BdAddrType,
data_len: usize,
data_buf: [u8; 31],
pub rssi: Option<i8>,
}
impl GapDeviceFound {
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)
}
#[derive(Copy, Clone, Debug)]
pub struct GapProcedureComplete {
pub procedure: GapProcedure,
pub status: GapProcedureStatus,
}
pub const MAX_NAME_LEN: usize = 248;
#[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
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GapProcedure {
LimitedDiscovery,
GeneralDiscovery,
NameDiscovery(usize, NameBuffer),
AutoConnectionEstablishment,
GeneralConnectionEstablishment(BdAddr),
SelectiveConnectionEstablishment,
DirectConnectionEstablishment,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GapProcedureStatus {
Success,
Failed,
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)
}
#[derive(Copy, Clone)]
pub struct GattAttributeModified {
pub conn_handle: ConnectionHandle,
pub attr_handle: AttributeHandle,
#[cfg(feature = "ms")]
pub offset: usize,
#[cfg(feature = "ms")]
pub continued: bool,
data_len: usize,
data_buf: [u8; MAX_ATTRIBUTE_LEN],
}
impl GattAttributeModified {
pub fn data(&self) -> &[u8] {
&self.data_buf[..self.data_len]
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct AttributeHandle(pub u16);
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,
})
}
#[derive(Copy, Clone, Debug)]
pub struct AttExchangeMtuResponse {
pub conn_handle: ConnectionHandle,
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,
})
}
#[derive(Copy, Clone, Debug)]
pub struct AttFindInformationResponse {
pub conn_handle: ConnectionHandle,
handle_uuid_pairs: HandleUuidPairs,
}
impl AttFindInformationResponse {
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,
})
}
}
}
}
const MAX_FORMAT16_PAIR_COUNT: usize = 62;
const MAX_FORMAT128_PAIR_COUNT: usize = 13;
#[derive(Copy, Clone, Debug)]
pub struct HandleUuid16Pair {
pub handle: AttributeHandle,
pub uuid: Uuid16,
}
#[derive(Copy, Clone, Debug)]
pub struct HandleUuid128Pair {
pub handle: AttributeHandle,
pub uuid: Uuid128,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Uuid16(pub u16);
#[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, "}}")
}
}
pub enum HandleUuidPairIterator<'a> {
Format16(HandleUuid16PairIterator<'a>),
Format128(HandleUuid128PairIterator<'a>),
}
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])
}
}
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))
}
#[derive(Copy, Clone)]
pub struct AttFindByTypeValueResponse {
pub conn_handle: ConnectionHandle,
handle_pair_count: usize,
handles: [HandleInfoPair; MAX_HANDLE_INFO_PAIR_COUNT],
}
impl AttFindByTypeValueResponse {
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, "}}")
}
}
const MAX_HANDLE_INFO_PAIR_COUNT: usize = 62;
#[derive(Copy, Clone, Debug)]
pub struct HandleInfoPair {
pub attribute: AttributeHandle,
pub group_end: GroupEndHandle,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct GroupEndHandle(pub u16);
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,
})
}
#[derive(Copy, Clone)]
pub struct AttReadByTypeResponse {
pub conn_handle: ConnectionHandle,
data_len: usize,
value_len: usize,
handle_value_pair_buf: [u8; MAX_HANDLE_VALUE_PAIR_BUF_LEN],
}
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 {
pub fn handle_value_pair_iter(&self) -> HandleValuePairIterator {
HandleValuePairIterator {
event: &self,
index: 0,
}
}
}
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],
})
}
}
pub struct HandleValuePair<'a> {
pub handle: AttributeHandle,
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,
})
}
#[derive(Copy, Clone)]
pub struct AttReadResponse {
pub conn_handle: ConnectionHandle,
value_len: usize,
value_buf: [u8; MAX_READ_RESPONSE_LEN],
}
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 {
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,
})
}
#[derive(Copy, Clone)]
pub struct AttReadByGroupTypeResponse {
pub conn_handle: ConnectionHandle,
data_len: usize,
attribute_group_len: usize,
attribute_data_buf: [u8; MAX_ATTRIBUTE_DATA_BUF_LEN],
}
const MAX_ATTRIBUTE_DATA_BUF_LEN: usize = 249;
impl AttReadByGroupTypeResponse {
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, "}}")
}
}
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],
})
}
}
pub struct AttributeData<'a> {
pub attribute_handle: AttributeHandle,
pub group_end_handle: GroupEndHandle,
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, attribute_group_len,
attribute_data_buf,
})
}
#[derive(Copy, Clone)]
pub struct AttPrepareWriteResponse {
pub conn_handle: ConnectionHandle,
pub attribute_handle: AttributeHandle,
pub offset: usize,
value_len: usize,
value_buf: [u8; MAX_WRITE_RESPONSE_VALUE_LEN],
}
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 {
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,
})
}
#[derive(Copy, Clone)]
pub struct AttributeValue {
pub conn_handle: ConnectionHandle,
pub attribute_handle: AttributeHandle,
value_len: usize,
value_buf: [u8; MAX_ATTRIBUTE_VALUE_LEN],
}
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 {
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,
})
}
#[derive(Copy, Clone, Debug)]
pub struct GattProcedureComplete {
pub conn_handle: ConnectionHandle,
pub status: GattProcedureStatus,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GattProcedureStatus {
Success,
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)?,
})
}
#[derive(Copy, Clone, Debug)]
pub struct AttErrorResponse {
pub conn_handle: ConnectionHandle,
pub request: AttRequest,
pub attribute_handle: AttributeHandle,
pub error: AttError,
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AttError {
InvalidHandle = 0x01,
ReadNotPermitted = 0x02,
WriteNotPermitted = 0x03,
InvalidPdu = 0x04,
InsufficientAuthentication = 0x05,
RequestNotSupported = 0x06,
InvalidOffset = 0x07,
InsufficientAuthorization = 0x08,
PrepareQueueFull = 0x09,
AttributeNotFound = 0x0A,
AttributeNotLong = 0x0B,
InsufficientEncryptionKeySize = 0x0C,
InvalidAttributeValueLength = 0x0D,
UnlikelyError = 0x0E,
InsufficientEncryption = 0x0F,
UnsupportedGroupType = 0x10,
InsufficientResources = 0x11,
ApplicationError0x80 = 0x80,
ApplicationError0x81 = 0x81,
ApplicationError0x82 = 0x82,
ApplicationError0x83 = 0x83,
ApplicationError0x84 = 0x84,
ApplicationError0x85 = 0x85,
ApplicationError0x86 = 0x86,
ApplicationError0x87 = 0x87,
ApplicationError0x88 = 0x88,
ApplicationError0x89 = 0x89,
ApplicationError0x8A = 0x8A,
ApplicationError0x8B = 0x8B,
ApplicationError0x8C = 0x8C,
ApplicationError0x8D = 0x8D,
ApplicationError0x8E = 0x8E,
ApplicationError0x8F = 0x8F,
ApplicationError0x90 = 0x90,
ApplicationError0x91 = 0x91,
ApplicationError0x92 = 0x92,
ApplicationError0x93 = 0x93,
ApplicationError0x94 = 0x94,
ApplicationError0x95 = 0x95,
ApplicationError0x96 = 0x96,
ApplicationError0x97 = 0x97,
ApplicationError0x98 = 0x98,
ApplicationError0x99 = 0x99,
ApplicationError0x9A = 0x9A,
ApplicationError0x9B = 0x9B,
ApplicationError0x9C = 0x9C,
ApplicationError0x9D = 0x9D,
ApplicationError0x9E = 0x9E,
ApplicationError0x9F = 0x9F,
WriteRequestRejected = 0xFC,
ClientCharacteristicConfigurationDescriptorImproperlyConfigured = 0xFD,
ProcedureAlreadyInProgress = 0xFE,
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),
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AttRequest {
ErrorResponse = 0x01,
ExchangeMtuRequest = 0x02,
ExchangeMtuResponse = 0x03,
FindInformationRequest = 0x04,
FindInformationResponse = 0x05,
FindByTypeValueRequest = 0x06,
FindByTypeValueResponse = 0x07,
ReadByTypeRequest = 0x08,
ReadByTypeResponse = 0x09,
ReadRequest = 0x0A,
ReadResponse = 0x0B,
ReadBlobRequest = 0x0C,
ReadBlobResponse = 0x0D,
ReadMultipleRequest = 0x0E,
ReadMultipleResponse = 0x0F,
ReadByGroupTypeRequest = 0x10,
ReadByGroupTypeResponse = 0x11,
WriteRequest = 0x12,
WriteResponse = 0x13,
WriteCommand = 0x52,
SignedWriteCommand = 0xD2,
PrepareWriteRequest = 0x16,
PrepareWriteResponse = 0x17,
ExecuteWriteRequest = 0x18,
ExecuteWriteResponse = 0x19,
HandleValueNotification = 0x1B,
HandleValueIndication = 0x1D,
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)?,
})
}
#[derive(Copy, Clone, Debug)]
pub struct AttReadPermitRequest {
pub conn_handle: ConnectionHandle,
pub attribute_handle: AttributeHandle,
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,
})
}
#[derive(Copy, Clone)]
pub struct AttReadMultiplePermitRequest {
pub conn_handle: ConnectionHandle,
handles_len: usize,
handles_buf: [AttributeHandle; MAX_ATTRIBUTE_HANDLE_BUFFER_LEN],
}
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 {
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,
})
}
#[cfg(feature = "ms")]
#[derive(Copy, Clone, Debug)]
pub struct GattTxPoolAvailable {
pub conn_handle: ConnectionHandle,
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,
})
}
#[cfg(feature = "ms")]
#[derive(Copy, Clone)]
pub struct AttPrepareWritePermitRequest {
pub conn_handle: ConnectionHandle,
pub attribute_handle: AttributeHandle,
pub offset: usize,
value_len: usize,
value_buf: [u8; MAX_PREPARE_WRITE_PERMIT_REQ_VALUE_LEN],
}
#[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 {
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,
})
}