@@ -31,11 +31,81 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
3131#define BT_UUID_DIS_MFR_NAME BT_UUID_DECLARE_16(BT_UUID_DIS_MFR_NAME_VAL)
3232
3333/* Device Information client state */
34- static ble_dis_info_t device_info ;
34+ static ble_dis_info_t device_info ; /* Active device's DIS info */
3535static bool dis_ready = false;
3636static struct bt_conn * current_conn = NULL ;
3737static struct bt_gatt_read_params read_params ;
3838
39+ /* In-memory cache for all bonded devices' DIS info (loaded from flash at boot) */
40+ #define MAX_DIS_CACHE_ENTRIES 4
41+ struct dis_cache_entry {
42+ bt_addr_le_t addr ;
43+ ble_dis_info_t info ;
44+ bool valid ;
45+ };
46+ static struct dis_cache_entry dis_cache [MAX_DIS_CACHE_ENTRIES ];
47+
48+ /* Mutex to protect dis_cache from concurrent access */
49+ static K_MUTEX_DEFINE (dis_cache_mutex );
50+
51+ /* Forward declarations needed by work handler */
52+ static void build_dis_settings_key (const bt_addr_le_t * addr , char * key , size_t key_len );
53+ int ble_dis_load_info_for_addr (const bt_addr_le_t * addr , ble_dis_info_t * out_info );
54+
55+ /* Work queue item for deferred flash writes */
56+ static struct k_work clear_fw_cache_work ;
57+ static bool clear_fw_cache_pending = false;
58+
59+ static void clear_fw_cache_work_handler (struct k_work * work )
60+ {
61+ ARG_UNUSED (work );
62+
63+ LOG_INF ("Clearing cached firmware version for all bonded devices (deferred)" );
64+
65+ /* Get list of bonded devices from ble_central */
66+ extern int ble_central_get_bonded_devices (struct bonded_device * out_list , size_t max_count );
67+
68+ struct bonded_device bonds [4 ];
69+ int count = ble_central_get_bonded_devices (bonds , 4 );
70+
71+ if (count <= 0 ) {
72+ LOG_DBG ("No bonded devices to clear firmware from" );
73+ clear_fw_cache_pending = false;
74+ return ;
75+ }
76+
77+ /* Clear firmware version for each bonded device */
78+ for (int i = 0 ; i < count ; i ++ ) {
79+ if (bonds [i ].is_valid ) {
80+ /* Load existing DIS info */
81+ ble_dis_info_t dis_info ;
82+ int err = ble_dis_load_info_for_addr (& bonds [i ].addr , & dis_info );
83+ if (err != 0 ) {
84+ continue ;
85+ }
86+
87+ /* Clear only the firmware version field */
88+ dis_info .has_firmware_version = false;
89+ dis_info .firmware_version [0 ] = '\0' ;
90+
91+ /* Save back to flash storage */
92+ char key [64 ];
93+ build_dis_settings_key (& bonds [i ].addr , key , sizeof (key ));
94+ err = settings_save_one (key , & dis_info , sizeof (ble_dis_info_t ));
95+ if (err ) {
96+ LOG_ERR ("Failed to save DIS info after clearing firmware (err %d)" , err );
97+ } else {
98+ char addr_str [BT_ADDR_LE_STR_LEN ];
99+ bt_addr_le_to_str (& bonds [i ].addr , addr_str , sizeof (addr_str ));
100+ LOG_INF ("Cleared cached firmware in flash for: %s" , addr_str );
101+ }
102+ }
103+ }
104+
105+ clear_fw_cache_pending = false;
106+ LOG_INF ("Cleared cached firmware for %d device(s) in flash" , count );
107+ }
108+
39109/* Characteristic handles */
40110static uint16_t fw_rev_handle = 0 ;
41111static uint16_t hw_rev_handle = 0 ;
@@ -101,21 +171,65 @@ static int save_dis_info_to_settings(const bt_addr_le_t *addr)
101171 }
102172
103173 LOG_INF ("Saved DIS info to persistent storage: %s" , key );
174+
175+ /* Also update in-memory cache (protected by mutex) */
176+ k_mutex_lock (& dis_cache_mutex , K_FOREVER );
177+ bool found = false;
178+ for (int i = 0 ; i < MAX_DIS_CACHE_ENTRIES ; i ++ ) {
179+ if (dis_cache [i ].valid && bt_addr_le_cmp (& dis_cache [i ].addr , addr ) == 0 ) {
180+ /* Update existing entry */
181+ memcpy (& dis_cache [i ].info , & device_info , sizeof (ble_dis_info_t ));
182+ LOG_DBG ("Updated in-memory cache entry %d" , i );
183+ found = true;
184+ break ;
185+ }
186+ }
187+
188+ /* If not found, add new entry */
189+ if (!found ) {
190+ for (int i = 0 ; i < MAX_DIS_CACHE_ENTRIES ; i ++ ) {
191+ if (!dis_cache [i ].valid ) {
192+ memcpy (& dis_cache [i ].addr , addr , sizeof (bt_addr_le_t ));
193+ memcpy (& dis_cache [i ].info , & device_info , sizeof (ble_dis_info_t ));
194+ dis_cache [i ].valid = true;
195+ LOG_INF ("Added new in-memory cache entry %d" , i );
196+ break ;
197+ }
198+ }
199+ }
200+ k_mutex_unlock (& dis_cache_mutex );
201+
104202 return 0 ;
105203}
106204
107205static int settings_set_cb (const char * name , size_t len , settings_read_cb read_cb , void * cb_arg )
108206{
109207 LOG_DBG ("DIS settings_set_cb called: name='%s', len=%d" , name , len );
110208
111- /* Settings are now per-device ( ble_dis/<addr>/info), loaded on-demand */
112- /* Just acknowledge all DIS settings without loading them globally */
209+ /* Settings are per-device: ble_dis/<addr>/info */
210+ /* Load all cached DIS info into memory at boot */
113211 if (len == sizeof (ble_dis_info_t )) {
114- /* Valid DIS info size, consume it but don't load globally */
115212 ble_dis_info_t temp_info ;
116213 ssize_t bytes_read = read_cb (cb_arg , & temp_info , sizeof (ble_dis_info_t ));
117214 if (bytes_read == sizeof (ble_dis_info_t )) {
118- LOG_DBG ("Found DIS info in settings: %s" , name );
215+ /* Parse address from key format: "<addr>/info" */
216+ bt_addr_le_t addr ;
217+ if (bt_addr_le_from_str (name , "RPA" , & addr ) == 0 ||
218+ bt_addr_le_from_str (name , "random" , & addr ) == 0 ||
219+ bt_addr_le_from_str (name , "public" , & addr ) == 0 ) {
220+ /* Find empty slot in cache (protected by mutex) */
221+ k_mutex_lock (& dis_cache_mutex , K_FOREVER );
222+ for (int i = 0 ; i < MAX_DIS_CACHE_ENTRIES ; i ++ ) {
223+ if (!dis_cache [i ].valid ) {
224+ memcpy (& dis_cache [i ].addr , & addr , sizeof (bt_addr_le_t ));
225+ memcpy (& dis_cache [i ].info , & temp_info , sizeof (ble_dis_info_t ));
226+ dis_cache [i ].valid = true;
227+ LOG_INF ("Loaded DIS cache entry %d from flash: has_fw=%d" , i , temp_info .has_firmware_version );
228+ break ;
229+ }
230+ }
231+ k_mutex_unlock (& dis_cache_mutex );
232+ }
119233 return 0 ;
120234 }
121235 }
@@ -134,6 +248,9 @@ int ble_dis_init(void)
134248 */
135249 dis_ready = false;
136250
251+ /* Initialize work queue for deferred flash writes */
252+ k_work_init (& clear_fw_cache_work , clear_fw_cache_work_handler );
253+
137254 LOG_INF ("DIS init - device_info state: has_fw=%d, fw='%s', has_pnp=%d, vid=0x%04X, pid=0x%04X" ,
138255 device_info .has_firmware_version , device_info .firmware_version ,
139256 device_info .has_pnp_id , device_info .vendor_id , device_info .product_id );
@@ -258,12 +375,121 @@ void ble_dis_clear_saved(void)
258375 /* This function now just clears the global cache */
259376}
260377
378+ void ble_dis_clear_cached_firmware_for_addr (const bt_addr_le_t * addr )
379+ {
380+ if (!addr || !IS_ENABLED (CONFIG_SETTINGS )) {
381+ return ;
382+ }
383+
384+ /* Load existing DIS info */
385+ ble_dis_info_t dis_info ;
386+ int err = ble_dis_load_info_for_addr (addr , & dis_info );
387+
388+ if (err != 0 ) {
389+ LOG_DBG ("No cached DIS info to clear firmware from" );
390+ return ;
391+ }
392+
393+ /* Clear only the firmware version field */
394+ dis_info .has_firmware_version = false;
395+ dis_info .firmware_version [0 ] = '\0' ;
396+
397+ /* Save back to flash storage */
398+ char key [64 ];
399+ build_dis_settings_key (addr , key , sizeof (key ));
400+
401+ err = settings_save_one (key , & dis_info , sizeof (ble_dis_info_t ));
402+ if (err ) {
403+ LOG_ERR ("Failed to save DIS info after clearing firmware (err %d)" , err );
404+ } else {
405+ char addr_str [BT_ADDR_LE_STR_LEN ];
406+ bt_addr_le_to_str (addr , addr_str , sizeof (addr_str ));
407+ LOG_INF ("Cleared cached firmware version in flash for device: %s" , addr_str );
408+ }
409+
410+ /* Also clear from in-memory cache (protected by mutex) */
411+ k_mutex_lock (& dis_cache_mutex , K_FOREVER );
412+ for (int i = 0 ; i < MAX_DIS_CACHE_ENTRIES ; i ++ ) {
413+ if (dis_cache [i ].valid && bt_addr_le_cmp (& dis_cache [i ].addr , addr ) == 0 ) {
414+ dis_cache [i ].info .has_firmware_version = false;
415+ dis_cache [i ].info .firmware_version [0 ] = '\0' ;
416+ LOG_INF ("Cleared cached firmware version in memory cache entry %d" , i );
417+ break ;
418+ }
419+ }
420+ k_mutex_unlock (& dis_cache_mutex );
421+ }
422+
423+ void ble_dis_clear_all_cached_firmware (void )
424+ {
425+ LOG_INF ("Clearing cached firmware version for all devices" );
426+
427+ /* Clear all in-memory cache entries immediately (protected by mutex) */
428+ k_mutex_lock (& dis_cache_mutex , K_FOREVER );
429+ int cleared = 0 ;
430+ for (int i = 0 ; i < MAX_DIS_CACHE_ENTRIES ; i ++ ) {
431+ if (dis_cache [i ].valid && dis_cache [i ].info .has_firmware_version ) {
432+ dis_cache [i ].info .has_firmware_version = false;
433+ dis_cache [i ].info .firmware_version [0 ] = '\0' ;
434+ cleared ++ ;
435+ }
436+ }
437+ k_mutex_unlock (& dis_cache_mutex );
438+
439+ /* Also clear current device_info */
440+ device_info .has_firmware_version = false;
441+ device_info .firmware_version [0 ] = '\0' ;
442+
443+ LOG_INF ("Cleared firmware from %d in-memory cache entries" , cleared );
444+
445+ /* Submit work to clear flash asynchronously (non-blocking) */
446+ if (!clear_fw_cache_pending ) {
447+ clear_fw_cache_pending = true;
448+ k_work_submit (& clear_fw_cache_work );
449+ LOG_INF ("Submitted deferred flash clear work" );
450+ }
451+ }
452+
453+ /* Load cached DIS from in-memory cache into device_info for the connected device */
454+ static void load_cache_for_addr (const bt_addr_le_t * addr )
455+ {
456+ if (!addr ) {
457+ /* No address - clear device_info */
458+ memset (& device_info , 0 , sizeof (device_info ));
459+ return ;
460+ }
461+
462+ /* Search for this address in the cache (protected by mutex) */
463+ k_mutex_lock (& dis_cache_mutex , K_FOREVER );
464+ bool found = false;
465+ for (int i = 0 ; i < MAX_DIS_CACHE_ENTRIES ; i ++ ) {
466+ if (dis_cache [i ].valid && bt_addr_le_cmp (& dis_cache [i ].addr , addr ) == 0 ) {
467+ /* Found cached info for this device */
468+ memcpy (& device_info , & dis_cache [i ].info , sizeof (ble_dis_info_t ));
469+ found = true;
470+ break ;
471+ }
472+ }
473+ k_mutex_unlock (& dis_cache_mutex );
474+
475+ if (found ) {
476+ LOG_INF ("Loaded cached DIS from memory: has_fw=%d, fw='%s'" ,
477+ device_info .has_firmware_version , device_info .firmware_version );
478+ } else {
479+ /* No cache found - clear device_info */
480+ memset (& device_info , 0 , sizeof (device_info ));
481+ LOG_DBG ("No cached DIS found in memory for this device" );
482+ }
483+ }
484+
485+ void ble_dis_load_cache_for_connected_device (const bt_addr_le_t * addr )
486+ {
487+ load_cache_for_addr (addr );
488+ }
489+
261490bool ble_dis_has_cached_firmware (void )
262491{
263- /* Check if device_info has valid firmware version
264- * This info is loaded from persistent storage on init via settings callback,
265- * so it persists across reboots
266- */
492+ /* Check if device_info has valid firmware version */
267493 return device_info .has_firmware_version && (device_info .firmware_version [0 ] != '\0' );
268494}
269495
0 commit comments