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