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

Central ble, how to relate UUID with handlers?

Hello,

I am developing a device with a nrf52 using s140 with the last sdk. The objective is to interact through ble with other devices that have different custom services. I have already implemented the central role, scan the devices and connect to them. But here is where I am a bit lost, I do not know which are the steps to follow to, for example, read one of the characteristics of the custom services in the peripheral devices. I guess I should use

sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)


But I do not how to retrieve the "handle" parameter. Again I guess I should use the discovery module but I do not know how to use it to relate the UUID of the characteristics with the "handle" parameter.

What are the steps to get the "handle" parameter related with a UUID characteristic?

My goal is to implement a wrap functions that read/write characteristics with a given UUID.

Thanks,

Parents
  • Hello,

    But I do not how to retrieve the "handle" parameter. Again I guess I should use the discovery module but I do not know how to use it to relate the UUID of the characteristics with the "handle" parameter.

    What are the steps to get the "handle" parameter related with a UUID characteristic?

    Yes, I would recommend using the db discovery module for this. The usage of the module is detailed in the referenced documentation.
    You could also see this demonstrated in most of the central examples from the SDK. Take for example the Nordic UART central example - it starts database discovery on the CONNECTED event looking for the Nordic UART service on the connected device. If it is found the events are forwarded to the nus client event handler, which then assigns it a handle and enables notifications for the TX characteristic.
    In case of multiple services you could take a look at the Heart rate collector example, which discovers and uses 2 separate services.

    Please do not hesitate to ask if any part of this should still be unclear, or if you have any other questions!

    Best regards,
    Karl

Reply
  • Hello,

    But I do not how to retrieve the "handle" parameter. Again I guess I should use the discovery module but I do not know how to use it to relate the UUID of the characteristics with the "handle" parameter.

    What are the steps to get the "handle" parameter related with a UUID characteristic?

    Yes, I would recommend using the db discovery module for this. The usage of the module is detailed in the referenced documentation.
    You could also see this demonstrated in most of the central examples from the SDK. Take for example the Nordic UART central example - it starts database discovery on the CONNECTED event looking for the Nordic UART service on the connected device. If it is found the events are forwarded to the nus client event handler, which then assigns it a handle and enables notifications for the TX characteristic.
    In case of multiple services you could take a look at the Heart rate collector example, which discovers and uses 2 separate services.

    Please do not hesitate to ask if any part of this should still be unclear, or if you have any other questions!

    Best regards,
    Karl

Children
  • Thanks for your fast answer.

    As far I understand with the documentation and using the UART example, I should be able to do something like this:

    // Custom Service
    #define BLE_UUID_BASE_UUID {{0x91, 0x6B, 0xB6, 0xB9, 0x58, 0x9E, 0x75, 0x9B, \
                                 0xBF, 0x4D, 0x09, 0x8D, 0x00, 0xE0, 0x5A, 0xFA}} // 128-bit base UUID
    
    #define BLE_UUID_SERVICE_UUID                0xE000  
    
    // Defining 16-bit characteristic UUID
    #define BLE_UUID_COMMAND_CHARACTERISTC_UUID  0xE002 
    #define BLE_UUID_STATUS_CHARACTERISTC_UUID   0xE004
    #define BLE_UUID_DATA_CHARACTERISTC_UUID     0xE006 
    #define BLE_UUID_FOTA_CHARACTERISTC_UUID     0xE008 
    // Handler to perform operations over characteristics
    typedef struct 
    {
      uint16_t cmdHandler;    // BLE_UUID_COMMAND_CHARACTERISTC_UUID     
      uint16_t statusHandler; // BLE_UUID_STATUS_CHARACTERISTC_UUID     
      uint16_t dataHandler;   // BLE_UUID_DATA_CHARACTERISTC_UUID     
      uint16_t fotaHandler;   // BLE_UUID_FOTA_CHARACTERISTC_UUID     
    }tBLECharacteristicsHandler;
    static tBLECharacteristicsHandler charHnd;
    static uint16_t connHandler;
    
    //******************************************************************************
    tRetCode BLE_ReadCharacteristicStatus(void)
    //******************************************************************************
    // Description: 
    // Parameters: None 
    // Returns: error check 
    //******************************************************************************
    {
      uint32_t err = 0;
      err = sd_ble_gattc_read(connHandler, charHnd.statusHandler, 0);
      if (err  != NRF_SUCCESS)
      { return RES_ERROR;}
      return RES_OK;
    }
    
    //******************************************************************************
    static void DataBaseDiscoveryHandler(ble_db_discovery_evt_t * pEvt)
    //******************************************************************************
    // Description: This function is a callback function to handle events from the 
    //   database discovery module. Depending on the UUIDs that are discovered, this
    //   function forwards the events to their respective services.
    // Parameters: 
    //  ble_db_discovery_evt_t * pEvt: Pointer to the database discovery event
    // Returns: error check 
    //******************************************************************************
    {
      uint32_t i = 0;
      ble_gatt_db_char_t *pChars = pEvt->params.discovered_db.charateristics;
      ble_db_discovery_t const *pDb;
      pDb = (ble_db_discovery_t *)pEvt->params.p_db_instance;
    
      ble_hrs_on_db_disc_evt(BLE_HeartRateClientHandler(), pEvt);
    
      if (pEvt->evt_type == BLE_DB_DISCOVERY_AVAILABLE) 
      {
        NRF_LOG_INFO("DB Discovery instance %p available on conn handle: %d", pDb,
                      pEvt->conn_handle);
        NRF_LOG_INFO("Found %d services on conn_handle: %d", pDb->srv_count,
                     pEvt->conn_handle); 
      }
    
      if (pEvt->evt_type != BLE_DB_DISCOVERY_COMPLETE) return;
      connHandler = pEvt->conn_handle;
      for (i = 0; i < pEvt->params.discovered_db.char_count; i++)
      {
        switch (pChars[i].characteristic.uuid.uuid)
        {
        case BLE_UUID_COMMAND_CHARACTERISTC_UUID:
          charHnd.cmdHandler = pChars[i].characteristic.handle_value;
          break;
        case BLE_UUID_STATUS_CHARACTERISTC_UUID:
          charHnd.statusHandler = pChars[i].characteristic.handle_value;
          break;
        case BLE_UUID_DATA_CHARACTERISTC_UUID:
          charHnd.dataHandler = pChars[i].characteristic.handle_value;
          break;    
        case BLE_UUID_FOTA_CHARACTERISTC_UUID:
          charHnd.fotaHandler = pChars[i].characteristic.handle_value;
          break;    
        default:
          break;
        }
      }
    }
    
    //******************************************************************************
    static tRetCode BLE_RegisterUUID(uint16_t uuid)
    //******************************************************************************
    // Description: This function register a UUId to the discovery database
    // Parameters: uint16_t uuid: UUID to add 
    // Returns: error check 
    //******************************************************************************
    {
      ble_uuid_t charUuid;
      uint8_t uuidType = 0;
      ble_uuid128_t baseUuid = BLE_UUID_BASE_UUID;
    
      if (sd_ble_uuid_vs_add(&baseUuid, &uuidType) != NRF_SUCCESS)
      { return RES_ERROR;}
      charUuid.uuid = uuid;
      charUuid.type = uuidType;
      if (ble_db_discovery_evt_register(&charUuid) != NRF_SUCCESS)
      { return RES_ERROR;}
      return RES_OK;
    }
    
    //******************************************************************************
    tRetCode BLE_DataBaseDiscoveryInit(void)
    //******************************************************************************
    // Description: Database discovery initialization.
    // Parameters: None 
    // Returns: error check 
    //******************************************************************************
    {
      ble_db_discovery_init_t dbInit;
    
      memset(&dbInit, 0, sizeof(dbInit));
    
      dbInit.evt_handler  = DataBaseDiscoveryHandler;
      dbInit.p_gatt_queue = &gattQueue;
    
      if (ble_db_discovery_init(&dbInit) != NRF_SUCCESS) return RES_ERROR;
    
      if (BLE_RegisterUUID(BLE_UUID_COMMAND_CHARACTERISTC_UUID) != RES_OK)
      { return RES_ERROR;}
      if (BLE_RegisterUUID(BLE_UUID_STATUS_CHARACTERISTC_UUID) != RES_OK)
      { return RES_ERROR;}
      if (BLE_RegisterUUID(BLE_UUID_DATA_CHARACTERISTC_UUID) != RES_OK)
      { return RES_ERROR;}
      if (BLE_RegisterUUID(BLE_UUID_FOTA_CHARACTERISTC_UUID) != RES_OK)
      { return RES_ERROR;}
    
      return RES_OK;
    }

    Where ble_db_discovery_start() is called at BLE_GAP_EVT_CONNECTED event.

    And after all, I should be able to call BLE_ReadCharacteristicStatus() to read the data in the BLE_GATTC_EVT_READ_RSP event.

    Am I wrong with the aproximation?

    The problem is that I never get BLE_DB_DISCOVERY_COMPLETE in the discover event. And, at 

    BLE_DB_DISCOVERY_AVAILABLE I get this in the debugger:
    This are the peripheral services and characteristics, the peripheral is mature product of my company and works successfully with other centrals.

    What am I doing wrong?

    Thanks for your help,

  • Angel said:
    Thanks for your fast answer.

    No problem at all, I am happy to help! :) 

    Angel said:
    As far I understand with the documentation and using the UART example, I should be able to do something like this:

    No, I think there might be a couple of possible things going wrong here.
    For example, you're registering the UUID's for service discovery and base UUID with the type UNKNOWN, since its 0. Do you get any runtime errors?
    From the services list I assume that you are going to accept notifications from some of these services, is this correct?
    I recommend that you create a separate source file for the services you will be accessing, akin to ble_lbs_c.c, ble_hrs_c.c, ble_bas_c.c, etc. You could take any one of the existing services source and header files to use as a template for this. This is best practice, rather than having it all be part of your main.c

    You might also want to make use of the GATT Queue library when working with multiple services and characteristics. The use of the GATT Queue library is also demonstrated in the BLE Central examples.

    Best regards,
    Karl

Related