nRF52832 Central device cannot receive Notifications from another nRF52832 peripheral

Hello!

I am trying to collect data from an nRF52832 device which works as a peripheral to another device nRF52832 which operates as both Central and Peripheral. 

Description: 
I connect with my phone to the Central-Peripheral Device with nRF Connect App. I write a command in a Write Characteristic, which initiates the scanning process. 
The device starts scanning and successfully connects and discoveres the Service of the other device-peripheral. The Service has only two characteristics, 0x0001 Write, 0x0002 Notify. 
The device-central writes/subscribes in the 0x0001 Write characteristic to activate the sensor from which data will be sent. The command is a specific uint8_t array[14]. 
Then it also enables the cccd command for the Notify 0x0002 characteristic from which it will receive the data, which are of size uint8_t arr [18] .

Issue: 
When I connect from nRF Connect App directly to the device-peripheral and follow the same steps (subscribe with the same data on 0x0001 and enable nitifications on 0x0002) I successfully receive data on the latter characteristic. 
When the device-central executes the steps, nothing is received, no BLE_GATTC_EVT_HVX event is even triggered.

Here is the logs from the debugger:

where you can see that in the yellow highlighted lines I get the success of bothGATTC procedures (first write the 14 bytes array and then enable the CCCD) but after that nothing happens, no data are received and for some reason phy update events are triggered. 

1. I noticed that in nRF Connect App, as soon as I write the 14 bytes array in 0x0001 characteristic, the phys are updated to 2MBPS. I did this also in my code but nothing changed. (It was normally set as AUTO). 
2.  I also changed the NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN from 16 to 18 in sdk_config.h, but didn't help. 

Below some parts of my code: 

// <e> NRF_BLE_GQ_ENABLED - nrf_ble_gq - BLE GATT Queue Module
//==========================================================
#ifndef NRF_BLE_GQ_ENABLED
#define NRF_BLE_GQ_ENABLED 1
#endif
// <o> NRF_BLE_GQ_DATAPOOL_ELEMENT_SIZE - Default size of a single element in the pool of memory objects. 
#ifndef NRF_BLE_GQ_DATAPOOL_ELEMENT_SIZE
#define NRF_BLE_GQ_DATAPOOL_ELEMENT_SIZE 20
#endif

// <o> NRF_BLE_GQ_DATAPOOL_ELEMENT_COUNT - Default number of elements in the pool of memory objects. 
#ifndef NRF_BLE_GQ_DATAPOOL_ELEMENT_COUNT
#define NRF_BLE_GQ_DATAPOOL_ELEMENT_COUNT 8
#endif

// <o> NRF_BLE_GQ_GATTC_WRITE_MAX_DATA_LEN - Maximal size of the data inside GATTC write request (in bytes). 
#ifndef NRF_BLE_GQ_GATTC_WRITE_MAX_DATA_LEN
#define NRF_BLE_GQ_GATTC_WRITE_MAX_DATA_LEN 16
#endif

// <o> NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN - Maximal size of the data inside GATTC notification or indication request (in bytes). 
#ifndef NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN
#define NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN 18
#endif

sdk_config.h

uint32_t ble_scol_c_adj_notif_enable(ble_scol_c_t * p_ble_scol_c, bool enable)
{
    VERIFY_PARAM_NOT_NULL(p_ble_scol_c);
    if (p_ble_scol_c->conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_INVALID_STATE;
    }
    NRF_LOG_INFO("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
                  p_ble_scol_c->peer_scol_db.live_meas_cccd_handle,
                  p_ble_scol_c->conn_handle);

    nrf_ble_gq_req_t cccd_req;
    uint16_t         cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
    uint8_t          cccd[BLE_CCCD_VALUE_LEN];
    

    cccd[0] = LSB_16(cccd_val);
    cccd[1] = MSB_16(cccd_val);

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

    cccd_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
    cccd_req.error_handler.cb            = gatt_error_handler;
    cccd_req.error_handler.p_ctx         = p_ble_scol_c;
    cccd_req.params.gattc_write.handle   = p_ble_scol_c->peer_scol_db.live_meas_cccd_handle;
    cccd_req.params.gattc_write.len      = BLE_CCCD_VALUE_LEN;
    //cccd_req.params.gattc_write.offset   = 0;
    cccd_req.params.gattc_write.p_value  = cccd;
    cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;

    return nrf_ble_gq_item_add(p_ble_scol_c->p_gatt_queue, &cccd_req, p_ble_scol_c->conn_handle);
}

function with which central enables notifications on the peripheral

uint32_t ble_scol_c_subscribe(ble_scol_c_t * p_ble_scol_c, uint8_t subscribe[14])
{

    uint8_t subscribe_size[14]={0};
    //char subscribe_size[14] = {0};

    VERIFY_PARAM_NOT_NULL(p_ble_scol_c);
    
    NRF_LOG_INFO("p_ble_scol_c->conn_handle %d", p_ble_scol_c->conn_handle);
    if (p_ble_scol_c->conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    NRF_LOG_INFO("Writing Subscription [%d,%d,%d,%d,%d..", subscribe[0], subscribe[1],subscribe[2],subscribe[3],subscribe[4]);
    NRF_LOG_INFO("                  .... %d,%d,%d,%d,%d....", subscribe[5],subscribe[6],subscribe[7],subscribe[8],subscribe[9]);
    NRF_LOG_INFO("                  .... %d,%d,%d,%d]", subscribe[10],subscribe[11],subscribe[12],subscribe[13]);

    nrf_ble_gq_req_t write_req;

    //memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));

    write_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
    write_req.error_handler.cb            = gatt_error_handler;
    write_req.error_handler.p_ctx         = p_ble_scol_c;
    write_req.params.gattc_write.handle   = p_ble_scol_c->peer_scol_db.subscribe_handle;
    write_req.params.gattc_write.len      = sizeof(subscribe_size);
    write_req.params.gattc_write.p_value  = (uint8_t *)&subscribe;
    write_req.params.gattc_write.offset   = 0;
    write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ; 

    return nrf_ble_gq_item_add(p_ble_scol_c->p_gatt_queue, &write_req, p_ble_scol_c->conn_handle);
}

function to write the uint8_t array in 0x0001 Characteristic

void ble_scol_on_db_disc_evt(ble_scol_c_t * p_ble_scol_c, const ble_db_discovery_evt_t * p_evt)
{
    // Check if the Service was discovered.
    
    if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
        p_evt->params.discovered_db.srv_uuid.uuid == SENSOR_UUID_SERVICE &&
        p_evt->params.discovered_db.srv_uuid.type == p_ble_scol_c->uuid_type)
    {
        ble_scol_c_evt_t evt;

        evt.evt_type    = BLE_SCOL_C_EVT_DISCOVERY_COMPLETE;
        evt.conn_handle = p_evt->conn_handle;

        for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
        {
            const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
            switch (p_char->characteristic.uuid.uuid)
            {
                // Check if characteristics were found on the peer
                case NOTIFY_CHARACTERISTIC:
                    evt.params.peer_db.live_meas_handle = p_char->characteristic.handle_value; /*< Handle for the characteristic when it received a value. */
                    evt.params.peer_db.live_meas_cccd_handle = p_char->cccd_handle;            /*< Handle for the characteristic to enable/disable notify/indicate. */
                    NRF_LOG_INFO("Notify Characteristic 0x0002 discovered");
                    break;
                case WRITE_CHARACTERISTIC:
                    evt.params.peer_db.subscribe_handle = p_char->characteristic.handle_value;

                    NRF_LOG_INFO("Write Characteristic 0x0001 discovered");
                    break;
             
                
                default:
                    break;
            }
        }


        NRF_LOG_DEBUG(" Service discovered at peer.");
        //If the instance was assigned prior to db_discovery, assign the db_handles
        if (p_ble_scol_c->conn_handle != BLE_CONN_HANDLE_INVALID)
        {
            if ((p_ble_scol_c->peer_scol_db.live_meas_handle  == BLE_GATT_HANDLE_INVALID)&&
                (p_ble_scol_c->peer_scol_db.live_meas_cccd_handle  == BLE_GATT_HANDLE_INVALID)&&
                (p_ble_scol_c->peer_scol_db.subscribe_handle  == BLE_GATT_HANDLE_INVALID))
            {
                p_ble_scol_c->peer_scol_db = evt.params.peer_db;
            }
        }
        p_ble_scol_c->evt_handler(p_ble_scol_c, &evt);
    }
}

function with which I confirm that the Service and the Characteristics are successfully discovered

static void on_hvx(ble_scol_c_t * p_ble_scol_c, ble_evt_t const * p_ble_evt)
{
    // Check if the event is on the link for this instance.
    if (p_ble_scol_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
    {
        NRF_LOG_INFO("Received hvx on link 0x%x not associated to this instance. Ignore.", p_ble_evt->evt.gattc_evt.conn_handle);
        return; 
    }

                                                                    
    // Check if the event is an Adjustment (live_meas) notification.
    if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_scol_c->peer_scol_db.live_meas_handle)
    {
        NRF_LOG_INFO("Received data of size: %d", p_ble_evt->evt.gattc_evt.params.hvx.len);
        uint8_t data_size[18];
        uint32_t index=0;
        if (p_ble_evt->evt.gattc_evt.params.hvx.len == sizeof(data_size))
        {
            
            ble_scol_c_evt_t ble_scol_c_evt;

            ble_scol_c_evt.evt_type                   = SCOL_C_NOTIFY_CHAR_WRITTEN;
            ble_scol_c_evt.conn_handle                = p_ble_scol_c->conn_handle;

            
            memcpy(&ble_scol_c_evt.params.acc_data[0], p_ble_evt->evt.gattc_evt.params.hvx.data+6, sizeof(ble_scol_c_evt.params.acc_data[0]));
            memcpy(&ble_scol_c_evt.params.acc_data[1], p_ble_evt->evt.gattc_evt.params.hvx.data+10, sizeof(ble_scol_c_evt.params.acc_data[0]));
            memcpy(&ble_scol_c_evt.params.acc_data[2], p_ble_evt->evt.gattc_evt.params.hvx.data+14, sizeof(ble_scol_c_evt.params.acc_data[0]));
            
            NRF_LOG_INFO("Notify Value Received ="NRF_LOG_FLOAT_MARKER, NRF_LOG_FLOAT(ble_scol_c_evt.params.acc_data[0]));
            
            p_ble_scol_c->evt_handler(p_ble_scol_c, &ble_scol_c_evt);
        }
    }
    
   
    else
    {
         NRF_LOG_INFO("Another write did happen. Ignore.");
    }
}

on_hvx function

Do I miss something here? Should I change something more in the config file?
Any ideas on this would be very much appreciated. 
Thank you in advance, 
Dimitra

  • Hi Dimitra

    Have you tried to capture some sniffer traces of the two cases, first when using the nRF Connect app and it's working fine, and then with your own central which is not working? 

    Then it should be quite easy to figure out what is different in the two cases, which should hopefully point to a solution. 

    One thing I spotted in the log is that you have a CCCD handle of 36, which implies that you have a pretty long GATT table? Are you sure this is correct? 

    If you only use two characteristics I wouldn't expect you to reach a handle of 36. 

    Best regards
    Torbjørn

  • One thing I spotted in the log is that you have a CCCD handle of 36, which implies that you have a pretty long GATT table? Are you sure this is correct? 

    The Services and Characteristics are more than I said, apart from the Generic Access, Generic Attribute, there are:
    Device Information (0x180A)
    Battery Service (0x180F)
    UnknownService (0xFDF3)
    UnknownService(0x2252) :the one that I mentioned and which is the only one I want to have access to.

    Have you tried to capture some sniffer traces of the two cases, first when using the nRF Connect app and it's working fine, and then with your own central which is not working? 

    I tried now for the first time, I haven't used it before, I will present below the logs from Sniffer. 

    here are the logs when my phone with nRF Connect app connects to the peripheral device. 

    here is the moment I write/subscribe to the write characteristic and to the cccd for the Notify

    and here when I receive the Notification data

    Versus when Central-Peripheral Device connects with the peripheral

    1st difference  here is that my Central Device performs bonding, which I thought wouldnt cause a problem. Maybe I should deactivate it. 

    And here is when I Write to the Write characterstic 

    So, 2nd difference  is that my device tries to write to the characterstic of another Service (in the parenthesis it says Amersports, which is another service of the peripheral device) . 

    However, in my code, 

    #define SENSOR_UUID_SERVICE             0x2252
    #define NOTIFY_CHARACTERISTIC           0x0002
    #define WRITE_CHARACTERISTIC            0x0001

    I let the Central device have acknowledge for only 0x2252 Service which is the only one I want it to communicate with, and with which I get the confirmation that it succesfuly discovered the Service and Characteristics, 

    these are the logs during connection. 
    So I thought that it scans and discovers and assigns the connection handles to this Service and Characteristics only, and ignore others. (The Amersports service also has 2 characterstics 0x0001, 0x0002)
    Here are the 2 Services in nRF Connect App:


    Edit: I saved the traces into files (and also included them in text type)

    8055.Wireshark-sniffertraces.zip

    In the folder, I also included the Log file from nRF Connect when my phone connects with the Peripheral device

    1. From the Sniffer, do you agree that the conclusion is that it probably writes and enables the characterstics of the other Service? 
    2. If that is the case, how do I solve this problem, that my device must look only at the specific service? 
    3. If this is not the case, what else could be the problem, if the Sniffer helps ?

    Edit: 4. Finally, this time I also captured the sniffer traces on the Central device side, and I noticed that when it attempts to write something on the write characteristic or on cccd there is a message "Encrypted packet decrypted incorreclty (bad MIC)". What does this mean? Could it be relevant?

  • Hi 

    I will take a look at the details and get back to you tomorrow. Do you mind attaching the sniffer traces directly rather than just sending screenshots? 

    You can simply drag drop a file into your reply to attach it (using zip is easier if you have multiple files). 

    Regards
    Torbjørn

  • Yes sure, I edited the answer above with the zip file, and one more question and observation.

    Thank you

  • Hello again, after more testing, I finally found the bug which was irrelevant to all the above.
    The bug was on the write function to the Write Characteristic and regarding about the type of data I send.

    function to write the uint8_t array in 0x0001 Characteristic

    In this function i had to change
    this line: 

    write_req.params.gattc_write.p_value  = (uint8_t *)&subscribe;

    to this:

    write_req.params.gattc_write.p_value  = (uint8_t *)subscribe;

    because the subscribe is already an array...

    I am so sorry for creating such an issue and for spending your time on a question which was caused by another problem. 

    By the way, always thankful for your assistance! 
    Best regards,

    Dimitra

Related