summaryrefslogtreecommitdiffstats
path: root/src/android
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2014-11-12 15:57:31 +0100
committerAlex Blasche <alexander.blasche@theqtcompany.com>2014-11-17 13:10:09 +0100
commit8ee716df65ffa40ec0bd0d650cfbcda101efe35d (patch)
tree10772ceb32f349bd6a3dc55ebdecc99725042cba /src/android
parentd113b4c0e1b070b1644810083828e23a148e7a21 (diff)
Ensure that Android can deal with concurrent write requests.
Change-Id: Ib4f8381a1975e17b5b142f49e0f3f32398a46bfb Reviewed-by: Timur Pocheptsov <Timur.Pocheptsov@digia.com> Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/android')
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java114
1 files changed, 101 insertions, 13 deletions
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java
index 04b211a5..988f3c3d 100644
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java
+++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java
@@ -128,7 +128,7 @@ public class QtBluetoothLE {
case BluetoothProfile.STATE_DISCONNECTED:
qLowEnergyController_State = 0;
// we disconnected -> get rid of data from previous run
- resetServiceDetailData();
+ resetData();
// reset mBluetoothGatt, reusing same object is not very reliable
// sometimes it reconnects and sometimes it does not.
mBluetoothGatt = null;
@@ -261,7 +261,11 @@ public class QtBluetoothLE {
errorCode = 2; break; // CharacteristicWriteError
}
+ synchronized (writeQueue) {
+ writeJobPending = false;
+ }
leCharacteristicWritten(qtObject, handle+1, characteristic.getValue(), errorCode);
+ performNextWrite();
}
public void onCharacteristicChanged(android.bluetooth.BluetoothGatt gatt,
@@ -356,7 +360,12 @@ public class QtBluetoothLE {
errorCode = 3; break; // DescriptorWriteError
}
+ synchronized (writeQueue) {
+ writeJobPending = false;
+ }
+
leDescriptorWritten(qtObject, handle+1, descriptor.getValue(), errorCode);
+ performNextWrite();
}
//TODO Requires Android API 21 which is not available on CI yet.
// public void onReliableWriteCompleted(android.bluetooth.BluetoothGatt gatt,
@@ -411,10 +420,20 @@ public class QtBluetoothLE {
public BluetoothGattDescriptor descriptor = null;
public int endHandle;
}
+ private class WriteJob
+ {
+ public GattEntry entry;
+ public byte[] newValue;
+ }
+
private final Hashtable<UUID, List<Integer>> uuidToEntry = new Hashtable<UUID, List<Integer>>(100);
private final ArrayList<GattEntry> entries = new ArrayList<GattEntry>(100);
private final LinkedList<Integer> servicesToBeDiscovered = new LinkedList<Integer>();
+
+ private final LinkedList<WriteJob> writeQueue = new LinkedList<WriteJob>();
+ private boolean writeJobPending;
+
/*
Internal helper function
Returns the handle id for the given characteristic; otherwise returns -1.
@@ -548,13 +567,18 @@ public class QtBluetoothLE {
private int currentServiceInDiscovery = -1;
private int runningHandle = -1;
- private synchronized void resetServiceDetailData()
+ private void resetData()
{
- runningHandle = -1;
- currentServiceInDiscovery = -1;
- uuidToEntry.clear();
- entries.clear();
- servicesToBeDiscovered.clear();
+ synchronized (this) {
+ runningHandle = -1;
+ currentServiceInDiscovery = -1;
+ uuidToEntry.clear();
+ entries.clear();
+ servicesToBeDiscovered.clear();
+ }
+ synchronized (writeQueue) {
+ writeQueue.clear();
+ }
}
public synchronized boolean discoverServiceDetails(String serviceUuid)
@@ -737,13 +761,22 @@ public class QtBluetoothLE {
return false;
}
- boolean result = entry.characteristic.setValue(newValue);
+ WriteJob newJob = new WriteJob();
+ newJob.newValue = newValue;
+ newJob.entry = entry;
+
+ boolean result;
+ synchronized (writeQueue) {
+ result = writeQueue.add(newJob);
+ }
+
if (!result) {
- Log.w(TAG, "BluetoothGattCharacteristic.setValue failed");
+ Log.w(TAG, "Cannot add characteristic write request for " + charHandle + " to queue" );
return false;
}
- return mBluetoothGatt.writeCharacteristic(entry.characteristic);
+ performNextWrite();
+ return true;
}
/*************************************************************/
@@ -763,13 +796,68 @@ public class QtBluetoothLE {
return false;
}
- boolean result = entry.descriptor.setValue(newValue);
+ WriteJob newJob = new WriteJob();
+ newJob.newValue = newValue;
+ newJob.entry = entry;
+
+ boolean result;
+ synchronized (writeQueue) {
+ result = writeQueue.add(newJob);
+ }
+
if (!result) {
- Log.w(TAG, "BluetoothGattDescriptor.setValue failed");
+ Log.w(TAG, "Cannot add descriptor write request for " + descHandle + " to queue" );
return false;
}
- return mBluetoothGatt.writeDescriptor(entry.descriptor);
+ performNextWrite();
+ return true;
+ }
+
+ /*
+ The queuing is required because two writeCharacteristic/writeDescriptor calls
+ cannot execute at the same time. The second write must happen after the
+ previous write has finished with on(Characteristic|Descriptor)Write().
+ */
+ private void performNextWrite()
+ {
+ if (mBluetoothGatt == null)
+ return;
+
+ boolean skip = false;
+ final WriteJob nextJob;
+ synchronized (writeQueue) {
+ if (writeQueue.isEmpty() || writeJobPending)
+ return;
+
+ nextJob = writeQueue.remove();
+ boolean result;
+ switch (nextJob.entry.type) {
+ case Characteristic:
+ result = nextJob.entry.characteristic.setValue(nextJob.newValue);
+ if (!result || !mBluetoothGatt.writeCharacteristic(nextJob.entry.characteristic))
+ skip = true;
+ break;
+ case Descriptor:
+ result = nextJob.entry.descriptor.setValue(nextJob.newValue);
+ if (!result || !mBluetoothGatt.writeDescriptor(nextJob.entry.descriptor))
+ skip = true;
+ break;
+ case Service:
+ case CharacteristicValue:
+ skip = true;
+ break;
+
+ }
+
+ if (!skip)
+ writeJobPending = true;
+ }
+
+ if (skip) {
+ Log.w(TAG, "Skipping write: " + nextJob.entry.type);
+ performNextWrite();
+ }
}