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

buttonless DFU and NUS

Hi !

I am on a firmware project for a nrf52832. I am using SES on Windows. 

There seem to be a problem when combining buttonless DFU and NUS. When I do the services_init, I have to choose if I call 'ble_dfu_buttonless_init' or 'ble_nus_init'. If I call both, one of them raise an error in the ERROR_CHECK. 

I would like to now how to enable NUS and buttonless at the same time.

Thanks !

Parents
  • Added this information to the uuids.. didn't work either.

    ble_uuid_t m_adv_uuids[] =                                          /**< Universally unique service identifier. */
    {
        {BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE},
        {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}
    };
    

  • JayLynkz said:
    However, even though I see it advertising, the central does not connect like it used to before I setted up DFU. Is it anything else I need to change ?

     That is probably because of the central's selection of who to connect to. Do you see the advertisements from the peripheral using e.g. nRF Connect?

    What is your central in this case? What sort of filters does it use to decide who to connect to? And what SDK version do you use (just in case it is relevant later).

    I'll assume you are using the ble_app_uart_c as a central. I'll refer to SDK 17.0.0 for now:

    You can see in scan_init(), it sets up a filter for the UUID for the NUS. Does your advertisement contain the NUS service's UUID?

    BR,

    Edvin

  • Hi Edvin, 

    Do you see the advertisements from the peripheral using e.g. nRF Connect? 

    Yes

    What is your central in this case ? What sort of filters does it use to decide who to connect to?

    My central is uploaded on a nrf52832 devkit. Its a custom app based on ble_app_uart_c. 

    This is the filter used. You can see it is the same that I am using for the peripheral, which makes sense because it used to work before I added the DFU part in services_init().

    /**@brief NUS UUID. */
    static ble_uuid_t const m_nus_uuid =
    {
        .uuid = BLE_UUID_NUS_SERVICE,
        .type = NUS_SERVICE_UUID_TYPE
    };

    And what SDK version do you use (just in case it is relevant later). 

    SDK 16

    I'll assume you are using the ble_app_uart_c as a central. I'll refer to SDK 17.0.0 for now:

    You can see in scan_init(), it sets up a filter for the UUID for the NUS. Does your advertisement contain the NUS service's UUID ? 

    Here's my scan_init() function. You can see it does include the UUID for the NUS. 

    static void scan_init(void)
    {
        ret_code_t          err_code;
        nrf_ble_scan_init_t init_scan;
    
        memset(&init_scan, 0, sizeof(init_scan));
    
        init_scan.connect_if_match = true;
        init_scan.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;
    
        err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_nus_uuid);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
        APP_ERROR_CHECK(err_code);
    }

    I add down here my services_init() function, in which I manually added the ble_dfu_buttonless_init.

    /**@brief Function for initializing services that will be used by the application.
     */
    void services_init(void)
    {
        uint32_t           err_code;
        ble_nus_init_t     nus_init;
        nrf_ble_qwr_init_t qwr_init = {0};
         ble_dfu_buttonless_init_t dfus_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // DFU 
    
        dfus_init.evt_handler = ble_dfu_evt_handler;
    
        err_code = ble_dfu_buttonless_init(&dfus_init);
        APP_ERROR_CHECK(err_code);
        
        // Initialize NUS.
        memset(&nus_init, 0, sizeof(nus_init));
    
        nus_init.data_handler = nus_data_handler;
    
        err_code = ble_nus_init(&m_nus, &nus_init);
        APP_ERROR_CHECK(err_code);  
    }

    As I said, when I take it off, my central finds the peripheral using NUS. But when I add the buttonless init, buttonless dfu works but the central doesn't find my peripheral anymore. 

    Thanks for your help !

  • Try this:

    Remove the buttonless service (or use the unmodified NUS example). Look at the advertising reports, to find the address of the advertising device. Then write it down.

    Then add the buttonless service back, and add the BLE_GAP_EVT_ADV_REPORT event in your central's ble_evt_handler in main.c.

    Then add a custom filter so that you only see the advertisements from that device, using the address that you wrote down.

    Then try to see what the advertisement packet looks like compared to the advertisements from ble_app_uart example. Are they identical?

    Also, try to debug in the nrf_ble_scan_on_ble_evt() in nrf_ble_scan.c, and find out why the scan filter is not matched. What is your all_filter_mode in nrf_ble_scan.c?

  • Hi Edvin, 

     Look at the advertising reports, to find the address of the advertising device. Then write it down.

    I couldn't find the way to see the advertising report. Do you mean that I should find an advertising report from my peripheral ? Is there any doc I could refer to on how to get the advertising report ?

    What is your all_filter_mode in nrf_ble_scan.c?

    bool const all_filter_mode   = p_scan_ctx->scan_filters.all_filters_mode;

    Thanks !

  • Sorry. Perhaps I was a bit short in the previous reply. 

    And it is perhaps a bit tedious to find the address this way. But if you use nRF Connect for Desktop -> Bluetooth Low Energy, you can see the address of all advertising devices:

    So if I flash the ble_app_uart example (and softdevice) to my DK, so that it starts advertising I will see this in nRF Connect for Desktop:

    Note that this is the reverse byte order (MSB), so in the application, the address of this device would be:

    addr[0] = 0xC1
    addr[1] = 0x0A
    addr[2] = 0x6B
    addr[3] = 0xA7
    addr[4] = 0xCE
    addr[5] = 0xED

    Now, the point of all this was that you should check your advertisements after you add the buttonless service. On your central, add the BLE_GAP_EVT_ADV_REPORT to your ble_evt_handler() in main.c:

            case BLE_GAP_EVT_ADV_REPORT:
                NRF_LOG_INFO("advertisement from %02x:%02x:%02x:%02x:%02x:%02x", p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[0],
                                                                                 p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[1],
                                                                                 p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[2],
                                                                                 p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[3],
                                                                                 p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[4],
                                                                                 p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[5]);
                NRF_LOG_RAW_INFO("Adv len: %d, data: ", p_ble_evt->evt.gap_evt.params.adv_report.data.len);
                for (uint16_t i=0; i< p_ble_evt->evt.gap_evt.params.adv_report.data.len; i++)
                {
                    NRF_LOG_RAW_INFO("%02x:", p_ble_evt->evt.gap_evt.params.adv_report.data.p_data[i]);
                }
                NRF_LOG_RAW_INFO("\r\n");
                break;

    This would print all advertisements that it scans, which is a lot. Therefore I thought you could filter out only the advertisements that you know you are looking for by using a "manual" filter by the address. One byte is probably enough. Therefore, in my case, I would add this if check to only print advertisements from one known address:

            case BLE_GAP_EVT_ADV_REPORT:
                if (p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[0] == 0xC1)
                {
                    NRF_LOG_INFO("advertisement from %02x:%02x:%02x:%02x:%02x:%02x", p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[0],
                                                                                     p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[1],
                                                                                     p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[2],
                                                                                     p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[3],
                                                                                     p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[4],
                                                                                     p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr[5]);
                    NRF_LOG_RAW_INFO("Adv len: %d, data: ", p_ble_evt->evt.gap_evt.params.adv_report.data.len);
                    for (uint16_t i=0; i< p_ble_evt->evt.gap_evt.params.adv_report.data.len; i++)
                    {
                        NRF_LOG_RAW_INFO("%02x:", p_ble_evt->evt.gap_evt.params.adv_report.data.p_data[i]);
                    }
                    NRF_LOG_RAW_INFO("\r\n");
                }
                break;

    You can do something similar (the manual address filter in BLE_GAP_EVT_ADV_REPORT in nrf_ble_scan.c, but remember to remove it later!!)

    To see why the central don't connect to your device when it detects the advertising report.

    Best regards,

    Edvin

  • Hi Edvin, 

    I figured out that if I place the NUS init before the DFU init in the services init, both work at the same time. 

    My services_init function looks like this : 

    void services_init(void)
    {
        uint32_t           err_code;
        ble_nus_init_t     nus_init;
        nrf_ble_qwr_init_t qwr_init = {0};
        ble_dfu_buttonless_init_t dfus_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize NUS. 
        memset(&nus_init, 0, sizeof(nus_init));
    
        nus_init.data_handler = nus_data_handler;
    
        err_code = ble_nus_init(&m_nus, &nus_init);  
        APP_ERROR_CHECK(err_code);
    
        // DFU 
    
        dfus_init.evt_handler = ble_dfu_evt_handler;
        
        err_code = ble_dfu_buttonless_init(&dfus_init);
        APP_ERROR_CHECK(err_code);
        
        
    }

    Thanks for your advices about the advertisement report, this might be helpful in the future ! 

    Best regards, 

    Jerome

Reply
  • Hi Edvin, 

    I figured out that if I place the NUS init before the DFU init in the services init, both work at the same time. 

    My services_init function looks like this : 

    void services_init(void)
    {
        uint32_t           err_code;
        ble_nus_init_t     nus_init;
        nrf_ble_qwr_init_t qwr_init = {0};
        ble_dfu_buttonless_init_t dfus_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize NUS. 
        memset(&nus_init, 0, sizeof(nus_init));
    
        nus_init.data_handler = nus_data_handler;
    
        err_code = ble_nus_init(&m_nus, &nus_init);  
        APP_ERROR_CHECK(err_code);
    
        // DFU 
    
        dfus_init.evt_handler = ble_dfu_evt_handler;
        
        err_code = ble_dfu_buttonless_init(&dfus_init);
        APP_ERROR_CHECK(err_code);
        
        
    }

    Thanks for your advices about the advertisement report, this might be helpful in the future ! 

    Best regards, 

    Jerome

Children
No Data
Related