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

DFU issues on Android 10

Hi,

We are currently testing DFU upgrades on Android. In my current setup I have two different phones, a Sony one running Android 8 and a OnePlus running Android 10.

The bootloader uses bonds and the application uses the buttonless DFU service.

Entering the bootloader and performing a DFU upgrade through the nRFConnect App on the Sony phone works fine. No failures there.

However on the OnePlus there are some issues. The first issue is that when trigger a DFU with the new FW zip file the nRF52832 enters the bootloader, the OnePlus connects again, but at reconnect it receives "GATT_INVALID_HANDLE", like it does not receive the GATT_SERVICE_CHANGED notification or that it receives it too late.

The second issue is that sometime the application cannot enter the bootloader from the buttonless DFU service, these are the logs from the application when I'm writing to the characteristic from the OnePlus:

<info> app: Read/Write Authorization request.
<info> app: Writing peer data to the bootloader...
<error> app: Request to enter bootloader mode failed asynchroneously.
<info> app: Handle Value Confirmation
<info> app: Read/Write Authorization request.
<info> app: Writing peer data to the bootloader...
<error> app: Request to enter bootloader mode failed asynchroneously.
<info> app: Handle Value Confirmation
<info> app: Read/Write Authorization request.
<info> app: Writing peer data to the bootloader...
<error> app: Request to enter bootloader mode failed asynchroneously.
<info> app: Handle Value Confirmation
<info> app: Read/Write Authorization request.
<info> app: Writing peer data to the bootloader...
<error> app: Request to enter bootloader mode failed asynchroneously.
<info> app: Handle Value Confirmation

Hardware: nRF52832 PCA10040

SDK: v15.0

Softdevice: v6.0.0

Edit: added screenshots from LOG

Parents Reply Children
  • I will implement the fix and see what happens.

    Regarding problem 2:

    ret = nrf_dfu_set_peer_data(&m_peer_data);

    is the function that returns INVALID_STATE, row 178 in ble_dfu_bonded.c

  • Here's the changes I made to nrf_dfu_ble.c. I copied the service_changed_cccd function and In case the softdevice call to service_changed fails I call that function. If I understand the code in gatt_cache_manager.c that's how it works there aswell.

    It does not seem to help.

    static ret_code_t service_changed_cccd(uint16_t conn_handle, uint16_t * p_cccd)
    {
        bool       sc_found = false;
        uint16_t   end_handle;
    
        ret_code_t err_code = sd_ble_gatts_initial_user_handle_get(&end_handle);
        ASSERT(err_code == NRF_SUCCESS);
    
        for (uint16_t handle = 1; handle < end_handle; handle++)
        {
            ble_uuid_t uuid;
            ble_gatts_value_t value = {.p_value = (uint8_t *)&uuid.uuid, .len = 2, .offset = 0};
    
            err_code = sd_ble_gatts_attr_get(handle, &uuid, NULL);
            if (err_code != NRF_SUCCESS)
            {
                return err_code;
            }
            else if (!sc_found && (uuid.uuid == BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED))
            {
                sc_found = true;
            }
            else if (sc_found && (uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG))
            {
                value.p_value = (uint8_t *)p_cccd;
                return sd_ble_gatts_value_get(conn_handle, handle, &value);
            }
        }
        return NRF_ERROR_NOT_FOUND;
    }
    
    
    #if (NRF_DFU_BLE_REQUIRES_BONDS)
    static uint32_t service_changed_send(void)
    {
        uint32_t err_code;
    
        NRF_LOG_DEBUG("Sending Service Changed indication");
    
        err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                             m_peer_data.sys_serv_attr,
                                             sizeof(m_peer_data.sys_serv_attr),
                                             BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                             NULL,
                                             0,
                                             BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_ble_gatts_service_changed(m_conn_handle, m_dfu.service_handle, 0xFFFF);
    
        if (   (err_code == BLE_ERROR_INVALID_CONN_HANDLE)
            || (err_code == NRF_ERROR_INVALID_STATE)
            || (err_code == NRF_ERROR_BUSY))
        {
            uint16_t cccd;
            err_code = service_changed_cccd(m_conn_handle, &cccd);
            if ((err_code == NRF_SUCCESS) && cccd)
            {
                NRF_LOG_DEBUG("Service changed cccd returned err_code: %d", err_code);
                // Possible ATT_MTU exchange ongoing.
                // Do nothing, treat as busy.
                return err_code;
            }
            else
            {
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_WARNING("Client did not have the Service Changed indication set to enabled."
                            "Error: 0x%08x", err_code);
                    err_code = NRF_SUCCESS;
    
                    //NRF_LOG_DEBUG("Unexpected error when looking for service changed CCCD: %s",
                    //              nrf_strerror_get(err_code));
                }
                // CCCDs not enabled or an error happened. Drop indication.
                // Fallthrough.
            }
            /* These errors can be expected when trying to send a Service Changed indication */
            /* if the CCCD is not set to indicate. Thus, set the returning error code to success. */
        }
    
        return err_code;
    }
    #endif
    

    The service changed notification is still sent from the events (no changes there):

    case BLE_GAP_EVT_CONN_SEC_UPDATE:
    case BLE_GATTS_EVT_SYS_ATTR_MISSING:
        {
            #if (NRF_DFU_BLE_REQUIRES_BONDS)
                err_code = service_changed_send();
            #else
                err_code = sd_ble_gatts_sys_attr_set(p_gap->conn_handle, NULL, 0, 0);
            #endif
            APP_ERROR_CHECK(err_code);
            NRF_LOG_DEBUG("Finished handling conn sec update");
        } break;
    
    

  • Hi,

    I see. Then I think it would be very useful with a sniffer trace and a log from the bootloader to know exactly what is going on (we have based it on assumptions up to now).

    Regarding problem 2, that is also a bit of a mystery. We may get a bit close if you look at the implementation in components\libraries\bootloader\dfu\nrf_dfu_svci_handler.c, an put breakpoints on all conditions that cause a NRF_ERROR_INVALID_STATE return value. I fail to see the reason, but reading this thread might suggest a link with problem 1.

  • 2816.sniffer.pcapng

    Hi,

    Here's the sniffer trace from wireshark. At package 6130 the connection to the bootloader starts.

    Hopefully you can read the data, I'm not very experienced with wireshark so I dont know if this is the correct way to do it.

    The sequence is here is write to DFU characteristic to "manually" put it in bootloader and then connect.

  • Hi,

    Thanks. All looks good here as far as I can see. I am wondering if there could be a timing issue in the Android DFU library itself, as you suggested earlier. Perhaps fixed by this. I am checking with the library developer and will get back to you.

Related