diff options
Diffstat (limited to 'examples/bluetooth')
-rw-r--r-- | examples/bluetooth/bluetooth.pro | 3 | ||||
-rw-r--r-- | examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc | 6 | ||||
-rw-r--r-- | examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc | 115 | ||||
-rw-r--r-- | examples/bluetooth/heartrate-server/heartrate-server.pro | 10 | ||||
-rw-r--r-- | examples/bluetooth/heartrate-server/main.cpp | 121 |
5 files changed, 253 insertions, 2 deletions
diff --git a/examples/bluetooth/bluetooth.pro b/examples/bluetooth/bluetooth.pro index a98bb62d..1c09dade 100644 --- a/examples/bluetooth/bluetooth.pro +++ b/examples/bluetooth/bluetooth.pro @@ -1,4 +1,7 @@ TEMPLATE = subdirs + +SUBDIRS += heartrate-server + qtHaveModule(widgets) { SUBDIRS += btchat \ btscanner \ diff --git a/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc b/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc index e7e1176f..2bb59ae1 100644 --- a/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc +++ b/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc @@ -51,8 +51,10 @@ A Bluetooth Low Energy device with a Heart Rate service is required for this application to work. An alternative might be a programmable - Bluetooth Low Energy device which might simulate the service. If no such device can be - found, the example uses a demo mode which creates and displays random values. + Bluetooth Low Energy device which might simulate the service. You can also use the + \l {heartrate-server} {Heart Rate server} example for that purpose. + If no such device can be found, the example uses a demo mode which creates and displays + random values. The \l {lowenergyscanner}{Bluetooth Low Energy Scanner} example might be more suitable if a heart rate device is not available. The scanner example works with any type of Bluetooth diff --git a/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc b/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc new file mode 100644 index 00000000..22c6fcd1 --- /dev/null +++ b/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example heartrate-server + \title Bluetooth Low Energy Heart Rate Server Example + \brief An example demonstrating how to set up and advertise a GATT service. The example + demonstrates the use of the Qt Bluetooth Low Energy classes related to peripheral (slave) + functionality. + + The Bluetooth Low Energy Heart Rate Server is a command-line application that shows how to + develop a Bluetooth GATT server using the Qt Bluetooth API. + The application covers setting up a service, advertising it and notifying clients about changes + to characteristic values. + + The example makes use of the following Qt classes: + + \list + \li \l QLowEnergyAdvertisingData + \li \l QLowEnergyAdvertisingParameters + \li \l QLowEnergyServiceData + \li \l QLowEnergyCharacteristicData + \li \l QLowEnergyDescriptorData + \li \l QLowEnergyController + \li \l QLowEnergyService + + \endlist + + The example implements a server application, which means it has no graphical user interface. + To visualize what it is doing, you can use the \l {heartlistener}{Heart Listener} + example, which is basically the client-side counterpart to this application. + + \note On Linux, advertising requires privileged access, so you need to run + the example as root, for instance via \c sudo. + + \section1 Setting up Advertising Data and Parameters + Two classes are used to configure the advertising process: \l QLowEnergyAdvertisingData to + specify which information is to be broadcast, and \l QLowEnergyAdvertisingParameters for + specific aspects such as setting the advertising interval or controlling which devices are + allowed to connect. In our example, we simply use the default parameters. + + The information contained in the \l QLowEnergyAdvertisingData will be visible to other devices + that are currently scanning. They can use it to decide whether they want to establish a connection + or not. In our example, we include the type of service we offer, a name that adequately + describes our device to humans, and the transmit power level of the device. The latter is + often useful to potential clients, because they can tell how far away our device is by + comparing the received signal strength to the advertised one. + \note Space for the advertising data is very limited (only 31 bytes in total), so + variable-length data such as the device name should be kept as short as possible. + \snippet heartrate-server/main.cpp Advertising Data + + \section1 Setting up Service Data + Next we configure the kind of service we want to offer. We use the \c {Heart Rate} service as + defined in the Bluetooth specification in its minimal form, that is, consisting only of the + \c {Heart Rate Measurement} characteristic. This characteristic must support the \c Notify + property (and no others), and it needs to have a \c {Client Characteristic Configuration} + descriptor, which enables clients to register to get notified about changes to characteristic + values. We set the initial heart rate value to zero, as it cannot be read anyway (the only + way the client can get at the value is via notifications). + \snippet heartrate-server/main.cpp Service Data + + \section1 Advertising and Listening for Incoming Connections + Now that all the data has been set up, we can start advertising. First we create a + \l QLowEnergyController object in the + \l {QLowEnergyController::PeripheralRole} {peripheral role} and use it to create a (dynamic) + \l QLowEnergyService object from our (static) \l QLowEnergyServiceData. + Then we call \l QLowEnergyController::startAdvertising(). + Note that we hand in our \l QLowEnergyAdvertisingData twice: The first argument + acts as the actual advertising data, the second one as the scan response data. They could + transport different information, but here we don't have a need for that. We also pass + a default-constructed instance of \l QLowEnergyAdvertisingParameters, because the default + advertising parameters are fine for us. If a client is interested in the advertised service, + it can now establish a connection to our device. When that happens, the device stops advertising + and the \l QLowEnergyController::connected() signal is emitted. + \note When a client disconnects, advertising does not resume automatically. If you want that + to happen, you need to connect to the \l QLowEnergyController::disconnected() signal + and call \l QLowEnergyController::startAdvertising() in the respective slot. + \snippet heartrate-server/main.cpp Start Advertising + + \section1 Providing the Heartrate + So far, so good. But how does a client actually get at the heart rate? This happens by + regularly updating the value of the respective characteristic in the \l QLowEnergyService + object that we received from the \l QLowEnergyController in the code snippet above. + The source of the heart rate would normally be some kind of sensor, but in our example, + we just make up values that we let oscillate between 60 and 100. The most important part in the + following code snippet is the call to \l QLowEnergyService::writeCharacteristic. If + a client is currently connected and has enabled notifications by writing to the aforementioned + \c {Client Characteristic Configuration}, it will get notified about the new value. + \snippet heartrate-server/main.cpp Provide Heartbeat +*/ + diff --git a/examples/bluetooth/heartrate-server/heartrate-server.pro b/examples/bluetooth/heartrate-server/heartrate-server.pro new file mode 100644 index 00000000..4ccf486c --- /dev/null +++ b/examples/bluetooth/heartrate-server/heartrate-server.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = heartrate-server + +QT += bluetooth +CONFIG += c++11 + +SOURCES += main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/heartrate-server +INSTALLS += target diff --git a/examples/bluetooth/heartrate-server/main.cpp b/examples/bluetooth/heartrate-server/main.cpp new file mode 100644 index 00000000..779dbb6a --- /dev/null +++ b/examples/bluetooth/heartrate-server/main.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtBluetooth/qlowenergyadvertisingdata.h> +#include <QtBluetooth/qlowenergyadvertisingparameters.h> +#include <QtBluetooth/qlowenergycharacteristic.h> +#include <QtBluetooth/qlowenergycharacteristicdata.h> +#include <QtBluetooth/qlowenergydescriptordata.h> +#include <QtBluetooth/qlowenergycontroller.h> +#include <QtBluetooth/qlowenergyservice.h> +#include <QtBluetooth/qlowenergyservicedata.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qlist.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qtimer.h> + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + //! [Advertising Data] + QLowEnergyAdvertisingData advertisingData; + advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral); + advertisingData.setIncludePowerLevel(true); + advertisingData.setLocalName("HeartRateServer"); + advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::HeartRate); + //! [Advertising Data] + + //! [Service Data] + QLowEnergyCharacteristicData charData; + charData.setUuid(QBluetoothUuid::HeartRateMeasurement); + charData.setValue(QByteArray(2, 0)); + charData.setProperties(QLowEnergyCharacteristic::Notify); + const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::ClientCharacteristicConfiguration, + QByteArray(2, 0)); + charData.addDescriptor(clientConfig); + + QLowEnergyServiceData serviceData; + serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); + serviceData.setUuid(QBluetoothUuid::HeartRate); + serviceData.addCharacteristic(charData); + //! [Service Data] + + //! [Start Advertising] + const QScopedPointer<QLowEnergyController> leController(QLowEnergyController::createPeripheral()); + const QScopedPointer<QLowEnergyService> service(leController->addService(serviceData)); + leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData, + advertisingData); + //! [Start Advertising] + + //! [Provide Heartbeat] + QTimer heartbeatTimer; + quint8 currentHeartRate = 60; + enum ValueChange { ValueUp, ValueDown } valueChange = ValueUp; + const auto heartbeatProvider = [&service, ¤tHeartRate, &valueChange]() { + QByteArray value; + value.append(char(0)); // Flags that specify the format of the value. + value.append(char(currentHeartRate)); // Actual value. + QLowEnergyCharacteristic characteristic + = service->characteristic(QBluetoothUuid::HeartRateMeasurement); + Q_ASSERT(characteristic.isValid()); + service->writeCharacteristic(characteristic, value); // Potentially causes notification. + if (currentHeartRate == 60) + valueChange = ValueUp; + else if (currentHeartRate == 100) + valueChange = ValueDown; + if (valueChange == ValueUp) + ++currentHeartRate; + else + --currentHeartRate; + }; + QObject::connect(&heartbeatTimer, &QTimer::timeout, heartbeatProvider); + heartbeatTimer.start(1000); + //! [Provide Heartbeat] + + auto reconnect = [&leController, advertisingData]() { + leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData, + advertisingData); + }; + QObject::connect(leController.data(), &QLowEnergyController::disconnected, reconnect); + + return app.exec(); +} |