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

How to handle characteristic data?

Hello,

For me, at the moment there are two things unclear. With the help of some Nordic examples, I was able to add a Service with 3 characteristics to the used S120 BLE stack. I`m able to connect to the PCA10028 demoboard via a Smartphone. I can see the service/characteristics with the nordic master control panel (Android).

The first two characteristics are defined readable only. The 3rd characteristic is defined readable/writable.

So the first question is, how I can add data to the first two characteristics? For example, I want to write 0xFFAAFFAA to the first chracteristic. My expectation is, if I read out the first characteristic with the Smartphone, I get 0xFFAAFFAA. Where do I have to place this data to the characteristic?

The second question is, how do I get data written from the Smartphone? I tried to see the written data (for example 0xFF) with the debugger (watch window). But I wasn`t able to get the written data. In which function do I have to handle the received data? In which variable the received data is stored?

Thanks in advance for any help!

Regards!

  • Hi,

    When you add the characteristic with sd_ble_gatts_characteristic_add(), the p_attr_char_value argument points to a ble_gatts_attr_t. This type has the initial data, UUID, lengths and such for the characteristic. If you want to set your read-only data, you will set it here initially and save the value handle that is returned from the characteristic_add() call. After that you update it during run-time with sd_ble_gatts_value_set().

    For writable characteristics, as you can see here, the stack will automatically receive and store any writes to the database for you. You will then receive an event that it happened, with a copy of the data. (This is only if you haven't enabled write authorization, which will prompt you to accept or deny the write). If you want to have a look at it at a later point, you can use sd_ble_gatts_value_get() to fetch the current value.

    Please read the documentation for any of the API calls I mentioned to see their usage and limitations, or look at the simpler SDK examples and see how they solve this.

  • I cannot understand this part of your answer Sir Ulrich "value handle that is returned from the characteristic_add() call. " Since, These are the Return values of sd_ble_gatts_characteristic_add() call NRF_SUCCESS Successfully added a characteristic. NRF_ERROR_INVALID_ADDR Invalid pointer supplied. NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and permissions need to adhere to the constraints. NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. NRF_ERROR_NO_MEM Not enough memory to complete operation. NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by Maximum attribute lengths.

  • The p_handles field in characteristic_add() is an output parameter. All the handles that are assigned will be stored in this struct for you to use later.

  • Hello Ulrich,

    thanks for your answer and sorry for my misunderstanding. Currently I`m not able to get this topic running. :-( Here is how I add my "sernum" characteristic.

    static uint32_t sernum_char_add(ble_device_t * p_dev, const ble_device_init_t * p_dev_init)
    {
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    		int i=0;
    	
    		for(i=0;i<4;i++)
    		{
    			sernum[i]= i;
    		}
    
        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.notify = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_dev->uuid_type;
        ble_uuid.uuid = BLE_UUID_DEV_SERNUM_CHARACTERISTIC;
    
        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    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = (4*sizeof(uint8_t));
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_DEVICE_MAX_SERNUM_LEN;
    		attr_char_value.p_value = sernum;
    
        return sd_ble_gatts_characteristic_add(p_dev->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_dev->sernum_handles);
    

    }

    sernum is a global array variable. So for my understanding attr_char_value.p_value points to the content of the array (filled with 0, 1, 2, 3). But if I try to read this characteristic with the android Master Control Panel, I only get: "Value: Notifications enabled". Where is my mistake!

    Regards!

  • You are reading the characteristic declaration (which has its own handle). The value handle should be just below this one. The "readable" property flag is also not set in char_md (you only set notify), which is why you see this "notifications enabled".

Related