summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2017-07-26 14:18:19 +0200
committerAlex Blasche <alexander.blasche@qt.io>2017-07-26 14:18:27 +0200
commit4849c1e95bb9521d08a7f8589c16c3b5849a7712 (patch)
treec31389410ae92cfb656de528adad766c6f512978
parent892d50020da29807d328b07d7568990e803c36f0 (diff)
parent96590b7d608ef25c21a2025d368b50b56b958364 (diff)
Merge remote-tracking branch 'gerrit/5.9' into dev
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java163
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.h4
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.h8
-rw-r--r--src/bluetooth/qbluetoothsocket_p.h6
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h4
5 files changed, 142 insertions, 43 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 9571ffdc..1b527ae3 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
@@ -48,6 +48,7 @@ import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
@@ -71,13 +72,21 @@ public class QtBluetoothLE {
private BluetoothGatt mBluetoothGatt = null;
private String mRemoteGattAddress;
private final UUID clientCharacteristicUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+ private final int MAX_MTU = 512;
+ private final int DEFAULT_MTU = 23;
+ private int mSupportedMtu = -1;
/*
* The atomic synchronizes the timeoutRunnable thread and the response thread for the pending
* I/O job. Whichever thread comes first will pass the atomic gate. The other thread is
* cut short.
*/
- private AtomicInteger handleForTimeout = new AtomicInteger(-1); // -1 implies not running
+ // handle values above zero are for regular handle specific read/write requests
+ // handle values below zero are reserved for handle-independent requests
+ private int HANDLE_FOR_RESET = -1;
+ private int HANDLE_FOR_MTU_EXCHANGE = -2;
+ private AtomicInteger handleForTimeout = new AtomicInteger(HANDLE_FOR_RESET); // implies not running by default
+
private final int RUNNABLE_TIMEOUT = 3000; // 3 seconds
private final Handler timeoutHandler = new Handler(Looper.getMainLooper());
@@ -85,14 +94,18 @@ public class QtBluetoothLE {
public TimeoutRunnable(int handle) { pendingJobHandle = handle; }
@Override
public void run() {
- boolean timeoutStillValid = handleForTimeout.compareAndSet(pendingJobHandle, -1);
+ boolean timeoutStillValid = handleForTimeout.compareAndSet(pendingJobHandle, HANDLE_FOR_RESET);
if (timeoutStillValid) {
Log.w(TAG, "****** Timeout for request on handle " + (pendingJobHandle & 0xffff));
- Log.w(TAG, "****** Looks like the characteristic or descriptor does NOT act in " +
+ Log.w(TAG, "****** Looks like the peripheral does NOT act in " +
"accordance to Bluetooth 4.x spec.");
Log.w(TAG, "****** Please check server implementation. Continuing under " +
"reservation.");
- interruptCurrentIO(pendingJobHandle & 0xffff);
+
+ if (pendingJobHandle > HANDLE_FOR_RESET)
+ interruptCurrentIO(pendingJobHandle & 0xffff);
+ else if (pendingJobHandle < HANDLE_FOR_RESET)
+ interruptCurrentIO(pendingJobHandle);
}
}
@@ -223,6 +236,8 @@ public class QtBluetoothLE {
errorCode = status; break; //TODO deal with all errors
}
leServicesDiscovered(qtObject, errorCode, builder.toString());
+
+ scheduleMtuExchange();
}
public void onCharacteristicRead(android.bluetooth.BluetoothGatt gatt,
@@ -247,7 +262,7 @@ public class QtBluetoothLE {
}
boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(foundHandle, IoJobType.Read), -1);
+ modifiedReadWriteHandle(foundHandle, IoJobType.Read), HANDLE_FOR_RESET);
if (requestTimedOut) {
Log.w(TAG, "Late char read reply after timeout was hit for handle " + foundHandle);
// Timeout has hit before this response -> ignore the response
@@ -311,7 +326,7 @@ public class QtBluetoothLE {
}
boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(handle, IoJobType.Write), -1);
+ modifiedReadWriteHandle(handle, IoJobType.Write), HANDLE_FOR_RESET);
if (requestTimedOut) {
Log.w(TAG, "Late char write reply after timeout was hit for handle " + handle);
// Timeout has hit before this response -> ignore the response
@@ -368,7 +383,7 @@ public class QtBluetoothLE {
}
boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(foundHandle, IoJobType.Read), -1);
+ modifiedReadWriteHandle(foundHandle, IoJobType.Read), HANDLE_FOR_RESET);
if (requestTimedOut) {
Log.w(TAG, "Late descriptor read reply after timeout was hit for handle " +
foundHandle);
@@ -441,7 +456,7 @@ public class QtBluetoothLE {
int handle = handleForDescriptor(descriptor);
boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(handle, IoJobType.Write), -1);
+ modifiedReadWriteHandle(handle, IoJobType.Write), HANDLE_FOR_RESET);
if (requestTimedOut) {
Log.w(TAG, "Late descriptor write reply after timeout was hit for handle " +
handle);
@@ -477,6 +492,32 @@ public class QtBluetoothLE {
// System.out.println("onReadRemoteRssi");
// }
+ // requires Android API v21
+ public void onMtuChanged(android.bluetooth.BluetoothGatt gatt, int mtu, int status)
+ {
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ Log.w(TAG, "MTU changed to " + mtu);
+ mSupportedMtu = mtu;
+ } else {
+ Log.w(TAG, "MTU change error " + status + ". New MTU " + mtu);
+ mSupportedMtu = DEFAULT_MTU;
+ }
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(HANDLE_FOR_MTU_EXCHANGE, IoJobType.Mtu), HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late mtu reply after timeout was hit");
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock ioJobPending -> the timeout has done that already
+ return;
+ }
+
+ synchronized (readWriteQueue) {
+ ioJobPending = false;
+ }
+
+ performNextIO();
+ }
};
@@ -554,7 +595,7 @@ public class QtBluetoothLE {
private enum IoJobType
{
- Read, Write
+ Read, Write, Mtu
}
private class ReadWriteJob
@@ -730,7 +771,7 @@ public class QtBluetoothLE {
// kill all timeout handlers
timeoutHandler.removeCallbacksAndMessages(null);
- handleForTimeout.set(-1);
+ handleForTimeout.set(HANDLE_FOR_RESET);
synchronized (readWriteQueue) {
readWriteQueue.clear();
@@ -841,6 +882,42 @@ public class QtBluetoothLE {
handleDiscoveredService + 1, discoveredService.endHandle + 1);
}
+ private boolean executeMtuExchange()
+ {
+ if (Build.VERSION.SDK_INT >= 21) {
+ try {
+ Method mtuMethod = mBluetoothGatt.getClass().getDeclaredMethod("requestMtu", int.class);
+ if (mtuMethod != null) {
+ Boolean success = (Boolean) mtuMethod.invoke(mBluetoothGatt, MAX_MTU);
+ if (success.booleanValue()) {
+ Log.w(TAG, "MTU change initiated");
+ return false;
+ } else {
+ Log.w(TAG, "MTU change request failed");
+ }
+ }
+ } catch (Exception ex) {}
+ }
+
+ Log.w(TAG, "Assuming default MTU value of 23 bytes");
+
+ mSupportedMtu = DEFAULT_MTU;
+ return true;
+ }
+
+ private void scheduleMtuExchange()
+ {
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.jobType = IoJobType.Mtu;
+ newJob.entry = null;
+
+ synchronized (readWriteQueue) {
+ readWriteQueue.add(newJob);
+ }
+
+ performNextIO();
+ }
+
/*
Internal Helper function for discoverServiceDetails()
@@ -1061,6 +1138,9 @@ public class QtBluetoothLE {
performNextIO();
+ if (handle == HANDLE_FOR_MTU_EXCHANGE)
+ return;
+
GattEntry entry = entries.get(handle);
if (entry == null)
return;
@@ -1085,24 +1165,28 @@ public class QtBluetoothLE {
boolean skip = false;
final ReadWriteJob nextJob;
- int handle = -1;
+ int handle = HANDLE_FOR_RESET;
synchronized (readWriteQueue) {
if (readWriteQueue.isEmpty() || ioJobPending)
return;
nextJob = readWriteQueue.remove();
- switch (nextJob.entry.type) {
- case Characteristic:
- handle = handleForCharacteristic(nextJob.entry.characteristic);
- break;
- case Descriptor:
- handle = handleForDescriptor(nextJob.entry.descriptor);
- break;
- case CharacteristicValue:
- handle = nextJob.entry.endHandle;
- default:
- break;
+ if (nextJob.jobType == IoJobType.Mtu) {
+ handle = HANDLE_FOR_MTU_EXCHANGE; //mtu request is special case
+ } else {
+ switch (nextJob.entry.type) {
+ case Characteristic:
+ handle = handleForCharacteristic(nextJob.entry.characteristic);
+ break;
+ case Descriptor:
+ handle = handleForDescriptor(nextJob.entry.descriptor);
+ break;
+ case CharacteristicValue:
+ handle = nextJob.entry.endHandle;
+ default:
+ break;
+ }
}
// timeout handler and handleForTimeout atomic must be setup before
@@ -1113,23 +1197,32 @@ public class QtBluetoothLE {
timeoutHandler.removeCallbacksAndMessages(null); // remove any timeout handlers
handleForTimeout.set(modifiedReadWriteHandle(handle, nextJob.jobType));
- if (nextJob.jobType == IoJobType.Read)
- skip = executeReadJob(nextJob);
- else
- skip = executeWriteJob(nextJob);
+ switch (nextJob.jobType) {
+ case Read:
+ skip = executeReadJob(nextJob);
+ break;
+ case Write:
+ skip = executeWriteJob(nextJob);
+ break;
+ case Mtu:
+ skip = executeMtuExchange();
+ break;
+ }
if (skip) {
- handleForTimeout.set(-1); // not a pending call -> release atomic
+ handleForTimeout.set(HANDLE_FOR_RESET); // not a pending call -> release atomic
} else {
ioJobPending = true;
timeoutHandler.postDelayed(new TimeoutRunnable(
modifiedReadWriteHandle(handle, nextJob.jobType)), RUNNABLE_TIMEOUT);
}
- Log.w(TAG, "Performing queued job, handle: " + handle + " " + nextJob.jobType + " (" +
+ if (nextJob.jobType != IoJobType.Mtu) {
+ Log.w(TAG, "Performing queued job, handle: " + handle + " " + nextJob.jobType + " (" +
(nextJob.requestedWriteType == BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) +
") ValueKnown: " + nextJob.entry.valueKnown + " Skipping: " + skip +
" " + nextJob.entry.type);
+ }
}
GattEntry entry = nextJob.entry;
@@ -1142,7 +1235,7 @@ public class QtBluetoothLE {
we have to report an error back to Qt. The error report is not required during
the initial service discovery though.
*/
- if (handle != -1) {
+ if (handle > HANDLE_FOR_RESET) {
// during service discovery we do not report error but emit characteristicRead()
// any other time a failure emits serviceError() signal
@@ -1171,15 +1264,16 @@ public class QtBluetoothLE {
break;
case CharacteristicValue:
// for more details see scheduleServiceDetailDiscovery(int)
- // ignore and continue unless last entry
- GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
- if (serviceEntry.endHandle == handle)
- finishCurrentServiceDiscovery(entry.associatedServiceHandle);
break;
case Service:
Log.w(TAG, "Scheduling of Service Gatt entry for service discovery should never happen.");
break;
}
+
+ // last entry of current discovery run?
+ GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
+ if (serviceEntry.endHandle == handle)
+ finishCurrentServiceDiscovery(entry.associatedServiceHandle);
} else {
int errorCode = 0;
@@ -1332,6 +1426,9 @@ public class QtBluetoothLE {
case Read:
modifiedHandle = (modifiedHandle | 0x00020000);
break;
+ case Mtu:
+ modifiedHandle = HANDLE_FOR_MTU_EXCHANGE;
+ break;
}
return modifiedHandle;
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
index 13d85a94..243d7fd2 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
@@ -78,12 +78,12 @@ class QDBusVariant;
QT_END_NAMESPACE
#endif
+QT_BEGIN_NAMESPACE
+
#ifdef QT_WINRT_BLUETOOTH
class QWinRTBluetoothDeviceDiscoveryWorker;
#endif
-QT_BEGIN_NAMESPACE
-
class QBluetoothDeviceDiscoveryAgentPrivate
#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH)
: public QObject
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
index 9a8da5e3..c4ea20a9 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
@@ -72,10 +72,6 @@ class QXmlStreamReader;
QT_END_NAMESPACE
#endif
-#ifdef QT_WINRT_BLUETOOTH
-class QWinRTBluetoothServiceDiscoveryWorker;
-#endif
-
QT_BEGIN_NAMESPACE
class QBluetoothDeviceDiscoveryAgent;
@@ -86,6 +82,10 @@ class LocalDeviceBroadcastReceiver;
#include <QtBluetooth/QBluetoothLocalDevice>
#endif
+#ifdef QT_WINRT_BLUETOOTH
+class QWinRTBluetoothServiceDiscoveryWorker;
+#endif
+
class QBluetoothServiceDiscoveryAgentPrivate
#if defined QT_WINRT_BLUETOOTH
: public QObject
diff --git a/src/bluetooth/qbluetoothsocket_p.h b/src/bluetooth/qbluetoothsocket_p.h
index 9aabf660..907acbe2 100644
--- a/src/bluetooth/qbluetoothsocket_p.h
+++ b/src/bluetooth/qbluetoothsocket_p.h
@@ -77,8 +77,6 @@ namespace ABI {
}
}
}
-
-class SocketWorker;
#endif // QT_WINRT_BLUETOOTH
#ifndef QPRIVATELINEARBUFFER_BUFFERSIZE
@@ -92,6 +90,10 @@ QT_FORWARD_DECLARE_CLASS(QSocketNotifier)
QT_BEGIN_NAMESPACE
+#ifdef QT_WINRT_BLUETOOTH
+class SocketWorker;
+#endif
+
class QBluetoothServiceDiscoveryAgent;
class QSocketServerPrivate
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h
index 3f220fe6..6e866144 100644
--- a/src/bluetooth/qlowenergycontroller_p.h
+++ b/src/bluetooth/qlowenergycontroller_p.h
@@ -85,8 +85,6 @@ QT_END_NAMESPACE
#elif defined(QT_WINRT_BLUETOOTH)
#include <wrl.h>
#include <windows.devices.bluetooth.h>
-
-class QWinRTLowEnergyServiceHandler;
#endif
#include <functional>
@@ -103,6 +101,8 @@ class QSocketNotifier;
class RemoteDeviceManager;
#elif defined(QT_ANDROID_BLUETOOTH)
class LowEnergyNotificationHub;
+#elif defined(QT_WINRT_BLUETOOTH)
+class QWinRTLowEnergyServiceHandler;
#endif
extern void registerQLowEnergyControllerMetaType();