1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtBluetooth module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtBluetooth/qlowenergyadvertisingdata.h>
30#include <QtBluetooth/qlowenergyadvertisingparameters.h>
31#include <QtBluetooth/qlowenergyconnectionparameters.h>
32#include <QtBluetooth/qlowenergycontroller.h>
33#include <QtBluetooth/qlowenergycharacteristicdata.h>
34#include <QtBluetooth/qlowenergydescriptordata.h>
35#include <QtBluetooth/qlowenergyservicedata.h>
36#include <QtCore/qcoreapplication.h>
37#include <QtCore/qendian.h>
38#include <QtCore/qhash.h>
39#include <QtCore/qscopedpointer.h>
40#include <QtCore/qsharedpointer.h>
41#include <QtCore/qvector.h>
42
43static QByteArray deviceName() { return "Qt GATT server"; }
44
45static QScopedPointer<QLowEnergyController> leController;
46typedef QSharedPointer<QLowEnergyService> ServicePtr;
47static QHash<QBluetoothUuid, ServicePtr> services;
48static int descriptorWriteCount = 0;
49static int disconnectCount = 0;
50static QBluetoothAddress remoteDevice;
51
52void addService(const QLowEnergyServiceData &serviceData)
53{
54 const ServicePtr service(leController->addService(service: serviceData));
55 Q_ASSERT(service);
56 services.insert(akey: service->serviceUuid(), avalue: service);
57}
58
59void addRunningSpeedService()
60{
61 QLowEnergyServiceData serviceData;
62 serviceData.setUuid(QBluetoothUuid::RunningSpeedAndCadence);
63 serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
64
65 QLowEnergyDescriptorData desc;
66 desc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
67 desc.setValue(QByteArray(2, 0)); // Default: No indication, no notification.
68 QLowEnergyCharacteristicData charData;
69 charData.setUuid(QBluetoothUuid::RSCMeasurement);
70 charData.addDescriptor(descriptor: desc);
71 charData.setProperties(QLowEnergyCharacteristic::Notify);
72 QByteArray value(4, 0);
73 value[0] = 1 << 2; // "Running", no optional fields.
74 charData.setValue(value);
75 serviceData.addCharacteristic(characteristic: charData);
76
77 charData = QLowEnergyCharacteristicData();
78 charData.setUuid(QBluetoothUuid::RSCFeature);
79 charData.setProperties(QLowEnergyCharacteristic::Read);
80 value = QByteArray(2, 0);
81 qToLittleEndian<quint16>(src: 1 << 2, dest: reinterpret_cast<uchar *>(value.data()));
82 charData.setValue(value);
83 serviceData.addCharacteristic(characteristic: charData);
84 addService(serviceData);
85}
86
87void addGenericAccessService()
88{
89 QLowEnergyServiceData serviceData;
90 serviceData.setUuid(QBluetoothUuid::GenericAccess);
91 serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
92
93 QLowEnergyCharacteristicData charData;
94 charData.setUuid(QBluetoothUuid::DeviceName);
95 charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write);
96 charData.setValue(deviceName());
97 serviceData.addCharacteristic(characteristic: charData);
98
99 charData = QLowEnergyCharacteristicData();
100 charData.setUuid(QBluetoothUuid::Appearance);
101 charData.setProperties(QLowEnergyCharacteristic::Read);
102 QByteArray value(2, 0);
103 qToLittleEndian<quint16>(src: 128, dest: reinterpret_cast<uchar *>(value.data())); // Generic computer.
104 charData.setValue(value);
105 serviceData.addCharacteristic(characteristic: charData);
106
107 serviceData.addIncludedService(service: services.value(akey: QBluetoothUuid::RunningSpeedAndCadence).data());
108 addService(serviceData);
109}
110
111void addCustomService()
112{
113 QLowEnergyServiceData serviceData;
114 serviceData.setUuid(QBluetoothUuid(quint16(0x2000)));
115 serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
116
117 QLowEnergyCharacteristicData charData;
118 charData.setUuid(QBluetoothUuid(quint16(0x5000))); // Made up.
119 charData.setProperties(QLowEnergyCharacteristic::Read);
120 charData.setValue(QByteArray(1024, 'x')); // Long value to test "Read Blob".
121 serviceData.addCharacteristic(characteristic: charData);
122
123 charData.setUuid(QBluetoothUuid(quint16(0x5001)));
124 charData.setProperties(QLowEnergyCharacteristic::Read);
125 charData.setReadConstraints(QBluetooth::AttAuthorizationRequired); // To test read failure.
126 serviceData.addCharacteristic(characteristic: charData);
127 charData.setValue("something");
128
129 charData.setUuid(QBluetoothUuid(quint16(0x5002)));
130 charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Indicate);
131 charData.setReadConstraints(QBluetooth::AttAccessConstraints());
132 const QLowEnergyDescriptorData desc(QBluetoothUuid::ClientCharacteristicConfiguration,
133 QByteArray(2, 0));
134 charData.addDescriptor(descriptor: desc);
135 serviceData.addCharacteristic(characteristic: charData);
136
137 charData.setUuid(QBluetoothUuid(quint16(0x5003)));
138 charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify);
139 serviceData.addCharacteristic(characteristic: charData);
140
141 charData.setUuid(QBluetoothUuid(quint16(0x5004)));
142 charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::WriteSigned);
143 charData.setDescriptors(QList<QLowEnergyDescriptorData>());
144 charData.setValue("initial");
145 serviceData.addCharacteristic(characteristic: charData);
146
147 addService(serviceData);
148
149 // service with full 128 bit custom uuids
150 QLowEnergyServiceData serviceData128;
151 serviceData128.setUuid(QBluetoothUuid(QString("c47774c7-f237-4523-8968-e4ae75431daf")));
152 serviceData128.setType(QLowEnergyServiceData::ServiceTypePrimary);
153
154 QLowEnergyCharacteristicData charData128;
155 charData128.setUuid(QBluetoothUuid(QString("c0ad61b1-79e7-42f9-ace0-0a9aa0d0a4f8")));
156 charData128.setProperties(QLowEnergyCharacteristic::Read);
157 charData128.setValue(QByteArray(15, 'a'));
158 serviceData128.addCharacteristic(characteristic: charData128);
159
160 addService(serviceData: serviceData128);
161}
162
163void startAdvertising()
164{
165 QLowEnergyAdvertisingParameters params;
166 params.setMode(QLowEnergyAdvertisingParameters::AdvInd);
167 QLowEnergyAdvertisingData data;
168 data.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityLimited);
169 data.setServices(services.keys());
170 data.setIncludePowerLevel(true);
171 data.setLocalName(deviceName());
172 leController->startAdvertising(parameters: params, advertisingData: data);
173}
174
175int main(int argc, char *argv[])
176{
177 QCoreApplication app(argc, argv);
178 leController.reset(other: QLowEnergyController::createPeripheral());
179 addRunningSpeedService();
180 addGenericAccessService();
181 addCustomService();
182 startAdvertising();
183
184 const ServicePtr customService = services.value(akey: QBluetoothUuid(quint16(0x2000)));
185 Q_ASSERT(customService);
186
187 const auto stateChangedHandler = [customService]() {
188 switch (leController->state()) {
189 case QLowEnergyController::ConnectedState:
190 remoteDevice = leController->remoteAddress();
191 break;
192 case QLowEnergyController::UnconnectedState: {
193 if (++disconnectCount == 2) {
194 qApp->quit();
195 break;
196 }
197 Q_ASSERT(disconnectCount == 1);
198 const QLowEnergyCharacteristic indicatableChar
199 = customService->characteristic(uuid: QBluetoothUuid(quint16(0x5002)));
200 Q_ASSERT(indicatableChar.isValid());
201 customService->writeCharacteristic(characteristic: indicatableChar, newValue: "indicated2");
202 Q_ASSERT(indicatableChar.value() == "indicated2");
203 const QLowEnergyCharacteristic notifiableChar
204 = customService->characteristic(uuid: QBluetoothUuid(quint16(0x5003)));
205 Q_ASSERT(notifiableChar.isValid());
206 customService->writeCharacteristic(characteristic: notifiableChar, newValue: "notified2");
207 Q_ASSERT(notifiableChar.value() == "notified2");
208 startAdvertising();
209 break;
210 }
211 default:
212 break;
213 }
214 };
215
216 QObject::connect(sender: leController.data(), signal: &QLowEnergyController::stateChanged, slot: stateChangedHandler);
217 const auto descriptorWriteHandler = [customService]() {
218 if (++descriptorWriteCount != 2)
219 return;
220 const QLowEnergyCharacteristic indicatableChar
221 = customService->characteristic(uuid: QBluetoothUuid(quint16(0x5002)));
222 Q_ASSERT(indicatableChar.isValid());
223 customService->writeCharacteristic(characteristic: indicatableChar, newValue: "indicated");
224 Q_ASSERT(indicatableChar.value() == "indicated");
225 const QLowEnergyCharacteristic notifiableChar
226 = customService->characteristic(uuid: QBluetoothUuid(quint16(0x5003)));
227 Q_ASSERT(notifiableChar.isValid());
228 customService->writeCharacteristic(characteristic: notifiableChar, newValue: "notified");
229 Q_ASSERT(notifiableChar.value() == "notified");
230 QLowEnergyConnectionParameters connParams;
231 connParams.setIntervalRange(minimum: 30, maximum: 62.5);
232 connParams.setLatency(5);
233 connParams.setSupervisionTimeout(5500);
234 leController->requestConnectionUpdate(parameters: connParams);
235 };
236 QObject::connect(sender: customService.data(), signal: &QLowEnergyService::descriptorWritten,
237 slot: descriptorWriteHandler);
238
239 return app.exec();
240}
241

source code of qtconnectivity/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp