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

Multiple Characteristics and Notifications

Hi Forum,

i've started the development of an custom service on a nrf51822 with s110. The Service contains 4 Characteristics where notifications are enabled.

At the central side i use a nrf51822 with s120. On this Device the multilink_central app is running with modifications to my needs.

I can connect to a peer device and also dicover my characteristics. But when i only can set one characteristic to notify. ( enable_notify)

When i try to run this more than one time the software crashes.

Hope you can help me.

Edit: Ive attached the functions where i am stuck.

The Problem is i can only receive one hvx Notification -> last i discovered

static void notif_enable(client_t * p_client)
{
  uint32_t                 err_code;
  ble_gattc_write_params_t write_params;
  uint8_t                  buf[BLE_CCCD_VALUE_LEN];
     
  printf("In Notify Enable \r\n");

  p_client->state = STATE_NOTIF_ENABLE;

  buf[0] = BLE_GATT_HVX_NOTIFICATION;
  buf[1] = 0;

  write_params.write_op = BLE_GATT_OP_WRITE_REQ;
  write_params.handle   = p_client->srv_db.services[0].charateristics[p_client->char_index].cccd_handle;
  write_params.offset   = 0;
  write_params.len      = sizeof(buf);
  write_params.p_value  = buf;

  err_code = sd_ble_gattc_write(p_client->srv_db.conn_handle, &write_params);
  printf("Error Code: %i",err_code);
  //sd_app_evt_wait();
  wait(200000);
  APP_ERROR_CHECK(err_code);


}


static void db_discovery_evt_handler(ble_db_discovery_evt_t * p_evt)
{
  // Find the client using the connection handle.
  client_t * p_client;
  uint32_t   index;
  bool       is_valid_srv_found = false;

  index = client_find(p_evt->conn_handle);
  p_client = &m_client[index];

  if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
  {
    uint8_t i;

    printf("Characteritics found: %i\r\n",p_evt->params.discovered_db.char_count);
    for (i = 0; i <= p_evt->params.discovered_db.char_count; i++)
    {
        ble_db_discovery_char_t * p_characteristic;

        p_characteristic = &(p_evt->params.discovered_db.charateristics[i]);
        printf("UUID: %x ",p_characteristic->characteristic.uuid.uuid);
        if ((p_characteristic->characteristic.uuid.uuid == TEXMESSBOX_PERIPHERAL_CHANNEL_1_UUID)
            &&
            (p_characteristic->characteristic.uuid.type == m_base_uuid_type))
        {
            // Characteristic found. Store the information needed and break.
    	printf("Texxmessbox Channel 1\r\n");
            p_client->char_index = i;
            is_valid_srv_found   = true;

            //break;
        }
        if ((p_characteristic->characteristic.uuid.uuid == TEXMESSBOX_PERIPHERAL_CHANNEL_2_UUID)
                        &&
                        (p_characteristic->characteristic.uuid.type == m_base_uuid_type))
                    {
                        // Characteristic found. Store the information needed and break.
    	printf("Texxmessbox Channel 2\r\n");
                        p_client->char_index = i;
                        is_valid_srv_found   = true;

                        //break;
                    }
        if ((p_characteristic->characteristic.uuid.uuid == TEXMESSBOX_PERIPHERAL_CHANNEL_3_UUID)
                                    &&
                                    (p_characteristic->characteristic.uuid.type == m_base_uuid_type))
                                {
                                    // Characteristic found. Store the information needed and break.
                	printf("Texxmessbox Channel 3\r\n");
                                    p_client->char_index = i;
                                    is_valid_srv_found   = true;
                                    //break;
                                }
        if ((p_characteristic->characteristic.uuid.uuid == TEXMESSBOX_PERIPHERAL_CHANNEL_4_UUID)
                                    &&
                                    (p_characteristic->characteristic.uuid.type == m_base_uuid_type))
                                {
                                    // Characteristic found. Store the information needed and break.
                	printf("Texxmessbox Channel 4\r\n");
                                    p_client->char_index = i;
                                    is_valid_srv_found   = true;
                                    //break;
                                }
    }
}

if (is_valid_srv_found)
{
  // Enable notification.
  printf("Enable Notification\r\n");
  notif_enable(p_client);
}
else
{
    printf("Error\r\n");
    p_client->state = STATE_ERROR;
  }

}

  • @Sebastian: you need to add more information on how the software crashed.

    Have you checked the err_code when you call the function to write CCCD (to enable notification) ?

    Have you make sure you selected the correct connection handle (conn_handle) when calling sd_ble_gattc_write() ?

  • @Sebastian: Looking at the code seems that you called sd_ble_gattc_write() only once. You would need to call it 4 times, one for each of the characteristic's CCCD you want to enable (each char_index).

    In the ble_app_multilink_central we only called once because we only have one characteristic that has CCCD to look for.

  • First: Thank you for your quick answer. Second: When i try this with a for loop

    for(uint8_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
    {
         write_params.write_op = BLE_GATT_OP_WRITE_REQ;
      write_params.handle   =   p_client->srv_db.services[0].charateristics[i].cccd_handle;
      write_params.offset   = 0;
      write_params.len      = sizeof(buf);
      write_params.p_value  = buf;
      err_code = sd_ble_gattc_write(p_client->srv_db.conn_handle, &write_params);
    }
    

    the Program crashes. I ve read in a different thread that i should use

      sd_app_evt_wait();
    

    but Im not shure how to use this.

  • I think the issue here is that you are trying to send multiple write requests. You cannot send a new request before you have received a response, unlike the write command which has no response. Until the response is received, sd_ble_gattc_write() will return NRF_ERROR_BUSY. You should therefore either:

    1. Wait for BLE_GATTC_EVT_WRITE_RSP before sending a new write request.
    2. Change to write command, and track free application buffers.

    It is important to notice that option 1 will take a bit longer time (1-2 connection intervals per CCCD), compared to write command which can write to up to 6 per connection interval (depending on the peer and the softdevice version). Option 2 can also fail if the number of CCCDs go beyond the number of available application buffers, which means you have to keep track of these separately to run safely. This is done by waiting for BLE_EVT_TX_COMPLETE events and counting how many buffers that were freed. There are multiple threads about this on DevZone if you go for this option.

  • Ok thank i think i get it, but how can i wait on BLE_GATTC_EVT_WRITE_RSP? Is there a special function for this, maybe sd_app_evt_wait()?

Related