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.

  • @HungBui, Master Control Panel is a really useful tool, thank you. Have it on PC now with PCA10000. 0x000E appears to be the handle for UART RX (from PC to nRF51822). I've updated the OP with a screenshot of all the data I can capture. There seems to be a conflict for pathway used to kick the firmware back to the bootloader (reset). In another trial (sporatically working) the UART RX characteristic has value 0x0016 and the DFU ClientCharacteristicConfiguration has handle value 0x000E.

  • @la-ble: Could you sum up what the issue you are having now? I'm kind of lost. Why do you want to do add DFU service when you don't flash the bootloader. How do you jump to the bootloader ? via a soft reset or a branching ?

    If possible please zip your project and update the file here. Also please don't mark the answer as correct when it has not fixed your issue.

  • I have the same problem.

    Code below run first two services but last one (DFU) do not work

    Printf return errors : 0, 0, 4

    also i have no idea how to mark code as one piece, welcome help

    <code=c>

    static void services_init(void) { // YOUR_JOB: Add code to initialize the services used by the application. uint32_t err_code;

    ble_nus_init_t nus_init;
    
    memset(&nus_init, 0, sizeof(nus_init));
    
      nus_init.data_handler = nus_data_handler;
    
    err_code = ble_nus_init(&m_nus, &nus_init);
    	printf("Error: %d", err_code);
    

    // APP_ERROR_CHECK(err_code);

    // Initialize Device Information Service.
    
    ble_dis_init_t dis_init;
    	
    	memset(&dis_init, 0, sizeof(dis_init));
    
    ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, (char *)MANUFACTURER_NAME);
    
    err_code = ble_dis_init(&dis_init);
    	printf("Error: %d", err_code);
    

    // APP_ERROR_CHECK(err_code); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_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;
    dfus_init.evt_handler   = dfu_app_on_dfu_evt;
    dfus_init.revision      = DFU_REVISION;
    
    err_code = ble_dfu_init(&m_dfus, &dfus_init);
    	printf("Error: %d", err_code);
    

    // APP_ERROR_CHECK(err_code);

    dfu_app_reset_prepare_set(reset_prepare);
    dfu_app_dm_appl_instance_set(m_app_handle);
    /** @snippet [DFU BLE Service initialization] */
    

    #endif // BLE_DFU_APP_SUPPORT }

  • Hi Szymon,

    Please create a new question and ask your question, you are using the "answer" section.

    Please add more information about the issue you are having and what showed when you try to debug it.

Related