Bluetooth: host: PA sync receive enable/disable
Adds support for enabling/disabling PA sync receive, which allows applications to control when to receive data while a sync is established. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
6c67d3cb4b
commit
44f00358a6
|
@ -977,6 +977,9 @@ struct bt_le_per_adv_sync_synced_info {
|
|||
|
||||
/** Advertiser PHY */
|
||||
uint8_t phy;
|
||||
|
||||
/** True if receiving periodic advertisements, false otherwise. */
|
||||
bool recv_enabled;
|
||||
};
|
||||
|
||||
struct bt_le_per_adv_sync_term_info {
|
||||
|
@ -1004,6 +1007,12 @@ struct bt_le_per_adv_sync_recv_info {
|
|||
uint8_t cte_type;
|
||||
};
|
||||
|
||||
|
||||
struct bt_le_per_adv_sync_state_info {
|
||||
/** True if receiving periodic advertisements, false otherwise. */
|
||||
bool recv_enabled;
|
||||
};
|
||||
|
||||
struct bt_le_per_adv_sync_cb {
|
||||
/**
|
||||
* @brief The periodic advertising has been successfully synced.
|
||||
|
@ -1044,6 +1053,20 @@ struct bt_le_per_adv_sync_cb {
|
|||
const struct bt_le_per_adv_sync_recv_info *info,
|
||||
struct net_buf_simple *buf);
|
||||
|
||||
/**
|
||||
* @brief The periodic advertising sync state has changed.
|
||||
*
|
||||
* This callback notifies the application about changes to the sync
|
||||
* state. Initialize sync and termination is handled by their individual
|
||||
* callbacks, and won't be notified here.
|
||||
*
|
||||
* @param sync The periodic advertising sync object.
|
||||
* @param info Information about the state change.
|
||||
*/
|
||||
void (*state_changed)(struct bt_le_per_adv_sync *sync,
|
||||
const struct bt_le_per_adv_sync_state_info *info);
|
||||
|
||||
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
|
@ -1170,6 +1193,28 @@ int bt_le_per_adv_sync_delete(struct bt_le_per_adv_sync *per_adv_sync);
|
|||
*/
|
||||
void bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb);
|
||||
|
||||
/**
|
||||
* @brief Enables receiving periodic advertising reports for a sync.
|
||||
*
|
||||
* If the sync is already receiving the reports, -EALREADY is returned.
|
||||
*
|
||||
* @param per_adv_sync The periodic advertising sync object.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_le_per_adv_sync_recv_enable(struct bt_le_per_adv_sync *per_adv_sync);
|
||||
|
||||
/**
|
||||
* @brief Disables receiving periodic advertising reports for a sync.
|
||||
*
|
||||
* If the sync report receiving is already disabled, -EALREADY is returned.
|
||||
*
|
||||
* @param per_adv_sync The periodic advertising sync object.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_le_per_adv_sync_recv_disable(struct bt_le_per_adv_sync *per_adv_sync);
|
||||
|
||||
enum {
|
||||
/** Convenience value when no options are specified. */
|
||||
BT_LE_SCAN_OPT_NONE = 0,
|
||||
|
|
|
@ -4616,6 +4616,12 @@ static void le_per_adv_report(struct net_buf *buf)
|
|||
return;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED)) {
|
||||
BT_ERR("Received PA adv report when receive disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
info.tx_power = evt->tx_power;
|
||||
info.rssi = evt->rssi;
|
||||
info.cte_type = evt->cte_type;
|
||||
|
@ -4723,6 +4729,10 @@ static void le_per_adv_sync_established(struct net_buf *buf)
|
|||
sync_info.addr = &pending_per_adv_sync->addr;
|
||||
sync_info.sid = pending_per_adv_sync->sid;
|
||||
|
||||
sync_info.recv_enabled =
|
||||
!atomic_test_bit(pending_per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED);
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
|
||||
if (listener->synced) {
|
||||
listener->synced(pending_per_adv_sync, &sync_info);
|
||||
|
@ -7401,6 +7411,15 @@ int bt_le_per_adv_sync_create(const struct bt_le_per_adv_sync_param *param,
|
|||
cp->cte_type |= BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE;
|
||||
}
|
||||
|
||||
if (param->options &
|
||||
BT_LE_PER_ADV_SYNC_OPT_REPORTING_INITIALLY_DISABLED) {
|
||||
cp->options |=
|
||||
BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED;
|
||||
|
||||
atomic_set_bit(per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED);
|
||||
}
|
||||
|
||||
cp->sid = param->sid;
|
||||
cp->skip = sys_cpu_to_le16(param->skip);
|
||||
cp->sync_timeout = sys_cpu_to_le16(param->timeout);
|
||||
|
@ -7497,6 +7516,81 @@ void bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb)
|
|||
{
|
||||
sys_slist_append(&pa_sync_cbs, &cb->node);
|
||||
}
|
||||
|
||||
static int bt_le_set_per_adv_recv_enable(
|
||||
struct bt_le_per_adv_sync *per_adv_sync, bool enable)
|
||||
{
|
||||
struct bt_hci_cp_le_set_per_adv_recv_enable *cp;
|
||||
struct bt_le_per_adv_sync_cb *listener;
|
||||
struct bt_le_per_adv_sync_state_info info;
|
||||
struct net_buf *buf;
|
||||
struct cmd_state_set state;
|
||||
int err;
|
||||
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!BT_FEAT_LE_EXT_PER_ADV(bt_dev.le.features)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!atomic_test_bit(per_adv_sync->flags, BT_PER_ADV_SYNC_SYNCED)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((enable && !atomic_test_bit(per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED)) ||
|
||||
(!enable && atomic_test_bit(per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED))) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE,
|
||||
sizeof(*cp));
|
||||
if (!buf) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
(void)memset(cp, 0, sizeof(*cp));
|
||||
|
||||
cp->handle = sys_cpu_to_le16(per_adv_sync->handle);
|
||||
cp->enable = enable ? 1 : 0;
|
||||
|
||||
cmd_state_set_init(&state, per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED,
|
||||
enable);
|
||||
cmd(buf)->state = &state;
|
||||
|
||||
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE,
|
||||
buf, NULL);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
info.recv_enabled = !atomic_test_bit(per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED);
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
|
||||
if (listener->state_changed) {
|
||||
listener->state_changed(per_adv_sync, &info);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_per_adv_sync_recv_enable(struct bt_le_per_adv_sync *per_adv_sync)
|
||||
{
|
||||
return bt_le_set_per_adv_recv_enable(per_adv_sync, true);
|
||||
}
|
||||
|
||||
int bt_le_per_adv_sync_recv_disable(struct bt_le_per_adv_sync *per_adv_sync)
|
||||
{
|
||||
return bt_le_set_per_adv_recv_enable(per_adv_sync, false);
|
||||
}
|
||||
#endif /* defined(CONFIG_BT_PER_ADV_SYNC) */
|
||||
|
||||
static bool valid_adv_ext_param(const struct bt_le_adv_param *param)
|
||||
|
|
|
@ -143,6 +143,9 @@ enum {
|
|||
/** Periodic advertising is attempting sync sync */
|
||||
BT_PER_ADV_SYNC_SYNCING,
|
||||
|
||||
/** Periodic advertising is attempting sync sync */
|
||||
BT_PER_ADV_SYNC_RECV_DISABLED,
|
||||
|
||||
BT_PER_ADV_SYNC_NUM_FLAGS,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue