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

How to add an additional characteristic to the NUS service

I tried to add an additional characteristic to NUS service as below.

However, any mobile apps could find only existing Nordic Rx and Nordic Tx characteristics, other than the new characteristics.

Based on the several experiment, only two characteristics under NUS service should be allowed.

Can you please let me know how to add the new one under NUS service?

FYI, there is no error though.

uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
    uint32_t      err_code;
    ble_uuid_t    ble_uuid;
    ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;

    VERIFY_PARAM_NOT_NULL(p_nus);
    VERIFY_PARAM_NOT_NULL(p_nus_init);

    // Initialize the service structure.
    p_nus->conn_handle             = BLE_CONN_HANDLE_INVALID;
    p_nus->data_handler            = p_nus_init->data_handler;
    p_nus->is_notification_enabled = false;

   
    // Add a custom base UUID.
    err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
    VERIFY_SUCCESS(err_code);

    ble_uuid.type = p_nus->uuid_type;
    ble_uuid.uuid = BLE_UUID_NUS_SERVICE;

    // Add the service.
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                        &ble_uuid,
                                        &p_nus->service_handle);
    
    VERIFY_SUCCESS(err_code);
		
    // Add the RX Characteristic.
    err_code = rx_char_add(p_nus, p_nus_init);
    VERIFY_SUCCESS(err_code);

    // Add the TX Characteristic.
    err_code = tx_char_add(p_nus, p_nus_init);
    VERIFY_SUCCESS(err_code);
		
	// Add A new Characteristic.
	err_code = a_new_char_add(p_nus, p_nus_init);
	VERIFY_SUCCESS(err_code);


    return NRF_SUCCESS;
}

static uint32_t a_new_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
    uint32_t   err_code = 0; // Variable to hold return codes from library and softdevice functions
    
		ble_gatts_char_md_t char_md;
		ble_gatts_attr_md_t cccd_md;
		ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          char_uuid;
		ble_gatts_attr_md_t attr_md;
		
		memset(&cccd_md, 0, sizeof(cccd_md));
		BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
		cccd_md.vloc                = BLE_GATTS_VLOC_STACK;
	
		memset(&char_md, 0, sizeof(char_md));
    
		char_md.char_props.read   = 1; 
    char_md.char_props.write  = 1;
	  char_md.p_cccd_md           = &cccd_md;
    char_md.char_props.notify   = 1;
		char_uuid.type = p_nus->uuid_type;
		char_uuid.uuid      = BLE_UUID_ASI_CHARACTERISTC_UUID;
    
		memset(&attr_md, 0, sizeof(attr_md));
	
		BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
	
		attr_md.vloc        = BLE_GATTS_VLOC_STACK;
		attr_md.rd_auth 		= 0;
    attr_md.wr_auth 		= 0;
    attr_md.vlen    		= 1;

		memset(&attr_char_value, 0, sizeof(attr_char_value));
		attr_char_value.p_uuid      = &char_uuid;
    attr_char_value.p_attr_md   = &attr_md;
    attr_char_value.max_len     = 128;
    attr_char_value.init_len    = 128;
    uint8_t value[128]            = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
																		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
    attr_char_value.p_value     = value;

    // ASI_JOB: Step 2.E, Add a new characteristic to the service
    err_code = sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                       &char_md,
                                       &attr_char_value,
                                       &p_nus->char_handles);
    APP_ERROR_CHECK(err_code);
    
    printf("\r\nService handle: %#x\n\r", p_nus->service_handle);
    printf("Char value handle: %#x\r\n", p_nus->char_handles.value_handle);
    printf("Char cccd handle: %#x\r\n\r\n", p_nus->char_handles.cccd_handle);

    return NRF_SUCCESS;
}

Parents
  • Hi, 

    This may be caused by attribute caching, your code appears to be correct. The phone will cache the attribute table across connections unless the "service changed" characteristic is present. I.e., it will remember the attribute table from before you added the new characteristic. If you have an iphone you can clear the cache by enabling and disabling flight mode.  

Reply
  • Hi, 

    This may be caused by attribute caching, your code appears to be correct. The phone will cache the attribute table across connections unless the "service changed" characteristic is present. I.e., it will remember the attribute table from before you added the new characteristic. If you have an iphone you can clear the cache by enabling and disabling flight mode.  

Children
  • Hi Vidar,

    Thank you for your feedback. Yes, you are right. It was the cache clearance issue from mobile phone.

    Now I have a new problem related with "sd_ble_gatts_value_get". My code was stuck at it.

    if (p_evt_write->handle == p_nus->char_handles1.value_handle)
    {

    sd_ble_gatts_value_get(p_nus->conn_handle, p_nus->char_handles1.value_handle, &rx_data);
    printf("Value received on handle %#06x: %#010x\r\n", p_evt_write->handle, data_buffer0);
    p_nus->gpio_output_write_handler(p_nus, data_buffer0);

    }

    Do you have any suggestion around this issue? 

    BTW, should I close this and re-open the ticket for this new issue?

    Thanks

  • Hi,

    I don't see anything in your code snippet that can cause the program to get stuck. However, you don't need to call  sd_ble_gatts_value_get() as the data pointer is provided in p_ble_evt->evt.gatts_evt.params.write.data.

     default on_write handler in nordic uart service:

    /**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
     *
     * @param[in] p_nus     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
    {
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
        if (
            (p_evt_write->handle == p_nus->rx_handles.cccd_handle)
            &&
            (p_evt_write->len == 2)
           )
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                p_nus->is_notification_enabled = true;
            }
            else
            {
                p_nus->is_notification_enabled = false;
            }
        }
        else if (
                 (p_evt_write->handle == p_nus->tx_handles.value_handle)
                 &&
                 (p_nus->data_handler != NULL)
                )
        {
            p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len); // Notify app through registered callback
        }
        else
        {
            // Do Nothing. This event is not relevant for this service.
        }
    }

  • static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
    {
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
    	
        if (
            (p_evt_write->handle == p_nus->rx_handles.cccd_handle)
            &&
            (p_evt_write->len == 2)
           )
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                p_nus->is_notification_enabled = true;
            }
            else
            {
                p_nus->is_notification_enabled = false;
            }
        }
        else if (
                 (p_evt_write->handle == p_nus->tx_handles.value_handle)
                 &&
                 (p_nus->data_handler != NULL)
                )
        {
            p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);
        }
        else
        {
    				// Decclare buffer variable to hold received data. The data can only be 32 bit long.
    				uint32_t data_buffer0;
    				// Populate ble_gatts_value_t structure to hold received data and metadata.
    				ble_gatts_value_t rx_data;
    				rx_data.len = sizeof(uint32_t);
    				rx_data.offset = 0;
    				rx_data.p_value = (uint8_t*)&data_buffer0;
    			
                    // Check if write event is performed on asi characteristic or the CCCD
    				if (p_evt_write->handle == p_nus->char_handles1.value_handle)
    				{
    					// Get data
    					sd_ble_gatts_value_get(p_nus->conn_handle, p_nus->char_handles1.value_handle, &rx_data);
    					p_nus->gpio_output_write_handler(p_nus, data_buffer0);
    				
    				}
    				else if((p_evt_write->handle == p_nus->char_handles1.cccd_handle)&&(p_evt_write->len == 2))
    				{
    					// Get data
    					sd_ble_gatts_value_get(p_nus->conn_handle, p_nus->char_handles1.cccd_handle, &rx_data);
    					if(data_buffer0 == 0x0001)
    					{
                printf("Notification enabled\r\n");
    					}
    					else if(data_buffer0 == 0x0000)
    					{
                printf("Notification disabled\r\n");
    					}
    				}
        }
    }

    What about this way? I want to add a separate char under NUS service.

  • Have you tested this, I think it should work, but still think that sd_ble_gatts_value_get() is redundant since you can retrieve the same data from the p_ble_evt->evt.gatts_evt.params.write.data pointer. Please try code below if it doesn't work:

    static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
    {
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    	
        if (
            (p_evt_write->handle == p_nus->rx_handles.cccd_handle)
            &&
            (p_evt_write->len == 2)
           )
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                p_nus->is_notification_enabled = true;
            }
            else
            {
                p_nus->is_notification_enabled = false;
            }
        }
        else if 
    		(
            (p_evt_write->handle == p_nus->char_handles1.cccd_handle)
             &&
             p_evt_write->len == 2)
    		)
    		
    			if (ble_srv_is_notification_enabled(p_evt_write->data))
    			{
    				printf("Notification enabled\r\n");
    			}
    			else
    			{
    				printf("Notification disabled\r\n");
    			}
    	
        else if (
                 (p_evt_write->handle == p_nus->tx_handles.value_handle)
                 &&
                 (p_nus->data_handler != NULL)
                )
        {
            p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);
        }
    	else if ( (p_evt_write->handle == p_nus->char_handles1.value_handle) && (p_evt_write->len == 4))
    	{
    		uint32_t data_buffer0;
    		
    		memcpy(&data_buffer0, p_evt_write->data, sizeof(uint32_t));
    		p_nus->gpio_output_write_handler(p_nus, data_buffer0)
    		
    	)	
    }

  • Hi,

    Now working fine. Please close the ticket.

    Thank you for your help

Related