Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
btutility.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
4
#
include
"qlowenergycharacteristicdata.h"
5
#
include
"qbluetoothaddress.h"
6
#
include
"qbluetoothuuid.h"
7
#
include
"btutility_p.h"
8
9
#
include
<
QtCore
/
qoperatingsystemversion
.
h
>
10
#
include
<
QtCore
/
qendian
.
h
>
11
#
include
<
QtCore
/
qstring
.
h
>
12
13
#
ifndef
QT_IOS_BLUETOOTH
14
15
#
import
<
IOBluetooth
/
objc
/
IOBluetoothSDPUUID
.
h
>
16
#
import
<
CoreFoundation
/
CoreFoundation
.
h
>
17
#
import
<
CoreBluetooth
/
CBUUID
.
h
>
18
19
#
endif
20
21
#
include
<
algorithm
>
22
#
include
<
limits
>
23
24
QT_BEGIN_NAMESPACE
25
26
Q_LOGGING_CATEGORY
(QT_BT_DARWIN,
"qt.bluetooth.darwin"
)
27
28
namespace
DarwinBluetooth
{
29
30
const
int
defaultLEScanTimeoutMS
= 40000;
31
// We use it only on iOS for now:
32
const
int
maxValueLength
= 512;
33
34
const
int
defaultMtu
= 23;
35
36
QString
qt_address
(NSString *address)
37
{
38
if
(address && address.length) {
39
NSString *
const
fixed = [address stringByReplacingOccurrencesOfString:@
"-"
withString:@
":"
];
40
return
QString::fromNSString(fixed);
41
}
42
43
return
QString();
44
}
45
46
#
ifndef
QT_IOS_BLUETOOTH
47
48
49
QBluetoothAddress
qt_address
(
const
BluetoothDeviceAddress *a)
50
{
51
if
(a) {
52
// TODO: can a byte order be different in BluetoothDeviceAddress?
53
const
quint64 qAddress = a->data[5] |
54
qint64(a->data[4]) << 8 |
55
qint64(a->data[3]) << 16 |
56
qint64(a->data[2]) << 24 |
57
qint64(a->data[1]) << 32 |
58
qint64(a->data[0]) << 40;
59
return
QBluetoothAddress(qAddress);
60
}
61
62
return
QBluetoothAddress();
63
}
64
65
BluetoothDeviceAddress
iobluetooth_address
(
const
QBluetoothAddress &qAddress)
66
{
67
BluetoothDeviceAddress a = {};
68
if
(!qAddress.isNull()) {
69
const
quint64 val = qAddress.toUInt64();
70
a.data[0] = (val >> 40) & 0xff;
71
a.data[1] = (val >> 32) & 0xff;
72
a.data[2] = (val >> 24) & 0xff;
73
a.data[3] = (val >> 16) & 0xff;
74
a.data[4] = (val >> 8) & 0xff;
75
a.data[5] = val & 0xff;
76
}
77
78
return
a;
79
}
80
81
ObjCStrongReference
<
IOBluetoothSDPUUID
>
iobluetooth_uuid
(
const
QBluetoothUuid &uuid)
82
{
83
const
unsigned
nBytes = 128 /
std
::numeric_limits<
unsigned
char
>::digits;
84
const
QUuid::Id128Bytes intVal(uuid.toBytes());
85
86
const
ObjCStrongReference<IOBluetoothSDPUUID> iobtUUID([IOBluetoothSDPUUID uuidWithBytes:intVal.data
87
length:nBytes], RetainPolicy::doInitialRetain);
88
return
iobtUUID;
89
}
90
91
QBluetoothUuid
qt_uuid
(IOBluetoothSDPUUID *uuid)
92
{
93
QBluetoothUuid qtUuid;
94
if
(!uuid || [uuid length] != 16)
// TODO: issue any diagnostic?
95
return
qtUuid;
96
97
// TODO: ensure the correct byte-order!!!
98
QUuid::Id128Bytes uuidVal = {};
99
const
quint8 *
const
source =
static_cast
<
const
quint8 *>([uuid bytes]);
100
std
::copy(source, source + 16, uuidVal.data);
101
return
QBluetoothUuid(uuidVal);
102
}
103
104
QString
qt_error_string
(IOReturn errorCode)
105
{
106
switch
(errorCode) {
107
case
kIOReturnSuccess:
108
// NoError in many classes == an empty string description.
109
return
QString();
110
case
kIOReturnNoMemory:
111
return
QString::fromLatin1(
"memory allocation failed"
);
112
case
kIOReturnNoResources:
113
return
QString::fromLatin1(
"failed to obtain a resource"
);
114
case
kIOReturnBusy:
115
return
QString::fromLatin1(
"device is busy"
);
116
case
kIOReturnStillOpen:
117
return
QString::fromLatin1(
"device(s) still open"
);
118
// Others later ...
119
case
kIOReturnError:
// "general error" (IOReturn.h)
120
default
:
121
return
QString::fromLatin1(
"unknown error"
);
122
}
123
}
124
125
void
qt_test_iobluetooth_runloop
()
126
{
127
// IOBluetooth heavily relies on a CFRunLoop machinery in a way it dispatches
128
// its callbacks. Technically, having a QThread with CFRunLoop-based event
129
// dispatcher would suffice. At the moment of writing we do not have such
130
// event dispatcher, so we only can work on the main thread.
131
if
(CFRunLoopGetMain() != CFRunLoopGetCurrent()) {
132
qCWarning(QT_BT_DARWIN) <<
"IOBluetooth works only on the main thread or a"
133
<<
"thread with a running CFRunLoop"
;
134
}
135
}
136
137
#
endif
// !QT_IOS_BLUETOOTH
138
139
// Apple has: CBUUID, NSUUID, CFUUID, IOBluetoothSDPUUID
140
// and it's handy to have several converters:
141
142
QBluetoothUuid
qt_uuid
(CBUUID *uuid)
143
{
144
// Apples' docs say "128 bit" and "16-bit UUIDs are implicitly
145
// pre-filled with the Bluetooth Base UUID."
146
// But Core Bluetooth can return CBUUID objects of length 2, 4, and 16.
147
148
if
(!uuid)
149
return
QBluetoothUuid();
150
151
QT_BT_MAC_AUTORELEASEPOOL
;
152
153
if
(uuid.data.length == 2) {
154
// CBUUID's docs say nothing about byte-order.
155
// Seems to be in big-endian.
156
const
uchar *
const
src =
static_cast
<
const
uchar *>(uuid.data.bytes);
157
return
QBluetoothUuid(qFromBigEndian<quint16>(src));
158
}
else
if
(uuid.data.length == 4) {
159
const
uchar *
const
src =
static_cast
<
const
uchar *>(uuid.data.bytes);
160
return
QBluetoothUuid(qFromBigEndian<quint32>(src));
161
}
else
if
(uuid.data.length == 16) {
162
QUuid::Id128Bytes qtUuidData = {};
163
const
quint8 *
const
source =
static_cast
<
const
quint8 *>(uuid.data.bytes);
164
std
::copy(source, source + 16, qtUuidData.data);
165
166
return
QBluetoothUuid(qtUuidData);
167
}
168
169
qCDebug(QT_BT_DARWIN) <<
"qt_uuid, invalid CBUUID, 2, 4, or 16 bytes expected, but got "
170
<< uuid.data.length <<
" bytes length"
;
171
return
QBluetoothUuid();
172
}
173
174
ObjCStrongReference
<
CBUUID
>
cb_uuid
(
const
QBluetoothUuid &qtUuid)
175
{
176
bool
ok =
false
;
177
const
auto
asUInt16 = qToBigEndian(qtUuid.toUInt16(&ok));
178
const
auto
asUInt128 = qtUuid.toBytes();
179
180
const
NSUInteger length = ok ?
sizeof
asUInt16 :
sizeof
asUInt128;
181
const
void
*bytes = &asUInt128;
182
if
(ok)
183
bytes = &asUInt16;
184
185
NSData *uuidData = [NSData dataWithBytes:bytes length:length];
186
ObjCStrongReference<CBUUID> cbUuid([CBUUID UUIDWithData:uuidData], RetainPolicy::doInitialRetain);
187
return
cbUuid;
188
}
189
190
bool
equal_uuids
(
const
QBluetoothUuid &qtUuid, CBUUID *cbUuid)
191
{
192
const
QBluetoothUuid qtUuid2(qt_uuid(cbUuid));
193
return
qtUuid == qtUuid2;
194
}
195
196
bool
equal_uuids
(CBUUID *cbUuid,
const
QBluetoothUuid &qtUuid)
197
{
198
return
equal_uuids(qtUuid, cbUuid);
199
}
200
201
QByteArray
qt_bytearray
(NSData *data)
202
{
203
QByteArray value;
204
if
(!data || !data.length)
205
return
value;
206
207
value.resize(data.length);
208
const
char
*
const
src =
static_cast
<
const
char
*>(data.bytes);
209
std
::copy(src, src + data.length, value.data());
210
211
return
value;
212
}
213
214
template
<
class
Integer>
215
QByteArray
qt_bytearray
(Integer n)
216
{
217
QByteArray value;
218
value.resize(
sizeof
n);
219
const
char
*
const
src =
reinterpret_cast
<
char
*>(&n);
220
std
::copy(src, src +
sizeof
n, value.data());
221
222
return
value;
223
}
224
225
QByteArray
qt_bytearray
(NSString *string)
226
{
227
if
(!string)
228
return
QByteArray();
229
230
QT_BT_MAC_AUTORELEASEPOOL
;
231
NSData *
const
utf8Data = [string dataUsingEncoding:NSUTF8StringEncoding];
232
233
return
qt_bytearray(utf8Data);
234
}
235
236
QByteArray
qt_bytearray
(NSObject *obj)
237
{
238
// descriptor.value has type 'id'.
239
// While the Apple's docs say this about descriptors:
240
//
241
// - CBUUIDCharacteristicExtendedPropertiesString
242
// The string representation of the UUID for the extended properties descriptor.
243
// The corresponding value for this descriptor is an NSNumber object.
244
//
245
// - CBUUIDCharacteristicUserDescriptionString
246
// The string representation of the UUID for the user description descriptor.
247
// The corresponding value for this descriptor is an NSString object.
248
//
249
// ... etc.
250
//
251
// This is not true. On OS X, they all seem to be NSData (or derived from NSData),
252
// and they can be something else on iOS (NSNumber, NSString, etc.)
253
if
(!obj)
254
return
QByteArray();
255
256
QT_BT_MAC_AUTORELEASEPOOL
;
257
258
if
([obj isKindOfClass:[NSData
class
]]) {
259
return
qt_bytearray(
static_cast
<NSData *>(obj));
260
}
else
if
([
obj
isKindOfClass
:[
NSString
class
]]) {
261
return
qt_bytearray
(
static_cast
<
NSString
*>(
obj
));
262
}
else
if
([
obj
isKindOfClass
:[
NSNumber
class
]]) {
263
NSNumber
*
const
nsNumber
=
static_cast
<
NSNumber
*>(
obj
);
264
return
qt_bytearray
([
nsNumber
unsignedShortValue
]);
265
}
266
// TODO: Where can be more types, but Core Bluetooth does not support them,
267
// or at least it's not documented.
268
269
return
QByteArray
();
270
}
271
272
ObjCStrongReference<NSData> data_from_bytearray(
const
QByteArray & qtData)
273
{
274
if
(!qtData.size())
275
return
ObjCStrongReference<NSData>([[NSData alloc] init], RetainPolicy::noInitialRetain);
276
277
ObjCStrongReference<NSData> result([NSData dataWithBytes:qtData.constData() length:qtData.size()], RetainPolicy::doInitialRetain);
278
return
result;
279
}
280
281
ObjCStrongReference<NSMutableData> mutable_data_from_bytearray(
const
QByteArray &qtData)
282
{
283
using
MutableData = ObjCStrongReference<NSMutableData>;
284
285
if
(!qtData.size())
286
return
MutableData([[NSMutableData alloc] init], RetainPolicy::noInitialRetain);
287
288
MutableData result([[NSMutableData alloc] initWithLength:qtData.size()], RetainPolicy::noInitialRetain);
289
[result replaceBytesInRange:NSMakeRange(0, qtData.size())
290
withBytes:qtData.constData()];
291
return
result;
292
}
293
294
// A small RAII class for a dispatch queue.
295
class
SerialDispatchQueue
296
{
297
public
:
298
explicit
SerialDispatchQueue
(
const
char
*label)
299
{
300
Q_ASSERT(label);
301
302
queue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL);
303
if
(!queue) {
304
qCCritical(QT_BT_DARWIN) <<
"failed to create dispatch queue with label"
305
<< label;
306
}
307
}
308
~
SerialDispatchQueue
()
309
{
310
if
(queue)
311
dispatch_release(queue);
312
}
313
314
dispatch_queue_t
data
()
const
315
{
316
return
queue;
317
}
318
private
:
319
dispatch_queue_t queue;
320
321
Q_DISABLE_COPY
(
SerialDispatchQueue
)
322
};
323
324
dispatch_queue_t qt_LE_queue()
325
{
326
static
const
SerialDispatchQueue
leQueue
(
"qt-bluetooth-LE-queue"
)
;
327
return
leQueue.data();
328
}
329
330
}
// namespace DarwinBluetooth
331
332
QT_END_NAMESPACE
QT_BT_MAC_AUTORELEASEPOOL
#define QT_BT_MAC_AUTORELEASEPOOL
Definition
btutility_p.h:78
DarwinBluetooth::SerialDispatchQueue
Definition
btutility.mm:296
DarwinBluetooth::SerialDispatchQueue::SerialDispatchQueue
SerialDispatchQueue(const char *label)
Definition
btutility.mm:298
DarwinBluetooth::SerialDispatchQueue::data
dispatch_queue_t data() const
Definition
btutility.mm:314
DarwinBluetooth::SerialDispatchQueue::~SerialDispatchQueue
~SerialDispatchQueue()
Definition
btutility.mm:308
DarwinBluetooth
Definition
btcentralmanager.mm:22
DarwinBluetooth::cb_uuid
ObjCStrongReference< CBUUID > cb_uuid(const QBluetoothUuid &qtUuid)
Definition
btutility.mm:174
DarwinBluetooth::defaultLEScanTimeoutMS
const int defaultLEScanTimeoutMS
Definition
btutility.mm:30
DarwinBluetooth::equal_uuids
bool equal_uuids(const QBluetoothUuid &qtUuid, CBUUID *cbUuid)
Definition
btutility.mm:190
DarwinBluetooth::qt_bytearray
QByteArray qt_bytearray(NSData *data)
Definition
btutility.mm:201
DarwinBluetooth::qt_address
QString qt_address(NSString *address)
Definition
btutility.mm:36
DarwinBluetooth::qt_bytearray
QByteArray qt_bytearray(Integer n)
Definition
btutility.mm:215
DarwinBluetooth::qt_test_iobluetooth_runloop
void qt_test_iobluetooth_runloop()
Definition
btutility.mm:125
DarwinBluetooth::iobluetooth_address
BluetoothDeviceAddress iobluetooth_address(const QBluetoothAddress &address)
Definition
btutility.mm:65
DarwinBluetooth::qt_error_string
QString qt_error_string(IOReturn errorCode)
Definition
btutility.mm:104
DarwinBluetooth::maxValueLength
const int maxValueLength
Definition
btutility.mm:32
DarwinBluetooth::qt_address
QBluetoothAddress qt_address(const BluetoothDeviceAddress *address)
Definition
btutility.mm:49
DarwinBluetooth::iobluetooth_uuid
ObjCStrongReference< IOBluetoothSDPUUID > iobluetooth_uuid(const QBluetoothUuid &uuid)
Definition
btutility.mm:81
DarwinBluetooth::qt_uuid
QBluetoothUuid qt_uuid(IOBluetoothSDPUUID *uuid)
Definition
btutility.mm:91
DarwinBluetooth::defaultMtu
const int defaultMtu
Definition
btutility.mm:34
DarwinBluetooth::equal_uuids
bool equal_uuids(CBUUID *cbUuid, const QBluetoothUuid &qtUuid)
Definition
btutility.mm:196
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
Q_LOGGING_CATEGORY
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
qtconnectivity
src
bluetooth
darwin
btutility.mm
Generated on
for Qt by
1.18.0