Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
btperipheralmanager.mm
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
9#include "btnotifier_p.h"
10#include "qbluetooth.h"
11
12#include <QtCore/qstring.h>
13#include <QtCore/qdebug.h>
14#include <QtCore/qlist.h>
15
16#include <algorithm>
17#include <vector>
18#include <limits>
19#include <deque>
20#include <map>
21
22namespace
23{
24
25CBCharacteristicProperties cb_properties(const QLowEnergyCharacteristicData &data)
26{
27 // Direct 'mapping' is ok.
28 return CBCharacteristicProperties(int(data.properties()));
29}
30
31CBAttributePermissions cb_permissions(const QLowEnergyCharacteristicData &data)
32{
33 using QLEC = QLowEnergyCharacteristic;
34
35 const auto props = data.properties();
36 CBAttributePermissions cbFlags = {};
37
38 if ((props & QLEC::Write) || (props & QLEC::WriteNoResponse)
39 || (props & QLEC::WriteSigned)) {
40 cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsWriteable);
41 }
42
43 if (props & QLEC::Read)
44 cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadable);
45
47 cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsWriteEncryptionRequired);
48
50 cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadEncryptionRequired);
51
52 return cbFlags;
53}
54
55ObjCStrongReference<CBMutableCharacteristic> create_characteristic(const QLowEnergyCharacteristicData &data)
56{
57 const ObjCStrongReference<CBMutableCharacteristic> ch([[CBMutableCharacteristic alloc] initWithType:cb_uuid(data.uuid())
58 properties:cb_properties(data)
59 value:nil
60 permissions:cb_permissions(data)],
62 return ch;
63}
64
65ObjCStrongReference<CBMutableDescriptor> create_descriptor(const QLowEnergyDescriptorData &data)
66{
67 // CoreBluetooth supports only:
68 /*
69 "That said, only two of these are currently supported when creating local,
70 mutable descriptors: the characteristic user description descriptor and
71 the characteristic format descriptor, represented by the CBUUID constants
72 CBUUIDCharacteristicUserDescriptionString and CBUUIDCharacteristicFormatString"
73 */
74
77 qCWarning(QT_BT_DARWIN) << "unsupported descriptor" << data.uuid();
78 return {};
79 }
80
82
83 // Descriptors are immutable with CoreBluetooth, that's why we
84 // have to provide a value here and not able to change it later.
85 ObjCStrongReference<NSObject> value;
87 const QString asQString(QString::fromUtf8(data.value()));
88 value.reset(asQString.toNSString(), RetainPolicy::doInitialRetain); // toNSString is auto-released, we have to retain.
89 } else {
90 const auto nsData = data_from_bytearray(data.value());
91 value.reset(nsData.data(), RetainPolicy::doInitialRetain);
92 }
93
94 const ObjCStrongReference<CBMutableDescriptor> d([[CBMutableDescriptor alloc]
95 initWithType:cb_uuid(data.uuid())
97 return d;
98}
99
101{
102 const auto maxu32 = std::numeric_limits<quint32>::max();
103 // + 1 for a service itself.
104 quint32 nEntries = 1 + quint32(data.includedServices().size());
105 for (const auto &ch : data.characteristics()) {
106 if (maxu32 - 2 < nEntries)
107 return {};
108 nEntries += 2;
109 if (maxu32 - ch.descriptors().size() < nEntries)
110 return {};
111 nEntries += ch.descriptors().size();
112 }
113
114 return nEntries;
115}
116
117bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
118{
119 if (data.minimumValueLength() > data.maximumValueLength()
120 || data.minimumValueLength() < 0) {
121 return false;
122 }
123
124 return data.value().size() <= data.maximumValueLength();
125}
126
127}
128
129@interface DarwinBTPeripheralManager (PrivateAPI)
130
131- (void)addConnectedCentral:(CBCentral *)central;
132- (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID;
133
134- (void)addIncludedServices:(const QLowEnergyServiceData &)data
135 to:(CBMutableService *)cbService
136 qtService:(QLowEnergyServicePrivate *)qtService;
137
138- (void)addCharacteristicsAndDescriptors:(const QLowEnergyServiceData &)data
139 to:(CBMutableService *)cbService
140 qtService:(QLowEnergyServicePrivate *)qtService;
141
142- (CBATTError)validateWriteRequest:(CBATTRequest *)request;
143
144@end
145
147{
148 ObjCScopedPointer<CBPeripheralManager> manager;
150
152 // Services in this vector are placed in such order:
153 // the one that has included services, must
154 // follow its included services to avoid exceptions from CBPeripheralManager.
155 std::vector<ObjCStrongReference<CBMutableService>> services;
156 decltype(services.size()) nextServiceToAdd;
157
158 // Lookup map for included services:
159 std::map<QBluetoothUuid, CBService *> serviceIndex;
160 ObjCScopedPointer<NSMutableDictionary> advertisementData;
161
162 GenericLEMap<CBCharacteristic *> charMap;
163 GenericLEMap<ObjCStrongReference<NSMutableData>> charValues;
164
165 QMap<QLowEnergyHandle, ValueRange> valueRanges;
166
167 std::deque<UpdateRequest> updateQueue;
168
171 decltype(services.size()) nOfFailedAds;
172}
173
174- (id)initWith:(LECBManagerNotifier *)aNotifier
175{
176 if (self = [super init]) {
177 Q_ASSERT(aNotifier);
178 notifier = aNotifier;
180 nextServiceToAdd = {};
181 maxNotificationValueLength = std::numeric_limits<NSUInteger>::max();
182 }
183
184 return self;
185}
186
187- (void)dealloc
188{
189 [self detach];
190 [super dealloc];
191}
192
194{
195 using QLES = QLowEnergyService;
196 using namespace DarwinBluetooth;
197
198 const auto nEntries = qt_countGATTEntries(data);
199 if (!nEntries || nEntries > std::numeric_limits<QLowEnergyHandle>::max() - lastHandle) {
200 qCCritical(QT_BT_DARWIN) << "addService: not enough handles";
201 return {};
202 }
203
205
206 const BOOL primary = data.type() == QLowEnergyServiceData::ServiceTypePrimary;
207 const auto cbUUID = cb_uuid(data.uuid());
208
209 const ObjCStrongReference<CBMutableService>
210 newCBService([[CBMutableService alloc] initWithType:cbUUID primary:primary],
212
213 if (!newCBService) {
214 qCCritical(QT_BT_DARWIN) << "addService: failed to create CBMutableService";
215 return {};
216 }
217
219 newQtService->state = QLowEnergyService::LocalService;
220 newQtService->uuid = data.uuid();
221 newQtService->type = primary ? QLES::PrimaryService : QLES::IncludedService;
222 newQtService->startHandle = ++lastHandle;
223 // Controller will be set by ... controller :)
224
225 [self addIncludedServices:data to:newCBService qtService:newQtService.data()];
226 [self addCharacteristicsAndDescriptors:data to:newCBService qtService:newQtService.data()];
227
228 services.push_back(newCBService);
229 serviceIndex[data.uuid()] = newCBService;
230
231 newQtService->endHandle = lastHandle;
232
233 return newQtService;
234}
235
236- (void) setParameters:(const QLowEnergyAdvertisingParameters &)parameters
237 data:(const QLowEnergyAdvertisingData &)data
238 scanResponse:(const QLowEnergyAdvertisingData &)scanResponse
239{
240 Q_UNUSED(parameters);
241
242 // This is the last method we call on the controller's thread
243 // before starting advertising on the Qt's LE queue.
244 // From Apple's docs:
245 /*
246 - (void)startAdvertising:(NSDictionary *)advertisementData
247
248 Advertises peripheral manager data.
249
250 * advertisementData
251
252 - An optional dictionary containing the data you want to advertise.
253 The possible keys of an advertisementData dictionary are detailed in CBCentralManagerDelegate
254 Protocol Reference. That said, only two of the keys are supported for peripheral manager objects:
255 CBAdvertisementDataLocalNameKey and CBAdvertisementDataServiceUUIDsKey.
256 */
257
259
260 advertisementData.reset([[NSMutableDictionary alloc] init],
262 if (!advertisementData) {
263 qCWarning(QT_BT_DARWIN) << "setParameters: failed to allocate "
264 "NSMutableDictonary (advertisementData)";
265 return;
266 }
267
268 auto localName = scanResponse.localName();
269 if (!localName.size())
270 localName = data.localName();
271
272 if (localName.size()) {
273 [advertisementData setObject:localName.toNSString()
274 forKey:CBAdvertisementDataLocalNameKey];
275 }
276
277 if (data.services().isEmpty() && scanResponse.services().isEmpty())
278 return;
279
280 const ObjCScopedPointer<NSMutableArray> uuids([[NSMutableArray alloc] init],
282 if (!uuids) {
283 qCWarning(QT_BT_DARWIN) << "setParameters: failed to allocate "
284 "NSMutableArray (services uuids)";
285 return;
286 }
287
288
289 for (const auto &qtUUID : data.services()) {
290 const auto cbUUID = cb_uuid(qtUUID);
291 if (cbUUID)
292 [uuids addObject:cbUUID];
293 }
294
295 for (const auto &qtUUID : scanResponse.services()) {
296 const auto cbUUID = cb_uuid(qtUUID);
297 if (cbUUID)
298 [uuids addObject:cbUUID];
299 }
300
301 if ([uuids count]) {
302 [advertisementData setObject:uuids
303 forKey:CBAdvertisementDataServiceUUIDsKey];
304 }
305}
306
307- (void)startAdvertising
308{
310 if (manager)
311 [manager setDelegate:nil];
312 manager.reset([[CBPeripheralManager alloc] initWithDelegate:self
315}
316
317- (void)stopAdvertising
318{
319 [manager stopAdvertising];
321}
322
323- (void)detach
324{
325 if (notifier) {
328 notifier = nullptr;
329 }
330
332 [manager stopAdvertising];
333 [manager setDelegate:nil];
335 }
336}
337
338- (void)write:(const QByteArray &)value
339 charHandle:(QLowEnergyHandle)charHandle
340{
341 using namespace DarwinBluetooth;
342
343 if (!notifier)
344 return;
345
347
348 if (!charMap.contains(charHandle) || !valueRanges.contains(charHandle)) {
350 return;
351 }
352
353 const auto & range = valueRanges[charHandle];
354 if (value.size() < qsizetype(range.first) || value.size() > qsizetype(range.second)
355#ifdef Q_OS_IOS
357#else
358 ) {
359#endif
360 qCWarning(QT_BT_DARWIN) << "ignoring value of invalid length" << value.size();
361 return;
362 }
363
365
366 const auto nsData = mutable_data_from_bytearray(value);
367 charValues[charHandle] = nsData;
368 // We copy data here: sending update requests is async (see sendUpdateRequests),
369 // by the time we're allowed to actually send them, the data can change again
370 // and we'll send an 'out of order' value.
371 const ObjCStrongReference<NSData> copy([NSData dataWithData:nsData], RetainPolicy::doInitialRetain);
372 updateQueue.push_back(UpdateRequest{charHandle, copy});
373 [self sendUpdateRequests];
374}
375
376- (void) addServicesToPeripheral
377{
379
380 if (nextServiceToAdd < services.size())
381 [manager addService:services[nextServiceToAdd++]];
382}
383
384// CBPeripheralManagerDelegate:
385
386- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
387{
388#pragma clang diagnostic push
389#pragma clang diagnostic ignored "-Wunguarded-availability-new"
390
391 if (peripheral != manager || !notifier)
392 return;
393
394 if (peripheral.state == CBManagerStatePoweredOn) {
395 // "Bluetooth is currently powered on and is available to use."
397 [manager removeAllServices];
398 nextServiceToAdd = {};
400 nOfFailedAds = 0;
401 [self addServicesToPeripheral];
402 }
403 return;
404 }
405
406 /*
407 "A state with a value lower than CBPeripheralManagerStatePoweredOn implies that
408 advertising has stopped and that any connected centrals have been disconnected."
409 */
410
411 maxNotificationValueLength = std::numeric_limits<NSUInteger>::max();
412
415 } else if (state == PeripheralState::connected) {
418 }
419
420 // The next four states are _below_ "powered off"; according to the docs:
421 /*
422 "In addition, the local database is cleared and all services must be
423 explicitly added again."
424 */
425
426 if (peripheral.state == CBManagerStateUnsupported) {
429 } else if (peripheral.state == CBManagerStateUnauthorized) {
432 }
433
434#pragma clang diagnostic pop
435}
436
437- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
438 error:(NSError *)error
439{
440 if (peripheral != manager || !notifier)
441 return;
442
443 if (error) {
444 NSLog(@"failed to start advertising, error: %@", error);
447 }
448}
449
450- (void)peripheralManager:(CBPeripheralManager *)peripheral
451 didAddService:(CBService *)service error:(NSError *)error
452{
453 Q_UNUSED(service);
454
455 if (peripheral != manager || !notifier)
456 return;
457
458 if (error) {
459 NSLog(@"failed to add a service, error: %@", error);
460 if (++nOfFailedAds == services.size()) {
463 return;
464 }
465 }
466
467 if (nextServiceToAdd == services.size()) {
468 nOfFailedAds = 0; // Discard any failed, some services made it into advertising.
469 [manager startAdvertising:[advertisementData count] ? advertisementData.get() : nil];
470 } else {
471 [self addServicesToPeripheral];
472 }
473}
474
475- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
476 didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
477{
478 Q_UNUSED(characteristic);
479
480 if (peripheral != manager || !notifier)
481 return;
482
483 [self addConnectedCentral:central];
484
485 if (const auto handle = charMap.key(characteristic))
487}
488
489- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
490 didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
491{
492 Q_UNUSED(characteristic);
493
494 if (peripheral != manager || !notifier)
495 return;
496
497 const auto handle = charMap.key(characteristic);
498 if (![static_cast<CBMutableCharacteristic*>(characteristic).subscribedCentrals count]
499 && handle)
501}
502
503- (void)peripheralManager:(CBPeripheralManager *)peripheral
504 didReceiveReadRequest:(CBATTRequest *)request
505{
506 if (peripheral != manager || !notifier)
507 return;
508
510
511 const auto handle = charMap.key(request.characteristic);
512 if (!handle || !charValues.contains(handle)) {
513 qCWarning(QT_BT_DARWIN) << "invalid read request, unknown characteristic";
514 [manager respondToRequest:request withResult:CBATTErrorInvalidHandle];
515 return;
516 }
517
518 const auto &value = charValues[handle];
519 if (request.offset > [value length]) {
520 qCWarning(QT_BT_DARWIN) << "invalid offset in a read request";
521 [manager respondToRequest:request withResult:CBATTErrorInvalidOffset];
522 return;
523 }
524
525 [self addConnectedCentral:request.central];
526
527 NSData *dataToSend = nil;
528 if (!request.offset) {
529 dataToSend = value;
530 } else {
531 dataToSend = [value subdataWithRange:
532 NSMakeRange(request.offset, [value length] - request.offset)];
533 }
534
535 request.value = dataToSend;
536 [manager respondToRequest:request withResult:CBATTErrorSuccess];
537}
538
539
540- (void)writeValueForCharacteristic:(QLowEnergyHandle) charHandle
541 withWriteRequest:(CBATTRequest *)request
542{
543 Q_ASSERT(charHandle);
545
546 Q_ASSERT(valueRanges.contains(charHandle));
547 const auto &range = valueRanges[charHandle];
548 Q_ASSERT(request.offset <= range.second
549 && request.value.length <= range.second - request.offset);
550
551 Q_ASSERT(charValues.contains(charHandle));
552 NSMutableData *const value = charValues[charHandle];
553 if (request.offset + request.value.length > value.length)
554 [value increaseLengthBy:request.offset + request.value.length - value.length];
555
556 [value replaceBytesInRange:NSMakeRange(request.offset, request.value.length)
557 withBytes:request.value.bytes];
558}
559
560- (void)peripheralManager:(CBPeripheralManager *)peripheral
561 didReceiveWriteRequests:(NSArray *)requests
562{
563 using namespace DarwinBluetooth;
564
566
567 if (peripheral != manager || !notifier) {
568 // Detached already.
569 return;
570 }
571
572 // We first test if all requests are valid
573 // since CoreBluetooth requires "all or none"
574 // and respond only _once_ to the first one.
575 for (CBATTRequest *request in requests) {
576 const auto status = [self validateWriteRequest:request];
577 if (status != CBATTErrorSuccess) {
578 [manager respondToRequest:[requests objectAtIndex:0]
579 withResult:status];
580 return;
581 }
582 }
583
584 std::map<QLowEnergyHandle, NSUInteger> updated;
585
586 for (CBATTRequest *request in requests) {
587 // Transition to 'connected' if needed.
588 [self addConnectedCentral:request.central];
589 const auto charHandle = charMap.key(request.characteristic);
590 const auto prevLen = updated[charHandle];
591 updated[charHandle] = std::max(request.offset + request.value.length,
592 prevLen);
593 [self writeValueForCharacteristic:charHandle withWriteRequest:request];
594 }
595
596 for (const auto &pair : updated) {
597 const auto handle = pair.first;
598 NSMutableData *value = charValues[handle];
599 value.length = pair.second;
601 const ObjCStrongReference<NSData> copy([NSData dataWithData:value],
604 }
605
606 if (requests.count) {
607 [manager respondToRequest:[requests objectAtIndex:0]
608 withResult:CBATTErrorSuccess];
609 }
610
611 [self sendUpdateRequests];
612}
613
614- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
615{
616 if (peripheral != manager || !notifier) {
617 // Detached.
618 return;
619 }
620
621 [self sendUpdateRequests];
622}
623
624- (void)sendUpdateRequests
625{
627
628 while (updateQueue.size()) {
629 const auto &request = updateQueue.front();
630 if (charMap.contains(request.charHandle)) {
632 qCWarning(QT_BT_DARWIN) << "value of length" << [request.value length]
633 << "will possibly be truncated to"
635 }
636 const BOOL res = [manager updateValue:request.value
637 forCharacteristic:static_cast<CBMutableCharacteristic *>(charMap[request.charHandle])
638 onSubscribedCentrals:nil];
639 if (!res) {
640 // Have to wait for the 'ManagerIsReadyToUpdate'.
641 break;
642 }
643 }
644
645 updateQueue.pop_front();
646 }
647}
648
649// Private API:
650
651- (void)addConnectedCentral:(CBCentral *)central
652{
653 if (!central)
654 return;
655
656 if (!notifier) {
657 // We were detached.
658 return;
659 }
660
662 central.maximumUpdateValueLength);
663
665
669 }
670}
671
672- (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID
673{
674 const auto it = serviceIndex.find(qtUUID);
675 if (it == serviceIndex.end())
676 return nil;
677
678 return it->second;
679}
680
681- (void)addIncludedServices:(const QLowEnergyServiceData &)data
682 to:(CBMutableService *)cbService
683 qtService:(QLowEnergyServicePrivate *)qtService
684{
685 Q_ASSERT(cbService);
686 Q_ASSERT(qtService);
687
689
690 ObjCScopedPointer<NSMutableArray> included([[NSMutableArray alloc] init],
692 if (!included) {
693 qCWarning(QT_BT_DARWIN) << "addIncludedSerivces: failed "
694 "to allocate NSMutableArray";
695 return;
696 }
697
698 for (auto includedService : data.includedServices()) {
699 if (CBService *cbs = [self findIncludedService:includedService->serviceUuid()]) {
700 [included addObject:cbs];
701 qtService->includedServices << includedService->serviceUuid();
702 ++lastHandle;
703 } else {
704 qCWarning(QT_BT_DARWIN) << "can not use" << includedService->serviceUuid()
705 << "as included, it has to be added first";
706 }
707 }
708
709 if ([included count])
710 cbService.includedServices = included;
711}
712
713- (void)addCharacteristicsAndDescriptors:(const QLowEnergyServiceData &)data
714 to:(CBMutableService *)cbService
715 qtService:(QLowEnergyServicePrivate *)qtService
716{
717 Q_ASSERT(cbService);
718 Q_ASSERT(qtService);
719
721
722 ObjCScopedPointer<NSMutableArray> newCBChars([[NSMutableArray alloc] init],
724 if (!newCBChars) {
725 qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
726 "failed to allocate NSMutableArray "
727 "(characteristics)";
728 return;
729 }
730
731 for (const auto &ch : data.characteristics()) {
732 if (!qt_validate_value_range(ch)) {
733 qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
734 "invalid value size/min-max length";
735 continue;
736 }
737
738#ifdef Q_OS_IOS
739 if (ch.value().size() > DarwinBluetooth::maxValueLength) {
740 qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
741 "value exceeds the maximal permitted "
742 "value length ("
744 << "octets) on the platform";
745 continue;
746 }
747#endif
748
749 const auto cbChar(create_characteristic(ch));
750 if (!cbChar) {
751 qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
752 "failed to allocate a characteristic";
753 continue;
754 }
755
756 const auto nsData(mutable_data_from_bytearray(ch.value()));
757 if (!nsData) {
758 qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
759 "addService: failed to allocate NSData (char value)";
760 continue;
761 }
762
763 [newCBChars addObject:cbChar];
764
765 const auto declHandle = ++lastHandle;
766 // CB part:
767 charMap[declHandle] = cbChar;
768 charValues[declHandle] = nsData;
769 valueRanges[declHandle] = ValueRange(ch.minimumValueLength(), ch.maximumValueLength());
770 // QT part:
772 charData.valueHandle = declHandle;
773 charData.uuid = ch.uuid();
774 charData.properties = ch.properties();
775 charData.value = ch.value();
776
777 const ObjCScopedPointer<NSMutableArray> newCBDescs([[NSMutableArray alloc] init],
779 if (!newCBDescs) {
780 qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
781 "failed to allocate NSMutableArray "
782 "(descriptors)";
783 continue;
784 }
785
786 for (const auto &desc : ch.descriptors()) {
787 // CB part:
788 const auto cbDesc(create_descriptor(desc));
789 const auto descHandle = ++lastHandle;
790 if (cbDesc) {
791 // See comments in create_descriptor on
792 // why cbDesc can be nil.
793 [newCBDescs addObject:cbDesc];
794 }
795 // QT part:
797 descData.uuid = desc.uuid();
798 descData.value = desc.value();
799 charData.descriptorList.insert(descHandle, descData);
800 }
801
802 if ([newCBDescs count])
803 cbChar.data().descriptors = newCBDescs.get();
804
805 qtService->characteristicList.insert(declHandle, charData);
806 }
807
808 if ([newCBChars count])
809 cbService.characteristics = newCBChars.get();
810}
811
812- (CBATTError)validateWriteRequest:(CBATTRequest *)request
813{
815
817
818 const auto handle = charMap.key(request.characteristic);
819 if (!handle || !charValues.contains(handle))
820 return CBATTErrorInvalidHandle;
821
822 Q_ASSERT(valueRanges.contains(handle));
823
824 const auto &range = valueRanges[handle];
825 if (request.offset > range.second)
826 return CBATTErrorInvalidOffset;
827
828 if (request.value.length > range.second - request.offset)
829 return CBATTErrorInvalidAttributeValueLength;
830
831 return CBATTErrorSuccess;
832}
833
834@end
DarwinBluetooth::CharHash charMap
CBPeripheral * peripheral
DarwinBluetooth::RequestQueue requests
DarwinBluetooth::LECBManagerNotifier * notifier
PeripheralState state
std::map< QBluetoothUuid, CBService * > serviceIndex
decltype(services.size()) nOfFailedAds
QMap< QLowEnergyHandle, ValueRange > valueRanges
ObjCScopedPointer< NSMutableDictionary > advertisementData
NSUInteger maxNotificationValueLength
GenericLEMap< CBCharacteristic * > charMap
GenericLEMap< ObjCStrongReference< NSMutableData > > charValues
QLowEnergyHandle lastHandle
decltype(services.size()) nextServiceToAdd
std::deque< UpdateRequest > updateQueue
LECBManagerNotifier * notifier
std::vector< ObjCStrongReference< CBMutableService > > services
QPair< NSUInteger, NSUInteger > ValueRange
#define QT_BT_MAC_AUTORELEASEPOOL
Definition btutility_p.h:78
void characteristicUpdated(QLowEnergyHandle charHandle, const QByteArray &value)
void characteristicWritten(QLowEnergyHandle charHandle, const QByteArray &value)
void notificationEnabled(QLowEnergyHandle charHandle, bool enabled)
void CBManagerError(QBluetoothDeviceDiscoveryAgent::Error error)
\inmodule QtBluetooth
\inmodule QtCore
Definition qbytearray.h:57
qsizetype length() const noexcept
Same as size().
Definition qbytearray.h:499
The QLowEnergyAdvertisingData class represents the data to be broadcast during Bluetooth Low Energy a...
The QLowEnergyAdvertisingParameters class represents the parameters used for Bluetooth Low Energy adv...
The QLowEnergyCharacteristicData class is used to set up GATT service data. \inmodule QtBluetooth.
QLowEnergyCharacteristic::PropertyTypes properties() const
Returns the properties of the characteristic.
The QLowEnergyDescriptorData class is used to create GATT service data. \inmodule QtBluetooth.
The QLowEnergyServiceData class is used to set up GATT service data. \inmodule QtBluetooth.
\inmodule QtBluetooth
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
\inmodule QtCore
static QSharedPointer create(Args &&...arguments)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QSet< QString >::iterator it
else opt state
[0]
ObjCStrongReference< CBUUID > cb_uuid(const QBluetoothUuid &qtUuid)
Definition btutility.mm:174
ObjCStrongReference< NSMutableData > mutable_data_from_bytearray(const QByteArray &qtData)
Definition btutility.mm:281
QByteArray qt_bytearray(NSData *data)
Definition btutility.mm:201
NSUInteger qt_countGATTEntries(CBService *service)
const int maxValueLength
Definition btutility.mm:32
ObjCStrongReference< NSData > data_from_bytearray(const QByteArray &qtData)
Definition btutility.mm:272
dispatch_queue_t qt_LE_queue()
Definition btutility.mm:324
QString self
Definition language.cpp:58
static jboolean copy(JNIEnv *, jobject)
quint16 QLowEnergyHandle
Definition qbluetooth.h:42
unsigned long NSUInteger
static const QCssKnownValue properties[NumProperties - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCCritical(category,...)
#define qCWarning(category,...)
GLuint64 GLenum void * handle
GLenum GLuint GLenum GLsizei length
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei range
GLenum GLuint GLsizei const GLenum * props
GLuint res
GLuint in
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
ptrdiff_t qsizetype
Definition qtypes.h:165
gzip write("uncompressed data")
QQueue< int > queue
[0]
QNetworkAccessManager manager
QNetworkRequest request(url)