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

Use sd_ble_gatts_value_get() to get characteristic value of the characteristic tutorial

Hello, after following this tutorial https://devzone.nordicsemi.com/tutorials/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial I have set a custom service with a custom characteristic, now I'm trying to use the function sd_ble_gatts_value_get() to get the value of that characteristic and display it on a screen (the screen job is not part of the question).

I'm using S132 with the nRF52 DK and the SDK 15.3.

So far, what I'm trying is the following:

on the timer_timeout_handler of the main.c I added:

    uint32_t err_code;
    uint32_t text = 0;
    ble_gatts_value_t textValue;
    textValue.p_value = (uint8_t*)&text;
    textValue.len = 10;
    textValue.offset = 0;
    //sd_temp_get(&temperature);
    get_text(&m_our_service, &textValue);

And the get_text() function is over our_service.c like this:

void get_text(ble_os_t *p_our_service, ble_gatts_value_t *text)
{
  uint32_t err_code;
  err_code = sd_ble_gatts_value_get(BLE_CONN_HANDLE_INVALID, p_our_service->char_handles.value_handle, text);
  APP_ERROR_CHECK(err_code);
}

But when I run the code after the first interval of the timer I receive the error NRF_ERROR_NOT_FOUND on the call of the function.

Any hint or help on what can be wrong?

Parents Reply Children
  • I think yes, I followed the tutorial, look at my code:

    our_service.c

    #include <stdint.h>
    #include <string.h>
    #include "our_service.h"
    #include "ble_srv_common.h"
    #include "app_error.h"
    #include "nrf_log.h"
    #include "SEGGER_RTT.h"
    
    // ALREADY_DONE_FOR_YOU: Declaration of a function that will take care of some housekeeping of ble connections related to our service and characteristic
    void ble_our_service_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
      	ble_os_t * p_our_service = (ble_os_t *) p_context;  
    		// OUR_JOB: Step 3.D Implement switch case handling BLE events related to our service. 
    	switch (p_ble_evt->header.evt_id)
              {
                case BLE_GAP_EVT_CONNECTED:
                  p_our_service->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                  break;
                case BLE_GAP_EVT_DISCONNECTED:
                  p_our_service->conn_handle = BLE_CONN_HANDLE_INVALID;
                  break;
                default:
                  break;
              }
    	
    }
    
    static uint32_t our_char_add(ble_os_t * p_our_service)
    {
        // OUR_JOB: Step 2.A, Add a custom characteristic UUID
        uint32_t  err_code;
        ble_uuid_t  char_uuid;
        ble_uuid128_t base_uuid = BLE_UUID_OUR_BASE_UUID;
        char_uuid.uuid = BLE_UUID_OUR_CHARACTERISTC_UUID;
        err_code = sd_ble_uuid_vs_add(&base_uuid, &char_uuid.type);
        APP_ERROR_CHECK(err_code);
    
        // OUR_JOB: Step 2.F Add read/write properties to our characteristic
        ble_gatts_char_md_t char_md;
        memset(&char_md, 0, sizeof(char_md));
        char_md.char_props.read = 1;
        char_md.char_props.write = 1;
    
        // OUR_JOB: Step 3.A, Configuring Client Characteristic Configuration Descriptor metadata and add to char_md structure
        ble_gatts_attr_md_t cccd_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;
        char_md.p_cccd_md = &cccd_md;
        char_md.char_props.notify   = 1;
        
        // OUR_JOB: Step 2.B, Configure the attribute metadata
        ble_gatts_attr_md_t attr_md;
        memset(&attr_md, 0, sizeof(attr_md));  
        attr_md.vloc = BLE_GATTS_VLOC_STACK;
        
        // OUR_JOB: Step 2.G, Set read/write security levels to our characteristic
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
        //BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); //Forbid permission
        //BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm); //Bond device
        
        // OUR_JOB: Step 2.C, Configure the characteristic value attribute
        ble_gatts_attr_t    attr_char_value;
        memset(&attr_char_value, 0, sizeof(attr_char_value));
        attr_char_value.p_uuid = &char_uuid;
        attr_char_value.p_attr_md = &attr_md;
        
        // OUR_JOB: Step 2.H, Set characteristic length in number of bytes
        attr_char_value.max_len = 9;
        attr_char_value.init_len = 9;
        uint8_t value[9] = {0x54,0x65,0x73,0x74,0x0,0x0,0x0,0x0,0x0};
        attr_char_value.p_value = value;
    
        // OUR_JOB: Step 2.E, Add our new characteristic to the service
        err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle, &char_md, &attr_char_value, &p_our_service->char_handles);
        APP_ERROR_CHECK(err_code);
    
    
        return NRF_SUCCESS;
    }
    
    /**@brief Function for initiating our new service.
     *
     * @param[in]   p_our_service        Our Service structure.
     *
     */
    void our_service_init(ble_os_t * p_our_service)
    {
    
        // STEP 3: Declare 16 bit service and 128 bit base UUIDs and add them to BLE stack table
        uint32_t err_code;
        ble_uuid_t service_uuid;
        ble_uuid128_t base_uuid = BLE_UUID_OUR_BASE_UUID;
        service_uuid.uuid = BLE_UUID_OUR_SERVICE;
        err_code = sd_ble_uuid_vs_add(&base_uuid, &service_uuid.type);
        APP_ERROR_CHECK(err_code);
        
    	// STEP 4: 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);
    	
        // Print messages to Segger Real Time Terminal
        // UNCOMMENT THE FOUR LINES BELOW AFTER INITIALIZING THE SERVICE OR THE EXAMPLE WILL NOT COMPILE.
        SEGGER_RTT_WriteString(0, "Executing our_service_init().\n"); // Print message to RTT to the application flow
        SEGGER_RTT_printf(0, "Service UUID: 0x%#04x\n", service_uuid.uuid); // Print service UUID should match definition BLE_UUID_OUR_SERVICE
        SEGGER_RTT_printf(0, "Service UUID type: 0x%#02x\n", service_uuid.type); // Print UUID type. Should match BLE_UUID_TYPE_VENDOR_BEGIN. Search for BLE_UUID_TYPES in ble_types.h for more info
        SEGGER_RTT_printf(0, "Service handle: 0x%#04x\n", p_our_service->service_handle); // Print out the service handle. Should match service handle shown in MCP under Attribute values
        our_char_add(p_our_service);
    }
    
    // ALREADY_DONE_FOR_YOU: Function to be called when updating characteristic value
    void our_text_characteristic_update(ble_os_t *p_our_service, uint8_t *text)
    {
        // OUR_JOB: Step 3.E, Update characteristic value
        if (p_our_service->conn_handle != BLE_CONN_HANDLE_INVALID)
          {
            uint16_t len = 10;
            ble_gatts_hvx_params_t hvx_params;
            memset(&hvx_params, 0, sizeof(hvx_params));
    
            hvx_params.handle = p_our_service->char_handles.value_handle;
            hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = 0;
            hvx_params.p_len = &len;
            hvx_params.p_data = (uint8_t*)text;
    
            sd_ble_gatts_hvx(p_our_service->conn_handle, &hvx_params);
          }
    
    
    }
    
    void get_text(ble_os_t *p_our_service, ble_gatts_value_t *text)
    {
      uint32_t err_code;
      err_code = sd_ble_gatts_value_get(BLE_CONN_HANDLE_INVALID, p_our_service->char_handles.value_handle, text);
      APP_ERROR_CHECK(err_code);
    }
    

    our_service.h

    #ifndef OUR_SERVICE_H__
    #define OUR_SERVICE_H__
    
    #include <stdint.h>
    #include "ble.h"
    #include "ble_srv_common.h"
    
    #define BLE_UUID_OUR_BASE_UUID              {0x23, 0xD1, 0x13, 0xEF, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00} // 128-bit base UUID
    #define BLE_UUID_OUR_SERVICE                0xABCD // Just a random, but recognizable value
    #define BLE_UUID_OUR_CHARACTERISTC_UUID          0xBEEF // Just a random, but recognizable value
    
    /**
     * @brief This structure contains various status information for our service. 
     * It only holds one entry now, but will be populated with more items as we go.
     * The name is based on the naming convention used in Nordic's SDKs. 
     * 'ble indicates that it is a Bluetooth Low Energy relevant structure and 
     * os is short for Our Service). 
     */
    typedef struct
    {
        uint16_t    service_handle;     /**< Handle of Our Service (as provided by the BLE stack). */
        uint16_t    conn_handle;
        ble_gatts_char_handles_t  char_handles;
    }ble_os_t;
    
    void ble_our_service_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
    
    /**@brief Function for initializing our new service.
     *
     * @param[in]   p_our_service       Pointer to Our Service structure.
     */
    void our_service_init(ble_os_t * p_our_service);
    
    void our_text_characteristic_update(ble_os_t *p_our_service, uint8_t *text);
    
    void get_text(ble_os_t *p_our_service, ble_gatts_value_t *text);
    
    #endif  /* _ OUR_SERVICE_H__ */
    

  • I looked at your code extensively, but cannot see anything wrong with it.

    The only difference is:

    #define BLE_UUID_OUR_BASE_UUID {0x23, 0xD1, 0x13, 0xEF, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00} // 128-bit base UUID

    compared to the example (and how I use it):

    #define BLE_UUID_OUR_BASE_UUID {{0x23, 0xD1, 0x13, 0xEF, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}} // 128-bit base UUID

    Although normally that should not matter much..

Related