17#include <QtCore/QFileInfo>
18#include <QtCore/QLoggingCategory>
19#include <QtCore/QSettings>
20#include <QtCore/QTimer>
21#include <QtBluetooth/QBluetoothLocalDevice>
22#include <QtBluetooth/QBluetoothSocket>
23#include <QtBluetooth/QLowEnergyCharacteristicData>
24#include <QtBluetooth/QLowEnergyDescriptorData>
25#include <QtBluetooth/QLowEnergyService>
26#include <QtBluetooth/QLowEnergyServiceData>
33#include <sys/socket.h>
39#define GATT_PRIMARY_SERVICE quint16(0x2800)
40#define GATT_SECONDARY_SERVICE quint16(0x2801)
41#define GATT_INCLUDED_SERVICE quint16(0x2802)
42#define GATT_CHARACTERISTIC quint16(0x2803)
45#define ERROR_RESPONSE_HEADER_SIZE 5
46#define FIND_INFO_REQUEST_HEADER_SIZE 5
47#define GRP_TYPE_REQ_HEADER_SIZE 7
48#define READ_BY_TYPE_REQ_HEADER_SIZE 7
49#define READ_REQUEST_HEADER_SIZE 3
50#define READ_BLOB_REQUEST_HEADER_SIZE 5
51#define WRITE_REQUEST_HEADER_SIZE 3
52#define PREPARE_WRITE_HEADER_SIZE 5
53#define EXECUTE_WRITE_HEADER_SIZE 2
54#define MTU_EXCHANGE_HEADER_SIZE 3
56#define APPEND_VALUE true
57#define NEW_VALUE false
70 if (response.
size() != 5
86 errorString =
QStringLiteral(
"not readable attribute - permissions");
break;
88 errorString =
QStringLiteral(
"not writable attribute - permissions");
break;
92 errorString =
QStringLiteral(
"needs authentication - permissions");
break;
94 errorString =
QStringLiteral(
"server does not support request");
break;
96 errorString =
QStringLiteral(
"offset past end of attribute");
break;
98 errorString =
QStringLiteral(
"need authorization - permissions");
break;
100 errorString =
QStringLiteral(
"run out of prepare queue space");
break;
102 errorString =
QStringLiteral(
"no attribute in given range found");
break;
104 errorString =
QStringLiteral(
"attribute not read/written using read blob");
break;
106 errorString =
QStringLiteral(
"need encryption key size - permissions");
break;
108 errorString =
QStringLiteral(
"written value is invalid size");
break;
112 errorString =
QStringLiteral(
"needs encryption - permissions");
break;
116 errorString =
QStringLiteral(
"insufficient resources to complete request");
break;
127 qCDebug(QT_BT_BLUEZ) <<
"Error:" << errorCode <<
"Error description:" << errorString
128 <<
"last command:" << lastCommand <<
"handle:" <<
handle;
147 dst +=
sizeof(uuid16);
150 memcpy(
dst, btOrder.
data,
sizeof(btOrder));
151 dst +=
sizeof(btOrder);
165 securityLevelValue(-1),
166 encryptionChangePending(
false)
169 qRegisterMetaType<QList<QLowEnergyHandle> >();
175 hciManager = std::make_shared<HciManager>(
localAdapter);
177 if (!hciManager->isValid()){
186 hciManager->monitorAclPackets();
188 connectionHandle = handle;
189 qCDebug(QT_BT_BLUEZ) <<
"received connection complete event, handle:" << handle;
193 if (handle == connectionHandle)
194 emit q_ptr->connectionUpdated(params);
199 if (handle != connectionHandle)
201 if ((remoteKey && role == QLowEnergyController::CentralRole)
202 || (!remoteKey && role == QLowEnergyController::PeripheralRole)) {
205 qCDebug(QT_BT_BLUEZ) <<
"received new signature resolving key"
207 sizeof csrk).
toHex();
217 gattRequestTimeout =
value;
221 if (gattRequestTimeout > 0) {
222 qCWarning(QT_BT_BLUEZ) <<
"Enabling GATT request timeout behavior" << gattRequestTimeout;
223 requestTimer =
new QTimer(
this);
224 requestTimer->setSingleShot(
true);
225 requestTimer->setInterval(gattRequestTimeout);
227 this, &QLowEnergyControllerPrivateBluez::handleGattRequestTimeout);
232void QLowEnergyControllerPrivateBluez::handleGattRequestTimeout()
235 if (encryptionChangePending) {
237 qCWarning(QT_BT_BLUEZ) <<
"****** Encryption change event blocking further GATT requests";
241 if (!openRequests.
isEmpty() && requestPending) {
243 requestPending =
false;
245 qCWarning(QT_BT_BLUEZ).nospace() <<
"****** Request type 0x" << currentRequest.command
246 <<
" to server/peripheral timed out";
247 qCWarning(QT_BT_BLUEZ) <<
"****** Looks like the characteristic or descriptor does NOT act in"
248 <<
"accordance to Bluetooth 4.x spec.";
249 qCWarning(QT_BT_BLUEZ) <<
"****** Please check server implementation."
250 <<
"Continuing under reservation.";
257 errorPackage[1] =
static_cast<quint8>(
276 processReply(currentRequest, createRequestErrorMessage(command, 0));
284 uint handleData = currentRequest.reference.toUInt();
287 processReply(currentRequest, createRequestErrorMessage(command,
288 descriptorHandle ? descriptorHandle : charHandle));
291 processReply(currentRequest, createRequestErrorMessage(
292 command, currentRequest.reference2.toUInt()));
299 uint handleData = currentRequest.reference.toUInt();
301 processReply(currentRequest,
302 createRequestErrorMessage(command, attrHandle));
306 qCWarning(QT_BT_BLUEZ) <<
"Missing response for ATT peripheral command: "
312 sendNextPendingRequest();
319 delete cmacCalculator;
320 cmacCalculator =
nullptr;
329 if (m_socket == -1) {
340 addr.l2_family = AF_BLUETOOTH;
344 if (
::bind(m_socket,
reinterpret_cast<sockaddr *
>(&
addr),
sizeof addr) == -1) {
363 const int socket = m_socket;
377 qCDebug(QT_BT_BLUEZ) <<
"Starting to advertise";
382 &QLowEnergyControllerPrivateBluez::handleAdvertisingError);
388 qCDebug(QT_BT_BLUEZ) <<
"Non-connectable advertising requested, "
389 "not listening for connections.";
403 &QLowEnergyControllerPrivateBluez::handleConnectionRequest);
419 hciManager->sendConnectionUpdateCommand(connectionHandle,
params);
421 hciManager->sendConnectionParameterUpdateRequest(connectionHandle,
params);
427 qCWarning(QT_BT_BLUEZ) <<
"Invalid/null remote device address";
435 l2cpSocket =
nullptr;
438 createServicesForCentralIfRequired();
444 QList<quint16> activeHandles = hciManager->activeLowEnergyConnections();
445 if (!activeHandles.
isEmpty()) {
446 qCWarning(QT_BT_BLUEZ) <<
"Cannot connect due to pending active LE connections";
448 if (!device1Manager) {
451 this, &QLowEnergyControllerPrivateBluez::activeConnectionTerminationDone);
455 for (
const auto handle: activeHandles) {
462 establishL2cpClientSocket();
469void QLowEnergyControllerPrivateBluez::activeConnectionTerminationDone()
474 qCDebug(QT_BT_BLUEZ) <<
"RemoteDeviceManager finished attempting"
475 <<
"to close external connections";
477 QList<quint16> activeHandles = hciManager->activeLowEnergyConnections();
478 if (!activeHandles.
isEmpty()) {
479 qCWarning(QT_BT_BLUEZ) <<
"Cannot close pending external BTLE connections. Aborting connect attempt";
485 establishL2cpClientSocket();
492void QLowEnergyControllerPrivateBluez::establishL2cpClientSocket()
512 qCDebug(QT_BT_BLUEZ) <<
"addresstypeToUse:"
516 l2cpSocket->
d_ptr->lowEnergySocketType = addressTypeToUse;
520 qCWarning(QT_BT_BLUEZ) <<
"l2cp socket not initialised";
528 addr.l2_family = AF_BLUETOOTH;
545 loadSigningDataIfNecessary(LocalSigningKey);
548void QLowEnergyControllerPrivateBluez::createServicesForCentralIfRequired()
559 qCDebug(QT_BT_BLUEZ) <<
"Creating default GAP/GATT services";
614void QLowEnergyControllerPrivateBluez::l2cpConnected()
618 securityLevelValue = securityLevel();
635 qWarning(QT_BT_BLUEZ) <<
"Unexpected closure of device. Cleaning up internal states.";
640void QLowEnergyControllerPrivateBluez::l2cpDisconnected()
645 storeClientConfigurations();
652 emit q->disconnected();
660 qCDebug(QT_BT_BLUEZ) <<
"The passed remote device address cannot be found";
664 qCDebug(QT_BT_BLUEZ) <<
"Network IO error while talking to LE device";
668 qCDebug(QT_BT_BLUEZ) <<
"Remote host closed the connection";
688void QLowEnergyControllerPrivateBluez::resetController()
690 openRequests.
clear();
691 openPrepareWriteRequests.
clear();
692 scheduledIndications.
clear();
693 indicationInFlight =
false;
695 encryptionChangePending =
false;
696 receivedMtuExchangeRequest =
false;
698 securityLevelValue = -1;
699 connectionHandle = 0;
706 advertiser =
nullptr;
712void QLowEnergyControllerPrivateBluez::restartRequestTimer()
717 if (gattRequestTimeout > 0)
718 requestTimer->
start(gattRequestTimeout);
721void QLowEnergyControllerPrivateBluez::l2cpReadyRead()
724 qCDebug(QT_BT_BLUEZ) <<
"Received size:" << incomingPacket.
size() <<
"data:"
725 << incomingPacket.
toHex();
733 processUnsolicitedReply(incomingPacket);
742 processUnsolicitedReply(incomingPacket);
748 handleExchangeMtuRequest(incomingPacket);
751 handleFindInformationRequest(incomingPacket);
754 handleFindByTypeValueRequest(incomingPacket);
757 handleReadByTypeRequest(incomingPacket);
760 handleReadRequest(incomingPacket);
763 handleReadBlobRequest(incomingPacket);
766 handleReadMultipleRequest(incomingPacket);
769 handleReadByGroupTypeRequest(incomingPacket);
774 handleWriteRequestOrCommand(incomingPacket);
777 handlePrepareWriteRequest(incomingPacket);
780 handleExecuteWriteRequest(incomingPacket);
783 if (indicationInFlight) {
784 indicationInFlight =
false;
785 sendNextIndication();
787 qCWarning(QT_BT_BLUEZ) <<
"received unexpected handle value confirmation";
798 qCWarning(QT_BT_BLUEZ) <<
"Received unexpected packet from peer, disconnecting.";
804 processReply(
request, incomingPacket);
806 sendNextPendingRequest();
818void QLowEnergyControllerPrivateBluez::encryptionChangedEvent(
821 if (!encryptionChangePending)
827 securityLevelValue = securityLevel();
839 uint ref = failedRequest.reference.toUInt();
845 if (!
service.isNull() &&
service->characteristicList.contains(charHandle)) {
846 if (!descriptorHandle)
852 uint handleData = failedRequest.reference.toUInt();
854 const QByteArray newValue = failedRequest.reference2.toByteArray();
859 sendExecuteWriteRequest(attrHandle, newValue,
true);
863 encryptionChangePending =
false;
864 sendNextPendingRequest();
867void QLowEnergyControllerPrivateBluez::sendPacket(
const QByteArray &packet)
880 qCWarning(QT_BT_BLUEZ) <<
"L2CP write request incomplete:"
886void QLowEnergyControllerPrivateBluez::sendNextPendingRequest()
896 restartRequestTimer();
909 (QLowEnergyCharacteristic::PropertyTypes)(
data[2] & 0xff);
913 if (elementLength == 7)
918 qCDebug(QT_BT_BLUEZ) <<
"Found handle:" <<
Qt::hex << attributeHandle
923 return attributeHandle;
941 if (elementLength == 8)
947 << attributeHandle <<
"uuid:" << *foundServices;
949 return attributeHandle;
952void QLowEnergyControllerPrivateBluez::processReply(
959 bool isErrorResponse =
false;
964 isErrorResponse =
true;
972 if (isErrorResponse) {
981 qCDebug(QT_BT_BLUEZ) <<
"Server MTU:" <<
mtu <<
"resulting mtu:" << mtuSize;
983 if (oldMtuSize != mtuSize)
984 emit q->mtuChanged(mtuSize);
993 if (isErrorResponse) {
996 q->discoveryFinished();
1005 const quint16 numElements = (response.
size() - 2) / elementLength;
1008 for (
int i = 0;
i < numElements;
i++) {
1013 if (elementLength == 6)
1015 else if (elementLength == 20)
1022 qCDebug(QT_BT_BLUEZ) <<
"Found uuid:" << uuid <<
"start handle:" <<
Qt::hex
1031 priv->setController(
this);
1036 emit q->serviceDiscovered(uuid);
1039 if (
end != 0xFFFF) {
1040 sendReadByGroupRequest(
end+1, 0xFFFF,
type);
1044 emit q->discoveryFinished();
1059 if (isErrorResponse) {
1064 if (!
p->characteristicList.isEmpty()) {
1065 readServiceValues(
p->uuid,
true);
1092 const quint16 numElements = (response.
size() - 2) / elementLength;
1095 for (
int i = 0;
i < numElements;
i++) {
1099 &characteristic, &
data[
offset], elementLength);
1100 p->characteristicList[
lastHandle] = characteristic;
1105 &includedServices, &
data[
offset], elementLength);
1106 p->includedServices = includedServices;
1115 sendReadByTypeRequest(
p,
lastHandle + 1, attributeType);
1120 readServiceValues(
p->uuid,
true);
1134 bool isServiceDiscoveryRun
1137 if (isErrorResponse) {
1138 Q_ASSERT(!encryptionChangePending);
1140 encryptionChangePending = increaseEncryptLevelfRequired(err);
1141 if (encryptionChangePending) {
1146 }
else if (!isServiceDiscoveryRun) {
1148 if (!descriptorHandle)
1154 if (!descriptorHandle)
1160 if (response.
size() == mtuSize) {
1161 qCDebug(QT_BT_BLUEZ) <<
"Switching to blob reads for"
1162 << charHandle << descriptorHandle
1163 <<
service->characteristicList[charHandle].uuid.toString();
1165 readServiceValuesByOffset(handleData, mtuSize-1,
1168 }
else if (!isServiceDiscoveryRun) {
1170 if (!descriptorHandle) {
1181 if (
request.reference2.toBool() && isServiceDiscoveryRun) {
1187 if (!descriptorHandle)
1188 discoverServiceDescriptors(
service->uuid);
1211 if (!isErrorResponse) {
1213 if (!descriptorHandle)
1219 if (response.
size() == mtuSize) {
1220 readServiceValuesByOffset(handleData,
length,
1225 if (!descriptorHandle) {
1230 emit service->descriptorRead(descriptor, descriptor.value());
1235 qWarning() <<
"READ BLOB for char:" << charHandle
1236 <<
"descriptor:" << descriptorHandle <<
"on service"
1237 <<
service->uuid.toString() <<
"failed (service discovery run:"
1241 if (
request.reference2.toBool()) {
1245 if (!descriptorHandle)
1246 discoverServiceDescriptors(
service->uuid);
1264 if (
keys.isEmpty()) {
1265 qCWarning(QT_BT_BLUEZ) <<
"Descriptor discovery for unknown characteristic received";
1274 if (isErrorResponse) {
1275 if (
keys.size() == 1) {
1277 readServiceValues(
p->uuid,
false);
1281 discoverNextDescriptor(
p,
keys,
keys.first());
1290 elementLength = 2 + 2;
1293 elementLength = 2 + 16;
1296 qCWarning(QT_BT_BLUEZ) <<
"Unknown format in FIND_INFORMATION_RESPONSE";
1300 const quint16 numElements = (response.
size() - 2) / elementLength;
1306 for (
int i = 0;
i < numElements;
i++) {
1322 qCDebug(QT_BT_BLUEZ) <<
"Suppressing primary/characteristic" <<
Qt::hex << shortUuid;
1327 if (descriptorHandle ==
p->characteristicList[charHandle].valueHandle) {
1328 qCDebug(QT_BT_BLUEZ) <<
"Suppressing char handle" <<
Qt::hex << descriptorHandle;
1334 p->characteristicList[charHandle].descriptorList.insert(
1335 descriptorHandle,
data);
1337 qCDebug(QT_BT_BLUEZ) <<
"Descriptor found, uuid:"
1339 <<
"descriptor handle:" <<
Qt::hex << descriptorHandle;
1343 if (
keys.size() == 1) {
1352 if ((
p->endHandle != 0xffff && nextPotentialHandle >=
p->endHandle + 1)
1353 || (descriptorHandle == 0xffff)) {
1357 readServiceValues(
p->uuid,
false);
1359 discoverNextDescriptor(
p,
keys, nextPotentialHandle);
1362 if (nextPotentialHandle >=
keys[1])
1364 discoverNextDescriptor(
p,
keys, nextPotentialHandle);
1377 if (
service.isNull() || !
service->characteristicList.contains(charHandle))
1380 if (isErrorResponse) {
1381 Q_ASSERT(!encryptionChangePending);
1383 encryptionChangePending = increaseEncryptLevelfRequired(err);
1384 if (encryptionChangePending) {
1389 if (!descriptorHandle)
1397 if (!descriptorHandle) {
1405 emit service->descriptorWritten(descriptor, newValue);
1416 const int writtenPayload = ((handleData >> 16) & 0xffff);
1418 if (isErrorResponse) {
1419 Q_ASSERT(!encryptionChangePending);
1421 encryptionChangePending = increaseEncryptLevelfRequired(err);
1422 if (encryptionChangePending) {
1427 sendExecuteWriteRequest(attrHandle, newValue,
true);
1429 if (writtenPayload < newValue.
size()) {
1430 sendNextPrepareWriteRequest(attrHandle, newValue, writtenPayload);
1432 sendExecuteWriteRequest(attrHandle, newValue,
false);
1444 bool wasCancellation = !((handleData >> 16) & 0xffff);
1452 if (isErrorResponse || wasCancellation) {
1462 emit service->descriptorWritten(descriptor, newValue);
1472 qCDebug(QT_BT_BLUEZ) <<
"Unknown packet: " << response.
toHex();
1482void QLowEnergyControllerPrivateBluez::sendReadByGroupRequest(
1495 qCDebug(QT_BT_BLUEZ) <<
"Sending read_by_group_type request, startHandle:" <<
Qt::hex
1504 sendNextPendingRequest();
1511 qCWarning(QT_BT_BLUEZ) <<
"Discovery of unknown service" << service.toString()
1517 serviceData->mode =
mode;
1518 serviceData->characteristicList.
clear();
1522void QLowEnergyControllerPrivateBluez::sendReadByTypeRequest(
1530 putBtData(serviceData->endHandle, &packet[3]);
1535 qCDebug(QT_BT_BLUEZ) <<
"Sending read_by_type request, startHandle:" <<
Qt::hex
1536 << nextHandle <<
"endHandle:" << serviceData->endHandle
1537 <<
"type:" << attributeType <<
"packet:" <<
data.toHex();
1543 request.reference2 = attributeType;
1546 sendNextPendingRequest();
1558void QLowEnergyControllerPrivateBluez::readServiceValues(
1562 if (QT_BT_BLUEZ().isDebugEnabled()) {
1563 if (readCharacteristics)
1564 qCDebug(QT_BT_BLUEZ) <<
"Reading all characteristic values for"
1567 qCDebug(QT_BT_BLUEZ) <<
"Reading all descriptor values for"
1574 if (readCharacteristics) {
1576 discoverServiceDescriptors(
service->uuid);
1591 for ( ; charIt !=
service->characteristicList.constEnd(); ++charIt) {
1595 if (readCharacteristics) {
1603 pair.second = charHandle;
1604 targetHandles.
append(pair);
1609 for ( ; descIt != charDetails.
descriptorList.constEnd(); ++descIt) {
1612 pair.first = descriptorHandle;
1613 pair.second = (charHandle | (descriptorHandle << 16));
1614 targetHandles.
append(pair);
1620 if (targetHandles.
isEmpty()) {
1621 if (readCharacteristics) {
1624 discoverServiceDescriptors(
service->uuid);
1633 pair = targetHandles.
at(
i);
1643 request.reference = pair.second;
1649 sendNextPendingRequest();
1662void QLowEnergyControllerPrivateBluez::readServiceValuesByOffset(
1672 if (descriptorHandle) {
1673 handleToRead = descriptorHandle;
1674 qCDebug(QT_BT_BLUEZ) <<
"Reading descriptor via blob request"
1675 <<
Qt::hex << descriptorHandle;
1681 &&
service->characteristicList.contains(charHandle)) {
1682 handleToRead =
service->characteristicList[charHandle].valueHandle;
1683 qCDebug(QT_BT_BLUEZ) <<
"Reading characteristic via blob request"
1696 request.reference = handleData;
1697 request.reference2 = isLastValue;
1701void QLowEnergyControllerPrivateBluez::discoverServiceDescriptors(
1704 qCDebug(QT_BT_BLUEZ) <<
"Discovering descriptor values for"
1708 if (
service->characteristicList.isEmpty()) {
1716 std::sort(
keys.begin(),
keys.end());
1718 discoverNextDescriptor(service,
keys,
keys[0]);
1721void QLowEnergyControllerPrivateBluez::processUnsolicitedReply(
const QByteArray &payload)
1728 if (QT_BT_BLUEZ().isDebugEnabled()) {
1730 qCDebug(QT_BT_BLUEZ) <<
"Change notification for handle" <<
Qt::hex << changedHandle;
1732 qCDebug(QT_BT_BLUEZ) <<
"Change indication for handle" <<
Qt::hex << changedHandle;
1736 if (
ch.isValid() &&
ch.handle() == changedHandle) {
1739 emit ch.d_ptr->characteristicChanged(
ch, payload.
mid(3));
1741 qCWarning(QT_BT_BLUEZ) <<
"Cannot find matching characteristic for "
1742 "notification/indication";
1746void QLowEnergyControllerPrivateBluez::exchangeMTU()
1748 qCDebug(QT_BT_BLUEZ) <<
"Exchanging MTU";
1762 sendNextPendingRequest();
1765int QLowEnergyControllerPrivateBluez::securityLevel()
const
1769 qCWarning(QT_BT_BLUEZ) <<
"Invalid l2cp socket, aborting getting of sec level";
1774 socklen_t
length =
sizeof(secData);
1775 memset(&secData, 0,
length);
1778 qCDebug(QT_BT_BLUEZ) <<
"Current l2cp sec level:" << secData.level;
1779 return secData.level;
1782 if (errno != ENOPROTOOPT)
1797 qCDebug(QT_BT_BLUEZ) <<
"Current l2cp sec level (old):" <<
level;
1804bool QLowEnergyControllerPrivateBluez::setSecurityLevel(
int level)
1811 qCWarning(QT_BT_BLUEZ) <<
"Invalid l2cp socket, aborting setting of sec level";
1816 socklen_t
length =
sizeof(secData);
1817 memset(&secData, 0,
length);
1818 secData.level =
level;
1821 qCDebug(QT_BT_BLUEZ) <<
"Setting new l2cp sec level:" << secData.level;
1825 if (errno != ENOPROTOOPT)
1844 qCDebug(QT_BT_BLUEZ) <<
"Old l2cp sec level:" << optval;
1851void QLowEnergyControllerPrivateBluez::discoverNextDescriptor(
1860 << pendingCharHandles << startingHandle;
1867 if (pendingCharHandles.
size() == 1)
1868 charEndHandle = serviceData->endHandle;
1870 charEndHandle = pendingCharHandles[1] - 1;
1881 request.reference = QVariant::fromValue<QList<QLowEnergyHandle> >(pendingCharHandles);
1882 request.reference2 = startingHandle;
1885 sendNextPendingRequest();
1888void QLowEnergyControllerPrivateBluez::sendNextPrepareWriteRequest(
1896 targetHandle = descriptor.handle();
1900 if (!targetHandle) {
1901 qCWarning(QT_BT_BLUEZ) <<
"sendNextPrepareWriteRequest cancelled due to invalid handle"
1911 qCDebug(QT_BT_BLUEZ) <<
"Writing long characteristic (prepare):"
1916 const qsizetype requiredPayload = (std::min)(newValue.
size() -
offset, maxAvailablePayload);
1931 request.reference2 = newValue;
1943void QLowEnergyControllerPrivateBluez::sendExecuteWriteRequest(
1957 qCDebug(QT_BT_BLUEZ) <<
"Sending Execute Write Request for long characteristic value"
1963 request.reference = (attrHandle | ((isCancelation ? 0x00 : 0x01) << 16));
1964 request.reference2 = newValue;
1983 if (!service->characteristicList.contains(charHandle))
1988 writeCharacteristicForPeripheral(charData, newValue);
1990 writeCharacteristicForCentral(service, charHandle, charData.
valueHandle, newValue,
mode);
2002 writeDescriptorForPeripheral(service, charHandle, descriptorHandle, newValue);
2004 writeDescriptorForCentral(charHandle, descriptorHandle, newValue);
2017 if (!service->characteristicList.contains(charHandle))
2021 = service->characteristicList[charHandle];
2026 qCWarning(QT_BT_BLUEZ) <<
"Reading non-readable char" << charHandle;
2036 qCDebug(QT_BT_BLUEZ) <<
"Targeted reading characteristic" <<
Qt::hex << charHandle;
2041 request.reference = charHandle;
2047 sendNextPendingRequest();
2056 if (!service->characteristicList.contains(charHandle))
2060 = service->characteristicList[charHandle];
2066 putBtData(descriptorHandle, &packet[1]);
2071 qCDebug(QT_BT_BLUEZ) <<
"Targeted reading descriptor" <<
Qt::hex << descriptorHandle;
2076 request.reference = (charHandle | (descriptorHandle << 16));
2082 sendNextPendingRequest();
2089bool QLowEnergyControllerPrivateBluez::increaseEncryptLevelfRequired(
2095 switch (errorCode) {
2099 if (!hciManager->isValid())
2104 qCDebug(QT_BT_BLUEZ) <<
"Requesting encrypted link";
2106 restartRequestTimer();
2118void QLowEnergyControllerPrivateBluez::handleAdvertisingError()
2120 qCWarning(QT_BT_BLUEZ) <<
"received advertising error";
2125bool QLowEnergyControllerPrivateBluez::checkPacketSize(
const QByteArray &packet,
int minSize,
2132 qCWarning(QT_BT_BLUEZ) <<
"client request of type" << packet.
at(0)
2133 <<
"has unexpected packet size" << packet.
size();
2152 if (startingHandle == 0 || startingHandle > endingHandle) {
2153 qCDebug(QT_BT_BLUEZ) <<
"handle range invalid";
2160void QLowEnergyControllerPrivateBluez::handleExchangeMtuRequest(
const QByteArray &packet)
2164 if (!checkPacketSize(packet, 3))
2166 if (receivedMtuExchangeRequest) {
2167 qCDebug(QT_BT_BLUEZ) <<
"Client sent extraneous MTU exchange packet";
2172 receivedMtuExchangeRequest =
true;
2183 qCDebug(QT_BT_BLUEZ) <<
"MTU request from client:" << clientRxMtu
2184 <<
"effective client RX MTU:" << mtuSize;
2188void QLowEnergyControllerPrivateBluez::handleFindInformationRequest(
const QByteArray &packet)
2192 if (!checkPacketSize(packet, 5))
2196 qCDebug(QT_BT_BLUEZ) <<
"client sends find information request; start:" << startingHandle
2197 <<
"end:" << endingHandle;
2208 ensureUniformUuidSizes(
results);
2214 responsePrefix[1] = uuidSize == 2 ? 0x1 : 0x2;
2216 const auto elemWriter = [](
const Attribute &attr,
char *&
data) {
2220 sendListResponse(responsePrefix, elementSize,
results, elemWriter);
2224void QLowEnergyControllerPrivateBluez::handleFindByTypeValueRequest(
const QByteArray &packet)
2228 if (!checkPacketSize(packet, 7, mtuSize))
2234 qCDebug(QT_BT_BLUEZ) <<
"client sends find by type value request; start:" << startingHandle
2235 <<
"end:" << endingHandle <<
"type:" <<
type
2236 <<
"value:" <<
value.toHex();
2255 const auto elemWriter = [](
const Attribute &attr,
char *&
data) {
2259 sendListResponse(responsePrefix, elemSize,
results, elemWriter);
2262void QLowEnergyControllerPrivateBluez::handleReadByTypeRequest(
const QByteArray &packet)
2266 if (!checkPacketSize(packet, 7, 21))
2270 const void *
const typeStart = packet.
constData() + 5;
2271 const bool is16BitUuid = packet.
size() == 7;
2272 const bool is128BitUuid = packet.
size() == 21;
2276 }
else if (is128BitUuid) {
2279 qCWarning(QT_BT_BLUEZ) <<
"read by type request has invalid packet size" << packet.
size();
2284 qCDebug(QT_BT_BLUEZ) <<
"client sends read by type request, start:" << startingHandle
2285 <<
"end:" << endingHandle <<
"type:" <<
type;
2292 getAttributes(startingHandle, endingHandle,
2293 [
type](
const Attribute &attr) {
return attr.type ==
type; });
2294 ensureUniformValueSizes(
results);
2312 responsePrefix[1] = elementSize;
2313 const auto elemWriter = [](
const Attribute &attr,
char *&
data) {
2317 sendListResponse(responsePrefix, elementSize,
results, elemWriter);
2320void QLowEnergyControllerPrivateBluez::handleReadRequest(
const QByteArray &packet)
2324 if (!checkPacketSize(packet, 3))
2327 qCDebug(QT_BT_BLUEZ) <<
"client sends read request; handle:" <<
handle;
2342 using namespace std;
2343 memcpy(response.
data() + 1,
attribute.value.constData(), sentValueLength);
2344 qCDebug(QT_BT_BLUEZ) <<
"sending response:" << response.
toHex();
2345 sendPacket(response);
2348void QLowEnergyControllerPrivateBluez::handleReadBlobRequest(
const QByteArray &packet)
2352 if (!checkPacketSize(packet, 5))
2356 qCDebug(QT_BT_BLUEZ) <<
"client sends read blob request; handle:" <<
handle
2357 <<
"offset:" << valueOffset;
2368 if (valueOffset >
attribute.value.size()) {
2373 if (
attribute.value.size() <= mtuSize - 3) {
2385 using namespace std;
2386 memcpy(response.
data() + 1,
attribute.value.constData() + valueOffset, sentValueLength);
2387 qCDebug(QT_BT_BLUEZ) <<
"sending response:" << response.
toHex();
2388 sendPacket(response);
2391void QLowEnergyControllerPrivateBluez::handleReadMultipleRequest(
const QByteArray &packet)
2395 if (!checkPacketSize(packet, 5, mtuSize))
2399 for (
qsizetype i = 0;
i < handles.size(); ++
i, ++packetPtr)
2401 qCDebug(QT_BT_BLUEZ) <<
"client sends read multiple request for handles" << handles;
2403 const auto it = std::find_if(handles.constBegin(), handles.constEnd(),
2413 for (
const Attribute &attr :
results) {
2423 response += attr.value.
left(mtuSize - response.
size());
2426 qCDebug(QT_BT_BLUEZ) <<
"sending response:" << response.
toHex();
2427 sendPacket(response);
2430void QLowEnergyControllerPrivateBluez::handleReadByGroupTypeRequest(
const QByteArray &packet)
2434 if (!checkPacketSize(packet, 7, 21))
2438 const bool is16BitUuid = packet.
size() == 7;
2439 const bool is128BitUuid = packet.
size() == 21;
2440 const void *
const typeStart = packet.
constData() + 5;
2444 }
else if (is128BitUuid) {
2447 qCWarning(QT_BT_BLUEZ) <<
"read by group type request has invalid packet size"
2453 qCDebug(QT_BT_BLUEZ) <<
"client sends read by group type request, start:" << startingHandle
2454 <<
"end:" << endingHandle <<
"type:" <<
type;
2467 getAttributes(startingHandle, endingHandle,
2468 [
type](
const Attribute &attr) {
return attr.type ==
type; });
2481 ensureUniformValueSizes(
results);
2486 responsePrefix[1] = elementSize;
2487 const auto elemWriter = [](
const Attribute &attr,
char *&
data) {
2492 sendListResponse(responsePrefix, elementSize,
results, elemWriter);
2495void QLowEnergyControllerPrivateBluez::updateLocalAttributeValue(
2503 if (handle < service->startHandle ||
handle >
service->endHandle)
2505 for (
auto charIt =
service->characteristicList.begin();
2506 charIt !=
service->characteristicList.end(); ++charIt) {
2508 if (
handle == charIt.key() + 1) {
2515 if (
handle == descIt.key()) {
2516 descIt.value().value =
value;
2523 qFatal(
"local services map inconsistent with local attribute map");
2529void QLowEnergyControllerPrivateBluez::writeCharacteristicForPeripheral(
2537 qCWarning(QT_BT_BLUEZ) <<
"ignoring value of invalid length" << newValue.
size()
2538 <<
"for attribute" << valueHandle;
2542 charData.
value = newValue;
2544 const bool hasIndicateProperty
2546 if (!hasNotifyProperty && !hasIndicateProperty)
2558 sendNotification(valueHandle);
2560 if (indicationInFlight)
2561 scheduledIndications << valueHandle;
2563 sendIndication(valueHandle);
2568 for (
auto it = clientConfigData.
begin();
it != clientConfigData.
end(); ++
it) {
2572 for (ClientConfigurationData &configData : configDataList) {
2573 if (configData.charValueHandle != valueHandle)
2577 configData.charValueWasUpdated =
true;
2595 bool writeWithResponse =
false;
2599 sendNextPrepareWriteRequest(charHandle, newValue, 0);
2600 sendNextPendingRequest();
2605 writeWithResponse =
true;
2613 qCWarning(QT_BT_BLUEZ) <<
"signed write not possible: requires bond between devices";
2618 qCWarning(QT_BT_BLUEZ) <<
"signed write not possible: not allowed on encrypted link";
2623 if (signingDataIt == signingData.
end()) {
2624 qCWarning(QT_BT_BLUEZ) <<
"signed write not possible: no signature key found";
2628 ++signingDataIt.value().counter;
2633 storeSignCounter(LocalSigningKey);
2637 qCDebug(QT_BT_BLUEZ) <<
"Writing characteristic" <<
Qt::hex << charHandle
2638 <<
"(size:" << packet.
size() <<
"with response:"
2645 if (!writeWithResponse) {
2653 request.reference = charHandle;
2654 request.reference2 = newValue;
2657 sendNextPendingRequest();
2660void QLowEnergyControllerPrivateBluez::writeDescriptorForPeripheral(
2669 qCWarning(QT_BT_BLUEZ) <<
"invalid value of size" << newValue.
size()
2670 <<
"for attribute" << descriptorHandle;
2674 service->characteristicList[charHandle].descriptorList[descriptorHandle].value = newValue;
2677void QLowEnergyControllerPrivateBluez::writeDescriptorForCentral(
2683 sendNextPrepareWriteRequest(descriptorHandle, newValue, 0);
2684 sendNextPendingRequest();
2690 putBtData(descriptorHandle, &packet[1]);
2697 qCDebug(QT_BT_BLUEZ) <<
"Writing descriptor" <<
Qt::hex << descriptorHandle
2698 <<
"(size:" <<
size <<
")";
2703 request.reference = (charHandle | (descriptorHandle << 16));
2704 request.reference2 = newValue;
2707 sendNextPendingRequest();
2710void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(
const QByteArray &packet)
2718 if (!checkPacketSize(packet, isSigned ? 15 : 3, mtuSize))
2721 qCDebug(QT_BT_BLUEZ) <<
"client sends" << (isSigned ?
"signed" :
"") <<
"write"
2722 << (isRequest ?
"request" :
"command") <<
"for handle" <<
handle;
2741 qCWarning(QT_BT_BLUEZ) <<
"Ignoring signed write from non-bonded device.";
2745 qCWarning(QT_BT_BLUEZ) <<
"Ignoring signed write on encrypted link.";
2749 if (signingDataIt == signingData.
constEnd()) {
2750 qCWarning(QT_BT_BLUEZ) <<
"No CSRK found for peer device, ignoring signed write";
2754 const quint32 signCounter = getBtData<quint32>(packet.
data() + packet.
size() - 12);
2755 if (signCounter < signingDataIt.value().counter + 1) {
2756 qCWarning(QT_BT_BLUEZ) <<
"Client's' sign counter" << signCounter
2757 <<
"not greater than local sign counter"
2758 << signingDataIt.value().counter
2759 <<
"; ignoring signed write command.";
2763 const quint64 macFromClient = getBtData<quint64>(packet.
data() + packet.
size() - 8);
2764 const bool signatureCorrect = verifyMac(packet.
left(packet.
size() - 12),
2765 signingDataIt.value().key, signCounter, macFromClient);
2766 if (!signatureCorrect) {
2767 qCWarning(QT_BT_BLUEZ) <<
"Signed Write packet has wrong signature, disconnecting";
2772 signingDataIt.value().counter = signCounter;
2773 storeSignCounter(RemoteSigningKey);
2774 valueLength = packet.
size() - 15;
2776 valueLength = packet.
size() - 3;
2779 if (valueLength >
attribute.maxLength) {
2793 updateLocalAttributeValue(
handle,
value, characteristic, descriptor);
2798 sendPacket(response);
2801 if (characteristic.
isValid()) {
2809void QLowEnergyControllerPrivateBluez::handlePrepareWriteRequest(
const QByteArray &packet)
2813 if (!checkPacketSize(packet, 5, mtuSize))
2816 qCDebug(QT_BT_BLUEZ) <<
"client sends prepare write request for handle" <<
handle;
2840 sendPacket(response);
2843void QLowEnergyControllerPrivateBluez::handleExecuteWriteRequest(
const QByteArray &packet)
2847 if (!checkPacketSize(packet, 2))
2849 const bool cancel = packet.
at(1) == 0;
2850 qCDebug(QT_BT_BLUEZ) <<
"client sends execute write request; flag is"
2851 << (
cancel ?
"cancel" :
"flush");
2854 openPrepareWriteRequests.
clear();
2876 updateLocalAttributeValue(
request.handle, newValue, characteristic, descriptor);
2877 if (characteristic.
isValid()) {
2878 characteristics << characteristic;
2879 }
else if (descriptor.
isValid()) {
2881 descriptors << descriptor;
2890 emit characteristic.
d_ptr->characteristicChanged(characteristic, characteristic.
value());
2892 emit descriptor.
d_ptr->descriptorWritten(descriptor, descriptor.
value());
2908 qCWarning(QT_BT_BLUEZ) <<
"sending error response; request:"
2914void QLowEnergyControllerPrivateBluez::sendListResponse(
const QByteArray &packetStart,
2917 const ElemWriter &elemWriter)
2923 using namespace std;
2927 [&
data, elemWriter](
const Attribute &attr) { elemWriter(attr, data); });
2928 qCDebug(QT_BT_BLUEZ) <<
"sending response:" << response.
toHex();
2929 sendPacket(response);
2940 indicationInFlight =
true;
2951 packet[0] =
static_cast<quint8>(opCode);
2953 using namespace std;
2954 memcpy(packet.
data() + 3,
attribute.value.constData(), maxValueLength);
2955 qCDebug(QT_BT_BLUEZ) <<
"sending notification/indication:" << packet.
toHex();
2959void QLowEnergyControllerPrivateBluez::sendNextIndication()
2961 if (!scheduledIndications.
isEmpty())
2962 sendIndication(scheduledIndications.
takeFirst());
2967 const QString peerAddressString = peerAddress.toString();
2973 reply.waitForFinished();
2974 if (
reply.isError())
2982 const QString &iface = jt.key();
2994void QLowEnergyControllerPrivateBluez::handleConnectionRequest()
2997 qCWarning(QT_BT_BLUEZ) <<
"Incoming connection request in unexpected state" <<
state;
3003 socklen_t clientAddrSize =
sizeof clientAddr;
3005 reinterpret_cast<sockaddr *
>(&clientAddr), &clientAddrSize);
3017 if (connectionHandle == 0)
3018 qCWarning(QT_BT_BLUEZ) <<
"Received client connection, but no connection complete event";
3022 if (l2cpSocket->
isOpen())
3023 l2cpSocket->
close();
3026 l2cpSocket =
nullptr;
3028 closeServerSocket();
3034 this, &QLowEnergyControllerPrivateBluez::l2cpDisconnected);
3036 &QLowEnergyControllerPrivateBluez::l2cpErrorChanged);
3042 restoreClientConfigurations();
3043 loadSigningDataIfNecessary(RemoteSigningKey);
3047 emit q->connected();
3050void QLowEnergyControllerPrivateBluez::closeServerSocket()
3052 if (!serverSocketNotifier)
3055 close(serverSocketNotifier->
socket());
3057 serverSocketNotifier =
nullptr;
3060bool QLowEnergyControllerPrivateBluez::isBonded()
const
3069QLowEnergyControllerPrivateBluez::gatherClientConfigData()
3073 for (
auto charIt =
service->characteristicList.begin();
3074 charIt !=
service->characteristicList.end(); ++charIt) {
3090void QLowEnergyControllerPrivateBluez::storeClientConfigurations()
3098 for (
const auto &tempConfigData : tempConfigList) {
3099 Q_ASSERT(tempConfigData.descData->value.size() == 2);
3102 clientConfigs << ClientConfigurationData(tempConfigData.charValueHandle,
3103 tempConfigData.configHandle,
value);
3109void QLowEnergyControllerPrivateBluez::restoreClientConfigurations()
3116 for (
const auto &tempConfigData : tempConfigList) {
3117 bool wasRestored =
false;
3118 for (
const auto &restoredData : restoredClientConfigs) {
3119 if (restoredData.charValueHandle == tempConfigData.charValueHandle) {
3120 Q_ASSERT(tempConfigData.descData->value.size() == 2);
3121 putBtData(restoredData.configValue, tempConfigData.descData->value.data());
3123 if (restoredData.charValueWasUpdated) {
3125 notifications << restoredData.charValueHandle;
3127 scheduledIndications << restoredData.charValueHandle;
3135 Q_ASSERT(tempConfigData.configHandle > tempConfigData.charValueHandle);
3136 localAttributes[tempConfigData.configHandle].value = tempConfigData.descData->value;
3140 sendNotification(
handle);
3141 sendNextIndication();
3144void QLowEnergyControllerPrivateBluez::loadSigningDataIfNecessary(SigningKeyType keyType)
3147 if (signingDataIt != signingData.
constEnd())
3149 const QString settingsFilePath = keySettingsFilePath();
3150 if (!
QFileInfo(settingsFilePath).exists()) {
3151 qCDebug(QT_BT_BLUEZ) <<
"No settings found for peer device.";
3155 const QString group = signingKeySettingsGroup(keyType);
3159 qCDebug(QT_BT_BLUEZ) <<
"Group" <<
group <<
"not found in settings file";
3164 qCWarning(QT_BT_BLUEZ) <<
"Signing key in settings file has invalid size"
3170 using namespace std;
3176void QLowEnergyControllerPrivateBluez::storeSignCounter(SigningKeyType keyType)
const
3179 if (signingDataIt == signingData.
constEnd())
3181 const QString settingsFilePath = keySettingsFilePath();
3182 if (!
QFileInfo(settingsFilePath).exists())
3191 const quint32 counterValue = signingDataIt.value().counter + 1;
3197QString QLowEnergyControllerPrivateBluez::signingKeySettingsGroup(SigningKeyType keyType)
const
3199 return QLatin1String(keyType == LocalSigningKey ?
"LocalSignatureKey" :
"RemoteSignatureKey");
3202QString QLowEnergyControllerPrivateBluez::keySettingsFilePath()
const
3226 serviceAttribute.
handle = startHandle;
3237 const bool includeUuidInValue = service->serviceUuid().minimumSize() == 2;
3239 char *valueData =
attribute.value.data();
3242 if (includeUuidInValue)
3256 char *valueData =
attribute.value.data();
3267 attribute.readConstraints = cd.readConstraints();
3268 attribute.writeConstraints = cd.writeConstraints();
3270 attribute.minLength = cd.minimumValueLength();
3271 attribute.maxLength = cd.maximumValueLength();
3279 attribute.properties = QLowEnergyCharacteristic::PropertyTypes();
3280 attribute.readConstraints = AttAccessConstraints();
3281 attribute.writeConstraints = AttAccessConstraints();
3301 attribute.writeConstraints = dd.writeConstraints();
3304 if (dd.isReadable())
3306 if (dd.isWritable()) {
3311 attribute.readConstraints = dd.readConstraints();
3312 attribute.writeConstraints = dd.writeConstraints();
3319 <<
"has invalid length of" <<
attribute.value.size()
3335void QLowEnergyControllerPrivateBluez::ensureUniformAttributes(
3341 const auto it = std::find_if(attributes.
begin() + 1, attributes.
end(),
3342 [firstSize,
getSize](
const Attribute &attr) { return getSize(attr) != firstSize; });
3343 if (
it != attributes.
end())
3348void QLowEnergyControllerPrivateBluez::ensureUniformUuidSizes(
QList<Attribute> &attributes)
3350 ensureUniformAttributes(attributes,
3351 [](
const Attribute &attr) {
return getUuidSize(attr.type); });
3354void QLowEnergyControllerPrivateBluez::ensureUniformValueSizes(
QList<Attribute> &attributes)
3356 ensureUniformAttributes(attributes,
3357 [](
const Attribute &attr) {
return attr.value.size(); });
3361QLowEnergyControllerPrivateBluez::getAttributes(
QLowEnergyHandle startHandle,
3363 const AttributePredicate &attributePredicate)
3370 Q_ASSERT(startHandle <= endHandle);
3375 if (attributePredicate(attr))
3382QLowEnergyControllerPrivateBluez::checkPermissions(
const Attribute &attr,
3390 Q_ASSERT(isReadAccess || isWriteAccess);
3391 if (!(attr.properties &
type)) {
3397 const bool unsignedWriteOk = isWriteCommand
3400 if (!unsignedWriteOk)
3403 const AttAccessConstraints constraints = isReadAccess
3404 ? attr.readConstraints : attr.writeConstraints;
3405 if (constraints.testFlag(AttAccessConstraint::AttAuthorizationRequired))
3408 if (constraints.testFlag(AttAccessConstraint::AttEncryptionRequired)
3411 if (constraints.testFlag(AttAccessConstraint::AttAuthenticationRequired)
3425QLowEnergyControllerPrivateBluez::checkReadPermissions(
QList<Attribute> &attributes)
3439 std::find_if(attributes.
begin() + 1, attributes.
end(), [
this](
const Attribute &attr) {
3440 return checkReadPermissions(attr) != QBluezConst::AttError::ATT_ERROR_NO_ERROR;
3442 if (
it != attributes.
end())
3450 if (!cmacCalculator)
3458#include "moc_qlowenergycontroller_bluez_p.cpp"
QT_BEGIN_NAMESPACE void initializeBluez5()
static quint16 bt_get_le16(const void *ptr)
#define ATTRIBUTE_CHANNEL_ID
#define BT_SECURITY_MEDIUM
void putBtData(T src, void *dst)
DarwinBluetooth::RequestQueue requests
QLowEnergyHandle lastHandle
static BluetoothManagement * instance()
void connectionUpdate(quint16 handle, const QLowEnergyConnectionParameters ¶meters)
void connectionComplete(quint16 handle)
void signatureResolvingKeyReceived(quint16 connHandle, bool remoteKey, BluezUint128 csrk)
quint64 calculateMac(const QByteArray &message, QUuid::Id128Bytes csrk) const
bool verify(const QByteArray &message, QUuid::Id128Bytes csrk, quint64 expectedMac) const
static QByteArray createFullMessage(const QByteArray &message, quint32 signCounter)
QString name() const
Returns the name assgined by the user to this Bluetooth device.
Pairing pairingStatus(const QBluetoothAddress &address) const
Returns the current bluetooth pairing status of address, if it's unpaired, paired,...
void connectToService(const QBluetoothServiceInfo &service, OpenMode openMode=ReadWrite)
Attempts to connect to the service described by service.
QString errorString() const
Returns a user displayable text string for the error.
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, SocketState socketState=SocketState::ConnectedState, OpenMode openMode=ReadWrite)
Sets the socket to use socketDescriptor with a type of socketType, which is in state socketState,...
void errorOccurred(QBluetoothSocket::SocketError error)
This signal is emitted when an error occurs.
QBluetoothSocketBasePrivate * d_ptr
void close() override
Disconnects the socket's connection with the device.
int socketDescriptor() const
Returns the platform-specific socket descriptor, if available.
SocketError
This enum describes Bluetooth socket error types.
@ UnsupportedProtocolError
void disconnected()
This signal is emitted when the socket is disconnected.
quint16 toUInt16(bool *ok=nullptr) const
Returns the 16 bit representation of this UUID.
int minimumSize() const
Returns the minimum size in bytes that this UUID can be represented in.
@ CharacteristicExtendedProperties
@ CharacteristicAggregateFormat
@ CharacteristicPresentationFormat
@ ServerCharacteristicConfiguration
@ ClientCharacteristicConfiguration
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
static QByteArray fromHex(const QByteArray &hexEncoded)
Returns a decoded copy of the hex encoded array hexEncoded.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
QByteArray first(qsizetype n) const
QByteArray left(qsizetype len) const
Returns a byte array that contains the first len bytes of this byte array.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toHex(char separator='\0') const
Returns a hex encoded copy of the byte array.
QByteArray mid(qsizetype index, qsizetype len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos.
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
static QDBusConnection systemBus()
Returns a QDBusConnection object opened with the system bus.
\inmodule QtCore \reentrant
bool remove(const Key &key)
Removes the item that has the key from the hash.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
const_iterator constFind(const Key &key) const noexcept
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
T value(const Key &key) const noexcept
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
friend class const_iterator
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
void readyRead()
This signal is emitted once every time new data is available for reading from the device's current re...
bool isOpen() const
Returns true if the device is open; otherwise returns false.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
qsizetype size() const noexcept
bool isEmpty() const noexcept
iterator erase(const_iterator begin, const_iterator end)
void push_back(parameter_type t)
const_reference at(qsizetype i) const noexcept
T value(qsizetype i) const
const_iterator constBegin() const noexcept
void prepend(rvalue_ref t)
void append(parameter_type t)
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.
void setProperties(QLowEnergyCharacteristic::PropertyTypes properties)
Sets the properties of this characteristic to properties.
void addDescriptor(const QLowEnergyDescriptorData &descriptor)
Adds descriptor to the list of descriptors of this characteristic, if it is valid.
void setUuid(const QBluetoothUuid &uuid)
Sets the UUID of this characteristic to uuid.
void setValue(const QByteArray &value)
Sets the value of this characteristic to value.
PropertyType
This enum describes the properties of a characteristic.
bool isValid() const
Returns true if the QLowEnergyCharacteristic object is valid, otherwise returns false.
The QLowEnergyConnectionParameters class is used when requesting or reporting an update of the parame...
void discoverServiceDetails(const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode) override
QList< Attribute > localAttributes
void discoverServices() override
void readCharacteristic(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle) override
void writeCharacteristic(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle, const QByteArray &newValue, QLowEnergyService::WriteMode mode) override
Writes long (prepare write request), short (write request) and writeWithoutResponse characteristic va...
void writeDescriptor(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle, const QLowEnergyHandle descriptorHandle, const QByteArray &newValue) override
QLowEnergyControllerPrivateBluez()
void stopAdvertising() override
void startAdvertising(const QLowEnergyAdvertisingParameters ¶ms, const QLowEnergyAdvertisingData &advertisingData, const QLowEnergyAdvertisingData &scanResponseData) override
void connectToDevice() override
~QLowEnergyControllerPrivateBluez() override
void disconnectFromDevice() override
void readDescriptor(const QSharedPointer< QLowEnergyServicePrivate > service, const QLowEnergyHandle charHandle, const QLowEnergyHandle descriptorHandle) override
void addToGenericAttributeList(const QLowEnergyServiceData &service, QLowEnergyHandle startHandle) override
void requestConnectionUpdate(const QLowEnergyConnectionParameters ¶ms) override
QLowEnergyCharacteristic characteristicForHandle(QLowEnergyHandle handle)
Returns a valid characteristic if the given handle is the handle of the characteristic itself or one ...
QSharedPointer< QLowEnergyServicePrivate > serviceForHandle(QLowEnergyHandle handle)
void invalidateServices()
QLowEnergyController::RemoteAddressType addressType
quint16 updateValueOfDescriptor(QLowEnergyHandle charHandle, QLowEnergyHandle descriptorHandle, const QByteArray &value, bool appendValue)
Returns the length of the updated descriptor value.
QLowEnergyDescriptor descriptorForHandle(QLowEnergyHandle handle)
Returns a valid descriptor if handle belongs to a descriptor; otherwise an invalid one.
ServiceDataMap localServices
ServiceDataMap serviceList
QLowEnergyController::Error error
void setError(QLowEnergyController::Error newError)
QLowEnergyController::Role role
QLowEnergyHandle lastLocalHandle
quint16 updateValueOfCharacteristic(QLowEnergyHandle charHandle, const QByteArray &value, bool appendValue)
Returns the length of the updated characteristic value.
QBluetoothAddress localAdapter
virtual QLowEnergyService * addServiceHelper(const QLowEnergyServiceData &service)
QLowEnergyController::ControllerState state
QBluetoothAddress remoteDevice
void setState(QLowEnergyController::ControllerState newState)
@ UnknownRemoteDeviceError
@ InvalidBluetoothAdapterError
The QLowEnergyDescriptorData class is used to create GATT service data. \inmodule QtBluetooth.
bool isValid() const
Returns true if the QLowEnergyDescriptor object is valid, otherwise returns false.
The QLowEnergyServiceData class is used to set up GATT service data. \inmodule QtBluetooth.
void setType(ServiceType type)
Sets the type of this service to type.
void addCharacteristic(const QLowEnergyCharacteristicData &characteristic)
Adds characteristic to the list of characteristics, if it is valid.
void setUuid(const QBluetoothUuid &uuid)
Sets the UUID of this service to uuid.
void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue)
DiscoveryMode
This enum lists service discovery modes.
@ CharacteristicWriteError
@ CharacteristicReadError
@ RemoteServiceDiscovered
WriteMode
This enum describes the mode to be used when writing a characteristic value.
T value(const Key &key, const T &defaultValue=T()) const
const_iterator constBegin() const
const_iterator constEnd() const
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
QScopedPointer< QObjectData > d_ptr
void deleteLater()
\threadsafe
void enqueue(const T &t)
Adds value t to the tail of the queue.
T & head()
Returns a reference to the queue's head item.
T dequeue()
Removes the head item in the queue and returns it.
const_iterator constEnd() const noexcept
void setValue(QAnyStringView key, const QVariant &value)
Sets the value of setting key to value.
QVariant value(QAnyStringView key, const QVariant &defaultValue) const
Returns the value for setting key.
QStringList allKeys() const
Returns a list of all keys, including subkeys, that can be read using the QSettings object.
bool isWritable() const
Returns true if settings can be written using this QSettings object; returns false otherwise.
void beginGroup(QAnyStringView prefix)
Appends prefix to the current group.
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
void clear()
Clears this QSharedPointer object, dropping the reference that it may have had to the pointer.
void activated(QSocketDescriptor socket, QSocketNotifier::Type activationEvent, QPrivateSignal)
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
qintptr socket() const
Returns the socket identifier assigned to this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toLatin1() const &
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void clear()
Clears the contents of the string and makes it null.
qsizetype size() const
Returns the number of characters in this string.
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
QString toString(StringFormat mode=WithBraces) const
Id128Bytes toBytes(QSysInfo::Endian order=QSysInfo::BigEndian) const noexcept
static QUuid fromBytes(const void *bytes, QSysInfo::Endian order=QSysInfo::BigEndian) noexcept
uint toUInt(bool *ok=nullptr) const
Returns the variant as an unsigned int if the variant has userType() \l QMetaType::UInt,...
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has userType() \l QMetaType::QByteArray or \l QMet...
bool scheduleJob(JobType job, const QList< QBluetoothAddress > &remoteDevices)
bool listen(const QBluetoothAddress &localAdapter)
QSet< QString >::iterator it
@ ATT_ERROR_INVAL_ATTR_VALUE_LEN
@ ATT_ERROR_INVALID_OFFSET
@ ATT_ERROR_INSUF_AUTHORIZATION
@ ATT_ERROR_READ_NOT_PERM
@ ATT_ERROR_REQUEST_NOT_SUPPORTED
@ ATT_ERROR_INSUF_ENCRYPTION
@ ATT_ERROR_INVALID_HANDLE
@ ATT_ERROR_INSUF_ENCR_KEY_SIZE
@ ATT_ERROR_WRITE_NOT_PERM
@ ATT_ERROR_ATTRIBUTE_NOT_LONG
@ ATT_ERROR_APPLICATION_END
@ ATT_ERROR_REQUEST_STALLED
@ ATT_ERROR_INSUF_AUTHENTICATION
@ ATT_ERROR_ATTRIBUTE_NOT_FOUND
@ ATT_ERROR_PREPARE_QUEUE_FULL
@ ATT_ERROR_APPLICATION_START
@ ATT_ERROR_INSUF_RESOURCES
@ ATT_ERROR_UNSUPPRTED_GROUP_TYPE
@ ATT_OP_FIND_BY_TYPE_VALUE_RESPONSE
@ ATT_OP_PREPARE_WRITE_RESPONSE
@ ATT_OP_EXECUTE_WRITE_REQUEST
@ ATT_OP_FIND_BY_TYPE_VALUE_REQUEST
@ ATT_OP_READ_BLOB_REQUEST
@ ATT_OP_EXECUTE_WRITE_RESPONSE
@ ATT_OP_FIND_INFORMATION_RESPONSE
@ ATT_OP_SIGNED_WRITE_COMMAND
@ ATT_OP_EXCHANGE_MTU_REQUEST
@ ATT_OP_HANDLE_VAL_NOTIFICATION
@ ATT_OP_READ_BY_TYPE_REQUEST
@ ATT_OP_EXCHANGE_MTU_RESPONSE
@ ATT_OP_READ_BY_GROUP_REQUEST
@ ATT_OP_HANDLE_VAL_CONFIRMATION
@ ATT_OP_HANDLE_VAL_INDICATION
@ ATT_OP_READ_BY_TYPE_RESPONSE
@ ATT_OP_FIND_INFORMATION_REQUEST
@ ATT_OP_PREPARE_WRITE_REQUEST
@ ATT_OP_READ_BLOB_RESPONSE
@ ATT_OP_READ_MULTIPLE_REQUEST
@ ATT_OP_READ_MULTIPLE_RESPONSE
@ ATT_OP_READ_BY_GROUP_RESPONSE
Combined button and popup list for selecting options.
Q_CORE_EXPORT QtJniTypes::Service service()
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
constexpr Initialization Uninitialized
static void convertAddress(const quint64 from, quint8(&to)[6])
std::pair< T1, T2 > QPair
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT EGLint attribute
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define GATT_CHARACTERISTIC
#define GATT_SECONDARY_SERVICE
static bool isNotificationEnabled(quint16 clientConfigValue)
QLowEnergyHandle parseReadByTypeIncludeDiscovery(QList< QBluetoothUuid > *foundServices, const char *data, quint16 elementLength)
#define GATT_PRIMARY_SERVICE
static int getUuidSize(const QBluetoothUuid &uuid)
#define WRITE_REQUEST_HEADER_SIZE
constexpr quint16 ATT_MAX_LE_MTU
QLowEnergyHandle parseReadByTypeCharDiscovery(QLowEnergyServicePrivate::CharData *charData, const char *data, quint16 elementLength)
#define GRP_TYPE_REQ_HEADER_SIZE
#define READ_REQUEST_HEADER_SIZE
#define READ_BY_TYPE_REQ_HEADER_SIZE
#define EXECUTE_WRITE_HEADER_SIZE
const int maxPrepareQueueSize
static QString nameOfRemoteCentral(const QBluetoothAddress &peerAddress)
#define PREPARE_WRITE_HEADER_SIZE
static void dumpErrorInformation(const QByteArray &response)
#define GATT_INCLUDED_SERVICE
#define READ_BLOB_REQUEST_HEADER_SIZE
static void putDataAndIncrement(const T &src, char *&dst)
static bool isIndicationEnabled(quint16 clientConfigValue)
#define MTU_EXCHANGE_HEADER_SIZE
#define FIND_INFO_REQUEST_HEADER_SIZE
#define ERROR_RESPONSE_HEADER_SIZE
static QByteArray uuidToByteArray(const QBluetoothUuid &uuid)
constexpr quint16 ATT_DEFAULT_LE_MTU
void registerQLowEnergyControllerMetaType()
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
GLuint64 GLenum void * handle
GLenum GLuint GLint level
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLuint GLuint64EXT address
GLsizei const void * pointer
GLdouble GLdouble GLdouble GLdouble q
static QString keyString(int sym, QChar::Category category)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
static QSize getSize(QTextDocument *doc, const QTextImageFormat &format)
unsigned long long quint64
QSettings settings("MySoft", "Star Runner")
[0]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
myObject disconnect()
[26]
QNetworkAccessManager manager
QNetworkRequest request(url)
socketLayer bind(QHostAddress::Any, 4000)
QUdpSocket clientSocket
[0]
serverDtls doHandshake & serverSocket
char * toString(const MyType &t)
[31]
QLowEnergyHandle groupEndHandle
QLowEnergyCharacteristic::PropertyTypes properties
QHash< QLowEnergyHandle, DescData > descriptorList
QLowEnergyHandle valueHandle
QLowEnergyCharacteristic::PropertyTypes properties