diff --git a/samples/bluetooth/fast_pair/locator_tag/include/app_fp_adv.h b/samples/bluetooth/fast_pair/locator_tag/include/app_fp_adv.h index a770baeeb871..b0fd0bae5928 100644 --- a/samples/bluetooth/fast_pair/locator_tag/include/app_fp_adv.h +++ b/samples/bluetooth/fast_pair/locator_tag/include/app_fp_adv.h @@ -108,6 +108,37 @@ int app_fp_adv_id_set(uint8_t id); */ uint8_t app_fp_adv_id_get(void); +/** Fast Pair advertising information callback descriptor. */ +struct app_fp_adv_info_cb { + /** Notify that the advertising state has changed. + * + * This information callback is used to track the state of the Fast Pair advertising set. + * The current state can be used to signal the application mode in the user interface + * (for example, on LEDs). + * + * @param enable True: Fast Pair advertising is enabled. + * False: Fast Pair advertising is disabled. + */ + void (*state_changed)(bool enabled); +}; + +/** Register Fast Pair advertising information callbacks. + * + * This function registers an instance of information callbacks. The registered instance needs to + * persist in the memory after this function exits, as it is used directly without the copy + * operation. It is possible to register only one instance of callbacks with this API. + * + * This function can only be called before enabling Fast Pair with the @ref app_fp_adv_enable + * API. + * + * This function must be called in the cooperative thread context. + * + * @param cb Callback struct. + * + * @return Zero on success or negative error code otherwise + */ +int app_fp_adv_info_cb_register(const struct app_fp_adv_info_cb *cb); + /** Initialize the Fast Pair advertising module. * * @return 0 if the operation was successful. Otherwise, a (negative) error code is returned. diff --git a/samples/bluetooth/fast_pair/locator_tag/src/fp_adv.c b/samples/bluetooth/fast_pair/locator_tag/src/fp_adv.c index ac948ce77d2f..d97e62ed9788 100644 --- a/samples/bluetooth/fast_pair/locator_tag/src/fp_adv.c +++ b/samples/bluetooth/fast_pair/locator_tag/src/fp_adv.c @@ -17,7 +17,6 @@ #include #include "app_fp_adv.h" -#include "app_ui.h" #include LOG_MODULE_DECLARE(fp_fmdn, LOG_LEVEL_INF); @@ -39,6 +38,7 @@ static bool fmdn_provisioned; static struct bt_conn *fp_conn; static struct bt_le_ext_adv *fp_adv_set; +static bool fp_adv_set_active; static bool fp_adv_rpa_rotation_suspended; static enum app_fp_adv_mode fp_adv_mode = APP_FP_ADV_MODE_OFF; static uint32_t fp_adv_request_bm; @@ -62,6 +62,35 @@ static void fp_adv_restart_work_handle(struct k_work *w); static K_WORK_DEFINE(fp_adv_restart_work, fp_adv_restart_work_handle); +/* Reference to the Fast Pair advertising information callback structure. */ +static const struct app_fp_adv_info_cb *fast_pair_adv_info_cb; + +static void fp_adv_state_changed_notify(bool enabled) +{ + if (fast_pair_adv_info_cb && fast_pair_adv_info_cb->state_changed) { + fast_pair_adv_info_cb->state_changed(enabled); + } +} + +int app_fp_adv_info_cb_register(const struct app_fp_adv_info_cb *cb) +{ + if (app_fp_adv_is_ready()) { + return -EACCES; + } + + if (!cb) { + return -EINVAL; + } + + if (fast_pair_adv_info_cb) { + return -EALREADY; + } + + fast_pair_adv_info_cb = cb; + + return 0; +} + static uint16_t fp_adv_rpa_timeout_calculate(void) { int err; @@ -178,18 +207,58 @@ static int fp_adv_payload_set(bool rpa_rotated, bool new_session) return 0; } -static int bt_stack_advertising_update(void) +static int bt_stack_advertising_start(void) { int err; struct bt_le_ext_adv_start_param ext_adv_start_param = {0}; __ASSERT(fp_adv_set, "Fast Pair: invalid state of the advertising set"); + + if (fp_adv_set_active) { + return 0; + } + + err = bt_le_ext_adv_start(fp_adv_set, &ext_adv_start_param); + if (err) { + LOG_ERR("Fast Pair: bt_le_ext_adv_start returned error: %d", err); + return err; + } + + fp_adv_set_active = true; + + return 0; +} + +static int bt_stack_advertising_stop(void) +{ + int err; + + __ASSERT(fp_adv_set, "Fast Pair: invalid state of the advertising set"); + + if (!fp_adv_set_active) { + return 0; + } + + err = bt_le_ext_adv_stop(fp_adv_set); + if (err) { + LOG_ERR("Fast Pair: cannot stop advertising (err: %d)", err); + return err; + } + + fp_adv_set_active = false; + + return 0; +} + +static int bt_stack_advertising_update(void) +{ + int err; + __ASSERT(!fp_conn, "Fast Pair: invalid connection state"); if (fp_adv_mode == APP_FP_ADV_MODE_OFF) { - err = bt_le_ext_adv_stop(fp_adv_set); + err = bt_stack_advertising_stop(); if (err) { - LOG_ERR("Fast Pair: cannot stop advertising (err: %d)", err); return err; } } else { @@ -199,9 +268,8 @@ static int bt_stack_advertising_update(void) return err; } - err = bt_le_ext_adv_start(fp_adv_set, &ext_adv_start_param); + err = bt_stack_advertising_start(); if (err) { - LOG_ERR("Fast Pair: bt_le_ext_adv_start returned error: %d", err); return err; } } @@ -212,26 +280,27 @@ static int bt_stack_advertising_update(void) static void fp_advertising_update(void) { int err; + bool fp_adv_set_was_active = fp_adv_set_active; err = bt_stack_advertising_update(); if (!err) { - app_ui_state_change_indicate(APP_UI_STATE_FP_ADV, - (fp_adv_mode != APP_FP_ADV_MODE_OFF)); - LOG_INF("Fast Pair: advertising in the %s mode", fp_adv_mode_description[fp_adv_mode]); } else { - app_ui_state_change_indicate(APP_UI_STATE_FP_ADV, false); - LOG_ERR("Fast Pair: advertising failed to start (err %d)", err); } + + if (fp_adv_set_was_active != fp_adv_set_active) { + fp_adv_state_changed_notify(fp_adv_set_active); + } } static void fp_adv_connected(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_connected_info *info) { __ASSERT_NO_MSG(!fp_conn); - app_ui_state_change_indicate(APP_UI_STATE_FP_ADV, false); + fp_adv_set_active = false; + fp_adv_state_changed_notify(fp_adv_set_active); fp_conn = info->conn; } diff --git a/samples/bluetooth/fast_pair/locator_tag/src/main.c b/samples/bluetooth/fast_pair/locator_tag/src/main.c index 3ee44b1255a8..6d37c5c770ea 100644 --- a/samples/bluetooth/fast_pair/locator_tag/src/main.c +++ b/samples/bluetooth/fast_pair/locator_tag/src/main.c @@ -422,6 +422,15 @@ static struct bt_fast_pair_fmdn_info_cb fmdn_info_cb = { .provisioning_state_changed = fmdn_provisioning_state_changed, }; +static void fp_adv_state_changed(bool enabled) +{ + app_ui_state_change_indicate(APP_UI_STATE_FP_ADV, enabled); +} + +static const struct app_fp_adv_info_cb fp_adv_info_cb = { + .state_changed = fp_adv_state_changed, +}; + static int fast_pair_prepare(void) { int err; @@ -438,6 +447,12 @@ static int fast_pair_prepare(void) return err; } + err = app_fp_adv_info_cb_register(&fp_adv_info_cb); + if (err) { + LOG_ERR("Fast Pair: app_fp_adv_info_cb_register failed (err %d)", err); + return err; + } + return 0; }