2121#include <zephyr/logging/log.h>
2222LOG_MODULE_DECLARE (fp_fmdn , LOG_LEVEL_INF );
2323
24+ /* RPA suspension timeout in minutes for the Fast Pair advertising set
25+ * as recommended by the FMDN specification.
26+ */
27+ #define FP_ADV_RPA_SUSPENSION_TIMEOUT (5)
28+
2429/* Fast Pair advertising interval 100ms. */
2530#define FP_ADV_INTERVAL (0x00A0)
2631
@@ -35,6 +40,7 @@ static bool is_initialized;
3540static bool is_enabled ;
3641
3742static bool fmdn_provisioned ;
43+ static bool fp_account_key_present ;
3844
3945static struct bt_conn * fp_conn ;
4046static struct bt_le_ext_adv * fp_adv_set ;
@@ -59,8 +65,28 @@ static struct bt_le_adv_param fp_adv_param = {
5965};
6066
6167static void fp_adv_restart_work_handle (struct k_work * w );
68+ static void fp_adv_rpa_suspension_work_handle (struct k_work * w );
6269
6370static K_WORK_DEFINE (fp_adv_restart_work , fp_adv_restart_work_handle ) ;
71+ static K_WORK_DELAYABLE_DEFINE (fp_adv_rpa_suspension_work , fp_adv_rpa_suspension_work_handle ) ;
72+
73+ static void fp_adv_rpa_rotation_suspended_set (bool suspended )
74+ {
75+ fp_adv_rpa_rotation_suspended = suspended ;
76+
77+ LOG_DBG ("Fast Pair: set RPA rotation suspended to %s" , suspended ? "true" : "false" );
78+ }
79+
80+ static void fp_adv_rpa_suspension_work_handle (struct k_work * w )
81+ {
82+ fp_adv_rpa_rotation_suspended_set (false);
83+ }
84+
85+ static void fp_adv_rpa_suspension_cancel (void )
86+ {
87+ (void ) k_work_cancel_delayable (& fp_adv_rpa_suspension_work );
88+ fp_adv_rpa_rotation_suspended_set (false);
89+ }
6490
6591/* Reference to the Fast Pair advertising information callback structure. */
6692static const struct app_fp_adv_info_cb * fast_pair_adv_info_cb ;
@@ -469,26 +495,52 @@ BT_CONN_CB_DEFINE(conn_callbacks) = {
469495
470496static void fp_adv_provisioning_state_changed (bool provisioned )
471497{
472- struct bt_le_oob oob ;
473- int err ;
474-
475498 fmdn_provisioned = provisioned ;
476499
500+ if (!app_fp_adv_is_ready ()) {
501+ return ;
502+ }
503+
477504 if (!provisioned ) {
505+ int err ;
506+ struct bt_le_oob oob ;
507+
478508 /* Force the RPA rotation to synchronize the Fast Pair advertising
479- * payload with its RPA address using rpa_expired callback.
480- */
509+ * payload with its RPA address using rpa_expired callback.
510+ */
481511 err = bt_le_oob_get_local (fp_adv_param .id , & oob );
482512 if (err ) {
483513 LOG_ERR ("Fast Pair: bt_le_oob_get_local failed: %d" , err );
484514 }
515+ } else {
516+ fp_adv_rpa_suspension_cancel ();
485517 }
486518}
487519
488520static struct bt_fast_pair_fmdn_info_cb fmdn_info_cb = {
489521 .provisioning_state_changed = fp_adv_provisioning_state_changed ,
490522};
491523
524+ static void fp_adv_account_key_written (struct bt_conn * conn )
525+ {
526+ /* The first and only Account Key write starts the FMDN provisioning. */
527+ if (!fmdn_provisioned && !fp_account_key_present && app_fp_adv_is_ready ()) {
528+ /* Fast Pair Implementation Guidelines for the locator tag use case:
529+ * after the Provider was paired, it should not change its MAC address
530+ * till FMDN is provisioned or till 5 minutes passes.
531+ */
532+ fp_adv_rpa_rotation_suspended_set (true);
533+ (void ) k_work_schedule (& fp_adv_rpa_suspension_work ,
534+ K_MINUTES (FP_ADV_RPA_SUSPENSION_TIMEOUT ));
535+ }
536+
537+ fp_account_key_present = bt_fast_pair_has_account_key ();
538+ }
539+
540+ static struct bt_fast_pair_info_cb fp_info_callbacks = {
541+ .account_key_written = fp_adv_account_key_written ,
542+ };
543+
492544enum app_fp_adv_mode app_fp_adv_mode_get (void )
493545{
494546 return fp_adv_mode ;
@@ -528,12 +580,11 @@ static void fp_adv_mode_set(enum app_fp_adv_mode adv_mode)
528580
529581static void fp_adv_mode_update (void )
530582{
531- bool has_account_key = bt_fast_pair_has_account_key ();
532583 bool is_any_request_enabled = (fp_adv_request_bm != 0 );
533584 enum app_fp_adv_mode requested_mode ;
534585
535586 if (is_any_request_enabled ) {
536- requested_mode = has_account_key ?
587+ requested_mode = fp_account_key_present ?
537588 APP_FP_ADV_MODE_NOT_DISCOVERABLE :
538589 APP_FP_ADV_MODE_DISCOVERABLE ;
539590 } else {
@@ -581,11 +632,6 @@ void app_fp_adv_payload_refresh(void)
581632 }
582633}
583634
584- void app_fp_adv_rpa_rotation_suspend (bool suspended )
585- {
586- fp_adv_rpa_rotation_suspended = suspended ;
587- }
588-
589635int app_fp_adv_id_set (uint8_t id )
590636{
591637 if (app_fp_adv_is_ready ()) {
@@ -616,6 +662,12 @@ int app_fp_adv_init(void)
616662 return err ;
617663 }
618664
665+ err = bt_fast_pair_info_cb_register (& fp_info_callbacks );
666+ if (err ) {
667+ LOG_ERR ("Fast Pair: bt_fast_pair_info_cb_register failed (err %d)" , err );
668+ return err ;
669+ }
670+
619671 STRUCT_SECTION_COUNT (app_fp_adv_trigger , & trigger_cnt );
620672 __ASSERT_NO_MSG (trigger_cnt <= BITS_PER_VAR (fp_adv_request_bm ));
621673
@@ -642,6 +694,8 @@ int app_fp_adv_enable(void)
642694 return err ;
643695 }
644696
697+ fp_account_key_present = bt_fast_pair_has_account_key ();
698+
645699 fp_adv_mode_update ();
646700
647701 is_enabled = true;
@@ -664,6 +718,9 @@ int app_fp_adv_disable(void)
664718
665719 is_enabled = false;
666720
721+ /* Reset the RPA suspension. */
722+ fp_adv_rpa_suspension_cancel ();
723+
667724 /* Suspend the requested advertising until the fp_adv module reinitializes. */
668725 fp_adv_mode_set (APP_FP_ADV_MODE_OFF );
669726
0 commit comments