Merge branch 'master' into release
This commit is contained in:
commit
1205a04c17
|
@ -6,6 +6,7 @@
|
||||||
<option name="distributionType" value="LOCAL" />
|
<option name="distributionType" value="LOCAL" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.2.1" />
|
<option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.2.1" />
|
||||||
|
<option name="gradleJvm" value="1.7" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
@ -15,5 +16,4 @@
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id="DFULibrary" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
<component name="FacetManager">
|
<component name="FacetManager">
|
||||||
<facet type="java-gradle" name="Java-Gradle">
|
<facet type="java-gradle" name="Java-Gradle">
|
||||||
<configuration>
|
<configuration>
|
||||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||||
|
<option name="BUILDABLE" value="false" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
|
@ -15,5 +16,4 @@
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -8,7 +8,7 @@ ext {
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 22
|
compileSdkVersion 22
|
||||||
buildToolsVersion '22.0.0'
|
buildToolsVersion '22.0.1'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 18
|
minSdkVersion 18
|
||||||
|
@ -26,7 +26,7 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compile 'com.android.support:support-v4:22.0.0'
|
compile 'com.android.support:support-v4:22.1.1'
|
||||||
compile 'com.google.code.gson:gson:2.3.1'
|
compile 'com.google.code.gson:gson:2.3.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
dfu/dfu.iml
12
dfu/dfu.iml
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="DFULibrary" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id=":dfu" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="DFULibrary" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
<component name="FacetManager">
|
<component name="FacetManager">
|
||||||
<facet type="android-gradle" name="Android-Gradle">
|
<facet type="android-gradle" name="Android-Gradle">
|
||||||
<configuration>
|
<configuration>
|
||||||
|
@ -12,8 +12,9 @@
|
||||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
|
|
||||||
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
||||||
|
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
|
||||||
|
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
|
||||||
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
|
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
|
||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||||
|
@ -87,8 +88,7 @@
|
||||||
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
|
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" exported="" name="gson-2.3.1" level="project" />
|
<orderEntry type="library" exported="" name="gson-2.3.1" level="project" />
|
||||||
<orderEntry type="library" exported="" name="support-v4-22.0.0" level="project" />
|
<orderEntry type="library" exported="" name="support-v4-22.1.1" level="project" />
|
||||||
<orderEntry type="library" exported="" name="support-annotations-22.0.0" level="project" />
|
<orderEntry type="library" exported="" name="support-annotations-22.1.1" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -66,6 +66,7 @@ import no.nordicsemi.android.dfu.exception.HexFileValidationException;
|
||||||
import no.nordicsemi.android.dfu.exception.RemoteDfuException;
|
import no.nordicsemi.android.dfu.exception.RemoteDfuException;
|
||||||
import no.nordicsemi.android.dfu.exception.UnknownResponseException;
|
import no.nordicsemi.android.dfu.exception.UnknownResponseException;
|
||||||
import no.nordicsemi.android.dfu.exception.UploadAbortedException;
|
import no.nordicsemi.android.dfu.exception.UploadAbortedException;
|
||||||
|
import no.nordicsemi.android.dfu.scanner.BootloaderScannerFactory;
|
||||||
import no.nordicsemi.android.error.GattError;
|
import no.nordicsemi.android.error.GattError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1727,14 +1728,32 @@ public abstract class DfuBaseService extends IntentService {
|
||||||
updateProgressNotification(PROGRESS_COMPLETED);
|
updateProgressNotification(PROGRESS_COMPLETED);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* The current service handle will try to upload Soft Device and/or Bootloader.
|
* In case when the Soft Device has been upgraded, and the application should be send in the following connection, we have to
|
||||||
* We need to enqueue another Intent that will try to send application only.
|
* make sure that we know the address the device is advertising with. Depending on the method used to start the DFU bootloader the first time
|
||||||
|
* the new Bootloader may advertise with the same address or one incremented by 1.
|
||||||
|
* When the buttonless update was used, the bootloader will use the same address as the application. The cached list of services on the Android device
|
||||||
|
* should be cleared thanks to the Service Changed characteristic (the fact that it exists if not bonded, or the Service Changed indication on bonded one).
|
||||||
|
* In case of forced DFU mode (using a button), the Bootloader does not know whether there was the Service Changed characteristic present in the list of
|
||||||
|
* application's services so it must advertise with a different address. The same situation applies when the new Soft Device was uploaded and the old
|
||||||
|
* application has been removed in this process.
|
||||||
|
*
|
||||||
|
* We could have save the fact of jumping as a parameter of the service but it ma be that some Android devices must first scan a device before connecting to it.
|
||||||
|
* It a device with the address+1 has never been detected before the service could have failed on connection.
|
||||||
|
*/
|
||||||
|
sendLogBroadcast(LOG_LEVEL_VERBOSE, "Scanning for the DFU bootloader...");
|
||||||
|
final String newAddress = BootloaderScannerFactory.getScanner().searchFor(mDeviceAddress);
|
||||||
|
sendLogBroadcast(LOG_LEVEL_INFO, "The Bootloader found (" + newAddress + ")");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The current service instance has uploaded the Soft Device and/or Bootloader.
|
||||||
|
* We need to start another instance that will try to send application only.
|
||||||
*/
|
*/
|
||||||
logi("Starting service that will upload application");
|
logi("Starting service that will upload application");
|
||||||
final Intent newIntent = new Intent();
|
final Intent newIntent = new Intent();
|
||||||
newIntent.fillIn(intent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_PACKAGE);
|
newIntent.fillIn(intent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_PACKAGE);
|
||||||
newIntent.putExtra(EXTRA_FILE_MIME_TYPE, MIME_TYPE_ZIP); // ensure this is set (f.e. for scripts)
|
newIntent.putExtra(EXTRA_FILE_MIME_TYPE, MIME_TYPE_ZIP); // ensure this is set (e.g. for scripts)
|
||||||
newIntent.putExtra(EXTRA_FILE_TYPE, TYPE_APPLICATION); // set the type to application only
|
newIntent.putExtra(EXTRA_FILE_TYPE, TYPE_APPLICATION); // set the type to application only
|
||||||
|
newIntent.putExtra(EXTRA_DEVICE_ADDRESS, newAddress);
|
||||||
newIntent.putExtra(EXTRA_PART_CURRENT, mPartCurrent + 1);
|
newIntent.putExtra(EXTRA_PART_CURRENT, mPartCurrent + 1);
|
||||||
newIntent.putExtra(EXTRA_PARTS_TOTAL, mPartsTotal);
|
newIntent.putExtra(EXTRA_PARTS_TOTAL, mPartsTotal);
|
||||||
startService(newIntent);
|
startService(newIntent);
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*************************************************************************************************************************************************
|
||||||
|
* Copyright (c) 2015, Nordic Semiconductor
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
************************************************************************************************************************************************/
|
||||||
|
|
||||||
|
package no.nordicsemi.android.dfu.scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* The DFU Bootloader may advertise with the same address as an application (in case of the buttonless update) or one incremented by 1 (in case of jumping to the DFU mode with a button,
|
||||||
|
* or after flashing the new Soft Device (flashing new SD removes the old application)).
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The DFU service always connects to the address given as a parameter. However, when flashing SD+BL+App it will first send the SD+BL as part one followed by the App in the second connection.
|
||||||
|
* As the service does not know which address was used in the first connection (normal, when buttonless update, or +1 when with-button update) we have to scan for the advertising device
|
||||||
|
* after SD+BL part is completed.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface BootloaderScanner {
|
||||||
|
/**
|
||||||
|
* After the buttonless jump from the application mode to the bootloader mode the service will wait this long for the advertising bootloader (in milliseconds).
|
||||||
|
*/
|
||||||
|
public final static long TIMEOUT = 2000l; // ms
|
||||||
|
/** The bootloader may advertise with the same address or one with the last byte incremented by this value. F.e. 00:11:22:33:44:55 -> 00:11:22:33:44:56. FF changes to 00. */
|
||||||
|
public final static int ADDRESS_DIFF = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the advertising bootloader. The bootloader may advertise with the same device address or one with the last byte incremented by 1.
|
||||||
|
* This method is a blocking one and ends when such device is found. There are two implementations of this interface - one for Androids 4.3 and 4.4.x and one for
|
||||||
|
* the Android 5+ devices.
|
||||||
|
*
|
||||||
|
* @param deviceAddress
|
||||||
|
* the application device address
|
||||||
|
* @return the address of the advertising DFU bootloader. If may be the same as the application address or one with the last byte incremented by 1 (AA:BB:CC:DD:EE:45/FF -> AA:BB:CC:DD:EE:46/00).
|
||||||
|
*/
|
||||||
|
public String searchFor(final String deviceAddress);
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*************************************************************************************************************************************************
|
||||||
|
* Copyright (c) 2015, Nordic Semiconductor
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
************************************************************************************************************************************************/
|
||||||
|
|
||||||
|
package no.nordicsemi.android.dfu.scanner;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The factory should be used to create the {@link BootloaderScanner} instance appropriate for the Android version.
|
||||||
|
*/
|
||||||
|
public class BootloaderScannerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scanner implementation.
|
||||||
|
*
|
||||||
|
* @return the bootloader scanner
|
||||||
|
*/
|
||||||
|
public static BootloaderScanner getScanner() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
return new BootloaderScannerLollipop();
|
||||||
|
return new BootloaderScannerJB();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*************************************************************************************************************************************************
|
||||||
|
* Copyright (c) 2015, Nordic Semiconductor
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
************************************************************************************************************************************************/
|
||||||
|
|
||||||
|
package no.nordicsemi.android.dfu.scanner;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see BootloaderScanner
|
||||||
|
*/
|
||||||
|
public class BootloaderScannerJB implements BootloaderScanner, BluetoothAdapter.LeScanCallback {
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
private String mDeviceAddress;
|
||||||
|
private String mDeviceAddressIncremented;
|
||||||
|
private String mBootloaderAddress;
|
||||||
|
private boolean mFound;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public String searchFor(final String deviceAddress) {
|
||||||
|
final String fistBytes = deviceAddress.substring(0, 15);
|
||||||
|
final String lastByte = deviceAddress.substring(15); // assuming that the device address is correct
|
||||||
|
final String lastByteIncremented = String.format("%02X", (Integer.valueOf(lastByte, 16) + ADDRESS_DIFF) & 0xFF);
|
||||||
|
|
||||||
|
mDeviceAddress = deviceAddress;
|
||||||
|
mDeviceAddressIncremented = fistBytes + lastByteIncremented;
|
||||||
|
mBootloaderAddress = null;
|
||||||
|
mFound = false;
|
||||||
|
|
||||||
|
// Add timeout
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(BootloaderScanner.TIMEOUT);
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mBootloaderAddress = null;
|
||||||
|
mFound = true;
|
||||||
|
|
||||||
|
// Notify the waiting thread
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "Scanner timer").start();
|
||||||
|
|
||||||
|
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
adapter.startLeScan(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
synchronized (mLock) {
|
||||||
|
while (!mFound)
|
||||||
|
mLock.wait();
|
||||||
|
}
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.stopLeScan(this);
|
||||||
|
return mBootloaderAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
|
||||||
|
final String address = device.getAddress();
|
||||||
|
|
||||||
|
if (mDeviceAddress.equals(address) || mDeviceAddressIncremented.equals(address)) {
|
||||||
|
mBootloaderAddress = address;
|
||||||
|
mFound = true;
|
||||||
|
|
||||||
|
// Notify the waiting thread
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*************************************************************************************************************************************************
|
||||||
|
* Copyright (c) 2015, Nordic Semiconductor
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
************************************************************************************************************************************************/
|
||||||
|
|
||||||
|
package no.nordicsemi.android.dfu.scanner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.le.BluetoothLeScanner;
|
||||||
|
import android.bluetooth.le.ScanCallback;
|
||||||
|
import android.bluetooth.le.ScanFilter;
|
||||||
|
import android.bluetooth.le.ScanResult;
|
||||||
|
import android.bluetooth.le.ScanSettings;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see BootloaderScanner
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public class BootloaderScannerLollipop extends ScanCallback implements BootloaderScanner {
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
private String mDeviceAddress;
|
||||||
|
private String mDeviceAddressIncremented;
|
||||||
|
private String mBootloaderAddress;
|
||||||
|
private boolean mFound;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String searchFor(final String deviceAddress) {
|
||||||
|
final String fistBytes = deviceAddress.substring(0, 15);
|
||||||
|
final String lastByte = deviceAddress.substring(15); // assuming that the device address is correct
|
||||||
|
final String lastByteIncremented = String.format("%02X", (Integer.valueOf(lastByte, 16) + ADDRESS_DIFF) & 0xFF);
|
||||||
|
|
||||||
|
mDeviceAddress = deviceAddress;
|
||||||
|
mDeviceAddressIncremented = fistBytes + lastByteIncremented;
|
||||||
|
mBootloaderAddress = null;
|
||||||
|
mFound = false;
|
||||||
|
|
||||||
|
// Add timeout
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(BootloaderScanner.TIMEOUT);
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mBootloaderAddress = null;
|
||||||
|
mFound = true;
|
||||||
|
|
||||||
|
// Notify the waiting thread
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "Scanner timer").start();
|
||||||
|
|
||||||
|
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
final BluetoothLeScanner scanner = adapter.getBluetoothLeScanner();
|
||||||
|
final List<ScanFilter> filters = new ArrayList<>();
|
||||||
|
filters.add(new ScanFilter.Builder().setDeviceAddress(mDeviceAddress).build());
|
||||||
|
filters.add(new ScanFilter.Builder().setDeviceAddress(mDeviceAddressIncremented).build());
|
||||||
|
final ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
|
||||||
|
scanner.startScan(filters, settings, this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
synchronized (mLock) {
|
||||||
|
while (!mFound)
|
||||||
|
mLock.wait();
|
||||||
|
}
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner.stopScan(this);
|
||||||
|
return mBootloaderAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScanResult(final int callbackType, final ScanResult result) {
|
||||||
|
final String address = result.getDevice().getAddress();
|
||||||
|
|
||||||
|
if (mDeviceAddress.equals(address) || mDeviceAddressIncremented.equals(address)) {
|
||||||
|
mBootloaderAddress = address;
|
||||||
|
mFound = true;
|
||||||
|
|
||||||
|
// Notify the waiting thread
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -135,12 +135,16 @@ public class GattError {
|
||||||
return "GATT ENCRYPTED NO MITM";
|
return "GATT ENCRYPTED NO MITM";
|
||||||
case 0x008e:
|
case 0x008e:
|
||||||
return "GATT NOT ENCRYPTED";
|
return "GATT NOT ENCRYPTED";
|
||||||
case 0x01FF:
|
case 0x008f:
|
||||||
|
return "GATT CONGESTED";
|
||||||
|
case 0x00FD:
|
||||||
|
return "GATT CCCD CFG ERROR";
|
||||||
|
case 0x00FE:
|
||||||
|
return "GATT PROCEDURE IN PROGRESS";
|
||||||
|
case 0x00FF:
|
||||||
return "GATT VALUE OUT OF RANGE";
|
return "GATT VALUE OUT OF RANGE";
|
||||||
case 0x0101:
|
case 0x0101:
|
||||||
return "TOO MANY OPEN CONNECTIONS";
|
return "TOO MANY OPEN CONNECTIONS";
|
||||||
case 0x00FF:
|
|
||||||
return "DFU SERVICE DISCOVERY NOT STARTED";
|
|
||||||
case DfuBaseService.ERROR_DEVICE_DISCONNECTED:
|
case DfuBaseService.ERROR_DEVICE_DISCONNECTED:
|
||||||
return "DFU DEVICE DISCONNECTED";
|
return "DFU DEVICE DISCONNECTED";
|
||||||
case DfuBaseService.ERROR_FILE_ERROR:
|
case DfuBaseService.ERROR_FILE_ERROR:
|
||||||
|
@ -152,7 +156,7 @@ public class GattError {
|
||||||
case DfuBaseService.ERROR_FILE_NOT_FOUND:
|
case DfuBaseService.ERROR_FILE_NOT_FOUND:
|
||||||
return "DFU FILE NOT FOUND";
|
return "DFU FILE NOT FOUND";
|
||||||
case DfuBaseService.ERROR_SERVICE_DISCOVERY_NOT_STARTED:
|
case DfuBaseService.ERROR_SERVICE_DISCOVERY_NOT_STARTED:
|
||||||
return "DFU ERROR WHILE SERVICE DISCOVERY";
|
return "DFU SERVICE DISCOVERY NOT STARTED";
|
||||||
case DfuBaseService.ERROR_SERVICE_NOT_FOUND:
|
case DfuBaseService.ERROR_SERVICE_NOT_FOUND:
|
||||||
return "DFU SERVICE NOT FOUND";
|
return "DFU SERVICE NOT FOUND";
|
||||||
case DfuBaseService.ERROR_CHARACTERISTICS_NOT_FOUND:
|
case DfuBaseService.ERROR_CHARACTERISTICS_NOT_FOUND:
|
||||||
|
|
Loading…
Reference in New Issue