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

Service Discovery Failed using pc-ble-driver

I am using an nRF52840 Dongle to try and connect to a product over Bluetooth and communicate with it. I have been able to open this dongle using nRF Connect Bluetooth Low Energy, and can successfully find my product, connect to it, and write to its characteristics. I am now needing to use a C program to do this same thing.

I have downloaded the pc-ble-driver, created a project in my C IDE, and copied the code from the heart rate collector example to be the project's source file. I got the project to build without issue, and following the instructions in the examples github page, have flashed the dongle with the correct firmware to allow the c program to connect to it. I am able to successfully connect to the dongle's COM port and scan for devices.

I did have to make some modifications to the source file. My product I want to connect to doesn't advertise its name, so I was unable to connect to it even when finding it. This product does, however, advertise the Manufacturer Specific Data field, and after some trial and error, I was able to modify the find_adv_name routine to instead check for Manufacturer Specific Data, and I was able to connect to the device this way.

After this, I get output strings that read: "Connection Established", "Discovering Primary Services", and "Received Service Discovery Response". However, I then get an error message saying "Service Discovery Failed. Error Code 0x10A". Stepping through the code, this error is getting set after the "on_connected" routine is finished, but before starting the on_service_discovery_response routine.

I have changed the value of BLE_UUID_HEART_RATE_SERVICE to match the UUID of my product's service, but there was no effect. I had also been told in the past to try changing the srvc_uuid.type from BLE_UUID_TYPE_BLE to BLE_UUID_TYPE_VENDOR_BEGIN, but when doing this, I get a failure returned from the function "sd_ble_gattc_primary_services_discover", with the error code 0x8005, which seemingly corresponds to NRF_ERROR_SD_RPC_NO_RESPONSE. 

Could anyone give me any pointers for where to look for what all to change in the source code in order to connect to my product rather than whatever heart rate monitor it is expecting? Thanks!

Parents
  • Ok, so I think I may have been getting the 0x8005 error due to stopping the program with a breakpoint, and the BLE device losing connectivity when stepping through slowly. I moved the breakpoint to right at the printing of the error message, and now my error code is consistently 0x7, which (according to nrf_error.h) should be an invalid parameter error.

    Considering this does not result in an error when I have srvc_uuid.type set to BLE_UUID_TYPE_BLE, I am assuming the invalid parameter is my srvc_uuid struct. I have been trying to figure out how exactly to set the "uuid" parameter of this struct properly. According to the struct definition, it should be either the 16bit uuid, or "octets 12-13" of the 128bit uuid. Considering I'm using BLE_UUID_TYPE_VENDOR_BEGIN, I'm guessing it will need to be the 2nd option.

    How do I determine what "octets 12-13" are though? Is this a little endian value? Big endian? Does it begin at octet 0, or 1? My full 128bit uuid is 17C30001EB0747848BF33212453B0D32. Thanks!

  • mmercier said:
    Is this a little endian value? Big endian?

    It is probably reversed, but I see it listed a bit different in different places. Let us say that the long UUID is "17C30001-EB07-4784-8BF3-3212453B0D32", then the UUID would be something like:

    "0100C317-07EB-8447-F38B-320D3B451232" in the source code.

    What you should do is to look at the examples. If you have an 128-bit UUID, you should look at the examples that use a 128-bit UUID, such as the ble_app_uart example. Try to flash it, and compare the UUID you get in nRF Connect to the one that is listed in ble_nus.c on line 64 in the SDK16.0.0:

    #define NUS_BASE_UUID                  {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */

    When I connect to it in nRF Connect, it says:

    (you have to hover the mouse over the service to see the UUID when it is one of the standards in nRF Connect)

    So it translates to:

    6E400001B5A3F393E0A9E50E24DCCA9E

    While the raw UUID from ble_nus.c:

    9ECADC240EE5A9E093F3A3B50000406E

    Or:

    6E400001-B5A3-F393-E0A9-E50E24DCCA9E

    9ECADC24-0EE5-A9E0-93F3-A3B50000406E

    So it is basically reversed, but notice that one of the 0000 are replaced with 0001, which is the service UUID. You will note that the characteristic UUIDs are identical, but the 0001 are switched to 0002 and 0003 for each of the characteristics.

    BR,

    Edvin

  • Here is the product when connected in nRF Connect.

  • Would you be able to let me know the functions I need to call in order to connect to this service using the pc-ble-driver C program? Thanks.

  • I did some more experimenting with different functions. I found a function called "sd_ble_uuid_vs_add", which is supposed to add a vendor specific UUID to the program. I defined a struct of type ble_uuid128_t, and assigned its 16-length array to be my device's full 128-bit UUID (in little endian format, ie, srvc_uuid128[0] = 0x32, srvc_uuid128[1] = 0x0D, etc).

    I assigned this function to return an error code and print a fail message if it isn't equal to NRF_SUCCESS, and I made it past this function with no errors. I am also now making it past the "sd_ble_gattc_primary_services_discover" function without error (using 0x0100 as my 16-bit UUID, based on the service).

    However, I am now receiving an error message at the "on_service_discovery_response" function. The very first thing checked is the "gatt_status" parameter of the "p_ble_gattc_evt" object. This is failing with an error code of 0x10A. I tried searching the header files for an 0x10A, with no results, and for an 0x100. The only result I found was an error code that corresponds to 0x100 + some constant, which is defined as 0x3000, so this clearly isn't my error message.

    So I am now at the point where I began, before trying to make changes to the UUID properties. Could you please help me to determine what this 0x10A error message means, and what to do about this? Thanks.

  • I believe I've found the error, I needed to search for 0x0100 instead of 0x100.

    It looks like this error message is called BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND. So there is some attribute not being found when the service is being discovered. Unfortunately, since this is not in response to any function call, I have no idea what is setting this variable. It is the "gatt_status" parameter of the ble_evt object's evt.gattc_evt parameter, which is passed to the "on_service_discovery_response" function by the event handler.

    Doing more studying with breakpoints, it looks like this "gatt_status" variable remains at 0 through the entire "on_connected" routine, even after finishing and ending the pass through the event handler's loop. But then, when the event handler enters its next pass (going to the case for BLE_GATTC_EVT_PRIM_SRVC_DISC_RESP), this value is now set to 0x10A.

    So whatever is changing the evt_id, I'm assuming, is responsible for changing the "gatt_status" parameter, and it's being set to this error code.

    Could you please help me figure out what attribute is not being found? Thanks.

  • Where exactly does the BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND appear?

    Is db_disc_handler() called? Or whatever function that is set to the event handler that is passed onto ble_db_discovery_init():

    /** @brief Function for initializing the database discovery module. */
    static void db_discovery_init(void)
    {
        ble_db_discovery_init_t db_init;
    
        memset(&db_init, 0, sizeof(ble_db_discovery_init_t));
    
        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);
    }

    Does it have:

    p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE?

    If so, what is p_evt->params.discovered_db.srv_uuid.uuid?

    If this event does not occur, can you show me how you initialize the central service on your central?

     

    mmercier said:
    Doing more studying with breakpoints, it looks like this "gatt_status" variable remains at 0 through the entire "on_connected"

     What do you mean by gatt_status? Can you show some snippets? In what event do you expect this to change? Are you talking about the 

    p_ble_gattc_evt->gatt_status? If so, 0 means BLE_GATT_STATUS_SUCCESS, so this being 0 is not unexpected.

    Are you talking about the on_primary_srv_discovery_rsp()? If so, does it print anything from this callback?

Reply
  • Where exactly does the BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND appear?

    Is db_disc_handler() called? Or whatever function that is set to the event handler that is passed onto ble_db_discovery_init():

    /** @brief Function for initializing the database discovery module. */
    static void db_discovery_init(void)
    {
        ble_db_discovery_init_t db_init;
    
        memset(&db_init, 0, sizeof(ble_db_discovery_init_t));
    
        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);
    }

    Does it have:

    p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE?

    If so, what is p_evt->params.discovered_db.srv_uuid.uuid?

    If this event does not occur, can you show me how you initialize the central service on your central?

     

    mmercier said:
    Doing more studying with breakpoints, it looks like this "gatt_status" variable remains at 0 through the entire "on_connected"

     What do you mean by gatt_status? Can you show some snippets? In what event do you expect this to change? Are you talking about the 

    p_ble_gattc_evt->gatt_status? If so, 0 means BLE_GATT_STATUS_SUCCESS, so this being 0 is not unexpected.

    Are you talking about the on_primary_srv_discovery_rsp()? If so, does it print anything from this callback?

Children
  • My code is based on the Heart Rate Collector example from the pc-ble-driver package, and has not been changed in terms of the event handler and any setup functions. Here is the event handler, for reference:

    static void ble_evt_dispatch(adapter_t * adapter, ble_evt_t * p_ble_evt)
    {
    if (p_ble_evt == NULL)
    {
    printf("Received an empty BLE event\n");
    fflush(stdout);
    return;
    }

    switch (p_ble_evt->header.evt_id)
    {
    case BLE_GAP_EVT_CONNECTED:
    on_connected(&(p_ble_evt->evt.gap_evt));
    break;

    case BLE_GAP_EVT_DISCONNECTED:
    printf("Disconnected, reason: 0x%02X\n",
    p_ble_evt->evt.gap_evt.params.disconnected.reason);
    fflush(stdout);
    m_connected_devices--;
    m_connection_handle = 0;
    break;

    case BLE_GAP_EVT_ADV_REPORT:
    on_adv_report(&(p_ble_evt->evt.gap_evt));
    break;

    case BLE_GAP_EVT_TIMEOUT:
    on_timeout(&(p_ble_evt->evt.gap_evt));
    break;

    case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
    on_service_discovery_response(&(p_ble_evt->evt.gattc_evt));
    break;

    case BLE_GATTC_EVT_CHAR_DISC_RSP:
    on_characteristic_discovery_response(&(p_ble_evt->evt.gattc_evt));
    break;

    case BLE_GATTC_EVT_DESC_DISC_RSP:
    on_descriptor_discovery_response(&(p_ble_evt->evt.gattc_evt));
    break;

    case BLE_GATTC_EVT_WRITE_RSP:
    on_write_response(&(p_ble_evt->evt.gattc_evt));
    break;

    case BLE_GATTC_EVT_HVX:
    on_hvx(&(p_ble_evt->evt.gattc_evt));
    break;

    case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
    on_conn_params_update_request(&(p_ble_evt->evt.gap_evt));
    break;

    case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
    on_exchange_mtu_request(&(p_ble_evt->evt.gatts_evt));
    break;

    case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
    on_exchange_mtu_response(&(p_ble_evt->evt.gattc_evt));
    break;

    default:
    printf("Received an un-handled event with ID: %d\n", p_ble_evt->header.evt_id);
    fflush(stdout);
    break;
    }
    }

    Previously, my issue with the UUIDs had occurred within the "on_connected" routine, but now, with the changes I described above, I've been able to move past this routine without errors. On the next pass through the event handler, I am entering the case for the "on_service_discovery_response" routine, and this is where I run into the error.

    The very first thing done in the "on_service_discovery_response" routine is to check the "gatt_status" parameter of the struct being passed to the function (in this case, p_ble_evt->evt.gattc_evt is being passed, as can be seen above). If gatt_status is equal to 0, then the routine continues on, but displays an error message if it is anything else. In my case, I am getting error message 0x10A, which seems to correspond to BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND.

    I stepped through the code using breakpoints to monitor this value, and see if I can figure out where it is being changed to 0x10A. As I mentioned, the event handler goes through the case for "on_connected" immediately before the case where I am seeing the error. During this entire pass through the event handler, the "gatt_status" parameter of p_ble_evt->evt.gattc_evt is equal to 0. This is true for when the "on_connected" routine is being executed, and for afterward, when the event handler case ends and goes to the end of the function.

    However, when the event handler then enters its next pass, the "gatt_status" suddenly changes to 0x10A. I do not know what all is going on between passes through the event handler. I am assuming it is done using the library functions, but just stepping through, I don't see anything occurring between passes. Either way, something is occurring, since the value of p_ble_evt->header.evt_id is changing (so that the event handler enters a different case), and I am assuming whatever changes this value is also responsible for setting the gatt_status.

    If it helps, the only code I've modified is the "on_adv_report" routine (to check for Manufacturer Specific Data rather than Device Name) and the "service_discovery_start" routine (to add the 128-bit UUID, as described above). Other than that, my code is effectively identical to the heart rate collector example in the pc-ble-driver github page.

  • Adding your code using insert->code for readability:

    static void ble_evt_dispatch(adapter_t * adapter, ble_evt_t * p_ble_evt)
    {
        if (p_ble_evt == NULL)
        {
            printf("Received an empty BLE event\n");
            fflush(stdout);
            return;
        }
        
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                on_connected(&(p_ble_evt->evt.gap_evt));
                break;
            
            case BLE_GAP_EVT_DISCONNECTED:
                printf("Disconnected, reason: 0x%02X\n",
                p_ble_evt->evt.gap_evt.params.disconnected.reason);
                fflush(stdout);
                m_connected_devices--;
                m_connection_handle = 0;
                break;
            
            case BLE_GAP_EVT_ADV_REPORT:
                on_adv_report(&(p_ble_evt->evt.gap_evt));
                break;
            
            case BLE_GAP_EVT_TIMEOUT:
                on_timeout(&(p_ble_evt->evt.gap_evt));
                break;
            
            case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
                on_service_discovery_response(&(p_ble_evt->evt.gattc_evt));
                break;
            
            case BLE_GATTC_EVT_CHAR_DISC_RSP:
                on_characteristic_discovery_response(&(p_ble_evt->evt.gattc_evt));
                break;
            
            case BLE_GATTC_EVT_DESC_DISC_RSP:
                on_descriptor_discovery_response(&(p_ble_evt->evt.gattc_evt));
                break;
            
            case BLE_GATTC_EVT_WRITE_RSP:
                on_write_response(&(p_ble_evt->evt.gattc_evt));
                break;
            
            case BLE_GATTC_EVT_HVX:
                on_hvx(&(p_ble_evt->evt.gattc_evt));
                break;
            
            case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
                on_conn_params_update_request(&(p_ble_evt->evt.gap_evt));
                break;
            
            case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
                on_exchange_mtu_request(&(p_ble_evt->evt.gatts_evt));
                break;
            
            case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
                on_exchange_mtu_response(&(p_ble_evt->evt.gattc_evt));
                break;
            
            default:
                printf("Received an un-handled event with ID: %d\n", p_ble_evt->header.evt_id);
                fflush(stdout);
                break;
        }
    }

  • What does your on_connected() look like, then?

     

    mmercier said:
    If it helps, the only code I've modified is the "on_adv_report" routine

     That is probably the issue, because this example will by default look for the HRS UUID in the service discovery. This is why I keep pointing to the SDK example ble_app_uart_c, because it shows you how to look for a long (128-bit) UUID, which you then need to modify to your own.

    If you haven't changed it, your on_connected() function looks like this, right?

    static void on_connected(const ble_gap_evt_t * const p_ble_gap_evt)
    {
        printf("Connection established\n");
        fflush(stdout);
    
        m_connected_devices++;
        m_connection_handle         = p_ble_gap_evt->conn_handle;
        m_connection_is_in_progress = false;
    
        service_discovery_start();
    }

    And your service_discover_start() looks like this:

    static uint32_t service_discovery_start()
    {
        uint32_t   err_code;
        uint16_t   start_handle = 0x01;
        ble_uuid_t srvc_uuid;
    
        printf("Discovering primary services\n");
        fflush(stdout);
    
        srvc_uuid.type = BLE_UUID_TYPE_BLE;
        srvc_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;
    
        // Initiate procedure to find the primary BLE_UUID_HEART_RATE_SERVICE.
        err_code = sd_ble_gattc_primary_services_discover(m_adapter,
                                                          m_connection_handle, start_handle,
                                                          &srvc_uuid);
        if (err_code != NRF_SUCCESS)
        {
            printf("Failed to initiate or continue a GATT Primary Service Discovery procedure\n");
            fflush(stdout);
        }
    
        return err_code;
    }

    What does service_discover_start()? And did you modify it somehow? If not, I suggest you try to change BLE_UUID_TYPE_BLE and BLE_UUID_HEART_RATE_SERVICE according to the device that you are trying to connect to.

    Don't use BLE_UUID_TYPE_BLE, because these are the 16-bit UUIDs defined by Bluetooth. You want to use BLE_UUID_TYPE_VENDOR_BEGIN, which are the 128-bit UUIDs. Then you need to change the BLE_UUID_HEART_RATE_SERVICE to a variable containing the UUID that you are expecting to find.

    Look at how this is done in SDK16.0.0\examples\ble_central\ble_app_uart_c.

    If you look in ble_nus_c_init(). the base_uuid is added as NUS_BASE_UUID, and the discovery is registered as uart_uuid.

    Now, I have not tried this with pc-ble-driver, which works a bit different, but you need to change the srvc_uuid that you pass on in service_discovery_start. Try to do this, and see if you can manage to make it discover the custom uuid.

  • I have been describing my modifications to the "service_discovery_start" routine in the above posts, as this is the routine that I'd been originally seeing errors in. For reference, here is the code for this routine:

    static uint32_t service_discovery_start()
    {
        uint32_t   err_code;
        uint16_t   start_handle = 0x01;
        ble_uuid_t srvc_uuid;
    	ble_uuid128_t srvc_uuid128;
    
        printf("Discovering primary services\n");
        fflush(stdout);
    
        //srvc_uuid.type = BLE_UUID_TYPE_BLE;
        srvc_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN;
        //srvc_uuid.type = BLE_UUID_TYPE_UNKNOWN;
        srvc_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;
    	
    	//for(int i=0;i<16;i++)
    		//srvc_uuid128.uuid128[i] = BLE_UUID_LONG[i];
        	//printf("%02X ", BLE_UUID_LONG[i]);
    	srvc_uuid128.uuid128[0] = 0x32;
    	srvc_uuid128.uuid128[1] = 0x0D;
    	srvc_uuid128.uuid128[2] = 0x3B;
    	srvc_uuid128.uuid128[3] = 0x45;
    	srvc_uuid128.uuid128[4] = 0x12;
    	srvc_uuid128.uuid128[5] = 0x32;
    	srvc_uuid128.uuid128[6] = 0xF3;
    	srvc_uuid128.uuid128[7] = 0x8B;
    	srvc_uuid128.uuid128[8] = 0x84;
    	srvc_uuid128.uuid128[9] = 0x47;
    	srvc_uuid128.uuid128[10] = 0x07;
    	srvc_uuid128.uuid128[11] = 0xEB;
    	srvc_uuid128.uuid128[12] = 0x00;
    	srvc_uuid128.uuid128[13] = 0x00;
    	srvc_uuid128.uuid128[14] = 0xC3;
    	srvc_uuid128.uuid128[15] = 0x17;
    	
    	err_code = sd_ble_uuid_vs_add(m_adapter, &srvc_uuid128, &srvc_uuid.type);
    	
    	if (err_code != NRF_SUCCESS)
        {
            printf("Failed to add custom 128-bit UUID\n");
            fflush(stdout);
        }
    
        // Initiate procedure to find the primary BLE_UUID_HEART_RATE_SERVICE.
        err_code = sd_ble_gattc_primary_services_discover(m_adapter,
                                                          m_connection_handle, start_handle,
                                                          &srvc_uuid);
                                                          //NULL);
        if (err_code != NRF_SUCCESS)
        {
            printf("Failed to initiate or continue a GATT Primary Service Discovery procedure\n");
            fflush(stdout);
        }
    
        return err_code;
    }

    The "on_connected" routine is identical to what you've posted. As you can see, I've changed the type parameter of the srvc_uuid struct to BLE_UUID_TYPE_VENDOR_BEGIN, and I've defined a new struct (srvc_uuid128) which I've populated with the values of my device's 128-bit UUID. I've added a call to "sd_ble_uuid_vs_add" to add this 128-bit UUID to the list of available UUIDs, and this does not return an error code.

    I've also changed the value of BLE_UUID_HEART_RATE_SERVICE to 0x0100, to match with octets 12-13 of my service UUID. For reference, the full UUID of the service is 17C30001EB0747848BF33212453B0D32.

    I have been using this code as my base because it is the only example in the pc-ble-driver. I've been told multiple times, by multiple different Nordic reps, that this is what I need to use. So that is why I am using it. This UART example is not in the pc-ble-driver. I need to be able to make a C program that can connect to my device's service, and read/write to its characteristics. From all I've been told, I need the pc-ble-driver to be able to do that. If there is other code that can do this, that can be built into a C project, please let me know. Thanks.

  • As I'd mentioned, after adding the call to "sd_ble_uuid_vs_add", I do not get error messages in the "service_discovery_start" or "on_connected" functions. I do not get any errors until after the event handler finishes the pass in which it called this function. When the event handler enters its next pass, with the p_ble_evt->header.evt_id set to BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP, this is when the value of p_ble_evt->evt.gattc_evt.gatt_status becomes 0x10A. This is the error I am trying to solve. Thanks.

Related