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

Reply
  • 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 }

Children
Related