Line data Source code
1 : // SPDX-FileCopyrightText: 2022-2025 Paul Colby <git@colby.id.au>
2 : // SPDX-License-Identifier: LGPL-3.0-or-later
3 :
4 : #include "scancommand.h"
5 :
6 : #include <qtpokit/pokitdiscoveryagent.h>
7 :
8 : #include <QBluetoothUuid>
9 : #include <QJsonArray>
10 : #include <QJsonDocument>
11 : #include <QJsonObject>
12 :
13 : #include <iostream>
14 :
15 : /*!
16 : * \class ScanCommand
17 : *
18 : * The ScanCommand class implements the `scan` CLI command, by scanning for nearby Pokit Bluetooth
19 : * devices. When devices are found, they are logged to stdout in the chosen format.
20 : */
21 :
22 : /*!
23 : * Construct a new ScanCommand object with \a parent.
24 : */
25 3777 : ScanCommand::ScanCommand(QObject * const parent) : AbstractCommand(parent)
26 2847 : {
27 2556 : #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) // Required signal, and Fields, added in Qt 5.12.
28 4896 : connect(discoveryAgent, &PokitDiscoveryAgent::pokitDeviceUpdated,
29 3216 : this, &ScanCommand::deviceUpdated);
30 2556 : #endif
31 5385 : }
32 :
33 180 : QStringList ScanCommand::requiredOptions(const QCommandLineParser &parser) const
34 208 : {
35 388 : return AbstractCommand::requiredOptions(parser);
36 208 : }
37 :
38 90 : QStringList ScanCommand::supportedOptions(const QCommandLineParser &parser) const
39 104 : {
40 284 : return AbstractCommand::supportedOptions(parser) + QStringList{
41 258 : };
42 104 : }
43 :
44 : /// \copydoc AbstractCommand::processOptions
45 45 : QStringList ScanCommand::processOptions(const QCommandLineParser &parser)
46 52 : {
47 97 : QStringList errors = AbstractCommand::processOptions(parser);
48 52 : if (!errors.isEmpty()) {
49 0 : return errors;
50 0 : }
51 :
52 52 : return errors;
53 52 : }
54 :
55 : /*!
56 : * Begins scanning for Pokit devices.
57 : */
58 45 : bool ScanCommand::start()
59 22 : {
60 22 : Q_ASSERT(discoveryAgent);
61 146 : qCInfo(lc).noquote() << tr("Scanning for Pokit devices...");
62 67 : discoveryAgent->start();
63 67 : return true;
64 22 : }
65 :
66 : /*!
67 : * Handles discovered Pokit devices, writing \a info to stdout.
68 : */
69 3780 : void ScanCommand::deviceDiscovered(const QBluetoothDeviceInfo &info)
70 4275 : {
71 8055 : switch (format) {
72 1425 : case OutputFormat::Csv:
73 4296 : for (; showCsvHeader; showCsvHeader = false) {
74 1989 : std::cout << qUtf8Printable(tr("uuid,address,name,major_class,minor_class,signal_strength\n"));
75 855 : }
76 6165 : std::cout << qUtf8Printable(QString::fromLatin1("%1,%2,%3,%4,%5,%6\n").arg(info.deviceUuid().toString(),
77 1425 : info.address().toString(), escapeCsvField(info.name()), toString(info.majorDeviceClass()),
78 1425 : toString(info.majorDeviceClass(), info.minorDeviceClass())).arg(info.rssi()));
79 2685 : break;
80 2685 : case OutputFormat::Json:
81 3945 : std::cout << QJsonDocument(toJson(info)).toJson().toStdString();
82 2685 : break;
83 2685 : case OutputFormat::Text:
84 5535 : std::cout << qUtf8Printable(tr("%1 %2 %3 %4\n").arg(info.deviceUuid().toString(),
85 1425 : info.address().toString(), info.name()).arg(info.rssi()));
86 2685 : break;
87 4275 : }
88 8055 : }
89 :
90 : /*!
91 : * Handles updated Pokit devices, writing \a info to stdout. Currently \a updatedFields us unused.
92 : */
93 : #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) // Required signal, and Fields, added in Qt 5.12.
94 1755 : void ScanCommand::deviceUpdated(const QBluetoothDeviceInfo &info,
95 : const QBluetoothDeviceInfo::Fields updatedFields)
96 1935 : {
97 1935 : Q_UNUSED(updatedFields)
98 3690 : deviceDiscovered(info);
99 3690 : }
100 : #endif
101 :
102 : /*!
103 : * Handles the completion of device discovery. In this override we simply exit, as the scan command
104 : * is nothing more than logging of discovered devices.
105 : */
106 45 : void ScanCommand::deviceDiscoveryFinished()
107 52 : {
108 110 : qCDebug(lc).noquote() << tr("Finished scanning for Pokit devices.");
109 97 : QCoreApplication::quit();
110 97 : }
111 :
112 : /*!
113 : * Returns \a info as a JSON object.
114 : */
115 1614 : QJsonObject ScanCommand::toJson(const QBluetoothDeviceInfo &info)
116 1832 : {
117 3446 : if (!info.isValid()) {
118 276 : return QJsonObject();
119 147 : }
120 1685 : QJsonObject json{
121 4270 : { QLatin1String("address"), info.address().toString() },
122 4655 : { QLatin1String("name"), info.name() },
123 3135 : { QLatin1String("isCached"), info.isCached() },
124 3170 : { QLatin1String("majorDeviceClass"), info.majorDeviceClass() },
125 3905 : { QLatin1String("majorDeviceClass"), toJson(info.majorDeviceClass()) },
126 3905 : { QLatin1String("minorDeviceClass"), toJson(info.majorDeviceClass(), info.minorDeviceClass()) },
127 3905 : { QLatin1String("signalStrength"), info.rssi() },
128 16030 : };
129 3170 : if (info.coreConfigurations() != QBluetoothDeviceInfo::UnknownCoreConfiguration) {
130 447 : json.insert(QLatin1String("coreConfiguration"), toJson(info.coreConfigurations()));
131 199 : }
132 3231 : if (!info.deviceUuid().isNull()) {
133 2847 : json.insert(QLatin1String("deviceUuid"), info.deviceUuid().toString());
134 1063 : }
135 1505 : #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) // Added in Qt 5.12.
136 2870 : if (!info.manufacturerData().isEmpty()) {
137 342 : json.insert(QLatin1String("manufacturerData"), toJson(info.manufacturerData()));
138 129 : }
139 1505 : #endif
140 3170 : if (info.serviceClasses() != QBluetoothDeviceInfo::NoService) {
141 543 : json.insert(QLatin1String("serviceClasses"), toJson(info.serviceClasses()));
142 242 : }
143 3905 : if (!info.serviceUuids().isEmpty()) {
144 138 : json.insert(QLatin1String("serviceUuids"), toJson(info.serviceUuids()));
145 52 : }
146 2670 : return json;
147 14702 : }
148 :
149 : /*!
150 : * Returns \a configuration as a JSON array of strings.
151 : */
152 354 : QJsonArray ScanCommand::toJson(const QBluetoothDeviceInfo::CoreConfigurations &configurations)
153 407 : {
154 761 : QJsonArray array;
155 407 : #define DOKIT_INTERNAL_IF_SET_THEN_APPEND(flag) \
156 1221 : if (configurations.testFlag(QBluetoothDeviceInfo::flag)) \
157 1221 : array.append(QLatin1String(#flag))
158 608 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(UnknownCoreConfiguration);
159 767 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(LowEnergyCoreConfiguration);
160 641 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(BaseRateCoreConfiguration);
161 : //DOKIT_INTERNAL_IF_SET_THEN_APPEND(BaseRateAndLowEnergyCoreConfiguration); // Combination flag.
162 407 : #undef DOKIT_INTERNAL_IF_SET_THEN_APPEND
163 761 : return array;
164 407 : }
165 :
166 : /*!
167 : * Returns \a majorClass as a JSON value. This is equivalent to toString, except that if toString
168 : * does not recognise \a majorClass, then \a majorClass is returned as a JSON number (not a string).
169 : *
170 : * \see toString(const QBluetoothDeviceInfo::MajorDeviceClass &majorClass)
171 : */
172 2115 : QJsonValue ScanCommand::toJson(const QBluetoothDeviceInfo::MajorDeviceClass &majorClass)
173 2413 : {
174 4528 : const QString string = toString(majorClass);
175 6643 : return (string.isNull() ? QJsonValue(majorClass) : QJsonValue(string));
176 3499 : }
177 :
178 : /*!
179 : * Returns \a minorClass as a JSON value. This is equivalent to toString, except that if toString
180 : * does not recognise \a minorClass as a sub-class of \a majorClass, then \a minorClass is returned
181 : * as a JSON number (not a string).
182 : *
183 : * \see toString(const QBluetoothDeviceInfo::MajorDeviceClass &majorClass, const quint8 minorClass)
184 : */
185 5625 : QJsonValue ScanCommand::toJson(const QBluetoothDeviceInfo::MajorDeviceClass &majorClass, const quint8 minorClass)
186 6469 : {
187 12094 : const QString string = toString(majorClass, minorClass);
188 17719 : return (string.isNull() ? QJsonValue(minorClass) : QJsonValue(string));
189 9427 : }
190 :
191 : /*!
192 : * Returns \a classes as a JSON array of strings.
193 : */
194 663 : QJsonArray ScanCommand::toJson(const QBluetoothDeviceInfo::ServiceClasses &classes)
195 762 : {
196 1425 : QJsonArray array;
197 762 : #define DOKIT_INTERNAL_IF_SET_THEN_APPEND(flag) \
198 6096 : if (classes.testFlag(QBluetoothDeviceInfo::flag)) \
199 6096 : array.append(QLatin1String(#flag))
200 1296 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(PositioningService);
201 1296 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(NetworkingService);
202 1296 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(RenderingService);
203 1263 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(CapturingService);
204 1263 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(ObjectTransferService);
205 1263 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(AudioService);
206 1263 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(TelephonyService);
207 1263 : DOKIT_INTERNAL_IF_SET_THEN_APPEND(InformationService);
208 762 : #undef DOKIT_INTERNAL_IF_SET_THEN_APPEND
209 1425 : return array;
210 762 : }
211 :
212 : /*!
213 : * Returns \a uuids as a JSON array.
214 : */
215 270 : QJsonArray ScanCommand::toJson(const QList<QBluetoothUuid> &uuids)
216 312 : {
217 582 : QJsonArray array;
218 1434 : for (const QBluetoothUuid &uuid: uuids) {
219 1476 : array.append(uuid.toString());
220 624 : }
221 582 : return array;
222 312 : }
223 :
224 : /*!
225 : * Returns Bluetooth manufacturer \a data as a JSON object that maps the manufacturer IDs (unsigned
226 : * integers as strings) to arrays of one or more values.
227 : */
228 273 : QJsonObject ScanCommand::toJson(const QMultiHash<quint16, QByteArray> &data)
229 301 : {
230 574 : QJsonObject object;
231 574 : QList<quint16> keys = data.uniqueKeys();
232 448 : std::sort(keys.begin(), keys.end());
233 1093 : for (const quint16 key: keys) {
234 : // Convert the key's values to a JSON array, reversing the order, because QMultiHash
235 : // guarantees that the values are orderer "from the most recently inserted to the least
236 : // recently inserted", which is the oppoosit of what we want.
237 760 : QList<QByteArray> values = data.values(key);
238 640 : std::reverse(values.begin(), values.end());
239 820 : QJsonArray array;
240 1578 : for (const QByteArray &value: values) {
241 1974 : array.append(QLatin1String(value.toBase64()));
242 627 : }
243 990 : object.insert(QString::number(key), array);
244 820 : }
245 574 : return object;
246 427 : }
247 :
248 : /*!
249 : * Returns \a majorClass as a human-readable string, or a null QString if \a majorClass is not
250 : * recognised.
251 : *
252 : * For example, if \a majorClass is \c QBluetoothDeviceInfo::ToyDevice, then the string `ToyDevice`
253 : * is returned.
254 : */
255 4005 : QString ScanCommand::toString(const QBluetoothDeviceInfo::MajorDeviceClass &majorClass)
256 4566 : {
257 4566 : #define DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(value) \
258 18866 : if (majorClass == QBluetoothDeviceInfo::value) \
259 18866 : return QLatin1String(#value)
260 8571 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(MiscellaneousDevice);
261 2664 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ComputerDevice);
262 2180 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(PhoneDevice);
263 336 : #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
264 336 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(LANAccessDevice); // Deprecated since Qt 5.13.
265 : #else
266 1264 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkDevice); // Added in Qt 5.13.
267 1160 : #endif
268 1496 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(AudioVideoDevice);
269 1392 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(PeripheralDevice);
270 1288 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ImagingDevice);
271 1184 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableDevice);
272 1080 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ToyDevice);
273 976 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthDevice);
274 980 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedDevice);
275 312 : #undef DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN
276 660 : qCDebug(lc).noquote() << tr("Unknown major class %1.").arg(majorClass);
277 312 : return QString(); // Null QString indicates unknown minor class.
278 848 : }
279 :
280 : /*!
281 : * Returns \a minorClass as a human-readable string, or a null QString if \a minorClass is not
282 : * recognised as a sub-class of \a majorClass.
283 : *
284 : * For example, if \a majorClass is \c QBluetoothDeviceInfo::ToyDevice, and \a minorClass is
285 : * \c QBluetoothDeviceInfo::ToyRobot, then the string `ToyRobot` is returned.
286 : */
287 11025 : QString ScanCommand::toString(const QBluetoothDeviceInfo::MajorDeviceClass &majorClass, const quint8 minorClass)
288 12678 : {
289 12678 : #define DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(value) \
290 56050 : if (minorClass == QBluetoothDeviceInfo::value) \
291 56050 : return QLatin1String(#value)
292 23703 : switch (majorClass) {
293 3998 : case QBluetoothDeviceInfo::MiscellaneousDevice:
294 3998 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedMiscellaneous);
295 484 : break;
296 2268 : case QBluetoothDeviceInfo::ComputerDevice:
297 1602 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedComputer);
298 1240 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(DesktopComputer);
299 1126 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ServerComputer);
300 1012 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(LaptopComputer);
301 898 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HandheldClamShellComputer);
302 784 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HandheldComputer);
303 670 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableComputer);
304 484 : break;
305 2074 : case QBluetoothDeviceInfo::PhoneDevice:
306 1466 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedPhone);
307 1126 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(CellularPhone);
308 1012 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(CordlessPhone);
309 898 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(SmartPhone);
310 784 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WiredModemOrVoiceGatewayPhone);
311 670 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(CommonIsdnAccessPhone);
312 484 : break;
313 84 : #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
314 396 : case QBluetoothDeviceInfo::LANAccessDevice: // Deprecated since Qt 5.13.
315 : #else
316 1350 : case QBluetoothDeviceInfo::NetworkDevice: // Added in Qt 5.13.
317 720 : #endif
318 1242 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkFullService);
319 934 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkLoadFactorOne);
320 820 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkLoadFactorTwo);
321 706 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkLoadFactorThree);
322 592 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkLoadFactorFour);
323 478 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkLoadFactorFive);
324 364 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkLoadFactorSix);
325 250 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(NetworkNoService);
326 104 : break;
327 3492 : case QBluetoothDeviceInfo::AudioVideoDevice:
328 2288 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedAudioVideoDevice);
329 1792 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableHeadsetDevice);
330 1688 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HandsFreeDevice);
331 1584 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(Microphone);
332 1480 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(Loudspeaker);
333 1376 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(Headphones);
334 1272 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(PortableAudioDevice);
335 1168 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(CarAudio);
336 1064 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(SetTopBox);
337 960 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HiFiAudioDevice);
338 856 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(Vcr);
339 752 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(VideoCamera);
340 648 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(Camcorder);
341 544 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(VideoMonitor);
342 440 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(VideoDisplayAndLoudspeaker);
343 336 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(VideoConferencing);
344 232 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(GamingDevice);
345 104 : break;
346 2134 : case QBluetoothDeviceInfo::PeripheralDevice:
347 1514 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedPeripheral);
348 1162 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(KeyboardPeripheral);
349 1048 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(PointingDevicePeripheral);
350 934 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(KeyboardWithPointingDevicePeripheral);
351 820 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(JoystickPeripheral);
352 706 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(GamepadPeripheral);
353 592 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(RemoteControlPeripheral);
354 478 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(SensingDevicePeripheral);
355 364 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(DigitizerTabletPeripheral);
356 250 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(CardReaderPeripheral);
357 104 : break;
358 1164 : case QBluetoothDeviceInfo::ImagingDevice:
359 834 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedImagingDevice);
360 698 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ImageDisplay);
361 562 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ImageCamera);
362 426 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ImageScanner);
363 290 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ImagePrinter);
364 104 : break;
365 1358 : case QBluetoothDeviceInfo::WearableDevice:
366 970 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedWearableDevice);
367 706 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableWristWatch);
368 592 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearablePager);
369 478 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableJacket);
370 364 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableHelmet);
371 250 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(WearableGlasses);
372 104 : break;
373 1746 : case QBluetoothDeviceInfo::ToyDevice:
374 1242 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedToy);
375 934 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ToyRobot);
376 820 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ToyVehicle);
377 706 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ToyDoll);
378 592 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ToyController);
379 478 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(ToyGame);
380 312 : break;
381 1746 : case QBluetoothDeviceInfo::HealthDevice:
382 1242 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(UncategorizedHealthDevice);
383 934 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthBloodPressureMonitor);
384 820 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthThermometer);
385 706 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthWeightScale);
386 592 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthGlucoseMeter);
387 478 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthPulseOximeter);
388 364 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthDataDisplay);
389 250 : DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN(HealthStepCounter);
390 104 : break;
391 744 : case QBluetoothDeviceInfo::UncategorizedDevice:
392 : // There are no minor classes defined (in Qt) for uncategorized devices.
393 744 : break;
394 12678 : }
395 3444 : #undef DOKIT_INTERNAL_IF_EQUAL_THEN_RETURN
396 7350 : qCDebug(lc).noquote() << tr("Unknown minor class %1 for major class %2.")
397 0 : .arg(minorClass).arg(majorClass);
398 3444 : return QString(); // Null QString indicates unknown minor class.
399 12678 : }
|