@@ -175,10 +175,21 @@ static void sc_ccc_cfg_changed(const struct bt_gatt_attr *attr,
175
175
BT_DBG ("value 0x%04x" , value );
176
176
}
177
177
178
+ enum {
179
+ CF_CHANGE_AWARE , /* Client is changed aware */
180
+ CF_OUT_OF_SYNC , /* Client is out of sync */
181
+
182
+ /* Total number of flags - must be at the end of the enum */
183
+ CF_NUM_FLAGS ,
184
+ };
185
+
186
+ #define CF_ROBUST_CACHING (_cfg ) (_cfg->data[0] & BIT(0))
187
+
178
188
struct gatt_cf_cfg {
179
189
u8_t id ;
180
190
bt_addr_le_t peer ;
181
191
u8_t data [1 ];
192
+ ATOMIC_DEFINE (flags , CF_NUM_FLAGS );
182
193
};
183
194
184
195
#if defined(CONFIG_BT_GATT_CACHING )
@@ -216,13 +227,15 @@ static ssize_t cf_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
216
227
static bool cf_set_value (struct gatt_cf_cfg * cfg , const u8_t * value , u16_t len )
217
228
{
218
229
u16_t i ;
230
+ u8_t last_byte = 1 ;
231
+ u8_t last_bit = 1 ;
219
232
220
233
/* Validate the bits */
221
- for (i = 0 ; i < len ; i ++ ) {
234
+ for (i = 0 ; i < len && i < last_byte ; i ++ ) {
222
235
u8_t chg_bits = value [i ] ^ cfg -> data [i ];
223
236
u8_t bit ;
224
237
225
- for (bit = 0 ; bit < 8 ; bit ++ ) {
238
+ for (bit = 0 ; bit < last_bit ; bit ++ ) {
226
239
/* A client shall never clear a bit it has set */
227
240
if ((BIT (bit ) & chg_bits ) &&
228
241
(BIT (bit ) & cfg -> data [i ])) {
@@ -232,8 +245,8 @@ static bool cf_set_value(struct gatt_cf_cfg *cfg, const u8_t *value, u16_t len)
232
245
}
233
246
234
247
/* Set the bits for each octect */
235
- for (i = 0 ; i < len ; i ++ ) {
236
- cfg -> data [i ] |= value [i ];
248
+ for (i = 0 ; i < len && i < last_byte ; i ++ ) {
249
+ cfg -> data [i ] |= value [i ] & (( 1 << last_bit ) - 1 ) ;
237
250
BT_DBG ("byte %u: data 0x%02x value 0x%02x" , i , cfg -> data [i ],
238
251
value [i ]);
239
252
}
@@ -272,6 +285,7 @@ static ssize_t cf_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
272
285
}
273
286
274
287
bt_addr_le_copy (& cfg -> peer , & conn -> le .dst );
288
+ atomic_set_bit (cfg -> flags , CF_CHANGE_AWARE );
275
289
276
290
return len ;
277
291
}
@@ -396,6 +410,14 @@ static ssize_t db_hash_read(struct bt_conn *conn,
396
410
db_hash_gen ();
397
411
}
398
412
413
+ /* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2347:
414
+ * 2.5.2.1 Robust Caching
415
+ * A connected client becomes change-aware when...
416
+ * The client reads the Database Hash characteristic and then the server
417
+ * receives another ATT request from the client.
418
+ */
419
+ bt_gatt_change_aware (conn , true);
420
+
399
421
return bt_gatt_attr_read (conn , attr , buf , len , offset , db_hash ,
400
422
sizeof (db_hash ));
401
423
}
@@ -485,6 +507,10 @@ static struct gatt_sc {
485
507
static void sc_indicate_rsp (struct bt_conn * conn ,
486
508
const struct bt_gatt_attr * attr , u8_t err )
487
509
{
510
+ #if defined(CONFIG_BT_GATT_CACHING )
511
+ struct gatt_cf_cfg * cfg ;
512
+ #endif
513
+
488
514
BT_DBG ("err 0x%02x" , err );
489
515
490
516
atomic_clear_bit (gatt_sc .flags , SC_INDICATE_PENDING );
@@ -494,6 +520,19 @@ static void sc_indicate_rsp(struct bt_conn *conn,
494
520
/* Reschedule without any delay since it is waiting already */
495
521
k_delayed_work_submit (& gatt_sc .work , K_NO_WAIT );
496
522
}
523
+
524
+ #if defined(CONFIG_BT_GATT_CACHING )
525
+ /* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2347:
526
+ * 2.5.2.1 Robust Caching
527
+ * A connected client becomes change-aware when...
528
+ * The client receives and confirms a Service Changed indication.
529
+ */
530
+ cfg = find_cf_cfg (& conn -> le .dst );
531
+ if (cfg && CF_ROBUST_CACHING (cfg )) {
532
+ atomic_set_bit (cfg -> flags , CF_CHANGE_AWARE );
533
+ BT_DBG ("%s change-aware" , bt_addr_le_str (& cfg -> peer ));
534
+ }
535
+ #endif
497
536
}
498
537
499
538
static void sc_process (struct k_work * work )
@@ -645,6 +684,28 @@ static void sc_indicate(struct gatt_sc *sc, uint16_t start, uint16_t end)
645
684
k_delayed_work_submit (& sc -> work , SC_TIMEOUT );
646
685
}
647
686
687
+ static void db_changed (void )
688
+ {
689
+ #if defined(CONFIG_BT_GATT_CACHING )
690
+ int i ;
691
+
692
+ k_delayed_work_submit (& db_hash_work , DB_HASH_TIMEOUT );
693
+
694
+ for (i = 0 ; i < ARRAY_SIZE (cf_cfg ); i ++ ) {
695
+ struct gatt_cf_cfg * cfg = & cf_cfg [i ];
696
+
697
+ if (!bt_addr_le_cmp (& cfg -> peer , BT_ADDR_LE_ANY )) {
698
+ continue ;
699
+ }
700
+
701
+ if (CF_ROBUST_CACHING (cfg ) &&
702
+ atomic_test_and_clear_bit (cfg -> flags , CF_CHANGE_AWARE )) {
703
+ BT_DBG ("%s change-unaware" , bt_addr_le_str (& cfg -> peer ));
704
+ }
705
+ }
706
+ #endif
707
+ }
708
+
648
709
int bt_gatt_service_register (struct bt_gatt_service * svc )
649
710
{
650
711
int err ;
@@ -670,9 +731,7 @@ int bt_gatt_service_register(struct bt_gatt_service *svc)
670
731
sc_indicate (& gatt_sc , svc -> attrs [0 ].handle ,
671
732
svc -> attrs [svc -> attr_count - 1 ].handle );
672
733
673
- #if defined(CONFIG_BT_GATT_CACHING )
674
- k_delayed_work_submit (& db_hash_work , DB_HASH_TIMEOUT );
675
- #endif /* COFNIG_BT_GATT_CACHING */
734
+ db_changed ();
676
735
677
736
return 0 ;
678
737
}
@@ -688,9 +747,7 @@ int bt_gatt_service_unregister(struct bt_gatt_service *svc)
688
747
sc_indicate (& gatt_sc , svc -> attrs [0 ].handle ,
689
748
svc -> attrs [svc -> attr_count - 1 ].handle );
690
749
691
- #if defined(CONFIG_BT_GATT_CACHING )
692
- k_delayed_work_submit (& db_hash_work , DB_HASH_TIMEOUT );
693
- #endif /* COFNIG_BT_GATT_CACHING */
750
+ db_changed ();
694
751
695
752
return 0 ;
696
753
}
@@ -2686,6 +2743,50 @@ void bt_gatt_connected(struct bt_conn *conn)
2686
2743
#endif /* CONFIG_BT_GATT_CLIENT */
2687
2744
}
2688
2745
2746
+ bool bt_gatt_change_aware (struct bt_conn * conn , bool req )
2747
+ {
2748
+ #if defined(CONFIG_BT_GATT_CACHING )
2749
+ struct gatt_cf_cfg * cfg ;
2750
+
2751
+ cfg = find_cf_cfg (& conn -> le .dst );
2752
+ if (!cfg || !CF_ROBUST_CACHING (cfg )) {
2753
+ return true;
2754
+ }
2755
+
2756
+ if (atomic_test_bit (cfg -> flags , CF_CHANGE_AWARE )) {
2757
+ return true;
2758
+ }
2759
+
2760
+ /* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2350:
2761
+ * If a change-unaware client sends an ATT command, the server shall
2762
+ * ignore it.
2763
+ */
2764
+ if (!req ) {
2765
+ return false;
2766
+ }
2767
+
2768
+ /* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2347:
2769
+ * 2.5.2.1 Robust Caching
2770
+ * A connected client becomes change-aware when...
2771
+ * The server sends the client a response with the error code set to
2772
+ * Database Out Of Sync and then the server receives another ATT
2773
+ * request from the client.
2774
+ */
2775
+ if (atomic_test_bit (cfg -> flags , CF_OUT_OF_SYNC )) {
2776
+ atomic_clear_bit (cfg -> flags , CF_OUT_OF_SYNC );
2777
+ atomic_set_bit (cfg -> flags , CF_CHANGE_AWARE );
2778
+ BT_DBG ("%s change-aware" , bt_addr_le_str (& cfg -> peer ));
2779
+ return true;
2780
+ }
2781
+
2782
+ atomic_set_bit (cfg -> flags , CF_OUT_OF_SYNC );
2783
+
2784
+ return false;
2785
+ #else
2786
+ return true;
2787
+ #endif
2788
+ }
2789
+
2689
2790
void bt_gatt_disconnected (struct bt_conn * conn )
2690
2791
{
2691
2792
BT_DBG ("conn %p" , conn );
0 commit comments