summaryrefslogtreecommitdiff
path: root/nrf-softdevice/src/ble/peripheral.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <dirbaio@dirbaio.net>2021-06-19 03:21:36 +0200
committerDario Nieuwenhuis <dirbaio@dirbaio.net>2021-06-19 03:59:51 +0200
commited4d42f88622c31003e5594afecbdb31441657f4 (patch)
tree2890a9d77aa29fb89cbe678be1dfcf4194a85f30 /nrf-softdevice/src/ble/peripheral.rs
parentf679f23dfba4e8b8c76fe5577498bb6f9434846f (diff)
downloadnrf-softdevice-ed4d42f88622c31003e5594afecbdb31441657f4.zip
Add non-connectable advertisements.
Diffstat (limited to 'nrf-softdevice/src/ble/peripheral.rs')
-rw-r--r--nrf-softdevice/src/ble/peripheral.rs222
1 files changed, 169 insertions, 53 deletions
diff --git a/nrf-softdevice/src/ble/peripheral.rs b/nrf-softdevice/src/ble/peripheral.rs
index 5b30d35..a232e14 100644
--- a/nrf-softdevice/src/ble/peripheral.rs
+++ b/nrf-softdevice/src/ble/peripheral.rs
@@ -9,6 +9,12 @@ use crate::util::get_union_field;
use crate::util::{OnDrop, Portal};
use crate::{RawError, Softdevice};
+struct RawAdvertisement<'a> {
+ kind: u8,
+ adv_data: Option<&'a [u8]>,
+ scan_data: Option<&'a [u8]>,
+}
+
/// Connectable advertisement types, which can accept connections from interested Central devices.
pub enum ConnectableAdvertisement<'a> {
ScannableUndirected {
@@ -31,56 +37,133 @@ pub enum ConnectableAdvertisement<'a> {
},
}
-impl<'a> ConnectableAdvertisement<'a> {
- fn convert(&self) -> (u8, Option<&[u8]>, Option<&[u8]>) {
- match self {
+impl<'a> From<ConnectableAdvertisement<'a>> for RawAdvertisement<'a> {
+ fn from(val: ConnectableAdvertisement<'a>) -> RawAdvertisement<'a> {
+ match val {
ConnectableAdvertisement::ScannableUndirected {
adv_data,
scan_data,
- } => (
- raw::BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED as u8,
- Some(adv_data),
- Some(scan_data),
- ),
- ConnectableAdvertisement::NonscannableDirected { scan_data } => (
- raw::BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED as u8,
- None,
- Some(scan_data),
- ),
- ConnectableAdvertisement::NonscannableDirectedHighDuty { scan_data } => (
- raw::BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE as u8,
- None,
- Some(scan_data),
- ),
+ } => RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED as u8,
+ adv_data: Some(adv_data),
+ scan_data: Some(scan_data),
+ },
+ ConnectableAdvertisement::NonscannableDirected { scan_data } => RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED as u8,
+ adv_data: None,
+ scan_data: Some(scan_data),
+ },
+ ConnectableAdvertisement::NonscannableDirectedHighDuty { scan_data } => {
+ RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE
+ as u8,
+ adv_data: None,
+ scan_data: Some(scan_data),
+ }
+ }
#[cfg(any(feature = "s132", feature = "s140"))]
- ConnectableAdvertisement::ExtendedNonscannableUndirected { adv_data } => (
- raw::BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED as u8,
- Some(adv_data),
- None,
- ),
+ ConnectableAdvertisement::ExtendedNonscannableUndirected { adv_data } => {
+ RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED as u8,
+ adv_data: Some(adv_data),
+ scan_data: None,
+ }
+ }
#[cfg(any(feature = "s132", feature = "s140"))]
- ConnectableAdvertisement::ExtendedNonscannableDirected { adv_data } => (
- raw::BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED as u8,
- Some(adv_data),
- None,
- ),
+ ConnectableAdvertisement::ExtendedNonscannableDirected { adv_data } => {
+ RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED as u8,
+ adv_data: Some(adv_data),
+ scan_data: None,
+ }
+ }
}
}
}
/// Non-Connectable advertisement types. They cannot accept connections, they can be
/// only used to broadcast information in the air.
-pub enum NonconnectableAdvertisement {
- ScannableUndirected,
- NonscannableUndirected,
+pub enum NonconnectableAdvertisement<'a> {
+ ScannableUndirected {
+ adv_data: &'a [u8],
+ scan_data: &'a [u8],
+ },
+ NonscannableUndirected {
+ adv_data: &'a [u8],
+ },
#[cfg(any(feature = "s132", feature = "s140"))]
- ExtendedScannableUndirected,
+ ExtendedScannableUndirected {
+ adv_data: &'a [u8],
+ scan_data: &'a [u8],
+ },
#[cfg(any(feature = "s132", feature = "s140"))]
- ExtendedScannableDirected,
+ ExtendedScannableDirected {
+ adv_data: &'a [u8],
+ scan_data: &'a [u8],
+ },
#[cfg(any(feature = "s132", feature = "s140"))]
- ExtendedNonscannableUndirected,
+ ExtendedNonscannableUndirected {
+ adv_data: &'a [u8],
+ },
#[cfg(any(feature = "s132", feature = "s140"))]
- ExtendedNonscannableDirected,
+ ExtendedNonscannableDirected {
+ adv_data: &'a [u8],
+ },
+}
+
+impl<'a> From<NonconnectableAdvertisement<'a>> for RawAdvertisement<'a> {
+ fn from(val: NonconnectableAdvertisement<'a>) -> RawAdvertisement<'a> {
+ match val {
+ NonconnectableAdvertisement::ScannableUndirected {
+ adv_data,
+ scan_data,
+ } => RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED as _,
+ adv_data: Some(adv_data),
+ scan_data: Some(scan_data),
+ },
+ NonconnectableAdvertisement::NonscannableUndirected { adv_data } => RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED as _,
+ adv_data: Some(adv_data),
+ scan_data: None,
+ },
+ #[cfg(any(feature = "s132", feature = "s140"))]
+ NonconnectableAdvertisement::ExtendedScannableUndirected {
+ adv_data,
+ scan_data,
+ } => RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED as _,
+ adv_data: Some(adv_data),
+ scan_data: Some(scan_data),
+ },
+ #[cfg(any(feature = "s132", feature = "s140"))]
+ NonconnectableAdvertisement::ExtendedScannableDirected {
+ adv_data,
+ scan_data,
+ } => RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED as _,
+ adv_data: Some(adv_data),
+ scan_data: Some(scan_data),
+ },
+ #[cfg(any(feature = "s132", feature = "s140"))]
+ NonconnectableAdvertisement::ExtendedNonscannableUndirected { adv_data } => {
+ RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED
+ as _,
+ adv_data: Some(adv_data),
+ scan_data: None,
+ }
+ }
+ #[cfg(any(feature = "s132", feature = "s140"))]
+ NonconnectableAdvertisement::ExtendedNonscannableDirected { adv_data } => {
+ RawAdvertisement {
+ kind: raw::BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED as _,
+ adv_data: Some(adv_data),
+ scan_data: None,
+ }
+ }
+ }
+ }
}
/// Error for [`advertise_start`]
@@ -101,17 +184,10 @@ impl From<RawError> for AdvertiseError {
static mut ADV_HANDLE: u8 = raw::BLE_GAP_ADV_SET_HANDLE_NOT_SET as u8;
pub(crate) static ADV_PORTAL: Portal<*const raw::ble_evt_t> = Portal::new();
-// Begins an ATT MTU exchange procedure, followed by a data length update request as necessary.
-pub async fn advertise(
- _sd: &Softdevice,
- adv: ConnectableAdvertisement<'_>,
- config: &Config,
-) -> Result<Connection, AdvertiseError> {
- let (adv_type, adv_data, scan_data) = adv.convert();
-
+fn start_adv(adv: RawAdvertisement<'_>, config: &Config) -> Result<(), AdvertiseError> {
// TODO make these configurable, only the right params based on type?
let mut adv_params: raw::ble_gap_adv_params_t = unsafe { mem::zeroed() };
- adv_params.properties.type_ = adv_type;
+ adv_params.properties.type_ = adv.kind;
adv_params.primary_phy = config.primary_phy as u8;
adv_params.secondary_phy = config.secondary_phy as u8;
adv_params.duration = config.timeout.map(|t| t.max(1)).unwrap_or(0);
@@ -134,17 +210,10 @@ pub async fn advertise(
};
let datas = raw::ble_gap_adv_data_t {
- adv_data: map_data(adv_data),
- scan_rsp_data: map_data(scan_data),
+ adv_data: map_data(adv.adv_data),
+ scan_rsp_data: map_data(adv.scan_data),
};
- let d = OnDrop::new(|| {
- let ret = unsafe { raw::sd_ble_gap_adv_stop(ADV_HANDLE) };
- if let Err(_e) = RawError::convert(ret) {
- warn!("sd_ble_gap_adv_stop: {:?}", _e);
- }
- });
-
let ret = unsafe {
raw::sd_ble_gap_adv_set_configure(&mut ADV_HANDLE as _, &datas as _, &adv_params as _)
};
@@ -171,8 +240,55 @@ pub async fn advertise(
err
})?;
+ Ok(())
+}
+
+/// Perform connectable advertising, returning the connection that's established as a result.
+pub async fn advertise(
+ _sd: &Softdevice,
+ adv: NonconnectableAdvertisement<'_>,
+ config: &Config,
+) -> Result<(), AdvertiseError> {
+ let d = OnDrop::new(|| {
+ let ret = unsafe { raw::sd_ble_gap_adv_stop(ADV_HANDLE) };
+ if let Err(_e) = RawError::convert(ret) {
+ warn!("sd_ble_gap_adv_stop: {:?}", _e);
+ }
+ });
+
+ start_adv(adv.into(), config)?;
+
// The advertising data needs to be kept alive for the entire duration of the advertising procedure.
+ let res = ADV_PORTAL
+ .wait_once(|ble_evt| unsafe {
+ match (*ble_evt).header.evt_id as u32 {
+ raw::BLE_GAP_EVTS_BLE_GAP_EVT_TIMEOUT => Err(AdvertiseError::Timeout),
+ raw::BLE_GAP_EVTS_BLE_GAP_EVT_ADV_SET_TERMINATED => Err(AdvertiseError::Timeout),
+ _ => unreachable!(),
+ }
+ })
+ .await;
+
+ d.defuse();
+ res
+}
+
+/// Perform connectable advertising, returning the connection that's established as a result.
+pub async fn advertise_connectable(
+ _sd: &Softdevice,
+ adv: ConnectableAdvertisement<'_>,
+ config: &Config,
+) -> Result<Connection, AdvertiseError> {
+ let d = OnDrop::new(|| {
+ let ret = unsafe { raw::sd_ble_gap_adv_stop(ADV_HANDLE) };
+ if let Err(_e) = RawError::convert(ret) {
+ warn!("sd_ble_gap_adv_stop: {:?}", _e);
+ }
+ });
+
+ start_adv(adv.into(), config)?;
+ // The advertising data needs to be kept alive for the entire duration of the advertising procedure.
let res = ADV_PORTAL
.wait_once(|ble_evt| unsafe {
match (*ble_evt).header.evt_id as u32 {