Bluetooth: Host: Rework enabling of scanner
To make the scanner module more understandable and more streamlined, I reworked the update mechanism of the scanner. The scanner tracks now the parameters that were used to enable it and the reason why it is running. This facilitates state logic and allows other modules to "start the scanner", altough it is already running. This is mostly a refactoring and not a functional change. Added a test to verify the behavior. Signed-off-by: Jan Müller <jan.mueller@nordicsemi.no> add to task
This commit is contained in:
parent
ed97f4f7d5
commit
c910520f4d
15 changed files with 846 additions and 271 deletions
|
@ -2294,6 +2294,7 @@ BUILD_ASSERT(BT_GAP_SCAN_FAST_WINDOW == BT_GAP_SCAN_FAST_INTERVAL_MIN,
|
|||
*
|
||||
* @return Zero on success or error code otherwise, positive in case of
|
||||
* protocol error or negative (POSIX) in case of stack internal error.
|
||||
* @retval -EBUSY if the scanner is already being started in a different thread.
|
||||
*/
|
||||
int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "hci_core.h"
|
||||
#include "id.h"
|
||||
#include "adv.h"
|
||||
#include "scan.h"
|
||||
#include "conn_internal.h"
|
||||
#include "l2cap_internal.h"
|
||||
#include "keys.h"
|
||||
|
@ -1265,10 +1266,18 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
|||
* the application through bt_conn_disconnect or by
|
||||
* timeout set by bt_conn_le_create_param.timeout.
|
||||
*/
|
||||
if (conn->err) {
|
||||
notify_connected(conn);
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
||||
int err = bt_le_scan_user_remove(BT_LE_SCAN_USER_CONN);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Error while removing conn user from scanner (%d)",
|
||||
err);
|
||||
}
|
||||
|
||||
if (conn->err) {
|
||||
notify_connected(conn);
|
||||
}
|
||||
}
|
||||
bt_conn_unref(conn);
|
||||
break;
|
||||
case BT_CONN_ADV_DIR_CONNECTABLE:
|
||||
|
@ -1693,7 +1702,7 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
|
|||
conn->err = reason;
|
||||
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
||||
bt_le_scan_update(false);
|
||||
return bt_le_scan_user_add(BT_LE_SCAN_USER_CONN);
|
||||
}
|
||||
return 0;
|
||||
case BT_CONN_INITIATING:
|
||||
|
@ -3360,27 +3369,32 @@ static int conn_le_create_common_checks(const bt_addr_le_t *peer,
|
|||
{
|
||||
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
||||
LOG_DBG("Conn check failed: BT dev not ready.");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!bt_le_conn_params_valid(conn_param)) {
|
||||
LOG_DBG("Conn check failed: invalid parameters.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states) && bt_le_explicit_scanner_running()) {
|
||||
LOG_DBG("Conn check failed: scanner was explicitly requested.");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
|
||||
LOG_DBG("Conn check failed: device is already initiating.");
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (!bt_id_scan_random_addr_check()) {
|
||||
LOG_DBG("Conn check failed: invalid random address.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bt_conn_exists_le(BT_ID_DEFAULT, peer)) {
|
||||
LOG_DBG("Conn check failed: ACL connection already exists.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -3433,8 +3447,9 @@ int bt_conn_le_create(const bt_addr_le_t *peer, const struct bt_conn_le_create_p
|
|||
/* Use host-based identity resolving. */
|
||||
bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING);
|
||||
|
||||
err = bt_le_scan_update(true);
|
||||
err = bt_le_scan_user_add(BT_LE_SCAN_USER_CONN);
|
||||
if (err) {
|
||||
bt_le_scan_user_remove(BT_LE_SCAN_USER_CONN);
|
||||
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
||||
bt_conn_unref(conn);
|
||||
|
||||
|
@ -3454,7 +3469,12 @@ int bt_conn_le_create(const bt_addr_le_t *peer, const struct bt_conn_le_create_p
|
|||
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
||||
bt_conn_unref(conn);
|
||||
|
||||
bt_le_scan_update(false);
|
||||
/* Best-effort attempt to inform the scanner that the initiator stopped. */
|
||||
int scan_check_err = bt_le_scan_user_add(BT_LE_SCAN_USER_NONE);
|
||||
|
||||
if (scan_check_err) {
|
||||
LOG_WRN("Error while updating the scanner (%d)", scan_check_err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -3556,17 +3576,18 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr,
|
|||
}
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
if (conn->state == BT_CONN_DISCONNECTED &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
|
||||
if (param) {
|
||||
bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING);
|
||||
err = bt_le_scan_user_add(BT_LE_SCAN_USER_CONN);
|
||||
}
|
||||
bt_le_scan_update(false);
|
||||
}
|
||||
|
||||
bt_conn_unref(conn);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
#endif /* !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
||||
#endif /* CONFIG_BT_CENTRAL */
|
||||
|
|
|
@ -1010,7 +1010,12 @@ static void hci_disconn_complete(struct net_buf *buf)
|
|||
#if defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_FILTER_ACCEPT_LIST)
|
||||
if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) {
|
||||
bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING);
|
||||
bt_le_scan_update(false);
|
||||
/* Just a best-effort check if the scanner should be started. */
|
||||
int err = bt_le_scan_user_remove(BT_LE_SCAN_USER_NONE);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Error while updating the scanner (%d)", err);
|
||||
}
|
||||
}
|
||||
#endif /* defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
||||
|
||||
|
@ -1561,9 +1566,14 @@ void bt_hci_le_enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
|
|||
|
||||
bt_conn_unref(conn);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
||||
conn->role == BT_HCI_ROLE_CENTRAL) {
|
||||
bt_le_scan_update(false);
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL) && conn->role == BT_HCI_ROLE_CENTRAL) {
|
||||
int err;
|
||||
|
||||
/* Just a best-effort check if the scanner should be started. */
|
||||
err = bt_le_scan_user_remove(BT_LE_SCAN_USER_NONE);
|
||||
if (err) {
|
||||
LOG_WRN("Error while updating the scanner (%d)", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1661,7 +1671,11 @@ static void enh_conn_complete_error_handle(uint8_t status)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL) && status == BT_HCI_ERR_UNKNOWN_CONN_ID) {
|
||||
le_conn_complete_cancel(status);
|
||||
bt_le_scan_update(false);
|
||||
int err = bt_le_scan_user_remove(BT_LE_SCAN_USER_NONE);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Error while updating the scanner (%d)", err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4200,7 +4214,7 @@ void bt_finalize_init(void)
|
|||
atomic_set_bit(bt_dev.flags, BT_DEV_READY);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_OBSERVER)) {
|
||||
bt_le_scan_update(false);
|
||||
bt_scan_reset();
|
||||
}
|
||||
|
||||
bt_dev_show_info();
|
||||
|
|
|
@ -38,16 +38,11 @@ enum {
|
|||
BT_DEV_HAS_PUB_KEY,
|
||||
BT_DEV_PUB_KEY_BUSY,
|
||||
|
||||
/** The application explicitly instructed the stack to scan for advertisers
|
||||
* using the API @ref bt_le_scan_start().
|
||||
*/
|
||||
BT_DEV_EXPLICIT_SCAN,
|
||||
|
||||
/** The application either explicitly or implicitly instructed the stack to scan
|
||||
* for advertisers.
|
||||
*
|
||||
* Examples of such cases
|
||||
* - Explicit scanning, @ref BT_DEV_EXPLICIT_SCAN.
|
||||
* - Explicit scanning, @ref BT_LE_SCAN_USER_EXPLICIT_SCAN.
|
||||
* - The application instructed the stack to automatically connect if a given device
|
||||
* is detected.
|
||||
* - The application wants to connect to a peer device using private addresses, but
|
||||
|
@ -63,13 +58,9 @@ enum {
|
|||
*/
|
||||
BT_DEV_SCANNING,
|
||||
|
||||
/* Cached parameters used when initially enabling the scanner.
|
||||
* These are needed to ensure the same parameters are used when restarting
|
||||
* the scanner after refreshing an RPA.
|
||||
/**
|
||||
* Scanner is configured with a timeout.
|
||||
*/
|
||||
BT_DEV_ACTIVE_SCAN,
|
||||
BT_DEV_SCAN_FILTER_DUP,
|
||||
BT_DEV_SCAN_FILTERED,
|
||||
BT_DEV_SCAN_LIMITED,
|
||||
|
||||
BT_DEV_INITIATING,
|
||||
|
@ -489,30 +480,6 @@ uint8_t bt_get_phy(uint8_t hci_phy);
|
|||
*/
|
||||
int bt_get_df_cte_type(uint8_t hci_cte_type);
|
||||
|
||||
/** Start or restart scanner if needed
|
||||
*
|
||||
* Examples of cases where it may be required to start/restart a scanner:
|
||||
* - When the auto-connection establishement feature is used:
|
||||
* - When the host sets a connection context for auto-connection establishment.
|
||||
* - When a connection was established.
|
||||
* The host may now be able to retry to automatically set up a connection.
|
||||
* - When a connection was disconnected/lost.
|
||||
* The host may now be able to retry to automatically set up a connection.
|
||||
* - When the application stops explicit scanning.
|
||||
* The host may now be able to retry to automatically set up a connection.
|
||||
* - The application tries to connect to another device, but fails.
|
||||
* The host may now be able to retry to automatically set up a connection.
|
||||
* - When the application wants to connect to a device, but we need
|
||||
* to fallback to host privacy.
|
||||
* - When the application wants to establish a periodic sync to a device
|
||||
* and the application has not already started scanning.
|
||||
*
|
||||
* @param fast_scan Use fast scan parameters or slow scan parameters
|
||||
*
|
||||
* @return 0 in case of success, or a negative error code on failure.
|
||||
*/
|
||||
int bt_le_scan_update(bool fast_scan);
|
||||
|
||||
int bt_le_create_conn(const struct bt_conn *conn);
|
||||
int bt_le_create_conn_cancel(void);
|
||||
int bt_le_create_conn_synced(const struct bt_conn *conn, const struct bt_le_ext_adv *adv,
|
||||
|
|
|
@ -689,11 +689,11 @@ static void rpa_timeout(struct k_work *work)
|
|||
le_rpa_invalidate();
|
||||
|
||||
/* IF no roles using the RPA is running we can stop the RPA timer */
|
||||
if (!(adv_enabled ||
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING) ||
|
||||
(atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN)))) {
|
||||
return;
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
||||
if (!(adv_enabled || atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING) ||
|
||||
bt_le_scan_active_scanner_running())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
le_update_private_addr();
|
||||
|
|
|
@ -5,8 +5,12 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/check.h>
|
||||
|
||||
|
@ -25,14 +29,32 @@
|
|||
#include "id.h"
|
||||
|
||||
#include "common/bt_str.h"
|
||||
#include "scan.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_scan);
|
||||
|
||||
struct scanner_state {
|
||||
ATOMIC_DEFINE(scan_flags, BT_LE_SCAN_USER_NUM_FLAGS);
|
||||
struct bt_le_scan_param explicit_scan_param;
|
||||
struct bt_le_scan_param used_scan_param;
|
||||
struct k_mutex scan_update_mutex;
|
||||
struct k_mutex scan_explicit_params_mutex;
|
||||
};
|
||||
|
||||
enum scan_action {
|
||||
SCAN_ACTION_NONE,
|
||||
SCAN_ACTION_START,
|
||||
SCAN_ACTION_STOP,
|
||||
SCAN_ACTION_UPDATE,
|
||||
};
|
||||
|
||||
static bt_le_scan_cb_t *scan_dev_found_cb;
|
||||
static sys_slist_t scan_cbs = SYS_SLIST_STATIC_INIT(&scan_cbs);
|
||||
|
||||
static struct scanner_state scan_state;
|
||||
|
||||
#if defined(CONFIG_BT_EXT_ADV)
|
||||
/* A buffer used to reassemble advertisement data from the controller. */
|
||||
NET_BUF_SIMPLE_DEFINE(ext_scan_buf, CONFIG_BT_EXT_SCAN_BUF_SIZE);
|
||||
|
@ -77,7 +99,7 @@ static sys_slist_t pa_sync_cbs = SYS_SLIST_STATIC_INIT(&pa_sync_cbs);
|
|||
#endif /* defined(CONFIG_BT_PER_ADV_SYNC) */
|
||||
#endif /* defined(CONFIG_BT_EXT_ADV) */
|
||||
|
||||
void bt_scan_reset(void)
|
||||
void bt_scan_softreset(void)
|
||||
{
|
||||
scan_dev_found_cb = NULL;
|
||||
#if defined(CONFIG_BT_EXT_ADV)
|
||||
|
@ -85,7 +107,15 @@ void bt_scan_reset(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int set_le_ext_scan_enable(uint8_t enable, uint16_t duration)
|
||||
void bt_scan_reset(void)
|
||||
{
|
||||
memset(&scan_state, 0x0, sizeof(scan_state));
|
||||
k_mutex_init(&scan_state.scan_update_mutex);
|
||||
k_mutex_init(&scan_state.scan_explicit_params_mutex);
|
||||
bt_scan_softreset();
|
||||
}
|
||||
|
||||
static int cmd_le_set_ext_scan_enable(bool enable, bool filter_duplicates, uint16_t duration)
|
||||
{
|
||||
struct bt_hci_cp_le_set_ext_scan_enable *cp;
|
||||
struct bt_hci_cmd_state_set state;
|
||||
|
@ -99,13 +129,7 @@ static int set_le_ext_scan_enable(uint8_t enable, uint16_t duration)
|
|||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
|
||||
if (enable == BT_HCI_LE_SCAN_ENABLE) {
|
||||
cp->filter_dup = atomic_test_bit(bt_dev.flags,
|
||||
BT_DEV_SCAN_FILTER_DUP);
|
||||
} else {
|
||||
cp->filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE;
|
||||
}
|
||||
|
||||
cp->filter_dup = filter_duplicates;
|
||||
cp->enable = enable;
|
||||
cp->duration = sys_cpu_to_le16(duration);
|
||||
cp->period = 0;
|
||||
|
@ -121,7 +145,7 @@ static int set_le_ext_scan_enable(uint8_t enable, uint16_t duration)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bt_le_scan_set_enable_legacy(uint8_t enable)
|
||||
static int cmd_le_set_scan_enable_legacy(bool enable, bool filter_duplicates)
|
||||
{
|
||||
struct bt_hci_cp_le_set_scan_enable *cp;
|
||||
struct bt_hci_cmd_state_set state;
|
||||
|
@ -135,13 +159,7 @@ static int bt_le_scan_set_enable_legacy(uint8_t enable)
|
|||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
|
||||
if (enable == BT_HCI_LE_SCAN_ENABLE) {
|
||||
cp->filter_dup = atomic_test_bit(bt_dev.flags,
|
||||
BT_DEV_SCAN_FILTER_DUP);
|
||||
} else {
|
||||
cp->filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE;
|
||||
}
|
||||
|
||||
cp->filter_dup = filter_duplicates;
|
||||
cp->enable = enable;
|
||||
|
||||
bt_hci_cmd_state_set_init(buf, &state, bt_dev.flags, BT_DEV_SCANNING,
|
||||
|
@ -155,20 +173,49 @@ static int bt_le_scan_set_enable_legacy(uint8_t enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_scan_set_enable(uint8_t enable)
|
||||
static int cmd_le_set_scan_enable(bool enable, bool filter_duplicates)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BT_EXT_ADV) &&
|
||||
BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
|
||||
return set_le_ext_scan_enable(enable, 0);
|
||||
if (IS_ENABLED(CONFIG_BT_EXT_ADV) && BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
|
||||
return cmd_le_set_ext_scan_enable(enable, filter_duplicates, 0);
|
||||
}
|
||||
|
||||
return bt_le_scan_set_enable_legacy(enable);
|
||||
return cmd_le_set_scan_enable_legacy(enable, filter_duplicates);
|
||||
}
|
||||
|
||||
static int start_le_scan_ext(struct bt_hci_ext_scan_phy *phy_1m,
|
||||
struct bt_hci_ext_scan_phy *phy_coded,
|
||||
uint16_t duration)
|
||||
int bt_le_scan_set_enable(uint8_t enable)
|
||||
{
|
||||
return cmd_le_set_scan_enable(enable, scan_state.used_scan_param.options &
|
||||
BT_LE_SCAN_OPT_FILTER_DUPLICATE);
|
||||
}
|
||||
|
||||
static int start_le_scan_ext(struct bt_le_scan_param *scan_param)
|
||||
{
|
||||
struct bt_hci_ext_scan_phy param_1m;
|
||||
struct bt_hci_ext_scan_phy param_coded;
|
||||
|
||||
struct bt_hci_ext_scan_phy *phy_1m = NULL;
|
||||
struct bt_hci_ext_scan_phy *phy_coded = NULL;
|
||||
|
||||
if (!(scan_param->options & BT_LE_SCAN_OPT_NO_1M)) {
|
||||
param_1m.type = scan_param->type;
|
||||
param_1m.interval = sys_cpu_to_le16(scan_param->interval);
|
||||
param_1m.window = sys_cpu_to_le16(scan_param->window);
|
||||
|
||||
phy_1m = ¶m_1m;
|
||||
}
|
||||
|
||||
if (scan_param->options & BT_LE_SCAN_OPT_CODED) {
|
||||
uint16_t interval = scan_param->interval_coded ? scan_param->interval_coded
|
||||
: scan_param->interval;
|
||||
uint16_t window =
|
||||
scan_param->window_coded ? scan_param->window_coded : scan_param->window;
|
||||
|
||||
param_coded.type = scan_param->type;
|
||||
param_coded.interval = sys_cpu_to_le16(interval);
|
||||
param_coded.window = sys_cpu_to_le16(window);
|
||||
phy_coded = ¶m_coded;
|
||||
}
|
||||
|
||||
struct bt_hci_cp_le_set_ext_scan_param *set_param;
|
||||
struct net_buf *buf;
|
||||
uint8_t own_addr_type;
|
||||
|
@ -178,7 +225,7 @@ static int start_le_scan_ext(struct bt_hci_ext_scan_phy *phy_1m,
|
|||
active_scan = (phy_1m && phy_1m->type == BT_HCI_LE_SCAN_ACTIVE) ||
|
||||
(phy_coded && phy_coded->type == BT_HCI_LE_SCAN_ACTIVE);
|
||||
|
||||
if (duration > 0) {
|
||||
if (scan_param->timeout > 0) {
|
||||
atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED);
|
||||
|
||||
/* Allow bt_le_oob_get_local to be called directly before
|
||||
|
@ -205,13 +252,9 @@ static int start_le_scan_ext(struct bt_hci_ext_scan_phy *phy_1m,
|
|||
set_param = net_buf_add(buf, sizeof(*set_param));
|
||||
set_param->own_addr_type = own_addr_type;
|
||||
set_param->phys = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_FILTER_ACCEPT_LIST) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_FILTERED)) {
|
||||
set_param->filter_policy = BT_HCI_LE_SCAN_FP_BASIC_FILTER;
|
||||
} else {
|
||||
set_param->filter_policy = BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER;
|
||||
}
|
||||
set_param->filter_policy = scan_param->options & BT_LE_SCAN_OPT_FILTER_ACCEPT_LIST
|
||||
? BT_HCI_LE_SCAN_FP_BASIC_FILTER
|
||||
: BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER;
|
||||
|
||||
if (phy_1m) {
|
||||
set_param->phys |= BT_HCI_LE_EXT_SCAN_PHY_1M;
|
||||
|
@ -228,17 +271,17 @@ static int start_le_scan_ext(struct bt_hci_ext_scan_phy *phy_1m,
|
|||
return err;
|
||||
}
|
||||
|
||||
err = set_le_ext_scan_enable(BT_HCI_LE_SCAN_ENABLE, duration);
|
||||
err = cmd_le_set_ext_scan_enable(BT_HCI_LE_SCAN_ENABLE,
|
||||
scan_param->options & BT_LE_SCAN_OPT_FILTER_DUPLICATE,
|
||||
scan_param->timeout);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
atomic_set_bit_to(bt_dev.flags, BT_DEV_ACTIVE_SCAN, active_scan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_le_scan_legacy(uint8_t scan_type, uint16_t interval, uint16_t window)
|
||||
static int start_le_scan_legacy(struct bt_le_scan_param *param)
|
||||
{
|
||||
struct bt_hci_cp_le_set_scan_param set_param;
|
||||
struct net_buf *buf;
|
||||
|
@ -247,22 +290,22 @@ static int start_le_scan_legacy(uint8_t scan_type, uint16_t interval, uint16_t w
|
|||
|
||||
(void)memset(&set_param, 0, sizeof(set_param));
|
||||
|
||||
set_param.scan_type = scan_type;
|
||||
set_param.scan_type = param->type;
|
||||
|
||||
/* for the rest parameters apply default values according to
|
||||
* spec 4.2, vol2, part E, 7.8.10
|
||||
*/
|
||||
set_param.interval = sys_cpu_to_le16(interval);
|
||||
set_param.window = sys_cpu_to_le16(window);
|
||||
set_param.interval = sys_cpu_to_le16(param->interval);
|
||||
set_param.window = sys_cpu_to_le16(param->window);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_FILTER_ACCEPT_LIST) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_FILTERED)) {
|
||||
param->options & BT_LE_SCAN_OPT_FILTER_ACCEPT_LIST) {
|
||||
set_param.filter_policy = BT_HCI_LE_SCAN_FP_BASIC_FILTER;
|
||||
} else {
|
||||
set_param.filter_policy = BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER;
|
||||
}
|
||||
|
||||
active_scan = scan_type == BT_HCI_LE_SCAN_ACTIVE;
|
||||
active_scan = param->type == BT_HCI_LE_SCAN_ACTIVE;
|
||||
err = bt_id_set_scan_own_addr(active_scan, &set_param.addr_type);
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -280,99 +323,205 @@ static int start_le_scan_legacy(uint8_t scan_type, uint16_t interval, uint16_t w
|
|||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_scan_set_enable(BT_HCI_LE_SCAN_ENABLE);
|
||||
err = cmd_le_set_scan_enable(BT_HCI_LE_SCAN_ENABLE,
|
||||
param->options & BT_LE_SCAN_OPT_FILTER_DUPLICATE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
atomic_set_bit_to(bt_dev.flags, BT_DEV_ACTIVE_SCAN, active_scan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool bt_le_scan_active_scanner_running(void)
|
||||
{
|
||||
return atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) &&
|
||||
scan_state.used_scan_param.type == BT_LE_SCAN_TYPE_ACTIVE;
|
||||
}
|
||||
|
||||
static void select_scan_params(struct bt_le_scan_param *scan_param)
|
||||
{
|
||||
/* From high priority to low priority: select parameters */
|
||||
/* 1. Priority: explicitly chosen parameters */
|
||||
if (atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_EXPLICIT_SCAN)) {
|
||||
memcpy(scan_param, &scan_state.explicit_scan_param, sizeof(*scan_param));
|
||||
}
|
||||
/* Below this, the scanner module chooses the parameters. */
|
||||
/* 2. Priority: reuse parameters from initiator */
|
||||
else if (atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
|
||||
*scan_param = (struct bt_le_scan_param){
|
||||
.type = BT_LE_SCAN_TYPE_PASSIVE,
|
||||
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
|
||||
.interval = bt_dev.create_param.interval,
|
||||
.window = bt_dev.create_param.window,
|
||||
.timeout = 0,
|
||||
.interval_coded = bt_dev.create_param.interval_coded,
|
||||
.window_coded = bt_dev.create_param.window_coded,
|
||||
};
|
||||
}
|
||||
/* 3. Priority: choose custom parameters */
|
||||
else {
|
||||
*scan_param = (struct bt_le_scan_param){
|
||||
.type = BT_LE_SCAN_TYPE_PASSIVE,
|
||||
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
|
||||
.interval = CONFIG_BT_BACKGROUND_SCAN_INTERVAL,
|
||||
.window = CONFIG_BT_BACKGROUND_SCAN_WINDOW,
|
||||
.timeout = 0,
|
||||
.interval_coded = 0,
|
||||
.window_coded = 0,
|
||||
};
|
||||
|
||||
if (BT_FEAT_LE_PHY_CODED(bt_dev.le.features)) {
|
||||
scan_param->options |= BT_LE_SCAN_OPT_CODED;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_PER_SYNC) ||
|
||||
atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_CONN)) {
|
||||
scan_param->window = BT_GAP_SCAN_FAST_WINDOW;
|
||||
scan_param->interval = BT_GAP_SCAN_FAST_INTERVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int start_scan(struct bt_le_scan_param *scan_param)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BT_EXT_ADV) && BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
|
||||
return start_le_scan_ext(scan_param);
|
||||
}
|
||||
|
||||
return start_le_scan_legacy(scan_param);
|
||||
}
|
||||
|
||||
static bool is_already_using_same_params(struct bt_le_scan_param *scan_param)
|
||||
{
|
||||
return !memcmp(scan_param, &scan_state.used_scan_param, sizeof(*scan_param));
|
||||
}
|
||||
|
||||
static enum scan_action get_scan_action(struct bt_le_scan_param *scan_param)
|
||||
{
|
||||
bool is_scanning = atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING);
|
||||
|
||||
/* Check if there is reason to have the scanner running */
|
||||
if (atomic_get(scan_state.scan_flags) != 0) {
|
||||
if (is_scanning) {
|
||||
if (is_already_using_same_params(scan_param)) {
|
||||
/* Already scanning with the desired parameters */
|
||||
return SCAN_ACTION_NONE;
|
||||
} else {
|
||||
return SCAN_ACTION_UPDATE;
|
||||
}
|
||||
} else {
|
||||
return SCAN_ACTION_START;
|
||||
}
|
||||
} else {
|
||||
/* Scanner should not run */
|
||||
if (is_scanning) {
|
||||
return SCAN_ACTION_STOP;
|
||||
} else {
|
||||
return SCAN_ACTION_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int scan_update(void)
|
||||
{
|
||||
int32_t err;
|
||||
|
||||
struct bt_le_scan_param scan_param;
|
||||
|
||||
/* Prevent partial updates of the scanner state. */
|
||||
err = k_mutex_lock(&scan_state.scan_update_mutex, K_NO_WAIT);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
select_scan_params(&scan_param);
|
||||
|
||||
enum scan_action action = get_scan_action(&scan_param);
|
||||
|
||||
/* start/stop/update if required and allowed */
|
||||
switch (action) {
|
||||
case SCAN_ACTION_NONE:
|
||||
break;
|
||||
case SCAN_ACTION_STOP:
|
||||
err = cmd_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE,
|
||||
BT_HCI_LE_SCAN_FILTER_DUP_DISABLE);
|
||||
if (err) {
|
||||
LOG_DBG("Could not stop scanner: %d", err);
|
||||
break;
|
||||
}
|
||||
memset(&scan_state.used_scan_param, 0x0,
|
||||
sizeof(scan_state.used_scan_param));
|
||||
break;
|
||||
case SCAN_ACTION_UPDATE:
|
||||
err = cmd_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE,
|
||||
BT_HCI_LE_SCAN_FILTER_DUP_DISABLE);
|
||||
if (err) {
|
||||
LOG_DBG("Could not stop scanner to update: %d", err);
|
||||
break;
|
||||
}
|
||||
__fallthrough;
|
||||
case SCAN_ACTION_START:
|
||||
err = start_scan(&scan_param);
|
||||
if (err) {
|
||||
LOG_DBG("Could not start scanner: %d", err);
|
||||
break;
|
||||
}
|
||||
memcpy(&scan_state.used_scan_param, &scan_param, sizeof(scan_param));
|
||||
break;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&scan_state.scan_update_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint32_t scan_check_if_state_allowed(enum bt_le_scan_user flag)
|
||||
{
|
||||
/* check if state is already set */
|
||||
if (atomic_test_bit(scan_state.scan_flags, flag)) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (flag == BT_LE_SCAN_USER_EXPLICIT_SCAN && !BT_LE_STATES_SCAN_INIT(bt_dev.le.states) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_host_initiated_scan(bool fast_scan)
|
||||
int bt_le_scan_user_add(enum bt_le_scan_user flag)
|
||||
{
|
||||
uint16_t interval, window;
|
||||
uint32_t err;
|
||||
|
||||
if (fast_scan) {
|
||||
interval = BT_GAP_SCAN_FAST_INTERVAL;
|
||||
window = BT_GAP_SCAN_FAST_WINDOW;
|
||||
} else {
|
||||
interval = CONFIG_BT_BACKGROUND_SCAN_INTERVAL;
|
||||
window = CONFIG_BT_BACKGROUND_SCAN_WINDOW;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_EXT_ADV) &&
|
||||
BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
|
||||
struct bt_hci_ext_scan_phy scan_phy_params;
|
||||
|
||||
scan_phy_params.type = BT_HCI_LE_SCAN_PASSIVE;
|
||||
scan_phy_params.interval = sys_cpu_to_le16(interval);
|
||||
scan_phy_params.window = sys_cpu_to_le16(window);
|
||||
|
||||
/* Scan on 1M + Coded if the controller supports it*/
|
||||
if (BT_FEAT_LE_PHY_CODED(bt_dev.le.features)) {
|
||||
return start_le_scan_ext(&scan_phy_params, &scan_phy_params, 0);
|
||||
} else {
|
||||
return start_le_scan_ext(&scan_phy_params, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return start_le_scan_legacy(BT_HCI_LE_SCAN_PASSIVE, interval, window);
|
||||
}
|
||||
|
||||
int bt_le_scan_update(bool fast_scan)
|
||||
{
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
/* The application has already explicitly started scanning.
|
||||
* We should keep the scanner running to avoid changing scan parameters.
|
||||
if (flag == BT_LE_SCAN_USER_NONE) {
|
||||
/* Only check if the scanner parameters should be updated / the scanner should be
|
||||
* started. This is mainly triggered once connections are established.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
||||
int err;
|
||||
|
||||
err = bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE);
|
||||
} else {
|
||||
/* Check if it can be enabled */
|
||||
err = scan_check_if_state_allowed(flag);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
atomic_set_bit(scan_state.scan_flags, flag);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
|
||||
struct bt_conn *conn;
|
||||
return scan_update();
|
||||
}
|
||||
|
||||
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states)) {
|
||||
/* don't restart scan if we have pending connection */
|
||||
conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL,
|
||||
BT_CONN_INITIATING);
|
||||
if (conn) {
|
||||
bt_conn_unref(conn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL,
|
||||
BT_CONN_SCAN_BEFORE_INITIATING);
|
||||
if (conn) {
|
||||
atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP);
|
||||
|
||||
bt_conn_unref(conn);
|
||||
|
||||
/* Start/Restart the scanner */
|
||||
return start_host_initiated_scan(fast_scan);
|
||||
}
|
||||
int bt_le_scan_user_remove(enum bt_le_scan_user flag)
|
||||
{
|
||||
if (flag == BT_LE_SCAN_USER_NONE) {
|
||||
/* Only check if the scanner parameters should be updated / the scanner should be
|
||||
* started. This is mainly triggered once connections are established.
|
||||
*/
|
||||
} else {
|
||||
atomic_clear_bit(scan_state.scan_flags, flag);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_PER_ADV_SYNC)
|
||||
if (get_pending_per_adv_sync()) {
|
||||
/* Start/Restart the scanner. */
|
||||
return start_host_initiated_scan(fast_scan);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return scan_update();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CENTRAL)
|
||||
|
@ -380,12 +529,13 @@ static void check_pending_conn(const bt_addr_le_t *id_addr,
|
|||
const bt_addr_le_t *addr, uint8_t adv_props)
|
||||
{
|
||||
struct bt_conn *conn;
|
||||
int err;
|
||||
|
||||
/* No connections are allowed during explicit scanning
|
||||
* when the controller does not support concurrent scanning and initiating.
|
||||
*/
|
||||
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_EXPLICIT_SCAN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -400,11 +550,13 @@ static void check_pending_conn(const bt_addr_le_t *id_addr,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!BT_LE_STATES_SCAN_INIT(bt_dev.le.states)) {
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) &&
|
||||
bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE)) {
|
||||
goto failed;
|
||||
}
|
||||
/* Stop the scanner if there is no other reason to have it running.
|
||||
* Ignore possible failures here, since the user is guaranteed to be removed
|
||||
* and the scanner state is updated once the initiator starts / stops.
|
||||
*/
|
||||
err = bt_le_scan_user_remove(BT_LE_SCAN_USER_CONN);
|
||||
if (err) {
|
||||
LOG_DBG("Error while removing conn user from scanner (%d)", err);
|
||||
}
|
||||
|
||||
bt_addr_le_copy(&conn->le.resp_addr, addr);
|
||||
|
@ -420,7 +572,12 @@ failed:
|
|||
conn->err = BT_HCI_ERR_UNSPECIFIED;
|
||||
bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
|
||||
bt_conn_unref(conn);
|
||||
bt_le_scan_update(false);
|
||||
/* Just a best-effort check if the scanner should be started. */
|
||||
err = bt_le_scan_user_remove(BT_LE_SCAN_USER_NONE);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Error while updating the scanner (%d)", err);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_CENTRAL */
|
||||
|
||||
|
@ -465,9 +622,8 @@ static void le_adv_recv(bt_addr_le_t *addr, struct bt_le_scan_recv_info *info,
|
|||
LOG_DBG("%s event %u, len %u, rssi %d dBm", bt_addr_le_str(addr), info->adv_type, len,
|
||||
info->rssi);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_PRIVACY) &&
|
||||
!IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) &&
|
||||
atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN) &&
|
||||
if (!IS_ENABLED(CONFIG_BT_PRIVACY) && !IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) &&
|
||||
atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_EXPLICIT_SCAN) &&
|
||||
(info->adv_props & BT_HCI_LE_ADV_PROP_DIRECT)) {
|
||||
LOG_DBG("Dropped direct adv report");
|
||||
return;
|
||||
|
@ -517,8 +673,16 @@ void bt_hci_le_scan_timeout(struct net_buf *buf)
|
|||
{
|
||||
struct bt_le_scan_cb *listener, *next;
|
||||
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING);
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
||||
int err = bt_le_scan_user_remove(BT_LE_SCAN_USER_EXPLICIT_SCAN);
|
||||
|
||||
if (err) {
|
||||
k_yield();
|
||||
err = bt_le_scan_user_remove(BT_LE_SCAN_USER_EXPLICIT_SCAN);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Could not stop the explicit scanner (%d)", err);
|
||||
}
|
||||
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED);
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID);
|
||||
|
@ -610,7 +774,7 @@ void bt_hci_le_adv_ext_report(struct net_buf *buf)
|
|||
bool more_to_come;
|
||||
bool is_new_advertiser;
|
||||
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
if (!atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_EXPLICIT_SCAN)) {
|
||||
/* The application has not requested explicit scan, so it is not expecting
|
||||
* advertising reports. Discard, and reset the reassembler if not inactive
|
||||
* This is done in the loop as this flag can change between each iteration,
|
||||
|
@ -1014,9 +1178,8 @@ static void bt_hci_le_per_adv_sync_established_common(struct net_buf *buf)
|
|||
pending_per_adv_sync = get_pending_per_adv_sync();
|
||||
|
||||
if (pending_per_adv_sync) {
|
||||
atomic_clear_bit(pending_per_adv_sync->flags,
|
||||
BT_PER_ADV_SYNC_SYNCING);
|
||||
err = bt_le_scan_update(false);
|
||||
atomic_clear_bit(pending_per_adv_sync->flags, BT_PER_ADV_SYNC_SYNCING);
|
||||
err = bt_le_scan_user_remove(BT_LE_SCAN_USER_PER_SYNC);
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Could not update scan (%d)", err);
|
||||
|
@ -1474,7 +1637,7 @@ void bt_hci_le_adv_report(struct net_buf *buf)
|
|||
while (num_reports--) {
|
||||
struct bt_le_scan_recv_info adv_info;
|
||||
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
if (!atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_EXPLICIT_SCAN)) {
|
||||
/* The application has not requested explicit scan, so it is not expecting
|
||||
* advertising reports. Discard.
|
||||
* This is done in the loop as this flag can change between each iteration,
|
||||
|
@ -1577,91 +1740,37 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Return if active scan is already enabled */
|
||||
if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
||||
err = bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE);
|
||||
if (err) {
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_set_bit_to(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP,
|
||||
param->options & BT_LE_SCAN_OPT_FILTER_DUPLICATE);
|
||||
|
||||
#if defined(CONFIG_BT_FILTER_ACCEPT_LIST)
|
||||
atomic_set_bit_to(bt_dev.flags, BT_DEV_SCAN_FILTERED,
|
||||
param->options & BT_LE_SCAN_OPT_FILTER_ACCEPT_LIST);
|
||||
#endif /* defined(CONFIG_BT_FILTER_ACCEPT_LIST) */
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_EXT_ADV) &&
|
||||
BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
|
||||
if (IS_ENABLED(CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL) && param->timeout) {
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
struct bt_hci_ext_scan_phy param_1m;
|
||||
struct bt_hci_ext_scan_phy param_coded;
|
||||
|
||||
struct bt_hci_ext_scan_phy *phy_1m = NULL;
|
||||
struct bt_hci_ext_scan_phy *phy_coded = NULL;
|
||||
|
||||
if (!(param->options & BT_LE_SCAN_OPT_NO_1M)) {
|
||||
param_1m.type = param->type;
|
||||
param_1m.interval = sys_cpu_to_le16(param->interval);
|
||||
param_1m.window = sys_cpu_to_le16(param->window);
|
||||
|
||||
phy_1m = ¶m_1m;
|
||||
}
|
||||
|
||||
if (param->options & BT_LE_SCAN_OPT_CODED) {
|
||||
uint16_t interval = param->interval_coded ?
|
||||
param->interval_coded :
|
||||
param->interval;
|
||||
uint16_t window = param->window_coded ?
|
||||
param->window_coded :
|
||||
param->window;
|
||||
|
||||
param_coded.type = param->type;
|
||||
param_coded.interval = sys_cpu_to_le16(interval);
|
||||
param_coded.window = sys_cpu_to_le16(window);
|
||||
phy_coded = ¶m_coded;
|
||||
}
|
||||
|
||||
err = start_le_scan_ext(phy_1m, phy_coded, param->timeout);
|
||||
} else {
|
||||
if (param->timeout) {
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
err = start_le_scan_legacy(param->type, param->interval,
|
||||
param->window);
|
||||
}
|
||||
/* Prevent multiple threads to try to enable explicit scanning at the same time.
|
||||
* That could lead to unwanted overwriting of scan_state.explicit_scan_param.
|
||||
*/
|
||||
err = k_mutex_lock(&scan_state.scan_explicit_params_mutex, K_NO_WAIT);
|
||||
|
||||
if (err) {
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
|
||||
return err;
|
||||
}
|
||||
|
||||
scan_dev_found_cb = cb;
|
||||
err = scan_check_if_state_allowed(BT_LE_SCAN_USER_EXPLICIT_SCAN);
|
||||
|
||||
return 0;
|
||||
if (err) {
|
||||
k_mutex_unlock(&scan_state.scan_explicit_params_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* store the parameters that were used to start the scanner */
|
||||
memcpy(&scan_state.explicit_scan_param, param,
|
||||
sizeof(scan_state.explicit_scan_param));
|
||||
|
||||
scan_dev_found_cb = cb;
|
||||
err = bt_le_scan_user_add(BT_LE_SCAN_USER_EXPLICIT_SCAN);
|
||||
k_mutex_unlock(&scan_state.scan_explicit_params_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_le_scan_stop(void)
|
||||
{
|
||||
/* Return if active scanning is already disabled */
|
||||
if (!atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
bt_scan_reset();
|
||||
bt_scan_softreset();
|
||||
scan_dev_found_cb = NULL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_EXT_ADV) &&
|
||||
atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED)) {
|
||||
|
@ -1672,7 +1781,7 @@ int bt_le_scan_stop(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
return bt_le_scan_update(false);
|
||||
return bt_le_scan_user_remove(BT_LE_SCAN_USER_EXPLICIT_SCAN);
|
||||
}
|
||||
|
||||
int bt_le_scan_cb_register(struct bt_le_scan_cb *cb)
|
||||
|
@ -1844,13 +1953,16 @@ int bt_le_per_adv_sync_create(const struct bt_le_per_adv_sync_param *param,
|
|||
* established. We don't need to use any callbacks since we rely on
|
||||
* the advertiser address in the sync params.
|
||||
*/
|
||||
if (!atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
||||
err = bt_le_scan_update(true);
|
||||
err = bt_le_scan_user_add(BT_LE_SCAN_USER_PER_SYNC);
|
||||
if (err) {
|
||||
int per_sync_remove_err = bt_le_scan_user_remove(BT_LE_SCAN_USER_PER_SYNC);
|
||||
|
||||
if (err) {
|
||||
bt_le_per_adv_sync_delete(per_adv_sync);
|
||||
return err;
|
||||
if (per_sync_remove_err) {
|
||||
LOG_WRN("Error while updating the scanner (%d)", per_sync_remove_err);
|
||||
}
|
||||
|
||||
bt_le_per_adv_sync_delete(per_adv_sync);
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_sync = per_adv_sync;
|
||||
|
@ -1870,6 +1982,12 @@ static int bt_le_per_adv_sync_create_cancel(
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = bt_le_scan_user_remove(BT_LE_SCAN_USER_PER_SYNC);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL, 0);
|
||||
if (!buf) {
|
||||
return -ENOBUFS;
|
||||
|
@ -2285,3 +2403,8 @@ int bt_le_per_adv_list_clear(void)
|
|||
return 0;
|
||||
}
|
||||
#endif /* defined(CONFIG_BT_PER_ADV_SYNC) */
|
||||
|
||||
bool bt_le_explicit_scanner_running(void)
|
||||
{
|
||||
return atomic_test_bit(scan_state.scan_flags, BT_LE_SCAN_USER_EXPLICIT_SCAN);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,120 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef SUBSYS_BLUETOOTH_HOST_SCAN_H_
|
||||
#define SUBSYS_BLUETOOTH_HOST_SCAN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
/**
|
||||
* Reasons why a scanner can be running.
|
||||
* Used as input to @ref bt_le_scan_user_add
|
||||
* and @ref bt_le_scan_user_remove.
|
||||
*/
|
||||
enum bt_le_scan_user {
|
||||
/** The application explicitly instructed the stack to scan for advertisers
|
||||
* using the API @ref bt_le_scan_start.
|
||||
* Users of the scanner module may not use this flag as input to @ref bt_le_scan_user_add
|
||||
* and @ref bt_le_scan_user_remove. Use ®ref bt_le_scan_start and @ref bt_le_scan_stop
|
||||
* instead.
|
||||
*/
|
||||
BT_LE_SCAN_USER_EXPLICIT_SCAN,
|
||||
|
||||
/**
|
||||
* Periodic sync syncing to a periodic advertiser.
|
||||
*/
|
||||
BT_LE_SCAN_USER_PER_SYNC,
|
||||
|
||||
/**
|
||||
* Scanning to find devices to connect to.
|
||||
*/
|
||||
BT_LE_SCAN_USER_CONN,
|
||||
|
||||
/**
|
||||
* Special state for a NOP for @ref bt_le_scan_user_add and @ref bt_le_scan_user_remove to
|
||||
* not add/remove any user.
|
||||
*/
|
||||
BT_LE_SCAN_USER_NONE,
|
||||
BT_LE_SCAN_USER_NUM_FLAGS,
|
||||
};
|
||||
|
||||
void bt_scan_reset(void);
|
||||
|
||||
bool bt_id_scan_random_addr_check(void);
|
||||
bool bt_le_scan_active_scanner_running(void);
|
||||
|
||||
int bt_le_scan_set_enable(uint8_t enable);
|
||||
|
||||
void bt_periodic_sync_disable(void);
|
||||
|
||||
/**
|
||||
* Start / update the scanner.
|
||||
*
|
||||
* This API updates the users of the scanner.
|
||||
* Multiple users can be enabled at the same time.
|
||||
* Depending on all the users, scan parameters are selected
|
||||
* and the scanner is started or updated, if needed.
|
||||
* This API may update the scan parameters, for example if the scanner is already running
|
||||
* when another user that demands higher duty-cycle is being added.
|
||||
* It is not allowed to add a user that was already added.
|
||||
*
|
||||
* Every SW module that informs the scanner that it should run, needs to eventually remove
|
||||
* the flag again using @ref bt_le_scan_user_remove once it does not require
|
||||
* the scanner to run, anymore.
|
||||
*
|
||||
* If flag is set to @ref BT_LE_SCAN_USER_NONE, no user is being added. Instead, the
|
||||
* existing users are checked and the scanner is started, stopped or updated.
|
||||
* For platforms where scanning and initiating at the same time is not supported,
|
||||
* this allows the background scanner to be started or stopped once the device starts to
|
||||
* initiate a connection.
|
||||
*
|
||||
* @param flag user requesting the scanner
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval -EALREADY if the user is already enabled
|
||||
* @retval -EPERM if the explicit scanner is being enabled while the initiator is running
|
||||
* and the device does not support this configuration.
|
||||
* @retval -ENOBUFS if no hci command buffer could be allocated
|
||||
* @retval -EBUSY if the scanner is updated in a different thread. The user was added but
|
||||
* the scanner was not started/stopped/updated.
|
||||
* @returns negative error codes for errors in @ref bt_hci_cmd_send_sync
|
||||
*/
|
||||
int bt_le_scan_user_add(enum bt_le_scan_user flag);
|
||||
|
||||
/**
|
||||
* Stop / update the scanner.
|
||||
*
|
||||
* This API updates the users of the scanner.
|
||||
* Depending on all enabled users, scan parameters are selected
|
||||
* and the scanner is stopped or updated, if needed.
|
||||
* This API may update the scan parameters, for example if the scanner is already running
|
||||
* when a user that demands higher duty-cycle is being removed.
|
||||
* Removing a user that was not added does not result in an error.
|
||||
*
|
||||
* This API allows removing the user why the scanner is running.
|
||||
* If all users for the scanner to run are removed, this API will stop the scanner.
|
||||
*
|
||||
* If flag is set to @ref BT_LE_SCAN_USER_NONE, no user is being added. Instead, the
|
||||
* existing users are checked and the scanner is started, stopped or updated.
|
||||
* For platforms where scanning and initiating at the same time is not supported,
|
||||
* this allows the background scanner to be started or stopped once the device starts to
|
||||
* initiate a connection.
|
||||
*
|
||||
* @param flag user releasing the scanner
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval -ENOBUFS if no hci command buffer could be allocated
|
||||
* @retval -EBUSY if the scanner is updated in a different thread. The user was removed but
|
||||
* the scanner was not started/stopped/updated.
|
||||
* @returns negative error codes for errors in @ref bt_hci_cmd_send_sync
|
||||
*/
|
||||
int bt_le_scan_user_remove(enum bt_le_scan_user flag);
|
||||
|
||||
/**
|
||||
* Check if the explicit scanner was enabled.
|
||||
*/
|
||||
bool bt_le_explicit_scanner_running(void);
|
||||
#endif /* defined SUBSYS_BLUETOOTH_HOST_SCAN_H_ */
|
||||
|
|
|
@ -9,3 +9,4 @@
|
|||
#include <mocks/scan.h>
|
||||
|
||||
DEFINE_FAKE_VALUE_FUNC(int, bt_le_scan_set_enable, uint8_t);
|
||||
DEFINE_FAKE_VALUE_FUNC(bool, bt_le_scan_active_scanner_running);
|
||||
|
|
|
@ -11,3 +11,4 @@
|
|||
#define SCAN_FFF_FAKES_LIST(FAKE) FAKE(bt_le_scan_set_enable)
|
||||
|
||||
DECLARE_FAKE_VALUE_FUNC(int, bt_le_scan_set_enable, uint8_t);
|
||||
DECLARE_FAKE_VALUE_FUNC(bool, bt_le_scan_active_scanner_running);
|
||||
|
|
|
@ -39,5 +39,6 @@ run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/privacy/device/compil
|
|||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/privacy/legacy/compile.sh
|
||||
|
||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/id/settings/compile.sh
|
||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/scan/start_stop/compile.sh
|
||||
|
||||
wait_for_background_jobs
|
||||
|
|
19
tests/bsim/bluetooth/host/scan/start_stop/CMakeLists.txt
Normal file
19
tests/bsim/bluetooth/host/scan/start_stop/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_scan_start_stop)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
)
|
||||
|
||||
# This contains babblesim-specific helpers, e.g. device synchronization.
|
||||
add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit)
|
||||
target_link_libraries(app PRIVATE babblekit)
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
)
|
14
tests/bsim/bluetooth/host/scan/start_stop/compile.sh
Executable file
14
tests/bsim/bluetooth/host/scan/start_stop/compile.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -eu
|
||||
: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}"
|
||||
|
||||
INCR_BUILD=1
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/compile.source
|
||||
|
||||
app="$(guess_test_relpath)" compile
|
||||
|
||||
wait_for_background_jobs
|
13
tests/bsim/bluetooth/host/scan/start_stop/prj.conf
Normal file
13
tests/bsim/bluetooth/host/scan/start_stop/prj.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_BROADCASTER=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_OBSERVER=y
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC=y
|
||||
CONFIG_BT_PER_ADV=y
|
||||
CONFIG_BT_DEVICE_NAME="Scanner Test"
|
||||
CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL=y
|
||||
CONFIG_BT_PRIVACY=n
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_ASSERT=y
|
268
tests/bsim/bluetooth/host/scan/start_stop/src/main.c
Normal file
268
tests/bsim/bluetooth/host/scan/start_stop/src/main.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
/* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/addr.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/atomic_builtin.h>
|
||||
#include <babblekit/testcase.h>
|
||||
#include <babblekit/sync.h>
|
||||
#include <babblekit/flags.h>
|
||||
|
||||
LOG_MODULE_REGISTER(bt_bsim_scan_start_stop, LOG_LEVEL_DBG);
|
||||
|
||||
#define WAIT_TIME_S 60
|
||||
#define WAIT_TIME (WAIT_TIME_S * 1e6)
|
||||
|
||||
static atomic_t flag_adv_report_received;
|
||||
static atomic_t flag_periodic_sync_established;
|
||||
static bt_addr_le_t adv_addr;
|
||||
|
||||
static void test_tick(bs_time_t HW_device_time)
|
||||
{
|
||||
if (bst_result != Passed) {
|
||||
TEST_FAIL("Test failed (not passed after %d seconds)\n", WAIT_TIME_S);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_init(void)
|
||||
{
|
||||
bst_ticker_set_next_tick_absolute(WAIT_TIME);
|
||||
}
|
||||
|
||||
static void bt_sync_established_cb(struct bt_le_per_adv_sync *sync,
|
||||
struct bt_le_per_adv_sync_synced_info *info)
|
||||
{
|
||||
LOG_DBG("Periodic sync established");
|
||||
atomic_set(&flag_periodic_sync_established, true);
|
||||
}
|
||||
|
||||
static struct bt_le_per_adv_sync_cb sync_callbacks = {
|
||||
.synced = bt_sync_established_cb,
|
||||
};
|
||||
|
||||
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
||||
struct net_buf_simple *ad)
|
||||
{
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
memcpy(&adv_addr, addr, sizeof(adv_addr));
|
||||
|
||||
bt_addr_le_to_str(&adv_addr, addr_str, sizeof(addr_str));
|
||||
LOG_DBG("Device found: %s (RSSI %d), type %u, AD data len %u",
|
||||
addr_str, rssi, type, ad->len);
|
||||
atomic_set(&flag_adv_report_received, true);
|
||||
}
|
||||
|
||||
void run_dut(void)
|
||||
{
|
||||
/* Test purpose:
|
||||
*
|
||||
* Verifies that the scanner can establish a sync to a device when
|
||||
* it is explicitly enabled and disabled. Disabling the scanner
|
||||
* explicitly should not stop the implicitly started scanner.
|
||||
* Verify that the explicit scanner can be started when the
|
||||
* implicit scanner is already running.
|
||||
*
|
||||
* Two devices:
|
||||
* - `dut`: tries to establish the sync
|
||||
* - `peer`: runs an advertiser / periodic advertiser
|
||||
*
|
||||
* Procedure:
|
||||
* - [dut] start establishing a sync (no peer)
|
||||
* - [peer] starts advertising
|
||||
* - [dut] starts explicit scanning
|
||||
* - [dut] wait for the peer to be found
|
||||
* - [dut] stops explicit scanning
|
||||
* - [dut] stop the periodic sync
|
||||
* - [dut] start establishing a sync to the peer
|
||||
* - [dut] start and stop explicit scanning
|
||||
* - [peer] start periodic advertiser
|
||||
* - [dut] wait until a sync is established
|
||||
*
|
||||
* [verdict]
|
||||
* - dut is able to sync to the peer.
|
||||
*/
|
||||
|
||||
LOG_DBG("start");
|
||||
bk_sync_init();
|
||||
int err;
|
||||
|
||||
LOG_DBG("Starting DUT");
|
||||
|
||||
err = bt_enable(NULL);
|
||||
TEST_ASSERT(!err, "Bluetooth init failed (err %d)\n", err);
|
||||
|
||||
LOG_DBG("Bluetooth initialised");
|
||||
|
||||
/* Try to establish a sync to a periodic advertiser.
|
||||
* This will start the scanner.
|
||||
*/
|
||||
memset(&adv_addr, 0x00, sizeof(adv_addr));
|
||||
struct bt_le_per_adv_sync_param per_sync_param = {
|
||||
.addr = adv_addr,
|
||||
.options = 0x0,
|
||||
.sid = 0x0,
|
||||
.skip = 0x0,
|
||||
.timeout = BT_GAP_PER_ADV_MAX_TIMEOUT,
|
||||
};
|
||||
struct bt_le_per_adv_sync *p_per_sync;
|
||||
|
||||
bt_le_per_adv_sync_cb_register(&sync_callbacks);
|
||||
|
||||
err = bt_le_per_adv_sync_create(&per_sync_param, &p_per_sync);
|
||||
TEST_ASSERT(!err, "Periodic sync setup failed (err %d)\n", err);
|
||||
LOG_DBG("Periodic sync started");
|
||||
|
||||
/* Start scanner. Check that we can start the scanner while it is already
|
||||
* running due to the periodic sync.
|
||||
*/
|
||||
struct bt_le_scan_param scan_params = {
|
||||
.type = BT_LE_SCAN_TYPE_ACTIVE,
|
||||
.options = 0x0,
|
||||
.interval = 123,
|
||||
.window = 12,
|
||||
.interval_coded = 222,
|
||||
.window_coded = 32,
|
||||
};
|
||||
|
||||
err = bt_le_scan_start(&scan_params, device_found);
|
||||
TEST_ASSERT(!err, "Scanner setup failed (err %d)\n", err);
|
||||
LOG_DBG("Explicit scanner started");
|
||||
|
||||
LOG_DBG("Wait for an advertising report");
|
||||
WAIT_FOR_FLAG(flag_adv_report_received);
|
||||
|
||||
/* Stop the scanner. That should not affect the periodic advertising sync. */
|
||||
err = bt_le_scan_stop();
|
||||
TEST_ASSERT(!err, "Scanner stop failed (err %d)\n", err);
|
||||
LOG_DBG("Explicit scanner stopped");
|
||||
|
||||
/* We should be able to stop the periodic advertising sync. */
|
||||
err = bt_le_per_adv_sync_delete(p_per_sync);
|
||||
TEST_ASSERT(!err, "Periodic sync stop failed (err %d)\n", err);
|
||||
LOG_DBG("Periodic sync stopped");
|
||||
|
||||
/* Start the periodic advertising sync. This time, provide the address of the advertiser
|
||||
* which it should connect to.
|
||||
*/
|
||||
per_sync_param = (struct bt_le_per_adv_sync_param) {
|
||||
.addr = adv_addr,
|
||||
.options = 0x0,
|
||||
.sid = 0x0,
|
||||
.skip = 0x0,
|
||||
.timeout = BT_GAP_PER_ADV_MAX_TIMEOUT
|
||||
};
|
||||
err = bt_le_per_adv_sync_create(&per_sync_param, &p_per_sync);
|
||||
TEST_ASSERT(!err, "Periodic sync setup failed (err %d)\n", err);
|
||||
LOG_DBG("Periodic sync started");
|
||||
|
||||
/* Start the explicit scanner */
|
||||
err = bt_le_scan_start(&scan_params, device_found);
|
||||
TEST_ASSERT(!err, "Scanner setup failed (err %d)\n", err);
|
||||
LOG_DBG("Explicit scanner started");
|
||||
|
||||
/* Stop the explicit scanner. This should not stop scanner, since we still try to establish
|
||||
* a sync.
|
||||
*/
|
||||
err = bt_le_scan_stop();
|
||||
TEST_ASSERT(!err, "Scanner stop failed (err %d)\n", err);
|
||||
LOG_DBG("Explicit scanner stopped");
|
||||
|
||||
/* Signal to the tester to start the periodic adv. */
|
||||
bk_sync_send();
|
||||
|
||||
/* Validate that we can still establish a sync */
|
||||
LOG_DBG("Wait for sync to periodic adv");
|
||||
WAIT_FOR_FLAG(flag_periodic_sync_established);
|
||||
|
||||
/* Signal to the tester to end the test. */
|
||||
bk_sync_send();
|
||||
|
||||
TEST_PASS("Test passed (DUT)\n");
|
||||
}
|
||||
|
||||
void run_tester(void)
|
||||
{
|
||||
LOG_DBG("start");
|
||||
bk_sync_init();
|
||||
|
||||
int err;
|
||||
|
||||
LOG_DBG("Starting DUT");
|
||||
|
||||
err = bt_enable(NULL);
|
||||
TEST_ASSERT(!err, "Bluetooth init failed (err %d)\n", err);
|
||||
|
||||
LOG_DBG("Bluetooth initialised");
|
||||
|
||||
struct bt_le_ext_adv *per_adv;
|
||||
|
||||
struct bt_le_adv_param adv_param = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_EXT_ADV,
|
||||
BT_GAP_ADV_FAST_INT_MIN_2,
|
||||
BT_GAP_ADV_FAST_INT_MAX_2,
|
||||
NULL);
|
||||
|
||||
err = bt_le_ext_adv_create(&adv_param, NULL, &per_adv);
|
||||
TEST_ASSERT(!err, "Failed to create advertising set: %d", err);
|
||||
LOG_DBG("Created extended advertising set.");
|
||||
|
||||
err = bt_le_ext_adv_start(per_adv, BT_LE_EXT_ADV_START_DEFAULT);
|
||||
TEST_ASSERT(!err, "Failed to start extended advertising: %d", err);
|
||||
LOG_DBG("Started extended advertising.");
|
||||
|
||||
/* Wait for the DUT before starting the periodic advertising */
|
||||
bk_sync_wait();
|
||||
err = bt_le_per_adv_set_param(per_adv, BT_LE_PER_ADV_DEFAULT);
|
||||
TEST_ASSERT(!err, "Failed to set periodic advertising parameters: %d", err);
|
||||
LOG_DBG("Periodic advertising parameters set.");
|
||||
|
||||
err = bt_le_per_adv_start(per_adv);
|
||||
TEST_ASSERT(!err, "Failed to start periodic advertising: %d", err);
|
||||
LOG_DBG("Periodic advertising started.");
|
||||
|
||||
/* Wait for the signal from the DUT before finishing the test */
|
||||
bk_sync_wait();
|
||||
|
||||
bt_le_per_adv_stop(per_adv);
|
||||
|
||||
TEST_PASS("Test passed (Tester)\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_def[] = {
|
||||
{
|
||||
.test_id = "scanner",
|
||||
.test_descr = "SCANNER",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = run_dut,
|
||||
},
|
||||
{
|
||||
.test_id = "periodic_adv",
|
||||
.test_descr = "PER_ADV",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = run_tester,
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_scan_start_stop_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_def);
|
||||
}
|
||||
|
||||
bst_test_install_t test_installers[] = {test_scan_start_stop_install, NULL};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bst_main();
|
||||
return 0;
|
||||
}
|
22
tests/bsim/bluetooth/host/scan/start_stop/test_scripts/start_stop.sh
Executable file
22
tests/bsim/bluetooth/host/scan/start_stop/test_scripts/start_stop.sh
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
|
||||
|
||||
test_exe="bs_${BOARD_TS}_tests_bsim_bluetooth_host_scan_start_stop_prj_conf"
|
||||
simulation_id="start_stop"
|
||||
verbosity_level=2
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute "./${test_exe}" \
|
||||
-v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=scanner
|
||||
|
||||
Execute "./${test_exe}" \
|
||||
-v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=periodic_adv
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}" \
|
||||
-D=2 -sim_length=5e6
|
||||
|
||||
wait_for_background_jobs
|
Loading…
Add table
Add a link
Reference in a new issue