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

How to know about the value of a custom characteristic in a custom service whenever that is being updated from the nordicConnect App?

I have implemented the custom service and added custom characteristics following the tutorial series, now I can connect and see the characteristics and their values. I can also update the values from the app, how can I call my own function whenever a value is being updated, and how do I get the updated value in my code when it gets updated from ble client(mobile phone running nordicConnect app in my case)

I am using the nrf52840 DK and latest SDK

Regards
Rit

  • Hi Rit, 
    How do you define your custom service ? The event you need to handle is BLE_GATTS_EVT_WRITE. It's the event when the peer device write to your characteristic. 
    Have you had a look at the ble_app_uart example ? 
    In the example you can find that we declare nus_data_handler() as the data_handler for the service (in services_init)

    The data_handler () function will be called in on_write() when there is BLE_GATTS_EVT_WRITE event.

  • Hi Hung,

    I am able to detect the BLE_GATTS_EVT_WRITE event when peer device is writing data, but I am not able to get the concerned characteristic value  in the BLE_GATTS_EVT_WRITE event. How do i do that?

    This is how I have defines custom service.

    void our_service_init(ble_os_t * p_our_service)
    {
        uint32_t   err_code; // Variable to hold return codes from library and softdevice functions
    
        // FROM_SERVICE_TUTORIAL: Declare 16-bit service and 128-bit base UUIDs and add them to the BLE stack
        ble_uuid_t        service_uuid;
        ble_uuid128_t     base_uuid = BLE_UUID_OUR_BASE_UUID;
        service_uuid.uuid = BLE_UUID_OUR_SERVICE_UUID;
        err_code = sd_ble_uuid_vs_add(&base_uuid, &service_uuid.type);
        APP_ERROR_CHECK(err_code);    
        
        // OUR_JOB: Step 3.B, Set our service connection handle to default value. I.e. an invalid handle since we are not yet in a connection.
    		p_our_service->conn_handle = BLE_CONN_HANDLE_INVALID;
    
        // FROM_SERVICE_TUTORIAL: Add our service
    		err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                            &service_uuid,
                                            &p_our_service->service_handle);
        
        APP_ERROR_CHECK(err_code);
        
        // OUR_JOB: Call the function our_char_add() to add our new characteristic to the service. 
        our_char_add(p_our_service);
    }
     

    This is where I've detected the event

    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context) {
      ret_code_t err_code = NRF_SUCCESS;
    
      switch (p_ble_evt->header.evt_id) {
      case BLE_GAP_EVT_DISCONNECTED:
        NRF_LOG_INFO("Disconnected.");
        // LED indication will be changed when advertising starts.
    
        break;
    
      case BLE_GAP_EVT_CONNECTED:
        NRF_LOG_INFO("Connected.");
        err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
        APP_ERROR_CHECK(err_code);
        m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
        err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
        APP_ERROR_CHECK(err_code);
    
        //When connected; start our timer to start regular temperature measurements
        app_timer_start(m_our_char_timer_id, OUR_CHAR_TIMER_INTERVAL, NULL);
        break;
    
      case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
        NRF_LOG_DEBUG("PHY update request.");
        ble_gap_phys_t const phys =
            {
                .rx_phys = BLE_GAP_PHY_AUTO,
                .tx_phys = BLE_GAP_PHY_AUTO,
            };
        err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
        APP_ERROR_CHECK(err_code);
      } break;
    
      case BLE_GATTC_EVT_TIMEOUT:
        // Disconnect on GATT Client timeout event.
        NRF_LOG_DEBUG("GATT Client Timeout.");
        err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
            BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
        break;
    
      case BLE_GATTS_EVT_TIMEOUT:
        // Disconnect on GATT Server timeout event.
        NRF_LOG_DEBUG("GATT Server Timeout.");
        err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
            BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
        break;
      case BLE_GATTS_EVT_WRITE:
        NRF_LOG_INFO("Data Written.");
        uint32_t err_code;
       // err_code = sd_ble_gatts_value_get(BLE_CONN_HANDLE_INVALID, m_our_service.char1_handles.value_handle, );
        //APP_ERROR_CHECK(err_code);
        break;
       case BLE_GATTS_EVT_HVN_TX_COMPLETE:
           NRF_LOG_INFO("BLE_GATTS_EVT_HVN_TX_COMPLETE");
    
        NRF_LOG_INFO("BLE_GATTS_EVT_HVN_TX_COMPLETE");
        
        break;
    
    
      default:
        // No implementation needed.
        break;
      }
    }

  • Hi Rit,
    You can get the value of the write command using p_ble_evt->evt.gatts_evt.params.write inside the event handler for BLE_GATTS_EVT_WRITE. 

    When you handle BLE_GATTS_EVT_WRITE event, you should check for the handle ID to match it with the characteristic you are monitoring. There could be different writes, for example to the CCCD or to other characteristics. 
    Please refer to the ble_app_lbs or ble_app_uart examples. 

Related