summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/osx/osxbtcentralmanager.mm
diff options
context:
space:
mode:
authorTimur Pocheptsov <Timur.Pocheptsov@digia.com>2014-11-28 16:13:39 +0100
committerTimur Pocheptsov <Timur.Pocheptsov@digia.com>2014-12-01 13:12:37 +0100
commitb82007fd2425bf7cae13dd525087bf390047a8cd (patch)
treebd1a143242711c50bbb8776b9ae71c1c01c93e72 /src/bluetooth/osx/osxbtcentralmanager.mm
parent78954716c7dfb5334386ba28d09363468a7fead2 (diff)
QLowEnergyController - concurrent characteristic writes
Qt's API assumes that several write operations must be serialized (this is not guaranteed with Core Bluetooth AFAIK). I can enqueu only write with response operations, otherwise I never know when to do the next write. Change-Id: Iaa83514748358437e2c39335ab142d084ff197e3 Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/bluetooth/osx/osxbtcentralmanager.mm')
-rw-r--r--src/bluetooth/osx/osxbtcentralmanager.mm61
1 files changed, 52 insertions, 9 deletions
diff --git a/src/bluetooth/osx/osxbtcentralmanager.mm b/src/bluetooth/osx/osxbtcentralmanager.mm
index 35a284c2..2b4a2dd4 100644
--- a/src/bluetooth/osx/osxbtcentralmanager.mm
+++ b/src/bluetooth/osx/osxbtcentralmanager.mm
@@ -577,7 +577,27 @@ using namespace QT_NAMESPACE;
writePending = true;
return [peripheral writeValue:data.data() forDescriptor:d];
} else {
- // TODO: characteristics write requests.
+ CBCharacteristic *const ch = charMap[request.handle];
+ Q_ASSERT_X(ch, "-performNextWriteRequest", "invalid characteristic (nil)");
+
+ ObjCStrongReference<NSData> data(data_from_bytearray(request.value));
+ if (!data) {
+ // Even if qtData.size() == 0, we still need NSData object.
+ qCWarning(QT_BT_OSX) << "-performNextWriteRequest, "
+ "failed to allocate NSData object";
+ [self performNextWriteRequest];
+ }
+
+ // TODO: check what happens if I'm using NSData with length 0.
+ if (request.withResponse) {
+ writePending = true;
+ [peripheral writeValue:data.data() forCharacteristic:ch
+ type:CBCharacteristicWriteWithResponse];
+ } else {
+ [peripheral writeValue:data.data() forCharacteristic:ch
+ type:CBCharacteristicWriteWithoutResponse];
+ [self performNextWriteRequest];
+ }
}
}
@@ -597,6 +617,22 @@ using namespace QT_NAMESPACE;
return false;
}
+ LEWriteRequest request;
+ request.isDescriptor = false;
+ request.withResponse = withResponse;
+ request.handle = charHandle;
+ request.value = value;
+
+ writeQueue.enqueue(request);
+ [self performNextWriteRequest];
+ // TODO: this is quite ugly: true value can be returned after
+ // write actually. If I have any problems with the order later,
+ // I'll use performSelector afterDelay with some delay.
+ return true;
+/*
+ // Write without responce is not serialized - no way I can
+ // know about the write operation success/failure - and
+ // I will never perform the next write.
CBCharacteristic *const ch = charMap[charHandle];
Q_ASSERT_X(ch, "-write:charHandle:withResponse:", "invalid characteristic (nil) for a give handle");
Q_ASSERT_X(peripheral, "-write:charHandle:withResponse:", "invalid peripheral (nil)");
@@ -611,9 +647,9 @@ using namespace QT_NAMESPACE;
// TODO: check what happens if I'm using NSData with length 0.
[peripheral writeValue:data.data() forCharacteristic:ch
- type: withResponse? CBCharacteristicWriteWithResponse : CBCharacteristicWriteWithoutResponse];
+ type:CBCharacteristicWriteWithoutResponse];
- return true;
+ return true;*/
}
- (bool)write:(const QByteArray &)value descHandle:(QLowEnergyHandle)descHandle
@@ -1223,6 +1259,9 @@ using namespace QT_NAMESPACE;
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
+ Q_UNUSED(aPeripheral)
+ Q_UNUSED(characteristic)
+
// From docs:
//
// "This method is invoked only when your app calls the writeValue:forCharacteristic:type:
@@ -1232,8 +1271,7 @@ using namespace QT_NAMESPACE;
using namespace OSXBluetooth;
- Q_UNUSED(aPeripheral)
- Q_UNUSED(characteristic)
+ writePending = false;
Q_ASSERT_X(delegate, "-peripheral:didWriteValueForCharacteristic:error",
"invalid delegate (null)");
@@ -1247,9 +1285,14 @@ using namespace QT_NAMESPACE;
delegate->error(qt_uuid(characteristic.service.UUID), 0,
QLowEnergyService::CharacteristicWriteError);
} else {
- ObjCStrongReference<CBCharacteristic> ch(characteristic, true);
- delegate->characteristicWriteNotification(ch);
+ // Keys are unique.
+ const QLowEnergyHandle cHandle = charMap.key(characteristic);
+ Q_ASSERT_X(cHandle, "-peripheral:didWriteValueForCharacteristic:error",
+ "invalid handle, not found in the characteristics map");
+ delegate->characteristicWriteNotification(cHandle, qt_bytearray(characteristic.value));
}
+
+ [self performNextWriteRequest];
}
- (void)peripheral:(CBPeripheral *)aPeripheral
@@ -1272,10 +1315,10 @@ using namespace QT_NAMESPACE;
delegate->error(qt_uuid(descriptor.characteristic.service.UUID), 0,
QLowEnergyService::DescriptorWriteError);
} else {
- // We know that keys are unique, so can find a key for a given descriptor.
+ // We know that keys are unique, so we can find a key for a given descriptor.
const QLowEnergyHandle dHandle = descMap.key(descriptor);
Q_ASSERT_X(dHandle, "-peripheral:didWriteValueForDescriptor:error:",
- "invalid descriptor, not found in a descMap");
+ "invalid descriptor, not found in the descriptors map");
delegate->descriptorWriteNotification(dHandle, qt_bytearray(descriptor.value));
}