extern crate bluetooth_hci as hci;
use byteorder::{ByteOrder, LittleEndian};
use core::convert::{TryFrom, TryInto};
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::time::Duration;
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
pub enum ReturnParameters {
HalGetFirmwareRevision(HalFirmwareRevision),
HalWriteConfigData(hci::Status<crate::event::Status>),
HalReadConfigData(HalConfigData),
HalSetTxPowerLevel(hci::Status<crate::event::Status>),
HalDeviceStandby(hci::Status<crate::event::Status>),
HalGetTxTestPacketCount(HalTxTestPacketCount),
HalStartTone(hci::Status<crate::event::Status>),
HalStopTone(hci::Status<crate::event::Status>),
HalGetLinkStatus(HalLinkStatus),
HalGetAnchorPeriod(HalAnchorPeriod),
GapSetNonDiscoverable(hci::Status<crate::event::Status>),
GapSetDiscoverable(hci::Status<crate::event::Status>),
GapSetDirectConnectable(hci::Status<crate::event::Status>),
GapSetIoCapability(hci::Status<crate::event::Status>),
GapSetAuthenticationRequirement(hci::Status<crate::event::Status>),
GapSetAuthorizationRequirement(hci::Status<crate::event::Status>),
GapPassKeyResponse(hci::Status<crate::event::Status>),
GapAuthorizationResponse(hci::Status<crate::event::Status>),
GapInit(GapInit),
GapSetNonConnectable(hci::Status<crate::event::Status>),
GapSetUndirectedConnectable(hci::Status<crate::event::Status>),
GapUpdateAdvertisingData(hci::Status<crate::event::Status>),
GapDeleteAdType(hci::Status<crate::event::Status>),
GapGetSecurityLevel(GapSecurityLevel),
GapSetEventMask(hci::Status<crate::event::Status>),
GapConfigureWhiteList(hci::Status<crate::event::Status>),
GapClearSecurityDatabase(hci::Status<crate::event::Status>),
GapAllowRebond(hci::Status<crate::event::Status>),
GapTerminateProcedure(hci::Status<crate::event::Status>),
#[cfg(not(feature = "ms"))]
GapResolvePrivateAddress(hci::Status<crate::event::Status>),
#[cfg(feature = "ms")]
GapResolvePrivateAddress(GapResolvePrivateAddress),
GapGetBondedDevices(GapBondedDevices),
#[cfg(feature = "ms")]
GapSetBroadcastMode(hci::Status<crate::event::Status>),
#[cfg(feature = "ms")]
GapStartObservationProcedure(hci::Status<crate::event::Status>),
GapIsDeviceBonded(hci::Status<crate::event::Status>),
GattInit(hci::Status<crate::event::Status>),
GattAddService(GattService),
GattIncludeService(GattService),
GattAddCharacteristic(GattCharacteristic),
GattAddCharacteristicDescriptor(GattCharacteristicDescriptor),
GattUpdateCharacteristicValue(hci::Status<crate::event::Status>),
GattDeleteCharacteristic(hci::Status<crate::event::Status>),
GattDeleteService(hci::Status<crate::event::Status>),
GattDeleteIncludedService(hci::Status<crate::event::Status>),
GattSetEventMask(hci::Status<crate::event::Status>),
GattWriteWithoutResponse(hci::Status<crate::event::Status>),
GattSignedWriteWithoutResponse(hci::Status<crate::event::Status>),
GattConfirmIndication(hci::Status<crate::event::Status>),
GattWriteResponse(hci::Status<crate::event::Status>),
GattAllowRead(hci::Status<crate::event::Status>),
GattSetSecurityPermission(hci::Status<crate::event::Status>),
GattSetDescriptorValue(hci::Status<crate::event::Status>),
GattReadHandleValue(GattHandleValue),
#[cfg(feature = "ms")]
GattReadHandleValueOffset(GattHandleValue),
#[cfg(feature = "ms")]
GattUpdateLongCharacteristicValue(hci::Status<crate::event::Status>),
L2CapConnectionParameterUpdateResponse(hci::Status<crate::event::Status>),
}
impl hci::event::VendorReturnParameters for ReturnParameters {
type Error = super::BlueNRGError;
fn new(bytes: &[u8]) -> Result<Self, hci::event::Error<Self::Error>> {
check_len_at_least(bytes, 3)?;
match hci::Opcode(LittleEndian::read_u16(&bytes[1..])) {
crate::opcode::HAL_GET_FIRMWARE_REVISION => Ok(
ReturnParameters::HalGetFirmwareRevision(to_hal_firmware_revision(&bytes[3..])?),
),
crate::opcode::HAL_WRITE_CONFIG_DATA => Ok(ReturnParameters::HalWriteConfigData(
to_status(&bytes[3..])?,
)),
crate::opcode::HAL_READ_CONFIG_DATA => Ok(ReturnParameters::HalReadConfigData(
to_hal_config_data(&bytes[3..])?,
)),
crate::opcode::HAL_SET_TX_POWER_LEVEL => Ok(ReturnParameters::HalSetTxPowerLevel(
to_status(&bytes[3..])?,
)),
crate::opcode::HAL_DEVICE_STANDBY => {
Ok(ReturnParameters::HalDeviceStandby(to_status(&bytes[3..])?))
}
crate::opcode::HAL_TX_TEST_PACKET_COUNT => {
Ok(ReturnParameters::HalGetTxTestPacketCount(
to_hal_tx_test_packet_count(&bytes[3..])?,
))
}
crate::opcode::HAL_START_TONE => {
Ok(ReturnParameters::HalStartTone(to_status(&bytes[3..])?))
}
crate::opcode::HAL_STOP_TONE => {
Ok(ReturnParameters::HalStopTone(to_status(&bytes[3..])?))
}
crate::opcode::HAL_GET_LINK_STATUS => Ok(ReturnParameters::HalGetLinkStatus(
to_hal_link_status(&bytes[3..])?,
)),
crate::opcode::HAL_GET_ANCHOR_PERIOD => Ok(ReturnParameters::HalGetAnchorPeriod(
to_hal_anchor_period(&bytes[3..])?,
)),
crate::opcode::GAP_SET_NONDISCOVERABLE => Ok(ReturnParameters::GapSetNonDiscoverable(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_SET_DISCOVERABLE => Ok(ReturnParameters::GapSetDiscoverable(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_SET_DIRECT_CONNECTABLE => Ok(
ReturnParameters::GapSetDirectConnectable(to_status(&bytes[3..])?),
),
crate::opcode::GAP_SET_IO_CAPABILITY => Ok(ReturnParameters::GapSetIoCapability(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_SET_AUTHENTICATION_REQUIREMENT => Ok(
ReturnParameters::GapSetAuthenticationRequirement(to_status(&bytes[3..])?),
),
crate::opcode::GAP_SET_AUTHORIZATION_REQUIREMENT => Ok(
ReturnParameters::GapSetAuthorizationRequirement(to_status(&bytes[3..])?),
),
crate::opcode::GAP_PASS_KEY_RESPONSE => Ok(ReturnParameters::GapPassKeyResponse(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_AUTHORIZATION_RESPONSE => Ok(
ReturnParameters::GapAuthorizationResponse(to_status(&bytes[3..])?),
),
crate::opcode::GAP_INIT => Ok(ReturnParameters::GapInit(to_gap_init(&bytes[3..])?)),
crate::opcode::GAP_SET_NONCONNECTABLE => Ok(ReturnParameters::GapSetNonConnectable(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_SET_UNDIRECTED_CONNECTABLE => Ok(
ReturnParameters::GapSetUndirectedConnectable(to_status(&bytes[3..])?),
),
crate::opcode::GAP_UPDATE_ADVERTISING_DATA => Ok(
ReturnParameters::GapUpdateAdvertisingData(to_status(&bytes[3..])?),
),
crate::opcode::GAP_DELETE_AD_TYPE => {
Ok(ReturnParameters::GapDeleteAdType(to_status(&bytes[3..])?))
}
crate::opcode::GAP_GET_SECURITY_LEVEL => Ok(ReturnParameters::GapGetSecurityLevel(
to_gap_security_level(&bytes[3..])?,
)),
crate::opcode::GAP_SET_EVENT_MASK => {
Ok(ReturnParameters::GapSetEventMask(to_status(&bytes[3..])?))
}
crate::opcode::GAP_CONFIGURE_WHITE_LIST => Ok(ReturnParameters::GapConfigureWhiteList(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_CLEAR_SECURITY_DATABASE => Ok(
ReturnParameters::GapClearSecurityDatabase(to_status(&bytes[3..])?),
),
crate::opcode::GAP_ALLOW_REBOND => {
Ok(ReturnParameters::GapAllowRebond(to_status(&bytes[3..])?))
}
crate::opcode::GAP_TERMINATE_PROCEDURE => Ok(ReturnParameters::GapTerminateProcedure(
to_status(&bytes[3..])?,
)),
crate::opcode::GAP_RESOLVE_PRIVATE_ADDRESS => {
#[cfg(not(feature = "ms"))]
{
Ok(ReturnParameters::GapResolvePrivateAddress(to_status(
&bytes[3..],
)?))
}
#[cfg(feature = "ms")]
{
Ok(ReturnParameters::GapResolvePrivateAddress(
to_gap_resolve_private_address(&bytes[3..])?,
))
}
}
crate::opcode::GAP_GET_BONDED_DEVICES => Ok(ReturnParameters::GapGetBondedDevices(
to_gap_bonded_devices(&bytes[3..])?,
)),
crate::opcode::GAP_SET_BROADCAST_MODE => {
#[cfg(feature = "ms")]
{
Ok(ReturnParameters::GapSetBroadcastMode(to_status(
&bytes[3..],
)?))
}
#[cfg(not(feature = "ms"))]
{
Err(hci::event::Error::UnknownOpcode(
crate::opcode::GAP_SET_BROADCAST_MODE,
))
}
}
crate::opcode::GAP_START_OBSERVATION_PROCEDURE => {
#[cfg(feature = "ms")]
{
Ok(ReturnParameters::GapStartObservationProcedure(to_status(
&bytes[3..],
)?))
}
#[cfg(not(feature = "ms"))]
{
Err(hci::event::Error::UnknownOpcode(
crate::opcode::GAP_START_OBSERVATION_PROCEDURE,
))
}
}
crate::opcode::GAP_IS_DEVICE_BONDED => {
Ok(ReturnParameters::GapIsDeviceBonded(to_status(&bytes[3..])?))
}
crate::opcode::GATT_INIT => Ok(ReturnParameters::GattInit(to_status(&bytes[3..])?)),
crate::opcode::GATT_ADD_SERVICE => Ok(ReturnParameters::GattAddService(
to_gatt_service(&bytes[3..])?,
)),
crate::opcode::GATT_INCLUDE_SERVICE => Ok(ReturnParameters::GattIncludeService(
to_gatt_service(&bytes[3..])?,
)),
crate::opcode::GATT_ADD_CHARACTERISTIC => Ok(ReturnParameters::GattAddCharacteristic(
to_gatt_characteristic(&bytes[3..])?,
)),
crate::opcode::GATT_ADD_CHARACTERISTIC_DESCRIPTOR => {
Ok(ReturnParameters::GattAddCharacteristicDescriptor(
to_gatt_characteristic_descriptor(&bytes[3..])?,
))
}
crate::opcode::GATT_UPDATE_CHARACTERISTIC_VALUE => Ok(
ReturnParameters::GattUpdateCharacteristicValue(to_status(&bytes[3..])?),
),
crate::opcode::GATT_DELETE_CHARACTERISTIC => Ok(
ReturnParameters::GattDeleteCharacteristic(to_status(&bytes[3..])?),
),
crate::opcode::GATT_DELETE_SERVICE => {
Ok(ReturnParameters::GattDeleteService(to_status(&bytes[3..])?))
}
crate::opcode::GATT_DELETE_INCLUDED_SERVICE => Ok(
ReturnParameters::GattDeleteIncludedService(to_status(&bytes[3..])?),
),
crate::opcode::GATT_SET_EVENT_MASK => {
Ok(ReturnParameters::GattSetEventMask(to_status(&bytes[3..])?))
}
crate::opcode::GATT_WRITE_WITHOUT_RESPONSE => Ok(
ReturnParameters::GattWriteWithoutResponse(to_status(&bytes[3..])?),
),
crate::opcode::GATT_SIGNED_WRITE_WITHOUT_RESPONSE => Ok(
ReturnParameters::GattSignedWriteWithoutResponse(to_status(&bytes[3..])?),
),
crate::opcode::GATT_CONFIRM_INDICATION => Ok(ReturnParameters::GattConfirmIndication(
to_status(&bytes[3..])?,
)),
crate::opcode::GATT_WRITE_RESPONSE => {
Ok(ReturnParameters::GattWriteResponse(to_status(&bytes[3..])?))
}
crate::opcode::GATT_ALLOW_READ => {
Ok(ReturnParameters::GattAllowRead(to_status(&bytes[3..])?))
}
crate::opcode::GATT_SET_SECURITY_PERMISSION => Ok(
ReturnParameters::GattSetSecurityPermission(to_status(&bytes[3..])?),
),
crate::opcode::GATT_SET_DESCRIPTOR_VALUE => Ok(
ReturnParameters::GattSetDescriptorValue(to_status(&bytes[3..])?),
),
crate::opcode::GATT_READ_HANDLE_VALUE => Ok(ReturnParameters::GattReadHandleValue(
to_gatt_handle_value(&bytes[3..])?,
)),
crate::opcode::GATT_READ_HANDLE_VALUE_OFFSET => {
#[cfg(feature = "ms")]
{
Ok(ReturnParameters::GattReadHandleValueOffset(
to_gatt_handle_value(&bytes[3..])?,
))
}
#[cfg(not(feature = "ms"))]
{
Err(hci::event::Error::UnknownOpcode(
crate::opcode::GATT_READ_HANDLE_VALUE_OFFSET,
))
}
}
crate::opcode::GATT_UPDATE_LONG_CHARACTERISTIC_VALUE => {
#[cfg(feature = "ms")]
{
Ok(ReturnParameters::GattUpdateLongCharacteristicValue(
to_status(&bytes[3..])?,
))
}
#[cfg(not(feature = "ms"))]
{
Err(hci::event::Error::UnknownOpcode(
crate::opcode::GATT_UPDATE_LONG_CHARACTERISTIC_VALUE,
))
}
}
crate::opcode::L2CAP_CONN_PARAM_UPDATE_RESP => Ok(
ReturnParameters::L2CapConnectionParameterUpdateResponse(to_status(&bytes[3..])?),
),
other => Err(hci::event::Error::UnknownOpcode(other)),
}
}
}
fn check_len_at_least(
buffer: &[u8],
len: usize,
) -> Result<(), hci::event::Error<super::BlueNRGError>> {
if buffer.len() < len {
Err(hci::event::Error::BadLength(buffer.len(), len))
} else {
Ok(())
}
}
fn to_status(
bytes: &[u8],
) -> Result<hci::Status<crate::event::Status>, hci::event::Error<super::BlueNRGError>> {
require_len_at_least!(bytes, 1);
bytes[0].try_into().map_err(hci::event::rewrap_bad_status)
}
#[derive(Clone, Debug)]
pub struct HalFirmwareRevision {
pub status: hci::Status<crate::event::Status>,
pub revision: u16,
}
fn to_hal_firmware_revision(
bytes: &[u8],
) -> Result<HalFirmwareRevision, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 3);
Ok(HalFirmwareRevision {
status: to_status(bytes)?,
revision: LittleEndian::read_u16(&bytes[1..]),
})
}
#[derive(Clone, Debug)]
pub struct HalConfigData {
pub status: hci::Status<crate::event::Status>,
pub value: HalConfigParameter,
}
#[derive(Clone, Debug, PartialEq)]
pub enum HalConfigParameter {
PublicAddress(hci::BdAddr),
Diversifier(u16),
EncryptionKey(hci::host::EncryptionKey),
Byte(u8),
}
fn to_hal_config_data(
bytes: &[u8],
) -> Result<HalConfigData, hci::event::Error<super::BlueNRGError>> {
require_len_at_least!(bytes, 2);
Ok(HalConfigData {
status: to_status(bytes)?,
value: to_hal_config_parameter(&bytes[1..])?,
})
}
fn to_hal_config_parameter(
bytes: &[u8],
) -> Result<HalConfigParameter, hci::event::Error<super::BlueNRGError>> {
match bytes.len() {
6 => {
let mut buf = [0; 6];
buf.copy_from_slice(bytes);
Ok(HalConfigParameter::PublicAddress(hci::BdAddr(buf)))
}
2 => Ok(HalConfigParameter::Diversifier(LittleEndian::read_u16(
&bytes,
))),
16 => {
let mut buf = [0; 16];
buf.copy_from_slice(bytes);
Ok(HalConfigParameter::EncryptionKey(hci::host::EncryptionKey(
buf,
)))
}
1 => Ok(HalConfigParameter::Byte(bytes[0])),
other => Err(hci::event::Error::Vendor(
super::BlueNRGError::BadConfigParameterLength(other),
)),
}
}
#[derive(Clone, Debug)]
pub struct HalTxTestPacketCount {
pub status: hci::Status<crate::event::Status>,
pub packet_count: u32,
}
fn to_hal_tx_test_packet_count(
bytes: &[u8],
) -> Result<HalTxTestPacketCount, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 5);
Ok(HalTxTestPacketCount {
status: to_status(bytes)?,
packet_count: LittleEndian::read_u32(&bytes[1..]),
})
}
#[derive(Clone, Debug)]
pub struct HalLinkStatus {
pub status: hci::Status<crate::event::Status>,
pub clients: [ClientStatus; 8],
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ClientStatus {
pub state: LinkState,
pub conn_handle: hci::ConnectionHandle,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LinkState {
Idle,
Advertising,
ConnectedAsPeripheral,
Scanning,
Reserved,
ConnectedAsPrimary,
TxTest,
RxTest,
}
impl TryFrom<u8> for LinkState {
type Error = super::BlueNRGError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(LinkState::Idle),
1 => Ok(LinkState::Advertising),
2 => Ok(LinkState::ConnectedAsPeripheral),
3 => Ok(LinkState::Scanning),
4 => Ok(LinkState::Reserved),
5 => Ok(LinkState::ConnectedAsPrimary),
6 => Ok(LinkState::TxTest),
7 => Ok(LinkState::RxTest),
_ => Err(super::BlueNRGError::UnknownLinkState(value)),
}
}
}
fn to_hal_link_status(
bytes: &[u8],
) -> Result<HalLinkStatus, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 25);
let mut status = HalLinkStatus {
status: to_status(&bytes[0..])?,
clients: [ClientStatus {
state: LinkState::Idle,
conn_handle: hci::ConnectionHandle(0),
}; 8],
};
for client in 0..8 {
status.clients[client].state = bytes[1 + client]
.try_into()
.map_err(hci::event::Error::Vendor)?;
status.clients[client].conn_handle = hci::ConnectionHandle(LittleEndian::read_u16(
&bytes[9 + 2 * client..9 + 2 * (client + 1)],
));
}
Ok(status)
}
#[derive(Clone, Debug)]
pub struct HalAnchorPeriod {
pub status: hci::Status<crate::event::Status>,
pub anchor_interval: Duration,
pub max_slot: Duration,
}
fn to_hal_anchor_period(
bytes: &[u8],
) -> Result<HalAnchorPeriod, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 9);
Ok(HalAnchorPeriod {
status: to_status(bytes)?,
anchor_interval: Duration::from_micros(
625 * u64::from(LittleEndian::read_u32(&bytes[1..5])),
),
max_slot: Duration::from_micros(625 * u64::from(LittleEndian::read_u32(&bytes[5..9]))),
})
}
#[derive(Copy, Clone, Debug)]
pub struct GapInit {
pub status: hci::Status<crate::event::Status>,
pub service_handle: crate::gatt::ServiceHandle,
pub dev_name_handle: crate::gatt::CharacteristicHandle,
pub appearance_handle: crate::gatt::CharacteristicHandle,
}
fn to_gap_init(bytes: &[u8]) -> Result<GapInit, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 7);
Ok(GapInit {
status: to_status(bytes)?,
service_handle: crate::gatt::ServiceHandle(LittleEndian::read_u16(&bytes[1..])),
dev_name_handle: crate::gatt::CharacteristicHandle(LittleEndian::read_u16(&bytes[3..])),
appearance_handle: crate::gatt::CharacteristicHandle(LittleEndian::read_u16(&bytes[5..])),
})
}
#[derive(Copy, Clone, Debug)]
pub struct GapSecurityLevel {
pub status: hci::Status<crate::event::Status>,
pub mitm_protection_required: bool,
pub bonding_required: bool,
pub out_of_band_data_present: bool,
pub pass_key_required: PassKeyRequirement,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PassKeyRequirement {
NotRequired,
FixedPin,
Generated,
}
impl TryFrom<u8> for PassKeyRequirement {
type Error = super::BlueNRGError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x00 => Ok(PassKeyRequirement::NotRequired),
0x01 => Ok(PassKeyRequirement::FixedPin),
0x02 => Ok(PassKeyRequirement::Generated),
_ => Err(super::BlueNRGError::BadPassKeyRequirement(value)),
}
}
}
fn to_boolean(value: u8) -> Result<bool, super::BlueNRGError> {
match value {
0 => Ok(false),
1 => Ok(true),
_ => Err(super::BlueNRGError::BadBooleanValue(value)),
}
}
fn to_gap_security_level(
bytes: &[u8],
) -> Result<GapSecurityLevel, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 5);
Ok(GapSecurityLevel {
status: to_status(&bytes[0..])?,
mitm_protection_required: to_boolean(bytes[1]).map_err(hci::event::Error::Vendor)?,
bonding_required: to_boolean(bytes[2]).map_err(hci::event::Error::Vendor)?,
out_of_band_data_present: to_boolean(bytes[3]).map_err(hci::event::Error::Vendor)?,
pass_key_required: bytes[4].try_into().map_err(hci::event::Error::Vendor)?,
})
}
#[cfg(feature = "ms")]
#[derive(Copy, Clone, Debug)]
pub struct GapResolvePrivateAddress {
pub status: hci::Status<crate::event::Status>,
pub bd_addr: Option<hci::BdAddr>,
}
#[cfg(feature = "ms")]
fn to_gap_resolve_private_address(
bytes: &[u8],
) -> Result<GapResolvePrivateAddress, hci::event::Error<super::BlueNRGError>> {
let status = to_status(&bytes)?;
if status == hci::Status::Success {
require_len!(bytes, 7);
let mut addr = [0; 6];
addr.copy_from_slice(&bytes[1..7]);
Ok(GapResolvePrivateAddress {
status,
bd_addr: Some(hci::BdAddr(addr)),
})
} else {
Ok(GapResolvePrivateAddress {
status,
bd_addr: None,
})
}
}
#[derive(Copy, Clone)]
pub struct GapBondedDevices {
pub status: hci::Status<crate::event::Status>,
address_count: usize,
address_buffer: [hci::BdAddrType; MAX_ADDRESSES],
}
const MAX_ADDRESSES: usize = 35;
impl GapBondedDevices {
pub fn bonded_addresses(&self) -> &[hci::BdAddrType] {
&self.address_buffer[..self.address_count]
}
}
impl Debug for GapBondedDevices {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{{")?;
for addr in self.bonded_addresses().iter() {
write!(f, "{:?}, ", addr)?;
}
write!(f, "}}")
}
}
fn to_gap_bonded_devices(
bytes: &[u8],
) -> Result<GapBondedDevices, hci::event::Error<super::BlueNRGError>> {
let status = to_status(&bytes)?;
match status {
hci::Status::Success => {
const HEADER_LEN: usize = 2;
const ADDR_LEN: usize = 7;
require_len_at_least!(bytes, HEADER_LEN);
let address_count = bytes[1] as usize;
if bytes.len() != HEADER_LEN + ADDR_LEN * address_count {
return Err(hci::event::Error::Vendor(
super::BlueNRGError::PartialBondedDeviceAddress,
));
}
let mut address_buffer = [hci::BdAddrType::Public(hci::BdAddr([0; 6])); MAX_ADDRESSES];
for (i, byte) in address_buffer.iter_mut().enumerate().take(address_count) {
let index = HEADER_LEN + i * ADDR_LEN;
let mut addr = [0; 6];
addr.copy_from_slice(&bytes[(1 + index)..(7 + index)]);
*byte = hci::to_bd_addr_type(bytes[index], hci::BdAddr(addr)).map_err(|e| {
hci::event::Error::Vendor(super::BlueNRGError::BadBdAddrType(e.0))
})?;
}
Ok(GapBondedDevices {
status,
address_count,
address_buffer,
})
}
_ => Ok(GapBondedDevices {
status,
address_count: 0,
address_buffer: [hci::BdAddrType::Public(hci::BdAddr([0; 6])); MAX_ADDRESSES],
}),
}
}
#[derive(Copy, Clone, Debug)]
pub struct GattService {
pub status: hci::Status<crate::event::Status>,
pub service_handle: crate::gatt::ServiceHandle,
}
fn to_gatt_service(bytes: &[u8]) -> Result<GattService, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 3);
Ok(GattService {
status: to_status(&bytes)?,
service_handle: crate::gatt::ServiceHandle(LittleEndian::read_u16(&bytes[1..3])),
})
}
#[derive(Copy, Clone, Debug)]
pub struct GattCharacteristic {
pub status: hci::Status<crate::event::Status>,
pub characteristic_handle: crate::gatt::CharacteristicHandle,
}
fn to_gatt_characteristic(
bytes: &[u8],
) -> Result<GattCharacteristic, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 3);
Ok(GattCharacteristic {
status: to_status(&bytes)?,
characteristic_handle: crate::gatt::CharacteristicHandle(LittleEndian::read_u16(
&bytes[1..3],
)),
})
}
#[derive(Copy, Clone, Debug)]
pub struct GattCharacteristicDescriptor {
pub status: hci::Status<crate::event::Status>,
pub descriptor_handle: crate::gatt::DescriptorHandle,
}
fn to_gatt_characteristic_descriptor(
bytes: &[u8],
) -> Result<GattCharacteristicDescriptor, hci::event::Error<super::BlueNRGError>> {
require_len!(bytes, 3);
Ok(GattCharacteristicDescriptor {
status: to_status(&bytes)?,
descriptor_handle: crate::gatt::DescriptorHandle(LittleEndian::read_u16(&bytes[1..3])),
})
}
#[derive(Copy, Clone)]
pub struct GattHandleValue {
pub status: hci::Status<crate::event::Status>,
value_buf: [u8; GattHandleValue::MAX_VALUE_BUF],
value_len: usize,
}
impl Debug for GattHandleValue {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{{")?;
write!(f, "status: {:?}; value: {{", self.status)?;
for addr in self.value().iter() {
write!(f, "{:?}, ", addr)?;
}
write!(f, "}}}}")
}
}
impl GattHandleValue {
const MAX_VALUE_BUF: usize = 249;
pub fn value(&self) -> &[u8] {
&self.value_buf[..self.value_len]
}
}
fn to_gatt_handle_value(
bytes: &[u8],
) -> Result<GattHandleValue, hci::event::Error<super::BlueNRGError>> {
require_len_at_least!(bytes, 3);
let status = to_status(bytes)?;
let value_len = LittleEndian::read_u16(&bytes[1..3]) as usize;
require_len!(bytes, 3 + value_len);
let mut handle_value = GattHandleValue {
status,
value_buf: [0; GattHandleValue::MAX_VALUE_BUF],
value_len,
};
handle_value.value_buf[..value_len].copy_from_slice(&bytes[3..]);
Ok(handle_value)
}