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;
  }

}

Parents
  • 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.

  • This really depends on how you have structured your application, but the event will come when the peer has responded, which can (by the spec) take up to 30 seconds. Usually it will take 2 connection intervals.

    If your app is interrupt-driven, an incoming event will trigger an interrupt and call all the on_ble_evt() handlers of each module. Then you have to somehow queue the packets yourself whenever write() returns BUSY, and retry again once the response is cleared. This means you have to continue sending the next write (if any) when WRITE_RSP is received.

    sd_app_evt_wait() puts the CPU into sleep until an event triggers (unless one is already pending), and continues from where it left off. But you do not know which event that woke you up, so you would have to set some state/flag that you can check when you wake up, then sleep if it was the wrong event.

Reply
  • This really depends on how you have structured your application, but the event will come when the peer has responded, which can (by the spec) take up to 30 seconds. Usually it will take 2 connection intervals.

    If your app is interrupt-driven, an incoming event will trigger an interrupt and call all the on_ble_evt() handlers of each module. Then you have to somehow queue the packets yourself whenever write() returns BUSY, and retry again once the response is cleared. This means you have to continue sending the next write (if any) when WRITE_RSP is received.

    sd_app_evt_wait() puts the CPU into sleep until an event triggers (unless one is already pending), and continues from where it left off. But you do not know which event that woke you up, so you would have to set some state/flag that you can check when you wake up, then sleep if it was the wrong event.

Children
No Data
Related