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

sd_ble_gatts_hvx indication sets len 0 and doesn't call onCharacteristicChanged on Adroid App

Hi,

I trying to send indication supplied with some data to my Android app (which BTW works fine with other BLE devices) as an answer to characteristic write command

Here is my sequence of calls:

Android:

1) Discover services and characteristic

2) Write 0x3 to CCCD (0x2902) of required characteristic to enable notifications and indications

3) Enable characteristic notifications

4) Write characteristic

nRF52:

1) create services, characteristic and CCCD

2) upone receiving BLE_GATTS_EVT_WRITE set new characteristic  value with sd_ble_gatts_value_set

3) call sd_ble_gatts_hvx with p_data as NULL (returns success)

 

Unfortunately Android callback onCharacteristicChanged is never called and p_len member of ble_gatts_hvx_params_t passed to sd_ble_gatts_hvx remains 0

Here is my add characteristic function:

static void add_characteristic(uint16_t svc_handle, uint16_t cuuid, ble_gatts_char_handles_t *p_char_handle) {      
    ble_uuid_t char_uuid;
    memset(&char_uuid, 0, sizeof(ble_uuid_t));
    char_uuid.uuid = cuuid;
    char_uuid.type = BLE_UUID_TYPE_BLE;

    ble_gatts_attr_md_t cccd_md;
    memset(&cccd_md, 0, sizeof(ble_gatts_attr_md_t));
    cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    cccd_md.vlen = 0; 
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    
    ble_gatts_attr_md_t attr_md;
    memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    attr_md.vlen       = 1;
    attr_md.vloc       = BLE_GATTS_VLOC_USER;
  
    ble_gatts_char_md_t char_md;
    memset(&char_md,0,sizeof(ble_gatts_char_md_t));
    char_md.char_props.indicate = 1;
    char_md.char_props.notify = 0;
    char_md.char_props.read = 0;
    char_md.char_props.write = 1;        
    char_md.char_props.write_wo_resp = 0;
    char_md.char_props.auth_signed_wr = 1;
    char_md.p_cccd_md = &cccd_md;    
    
    

    ble_gatts_attr_t  attr_char_value;
    memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
    attr_char_value.p_uuid    = &char_uuid;
    attr_char_value.p_attr_md = &attr_md;    
    attr_char_value.max_len   = 500;
    attr_char_value.init_len  = 1;
    attr_char_value.init_offs = 0;    
    

    uint32_t err = sd_ble_gatts_characteristic_add(svc_handle, &char_md, &attr_char_value, p_char_handle);
    if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_characteristic_add(%04x) ERROR: %d\n",cuuid,err);
}

Here is my write response function called on BLE_GATTS_EVT_WRITE 

static void write_response(uint16_t conn_handle, uint16_t char_handle, uint16_t len, uint8_t *data){
    ble_gatts_hvx_params_t params;
    uint16_t wr_len =0;
    memset(&params, 0, sizeof(ble_gatts_hvx_params_t));
    params.handle = char_handle;
    params.type = BLE_GATT_HVX_INDICATION;
    params.p_len = &wr_len;
    params.p_data = NULL;
    params.offset = 0;    

    ble_gatts_value_t pvalue;
    memset(&pvalue, 0, sizeof(ble_gatts_value_t));
    pvalue.len = len;
    pvalue.offset = 0;
    pvalue.p_value = data;

    uint32_t err = sd_ble_gatts_value_set(conn_handle, char_handle, &pvalue);
    if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_value_set ERROR: %x\n",err); // else printf("\tsd_ble_gatts_value_set OK: %d\n",pvalue.len);
    
    printf("\twrite_response: conn_h: %d, cchar_h: %d, len=%d\n", conn_handle, char_handle, len);
    err = sd_ble_gatts_hvx(conn_handle, &params);
    if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_hvx ERROR: %x\n",err); else printf("\tsd_ble_gatts_hvx OK: %d\n",wr_len);
   
}

What am I missing?

Parents
  • So... looks like I found a bug:

    Comments in ble_gatts.h says:

    that means my write_response function is OK.

    But whe I set  params.p_data = data (existing pointer)  then I do get onCharacteristicChanged called on Android. BUT with zero-length byte array

    So I decided to set wr_len = len hoping that in this case I'll get data in Android but I didn't - onCharacteristicChanged again not called.

    I might say - API documentation/comments are very unclear..

  • Looking at the implementation of HVX inside softdevice, the documentation looks correct. So I am not sure why you see that behaviour.

    Can you try the below instead in your write_response and see what happens?

    static void write_response(uint16_t conn_handle, uint16_t char_handle, uint16_t len, uint8_t *data){
        ble_gatts_hvx_params_t params;
        uint16_t wr_len =0;
        memset(&params, 0, sizeof(ble_gatts_hvx_params_t));
        params.handle = char_handle;
        params.type = BLE_GATT_HVX_INDICATION;
        params.p_len = len;
        params.p_data = data;
        params.offset = 0;    
    
        ble_gatts_value_t pvalue;
        memset(&pvalue, 0, sizeof(ble_gatts_value_t));
        pvalue.len = len;
        pvalue.offset = 0;
        pvalue.p_value = data;
    
        uint32_t err = sd_ble_gatts_value_set(conn_handle, char_handle, &pvalue);
        if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_value_set ERROR: %x\n",err); // else printf("\tsd_ble_gatts_value_set OK: %d\n",pvalue.len);
        
        printf("\twrite_response: conn_h: %d, cchar_h: %d, len=%d\n", conn_handle, char_handle, len);
        err = sd_ble_gatts_hvx(conn_handle, &params);
        if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_hvx ERROR: %x\n",err); else printf("\tsd_ble_gatts_hvx OK: %d\n",wr_len);
       
    }

Reply
  • Looking at the implementation of HVX inside softdevice, the documentation looks correct. So I am not sure why you see that behaviour.

    Can you try the below instead in your write_response and see what happens?

    static void write_response(uint16_t conn_handle, uint16_t char_handle, uint16_t len, uint8_t *data){
        ble_gatts_hvx_params_t params;
        uint16_t wr_len =0;
        memset(&params, 0, sizeof(ble_gatts_hvx_params_t));
        params.handle = char_handle;
        params.type = BLE_GATT_HVX_INDICATION;
        params.p_len = len;
        params.p_data = data;
        params.offset = 0;    
    
        ble_gatts_value_t pvalue;
        memset(&pvalue, 0, sizeof(ble_gatts_value_t));
        pvalue.len = len;
        pvalue.offset = 0;
        pvalue.p_value = data;
    
        uint32_t err = sd_ble_gatts_value_set(conn_handle, char_handle, &pvalue);
        if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_value_set ERROR: %x\n",err); // else printf("\tsd_ble_gatts_value_set OK: %d\n",pvalue.len);
        
        printf("\twrite_response: conn_h: %d, cchar_h: %d, len=%d\n", conn_handle, char_handle, len);
        err = sd_ble_gatts_hvx(conn_handle, &params);
        if (err != NRF_SUCCESS) printf("\tsd_ble_gatts_hvx ERROR: %x\n",err); else printf("\tsd_ble_gatts_hvx OK: %d\n",wr_len);
       
    }

Children
Related