Device advertising name is truncated to the length of the second name sent to device.

Hi,

I've read many questions about why the device advertising name may be getting truncated after calling sd_ble_gap_device_name_set() (advertising data more than 31 bytes).

However, I'm noticing a slightly different issue. When I first turn on the device, the default name loads in fine - let's call it 01234567890ABCDEF. I've set up a BLE characteristic write handler so that users may change this name, which works great for the first name they send to the device (eg, "TestName"). However, all subsequent names are shortened to the length of this "TestName" first sent to the device, even though there should be plenty of room in the advertising data - the much longer default name fits fine.

Here is some of my code:

BLE characteristic code that calls the adv_name_write_handler:

if (p_ble_evt->evt.gatts_evt.params.write.uuid.uuid == BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME && (p_lbs->adv_name_write_handler != NULL)){
    printf("Data: %s\n",p_evt_write->data);
    p_lbs->adv_name_write_handler(p_ble_evt->evt.gap_evt.conn_handle, p_lbs, p_evt_write->data, p_evt_write->len);
    return;
}

Calls adv_name_write_handler: (str_buffer is a static uint8_t[32])

static void adv_name_write_handler(uint16_t conn_handle, ble_lbs_t *p_lbs, const uint8_t *data, uint8_t len) {
  memcpy(str_buffer, 0, MAX_NAME_LEN);
  strncpy(str_buffer, data, len);
  printf("str_buffer: %s\n", str_buffer);
  //device_name = data;

  ret_code_t err_code = set_adv_name(str_buffer, len);

  if (err_code != NRF_SUCCESS)
    printf("Error in adv_name_write_handler: 0x%x\n", err_code);
}

Calls set_adv_name with str_buffer and len:

static ret_code_t set_adv_name(uint8_t *name, uint8_t len) {
  //Save to flash to persist across reboot
  ret_code_t err_code = flash_update(str_buffer, MAX_NAME_LEN, FDS_KEY_NAME_STR);

  //Now, restart advertising
  sd_ble_gap_adv_stop(m_adv_handle);
  gap_params_init(len);
  advertising_init();

  return err_code;
}

gap_params_init(0) and advertising_init() are also called when the chip first boots up. The default device name is set in the static device_name variable. Here they are:

static void gap_params_init(uint8_t len) {
  ret_code_t err_code;
  ble_gap_conn_params_t gap_conn_params;
  ble_gap_conn_sec_mode_t sec_mode;

  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
  if (!strlen(str_buffer))
    strcpy(str_buffer, device_name);
  if(!len)
    len = strlen(str_buffer);
  
  //printf("Setting name: %s, len: %d\n", str_buffer, len);
  err_code = sd_ble_gap_device_name_set(&sec_mode,
      (const uint8_t *)str_buffer,
      len);
  APP_ERROR_CHECK(err_code);

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

  gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
  gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
  gap_conn_params.slave_latency = SECONDARY_LATENCY;
  gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;

  err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
  APP_ERROR_CHECK(err_code);
}

static void advertising_init(void) {
  ret_code_t err_code;
  ble_advdata_t advdata;
  ble_advdata_t srdata;

  ble_uuid_t adv_uuids[] = {{LBS_UUID_SERVICE, m_lbs.uuid_type}};

  // Build and set advertising data.
  memset(&advdata, 0, sizeof(advdata));

  advdata.name_type = BLE_ADVDATA_FULL_NAME;
  advdata.include_appearance = false;
  advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;

  memset(&srdata, 0, sizeof(srdata));
  srdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
  srdata.uuids_complete.p_uuids = adv_uuids;

  err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
  APP_ERROR_CHECK(err_code);

  err_code = ble_advdata_encode(&srdata, m_adv_data.scan_rsp_data.p_data, &m_adv_data.scan_rsp_data.len);
  APP_ERROR_CHECK(err_code);

  ble_gap_adv_params_t adv_params;

  // Set advertising parameters.
  memset(&adv_params, 0, sizeof(adv_params));

  adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
  adv_params.duration = APP_ADV_DURATION;
  adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
  adv_params.p_peer_addr = NULL;
  adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
  adv_params.interval = APP_ADV_INTERVAL;

  err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &adv_params);
  APP_ERROR_CHECK(err_code);
}

Steps to reproduce:
1. Restart device - it will either load the last used name from flash, or use the default name. The full name is advertised.
2. Using nRF Connect or a similar app, set the 0x2A00 "Device Name" characteristic to something - note the length of this name.
3. Reconnect to the device, and set the Device Name characteristic to a longer name than set in step 2.
4. Disconnect from device to check advertised name, and note that it was truncated to the length of the name set in step 2.

Toolchain: SEGGER Embedded Studio V4.18 on Linux, nRF5 SDK v17.0.2
SoftDevice: s132_nrf52_7.2.0

Let me know if you need any more details, and thanks in advance!

Parents
  • Hi Ella, 

    Could you provide a minimum code that reproduce the issue so we can test here  ? 
    I suspect that there could be something wrong in the ble_advdata.c.

    Have you tried to call sd_ble_gap_device_name_get() to see what's the actual device name in the softdevice ? When you connect to the device and read the Device name , what do you see ? 
    I assume you have verified the actual advertising data with a sniffer (or nRF Connect on Desktop) this is to avoid the caching problem may happen on the phone. 

  • Sure! Here's a minimal project that demonstrates the bug, you can place it in any subfolder inside the SDK's Examples folder to get it to work. So, the full filepath should be nrf5v17/examples/MyExamples/ble-rename-example/pca10040/... .
    Let me know if you have any issues getting it to build and run, but it's running on my development kit just fine (and demonstrates the truncation issue).

    https://drive.google.com/file/d/1H1hekojdLv9MejNIWOVmekxO9ZJuPBeK/view?usp=sharing

    I just tried calling sd_ble_gap_device_name_get() as part of gap_params_init() and it returns the full name, yet it's still truncated.

    I have verified the actual advertising data after restarting Bluetooth. I've used my computer, in addition to the nRF Connect app (on my phone and my tablet) to verify - the name is truncated on all devices. I think that this rules out the phone caching issue, but let me know if there's something else I should try in that regard.

    Thank you!

  • Hi Ella, 
    I think I found what would be wrong here. 
    The advertising_init() was not designed to be used more than once. 
    In particular the p_len in ble_advdata_encode() return the length of encoded data. after the call.

    But it's also used as the input for the next call. So if you don't update it to BLE_GAP_ADV_SET_DATA_SIZE_MAX. The next call of advertising_init() will limit the size of the advertising packet down to the size of the last advertising packet. In short m_adv_data is not reinitialized when you call advertising_init() the second time.  This explained the behavior. 


    So if you add these: 

      m_adv_data.adv_data.len=BLE_GAP_ADV_SET_DATA_SIZE_MAX;
      m_adv_data.scan_rsp_data.len=BLE_GAP_ADV_SET_DATA_SIZE_MAX;

    Into advertising_init(), it should work. 


Reply
  • Hi Ella, 
    I think I found what would be wrong here. 
    The advertising_init() was not designed to be used more than once. 
    In particular the p_len in ble_advdata_encode() return the length of encoded data. after the call.

    But it's also used as the input for the next call. So if you don't update it to BLE_GAP_ADV_SET_DATA_SIZE_MAX. The next call of advertising_init() will limit the size of the advertising packet down to the size of the last advertising packet. In short m_adv_data is not reinitialized when you call advertising_init() the second time.  This explained the behavior. 


    So if you add these: 

      m_adv_data.adv_data.len=BLE_GAP_ADV_SET_DATA_SIZE_MAX;
      m_adv_data.scan_rsp_data.len=BLE_GAP_ADV_SET_DATA_SIZE_MAX;

    Into advertising_init(), it should work. 


Children
Related