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

How to collect value from multiple characteristics in the client?

Hi, 

I am working on the client program to retrieve the value from 4 characteristics at the same time using notifications. I have already done with the server program. Using nrf connect to connect with my program, it looks like this:

I would like to collect the value from these four characteristics using notifications. Here' s the code to update 4 characteristic data on server:

void ble_eeg_update_4ch(ble_eeg_t *p_eeg) {
  //packet 1:
  uint32_t err_code;
  if (p_eeg->conn_handle != BLE_CONN_HANDLE_INVALID && p_eeg->ads1299_current_configuration[4] != 0xE1) {
    uint16_t hvx_len = EEG_PACKET_LENGTH;//The length is 60
    ble_gatts_hvx_params_t const hvx_params = {
        .handle = p_eeg->eeg_ch1_handles.value_handle,
        .type = BLE_GATT_HVX_NOTIFICATION,
        .offset = 0,
        .p_len = &hvx_len,
        .p_data = p_eeg->eeg_ch1_buffer,
    };
    err_code = sd_ble_gatts_hvx(p_eeg->conn_handle, &hvx_params);
  }
  if (err_code == NRF_ERROR_RESOURCES) {
    NRF_LOG_INFO("sd_ble_gatts_hvx() ERR/RES: 0x%x\r\n", err_code);
  }
  //Packet 2
  if (p_eeg->conn_handle != BLE_CONN_HANDLE_INVALID && p_eeg->ads1299_current_configuration[5] != 0xE1) {
    uint16_t hvx_len = EEG_PACKET_LENGTH;//The length is 60
    ble_gatts_hvx_params_t const hvx_params = {
        .handle = p_eeg->eeg_ch2_handles.value_handle,
        .type = BLE_GATT_HVX_NOTIFICATION,
        .offset = 0,
        .p_len = &hvx_len,
        .p_data = p_eeg->eeg_ch2_buffer,
    };
    err_code = sd_ble_gatts_hvx(p_eeg->conn_handle, &hvx_params);
  }
  if (err_code == NRF_ERROR_RESOURCES) {
    NRF_LOG_INFO("sd_ble_gatts_hvx() ERR/RES: 0x%x\r\n", err_code);
  }

  //Packet 3
  if (p_eeg->conn_handle != BLE_CONN_HANDLE_INVALID && p_eeg->ads1299_current_configuration[6] != 0xE1) {
    uint16_t hvx_len = EEG_PACKET_LENGTH;//The length is 60
    ble_gatts_hvx_params_t const hvx_params = {
        .handle = p_eeg->eeg_ch3_handles.value_handle,
        .type = BLE_GATT_HVX_NOTIFICATION,
        .offset = 0,
        .p_len = &hvx_len,
        .p_data = p_eeg->eeg_ch3_buffer,
    };
    err_code = sd_ble_gatts_hvx(p_eeg->conn_handle, &hvx_params);
  }
  if (err_code == NRF_ERROR_RESOURCES) {
    NRF_LOG_INFO("sd_ble_gatts_hvx() ERR/RES: 0x%x\r\n", err_code);
  }

  //Packet 4
  if (p_eeg->conn_handle != BLE_CONN_HANDLE_INVALID && p_eeg->ads1299_current_configuration[7] != 0xE1) {
    uint16_t hvx_len = EEG_PACKET_LENGTH;//The length is 60
    ble_gatts_hvx_params_t const hvx_params = {
        .handle = p_eeg->eeg_ch4_handles.value_handle,
        .type = BLE_GATT_HVX_NOTIFICATION,
        .offset = 0,
        .p_len = &hvx_len,
        .p_data = p_eeg->eeg_ch4_buffer,
    };
    err_code = sd_ble_gatts_hvx(p_eeg->conn_handle, &hvx_params);
  }
  if (err_code == NRF_ERROR_RESOURCES) {
    NRF_LOG_INFO("sd_ble_gatts_hvx() ERR/RES: 0x%x\r\n", err_code);
  }
}

 

Question:

1. Do you have examples that have multiple characteristics that need notifications in one service? I read the code of ble_app_hrs_c, but this program is not what I want.

2. If I can get retrieve these 4 characteristics data on the client, how to differentiate them?

Parents
  • Hi,

    In the ble event, the handle in the ble_gattc_evt_hvx_t data structure is the attribute handle which identifies the characteristic. (Not to be confused with the connection handle, which is found in the ble_gattc_evt_t structure that holds the ble_gattc_evt_hvx_t structure in its params.hvx field.)

    For examples on how to handle this, please have a look at the client service implementations in <sdk folder>/components/ble/ble_services (the folders ending in "_c"). Typically there is an on_hvx() function that checks the handle, e.g. for the battery service client in ble_bas_c.c:

    /**@brief     Function for handling Handle Value Notification received from the SoftDevice.
     *
     * @details   This function handles the Handle Value Notification received from the SoftDevice
     *            and checks whether it is a notification of the Battery Level measurement from the peer. If
     *            it is, this function decodes the battery level measurement and sends it to the
     *            application.
     *
     * @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
     * @param[in] p_ble_evt   Pointer to the BLE event received.
     */
    static void on_hvx(ble_bas_c_t * p_ble_bas_c, ble_evt_t const * p_ble_evt)
    {
        // Check if the event is on the link for this instance.
        if (p_ble_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
        {
            return;
        }
        // Check if this notification is a battery level notification.
        if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_bas_c->peer_bas_db.bl_handle)
        {
            if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
            {
                ble_bas_c_evt_t ble_bas_c_evt;
                ble_bas_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
                ble_bas_c_evt.evt_type    = BLE_BAS_C_EVT_BATT_NOTIFICATION;
    
                ble_bas_c_evt.params.battery_level = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
    
                p_ble_bas_c->evt_handler(p_ble_bas_c, &ble_bas_c_evt);
            }
        }
    }

    Regards,
    Terje

  • Also, I 'm trying to enable 4 notifications after discovering the characteristics. The functions are:

    static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
    {
        uint8_t buf[BLE_CCCD_VALUE_LEN];
        buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
        buf[1] = 0;
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_REQ,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = cccd_handle,
            .offset   = 0,
            .len      = sizeof(buf),
            .p_value  = buf
        };
        return sd_ble_gattc_write(conn_handle, &write_params);
    }
    //functions of ch1, ch2, ch3, ch4 are same
    uint32_t ble_eeg_ch1_c_tx_notif_enable(ble_eeg_uarts_c_t * p_ble_uarts_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_uarts_c);
        if ( (p_ble_uarts_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_uarts_c->handles.eeg_ch1_tx_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
    		
        return cccd_configure(p_ble_uarts_c->conn_handle,p_ble_uarts_c->handles.eeg_ch1_tx_cccd_handle, true);
    }
    // in the main.c:
    
    static void ble_uarts_c_evt_handler(ble_eeg_uarts_c_t * p_ble_uarts_c, ble_eeg_uarts_c_evt_t const * p_ble_uarts_evt)
    {
        ret_code_t err_code;
    
        switch (p_ble_uarts_evt->evt_type)
        {
            case BLE_UARTS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Discovery complete.");
                err_code = ble_uarts_c_handles_assign(p_ble_uarts_c, p_ble_uarts_evt->conn_handle, &p_ble_uarts_evt->handles);
                APP_ERROR_CHECK(err_code);
                //Enable Notify
                err_code = ble_eeg_ch1_c_tx_notif_enable(p_ble_uarts_c);
                APP_ERROR_CHECK(err_code);
    			NRF_LOG_INFO("Enabel notification of the Channel 1 Char");
    			
    			err_code = ble_eeg_ch2_c_tx_notif_enable(p_ble_uarts_c);
                APP_ERROR_CHECK(err_code);
    			NRF_LOG_INFO("Enabel notification of the Channel 2 Char");
    				
    		    err_code = ble_eeg_ch3_c_tx_notif_enable(p_ble_uarts_c);
                APP_ERROR_CHECK(err_code);
    			NRF_LOG_INFO("Enabel notification of the Channel 3 Char");
    						
    			err_code = ble_eeg_ch4_c_tx_notif_enable(p_ble_uarts_c);
                APP_ERROR_CHECK(err_code);
    			NRF_LOG_INFO("Enabel notification of the Channel 4 Char");
                NRF_LOG_INFO("Connected to device with EEG Service.");
                break;
    
            case BLE_UARTS_C_EVT_NUS_TX_EVT:
                uart_chars_print(p_ble_uarts_evt->p_data, p_ble_uarts_evt->data_len);
                break;
    
            case BLE_UARTS_C_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                scan_start();
                break;
        }
    }
    
    

    However, when it tries to enable the notifications of ch1~4, it is said there's a fatal error. How to enable these four characteristics correctly?

    Thank you!

  • Hi,

    What error code do you get, and from what function call? (It sounds like it is from ble_eeg_ch4_c_tx_notif_enable(), can you confirm or correct that assumption?) This will usually point towards what kind of error you are seeing.

    Regards,
    Terje

Reply Children
No Data
Related