This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Confused about persisting characteristic values written by a central

I have an nRF51822-based device, which is a peripheral running the Soft Device s110. It has some vendor specific (custom) characteristics that are read/write. A mobile app (central) reads and writes them.

I'm confused about how I should be persisting the values for these characteristics. They need to be persisted across a reset or system off.

Firstly, is it my responsibility to persist the value or do I get that for free somehow? Having a look at the source for the Immediate Alert Service implementation in the SDK, there's no persistence going on, so it seems like the responsibility of the application.

If I must persist the values myself, it seems I have these options:

  1. Keep the value in RAM and use RAM retention. There's an example app for this: ram_retention_example.

  2. Keep the value in flash and use the pstorage module.

  3. The new Device Manager has an application context which looks like it might be a suitable place to write the values. I can see no examples that use it, however. If I write some data to it, does the Device Manager use pstorage to write this to flash for me?

If #3 is not suitable, what are the power consumption considerations for choosing between #1 and #2? Does my flash "wear out" over thousands of read/write operations?

Parents
  • Hi Eliot,

    The application context in Device Manager has been added to address use cases you mention above. Hence 3, is suitable. However, note that you will be to use application context store and load functionality only for a bonded device.

    You are right, there is no SDK example that shows how to use the application context.

    Below are some code snippets that may be of useful to you.

    typedef struct
    {
        uint32_t value;
    }my_char_t;
    
    static dm_handle_t m_bonded_dev_handle;
    static my_char_t   m_my_char;
    
    
    // Code for storing.
    static void on_ble_evt(ble_evt_t * p_evt)
    {
       api_result_t               retval;
       dm_application_context_t   app_context;
       
       switch (p_evt->header.evt_id)
       {
            .
    	    .
    	    case BLE_GAP_EVT_DISCONNECTED:
    	    {
    		    app_context.len    = sizeof(my_char_t);
    			app_context.p_data = ((uint8_t *)&m_my_char); 
    			
    	        // Want to store the last updated value of the characteristic persistently.
    		    retval = dm_application_context_set(&m_bonded_dev_handle,
    		                                       &app_context);
                if (retval == NRF_SUCCESS)
    			{
    			    // Wait for DM_EVT_APPL_CONTEXT_STORED event.
    				// Note do not reuse or change m_my_char.
    			}
    			else
    			{
    			    // Failed to store application context.
    			}
    	        break;
           }
    	   .
    	   .
       }
    }
    
    
    // Code for loading.
    static uint32_t device_manager_evt_handler(dm_handle_t const    * p_handle,
                                               dm_event_t const     * p_event,
                                               api_result_t           event_result)
    {
        APP_ERROR_CHECK(event_result);
    	
    	
        api_result_t               retval;
        dm_application_context_t   app_context;
    	
    	switch(p_event->event_id)
    	{
    	    .
    		.
    		case DM_EVT_DEVICE_CONTEXT_LOADED:
    		{		
    		    // This event is generated as soon as a bonded device reconnects and its bond and 
    			// service information have been loaded. This may be most appropriate to load application
    			// context. 			
    			app_context.len    = sizeof(my_char_t);
    			app_context.p_data = ((uint8_t *)&m_my_char);
    			
    			retval = dm_application_context_get(p_handle,&app_context);
    			if (retval == NRF_SUCCESS)
    			{
                    // DM_EVT_APPL_CONTEXT_LOADED event generated to indicate load complete.
    				// Note do not reuse or change m_my_char.
    			}
    		    break;
    		}
    		case DM_EVT_APPL_CONTEXT_LOADED:		
    		{
    		    // Set char value using sd_ble_gatts_value_set
    		    break;
    		}
    		.
    		.
    	}
        return NRF_SUCCESS;
    }
    

    Please ensure that DEVICE_MANAGER_APP_CONTEXT_SIZE is set to a value suitable for storing your application context size. By default DEVICE_MANAGER_APP_CONTEXT_SIZE is set to 0 in examples to disable these APIs for applications that do not need it. Also, note that I mention suitable here and not maximum because the DEVICE_MANAGER_APP_CONTEXT_SIZE is expected to be a multiple of 4. Therefore in case your application context size if 30, you will need to set this to 32.

    Hope this helps!

    Regards, Krishna

Reply
  • Hi Eliot,

    The application context in Device Manager has been added to address use cases you mention above. Hence 3, is suitable. However, note that you will be to use application context store and load functionality only for a bonded device.

    You are right, there is no SDK example that shows how to use the application context.

    Below are some code snippets that may be of useful to you.

    typedef struct
    {
        uint32_t value;
    }my_char_t;
    
    static dm_handle_t m_bonded_dev_handle;
    static my_char_t   m_my_char;
    
    
    // Code for storing.
    static void on_ble_evt(ble_evt_t * p_evt)
    {
       api_result_t               retval;
       dm_application_context_t   app_context;
       
       switch (p_evt->header.evt_id)
       {
            .
    	    .
    	    case BLE_GAP_EVT_DISCONNECTED:
    	    {
    		    app_context.len    = sizeof(my_char_t);
    			app_context.p_data = ((uint8_t *)&m_my_char); 
    			
    	        // Want to store the last updated value of the characteristic persistently.
    		    retval = dm_application_context_set(&m_bonded_dev_handle,
    		                                       &app_context);
                if (retval == NRF_SUCCESS)
    			{
    			    // Wait for DM_EVT_APPL_CONTEXT_STORED event.
    				// Note do not reuse or change m_my_char.
    			}
    			else
    			{
    			    // Failed to store application context.
    			}
    	        break;
           }
    	   .
    	   .
       }
    }
    
    
    // Code for loading.
    static uint32_t device_manager_evt_handler(dm_handle_t const    * p_handle,
                                               dm_event_t const     * p_event,
                                               api_result_t           event_result)
    {
        APP_ERROR_CHECK(event_result);
    	
    	
        api_result_t               retval;
        dm_application_context_t   app_context;
    	
    	switch(p_event->event_id)
    	{
    	    .
    		.
    		case DM_EVT_DEVICE_CONTEXT_LOADED:
    		{		
    		    // This event is generated as soon as a bonded device reconnects and its bond and 
    			// service information have been loaded. This may be most appropriate to load application
    			// context. 			
    			app_context.len    = sizeof(my_char_t);
    			app_context.p_data = ((uint8_t *)&m_my_char);
    			
    			retval = dm_application_context_get(p_handle,&app_context);
    			if (retval == NRF_SUCCESS)
    			{
                    // DM_EVT_APPL_CONTEXT_LOADED event generated to indicate load complete.
    				// Note do not reuse or change m_my_char.
    			}
    		    break;
    		}
    		case DM_EVT_APPL_CONTEXT_LOADED:		
    		{
    		    // Set char value using sd_ble_gatts_value_set
    		    break;
    		}
    		.
    		.
    	}
        return NRF_SUCCESS;
    }
    

    Please ensure that DEVICE_MANAGER_APP_CONTEXT_SIZE is set to a value suitable for storing your application context size. By default DEVICE_MANAGER_APP_CONTEXT_SIZE is set to 0 in examples to disable these APIs for applications that do not need it. Also, note that I mention suitable here and not maximum because the DEVICE_MANAGER_APP_CONTEXT_SIZE is expected to be a multiple of 4. Therefore in case your application context size if 30, you will need to set this to 32.

    Hope this helps!

    Regards, Krishna

Children
Related