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

Sending up to 20 bytes of data during a notify event.

In a previous post Related post it was mentioned that the below posted code would allow for a transmission of 20 bytes. However when I try to run this code I see a reported value of 20, even if i change the length of the data array down to 5 (data[5] = {1,2,3,4,5,})

the characteristic keeps reporting garbage data instead of what I expect to see defined within the contents of data

What did I do wrong?

ble_gatts_hvx_params_t hvx_params;
memset(&hvx_params, 0, sizeof(hvx_params));
uint16_t len = 20;
uint8_t data[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; // 20 bytes of data

hvx_params.handle = value_handle;
hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len  = &len; // remember that this is also a pointer!
hvx_params.p_data = data;

err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);

When I run this code, I expect to see the pre-defined 20 bytes within data but that doesn't happen. I have attached the following screen shot of what I receive.

nRF master Control Panel

-- ANSWER: within characteristic definition attr_char_value.max_len needs to be set to the number of bytes to be sent.

However I still see garbage data. There is something else I'm not doing right.

  • In the service.c file I set the characteristic like so:

        static uint32_t imu_char_add(ble_aavs_t * p_aavs)
    {
        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;
    
        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.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_aavs->uuid_type;
        ble_uuid.uuid = AAVS_UUID_IMU_CHAR;
        
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
        attr_md.vloc       = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth    = 0;
        attr_md.wr_auth    = 0;
        attr_md.vlen       = 0;
        
        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     = sizeof(uint8_t);
        attr_char_value.init_offs    = 0;
        attr_char_value.max_len      = 20;//sizeof(uint8_t);  // This sets the data length to be transmitted.
        attr_char_value.p_value      = NULL;
        
        return sd_ble_gatts_characteristic_add(p_aavs->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_aavs->imu_char_handles);
    }
    

    I then later define a method which is supposed to transfer data over ble from the pointer I feed into it.

       uint32_t ble_aavs_on_imu_available(ble_aavs_t * p_aavs, uint8_t* p_imu_data, uint16_t imu_data_len)			
    {
    	 uint32_t err_code;
    	
     if (p_aavs->conn_handle != BLE_CONN_HANDLE_INVALID)
    {
    ble_gatts_hvx_params_t params;
    
      
    memset(&params, 0, sizeof(params));
    params.handle 	= p_aavs->imu_char_handles.value_handle;
    params.type 		= BLE_GATT_HVX_NOTIFICATION;
    params.offset 	= 0;
    params.p_len 	= &imu_data_len;
    params.p_data 	= p_imu_data;
    					    
    err_code = sd_ble_gatts_hvx(p_aavs->conn_handle, &params);
    					
    	}
    	else
    	{
    		err_code = NRF_ERROR_INVALID_STATE;
    	}
    	
    		return err_code;
    

    }

    from within the application I have a method which calls the notification code under the condition it sees a BLE_EVT_TX_COMPLETE within the on_ble_evt method

  • This here:

    uint16_t len = sizeof(p_imu_data)/sizeof(p_imu_data[0])

    sizeof(ptr) will always give you 4 bytes, you cannot do that in C to obtain the length of the memory pointed to. You will have to pass imu_data_len as a parameter to ble_aavs_on_imu_available()

  • Thanks Carles, Ive updated the code to reflect your changes. I agree the size of a pointer will never changes, that got passed me. I still see garbage data though. Not sure what could be causing it.

  • I'm running out of ideas now but you say that you call hvx() when you get a TX_COMPLETE event. What triggers then the first notification? It's the first notification that will trigger that first TX_COMPLETE event.

Related