5050LOG_MODULE_REGISTER (bt_gatt );
5151
5252#define SC_TIMEOUT K_MSEC(10)
53- #define CCC_STORE_DELAY K_SECONDS(1)
54-
5553#define DB_HASH_TIMEOUT K_MSEC(10)
5654
5755static uint16_t last_static_handle ;
@@ -544,6 +542,16 @@ static void clear_cf_cfg(struct gatt_cf_cfg *cfg)
544542 atomic_set (cfg -> flags , 0 );
545543}
546544
545+ enum delayed_store_flags {
546+ DELAYED_STORE_CCC ,
547+ DELAYED_STORE_CF ,
548+ DELAYED_STORE_NUM_FLAGS
549+ };
550+
551+ #if defined(CONFIG_BT_SETTINGS_DELAYED_STORE )
552+ static void gatt_delayed_store_enqueue (struct bt_conn * conn , enum delayed_store_flags flag );
553+ #endif
554+
547555#if defined(CONFIG_BT_GATT_CACHING )
548556static struct gatt_cf_cfg * find_cf_cfg (struct bt_conn * conn )
549557{
@@ -640,6 +648,12 @@ static ssize_t cf_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
640648 cfg -> id = conn -> id ;
641649 atomic_set_bit (cfg -> flags , CF_CHANGE_AWARE );
642650
651+ #if defined(CONFIG_BT_SETTINGS_DELAYED_STORE )
652+ /* Save the new configuration to NVM (in another thread) */
653+ LOG_DBG ("trigger CF write" );
654+ gatt_delayed_store_enqueue (conn -> id , & conn -> le .dst , DELAYED_STORE_CF );
655+ #endif
656+
643657 return len ;
644658}
645659
@@ -915,7 +929,10 @@ static ssize_t sf_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
915929#endif /* CONFIG_BT_EATT */
916930#endif /* CONFIG_BT_GATT_CACHING */
917931
918- static int bt_gatt_store_cf (struct bt_conn * conn )
932+ static struct gatt_cf_cfg * find_cf_cfg_by_addr (uint8_t id ,
933+ const bt_addr_le_t * addr );
934+
935+ static int bt_gatt_store_cf (uint8_t id , const bt_addr_le_t * peer )
919936{
920937#if defined(CONFIG_BT_GATT_CACHING )
921938 struct gatt_cf_cfg * cfg ;
@@ -924,7 +941,7 @@ static int bt_gatt_store_cf(struct bt_conn *conn)
924941 size_t len ;
925942 int err ;
926943
927- cfg = find_cf_cfg ( conn );
944+ cfg = find_cf_cfg_by_addr ( id , peer );
928945 if (!cfg ) {
929946 /* No cfg found, just clear it */
930947 LOG_DBG ("No config for CF" );
@@ -934,18 +951,18 @@ static int bt_gatt_store_cf(struct bt_conn *conn)
934951 str = (char * )cfg -> data ;
935952 len = sizeof (cfg -> data );
936953
937- if (conn -> id ) {
954+ if (id ) {
938955 char id_str [4 ];
939956
940- u8_to_dec (id_str , sizeof (id_str ), conn -> id );
957+ u8_to_dec (id_str , sizeof (id_str ), id );
941958 bt_settings_encode_key (key , sizeof (key ), "cf" ,
942- & conn -> le . dst , id_str );
959+ peer , id_str );
943960 }
944961 }
945962
946- if (!cfg || !conn -> id ) {
963+ if (!cfg || !id ) {
947964 bt_settings_encode_key (key , sizeof (key ), "cf" ,
948- & conn -> le . dst , NULL );
965+ peer , NULL );
949966 }
950967
951968 err = settings_save_one (key , str , len );
@@ -954,7 +971,7 @@ static int bt_gatt_store_cf(struct bt_conn *conn)
954971 return err ;
955972 }
956973
957- LOG_DBG ("Stored CF for %s (%s)" , bt_addr_le_str (& conn -> le . dst ), key );
974+ LOG_DBG ("Stored CF for %s (%s)" , bt_addr_le_str (peer ), key );
958975#endif /* CONFIG_BT_GATT_CACHING */
959976 return 0 ;
960977
@@ -1008,7 +1025,7 @@ static void bt_gatt_identity_resolved(struct bt_conn *conn, const bt_addr_le_t *
10081025
10091026 /* Store the ccc and cf data */
10101027 bt_gatt_store_ccc (conn -> id , & (conn -> le .dst ));
1011- bt_gatt_store_cf (conn );
1028+ bt_gatt_store_cf (conn -> id , & conn -> le . dst );
10121029}
10131030#endif /* CONFIG_BT_SETTINGS && CONFIG_BT_SMP && CONFIG_BT_GATT_CLIENT */
10141031
@@ -1211,73 +1228,129 @@ static void clear_ccc_cfg(struct bt_gatt_ccc_cfg *cfg)
12111228 cfg -> value = 0U ;
12121229}
12131230
1214- #if defined(CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE )
1215- static struct gatt_ccc_store {
1216- struct bt_conn * conn_list [CONFIG_BT_MAX_CONN ];
1231+ #if defined(CONFIG_BT_SETTINGS_DELAYED_STORE )
1232+ struct ds_peer {
1233+ uint8_t id ;
1234+ bt_addr_le_t peer ;
1235+
1236+ ATOMIC_DEFINE (flags , DELAYED_STORE_NUM_FLAGS );
1237+ };
1238+
1239+ static struct gatt_delayed_store {
1240+ struct ds_peer peer_list [CONFIG_BT_MAX_PAIRED + CONFIG_BT_MAX_CONN ];
12171241 struct k_work_delayable work ;
1218- } gatt_ccc_store ;
1242+ } gatt_delayed_store ;
12191243
1220- static bool gatt_ccc_conn_is_queued (struct bt_conn * conn )
1244+ static struct ds_peer * gatt_delayed_store_find (uint8_t id ,
1245+ const bt_addr_le_t * peer_addr )
12211246{
1222- return (conn == gatt_ccc_store .conn_list [bt_conn_index (conn )]);
1247+ struct ds_peer * el ;
1248+
1249+ for (size_t i = 0 ; i < ARRAY_SIZE (gatt_delayed_store .peer_list ); i ++ ) {
1250+ el = & gatt_delayed_store .peer_list [i ];
1251+ if (el -> id == id &&
1252+ bt_addr_le_eq (peer_addr , & el -> peer )) {
1253+ return el ;
1254+ }
1255+ }
1256+
1257+ return NULL ;
12231258}
12241259
1225- static void gatt_ccc_conn_unqueue (struct bt_conn * conn )
1260+ static struct ds_peer * gatt_delayed_store_alloc (uint8_t id ,
1261+ const bt_addr_le_t * peer_addr )
12261262{
1227- uint8_t index = bt_conn_index (conn );
1263+ struct ds_peer * el ;
1264+
1265+ for (size_t i = 0 ; i < ARRAY_SIZE (gatt_delayed_store .peer_list ); i ++ ) {
1266+ el = & gatt_delayed_store .peer_list [i ];
12281267
1229- if (gatt_ccc_store .conn_list [index ] != NULL ) {
1230- bt_conn_unref (gatt_ccc_store .conn_list [index ]);
1231- gatt_ccc_store .conn_list [index ] = NULL ;
1268+ /* Checking for the flags is cheaper than a memcmp for the
1269+ * address, so we use that to signal that a given slot is
1270+ * free.
1271+ */
1272+ if (atomic_get (el -> flags ) == 0 ) {
1273+ bt_addr_le_copy (& el -> peer , peer_addr );
1274+ el -> id = id ;
1275+
1276+ return el ;
1277+ }
12321278 }
1279+
1280+ return NULL ;
12331281}
12341282
1235- static void gatt_ccc_conn_enqueue (struct bt_conn * conn )
1283+ static void gatt_delayed_store_free (struct ds_peer * el )
12361284{
1237- if ((!gatt_ccc_conn_is_queued (conn )) &&
1238- bt_addr_le_is_bonded (conn -> id , & conn -> le .dst )) {
1239- /* Store the connection with the same index it has in
1240- * the conns array
1241- */
1242- gatt_ccc_store .conn_list [bt_conn_index (conn )] =
1243- bt_conn_ref (conn );
1285+ if (el ) {
1286+ el -> id = 0 ;
1287+ memset (& el -> peer , 0 , sizeof (el -> peer ));
1288+ atomic_set (el -> flags , 0 );
1289+ }
1290+ }
1291+
1292+ static void gatt_delayed_store_enqueue (uint8_t id , const bt_addr_le_t * peer_addr ,
1293+ enum delayed_store_flags flag )
1294+ {
1295+ bool bonded = bt_addr_le_is_bonded (id , peer_addr );
1296+ struct ds_peer * el = gatt_delayed_store_find (id , peer_addr );
1297+
1298+ if (bonded ) {
1299+ if (el == NULL ) {
1300+ el = gatt_delayed_store_alloc (id , peer_addr );
1301+ __ASSERT (el != NULL , "Can't save CF / CCC to flash" );
1302+ }
1303+
1304+ atomic_set_bit (el -> flags , flag );
12441305
1245- k_work_reschedule (& gatt_ccc_store .work , CCC_STORE_DELAY );
1306+ k_work_reschedule (& gatt_delayed_store .work ,
1307+ K_MSEC (CONFIG_BT_SETTINGS_DELAYED_STORE_MS ));
12461308 }
12471309}
12481310
1249- static bool gatt_ccc_conn_queue_is_empty (void )
1311+ static bool gatt_delayed_work_queue_is_empty (void )
12501312{
1251- for (size_t i = 0 ; i < CONFIG_BT_MAX_CONN ; i ++ ) {
1252- if (gatt_ccc_store .conn_list [i ]) {
1313+ for (size_t i = 0 ; i < ARRAY_SIZE (gatt_delayed_store .peer_list ); i ++ ) {
1314+ /* Checking for the flags is cheaper than a memcmp for the
1315+ * address, so we use that to signal that a given slot is
1316+ * free.
1317+ */
1318+ if (atomic_get (gatt_delayed_store .peer_list [i ].flags ) != 0 ) {
12531319 return false;
12541320 }
12551321 }
12561322
12571323 return true;
12581324}
12591325
1260- static void ccc_delayed_store (struct k_work * work )
1326+ static void delayed_store (struct k_work * work )
12611327{
1328+ struct ds_peer * el ;
12621329 struct k_work_delayable * dwork = k_work_delayable_from_work (work );
1263- struct gatt_ccc_store * ccc_store =
1264- CONTAINER_OF (dwork , struct gatt_ccc_store , work );
1330+ struct gatt_delayed_store * store =
1331+ CONTAINER_OF (dwork , struct gatt_delayed_store , work );
12651332
1266- for (size_t i = 0 ; i < CONFIG_BT_MAX_CONN ; i ++ ) {
1267- struct bt_conn * conn = ccc_store -> conn_list [i ];
1333+ for (size_t i = 0 ; i < ARRAY_SIZE ( gatt_delayed_store . peer_list ) ; i ++ ) {
1334+ el = & store -> peer_list [i ];
12681335
1269- if (!conn ) {
1270- continue ;
1271- }
1336+ if (bt_addr_le_is_bonded (el -> id , & el -> peer )) {
1337+ if (IS_ENABLED (CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE ) &&
1338+ atomic_test_and_clear_bit (el -> flags , DELAYED_STORE_CCC )) {
1339+ bt_gatt_store_ccc (el -> id , & el -> peer );
1340+ }
12721341
1273- if (bt_addr_le_is_bonded (conn -> id , & conn -> le .dst )) {
1274- ccc_store -> conn_list [i ] = NULL ;
1275- bt_gatt_store_ccc (conn -> id , & conn -> le .dst );
1276- bt_conn_unref (conn );
1342+ if (IS_ENABLED (CONFIG_BT_SETTINGS_CF_STORE_ON_WRITE ) &&
1343+ atomic_test_and_clear_bit (el -> flags , DELAYED_STORE_CF )) {
1344+ bt_gatt_store_cf (el -> id , & el -> peer );
1345+ }
1346+
1347+ if (atomic_get (el -> flags ) == 0 ) {
1348+ gatt_delayed_store_free (el );
1349+ }
12771350 }
12781351 }
12791352}
1280- #endif
1353+ #endif /* CONFIG_BT_SETTINGS_DELAYED_STORE */
12811354
12821355static void bt_gatt_service_init (void )
12831356{
@@ -1323,8 +1396,8 @@ void bt_gatt_init(void)
13231396 }
13241397#endif /* defined(CONFIG_BT_GATT_SERVICE_CHANGED) */
13251398
1326- #if defined(CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE )
1327- k_work_init_delayable (& gatt_ccc_store .work , ccc_delayed_store );
1399+ #if defined(CONFIG_BT_SETTINGS_DELAYED_STORE )
1400+ k_work_init_delayable (& gatt_delayed_store .work , delayed_store );
13281401#endif
13291402
13301403#if defined(CONFIG_BT_GATT_CLIENT ) && defined(CONFIG_BT_SETTINGS ) && defined(CONFIG_BT_SMP )
@@ -1431,7 +1504,9 @@ static void gatt_unregister_ccc(struct _bt_gatt_ccc *ccc)
14311504 if (conn ) {
14321505 if (conn -> state == BT_CONN_CONNECTED ) {
14331506#if defined(CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE )
1434- gatt_ccc_conn_enqueue (conn );
1507+ gatt_delayed_store_enqueue (conn -> id ,
1508+ & conn -> le .dst ,
1509+ DELAYED_STORE_CCC );
14351510#endif
14361511 store = false;
14371512 }
@@ -1998,7 +2073,7 @@ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn,
19982073 if (value_changed ) {
19992074#if defined(CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE )
20002075 /* Enqueue CCC store if value has changed for the connection */
2001- gatt_ccc_conn_enqueue (conn );
2076+ gatt_delayed_store_enqueue (conn -> id , & conn -> le . dst , DELAYED_STORE_CCC );
20022077#endif
20032078 }
20042079
@@ -6067,18 +6142,20 @@ void bt_gatt_disconnected(struct bt_conn *conn)
60676142 cleanup_notify (conn );
60686143#endif /* CONFIG_BT_GATT_NOTIFY_MULTIPLE */
60696144
6070- #if defined(CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE )
6071- gatt_ccc_conn_unqueue (conn );
6145+ #if defined(CONFIG_BT_SETTINGS_DELAYED_STORE )
6146+ struct ds_peer * el = gatt_delayed_store_find (conn -> id , & conn -> le .dst );
6147+
6148+ gatt_delayed_store_free (el );
60726149
6073- if (gatt_ccc_conn_queue_is_empty ()) {
6074- k_work_cancel_delayable (& gatt_ccc_store .work );
6150+ if (gatt_delayed_work_queue_is_empty ()) {
6151+ k_work_cancel_delayable (& gatt_delayed_store .work );
60756152 }
60766153#endif
60776154
60786155 if (IS_ENABLED (CONFIG_BT_SETTINGS ) &&
60796156 bt_addr_le_is_bonded (conn -> id , & conn -> le .dst )) {
60806157 bt_gatt_store_ccc (conn -> id , & conn -> le .dst );
6081- bt_gatt_store_cf (conn );
6158+ bt_gatt_store_cf (conn -> id , & conn -> le . dst );
60826159 }
60836160
60846161 /* Make sure to clear the CCC entry when using lazy loading */
0 commit comments