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

ble_dfus WITH ble_nus

I've been using the device firmware update service for quite some time now. I'm looking to add the ble_nus service, but this feature seems to fail when ble_dfus is re-enabled. I check all my err_codes and nothing ever fails. I just can't ever get my callback COMMS_OnNusDataReceived to execute on data being received from the nrftoobox UART sub-app. Is there a known incompatibility with ble_dfus and ble_nus?

What is strange is that I can sometimes get this to work if the bootloader is also programmed. Without the bootloader programmed in, I can only get the ble_nus callback to execute if I comment out the ble_dfu_on_ble_evt usage:

static void COMMS_InitServices(void) {
  uint32_t err_code;
  ble_dfu_init_t dfus_init;
  ble_nus_init_t nus_init;
  ble_bas_init_t bas_init;
  ble_dis_init_t dis_init;
  
  // Initialize the Device Firmware Update Service.
  memset(&dfus_init, 0, sizeof(dfus_init));
  dfus_init.evt_handler    = dfu_app_on_dfu_evt;
  dfus_init.error_handler  = NULL; // Not used as only the switch from app to DFU mode is required and not full dfu service.
  dfus_init.revision       = DFU_REVISION;
  err_code = ble_dfu_init(&comms.dfus, &dfus_init);
  APP_ERROR_CHECK(err_code);
  // Specify the callback to execute just before resetting
  dfu_app_reset_prepare_set(COMMS_PrepareForReset);
  
  // Initialize the Nordic UART Service
  memset(&nus_init, 0, sizeof(nus_init));
  nus_init.data_handler = COMMS_OnNusDataReceived;
  err_code = ble_nus_init(&comms.nus, &nus_init);
  APP_ERROR_CHECK(err_code);
  
  // Initialize the Battery Service
  memset(&bas_init, 0, sizeof(bas_init));
  // Here the sec level for the Battery Service can be changed/increased
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm);
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm);
  BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm);
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm);
  bas_init.evt_handler          = NULL;
  bas_init.support_notification = true;
  bas_init.p_report_ref         = NULL;
  bas_init.initial_batt_level   = 100;
  err_code = ble_bas_init(&bas, &bas_init);
  APP_ERROR_CHECK(err_code);
  
  // Initialize the Device Information Service
  memset(&dis_init, 0, sizeof(dis_init));
  ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME);
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm);
  BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm);
  err_code = ble_dis_init(&dis_init);
  APP_ERROR_CHECK(err_code);
}

static void COMMS_InitAdvertising(void) {
  uint32_t err_code;
  ble_advdata_t advdata;
  ble_advdata_t scanrsp;
  
  // BUG ALERT: WE ONLY HAVE ENOUGH BYTES IN THE PAYLOAD FOR ONE CUSTOM UUID
  ble_uuid_t adv_uuids[] = {
    {BLE_UUID_NUS_SERVICE, comms.nus.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(&scanrsp, 0, sizeof(scanrsp));
  scanrsp.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
  scanrsp.uuids_complete.p_uuids  = adv_uuids;
  
  err_code = ble_advdata_set(&advdata, &scanrsp);
  APP_ERROR_CHECK(err_code);
  
  // Initialize advertising parameters (used when starting advertising)
  memset(&comms.adv_params, 0, sizeof(ble_gap_adv_params_t));
  comms.adv_params.type        = BLE_GAP_ADV_TYPE_ADV_IND;
  comms.adv_params.p_peer_addr = NULL; // Undirected advertisement.
  comms.adv_params.fp          = BLE_GAP_ADV_FP_ANY;
  comms.adv_params.interval    = APP_ADV_INTERVAL;
  comms.adv_params.timeout     = APP_ADV_TIMEOUT_IN_SECONDS;
}

static void COMMS_DispatchBleEvent(ble_evt_t* p_ble_evt) {
  dm_ble_evt_handler(p_ble_evt);
  ble_conn_params_on_ble_evt(p_ble_evt);
  ble_nus_on_ble_evt(&comms.nus, p_ble_evt);
  ble_dfu_on_ble_evt(&comms.dfus, p_ble_evt); //<-- IF I COMMENT THIS OUT, NUS WORKS
  COMMS_OnBleEvent(p_ble_evt);
}

EDIT

Master Control Panel Screenshot of working trial using a PCA10000 on the PC side and my own device. I write to request firmware version and a valid response is returned. There are no changes to the firmware which is tracked with git. There is no bootloader on this device and I am running with the debugger. I can breakpoint in my callback:

image description

In a failed trial, the NUS UART RX (data pathway TO the device) characteristic had handle 0x000E. This does NOT seem deterministic. There is a variable other than the firmware.

EDIT 2

I reduced the size of a large buffer in my application. I may have been close to consuming the limit of RAM for my variant? Things seem to be working better now. I wish there was a simpler way to monitor the RAM and Flash consumption. Perhaps a little usage report printed at the end of a successful compilation or some basic GUI element or some kind of coarse percentage is fine enough.

Parents
  • @la-ble: It's pretty strange what you experienced. I can see in your code ble_nus_on_ble_evt() is called before ble_dfu_on_ble_evt().

    Could you add a breakpoint in ble_nus_on_ble_evt() at BLE_GATTS_EVT_WRITE event to check if the write command is correctly executed? There will be 2 write event, first is the one to set CCCD (only happens once), after that will be the write command for the actual data, checkout the p_evt_write->handle when the event arrives.

  • The p_evt_write I mentioned is exactly the p_evt_write you used in "p_evt_write->handle == p_nus->tx_handles.value_handle 0x000E != 0x0016."

    Could you check what characteristic is at handle 0x000E ? You can find the handle using the Master Control Panel tool we have on PC. Note that you should add the breakpoint only after the CCCD has been enabled. When enabling CCCDs we also use write commands, so you will also have the BLE_GATTS_EVT_WRITE event for those commands.

Reply
  • The p_evt_write I mentioned is exactly the p_evt_write you used in "p_evt_write->handle == p_nus->tx_handles.value_handle 0x000E != 0x0016."

    Could you check what characteristic is at handle 0x000E ? You can find the handle using the Master Control Panel tool we have on PC. Note that you should add the breakpoint only after the CCCD has been enabled. When enabling CCCDs we also use write commands, so you will also have the BLE_GATTS_EVT_WRITE event for those commands.

Children
No Data
Related