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

How to Continue Peripheral Device Advertising After the Connection of a Central Device that Peripheral Device

I am developing firmware for my Peripheral Device (nRF52840) using S140 (v7) and SDK 15.3. In my application, I will advertise (with advert payload changes) and support Smartphone app connect/disconnect to read and write custom characteristic values. Changing the payload was a challenge, but has been resolved using forum posts on this subject. I have created advertising_config(bool firstCall) to set up (firstCall=true) or update (firstCall=false) advertising.  It is not updating with meaningful data yet, but it shows that (conceptually), updates work (toggles data between "SomeData!" and "TomeData!" every 10 sec).

// Config advertising.
static void advertising_config(bool firstCall)
{
  ret_code_t             err_code;

  // Setup var to hold ble_advdata_t advert data. 
  ble_advdata_t advdata;
  memset(&advdata, 0, sizeof(advdata));

  // Setup var to hold ble_advdata_t scan resp data. 
  ble_advdata_t srdata;
  memset(&srdata, 0, sizeof(srdata));

  // Just use srdata to indicate that we want to expose the name provided in gap_params_init().
  srdata.name_type = BLE_ADVDATA_FULL_NAME;
  
  // Setup variable to hold manufacturer specific advert data
  ble_advdata_manuf_data_t mfr_advdata; 
  memset(&mfr_advdata, 0, sizeof(mfr_advdata));

  // Update mfr_data and add to advdata.
  uint8_t data[10];
  if(m_bufIdx == 0) { strcpy(data, "SomeData!"); }
  else { strcpy(data, "TomeData!"); } //Our data to advertise
  mfr_advdata.company_identifier         =  0x0059; //Nordics company ID
  mfr_advdata.data.p_data                = data;
  mfr_advdata.data.size                  = sizeof(data);
  advdata.name_type                    = BLE_ADVDATA_NO_NAME;
  advdata.p_manuf_specific_data        = &mfr_advdata;

  advdata.include_appearance      = true;
  advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
  advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
  advdata.uuids_complete.p_uuids  = m_adv_uuids;

  // Initialize advertising parameters (used when starting advertising).
  memset(&m_adv_params, 0, sizeof(m_adv_params));

  m_adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
  m_adv_params.p_peer_addr     = NULL;    // Undirected advertisement.
  m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
  m_adv_params.interval        = APP_ADV_INTERVAL;
  m_adv_params.duration        = 0;       // Never time out.

  // Encode advdata to m_gapData[m_bufIdx]
  err_code = ble_advdata_encode(&advdata, m_gapData[m_bufIdx].adv_data.p_data, (uint16_t *) &m_gapData[m_bufIdx].adv_data.len);
  APP_ERROR_CHECK(err_code);

  // Encode srdata to m_gapData[m_bufIdx]
  err_code = ble_advdata_encode(&srdata, m_gapData[m_bufIdx].scan_rsp_data.p_data, (uint16_t *) &m_gapData[m_bufIdx].scan_rsp_data.len);
  APP_ERROR_CHECK(err_code);

  // Setup adverts. On first call, also set advert params.
  if(firstCall)
  {
    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_gapData[m_bufIdx], &m_adv_params);
    APP_ERROR_CHECK(err_code);
  }
  else  // Susequent calls - update payloady only.
  {
    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_gapData[m_bufIdx], NULL);
    APP_ERROR_CHECK(err_code);
  }

  // Toggle buffer index to toggle buffer used.
  if(m_bufIdx == 0) {m_bufIdx ++;}
  else {m_bufIdx = 0;}
}

My remaining challenge is getting advertising to restart after a Smartphone app disconnects. I have been using the Android nRF Connect app for testing.

I have tried using the hrs example app (\nRF5_SDK_15.3.0_59ac345\examples\ble_peripheral\ble_app_hrs) as a reference, but it does not work. Whenever I connect to it, read a characteristic value and then disconnect, its advertising does not restart after disconnect (stops when I connect to my dev kit using nRF Connect).

What works (not a feasible solution in the real world due to delay discussed following) is restarting advertising (sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);) when BLE_GAP_EVT_DISCONNECTED is passed to my ble_evt_handler() as shown below. 

// Handle BLE events.
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
  ret_code_t err_code = NRF_SUCCESS;

  switch (p_ble_evt->header.evt_id)
  {
    case BLE_GAP_EVT_DISCONNECTED:
      NRF_LOG_INFO("Disconnected.");
      SEGGER_RTT_printf(0, "Disconnect Evt.\n");
      sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);

      m_conn_handle = BLE_CONN_HANDLE_INVALID;
      break;

    case BLE_GAP_EVT_CONNECTED:
      NRF_LOG_INFO("Connected.");
      SEGGER_RTT_printf(0, "Connect Evt.\n");
      err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
      APP_ERROR_CHECK(err_code);
      m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
      err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
      APP_ERROR_CHECK(err_code);
      break;

The problem with this approach is that BLE_GAP_EVT_DISCONNECTED can come into ble_evt_handler() 3 - 12 minutes after nRF Connect disconnects from the peripheral.

If I can get a faster indication of disconnection, I can stick with the approach that I have now (just call sd_ble_gap_adv_start() after getting an indication of disconnection). Please advise how to change BLE GAP config to support this.

Optionally - if there is a way to setup auto-restart upon disconnection, that approach would be even better.

Maybe also worth consideration .... when I select Disconnect within the nRF Connect app, is it actually disconnecting or am I just seeing a timeout 3-12 min later (i.e. nRF Connect bug)?

Looking forward to a reply and all help and input is appreciated.

Mark J

Parents Reply Children
Related