DFU Bootloader version (please complete the following information):
- SDK version: 30
- Bonding used: [no]
- Library version: [e.g. 1.11.0]
Device information (please complete the following information):
- Device: Xiaomi Redmi Note 7
- OS: Android 9
Question
When I am trying to start DFU, nothing happens and I get a message "DFU Service not found". My firmware file has .bin extension (if that makes any difference). I can successfully update firmware using nRF Connect app, but not using my code.
This is the main part of my code:
final DfuServiceInitiator starter = new DfuServiceInitiator(bluetoothDevice.getAddress()) .setDeviceName(bluetoothDevice.getName()) .setKeepBond(true) .setForceDfu(true) .setForeground(false) .setDisableNotification(true) .setPacketsReceiptNotificationsEnabled(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) .setPacketsReceiptNotificationsValue(DfuServiceInitiator.DEFAULT_PRN_VALUE) .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true) .setPrepareDataObjectDelay(300L); starter.setBinOrHex(DfuService.TYPE_SOFT_DEVICE, fileUri, filePath); starter.start(this, DfuService.class);
Full code:
FlashActivity.java:
public class FlashActivity extends AppCompatActivity { TextView fileText; private Uri fileUri; private String filePath; BluetoothDevice bluetoothDevice; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Intent intent = getIntent(); bluetoothDevice = (BluetoothDevice) intent.getExtras().get("Device"); setContentView(R.layout.activity_flash); } public void selectFile(View v){ Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT); chooseFile.setType("*/*"); chooseFile = Intent.createChooser(chooseFile, "Choose a file"); startActivityForResult(chooseFile, 1); } public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case 1: if (resultCode == -1) { fileUri = data.getData(); filePath = fileUri.getPath(); fileText = findViewById(R.id.fileText); fileText.setText(filePath); } break; } } public void clickFlash(View v){ final DfuServiceInitiator starter = new DfuServiceInitiator(bluetoothDevice.getAddress()) .setDeviceName(bluetoothDevice.getName()) .setKeepBond(true) .setForceDfu(true) .setForeground(false) .setDisableNotification(true) .setPacketsReceiptNotificationsEnabled(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) .setPacketsReceiptNotificationsValue(DfuServiceInitiator.DEFAULT_PRN_VALUE) .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true) .setPrepareDataObjectDelay(300L); starter.setBinOrHex(DfuService.TYPE_SOFT_DEVICE, fileUri, filePath); starter.start(this, DfuService.class); } }
DfuService.java:
public class DfuService extends DfuBaseService { @Override protected Class<? extends Activity> getNotificationTarget() { /* * As a target activity the NotificationActivity is returned, not the MainActivity. This is because * the notification must create a new task: * * intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); * * when you press it. You can use NotificationActivity to check whether the new activity * is a root activity (that means no other activity was open earlier) or that some * other activity is already open. In the latter case the NotificationActivity will just be * closed. The system will restore the previous activity. However, if the application has been * closed during upload and you click the notification, a NotificationActivity will * be launched as a root activity. It will create and start the main activity and * terminate itself. * * This method may be used to restore the target activity in case the application * was closed or is open. It may also be used to recreate an activity history using * startActivities(...). */ return NotificationActivity.class; } @Override protected boolean isDebug() { // Here return true if you want the service to print more logs in LogCat. // Library's BuildConfig in current version of Android Studio is always set to DEBUG=false, so // make sure you return true or your.app.BuildConfig.DEBUG here. return BuildConfig.DEBUG; } @Override protected void updateForegroundNotification(@NonNull final NotificationCompat.Builder builder) { // Customize the foreground service notification here. } }
NotificationActivity:
public class NotificationActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // If this activity is the root activity of the task, the app is not running if (isTaskRoot()) { // Start the app before finishing final Intent intent = new Intent(this, WaitActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtras(getIntent().getExtras()); // copy all extras startActivity(intent); } // Now finish, which will drop you to the activity at which you were at the top of the task stack finish(); } }
Logs
D/BluetoothGatt: connect() - device: EF:EF:DA:98:65:0B, auto: false
registerApp()
D/BluetoothGatt: registerApp() - UUID=3f8b73f3-2108-4f2e-a639-5bcb2ef109ad
D/BluetoothGatt: onClientRegistered() - status=0 clientIf=14
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=14 device=EF:EF:DA:98:65:0B
D/BluetoothGatt: discoverServices() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: onSearchComplete() = Device=EF:EF:DA:98:65:0B Status=0
W/DfuBaseService: DFU Service not found.
D/BluetoothGatt: cancelOpen() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=14 device=EF:EF:DA:98:65:0B
W/mple.safety_ap: Accessing hidden method Landroid/bluetooth/BluetoothGatt;->refresh()Z (light greylist, reflection)
D/BluetoothGatt: refresh() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: cancelOpen() - device: EF:EF:DA:98:65:0B
D/BluetoothGatt: close()
Final remarks
If possible could you provide me a code snippet ? I am not a pro at Android, the docs are not fully clear to me and the code examples from NordicSemiconductor are hard to follow. Thank you
I also asked the same question here: github.com/.../283