In BLE Master, get GATT Services and characteristics about a peripheral. (nrf5_SDK)

Hello, I want to get information list about BLE GATT services and characteristics of a device.

I want to connect to a peripheral with a specific name, then  get all metadata about the device and store it in a structure.

I couldn't find a specific example about generic discovery.  The SDK provide API for different kind of official service.

I have taken a look here to see what can exist.

- Bluetooth low energy Characteristics, a beginner's tutorial

- Discovering Different UUID base of service and characteristics from BLE Central

- S130 Custom UUID Service discovery

- nrf connect sdk - generic discovery and reading/writing Gatt services and characteristics

- What is the best way to get these data with nrf5_SDK ?

- How I can read/wirte/be notified after that ? (set specific handle ? )

Configuration:

- Bluetooth : SoftDevice S132.

- SDK : nRF5_SDK_17.1.0_ddde560

Regards,

lilian

  • Using  "ble_db_discovery" API is the good way to do this ?

    typedef struct
    {
        ble_db_discovery_evt_type_t evt_type;    /**< Type of event. */
        uint16_t                    conn_handle; /**< Handle of the connection for which this event has occurred. */
        union
        {
            ble_gatt_db_srv_t   discovered_db;  /**< Structure containing the information about the GATT Database at the server. This will be filled when the event type is @ref BLE_DB_DISCOVERY_COMPLETE. The UUID field of this will be filled when the event type is @ref BLE_DB_DISCOVERY_SRV_NOT_FOUND. */
            void const        * p_db_instance;  /**< Pointer to DB discovery instance @ref ble_db_discovery_t, indicating availability to the new discovery process. This will be filled when the event type is @ref BLE_DB_DISCOVERY_AVAILABLE. */
            uint32_t            err_code;       /**< nRF Error code indicating the type of error which occurred in the DB Discovery module. This will be filled when the event type is @ref BLE_DB_DISCOVERY_ERROR. */
        } params;
    } ble_db_discovery_evt_t;
    
    ...
    
    static void _db_disc_handler(ble_db_discovery_evt_t* p_evt)
    {
         .... // Get informations here.
    }
    
    

  • Yes. Look at how e.g. the ble_app_uart_c does service discovery and uses the db_disc_handler() to call ble_nus_c_on_db_disc_evt(). I know that ble_nus_c_on_db_disc_evt() is service specific, but you can look at the implementation how it checks the service UUID in the handler. Instead of comparing it to a known UUID, you can do whatever you like with that information. 

    Best regards,

    Edvin

  • Thank you for your answer. I looked at how the example works.

    I managed to get the characteristics of a service using the API.

    ble_uuid_t puuid = { .type= BLE_UUID_TYPE_BLE, .uuid = 0x1170};
    ble_db_discovery_evt_register(&puuid);
    ble_db_discovery_start(&_xDbDiscovery, p_ble_evt->evt.gap_evt.conn_handle);


    However, I need to know the UUID of the service before launching a discovery start.

    - Is there a way to find out which UUIDs are available on the device before starting the discovery scan?

    - If I understand correctly, I need to register each UUID  that I want to discover in the device before ble_db_discovery_start ?

  • ZaltoEver said:
    Is there a way to find out which UUIDs are available on the device before starting the discovery scan?

    No. That is the point of the service discovery. To discover what UUIDs that are available on the device.

    ZaltoEver said:
    - If I understand correctly, I need to register each UUID  that I want to discover in the device before ble_db_discovery_start ?

    The reason I pointed to the ble_app_uart_c example is that this starts the discovery process without knowing the UUID up front. You can see how the discovery is started in the BLE_GAP_EVT_CONNECTED event in ble_evt_handler() in main.c.

    This will trigger callbacks (for each service) in db_disc_handler(), which in this case is handled by ble_nus_c_on_db_disc_evt(), but you can handle it in any function. the ble_nus_c_on_db_disc_evt() is just an example comparing the UUID of a preknown UUID. The UUID in the callback is present in:

    p_evt->params.discovered_db.srv_uuid.uuid

    the number of characteristics in that service will be present in p_evt->params.discovered_db.char_count

    and the characteristics UUIDs will be present in:

    p_evt->params.discovered_db.charateristics[i].characteristic.uuid

    And all of these are used for reference in ble_nus_c_on_db_disc_evt() in the ble_app_uart_c example.

    BR,

    Edvin

  • However, when I read the source code, I see that the NUS service registers a UUID.

    uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
    {
        uint32_t      err_code;
        ble_uuid_t    uart_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init->p_gatt_queue);
    
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        uart_uuid.type = p_ble_nus_c->uuid_type;
        uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        p_ble_nus_c->conn_handle           = BLE_CONN_HANDLE_INVALID;
        p_ble_nus_c->evt_handler           = p_ble_nus_c_init->evt_handler;
        p_ble_nus_c->error_handler         = p_ble_nus_c_init->error_handler;
        p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->p_gatt_queue          = p_ble_nus_c_init->p_gatt_queue;
    
        return ble_db_discovery_evt_register(&uart_uuid);
    }

    This seems logic because I am unable to start a discovery without register a service first (error 8). The variable "m_num_of_handlers_reg" is equal to 0.

    uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery, uint16_t conn_handle)
    {
        VERIFY_PARAM_NOT_NULL(p_db_discovery);
        VERIFY_MODULE_INITIALIZED();
    
        if (m_num_of_handlers_reg == 0)
        {
            // No user modules were registered. There are no services to discover.
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (p_db_discovery->discovery_in_progress)
        {
            return NRF_ERROR_BUSY;
        }
    
        return discovery_start(p_db_discovery, conn_handle);
    }
    

    When I start the scan:

    - With good UUID registered,  I then have 2 events :  BLE_DB_DISCOVERY_SRV_NOT_FOUND and BLE_DB_DISCOVERY_AVAILABLE

    - Without good UUID registered,  I then have 2 events :  BLE_DB_DISCOVERY_COMPLETE and BLE_DB_DISCOVERY_AVAILABLE

    Sorry for the misunderstanding. I want to know the services UUIDs on the peripheral device before those of the characteristics.
    It is possible ?


    Lilian
Related