Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1.17.1 #7

Merged
merged 31 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
be563b8
feat(vendor event): Gap Pairing Complete event now returns a reason
OueslatiGhaith Jan 2, 2024
638306c
doc(vendor GAP commad): updated docs for GAP Clear Security command
OueslatiGhaith Jan 2, 2024
b732598
feat(vendor GAP command): add ADV Set Config command
OueslatiGhaith Jan 3, 2024
5ee3663
feat(vendor GAP command): add ADV Set Enable command
OueslatiGhaith Jan 3, 2024
3f6116c
feat(vendor GAP command): add ADV Set AAdvertising Data command
OueslatiGhaith Jan 4, 2024
4924dbc
feat(vendor GAP command): add ADV Set Scan Response Data command
OueslatiGhaith Jan 4, 2024
be4168b
feat(vendor GAP command): add ADV Remove Set command
OueslatiGhaith Jan 4, 2024
d6a7570
feat(vendor GAP command): add ADV Clear Sets command
OueslatiGhaith Jan 4, 2024
711c539
feat(vendor GAP command): add ADV Set Random Address command
OueslatiGhaith Jan 4, 2024
90c8234
feat(vendor GATT command): add Deny Read command
OueslatiGhaith Jan 4, 2024
8b49611
feat(vendor GATT command): add Set Access Permission command
OueslatiGhaith Jan 4, 2024
b8222b2
feat(vendor GATT command): add Store Database command
OueslatiGhaith Jan 4, 2024
ee54737
feat(vendor GATT command): add Send Multiple Notification command
OueslatiGhaith Jan 4, 2024
7bac2f2
feat(vendor GATT command): add Read Multiple Variable Characteristic …
OueslatiGhaith Jan 4, 2024
59c054d
feat(vendor HAL command): add Set Radio Activity Mask command
OueslatiGhaith Jan 4, 2024
8fb7d28
feat(vendor HAL command): add Set Event Mask command
OueslatiGhaith Jan 4, 2024
9fd84a1
feat(vendor HAL command): add Get PM Debug Info command
OueslatiGhaith Jan 8, 2024
a45a4bd
feat(vendor HAL command): add Set Peripheral Latency command
OueslatiGhaith Jan 8, 2024
555baf1
feat(vendor HAL event): add PM Debug Info event return parameters
OueslatiGhaith Jan 8, 2024
773d99c
feat(vendor HAL command): add Read RSSI command
OueslatiGhaith Jan 8, 2024
b212b01
feat(vendor HAL command): add Read Radio Register command
OueslatiGhaith Jan 8, 2024
ad7b9ff
feat(vendor HAL command): add Read Raw RSSI command
OueslatiGhaith Jan 8, 2024
b231d49
feat(vendor HAL command): add RX Start command
OueslatiGhaith Jan 8, 2024
6c6ece2
feat(vendor HAL command): add RX Stop command
OueslatiGhaith Jan 8, 2024
16d3495
feat(vendor HAL command): add Stack Reset command
OueslatiGhaith Jan 8, 2024
178820b
feat(LE event): add LE Read Local P-256 Public Key Complete event
OueslatiGhaith Jan 9, 2024
c83dc5a
feat(LE event): add LE Generated DH Key Complete event
OueslatiGhaith Jan 9, 2024
19e9bd8
feat(LE event): add LE Enhanced Connection Complete event
OueslatiGhaith Jan 9, 2024
a638285
feat(Vendor HAL Event): add HAL End Of Radio Activity event
OueslatiGhaith Jan 15, 2024
807af00
feat(Vendor HAL Event): add HAL Scan Request Report event
OueslatiGhaith Jan 15, 2024
5e75f64
feat(Vendor HAL Event): add HAL Firmware Error event
OueslatiGhaith Jan 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,30 @@ pub enum Event {
/// Vol 2, Part E, Section 7.7.65.7
LeDataLengthChangeEvent(LeDataLengthChangeEvent),

/// This event is generated when local P-256 key generation is complete.
///
/// Vol 4, Part E, 7.7.65.8
LeReadLocalP256PublicKeyComplete([u8; 64]),

/// This event indicates that LE Diffie Hellman key generation has been completed by the Controller.
///
/// Vol 4, Part E, Section 7.7.65.9
LeGenerateDHKeyComplete([u8; 32]),

/// Vol 4, Part E, Section 7.7.65.10
LeEnhancedConnectionComplete(LeEnhancedConnectionComplete),

/// Vol 2, Part E, Section 7.7.65.12
LePhyUpdateComplete(LePhyUpdateComplete),

// TODO: le_enhanced_connection_complete
// TODO: le_directed_advertising_report
// TODO: le_phy_update_complete
// TODO: le_extended_advertising_report
// TODO: le_scan_timeout
// TODO: le_advertising_set_terminated
// TODO: le_scan_reauest_received
// TODO: le_channel_selection_algorithm
/// Vendor-specific events (opcode 0xFF)
Vendor(VendorEvent),
}
Expand Down Expand Up @@ -296,9 +317,19 @@ fn to_le_meta_event(payload: &[u8]) -> Result<Event, Error> {
0x07 => Ok(Event::LeDataLengthChangeEvent(
to_le_data_length_change_event(payload)?,
)),
0x08 => Ok(Event::LeReadLocalP256PublicKeyComplete(
to_le_read_local_p256_public_key(payload)?,
)),
0x09 => Ok(Event::LeGenerateDHKeyComplete(
to_le_generate_dhkey_complete(payload)?,
)),
0x0A => Ok(Event::LeEnhancedConnectionComplete(
to_le_enhanced_connection_complete(payload)?,
)),
0x0C => Ok(Event::LePhyUpdateComplete(to_le_phy_update_complete(
payload,
)?)),

_ => Err(Error::UnknownEvent(payload[0])),
}
}
Expand Down Expand Up @@ -1276,3 +1307,111 @@ fn to_le_phy_update_complete(payload: &[u8]) -> Result<LePhyUpdateComplete, Erro
rx_phy: Phy::try_from(payload[5])?,
})
}

fn to_le_read_local_p256_public_key(payload: &[u8]) -> Result<[u8; 64], Error> {
require_len!(payload, 65);

let mut key = [0; 64];
key.copy_from_slice(&payload[1..]);
Ok(key)
}

fn to_le_generate_dhkey_complete(payload: &[u8]) -> Result<[u8; 32], Error> {
require_len!(payload, 33);

let mut key = [0; 32];
key.copy_from_slice(&payload[1..]);
Ok(key)
}

/// This event indicates to both of the Hosts forming the connection that a new connection has been created.
/// Upon the creation of the connection, a [Connection Handle](ConnectionHandle) shall be assigned to the
/// Controller, and passed to the Host in this event.
///
/// If the connection establishment fails, this event shall be provided to the Host that had issued the
/// [LE Create Connection](crate::host::HostHci::le_create_connection) command.
///
/// If this event is unmasked and [LE Connection Complete](Event::LeConnectionComplete) event is unmasked,
/// only the [LE Enhanced Connection Complete](Event::LeEnhancedConnectionComplete) event is sent when a
/// new connection has been completed.
///
/// This event indicates to the Host that issued a [LE Create Connection](crate::host::HostHci::le_create_connection)
/// command and received a [Command Status](CommandStatus) event if the connection establishment failed or
/// was successful.
///
/// The [Central Clock Accuracy](LeEnhancedConnectionComplete::central_clock_accuracy) parameter is only valid
/// for a Peripheral. On a Central, this parameter is set to 0x00
///
/// Defined in Vol 4, Part E, Section 7.7.65.10
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct LeEnhancedConnectionComplete {
/// Did the LE Connection fail, and if so, how?
pub status: Status,

/// Connection Handle for which the event applies
pub conn_handle: ConnectionHandle,

/// Role of the device receiving this event in the connection.
pub role: ConnectionRole,

/// Address of the peer device.
pub peer_bd_addr: crate::BdAddrType,

/// Resolvable Private Address being used by the local device for this connection.
///
/// This is only valid when the [Own Address Type](crate::host::OwnAddressType) is set to
/// [Private Fallback Public](crate::host::OwnAddressType::PrivateFallbackPublic) or
/// [Private Fallback Random](crate::host::OwnAddressType::PrivateFallbackRandom).
/// For other [Own Address Type](crate::host::OwnAddressType) values, the Controller shall
/// return all zeros
pub local_resolvable_private_address: crate::BdAddr,

/// Resolvable Private Address being used by the peer device for this connection.
///
/// This is only valid when the [Peer Address Type](crate::host::PeerAddrType) is set to
/// [Public Identity Address](crate::host::PeerAddrType::PublicIdentityAddress) or
/// [Random Identity Address](crate::host::PeerAddrType::RandomIdentityAddress).
/// For other [Peer Address Type](crate::host::PeerAddrType) values, the Controller shall
/// return all zeros
pub peer_resolvable_private_address: crate::BdAddr,

/// Connection interval used on this connection.
pub conn_interval: FixedConnectionInterval,

/// This is only valid for a peripheral. On a central device, this parameter shall be set to
/// Ppm500.
pub central_clock_accuracy: CentralClockAccuracy,
}

fn to_le_enhanced_connection_complete(
payload: &[u8],
) -> Result<LeEnhancedConnectionComplete, Error> {
require_len!(payload, 31);

let mut bd_addr = crate::BdAddr([0; 6]);
bd_addr.0.copy_from_slice(&payload[6..12]);

let mut local_resolvable_private_address = crate::BdAddr([0; 6]);
local_resolvable_private_address
.0
.copy_from_slice(&payload[12..18]);

let mut peer_resolvable_private_address = crate::BdAddr([0; 6]);
peer_resolvable_private_address
.0
.copy_from_slice(&payload[18..24]);

Ok(LeEnhancedConnectionComplete {
status: payload[1].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[2..])),
role: payload[4].try_into()?,
peer_bd_addr: crate::to_bd_addr_type(payload[5], bd_addr)
.map_err(rewrap_bd_addr_type_err)?,
local_resolvable_private_address,
peer_resolvable_private_address,
conn_interval: FixedConnectionInterval::from_bytes(&payload[24..30])
.map_err(Error::BadConnectionInterval)?,
central_clock_accuracy: payload[30].try_into()?,
})
}
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,14 @@ impl core::convert::From<Status> for u8 {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ConnectionHandle(pub u16);

/// Newtype for an advertising handle.
///
/// Values:
/// - 0x00 .. 0xEF
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AdvertisingHandle(pub u8);

/// Newtype for BDADDR.
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down
201 changes: 201 additions & 0 deletions src/types/extended_advertisement.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
use core::time::Duration;

use byteorder::{ByteOrder, LittleEndian};

use crate::AdvertisingHandle;

#[cfg(not(feature = "defmt"))]
bitflags::bitflags! {
/// Extended advertising modes
pub struct AdvertisingMode: u8 {
/// Use specific random address
const SPECIFIC = 0x01;
}
}

#[cfg(feature = "defmt")]
defmt::bitflags! {
/// Extended advertising modes
pub struct AdvertisingMode: u8 {
/// Use specific random address
const SPECIFIC = 0x01;
}
}

#[cfg(not(feature = "defmt"))]
bitflags::bitflags! {
/// Advertising event types
pub struct AdvertisingEvent: u16 {
/// Connectable advertising
const CONNECTABLE = 0x0001;
/// Scannable advertising
const SCANNABLE = 0x0002;
/// Directed advertising
const DIRECTED = 0x0004;
/// High duty cycle directed connectable advertising
const HIGH_DUTY_DIRECTED = 0x0008;
/// Use legacy advertising PDUs
const LEGACY = 0x0010;
/// Anonymous advertising
const ANONYMOUS = 0x0020;
/// Include Tx power in at least one advertising PDU
const INCLUDE_TX_POWER = 0x0040;
}
}

#[cfg(feature = "defmt")]
defmt::bitflags! {
/// Advertising event types
pub struct AdvertisingEvent: u16 {
/// Connectable advertising
const CONNECTABLE = 0x0001;
/// Scannable advertising
const SCANNABLE = 0x0002;
/// Directed advertising
const DIRECTED = 0x0004;
/// High duty cycle directed connectable advertising
const HIGH_DUTY_DIRECTED = 0x0008;
/// Use legacy advertising PDUs
const LEGACY = 0x0010;
/// Anonymous advertising
const ANONYMOUS = 0x0020;
/// Include Tx power in at least one advertising PDU
const INCLUDE_TX_POWER = 0x0040;
}
}

/// Define an extended advertising interval range.
///
/// The advertising interval min shall be less than or equal to the advertising interval
/// max. The advertising interval min and advertising interval max should not be the same
/// values to enable the Controller to determine the best advertising interval given other
/// adctivities, through this implementation allows them to be equal.
pub struct ExtendedAdvertisingInterval {
/// The first field is the min, the second is the max
interval: (Duration, Duration),
}

impl ExtendedAdvertisingInterval {
/// Creates an advertising interval with the provided minimum and maximum values.
///
/// # Errors
///
/// - [TooShort](ExtendedAdvertisingIntervalError::TooShort) if the minimum value is too small. For
/// Bluetooth specifications v4.x, if the advertising type is
/// [ScannableUndirected](AdvertisingType::ScannableUndirected), then the minimum value is 100
/// ms. In all other cases, the minimum value is 20 ms.
/// - [TooLong](ExtendedAdvertisingIntervalError::TooLong) if the maximum value is too large. The
/// maximum value is 10.24 seconds.
/// - [Inverted](ExtendedAdvertisingIntervalError::Inverted) if the minimum is greater than the
/// maximum.
pub fn with_range(
min: Duration,
max: Duration,
) -> Result<Self, ExtendedAdvertisingIntervalError> {
const MIN: Duration = Duration::from_millis(20);
const MAX: Duration = Duration::from_micros(10485759375);

if min < MIN {
return Err(ExtendedAdvertisingIntervalError::TooShort(min));
}
if max > MAX {
return Err(ExtendedAdvertisingIntervalError::TooLong(max));
}
if min > max {
return Err(ExtendedAdvertisingIntervalError::Inverted(min, max));
}

Ok(Self {
interval: (min, max),
})
}

fn duration_as_u32(d: Duration) -> u32 {
// T = 0.625 ms * N
// so N = T / 0.625 ms
// = T / 625 us
//
// Note: 1600 = 1_000_000 / 625
1600 * d.as_secs() as u32 + (d.subsec_micros() / 625)
}

/// Serialize the interval into the given buffer.
///
/// Serializes the minimum range of the interval (4 bytes), the maximum range of the
/// interval (4 bytees)
///
/// # Panics
///
/// - If the provided buffer is not at least 8 bytes long.
pub fn copy_into_slice(&self, bytes: &mut [u8]) {
LittleEndian::write_u32(&mut bytes[0..], Self::duration_as_u32(self.interval.0));
LittleEndian::write_u32(&mut bytes[4..], Self::duration_as_u32(self.interval.1));
}
}

/// Potential errors that can occur when specifying an [`ExtendedAdvertisingInterval`].
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ExtendedAdvertisingIntervalError {
/// The minimum value was too short. Includes the invalid value.
TooShort(Duration),
/// The maximum value was too long. Includes the invalid value.
TooLong(Duration),
/// The minimum value was greater than the maximum value. Includes the provided minimum and
/// value, respectively.
Inverted(Duration, Duration),
}

/// Advertising PHY
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AdvertisingPhy {
/// Advertisement PHY is LE 1M
Le1M = 0x01,
/// Advertisement PHY is LE 2M
Le2M = 0x02,
}

/// Advertising set
pub struct AdvSet {
/// Used to identify an advertising set
pub handle: AdvertisingHandle,
/// Duration of advertising set.
///
/// Values:
/// - 0x0000 (0 ms) : No advertising duration.
/// - 0x0001 (10 ms) ... 0xFFFF (655350 ms) : Advertising duration
pub duration: u16,
/// Maximum number of advertising events.
///
/// Values:
/// - 0x00: No maximum number of advertising events
/// - 0x01 .. 0xFF: Maximum number of extended advertising events the
/// Controller shall attempt to send prior to terminating the extended
/// advertising
pub max_extended_adv_events: u8,
}

impl AdvSet {
pub(crate) fn copy_into_slice(&self, bytes: &mut [u8]) {
bytes[0] = self.handle.0;
LittleEndian::write_u16(&mut bytes[1..], self.duration);
bytes[3] = self.max_extended_adv_events;
}
}

/// Advertising Operation
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AdvertisingOperation {
/// Intermediate fragment of fragmented extended advertising data
IntermediateFragment = 0x00,
/// First fragment of fragmented extended advertising data
FirstFragment = 0x01,
/// Last fragment of fragmented extended advertising data
LastFragment = 0x02,
/// Complete extended advertising data
CompleteData = 0x03,
/// Unchanged data (just update the advertising DID)
UnchangedData = 0x04,
}
1 change: 1 addition & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod advertising_interval;
mod common;
mod connection_interval;
mod expected_connection_length;
pub mod extended_advertisement;
mod scan_window;

pub use self::advertisement::*;
Expand Down
Loading