Using ble_db_discovery to find the DFU service

I understand there isn't a code example of the DFU updater since it is expected that we will use a phone or other device running the Nordic app to deploy updates, but in my case I am trying to implement the update process from a nRF52833. I'm able to scan for and connect to a "DfuTarg" (running a generic secure_bootloader_ble project), but run into trouble when I try to discover the services and update the local discovery db.

// Init Macros
BLE_DB_DISCOVERY_DEF(m_db_disc);
NRF_BLE_GQ_DEF(m_ble_gatt_queue,
               NRF_SDH_BLE_CENTRAL_LINK_COUNT,
               NRF_BLE_GQ_QUEUE_SIZE);

// From bootloader_ble project
#define DFU_UUID_BASE  {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, \
                        0x60, 0x4F, 0x15, 0xF3,  0x00, 0x00, 0xC9, 0x8E}
#define DFU_UUID_SERVICE 0xFE59

// Base and Service UUID
static ble_uuid128_t dfu_base_uuid = {DFU_UUID_BASE};
static ble_uuid_t dfu_uuid = 
{
  .type = BLE_UUID_TYPE_VENDOR_BEGIN,
  .uuid = DFU_UUID_SERVICE,
};

// Discovery Handler
static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
    nrf_delay_us(1);  // Testing Breakpoint
}

// Discovery Init
static void db_discovery_init(void)
{
    ble_db_discovery_init_t db_init;

    memset(&db_init, 0, sizeof(db_init));

    db_init.evt_handler  = db_disc_handler;
    db_init.p_gatt_queue = &m_ble_gatt_queue;

    ret_code_t err_code = ble_db_discovery_init(&db_init);
    APP_ERROR_CHECK(err_code);
}

// Setup
void discovery_setup(void)
{
	db_discovery_init();

	sd_ble_uuid_vs_add(&dfu_base_uuid, &dfu_uuid.type);

	ble_db_discovery_evt_register(&dfu_uuid);
}

// Start
uint32_t discovery_start(uint16_t conn_handle)
{
  return ble_db_discovery_start(&m_db_disc, conn_handle);
}

My current thought is that my assumption that the DFU service UUID is "vendor specific" and uses the same base UUID as the characteristics is incorrect, but without an example project I'm not sure what it should be.

I start discovery by calling "discovery_start()" within my BLE_GAP_EVT_CONNECTED case in the main BLE event handler, and pass in the p_gap_evt->conn_handle. This triggers two event responses at my breakpoint in the discovery handler, neither is what I think I'm looking for.

First, a BLE_DB_DISCOVERY_SRV_NOT_FOUND response that appears to be referencing what I'm targeting, just unsuccessfully:

Second, a BLE_DB_DISCOVERY_AVAILABLE response, but from a UUID that doesn't match the DFU service running on the BLE bootloader (UUID 0x2CAC):

I tried to cut down the code to the meaningful bits relating to discovery, but if everything above looks OK or more context would help let me know. Any insight would be appreciated!

Thanks.

*edit* Added m_ble_gatt_queue macro definition that was missing before, but used in the initialization of the discovery db.

Parents
  • One more update to take this through to complete discovery. You do need to call sd_ble_uuid_vs_add(), but for the characteristic UUIDs so db_discovery can find them. Small tweaks to the initial code above.

    // Init Macros
    BLE_DB_DISCOVERY_DEF(m_db_disc);
    NRF_BLE_GQ_DEF(m_ble_gatt_queue,
                   NRF_SDH_BLE_CENTRAL_LINK_COUNT,
                   NRF_BLE_GQ_QUEUE_SIZE);
    
    // From bootloader_ble project
    #define DFU_UUID_SERVICE 0xFE59
    #define DFU_CONTROL_POINT_UUID 0x0001
    #define DFU_PACKET_UUID 0x0002
    #define DFU_UUID_BASE  {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, \
                            0x60, 0x4F, 0x15, 0xF3,  0x00, 0x00, 0xC9, 0x8E}
    
    // UUID Defines
    static ble_uuid128_t dfu_base_uuid = {DFU_UUID_BASE};
    static ble_uuid_t dfu_service_uuid = 
    {
      .type = BLE_UUID_TYPE_BLE,
      .uuid = DFU_UUID_SERVICE,
    };
    static ble_uuid_t dfu_control_point_uuid = {
      .type = BLE_UUID_TYPE_VENDOR_BEGIN,
      .uuid = DFU_CONTROL_POINT_UUID,
    };
    static ble_uuid_t dfu_packet_uuid = {
      .type = BLE_UUID_TYPE_VENDOR_BEGIN,
      .uuid = DFU_PACKET_UUID,
    };
    
    // Discovery Handler
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        nrf_delay_us(1);  // Testing Breakpoint
    }
    
    // Discovery Init
    static void db_discovery_init(void)
    {
        ble_db_discovery_init_t db_init;
    
        memset(&db_init, 0, sizeof(db_init));
    
        db_init.evt_handler  = db_disc_handler;
        db_init.p_gatt_queue = &m_ble_gatt_queue;
    
        ret_code_t err_code = ble_db_discovery_init(&db_init);
        APP_ERROR_CHECK(err_code);
    }
    
    // Setup
    void discovery_setup(void)
    {
    	db_discovery_init();
    
      // Register Characteristic UUIDs with the SoftDevice so they can be found during discovery
    	sd_ble_uuid_vs_add(&dfu_base_uuid, &dfu_control_point_uuid.type);
      sd_ble_uuid_vs_add(&dfu_base_uuid, &dfu_packet_uuid.type);
    
      // Register Service UUID with db_discovery
    	ble_db_discovery_evt_register(&dfu_service_uuid);
    }
    
    // Start
    uint32_t discovery_start(uint16_t conn_handle)
    {
      return ble_db_discovery_start(&m_db_disc, conn_handle);
    }

    Hopefully this helps somebody else!

Reply
  • One more update to take this through to complete discovery. You do need to call sd_ble_uuid_vs_add(), but for the characteristic UUIDs so db_discovery can find them. Small tweaks to the initial code above.

    // Init Macros
    BLE_DB_DISCOVERY_DEF(m_db_disc);
    NRF_BLE_GQ_DEF(m_ble_gatt_queue,
                   NRF_SDH_BLE_CENTRAL_LINK_COUNT,
                   NRF_BLE_GQ_QUEUE_SIZE);
    
    // From bootloader_ble project
    #define DFU_UUID_SERVICE 0xFE59
    #define DFU_CONTROL_POINT_UUID 0x0001
    #define DFU_PACKET_UUID 0x0002
    #define DFU_UUID_BASE  {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, \
                            0x60, 0x4F, 0x15, 0xF3,  0x00, 0x00, 0xC9, 0x8E}
    
    // UUID Defines
    static ble_uuid128_t dfu_base_uuid = {DFU_UUID_BASE};
    static ble_uuid_t dfu_service_uuid = 
    {
      .type = BLE_UUID_TYPE_BLE,
      .uuid = DFU_UUID_SERVICE,
    };
    static ble_uuid_t dfu_control_point_uuid = {
      .type = BLE_UUID_TYPE_VENDOR_BEGIN,
      .uuid = DFU_CONTROL_POINT_UUID,
    };
    static ble_uuid_t dfu_packet_uuid = {
      .type = BLE_UUID_TYPE_VENDOR_BEGIN,
      .uuid = DFU_PACKET_UUID,
    };
    
    // Discovery Handler
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        nrf_delay_us(1);  // Testing Breakpoint
    }
    
    // Discovery Init
    static void db_discovery_init(void)
    {
        ble_db_discovery_init_t db_init;
    
        memset(&db_init, 0, sizeof(db_init));
    
        db_init.evt_handler  = db_disc_handler;
        db_init.p_gatt_queue = &m_ble_gatt_queue;
    
        ret_code_t err_code = ble_db_discovery_init(&db_init);
        APP_ERROR_CHECK(err_code);
    }
    
    // Setup
    void discovery_setup(void)
    {
    	db_discovery_init();
    
      // Register Characteristic UUIDs with the SoftDevice so they can be found during discovery
    	sd_ble_uuid_vs_add(&dfu_base_uuid, &dfu_control_point_uuid.type);
      sd_ble_uuid_vs_add(&dfu_base_uuid, &dfu_packet_uuid.type);
    
      // Register Service UUID with db_discovery
    	ble_db_discovery_evt_register(&dfu_service_uuid);
    }
    
    // Start
    uint32_t discovery_start(uint16_t conn_handle)
    {
      return ble_db_discovery_start(&m_db_disc, conn_handle);
    }

    Hopefully this helps somebody else!

Children
  • Hi  , I did what you did but got and error for sd_ble_uuid_vs_add. The discovery did complete (if I don't check for error) but not for those characteristics. It only found one characteristic - 0x0000. I can confirm that the peripheral code itself can show advertisement of characteristic UUID 8EC90003F3154F609FB8838830DAEA50. So the problem is definitely on the central code. Also, I'm curious about how sd_ble_uuid_vs_add knows the characteristic UUID when it's not part of the input?

    Any assistance would be really appreciated. Thanks in advance.

  • If you're getting an error calling sd_ble_uuid_vs_add, that's likely your issue since that should be returning NRF_SUCCESS. Checking ble.h for the potential errors, and I'm betting you are getting an NRF_ERROR_NO_MEM (er:4) indicating you don't have any free vendor-specific UUID slots available.

    Check your sdk_config.h file and ensure that NRF_SDH_BLE_VS_UUID_COUNT is set to at least 1. Reading more closely, I think the second call I'm making to 'sd_ble_uuid_vs_add' just aliases to the first and returns success, but is unnecessary since both ble_uuid_t structs have the same 'type' property so the calls are identical.

  • Thanks for your help, Jeremy, that is indeed the case.

Related