diff options
105 files changed, 9130 insertions, 169 deletions
diff --git a/examples/bluetooth/bluetooth.pro b/examples/bluetooth/bluetooth.pro index e8a6f9a6..f7fe9d20 100644 --- a/examples/bluetooth/bluetooth.pro +++ b/examples/bluetooth/bluetooth.pro @@ -6,4 +6,7 @@ qtHaveModule(widgets) { bttennis } -qtHaveModule(quick): SUBDIRS += scanner picturetransfer +qtHaveModule(quick): SUBDIRS += scanner \ + picturetransfer \ + lowenergyscanner \ + heartlistener diff --git a/examples/bluetooth/btchat/chatserver.cpp b/examples/bluetooth/btchat/chatserver.cpp index 0b29b87b..6da4b471 100644 --- a/examples/bluetooth/btchat/chatserver.cpp +++ b/examples/bluetooth/btchat/chatserver.cpp @@ -83,7 +83,9 @@ void ChatServer::startServer(const QBluetoothAddress& localAdapter) classId); classId.prepend(QVariant::fromValue(QBluetoothUuid(serviceUuid))); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId); + serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,classId); //! [Class Uuuid must contain at least 1 entry] diff --git a/examples/bluetooth/btscanner/service.cpp b/examples/bluetooth/btscanner/service.cpp index d9172d69..e304f850 100644 --- a/examples/bluetooth/btscanner/service.cpp +++ b/examples/bluetooth/btscanner/service.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtBluetooth module of the Qt Toolkit. @@ -44,6 +45,9 @@ #include <qbluetoothservicediscoveryagent.h> #include <qbluetoothserviceinfo.h> #include <qbluetoothlocaldevice.h> +#include <qlowenergyserviceinfo.h> +#include <qlowenergycharacteristicinfo.h> +#include <qbluetoothuuid.h> ServiceDiscoveryDialog::ServiceDiscoveryDialog(const QString &name, @@ -74,6 +78,8 @@ ServiceDiscoveryDialog::ServiceDiscoveryDialog(const QString &name, connect(discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), this, SLOT(addService(QBluetoothServiceInfo))); connect(discoveryAgent, SIGNAL(finished()), ui->status, SLOT(hide())); + connect(discoveryAgent, SIGNAL(serviceDiscovered(const QLowEnergyServiceInfo&)), + this, SLOT(addLowEnergyService(const QLowEnergyServiceInfo&))); discoveryAgent->start(); } @@ -98,3 +104,10 @@ void ServiceDiscoveryDialog::addService(const QBluetoothServiceInfo &info) ui->list->addItem(line); } +void ServiceDiscoveryDialog::addLowEnergyService(const QLowEnergyServiceInfo &gatt) +{ + QString line = gatt.serviceName(); + + ui->list->addItem(line); +} + diff --git a/examples/bluetooth/btscanner/service.h b/examples/bluetooth/btscanner/service.h index 293bc7a9..2089eb87 100644 --- a/examples/bluetooth/btscanner/service.h +++ b/examples/bluetooth/btscanner/service.h @@ -49,6 +49,8 @@ QT_FORWARD_DECLARE_CLASS(QBluetoothAddress) QT_FORWARD_DECLARE_CLASS(QBluetoothServiceInfo) QT_FORWARD_DECLARE_CLASS(QBluetoothServiceDiscoveryAgent) +QT_FORWARD_DECLARE_CLASS (QLowEnergyServiceInfo) +QT_FORWARD_DECLARE_CLASS (QLowEnergyCharacteristicInfo) QT_USE_NAMESPACE @@ -62,6 +64,7 @@ public: public slots: void addService(const QBluetoothServiceInfo&); + void addLowEnergyService(const QLowEnergyServiceInfo&); private: QBluetoothServiceDiscoveryAgent *discoveryAgent; diff --git a/examples/bluetooth/heartlistener/assets/Button.qml b/examples/bluetooth/heartlistener/assets/Button.qml new file mode 100644 index 00000000..40e98875 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/Button.qml @@ -0,0 +1,77 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id:button + //color: "#3870BA" + + property real buttonWidth: 300 + property real buttonHeight: 80 + property string text: "Button" + + signal buttonClick() + width: click.pressed ? (buttonWidth - 15) : buttonWidth + height: click.pressed ? (buttonHeight - 15) :buttonHeight + + color: click.pressed ? "#3265A7" : "#3870BA" + + border.color: "#F0EBED" + border.width: 5 + radius: 10 + + Text { + id: label + font.pixelSize: 30; font.bold: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + elide: Text.ElideMiddle + color: "#F0EBED" + text: button.text + } + + MouseArea { + id: click + anchors.fill: parent + onClicked: buttonClick() + } +} diff --git a/examples/bluetooth/heartlistener/assets/Point.qml b/examples/bluetooth/heartlistener/assets/Point.qml new file mode 100644 index 00000000..2ed94a4d --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/Point.qml @@ -0,0 +1,51 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: point + + Image { + width: 10; height: 7 + smooth: true + source: "blue_heart_small.png" + } +} diff --git a/examples/bluetooth/heartlistener/assets/blue_heart.png b/examples/bluetooth/heartlistener/assets/blue_heart.png Binary files differnew file mode 100644 index 00000000..997ee699 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/blue_heart.png diff --git a/examples/bluetooth/heartlistener/assets/blue_heart_small.png b/examples/bluetooth/heartlistener/assets/blue_heart_small.png Binary files differnew file mode 100644 index 00000000..7bd1f981 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/blue_heart_small.png diff --git a/examples/bluetooth/heartlistener/assets/busy_dark.png b/examples/bluetooth/heartlistener/assets/busy_dark.png Binary files differnew file mode 100644 index 00000000..3a105953 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/busy_dark.png diff --git a/examples/bluetooth/heartlistener/assets/dialog.qml b/examples/bluetooth/heartlistener/assets/dialog.qml new file mode 100644 index 00000000..45b64cf3 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/dialog.qml @@ -0,0 +1,61 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: root + opacity: 0.8 + color: "#E0DEDF" + anchors.horizontalCenter: parent.horizontalCenter + + property int hr: heartRate.hr + Text { + text: heartRate.message + color: "#3870BA" + + } + + onHrChanged: { + if (heartRate.hr > 0) { + root.destroy() + } + } +} diff --git a/examples/bluetooth/heartlistener/assets/draw.js b/examples/bluetooth/heartlistener/assets/draw.js new file mode 100644 index 00000000..a5de5474 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/draw.js @@ -0,0 +1,74 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +var component; +var size = 0; +var counter = 0; +var difference = 0; + +function start() { + size = heartRate.measurementsSize(); + difference = (plot.width-topbar.width)/size; + console.log(size +" "+ plot.width); + for (var i = 0; i< size; i++) { + var value = heartRate.measurements(i); + + drawIt(value); + counter++; + } +} + +function drawIt(value) { + if (component == null) + component = Qt.createComponent("Point.qml"); + if (component.status == Component.Ready) { + var dynamicObject = component.createObject(plot); + if (dynamicObject == null) { + console.log("error creating block"); + console.log(component.errorString()); + return false; + } + dynamicObject.x = 10+(counter*difference); + console.log(plot.height) + dynamicObject.y = plot.height -value; + + } +} + diff --git a/examples/bluetooth/heartlistener/assets/home.qml b/examples/bluetooth/heartlistener/assets/home.qml new file mode 100644 index 00000000..2c5e9485 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/home.qml @@ -0,0 +1,186 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: screen + color: "#F0EBED" + property string message: heartRate.message + onMessageChanged: { + if (heartRate.message != "Scanning for devices..." && heartRate.message != "Low Energy device found. Scanning for more...") { + background.visible = false; + demoMode.visible = true; + } + else { + demoMode.visible = false; + background.visible = true; + } + } + + Rectangle { + id:select + width: parent.width + anchors.top: parent.top + height: 80 + color: "#F0EBED" + border.color: "#3870BA" + border.width: 2 + radius: 10 + + Text { + id: selectText + color: "#3870BA" + font.pixelSize: 34 + anchors.centerIn: parent + text: "Select Device" + } + } + + Rectangle { + id: spinner + width: parent.width + anchors.top: select.bottom + anchors.bottom: demoMode.top + visible: false + color: "#F0EBED" + z: 100 + + Rectangle { + id: inside + anchors.centerIn: parent + Image { + id: background + + width:100 + height:100 + anchors.horizontalCenter: parent.horizontalCenter + + source: "busy_dark.png" + fillMode: Image.PreserveAspectFit + NumberAnimation on rotation { duration: 3000; from:0; to: 360; loops: Animation.Infinite} + } + + Text { + id: infotext + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: background.bottom + text: heartRate.message + color: "#8F8F8F" + } + } + } + + Component.onCompleted: { + heartRate.deviceSearch(); + spinner.visible=true; + } + + ListView { + id: theListView + width: parent.width + onModelChanged: spinner.visible=false + anchors.top: select.bottom + anchors.bottom: demoMode.top + model: heartRate.name + + delegate: Rectangle { + id: box + height:140 + width: parent.width + color: "#3870BA" + border.color: "#F0EBED" + border.width: 5 + radius: 15 + + MouseArea { + anchors.fill: parent + onPressed: { box.color= "#3265A7"; box.height=110} + onClicked: { + heartRate.connectToService(modelData.deviceAddress); + pageLoader.source="monitor.qml"; + } + } + + Text { + id: device + font.pixelSize: 30 + text: modelData.deviceName + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + color: "#F0EBED" + } + + Text { + id: deviceAddress + font.pixelSize: 30 + text: modelData.deviceAddress + anchors.bottom: parent.bottom + anchors.bottomMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + color: "#F0EBED" + } + } + } + + Button { + id:demoMode + buttonWidth: parent.width + buttonHeight: 0.1*parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: scanAgain.top + text: "Run Demo" + onButtonClick: { + heartRate.startDemo(); + pageLoader.source="monitor.qml"; + } + } + + Button { + id:scanAgain + buttonWidth: parent.width + buttonHeight: 0.1*parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + text: "Menu" + onButtonClick: pageLoader.source="main.qml" + } +} diff --git a/examples/bluetooth/heartlistener/assets/main.qml b/examples/bluetooth/heartlistener/assets/main.qml new file mode 100644 index 00000000..e892eb47 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/main.qml @@ -0,0 +1,84 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + width: 400 + height: 600 + id: begin + + Rectangle { + color: "#F0EBED" + anchors.fill: parent + Rectangle { + id: about + width: 0.75*parent.width + height: 0.1*parent.height + anchors.top: parent.top + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + color: "#F0EBED" + border.color: "#3870BA" + border.width: 2 + radius: 10 + Text { + id: aboutinfo + anchors.centerIn: parent + color: "#3870BA" + text: "Welcome to the Heart Listener Application" + } + } + + Button { + id:call + buttonWidth: 0.75*parent.width + buttonHeight: 0.15*parent.height + anchors.centerIn: parent + text: "Scan for Devices" + onButtonClick: pageLoader.source="home.qml" + } + } + + Loader { + id: pageLoader + anchors.fill: parent + } +} diff --git a/examples/bluetooth/heartlistener/assets/monitor.qml b/examples/bluetooth/heartlistener/assets/monitor.qml new file mode 100644 index 00000000..5dbf66c3 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/monitor.qml @@ -0,0 +1,154 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + id: screenMonitor + color: "#F0EBED" + + Button { + id:menu + buttonWidth: parent.width + buttonHeight: 0.1 * parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + text: "Menu" + onButtonClick: { + heartRate.disconnectService(); + pageLoader.source="home.qml"; + } + } + + Text { + id: hrValue + font.pointSize: 24; font.bold: true + anchors.top:menu.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 25 + + color: "#3870BA" + text: heartRate.hr + onTextChanged: { + if (heartRate.hr > 0 && updatei != null && heartRate.numDevices() > 0) { + updatei.destroy() + } + } + } + + Rectangle { + id: updatei + width: parent.width + height: 80 + anchors.bottom: stop.top + + color: "#F0EBED" + border.color: "#3870BA" + border.width: 2 + + Text { + id: logi + text: heartRate.message + anchors.centerIn: parent + color: "#3870BA" + } + } + + Image { + id: background + width: 300 + height: width + anchors.centerIn: parent + source: "blue_heart.png" + fillMode: Image.PreserveAspectFit + NumberAnimation on width { + running: heartRate.hr > 0; + duration: heartRate.hr/60*250; + from:300; to: 350; + loops: Animation.Infinite; + } + + ParticleSystem { + id: systwo + anchors.fill: parent + + ImageParticle { + system: systwo + id: cptwo + source: "star.png" + colorVariation: 0.4 + color: "#000000FF" + } + + Emitter { + //burst on click + id: burstytwo + system: systwo + enabled: true + x: 160 + y: 150 + emitRate: heartRate.hr*100 + maximumEmitted: 4000 + acceleration: AngleDirection {angleVariation: 360; magnitude: 360; } + size: 4 + endSize: 8 + sizeVariation: 4 + } + + + } + + } + + Button { + id:stop + buttonWidth: parent.width + buttonHeight: 0.1*parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + text: "Stop Monitoring" + onButtonClick: { + burstytwo.enabled = false; + heartRate.disconnectService(); + pageLoader.source = "results.qml"; + } + } +} diff --git a/examples/bluetooth/heartlistener/assets/results.qml b/examples/bluetooth/heartlistener/assets/results.qml new file mode 100644 index 00000000..78c08873 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/results.qml @@ -0,0 +1,290 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import "draw.js" as DrawGraph + +Rectangle { + id: results + color: "#F0EBED" + + Component.onCompleted: heartRate.obtainResults() + + function getTime() { + var t = heartRate.time; + var min = Math.floor(t/60); + var sec = t%60; + var r = min + " min " + sec + " sec " + return r; + } + + function drawGraph() { + var b = plot.height/200; + var ctx = canvas1.getContext('2d'); + ctx.beginPath() + ctx.moveTo(10, plot.height- (b*60)) + var size = heartRate.measurementsSize(); + var difference = (plot.width-topbar.width)/size; + + for (var i = 0; i< size; i++) { + var value = heartRate.measurements(i); + if (i == 0) { + ctx.moveTo(10+2, (plot.height- (value*b) + 2)); + ctx.rect((10 + i*difference), (plot.height- (value*b)), 4, 4); + + } + else { + ctx.lineTo((10+2 + i*difference), (plot.height- (value*b) + 2)); + ctx.rect((10 + i*difference), (plot.height- (value*b)), 4, 4); + } + + } + ctx.fillStyle = "#3870BA" + ctx.fill() + ctx.strokeStyle = "#3870BA" + ctx.stroke() + ctx.closePath() + } + + Rectangle { + id: res + width: parent.width + anchors.top: parent.top + height: 80 + color: "#F0EBED" + border.color: "#3870BA" + border.width: 2 + radius: 10 + Text { + id: restText + color: "#3870BA" + font.pixelSize: 34 + anchors.centerIn: parent + text: "Results" + } + } + + Text { + id: topbar + text: "200" + anchors.left: parent.left + anchors.top: res.bottom + anchors.rightMargin: 4 + color: "#3870BA" + z: 50 + } + + Rectangle { + id: level + anchors.left: topbar.right + + anchors.top: res.bottom + height: ((results.height -(res.height + menuLast.height + start.height ))/2) + width: 3 + color: "#3870BA" + } + + Text { + id: middlebar + anchors.verticalCenter: level.verticalCenter + anchors.left: parent.left + text: "100" + color: "#3870BA" + z: 50 + } + + Rectangle{ + id: downlevel + anchors.bottom: cover.top + width: parent.width + anchors.left: level.right + height: 3 + color: "#3870BA" + z: 50 + } + + Rectangle { + id: plot + anchors.left: level.right + anchors.leftMargin: 15 + width: results.width + height: ((parent.height-(res.height+menuLast.height+start.height))/2) + + anchors.top: res.bottom + color: "#F0EBED" + Canvas { + id: canvas1 + anchors.fill: parent + z: 150 + onPaint: drawGraph() + } + } + + Rectangle { + id: cover + anchors.top: plot.bottom + anchors.bottom: menuLast.top + width: parent.width + height: ((parent.height-(res.height+menuLast.height+start.height))/2) + color: "#F0EBED" + radius: 10 + border.color: "#3870BA" + border.width: 2 + + Flickable { + id: scroll + anchors.fill: parent + anchors.margins: 5 + clip: true + contentWidth: parent.width + contentHeight: stresult.height + + Rectangle { + id: stresult + width: parent.width + height: (results.height - (res.height + menuLast.height + start.height - 100)) + color: "#F0EBED" + radius: 10 + + Text { + id: averageHR + font.pixelSize: 30; + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + + color: "#3870BA" + text: "Average Heart Rate" + } + + Text { + id: averageHRt + font.pixelSize: 40; font.bold: true + anchors.top: averageHR.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: heartRate.average + } + + Text { + id: time + font.pixelSize: 30; + anchors.top: averageHRt.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: "Seconds measured " + } + + Text { + id: timet + font.pixelSize: 40; font.bold: true + anchors.top: time.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: getTime() + } + Text { + id: maxi + font.pixelSize: 30; + anchors.top: timet.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: " Max || Min " + } + + Text { + id: mini + font.pixelSize: 40; font.bold: true + anchors.top:maxi.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: " " + heartRate.maxHR + " || " + heartRate.minHR + } + + Text { + id: calories + font.pixelSize: 30; + anchors.top: mini.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: " Calories " + } + + Text { + id: caloriestext + font.pixelSize: 40; font.bold: true + anchors.top:calories.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + color: "#3870BA" + text: Math.floor(heartRate.calories) + } + } + } + } + + Button { + id:menuLast + buttonWidth: parent.width + buttonHeight: 0.1*parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: start.top + text: "Menu" + onButtonClick: { pageLoader.source="main.qml"} + } + + Button { + id:start + buttonWidth: parent.width + buttonHeight: 0.1*parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + text: "Start Monitoring" + onButtonClick: { + heartRate.connectToService(heartRate.deviceAddress()); + pageLoader.source="monitor.qml"; + } + } +} diff --git a/examples/bluetooth/heartlistener/assets/star.png b/examples/bluetooth/heartlistener/assets/star.png Binary files differnew file mode 100644 index 00000000..defbde53 --- /dev/null +++ b/examples/bluetooth/heartlistener/assets/star.png diff --git a/examples/bluetooth/heartlistener/deviceinfo.cpp b/examples/bluetooth/heartlistener/deviceinfo.cpp new file mode 100644 index 00000000..656d6126 --- /dev/null +++ b/examples/bluetooth/heartlistener/deviceinfo.cpp @@ -0,0 +1,57 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "deviceinfo.h" + +DeviceInfo::DeviceInfo(const QBluetoothDeviceInfo &device): + m_device(device) +{ + Q_EMIT deviceChanged(); +} + +QBluetoothDeviceInfo DeviceInfo::getDevice() +{ + return m_device; +} + +void DeviceInfo::setDevice(const QBluetoothDeviceInfo &device) +{ + m_device = device; +} diff --git a/examples/bluetooth/heartlistener/deviceinfo.h b/examples/bluetooth/heartlistener/deviceinfo.h new file mode 100644 index 00000000..94b0db80 --- /dev/null +++ b/examples/bluetooth/heartlistener/deviceinfo.h @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef DEVICEINFO_H +#define DEVICEINFO_H + +#include <QString> +#include <QObject> +#include <qbluetoothdeviceinfo.h> +#include <qbluetoothaddress.h> + +class DeviceInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString deviceName READ getName NOTIFY deviceChanged) + Q_PROPERTY(QString deviceAddress READ getAddress NOTIFY deviceChanged) +public: + DeviceInfo(const QBluetoothDeviceInfo &device); + void setDevice(const QBluetoothDeviceInfo &device); + QString getName() { return m_device.name(); } + QString getAddress() { return m_device.address().toString(); } + QBluetoothDeviceInfo getDevice(); + +signals: + void deviceChanged(); + +private: + QBluetoothDeviceInfo m_device; +}; + +#endif // DEVICEINFO_H diff --git a/examples/bluetooth/heartlistener/doc/images/hearratemonitor.png b/examples/bluetooth/heartlistener/doc/images/hearratemonitor.png Binary files differnew file mode 100644 index 00000000..ed51ba86 --- /dev/null +++ b/examples/bluetooth/heartlistener/doc/images/hearratemonitor.png diff --git a/examples/bluetooth/heartlistener/doc/images/hearrateresults.png b/examples/bluetooth/heartlistener/doc/images/hearrateresults.png Binary files differnew file mode 100644 index 00000000..2c961517 --- /dev/null +++ b/examples/bluetooth/heartlistener/doc/images/hearrateresults.png diff --git a/examples/bluetooth/heartlistener/doc/images/hearrateresults1.png b/examples/bluetooth/heartlistener/doc/images/hearrateresults1.png Binary files differnew file mode 100644 index 00000000..7af63b57 --- /dev/null +++ b/examples/bluetooth/heartlistener/doc/images/hearrateresults1.png diff --git a/examples/bluetooth/heartlistener/doc/images/heartrateintro.png b/examples/bluetooth/heartlistener/doc/images/heartrateintro.png Binary files differnew file mode 100644 index 00000000..fb0a7b34 --- /dev/null +++ b/examples/bluetooth/heartlistener/doc/images/heartrateintro.png diff --git a/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc b/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc new file mode 100644 index 00000000..fa63714a --- /dev/null +++ b/examples/bluetooth/heartlistener/doc/src/heartlistener.qdoc @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 heartlistener + \title Bluetooth Low Energy Heart Listener example + + The Bluetooth Low Energy (BLE) Heart Listener Example shows how to develop a Bluetooth + Low Energy applications using the Qt Bluetooth API. The application covers + the scanning for BLE devices, connecting to the BLE Heart Rate service and + receiving updates from the BLE heart belt. The BLE heart belt is required + for this application to work. + + \image heartrateintro.png + + The best and the safest approach is to do a service discovery for BLE device first and + then pick the heart rate service. Before that it is necessary to connect signals from + the QLowEnergyController class, which is responsible for the communication with the + BLE device. + + \snippet heartlistener/heartrate.cpp Connect signals + + After service scan is done and heart rate service found, the heart rate measurement + characteristic needs to be found and enabled for the notifications (advertisements). + + \snippet heartlistener/heartrate.cpp Connecting to service + + The enableNotifications(m_heartRateCharacteristic) method is the one that + will enable advertisement from the BLE device. Every time, when new update gets from + the BLE device (in our case heart rate belt) QLowEnergyController will emit + valueChanged(QLowEnergyCharacteristicInfo) method, which will invoke + receiveMeasurement(const QLowEnergyCharacteristicInfo &) slot. + + \snippet heartlistener/heartrate.cpp Reading value + + Every BLE device has its own structure of data that is advertising. In the code above, + the approach for checking the value structure is presented. The heart rate service contains + that information in the first 8 bits of the advertised value. For instance, first bit tells + the format of the value (is it 8 or 16 bit value), fourth tells does the heart belt provide + energy spenditure information, etc. + + \snippet heartlistener/heartrate.cpp Error handling + + In case an error occurs, QLowEnergyController will emit error, which can be read with + errorString() method. An error for BLE service can occur in the process of connecting to + the service. For BLE characteristics, an error can occur when trying to subscribe for the + notifications. + + In the end, it is required to disconnect from the service. + + \snippet heartlistener/heartrate.cpp Disconnecting from service + + \image hearratemonitor.png + \image hearrateresults.png + \image hearrateresults1.png + +*/ + diff --git a/examples/bluetooth/heartlistener/heartlistener.pro b/examples/bluetooth/heartlistener/heartlistener.pro new file mode 100644 index 00000000..7856b64e --- /dev/null +++ b/examples/bluetooth/heartlistener/heartlistener.pro @@ -0,0 +1,20 @@ +TEMPLATE = app +TARGET = heartlistener + +QT += quick bluetooth + +# Input +HEADERS += deviceinfo.h \ + heartrate.h +SOURCES += deviceinfo.cpp \ + heartrate.cpp \ + main.cpp + +OTHER_FILES += assets/*.qml \ + assets/*.js + +RESOURCES += \ + resources.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/heartlistener +INSTALLS += target diff --git a/examples/bluetooth/heartlistener/heartrate.cpp b/examples/bluetooth/heartlistener/heartrate.cpp new file mode 100644 index 00000000..a1f80121 --- /dev/null +++ b/examples/bluetooth/heartlistener/heartrate.cpp @@ -0,0 +1,397 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "heartrate.h" + +#include <qbluetoothaddress.h> +#include <qbluetoothservicediscoveryagent.h> +#include <qbluetoothserviceinfo.h> +#include <qbluetoothlocaldevice.h> +#include <qlowenergyserviceinfo.h> +#include <qlowenergycharacteristicinfo.h> +#include <qbluetoothuuid.h> +#include <QTimer> + +HeartRate::HeartRate(): + m_currentDevice(QBluetoothDeviceInfo()), foundHeartRateService(false), foundHeartRateCharacteristic(false), m_HRMeasurement(0), m_max(0), m_min(0), calories(0), m_leInfo(0), timer(0) +{ + m_deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(); + m_serviceDiscoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress()); + + connect(m_deviceDiscoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)), + this, SLOT(addDevice(const QBluetoothDeviceInfo&))); + connect(m_deviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), + this, SLOT(deviceScanError(QBluetoothDeviceDiscoveryAgent::Error))); + connect(m_deviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished())); + + connect(m_serviceDiscoveryAgent, SIGNAL(serviceDiscovered(const QLowEnergyServiceInfo&)), + this, SLOT(addLowEnergyService(const QLowEnergyServiceInfo&))); + connect(m_serviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(serviceScanDone())); + connect(m_serviceDiscoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), + this, SLOT(serviceScanError(QBluetoothServiceDiscoveryAgent::Error))); +} + +HeartRate::~HeartRate() +{ + delete m_deviceDiscoveryAgent; + delete m_serviceDiscoveryAgent; + delete m_leInfo; + delete timer; + qDeleteAll(m_devices); + m_devices.clear(); +} + +void HeartRate::deviceSearch() +{ + m_devices.clear(); + m_deviceDiscoveryAgent->start(); + setMessage("Scanning for devices..."); +} + +void HeartRate::addDevice(const QBluetoothDeviceInfo &device) +{ + if (device.coreConfiguration() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { + QBluetoothLocalDevice localDevice; + QBluetoothLocalDevice::Pairing pairingStatus = localDevice.pairingStatus(device.address()); + if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == QBluetoothLocalDevice::AuthorizedPaired ) + qWarning() << "Discovered LE Device name: " << device.name() << " Address: " << device.address().toString() << " Paired"; + else + qWarning() << "Discovered LE Device name: " << device.name() << " Address: " << device.address().toString() << " not Paired"; + DeviceInfo *dev = new DeviceInfo(device); + m_devices.append(dev); + setMessage("Low Energy device found. Scanning for more..."); + } +} + +void HeartRate::scanFinished() +{ + if (m_devices.size() == 0) + setMessage("No Low Energy devices found"); + Q_EMIT nameChanged(); +} + +void HeartRate::setMessage(QString message) +{ + m_info = message; + Q_EMIT messageChanged(); +} + +QString HeartRate::message() const +{ + return m_info; +} + +QVariant HeartRate::name() +{ + return QVariant::fromValue(m_devices); +} + +void HeartRate::connectToService(const QString &address) +{ + bool deviceHere = false; + for (int i = 0; i<m_devices.size(); i++) { + if (((DeviceInfo*)m_devices.at(i))->getAddress() == address ) { + m_currentDevice.setDevice(((DeviceInfo*)m_devices.at(i))->getDevice()); + setMessage("Device selected."); + deviceHere = true; + } + } + // This in case we are running demo mode + if (!deviceHere) + startDemo(); + else { + QBluetoothDeviceInfo device = m_currentDevice.getDevice(); + //! [Connect signals] + m_serviceDiscoveryAgent->setRemoteAddress(device.address()); + m_serviceDiscoveryAgent->start(); + if (!m_leInfo) { + m_leInfo = new QLowEnergyController(); + connect(m_leInfo, SIGNAL(connected(QLowEnergyServiceInfo)), this, SLOT(serviceConnected(QLowEnergyServiceInfo))); + connect(m_leInfo, SIGNAL(disconnected(QLowEnergyServiceInfo)), this, SLOT(serviceDisconnected(QLowEnergyServiceInfo))); + connect(m_leInfo, SIGNAL(error(QLowEnergyServiceInfo)), this, SLOT(errorReceived(QLowEnergyServiceInfo))); + connect(m_leInfo, SIGNAL(error(QLowEnergyCharacteristicInfo)), this, SLOT(errorReceivedCharacteristic(QLowEnergyCharacteristicInfo))); + connect(m_leInfo, SIGNAL(valueChanged(QLowEnergyCharacteristicInfo)), this, SLOT(receiveMeasurement(QLowEnergyCharacteristicInfo))); + } + //! [Connect signals] + } +} + +void HeartRate::addLowEnergyService(const QLowEnergyServiceInfo &gatt) +{ + if (gatt.serviceUuid() == QBluetoothUuid::HeartRate) { + setMessage("Heart Rate service discovered. Waiting for service scan to be done..."); + m_heartRateService = QLowEnergyServiceInfo(gatt); + foundHeartRateService = true; + } +} + +//! [Connecting to service] +void HeartRate::serviceScanDone() +{ + //If HeartBelt is not connected (installed on the body) this message will stay. + setMessage("Connecting to service... Be patient..."); + //It is not advisable to connect to BLE device right after scanning. + if (foundHeartRateService) + QTimer::singleShot(3000, this, SLOT(startConnection())); + else + setMessage("Heart Rate Service not found. Make sure your device is paired."); +} + +void HeartRate::startConnection() +{ + // HeartRate belt that this application was using had a random device address. This is only needed + // for Linux platform. + // m_heartRateService.setRandomAddress(); + m_leInfo->connectToService(m_heartRateService); +} + +void HeartRate::serviceConnected(const QLowEnergyServiceInfo &leService) +{ + setMessage("Connected to service. Waiting for updates"); + if (leService.serviceUuid() == QBluetoothUuid::HeartRate) { + for ( int i = 0; i<leService.characteristics().size(); i++) { + if (leService.characteristics().at(i).uuid() == QBluetoothUuid::HeartRateMeasurement) { + m_start = QDateTime::currentDateTime(); + m_heartRateCharacteristic = QLowEnergyCharacteristicInfo(leService.characteristics().at(i)); + m_leInfo->enableNotifications(m_heartRateCharacteristic); + foundHeartRateCharacteristic = true; + } + } + } +} +//! [Connecting to service] + +void HeartRate::receiveMeasurement(const QLowEnergyCharacteristicInfo &characteristic) +{ + m_heartRateCharacteristic = QLowEnergyCharacteristicInfo(characteristic); + //! [Reading value] + QString val; + qint16 energy_expended = 0; + int flags = 0; + int index = 0; + + //8 bit flags + val[0] = m_heartRateCharacteristic.value().at(index++); + val[1] = m_heartRateCharacteristic.value().at(index++); + flags = val.toUInt(0, 16); + + // Each Heart Belt has its own settings and features, besides heart rate measurement + // By checking the flags we can determine whether it has energy feature. We will go through the array + // of the characters in the characteristic value. + // The following flags are used to determine what kind of value is being sent from the device. + // see https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml + quint8 heartRateValueIs16BitFlag = 0x1; //8 bit or 16 bit + quint8 energyExpendedFeatureFlag = 0x8; + + val.clear(); + val[0] = m_heartRateCharacteristic.value().at(index++); //1st 4 bit + val[1] = m_heartRateCharacteristic.value().at(index++); //2nd 4 bit + if (flags & heartRateValueIs16BitFlag) { //16 bit value + val[2] = m_heartRateCharacteristic.value().at(index++); + val[3] = m_heartRateCharacteristic.value().at(index++); + } + + m_HRMeasurement = val.toUInt(0, 16); + //! [Reading value] + m_measurements.append(m_HRMeasurement); + + if (flags & energyExpendedFeatureFlag) { + QString energy; + int counter1 = 0; + for (int i = index; i < (m_heartRateCharacteristic.value().size() - 1); i++) { + if (counter1 > 3) + break; + energy[i] = m_heartRateCharacteristic.value().at(i); + counter1 ++; + } + energy_expended = energy.toUInt(0, 16); + } + qWarning() << "Used energy: " << energy_expended; + Q_EMIT hrChanged(); +} + +int HeartRate::hR() const +{ + return m_HRMeasurement; +} + +//! [Error handling] +void HeartRate::errorReceived(const QLowEnergyServiceInfo &leService) +{ + qWarning() << "Error: " << leService.serviceUuid() << m_leInfo->errorString(); + setMessage(QStringLiteral("Error: ") + m_leInfo->errorString()); +} + +void HeartRate::errorReceivedCharacteristic(const QLowEnergyCharacteristicInfo &leCharacteristic) +{ + qWarning() << "Error: " << leCharacteristic.uuid() << m_leInfo->errorString(); + setMessage(QStringLiteral("Error: ") + m_leInfo->errorString()); +} +//! [Error handling] + +void HeartRate::disconnectService() +{ + if (foundHeartRateCharacteristic) { + m_stop = QDateTime::currentDateTime(); + //! [Disconnecting from service] + m_leInfo->disableNotifications(m_heartRateCharacteristic); + m_leInfo->disconnectFromService(); + //! [Disconnecting from service] + } + else if (m_devices.size() == 0) { + m_stop = QDateTime::currentDateTime(); + timer->stop(); + timer = 0; + } + foundHeartRateCharacteristic = false; + foundHeartRateService = false; +} + +void HeartRate::obtainResults() +{ + Q_EMIT timeChanged(); + Q_EMIT averageChanged(); + Q_EMIT caloriesChanged(); +} + +int HeartRate::time() +{ + return m_start.secsTo(m_stop); +} + +int HeartRate::maxHR() const +{ + return m_max; +} + +int HeartRate::minHR() const +{ + return m_min; +} + +float HeartRate::average() +{ + if (m_measurements.size() == 0) + return 0; + else { + m_max = 0; + m_min = 1000; + int sum = 0; + for (int i=0; i< m_measurements.size(); i++) { + sum += (int) m_measurements.value(i); + if (((int)m_measurements.value(i)) > m_max) + m_max = (int)m_measurements.value(i); + if (((int)m_measurements.value(i)) < m_min) + m_min = (int)m_measurements.value(i); + } + return sum/m_measurements.size(); + } +} + +int HeartRate::measurements(int index) +{ + if (index > m_measurements.size()) + return 0; + else + return (int)m_measurements.value(index); +} + +int HeartRate::measurementsSize() +{ + return m_measurements.size(); +} + +QString HeartRate::deviceAddress() +{ + return m_currentDevice.getDevice().address().toString(); +} + +float HeartRate::caloriesCalculation() +{ + calories = ((-55.0969 + (0.6309 * average()) + (0.1988 * 94) + (0.2017 * 24)) / 4.184) * 60 * time()/3600 ; + return calories; +} + +void HeartRate::serviceDisconnected(const QLowEnergyServiceInfo &service) +{ + setMessage("Heart Rate service disconnected"); + qWarning() << "Service disconnected: " << service.serviceUuid(); +} + +int HeartRate::numDevices() const +{ + return m_devices.size(); +} + +void HeartRate::startDemo() +{ + m_start = QDateTime::currentDateTime(); + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(receiveDemo())); + timer->start(1000); + setMessage("This is Demo mode"); +} + +void HeartRate::receiveDemo() +{ + m_HRMeasurement = 60; + m_measurements.append(m_HRMeasurement); + Q_EMIT hrChanged(); +} + +void HeartRate::serviceScanError(QBluetoothServiceDiscoveryAgent::Error error) +{ + if (error == QBluetoothServiceDiscoveryAgent::PoweredOffError) + setMessage("The Bluetooth adaptor is powered off, power it on before doing discovery."); + else if (error == QBluetoothServiceDiscoveryAgent::InputOutputError) + setMessage("Writing or reading from the device resulted in an error."); + else + setMessage("An unknown error has occurred."); +} + +void HeartRate::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error error) +{ + if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError) + setMessage("The Bluetooth adaptor is powered off, power it on before doing discovery."); + else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError) + setMessage("Writing or reading from the device resulted in an error."); + else + setMessage("An unknown error has occurred."); +} diff --git a/examples/bluetooth/heartlistener/heartrate.h b/examples/bluetooth/heartlistener/heartrate.h new file mode 100644 index 00000000..33e3181c --- /dev/null +++ b/examples/bluetooth/heartlistener/heartrate.h @@ -0,0 +1,144 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef HEARTRATE_H +#define HEARTRATE_H + +#include <QString> +#include <QObject> +#include <QList> +#include <QtCore/QDebug> +#include <QDateTime> +#include <QVector> +#include <QTimer> +#include "deviceinfo.h" +#include <qbluetoothglobal.h> +#include <qbluetoothlocaldevice.h> +#include <qbluetoothdeviceinfo.h> +#include "qlowenergyserviceinfo.h" +#include "qlowenergycontroller.h" +#include <QBluetoothServiceDiscoveryAgent> +#include <QBluetoothDeviceDiscoveryAgent> + +QT_FORWARD_DECLARE_CLASS (QLowEnergyServiceInfo) +QT_FORWARD_DECLARE_CLASS (QLowEnergyCharacteristicInfo) +QT_FORWARD_DECLARE_CLASS (QLowEnergyController) + +QT_USE_NAMESPACE +class HeartRate: public QObject +{ + Q_OBJECT + Q_PROPERTY(QVariant name READ name NOTIFY nameChanged) + Q_PROPERTY(QString message READ message NOTIFY messageChanged) + Q_PROPERTY(int hr READ hR NOTIFY hrChanged) + Q_PROPERTY(int maxHR READ maxHR NOTIFY averageChanged) + Q_PROPERTY(int minHR READ minHR NOTIFY averageChanged) + Q_PROPERTY(float average READ average NOTIFY averageChanged) + Q_PROPERTY(int time READ time NOTIFY timeChanged) + Q_PROPERTY(float calories READ caloriesCalculation NOTIFY caloriesChanged) + +public: + HeartRate(); + ~HeartRate(); + void setMessage(QString message); + QString message() const; + QVariant name(); + int hR() const; + int time(); + float average(); + int maxHR() const; + int minHR() const; + float caloriesCalculation(); + +public slots: + void deviceSearch(); + void addDevice(const QBluetoothDeviceInfo&); + void deviceScanError(QBluetoothDeviceDiscoveryAgent::Error); + void scanFinished(); + void connectToService(const QString &address); + void addLowEnergyService(const QLowEnergyServiceInfo&); + void serviceScanDone(); + void serviceScanError(QBluetoothServiceDiscoveryAgent::Error); + void serviceConnected(const QLowEnergyServiceInfo &); + void receiveMeasurement(const QLowEnergyCharacteristicInfo &); + void errorReceived(const QLowEnergyServiceInfo &); + void errorReceivedCharacteristic(const QLowEnergyCharacteristicInfo &); + void serviceDisconnected(const QLowEnergyServiceInfo &); + void disconnectService(); + void obtainResults(); + void startConnection(); + int measurements(int index); + int measurementsSize(); + QString deviceAddress(); + int numDevices() const; + void startDemo(); + void receiveDemo(); + +Q_SIGNALS: + void messageChanged(); + void nameChanged(); + void hrChanged(); + void averageChanged(); + void timeChanged(); + void caloriesChanged(); + +private: + DeviceInfo m_currentDevice; + QBluetoothServiceDiscoveryAgent *m_serviceDiscoveryAgent; + QBluetoothDeviceDiscoveryAgent *m_deviceDiscoveryAgent; + QLowEnergyCharacteristicInfo m_heartRateCharacteristic; + QList<QObject*> m_devices; + QString m_info; + QLowEnergyServiceInfo m_heartRateService; + bool foundHeartRateService; + bool foundHeartRateCharacteristic; + int m_HRMeasurement; + QVector<quint8> m_measurements; + QDateTime m_start; + QDateTime m_stop; + int m_max; + int m_min; + QVector<QDateTime> m_timestamps; + float calories; + QLowEnergyController *m_leInfo; + QTimer *timer; // for demo application +}; + +#endif // HEARTRATE_H diff --git a/examples/bluetooth/heartlistener/main.cpp b/examples/bluetooth/heartlistener/main.cpp new file mode 100644 index 00000000..3ea3a652 --- /dev/null +++ b/examples/bluetooth/heartlistener/main.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 <QQmlContext> +#include <QGuiApplication> +#include <QQuickView> +#include "heartrate.h" + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + HeartRate heartRate; + QQuickView *view = new QQuickView; + view->rootContext()->setContextProperty("heartRate", &heartRate); + view->setSource(QUrl("qrc:/assets/main.qml")); + view->setResizeMode(QQuickView::SizeRootObjectToView); + view->show(); + return app.exec(); + +} diff --git a/examples/bluetooth/heartlistener/resources.qrc b/examples/bluetooth/heartlistener/resources.qrc new file mode 100644 index 00000000..ac6f9c83 --- /dev/null +++ b/examples/bluetooth/heartlistener/resources.qrc @@ -0,0 +1,16 @@ +<RCC> + <qresource prefix="/"> + <file>assets/blue_heart.png</file> + <file>assets/busy_dark.png</file> + <file>assets/Button.qml</file> + <file>assets/dialog.qml</file> + <file>assets/draw.js</file> + <file>assets/home.qml</file> + <file>assets/main.qml</file> + <file>assets/monitor.qml</file> + <file>assets/Point.qml</file> + <file>assets/results.qml</file> + <file>assets/star.png</file> + <file>assets/blue_heart_small.png</file> + </qresource> +</RCC> diff --git a/examples/bluetooth/lowenergyscanner/assets/Characteristics.qml b/examples/bluetooth/lowenergyscanner/assets/Characteristics.qml new file mode 100644 index 00000000..bb308f2f --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/Characteristics.qml @@ -0,0 +1,129 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: 300 + height: 600 + + Header { + id: header + anchors.top: parent.top + headerText: "Characteristics list" + } + + Dialog { + id: info + anchors.centerIn: parent + visible: false + } + + ListView { + id: characteristicview + width: parent.width + + anchors.top: header.bottom + anchors.bottom: menu.top + model: device.characteristicList + + delegate: Rectangle { + id: characteristicbox + height:350 + width: parent.width + + Component.onCompleted: menu.menuText = "Back" + + Label { + id: characteristicName1 + textContent: modelData.characteristicName + anchors.top: parent.top + anchors.topMargin: 5 + + } + + Label { + id: characteristicUuid1 + textContent: modelData.characteristicUuid + anchors.verticalCenter: parent.verticalCenter + } + + Label { + id: characteristicValue + textContent: ("Value: " + modelData.characteristicValue) + anchors.bottom: characteristicHandle.top + horizontalAlignment: Text.AlignHCenter + anchors.topMargin: 5 + } + + Label { + id: characteristicHandle + textContent: ("Handlers: " + modelData.characteristicHandle) + anchors.bottom: characteristicPermission.top + anchors.topMargin: 5 + } + + Label { + id: characteristicPermission + textContent: modelData.characteristicPermission + anchors.bottom: parent.bottom + anchors.topMargin: 10 + } + + Rectangle { + id: bottomarea + anchors.bottom: characteristicbox.bottom + width: parent.width + height: 2 + color: "#363636" + } + + } + } + + Menu { + id: menu + anchors.bottom: parent.bottom + menuWidth: parent.width + menuText: device.update + menuHeight: (parent.height/6) + onButtonClick: {device.disconnectFromService(); pageLoader.source = "Services.qml"} + } +} diff --git a/examples/bluetooth/lowenergyscanner/assets/Dialog.qml b/examples/bluetooth/lowenergyscanner/assets/Dialog.qml new file mode 100644 index 00000000..f374d762 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/Dialog.qml @@ -0,0 +1,60 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: parent.width/2 + height: 62 + z: 50 + property string dialogText: "" + border.width: 1 + border.color: "#363636" + radius: 10 + + Text { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + elide: Text.ElideMiddle + text: dialogText + color: "#363636" + } +} diff --git a/examples/bluetooth/lowenergyscanner/assets/Header.qml b/examples/bluetooth/lowenergyscanner/assets/Header.qml new file mode 100644 index 00000000..654fda34 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/Header.qml @@ -0,0 +1,61 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: parent.width + height: 70 + border.width: 1 + border.color: "#363636" + radius: 5 + property string headerText: "" + + Text { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + text: headerText + font.bold: true + font.pixelSize: 30 + elide: Text.ElideMiddle + color: "#363636" + } +} diff --git a/examples/bluetooth/lowenergyscanner/assets/Label.qml b/examples/bluetooth/lowenergyscanner/assets/Label.qml new file mode 100644 index 00000000..7576ffb7 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/Label.qml @@ -0,0 +1,50 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Text { + property string textContent: "" + font.pixelSize: 30 + anchors.horizontalCenter: parent.horizontalCenter + color: "#363636" + elide: Text.ElideMiddle + text: textContent +} diff --git a/examples/bluetooth/lowenergyscanner/assets/Menu.qml b/examples/bluetooth/lowenergyscanner/assets/Menu.qml new file mode 100644 index 00000000..796c27be --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/Menu.qml @@ -0,0 +1,88 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + + property real menuWidth: 100 + property real menuHeight: 50 + property string menuText: "Search" + signal buttonClick() + + height: menuHeight + width: menuWidth + + Rectangle { + id: search + width: parent.width + height: parent.height + color: "#363636" + border.width: 1 + border.color: "#E3E3E3" + radius: 10 + Text { + id: searchText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + text: menuText + elide: Text.ElideMiddle + color: "#E3E3E3" + } + + MouseArea { + anchors.fill: parent + onPressed: { + search.width = search.width - 7 + search.height = search.height - 5 + } + + onReleased: { + search.width = search.width + 7 + search.height = search.height + 5 + } + + onClicked: { + buttonClick() + } + } + } +} diff --git a/examples/bluetooth/lowenergyscanner/assets/Services.qml b/examples/bluetooth/lowenergyscanner/assets/Services.qml new file mode 100644 index 00000000..31775884 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/Services.qml @@ -0,0 +1,115 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: 300 + height: 600 + + Header { + id: header + anchors.top: parent.top + headerText: "Services list" + } + + Dialog { + id: info + anchors.centerIn: parent + visible: false + } + + Component.onCompleted: { info.visible = true; info.dialogText = "Scanning for services...";} + + ListView { + id: servicesview + width: parent.width + anchors.top: header.bottom + anchors.bottom: menu.top + model: device.servicesList + + delegate: Rectangle { + id: servicebox + height:140 + width: parent.width + Component.onCompleted: info.visible = false + + MouseArea { + anchors.fill: parent + onPressed: { servicebox.height= 135; bottomarea.height = 7} + onReleased: { servicebox.height= 140; bottomarea.height = 2} + onClicked: { device.connectToService(modelData.serviceUuid); pageLoader.source = "Characteristics.qml";} + + } + + Label { + id: serviceName1 + textContent: modelData.serviceName + anchors.top: parent.top + anchors.topMargin: 5 + } + + Label { + id: serviceUuid + textContent: modelData.serviceUuid + anchors.bottom: bottomarea.top + anchors.bottomMargin: 5 + } + + Rectangle { + id: bottomarea + anchors.bottom: servicebox.bottom + width: parent.width + height: 2 + color: "#363636" + } + + } + } + + Menu { + id: menu + anchors.bottom: parent.bottom + menuWidth: parent.width + menuText: "Back" + menuHeight: (parent.height/6) + onButtonClick: pageLoader.source = "main.qml" + } +} diff --git a/examples/bluetooth/lowenergyscanner/assets/main.qml b/examples/bluetooth/lowenergyscanner/assets/main.qml new file mode 100644 index 00000000..c7c201e8 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/assets/main.qml @@ -0,0 +1,128 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: back + width: 300 + height: 600 + property bool deviceState: device.state + onDeviceStateChanged: { + if (!device.state) + info.visible = false; + } + + Header { + id: header + anchors.top: parent.top + headerText: "Start a Device Discovery" + } + + Dialog { + id: info + anchors.centerIn: parent + visible: false + } + + ListView { + id: theListView + width: parent.width + + anchors.top: header.bottom + anchors.bottom: menu.top + model: device.devicesList + + delegate: Rectangle { + id: box + height:140 + width: parent.width + Component.onCompleted: { info.visible = false; + header.headerText = "Select a device"; + } + + MouseArea { + anchors.fill: parent + onPressed: { box.height= 135; downpart.height = 7} + onReleased: { box.height= 140; downpart.height = 2} + onClicked: {device.scanServices(modelData.deviceAddress); pageLoader.source = "Services.qml"} + + } + + Label { + id: deviceName1 + textContent: modelData.deviceName + anchors.top: parent.top + anchors.topMargin: 5 + } + + Label { + id: deviceAddress1 + textContent: modelData.deviceAddress + anchors.bottom: downpart.top + anchors.bottomMargin: 5 + } + + Rectangle { + id: downpart + anchors.bottom: box.bottom + width: parent.width + height: 2 + color: "#363636" + } + + } + } + + Menu { + id: menu + anchors.bottom: parent.bottom + menuWidth: parent.width + menuHeight: (parent.height/6) + menuText: device.update + onButtonClick: { device.startDeviceDiscovery(); info.dialogText = "Searching..."; info.visible = true;} + } + + Loader { + id: pageLoader + anchors.fill: parent + + } +} diff --git a/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp b/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp new file mode 100644 index 00000000..18b9e282 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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 "characteristicinfo.h" +#include "qbluetoothuuid.h" +#include <QByteArray> + +CharacteristicInfo::CharacteristicInfo(): + m_characteristic(QLowEnergyCharacteristicInfo()) +{ +} + +CharacteristicInfo::CharacteristicInfo(const QLowEnergyCharacteristicInfo &characteristic): + m_characteristic(characteristic) +{ + emit characteristicChanged(); +} + +void CharacteristicInfo::setCharacteristic(const QLowEnergyCharacteristicInfo &characteristic) +{ + m_characteristic = QLowEnergyCharacteristicInfo(characteristic); + emit characteristicChanged(); +} + +QString CharacteristicInfo::getName() const +{ + return m_characteristic.name(); +} + +QString CharacteristicInfo::getUuid() const +{ + return m_characteristic.uuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); +} + +QString CharacteristicInfo::getValue() const +{ + // All characteristics values are in hexadecimal format. + // Show human string first and hex value below + QByteArray a = m_characteristic.value(); + QString result; + result += QByteArray::fromHex(a) + QLatin1Char('\n'); + result += a; + return result; +} + +QString CharacteristicInfo::getHandle() const +{ + return m_characteristic.handle(); +} + +QString CharacteristicInfo::getPermission() const +{ + QString properties = "Properties:"; + int permission = m_characteristic.permissions(); + if (permission & QLowEnergyCharacteristicInfo::Read) + properties = properties + QStringLiteral(" Read"); + if (permission & QLowEnergyCharacteristicInfo::Write) + properties = properties + QStringLiteral(" Write"); + if (permission & QLowEnergyCharacteristicInfo::Notify) + properties = properties + QStringLiteral(" Notify"); + if (permission & QLowEnergyCharacteristicInfo::Indicate) + properties = properties + QStringLiteral(" Indicate"); + if (permission & QLowEnergyCharacteristicInfo::ExtendedProperty) + properties = properties + QStringLiteral(" ExtendedProperty"); + return properties; +} + +QLowEnergyCharacteristicInfo CharacteristicInfo::getCharacteristic() const +{ + return m_characteristic; +} diff --git a/examples/bluetooth/lowenergyscanner/characteristicinfo.h b/examples/bluetooth/lowenergyscanner/characteristicinfo.h new file mode 100644 index 00000000..7f746960 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/characteristicinfo.h @@ -0,0 +1,74 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef CHARACTERISTICINFO_H +#define CHARACTERISTICINFO_H +#include <QObject> +#include <QString> +#include <qlowenergycharacteristicinfo.h> + +class CharacteristicInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString characteristicName READ getName NOTIFY characteristicChanged) + Q_PROPERTY(QString characteristicUuid READ getUuid NOTIFY characteristicChanged) + Q_PROPERTY(QString characteristicValue READ getValue NOTIFY characteristicChanged) + Q_PROPERTY(QString characteristicHandle READ getHandle NOTIFY characteristicChanged) + Q_PROPERTY(QString characteristicPermission READ getPermission NOTIFY characteristicChanged) + +public: + CharacteristicInfo(); + CharacteristicInfo(const QLowEnergyCharacteristicInfo &characteristic); + void setCharacteristic(const QLowEnergyCharacteristicInfo &characteristic); + QString getName() const; + QString getUuid() const; + QString getValue() const; + QString getHandle() const; + QString getPermission() const; + QLowEnergyCharacteristicInfo getCharacteristic() const; + +Q_SIGNALS: + void characteristicChanged(); + +private: + QLowEnergyCharacteristicInfo m_characteristic; +}; + +#endif // CHARACTERISTICINFO_H diff --git a/examples/bluetooth/lowenergyscanner/device.cpp b/examples/bluetooth/lowenergyscanner/device.cpp new file mode 100644 index 00000000..44cd3512 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/device.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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 "device.h" +#include <qbluetoothaddress.h> +#include <qbluetoothdevicediscoveryagent.h> +#include <qbluetoothlocaldevice.h> +#include <qbluetoothdeviceinfo.h> +#include <qbluetoothservicediscoveryagent.h> +#include <qbluetoothserviceinfo.h> +#include <qlowenergycharacteristicinfo.h> +#include <qlowenergycontroller.h> +#include <QDebug> +#include <QList> + +Device::Device(): + connected(false), info(0), m_deviceScanState(false) +{ + discoveryAgent = new QBluetoothDeviceDiscoveryAgent(); + connect(discoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)), + this, SLOT(addDevice(const QBluetoothDeviceInfo&))); + connect(discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), + this, SLOT(deviceScanError(QBluetoothDeviceDiscoveryAgent::Error))); + connect(discoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished())); + serviceDiscoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress()); + + //Connecting signals and slots for service discovery + connect(serviceDiscoveryAgent, SIGNAL(serviceDiscovered(const QLowEnergyServiceInfo&)), + this, SLOT(addLowEnergyService(const QLowEnergyServiceInfo&))); + connect(serviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(serviceScanDone())); + connect(serviceDiscoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), + this, SLOT(serviceScanError(QBluetoothServiceDiscoveryAgent::Error))); + + setUpdate("Search"); +} + +Device::~Device() +{ + delete discoveryAgent; + delete serviceDiscoveryAgent; + delete info; + qDeleteAll(devices); + qDeleteAll(m_services); + qDeleteAll(m_characteristics); + devices.clear(); + m_services.clear(); + m_characteristics.clear(); +} + +void Device::startDeviceDiscovery() +{ + devices.clear(); + setUpdate("Scanning for devices ..."); + discoveryAgent->start(); + m_deviceScanState = true; + Q_EMIT stateChanged(); +} + +void Device::addDevice(const QBluetoothDeviceInfo &info) +{ + if (info.coreConfiguration() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { + DeviceInfo *d = new DeviceInfo(info); + devices.append(d); + setUpdate("Last device added: " + d->getName()); + } +} + +void Device::scanFinished() +{ + Q_EMIT devicesDone(); + m_deviceScanState = false; + Q_EMIT stateChanged(); + if (devices.isEmpty()) + setUpdate("No Low Energy devices found..."); + else + setUpdate("Done! Scan Again!"); +} + +QVariant Device::getDevices() +{ + return QVariant::fromValue(devices); +} + +QVariant Device::getServices() +{ + return QVariant::fromValue(m_services); +} + +QVariant Device::getCharacteristics() +{ + return QVariant::fromValue(m_characteristics); +} + +QString Device::getUpdate() +{ + return m_message; +} + +void Device::scanServices(QString address) +{ + // We need the current device for service discovery. + for (int i = 0; i < devices.size(); i++) { + if (((DeviceInfo*)devices.at(i))->getAddress() == address ) { + currentDevice.setDevice(((DeviceInfo*)devices.at(i))->getDevice()); + } + } + + m_services.clear(); + QBluetoothDeviceInfo dev = currentDevice.getDevice(); + serviceDiscoveryAgent->setRemoteAddress(dev.address()); + serviceDiscoveryAgent->start(); + setUpdate("Scanning for services..."); + + if (!info) { + // Connecting signals and slots for connecting to LE services. + info = new QLowEnergyController(); + connect(info, SIGNAL(connected(QLowEnergyServiceInfo)), this, SLOT(serviceConnected(QLowEnergyServiceInfo))); + connect(info, SIGNAL(error(QLowEnergyServiceInfo)), this, SLOT(errorReceived(QLowEnergyServiceInfo))); + connect(info, SIGNAL(disconnected(QLowEnergyServiceInfo)), this, SLOT(serviceDisconnected(QLowEnergyServiceInfo))); + } +} + +void Device::addLowEnergyService(const QLowEnergyServiceInfo &service) +{ + ServiceInfo *serv = new ServiceInfo(service); + m_services.append(serv); +} + +void Device::serviceScanDone() +{ + Q_EMIT servicesDone(); + setUpdate("Service scan done!"); +} + +void Device::connectToService(const QString &uuid) +{ + QString serviceUuid = uuid; + serviceUuid = serviceUuid.remove(QLatin1Char('{')).remove(QLatin1Char('}')); + QBluetoothUuid u(serviceUuid); + QLowEnergyServiceInfo a; + for (int i = 0; i < m_services.size(); i++) { + ServiceInfo *service = (ServiceInfo*)m_services.at(i); + a = QLowEnergyServiceInfo(service->getLeService()); + if (a.serviceUuid() == u) + info->connectToService(a); + } +} + +void Device::serviceConnected(const QLowEnergyServiceInfo &service) +{ + m_characteristics.clear(); + setUpdate("Service connected!"); + connected = true; + for (int i = 0; i < service.characteristics().size(); i++) { + CharacteristicInfo *chars = new CharacteristicInfo((QLowEnergyCharacteristicInfo)service.characteristics().at(i)); + m_characteristics.append(chars); + } + emit characteristicsDone(); +} + +void Device::errorReceived(const QLowEnergyServiceInfo &service) +{ + qWarning() << "Error: " << info->errorString() << service.serviceUuid(); + setUpdate(info->errorString()); +} + +void Device::setUpdate(QString message) +{ + m_message = message; + emit updateChanged(); +} + +void Device::disconnectFromService() +{ + if (connected) + info->disconnectFromService(); +} + +void Device::serviceDisconnected(const QLowEnergyServiceInfo &service) +{ + setUpdate("Service Disconnected " + service.serviceName()); +} + +void Device::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error error) +{ + if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError) + setUpdate("The Bluetooth adaptor is powered off, power it on before doing discovery."); + else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError) + setUpdate("Writing or reading from the device resulted in an error."); + else + setUpdate("An unknown error has occurred."); +} + +void Device::serviceScanError(QBluetoothServiceDiscoveryAgent::Error error) +{ + if (error == QBluetoothServiceDiscoveryAgent::PoweredOffError) + setUpdate("The Bluetooth adaptor is powered off, power it on before doing discovery."); + else if (error == QBluetoothServiceDiscoveryAgent::InputOutputError) + setUpdate("Writing or reading from the device resulted in an error."); + else + setUpdate("An unknown error has occurred."); +} + +bool Device::state() +{ + return m_deviceScanState; +} diff --git a/examples/bluetooth/lowenergyscanner/device.h b/examples/bluetooth/lowenergyscanner/device.h new file mode 100644 index 00000000..307b0fb9 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/device.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the demonstration applications 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef DEVICE_H +#define DEVICE_H + +#include <qbluetoothglobal.h> +#include <qbluetoothlocaldevice.h> +#include <QObject> +#include <QVariant> +#include <QList> +#include <QBluetoothServiceDiscoveryAgent> +#include <QBluetoothDeviceDiscoveryAgent> +#include "deviceinfo.h" +#include "qlowenergyserviceinfo.h" +#include "serviceinfo.h" +#include "characteristicinfo.h" + +QT_FORWARD_DECLARE_CLASS (QBluetoothDeviceInfo) +QT_FORWARD_DECLARE_CLASS (QLowEnergyServiceInfo) +QT_FORWARD_DECLARE_CLASS (QLowEnergyCharacteristicInfo) +QT_FORWARD_DECLARE_CLASS (QLowEnergyController) +QT_FORWARD_DECLARE_CLASS (QBluetoothServiceInfo) + +class Device: public QObject +{ + Q_OBJECT + Q_PROPERTY(QVariant devicesList READ getDevices NOTIFY devicesDone) + Q_PROPERTY(QVariant servicesList READ getServices NOTIFY servicesDone) + Q_PROPERTY(QVariant characteristicList READ getCharacteristics NOTIFY characteristicsDone) + Q_PROPERTY(QString update READ getUpdate NOTIFY updateChanged) + Q_PROPERTY(bool state READ state NOTIFY stateChanged) +public: + Device(); + ~Device(); + QVariant getDevices(); + QVariant getServices(); + QVariant getCharacteristics(); + QString getUpdate(); + bool state(); + +public slots: + void addDevice(const QBluetoothDeviceInfo&); + void startDeviceDiscovery(); + void scanFinished(); + void deviceScanError(QBluetoothDeviceDiscoveryAgent::Error); + void scanServices(QString address); + void addLowEnergyService(const QLowEnergyServiceInfo&); + void serviceScanDone(); + void serviceConnected(const QLowEnergyServiceInfo &service); + void connectToService(const QString &uuid); + void errorReceived(const QLowEnergyServiceInfo &service); + void disconnectFromService(); + void serviceDisconnected(const QLowEnergyServiceInfo &service); + void serviceScanError(QBluetoothServiceDiscoveryAgent::Error); + +Q_SIGNALS: + void devicesDone(); + void servicesDone(); + void characteristicsDone(); + void updateChanged(); + void stateChanged(); + +private: + void setUpdate(QString message); + QBluetoothDeviceDiscoveryAgent *discoveryAgent; + QBluetoothServiceDiscoveryAgent *serviceDiscoveryAgent; + DeviceInfo currentDevice; + QList<QObject*> devices; + QList<QObject*> m_services; + QList<QObject*> m_characteristics; + QString m_message; + bool connected; + QLowEnergyController *info; + bool m_deviceScanState; +}; + +#endif // DEVICE_H diff --git a/examples/bluetooth/lowenergyscanner/deviceinfo.cpp b/examples/bluetooth/lowenergyscanner/deviceinfo.cpp new file mode 100644 index 00000000..552f5ec3 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/deviceinfo.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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 "deviceinfo.h" + +DeviceInfo::DeviceInfo() +{ + device = QBluetoothDeviceInfo(); +} + +DeviceInfo::DeviceInfo(const QBluetoothDeviceInfo &d) +{ + device = QBluetoothDeviceInfo(d); + Q_EMIT deviceChanged(); +} + +QString DeviceInfo::getAddress() const +{ + return device.address().toString(); +} + +QString DeviceInfo::getName() const +{ + return device.name(); +} + +QBluetoothDeviceInfo DeviceInfo::getDevice() +{ + return device; +} + +void DeviceInfo::setDevice(const QBluetoothDeviceInfo &dev) +{ + device = QBluetoothDeviceInfo(dev); +} diff --git a/examples/bluetooth/lowenergyscanner/deviceinfo.h b/examples/bluetooth/lowenergyscanner/deviceinfo.h new file mode 100644 index 00000000..383ecfac --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/deviceinfo.h @@ -0,0 +1,70 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef DEVICEINFO_H +#define DEVICEINFO_H + +#include <QObject> +#include <qbluetoothdeviceinfo.h> +#include <qbluetoothaddress.h> +#include <QList> +#include "deviceinfo.h" + +class DeviceInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString deviceName READ getName NOTIFY deviceChanged) + Q_PROPERTY(QString deviceAddress READ getAddress NOTIFY deviceChanged) +public: + DeviceInfo(); + DeviceInfo(const QBluetoothDeviceInfo &d); + QString getAddress() const; + QString getName() const; + QBluetoothDeviceInfo getDevice(); + void setDevice(const QBluetoothDeviceInfo &dev); + +Q_SIGNALS: + void deviceChanged(); + +private: + QBluetoothDeviceInfo device; +}; + +#endif // DEVICEINFO_H diff --git a/examples/bluetooth/lowenergyscanner/doc/images/lowenergyscanner-example.png b/examples/bluetooth/lowenergyscanner/doc/images/lowenergyscanner-example.png Binary files differnew file mode 100644 index 00000000..bdc3a22e --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/doc/images/lowenergyscanner-example.png diff --git a/examples/bluetooth/lowenergyscanner/doc/images/lowenergyscanner-example1.png b/examples/bluetooth/lowenergyscanner/doc/images/lowenergyscanner-example1.png Binary files differnew file mode 100644 index 00000000..4854abf7 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/doc/images/lowenergyscanner-example1.png diff --git a/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc b/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc new file mode 100644 index 00000000..fe7e007f --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 lowenergyscanner + \title Bluetooth Low Energy Scanner Example + + The Bluetooth Low Energy Scanner Example shows how to develop Bluetooth + Low Energy applications using the Qt Bluetooth API. The application covers + scanning for Low Energy devices, scanning their services and reading + the service characteristics. + + \image lowenergyscanner-example.png + \image lowenergyscanner-example1.png + +*/ diff --git a/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro b/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro new file mode 100644 index 00000000..f3378b4c --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro @@ -0,0 +1,25 @@ +TARGET = lowenergyscanner +INCLUDEPATH += . + +QT += quick bluetooth + +# Input +SOURCES += main.cpp \ + device.cpp \ + deviceinfo.cpp \ + serviceinfo.cpp \ + characteristicinfo.cpp + +OTHER_FILES += assets/*.qml + +HEADERS += \ + device.h \ + deviceinfo.h \ + serviceinfo.h \ + characteristicinfo.h + +RESOURCES += \ + resources.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/lowenergyscanner +INSTALLS += target diff --git a/examples/bluetooth/lowenergyscanner/main.cpp b/examples/bluetooth/lowenergyscanner/main.cpp new file mode 100644 index 00000000..1a8487c8 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/main.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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 <QQmlContext> +#include <QGuiApplication> +#include <QQuickView> +#include "device.h" + + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + + Device d; + QQuickView *view = new QQuickView; + view->rootContext()->setContextProperty("device", &d); + + view->setSource(QUrl("qrc:/assets/main.qml")); + view->setResizeMode(QQuickView::SizeRootObjectToView); + view->show(); + return app.exec(); +} diff --git a/examples/bluetooth/lowenergyscanner/resources.qrc b/examples/bluetooth/lowenergyscanner/resources.qrc new file mode 100644 index 00000000..49a518e8 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/resources.qrc @@ -0,0 +1,11 @@ +<RCC> + <qresource prefix="/"> + <file>assets/Characteristics.qml</file> + <file>assets/main.qml</file> + <file>assets/Menu.qml</file> + <file>assets/Services.qml</file> + <file>assets/Header.qml</file> + <file>assets/Dialog.qml</file> + <file>assets/Label.qml</file> + </qresource> +</RCC> diff --git a/examples/bluetooth/lowenergyscanner/serviceinfo.cpp b/examples/bluetooth/lowenergyscanner/serviceinfo.cpp new file mode 100644 index 00000000..1028fb40 --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/serviceinfo.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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 "serviceinfo.h" + +ServiceInfo::ServiceInfo(): + m_serviceLe(QLowEnergyServiceInfo()) +{ + +} + +ServiceInfo::ServiceInfo(const QLowEnergyServiceInfo &service): + m_serviceLe(service) +{ + +} + +QLowEnergyServiceInfo ServiceInfo::getLeService() const +{ + return m_serviceLe; +} + +QString ServiceInfo::getName() const +{ + return m_serviceLe.serviceName(); +} + +QString ServiceInfo::getUuid() const +{ + return m_serviceLe.serviceUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); +} diff --git a/examples/bluetooth/lowenergyscanner/serviceinfo.h b/examples/bluetooth/lowenergyscanner/serviceinfo.h new file mode 100644 index 00000000..56140e4c --- /dev/null +++ b/examples/bluetooth/lowenergyscanner/serviceinfo.h @@ -0,0 +1,66 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef SERVICEINFO_H +#define SERVICEINFO_H +#include <QObject> +#include "qlowenergyserviceinfo.h" +#include "qbluetoothuuid.h" + +class ServiceInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString serviceName READ getName NOTIFY serviceChanged) + Q_PROPERTY(QString serviceUuid READ getUuid NOTIFY serviceChanged) +public: + ServiceInfo(); + ServiceInfo(const QLowEnergyServiceInfo &service); + QLowEnergyServiceInfo getLeService() const; + QString getUuid() const; + QString getName() const; + +Q_SIGNALS: + void serviceChanged(); + +private: + QLowEnergyServiceInfo m_serviceLe; +}; + +#endif // SERVICEINFO_H diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index 44d2444c..bb4e6266 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -2,6 +2,7 @@ TARGET = QtBluetooth QT = core QT_PRIVATE = concurrent + QMAKE_DOCS = $$PWD/doc/qtbluetooth.qdocconf OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator @@ -22,7 +23,11 @@ PUBLIC_HEADERS += \ qbluetoothlocaldevice.h \ qbluetoothtransfermanager.h \ qbluetoothtransferrequest.h \ - qbluetoothtransferreply.h + qlowenergyserviceinfo.h \ + qlowenergycharacteristicinfo.h \ + qlowenergydescriptorinfo.h \ + qbluetoothtransferreply.h \ + qlowenergycontroller.h PRIVATE_HEADERS += \ qbluetoothaddress_p.h\ @@ -36,7 +41,12 @@ PRIVATE_HEADERS += \ qbluetoothtransferreply_p.h \ qbluetoothtransferrequest_p.h \ qprivatelinearbuffer_p.h \ - qbluetoothlocaldevice_p.h + qbluetoothlocaldevice_p.h \ + qlowenergyserviceinfo_p.h \ + qlowenergycharacteristicinfo_p.h \ + qlowenergyprocess_p.h \ + qlowenergydescriptorinfo_p.h \ + qlowenergycontroller_p.h SOURCES += \ qbluetoothaddress.cpp\ @@ -52,7 +62,11 @@ SOURCES += \ qbluetooth.cpp \ qbluetoothtransfermanager.cpp \ qbluetoothtransferrequest.cpp \ - qbluetoothtransferreply.cpp + qbluetoothtransferreply.cpp \ + qlowenergyserviceinfo.cpp \ + qlowenergycharacteristicinfo.cpp \ + qlowenergydescriptorinfo.cpp \ + qlowenergycontroller.cpp config_bluez:qtHaveModule(dbus) { QT *= dbus @@ -70,16 +84,20 @@ config_bluez:qtHaveModule(dbus) { qbluetoothsocket_bluez.cpp \ qbluetoothserver_bluez.cpp \ qbluetoothlocaldevice_bluez.cpp \ - qbluetoothtransferreply_bluez.cpp + qbluetoothtransferreply_bluez.cpp \ + qlowenergyprocess_bluez.cpp \ + qlowenergyserviceinfo_bluez.cpp \ + qlowenergycharacteristicinfo_bluez.cpp \ + qlowenergycontroller_bluez.cpp } else:CONFIG(blackberry) { DEFINES += QT_QNX_BLUETOOTH include(qnx/qnx.pri) + LIBS += -lbtapi config_btapi10_2_1 { DEFINES += QT_QNX_BT_BLUETOOTH - LIBS += -lbtapi } PRIVATE_HEADERS += \ @@ -92,7 +110,10 @@ config_bluez:qtHaveModule(dbus) { qbluetoothservicediscoveryagent_qnx.cpp \ qbluetoothsocket_qnx.cpp \ qbluetoothserver_qnx.cpp \ - qbluetoothtransferreply_qnx.cpp + qbluetoothtransferreply_qnx.cpp \ + qlowenergycharacteristicinfo_qnx.cpp \ + qlowenergyserviceinfo_qnx.cpp \ + qlowenergyprocess_qnx.cpp } else:android:!android-no-sdk { include(android/android.pri) @@ -113,7 +134,11 @@ config_bluez:qtHaveModule(dbus) { qbluetoothserviceinfo_android.cpp \ qbluetoothservicediscoveryagent_android.cpp \ qbluetoothsocket_android.cpp \ - qbluetoothserver_android.cpp + qbluetoothserver_android.cpp \ + qlowenergyserviceinfo_p.cpp \ + qlowenergycharacteristicinfo_p.cpp \ + qlowenergyprocess_p.cpp \ + qlowenergycontroller_p.cpp } else { message("Unsupported bluetooth platform, will not build a working QBluetooth library") @@ -124,12 +149,13 @@ config_bluez:qtHaveModule(dbus) { qbluetoothserviceinfo_p.cpp \ qbluetoothservicediscoveryagent_p.cpp \ qbluetoothsocket_p.cpp \ - qbluetoothserver_p.cpp - + qbluetoothserver_p.cpp \ + qlowenergyserviceinfo_p.cpp \ + qlowenergycharacteristicinfo_p.cpp \ + qlowenergyprocess_p.cpp \ + qlowenergycontroller_p.cpp } OTHER_FILES += HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS - - diff --git a/src/bluetooth/bluez/bluez.pri b/src/bluetooth/bluez/bluez.pri index 5a679091..a4b597a0 100644 --- a/src/bluetooth/bluez/bluez.pri +++ b/src/bluetooth/bluez/bluez.pri @@ -20,7 +20,8 @@ HEADERS += bluez/manager_p.h \ bluez/obex_client_p.h \ bluez/obex_agent_p.h \ bluez/obex_transfer_p.h \ - bluez/obex_manager_p.h + bluez/obex_manager_p.h \ + bluez/characteristic_p.h SOURCES += bluez/manager.cpp \ @@ -32,4 +33,5 @@ SOURCES += bluez/manager.cpp \ bluez/obex_client.cpp \ bluez/obex_agent.cpp \ bluez/obex_transfer.cpp \ - bluez/obex_manager.cpp + bluez/obex_manager.cpp \ + bluez/characteristic.cpp diff --git a/src/bluetooth/bluez/characteristic.cpp b/src/bluetooth/bluez/characteristic.cpp new file mode 100644 index 00000000..ed4b8485 --- /dev/null +++ b/src/bluetooth/bluez/characteristic.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "characteristic_p.h" + +/* + * Implementation of interface class OrgBluezCharacteristicInterface + */ + +OrgBluezCharacteristicInterface::OrgBluezCharacteristicInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgBluezCharacteristicInterface::~OrgBluezCharacteristicInterface() +{ +} diff --git a/src/bluetooth/bluez/characteristic_p.h b/src/bluetooth/bluez/characteristic_p.h new file mode 100644 index 00000000..ef510ab2 --- /dev/null +++ b/src/bluetooth/bluez/characteristic_p.h @@ -0,0 +1,111 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CHARACTERISTIC_P_H +#define CHARACTERISTIC_P_H + +#endif // CHARACTERISTIC_P_H + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.bluez.Device + */ +class OrgBluezCharacteristicInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.bluez.Characteristic"; } + +public: + OrgBluezCharacteristicInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + ~OrgBluezCharacteristicInterface(); + +public Q_SLOTS: + inline QDBusPendingReply<QVariantMap> GetProperties() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + } + + inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1) + { + QList<QVariant> argumentList; + argumentList << qVariantFromValue(in0) << qVariantFromValue(in1); + return asyncCallWithArgumentList(QLatin1String("SetProperty"), argumentList); + } + inline QDBusPendingReply<QList<QDBusObjectPath> > DiscoverCharacteristics() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("DiscoverCharacteristics"), argumentList); + } + + inline QDBusPendingReply<> RegisterCharacteristicsWatcher(const QDBusObjectPath &in0) + { + QList<QVariant> argumentList; + argumentList << qVariantFromValue(in0); + return asyncCallWithArgumentList(QLatin1String("RegisterCharacteristicsWatcher"), argumentList); + } + + inline QDBusPendingReply<> UnregisterCharacteristicsWatcher(const QDBusObjectPath &in0) + { + QList<QVariant> argumentList; + argumentList << qVariantFromValue(in0); + return asyncCallWithArgumentList(QLatin1String("UnregisterCharacteristicsWatcher"), argumentList); + } + +Q_SIGNALS: + void PropertyChanged(const QString &in0, const QDBusVariant &in1); +}; + +namespace org { + namespace bluez { + typedef ::OrgBluezCharacteristicInterface Characteristic; + } +} diff --git a/src/bluetooth/doc/src/bluetooth-index.qdoc b/src/bluetooth/doc/src/bluetooth-index.qdoc index cde64891..e9575db1 100644 --- a/src/bluetooth/doc/src/bluetooth-index.qdoc +++ b/src/bluetooth/doc/src/bluetooth-index.qdoc @@ -70,6 +70,8 @@ import statement in your \c .qml file: \list \li \l {scanner}{QML Bluetooth Scanner} \li \l {picturetransfer}{QML Bluetooth Picture Push} + \li \l {lowenergyscanner}{Bluetooth Low Energy Scanner} + \li \l {heartlistener}{Heart Listener} \endlist \li C++ \list diff --git a/src/bluetooth/doc/src/bluetooth-overview.qdoc b/src/bluetooth/doc/src/bluetooth-overview.qdoc index 2afd2bd8..bc8a9543 100644 --- a/src/bluetooth/doc/src/bluetooth-overview.qdoc +++ b/src/bluetooth/doc/src/bluetooth-overview.qdoc @@ -29,7 +29,8 @@ \ingroup technology-apis \title Qt Bluetooth Overview \page qtbluetooth-overview.html -\brief The Qt Bluetooth API enables connectivity with other Bluetooth enabled devices. +\brief The Qt Bluetooth API enables connectivity with other regular Bluetooth + and Bluetooth Low Energy enabled devices. \tableofcontents @@ -41,6 +42,9 @@ \li Push files to remote devices using the OBEX Object Push Profile (OPP) \li Connect to remote devices through a RFCOMM channel using the Serial Port Profile (SPP). \li Create a RFCOMM server that allows incoming connections using SPP. + \li Retrieve specification about Bluetooth Low Energy device. + \li Connect to Bluetooth Low Energy device. + \li Receive advertisement from Bluetooth Low Energy device. \endlist Note that the Object Push Profile is not supported on Android. @@ -103,4 +107,103 @@ \l QBluetoothSocket classes. A good example to start with SPP is the \l{btchat}{Bluetooth Chat} example. + \section1 Bluetooth Low Energy + + Bluetooth Low Energy (in later text BLE), also known as Bluetooth Smart is a wireless computer + network technology, which was officially introduced in 2011. It works at the same, + 2,4HGz frequency, as ”classic” Bluetooth. The main difference is, as stated by its technology name, + low energy consumption. It provides an opportunity for BLE devices to operate for months, + even years, on coin-cell batteries. This technology was introduced with Bluetooth v 4.0 + and devices which support this technology are called Bluetooth Smart Ready Devices. + The key features of technology are: + \list + \li Ultra-low peak, average and idle mode power consumption + \li Ability to run for years on standard, coin-cell batteries + \li Low cost + \li Multi-vendor interoperability + \li Enhanced range + \endlist + + BLE uses a client-server architecture. The server (BLE device) offers services (temperature, + heart rate or any other measurements) and advertises them. The client (PC, smartphone + or any other Bluetooth Smart Ready device) connects to the server and reads the values + advertised by the server. The BLE API is based on GATT (Generic Attribute Profile) concepts. + GATT commands are initiated by the client, as mentioned above, and the server is receiving + GATT commands and sends replies. + + These GATT commands initiate the services, which consist of characteristics. A characteristic + is data that is being transferred. Each characteristic has descriptors, which give additional + information about the characteristic. Services, characteristics and descriptors are recognized + by their 128bits UUIDs. + + To be able to get and read characteristics, it is required to connect to the LE device service. + + \code + QObject::connect(m_serviceDiscoveryAgent, SIGNAL(serviceDiscovered(const QLowEnergyServiceInfo&)), + this, SLOT(addLowEnergyService(const QLowEnergyServiceInfo&))); + QObject::connect(m_serviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(serviceScanDone())); + m_serviceDiscoveryAgent->setRemoteAddress(device.address()); + m_serviceDiscoveryAgent->start(); + lowEnergyController = new QLowEnergyController(); + QObject::connect(lowEnergyController, SIGNAL(connected(QLowEnergyServiceInfo)), + this, SLOT(serviceConnected(QLowEnergyServiceInfo))); + QObject::connect(lowEnergyController, SIGNAL(error(QLowEnergyServiceInfo)), + this, SLOT(errorReceived(QLowEnergyServiceInfo))); + QObject::connect(lowEnergyController, SIGNAL(valueChanged(QLowEnergyCharacteristicInfo)), + this, SLOT(receiveMeasurement(QLowEnergyCharacteristicInfo))); + QObject::connect(lowEnergyController, SIGNAL(disconnected(QLowEnergyServiceInfo)), + this, SLOT(serviceDisconnected(QLowEnergyServiceInfo))); + + \endcode + + We start a service discovery with a \l QBluetoothServiceDiscoveryAgent class and connect its + signal \l serviceDiscovered(QLowEnergyServiceInfo) to our slot + \l addLowEnergyService(QLowEnergyServiceInfo). This way, it is possible to store all LE services + or connect to the desired one. \l QLowEnergyController is used for connecting to service, + receiving emitted errors from the service and disconnecting from the service. + + Even though it is possible to connect to an LE service before the service scan is done, + it is advisable to do it after the service scan is done. + + \code + void serviceScanDone() + { + lowEnergyController->connectToService(wantedLowEnergyService); + } + \endcode + + Here, the \c wantedLowEnergyService can be one service or you can pick more or all services + to connect. Some LE devices, become available one or two seconds after service scan. + + \code + void serviceConnected(const QLowEnergyServiceInfo &leService) + { + QList<QLowEnergyCharacteristicInfo> lowEnergyCharacteristics = leService.getCharacteristics(); + for (int i = 0; i<lowEnergyCharacteristics.size(); i++) { + QLowEnergyCharacteristicInfo wantedCharacteristic = + QLowEnergyCharacteristicInfo(lowEnergyCharacteristics.at(i)); + lowEnergyController->enableNotifications(wantedCharacteristic); + } + } + \endcode + + In the code example above all characteristics will be enabled for the notifications, but not + all of them have that option as explained in \l QLowEnergyController documentation. It is possible + to select only one characteristic, for instance \l QBluetoothUuid::HeartRateMeasurement. + + Finally, to receive updates, the receiveMeasurement(QLowEnergyCharacteristicInfo) slot was defined. + + \code + void HeartRate::receiveMeasurement(const QLowEnergyCharacteristicInfo &characteristic) + { + wantedCharacteristic = QLowEnergyCharacteristicInfo(characteristic); + wantedCharacteristic.value(); + } + \endcode + + The returned value is the hexadecimal value. The procedure of reading and converting hexadecimal + value properly depends on the BLE devices that is sending updates since every device has a different + value structure. + + */ diff --git a/src/bluetooth/doc/src/examples.qdoc b/src/bluetooth/doc/src/examples.qdoc index d6b73ae8..08759874 100644 --- a/src/bluetooth/doc/src/examples.qdoc +++ b/src/bluetooth/doc/src/examples.qdoc @@ -71,6 +71,13 @@ \row \li \l{picturetransfer}{QML Picture Push Example} \li A QML application that transfers pictures between Bluetooth devices. + \row + \li \l{lowenergyscanner}{QML Bluetooth Low Energy Scanner} + \li Scan for Bluetooth Low Energy devices, services and characteristics. + \row + \li \l{heartlistener}{QML Bluetooth Low Energy Heart Listener} + \li Connect to the Bluetooth Low Energy heart belt and receive + measurements. \endtable */ diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index 83b83fbd..f866b477 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -183,6 +183,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres } device.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete); device.setCached(dict.value(QLatin1String("Cached")).toBool()); + + /* + * Bluez v4.1 does not have extra bit which gives information if device is Bluetooth + * Low Energy device and the way to discover it is with Class property of the Bluetooth device. + * Low Energy devices do not have property Class. + */ + if (btClass == 0) + device.setCoreConfiguration(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + else + device.setCoreConfiguration(QBluetoothDeviceInfo::BaseRateCoreConfiguration); for(int i = 0; i < discoveredDevices.size(); i++){ if(discoveredDevices[i].address() == device.address()) { if(discoveredDevices[i] == device) { diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp index 390faf50..42b6ceff 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp @@ -168,11 +168,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) int cod = 0; int dev_type = 0; int rssi = 0; - + bool hasGatt = false; pps_decoder_get_bool(&ppsDecoder, "paired", &paired); pps_decoder_get_int(&ppsDecoder, "cod", &cod); pps_decoder_get_int(&ppsDecoder, "dev_type", &dev_type); pps_decoder_get_int(&ppsDecoder, "rssi", &rssi); + pps_decoder_push(&ppsDecoder, "gatt_available_services"); + const char *next_service = 0; + + for (int service_count=0; pps_decoder_get_string(&ppsDecoder, 0, &next_service ) == PPS_DECODER_OK; service_count++) { + hasGatt = true; + //qBluetoothDebug() << next_service; + } pps_decoder_cleanup(&ppsDecoder); QBluetoothDeviceInfo deviceInfo(deviceAddr, deviceName, cod); @@ -195,6 +202,20 @@ void QBluetoothDeviceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) m_finishedTimer.start(7000); if (!deviceAddr.isNull()) { qCDebug(QT_BT_QNX) << "Device discovered: " << deviceName << deviceAddr.toString(); + /* Looking for device type. Only Low energy devices will be added + * BT_DEVICE_TYPE_LE_PUBLIC is 0 --->LE device + * BT_DEVICE_TYPE_LE_PRIVATE is 1 ---> LE device + * BT_DEVICE_TYPE_REGULAR is 32 + * BT_DEVICE_TYPE_UNKNOWN is 255 + */ + if (dev_type == 0 || dev_type == 1) + deviceInfo.setCoreConfiguration(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + else{ + if (hasGatt) + deviceInfo.setCoreConfiguration(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); + else + deviceInfo.setCoreConfiguration(QBluetoothDeviceInfo::BaseRateCoreConfiguration); + } discoveredDevices.append(deviceInfo); if (!updated)//We are not allowed to emit a signal with the updated version emit q_ptr->deviceDiscovered(discoveredDevices.last()); diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp index f10ec133..58d45e3b 100644 --- a/src/bluetooth/qbluetoothdeviceinfo.cpp +++ b/src/bluetooth/qbluetoothdeviceinfo.cpp @@ -247,12 +247,24 @@ QT_BEGIN_NAMESPACE \value DataUnavailable No data is available. */ +/*! + \enum QBluetoothDeviceInfo::CoreConfiguration + + This enum describes the configuration of the device. + + \value BaseRateCoreConfiguration The device is a standard Bluetooth device. + \value BaseRateAndLowEnergyConfiguration The device is a Bluetooth Smart device with support + for standard and Low Energy device. + \value LowEnergyCoreCOnfiguration The device is a Bluetooth Low Energy device. +*/ + QBluetoothDeviceInfoPrivate::QBluetoothDeviceInfoPrivate() : valid(false), cached(false), rssi(1), serviceClasses(QBluetoothDeviceInfo::NoService), majorDeviceClass(QBluetoothDeviceInfo::MiscellaneousDevice), minorDeviceClass(0), - serviceUuidsCompleteness(QBluetoothDeviceInfo::DataUnavailable) + serviceUuidsCompleteness(QBluetoothDeviceInfo::DataUnavailable), + deviceCoreConfiguration(QBluetoothDeviceInfo::BaseRateCoreConfiguration) { } @@ -359,6 +371,7 @@ QBluetoothDeviceInfo &QBluetoothDeviceInfo::operator=(const QBluetoothDeviceInfo d->serviceUuidsCompleteness = other.d_func()->serviceUuidsCompleteness; d->serviceUuids = other.d_func()->serviceUuids; d->rssi = other.d_func()->rssi; + d->deviceCoreConfiguration = other.d_func()->deviceCoreConfiguration; return *this; } @@ -370,25 +383,27 @@ bool QBluetoothDeviceInfo::operator==(const QBluetoothDeviceInfo &other) const { Q_D(const QBluetoothDeviceInfo); - if(d->cached != other.d_func()->cached) + if (d->cached != other.d_func()->cached) return false; - if(d->valid != other.d_func()->valid) + if (d->valid != other.d_func()->valid) return false; - if(d->majorDeviceClass != other.d_func()->majorDeviceClass) + if (d->majorDeviceClass != other.d_func()->majorDeviceClass) return false; - if(d->minorDeviceClass != other.d_func()->minorDeviceClass) + if (d->minorDeviceClass != other.d_func()->minorDeviceClass) return false; - if(d->serviceClasses != other.d_func()->serviceClasses) + if (d->serviceClasses != other.d_func()->serviceClasses) return false; - if(d->name != other.d_func()->name) + if (d->name != other.d_func()->name) return false; - if(d->address != other.d_func()->address) + if (d->address != other.d_func()->address) return false; - if(d->serviceUuidsCompleteness != other.d_func()->serviceUuidsCompleteness) + if (d->serviceUuidsCompleteness != other.d_func()->serviceUuidsCompleteness) return false; - if(d->serviceUuids.count() != other.d_func()->serviceUuids.count()) + if (d->serviceUuids.count() != other.d_func()->serviceUuids.count()) return false; - if(d->serviceUuids != other.d_func()->serviceUuids) + if (d->serviceUuids != other.d_func()->serviceUuids) + return false; + if (d->deviceCoreConfiguration != other.d_func()->deviceCoreConfiguration) return false; return true; @@ -498,6 +513,29 @@ QBluetoothDeviceInfo::DataCompleteness QBluetoothDeviceInfo::serviceUuidsComplet } /*! + Sets the CoreConfiguration of the device to a \a coreConfig. This will help to make a difference + between regular and Low Energy devices. +*/ +void QBluetoothDeviceInfo::setCoreConfiguration(const CoreConfiguration &coreConfig) +{ + Q_D(QBluetoothDeviceInfo); + + d->deviceCoreConfiguration = coreConfig; +} + +/*! + Returns the configuration of the device. If device configuration is not set, + basic rate device configuration will be returned. + \sa setCoreConfiguration +*/ +QBluetoothDeviceInfo::CoreConfiguration QBluetoothDeviceInfo::coreConfiguration() const +{ + Q_D(const QBluetoothDeviceInfo); + + return d->deviceCoreConfiguration; +} + +/*! Returns true if the QBluetoothDeviceInfo object is created from cached data. */ bool QBluetoothDeviceInfo::isCached() const diff --git a/src/bluetooth/qbluetoothdeviceinfo.h b/src/bluetooth/qbluetoothdeviceinfo.h index be605f8d..a9aad493 100644 --- a/src/bluetooth/qbluetoothdeviceinfo.h +++ b/src/bluetooth/qbluetoothdeviceinfo.h @@ -196,6 +196,13 @@ public: DataUnavailable }; + enum CoreConfiguration { + LowEnergyCoreConfiguration = 0x01, + BaseRateCoreConfiguration = 0x02, + BaseRateAndLowEnergyCoreConfiguration = 0x03 + }; + Q_DECLARE_FLAGS(CoreConfigurations, CoreConfiguration) + QBluetoothDeviceInfo(); QBluetoothDeviceInfo(const QBluetoothAddress &address, const QString &name, quint32 classOfDevice); QBluetoothDeviceInfo(const QBluetoothDeviceInfo &other); @@ -223,6 +230,8 @@ public: void setServiceUuids(const QList<QBluetoothUuid> &uuids, DataCompleteness completeness); QList<QBluetoothUuid> serviceUuids(DataCompleteness *completeness = 0) const; DataCompleteness serviceUuidsCompleteness() const; + void setCoreConfiguration(const CoreConfiguration &coreConfig); + CoreConfiguration coreConfiguration() const; protected: QBluetoothDeviceInfoPrivate *d_ptr; diff --git a/src/bluetooth/qbluetoothdeviceinfo_p.h b/src/bluetooth/qbluetoothdeviceinfo_p.h index b08a8fec..d6c63a24 100644 --- a/src/bluetooth/qbluetoothdeviceinfo_p.h +++ b/src/bluetooth/qbluetoothdeviceinfo_p.h @@ -69,6 +69,7 @@ public: QBluetoothDeviceInfo::DataCompleteness serviceUuidsCompleteness; QList<QBluetoothUuid> serviceUuids; + QBluetoothDeviceInfo::CoreConfiguration deviceCoreConfiguration; }; QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp index 7e0e701d..615d0f4a 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp @@ -246,7 +246,6 @@ bool QBluetoothServiceDiscoveryAgent::setRemoteAddress(const QBluetoothAddress & if (!address.isNull()) d_ptr->singleDevice = true; d_ptr->deviceAddress = address; - return true; } diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h index 59c7b74b..90482048 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent.h @@ -49,6 +49,7 @@ #include <QtBluetooth/QBluetoothServiceInfo> #include <QtBluetooth/QBluetoothUuid> #include <QtBluetooth/QBluetoothDeviceDiscoveryAgent> +#include <QtBluetooth/QLowEnergyServiceInfo> QT_BEGIN_NAMESPACE @@ -100,6 +101,7 @@ public Q_SLOTS: Q_SIGNALS: void serviceDiscovered(const QBluetoothServiceInfo &info); + void serviceDiscovered(const QLowEnergyServiceInfo &info); void finished(); void canceled(); void error(QBluetoothServiceDiscoveryAgent::Error error); diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index 0e782d5c..c7fc47fb 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -41,13 +41,17 @@ #include "qbluetoothservicediscoveryagent.h" #include "qbluetoothservicediscoveryagent_p.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyserviceinfo_p.h" #include "bluez/manager_p.h" #include "bluez/adapter_p.h" #include "bluez/device_p.h" +#include "bluez/characteristic_p.h" #include <QtCore/QLoggingCategory> #include <QtDBus/QDBusPendingCallWatcher> +#include <QtCore/QUuid> QT_BEGIN_NAMESPACE @@ -96,6 +100,15 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr adapter = new OrgBluezAdapterInterface(QLatin1String("org.bluez"), reply.value().path(), QDBusConnection::systemBus()); + if (m_deviceAdapterAddress.isNull()) { + QDBusPendingReply<QVariantMap> reply = adapter->GetProperties(); + reply.waitForFinished(); + if (!reply.isError()) { + const QBluetoothAddress path_address(reply.value().value(QStringLiteral("Address")).toString()); + m_deviceAdapterAddress = path_address; + } + } + QDBusPendingReply<QDBusObjectPath> deviceObjectPath = adapter->CreateDevice(address.toString()); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(deviceObjectPath, q); @@ -173,17 +186,74 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWa delete adapter; adapter = 0; - QString pattern; - foreach (const QBluetoothUuid &uuid, uuidFilter) - pattern += uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')) + QLatin1Char(' '); + QVariantMap deviceProperties; + QString classType; + QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties(); + deviceReply.waitForFinished(); + if (!deviceReply.isError()) { + deviceProperties = deviceReply.value(); + classType = deviceProperties.value(QStringLiteral("Class")).toString(); + } - pattern = pattern.trimmed(); - qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Discover restrictions:" << pattern; + /* + * Low Energy services in bluez are represented as the list of the paths that can be + * accessed with org.bluez.Characteristic + */ + //QDBusArgument services = v.value(QLatin1String("Services")).value<QDBusArgument>(); + + + /* + * Bluez v4.1 does not have extra bit which gives information if device is Bluetooth + * Low Energy device and the way to discover it is with Class property of the Bluetooth device. + * Low Energy devices do not have property Class. + * In case we have LE device finish service discovery; otherwise search for regular services. + */ + if (classType.isEmpty()) { //is BLE device or device properties above not retrievable + qCDebug(QT_BT_BLUEZ) << "Discovered BLE-only device. Normal service discovery skipped."; + delete device; + device = 0; - QDBusPendingReply<ServiceMap> discoverReply = device->DiscoverServices(pattern); - watcher = new QDBusPendingCallWatcher(discoverReply, q); - QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), - q, SLOT(_q_discoveredServices(QDBusPendingCallWatcher*))); + const QStringList deviceUuids = deviceProperties.value(QStringLiteral("UUIDs")).toStringList(); + for (int i = 0; i < deviceUuids.size(); i++) { + QString b = deviceUuids.at(i); + b = b.remove(QLatin1Char('{')).remove(QLatin1Char('}')); + const QBluetoothUuid uuid(b); + + qCDebug(QT_BT_BLUEZ) << "Discovered BLE service" << uuid << uuidFilter.size(); + QLowEnergyServiceInfo lowEnergyService(uuid); + lowEnergyService.d_ptr->adapterAddress = m_deviceAdapterAddress; + lowEnergyService.setDevice(discoveredDevices.at(0)); + if (uuidFilter.isEmpty()) + emit q->serviceDiscovered(lowEnergyService); + else { + for (int j = 0; j < uuidFilter.size(); j++) { + if (uuidFilter.at(j) == uuid) + emit q->serviceDiscovered(lowEnergyService); + + } + } + + } + + if (singleDevice && deviceReply.isError()) { + error = QBluetoothServiceDiscoveryAgent::InputOutputError; + errorString = QBluetoothServiceDiscoveryAgent::tr("Unable to access device"); + emit q->error(error); + } + _q_serviceDiscoveryFinished(); + } else { + QString pattern; + foreach (const QBluetoothUuid &uuid, uuidFilter) + pattern += uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')) + QLatin1Char(' '); + + pattern = pattern.trimmed(); + qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Discover restrictions:" << pattern; + + QDBusPendingReply<ServiceMap> discoverReply = device->DiscoverServices(pattern); + watcher = new QDBusPendingCallWatcher(discoverReply, q); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + q, SLOT(_q_discoveredServices(QDBusPendingCallWatcher*))); + } } void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingCallWatcher *watcher) @@ -213,36 +283,50 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC qCDebug(QT_BT_BLUEZ) << "Parsing xml" << discoveredDevices.at(0).address().toString() << discoveredDevices.count() << map.count(); + Q_Q(QBluetoothServiceDiscoveryAgent); + foreach (const QString &record, reply.value()) { QXmlStreamReader xml(record); QBluetoothServiceInfo serviceInfo; - serviceInfo.setDevice(discoveredDevices.at(0)); + bool btle = false; // Detecting potential BTLE services while (!xml.atEnd()) { xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::StartElement && - xml.name() == QLatin1String("attribute")) { - quint16 attributeId = - xml.attributes().value(QLatin1String("id")).toString().toUShort(0, 0); + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == QStringLiteral("attribute")) { + quint16 attributeId = xml.attributes().value(QStringLiteral("id")).toString().toUShort(0, 0); if (xml.readNextStartElement()) { QVariant value = readAttributeValue(xml); - + if (attributeId == 1) {// Attribute with id 1 contains UUID of the service + const QBluetoothServiceInfo::Sequence seq = value.value<QBluetoothServiceInfo::Sequence>(); + for (int i = 0; i < seq.count(); i++) { + const QBluetoothUuid uuid = seq.at(i).value<QBluetoothUuid>(); + if ((uuid.data1 & 0x1800) == 0x1800) {// We are taking into consideration that LE services starts at 0x1800 + QLowEnergyServiceInfo leService(uuid); + leService.setDevice(discoveredDevices.at(0)); + btle = true; + emit q->serviceDiscovered(leService); + break; + } + } + } serviceInfo.setAttribute(attributeId, value); } } } - if (!serviceInfo.isValid()) - continue; + if (!btle) { + serviceInfo.setDevice(discoveredDevices.at(0)); + if (!serviceInfo.isValid()) + continue; - Q_Q(QBluetoothServiceDiscoveryAgent); + discoveredServices.append(serviceInfo); + qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString(); + emit q->serviceDiscovered(serviceInfo); + } - discoveredServices.append(serviceInfo); - qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString(); - emit q->serviceDiscovered(serviceInfo); // could stop discovery, check for state if(discoveryState() == Inactive){ qCDebug(QT_BT_BLUEZ) << "Exit discovery after stop"; @@ -257,6 +341,130 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC _q_serviceDiscoveryFinished(); } +/* + * Following three methods are implemented in this way to avoid blocking the main thread. + * We first go through list of services path and then through services characteristics paths. + * + * Bluez v4.x does not have support for LE devices through org.bluez interfaces. Because of that + * these functions will not be used now. I propose to leave them commented because in Bluez v5.x + * we have support for LE devices and we can use these functions. + */ +/* +void QBluetoothServiceDiscoveryAgentPrivate::_g_discoveredGattService() +{ + + if (!gattServices.empty()) { + qDebug() << gattServices.at(0) << gattServices.size(); + gattService = QLowEnergyServiceInfo(gattServices.at(0)); + gattService.getProperties(); + QObject::connect(gattService.d_ptr.data(), SIGNAL(finished()), this, SLOT(_g_discoveredGattService())); + characteristic = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattServices.at(0), QDBusConnection::systemBus()); + QDBusPendingReply<QList<QDBusObjectPath> > characterictisReply = characteristic->DiscoverCharacteristics(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(characterictisReply, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(_q_discoverGattCharacteristics(QDBusPendingCallWatcher*))); + + gattServices.removeFirst(); + q_ptr->lowEnergyServiceDiscovered(gattService); + emit gattService.d_ptr->finished(); + } + else + q_ptr->finished(); + +} + +void QBluetoothServiceDiscoveryAgentPrivate::_q_discoverGattCharacteristics(QDBusPendingCallWatcher *watcher) +{ + + QDBusPendingReply<QList<QDBusObjectPath> > characterictisReply = *watcher; + if (characterictisReply.isError()){ + qDebug()<< "Discovering service characteristic error" << characterictisReply.error().message(); + Q_Q(QBluetoothServiceDiscoveryAgent); + error = QBluetoothServiceDiscoveryAgent::UnknownError; + errorString = characterictisReply.error().message(); + emit q->error(error); + _q_serviceDiscoveryFinished(); + return; + } + + foreach (const QDBusObjectPath &characteristicPath, characterictisReply.value()) + gattCharacteristics.append(characteristicPath.path()); + characteristic = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattCharacteristics.at(0), QDBusConnection::systemBus()); + QDBusPendingReply<QVariantMap> characteristicProperty = characteristic->GetProperties(); + watcher = new QDBusPendingCallWatcher(characteristicProperty, this); + _q_discoveredGattCharacteristic(watcher); + +} + +void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher) +{ + + QDBusPendingReply<QVariantMap> characteristicProperty = *watcher; + //qDebug()<<characteristicProperty.value(); + if (characteristicProperty.isError()){ + qDebug() << "Characteristic properties error" << characteristicProperty.error().message(); + Q_Q(QBluetoothServiceDiscoveryAgent); + error = QBluetoothServiceDiscoveryAgent::UnknownError; + errorString = characteristicProperty.error().message(); + emit q->error(error); + _q_serviceDiscoveryFinished(); + return; + } + QStringList serviceName; + + if (characteristicProperty.isError()) + qDebug()<<characteristicProperty.error().message(); + + QVariantMap properties = characteristicProperty.value(); + QString name = properties.value(QLatin1String("Name")).toString(); + QString description = properties.value(QLatin1String("Description")).toString(); + serviceName = description.split(QStringLiteral(" ")); + QString charUuid = properties.value(QLatin1String("UUID")).toString(); + QBluetoothUuid characteristicUuid(charUuid); + + QVariant value = properties.value(QLatin1String("Value")); + QByteArray byteValue = QByteArray(); + if (value.type() == QVariant::ByteArray) + byteValue = value.toByteArray(); + + //qDebug() << name << description << characteristicUuid.toString()<< byteValue.size(); + gattCharacteristic = QLowEnergyCharacteristicInfo(name, description, characteristicUuid, byteValue); + gattCharacteristic.setPath(gattCharacteristics.at(0)); + qDebug() << gattCharacteristics.at(0); + gattService.addCharacteristic(gattCharacteristic); + + + //Testing part for setting the property + QString b = "f000aa02-0451-4000-b000-000000000000"; + QBluetoothUuid u(b); + if (gattCharacteristic.uuid() == u){ + for (int j = 0; j< byteValue.size(); j++){ + qDebug() << (int) byteValue.at(j); + byteValue[j]=1; + qDebug() << (int) byteValue.at(j); + } + bool s = gattCharacteristic.setPropertyValue(QStringLiteral("Value"), byteValue); + qDebug() <<s; + } + + QString serName = serviceName.at(0) + " Service"; + + gattCharacteristics.removeFirst(); + if (gattCharacteristics.isEmpty()){ + q_ptr->lowEnergyServiceDiscovered(gattService); + emit gattService.d_ptr->finished(); + } + else{ + OrgBluezCharacteristicInterface *characteristicProperties = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattCharacteristics.at(0), QDBusConnection::systemBus()); + QDBusPendingReply<QVariantMap> characteristicProperty = characteristicProperties->GetProperties(); + watcher = new QDBusPendingCallWatcher(characteristicProperty, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(_q_discoveredGattCharacteristic(QDBusPendingCallWatcher*))); + } + +} +*/ + QVariant QBluetoothServiceDiscoveryAgentPrivate::readAttributeValue(QXmlStreamReader &xml) { if (xml.name() == QLatin1String("boolean")) { diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index bfd6d954..65082558 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -46,13 +46,16 @@ #include "qbluetoothdeviceinfo.h" #include "qbluetoothserviceinfo.h" #include "qbluetoothservicediscoveryagent.h" +#include "qlowenergyserviceinfo.h" #include <QStack> +#include <QStringList> #ifdef QT_BLUEZ_BLUETOOTH class OrgBluezManagerInterface; class OrgBluezAdapterInterface; class OrgBluezDeviceInterface; +class OrgBluezCharacteristicInterface; QT_BEGIN_NAMESPACE class QDBusPendingCallWatcher; class QXmlStreamReader; @@ -108,7 +111,6 @@ public: void setDiscoveryMode(QBluetoothServiceDiscoveryAgent::DiscoveryMode m) { mode = m; } QBluetoothServiceDiscoveryAgent::DiscoveryMode DiscoveryMode() { return mode; } - // private slots void _q_deviceDiscoveryFinished(); void _q_deviceDiscovered(const QBluetoothDeviceInfo &info); void _q_serviceDiscoveryFinished(); @@ -116,6 +118,12 @@ public: #ifdef QT_BLUEZ_BLUETOOTH void _q_discoveredServices(QDBusPendingCallWatcher *watcher); void _q_createdDevice(QDBusPendingCallWatcher *watcher); + //Slots below are used for discovering Bluetooth Low Energy devices. It will be used with Bluez 5.x version. + /* + void _g_discoveredGattService(); + void _q_discoverGattCharacteristics(QDBusPendingCallWatcher *watcher); + void _q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher); + */ #endif #ifdef QT_ANDROID_BLUETOOTH void _q_processFetchedUuids(const QBluetoothAddress &address, const QList<QBluetoothUuid> &uuids); @@ -149,6 +157,7 @@ private: QSocketNotifier *rdNotifier; QTimer m_queryTimer; bool m_btInitialized; + bool m_serviceScanDone; #endif public: @@ -168,11 +177,15 @@ private: QBluetoothServiceDiscoveryAgent::DiscoveryMode mode; bool singleDevice; - #ifdef QT_BLUEZ_BLUETOOTH OrgBluezManagerInterface *manager; OrgBluezAdapterInterface *adapter; OrgBluezDeviceInterface *device; + // variables below are used for discovering Bluetooth Low Energy devices + OrgBluezCharacteristicInterface *characteristic; + QStringList gattServices; + QStringList gattCharacteristics; + QLowEnergyCharacteristicInfo gattCharacteristic; #endif #ifdef QT_ANDROID_BLUETOOTH diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp index 59551451..37fabfab 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp @@ -45,16 +45,22 @@ #include "qbluetoothdeviceinfo.h" #include "qbluetoothdevicediscoveryagent.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyserviceinfo_p.h" + #include <QStringList> #include "qbluetoothuuid.h" - +#include <stdio.h> +#include <unistd.h> #include <sys/pps.h> #ifdef QT_QNX_BT_BLUETOOTH #include <errno.h> #include <QPointer> #endif - #include <QFile> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> #include <QtCore/private/qcore_unix_p.h> @@ -196,33 +202,45 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr #else qCDebug(QT_BT_QNX) << "Starting Service discovery for" << address.toString(); const QString filePath = QStringLiteral("/pps/services/bluetooth/remote_devices/").append(address.toString()); + bool hasError = false; if ((m_rdfd = qt_safe_open(filePath.toLocal8Bit().constData(), O_RDONLY)) == -1) { if (QFile::exists(filePath + QLatin1String("-00")) || - QFile::exists(filePath + QLatin1String("-01"))) { - qCDebug(QT_BT_QNX) << "LE device discovered...skipping"; + QFile::exists(filePath + QLatin1String("-01"))) + { + qCDebug(QT_BT_QNX) << "LE device discovered..."; + QString lePath = filePath + QStringLiteral("-00"); + if ((m_rdfd = qt_safe_open(lePath.toLocal8Bit().constData(), O_RDONLY)) == -1) { + lePath = filePath + QStringLiteral("-01"); + if ((m_rdfd = qt_safe_open(lePath.toLocal8Bit().constData(), O_RDONLY)) == -1) + hasError = true; + } } else { - qCWarning(QT_BT_QNX) << "Failed to open " << filePath; - error = QBluetoothServiceDiscoveryAgent::InputOutputError; - errorString = QBluetoothServiceDiscoveryAgent::tr("Failed to open remote device file"); - q->error(error); + hasError = true; } + } + if (hasError) { + qCWarning(QT_BT_QNX) << "Failed to open " << filePath; + error = QBluetoothServiceDiscoveryAgent::InputOutputError; + errorString = QBluetoothServiceDiscoveryAgent::tr("Failed to open remote device file"); + q->error(error); _q_serviceDiscoveryFinished(); return; + } + + if (rdNotifier) + delete rdNotifier; + rdNotifier = new QSocketNotifier(m_rdfd, QSocketNotifier::Read, this); + if (rdNotifier) { + connect(rdNotifier, SIGNAL(activated(int)), this, SLOT(remoteDevicesChanged(int))); } else { - if (rdNotifier) - delete rdNotifier; - rdNotifier = new QSocketNotifier(m_rdfd, QSocketNotifier::Read, this); - if (rdNotifier) { - connect(rdNotifier, SIGNAL(activated(int)), this, SLOT(remoteDevicesChanged(int))); - } else { - qCWarning(QT_BT_QNX) << "Service Discovery: Failed to connect to rdNotifier"; - error = QBluetoothServiceDiscoveryAgent::InputOutputError; - errorString = QBluetoothServiceDiscoveryAgent::tr("Failed to connect to notifier"); - q->error(error); - _q_serviceDiscoveryFinished(); - return; - } + qWarning() << "Service Discovery: Failed to connect to rdNotifier"; + error = QBluetoothServiceDiscoveryAgent::InputOutputError; + errorString = QStringLiteral("Failed to connect to rdNotifier"); + q->error(error); + _q_serviceDiscoveryFinished(); + return; } + m_queryTimer.start(10000); ppsSendControlMessage("service_query", QStringLiteral("{\"addr\":\"%1\"}").arg(address.toString()), this); #endif @@ -258,14 +276,14 @@ void QBluetoothServiceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) pps_decoder_cleanup(&ppsDecoder); return; } - + // Checking for standard Bluetooth services pps_decoder_push(&ppsDecoder, "available_services"); - + bool standardService = false; const char *next_service = 0; for (int service_count=0; pps_decoder_get_string(&ppsDecoder, 0, &next_service ) == PPS_DECODER_OK; service_count++) { if (next_service == 0) break; - + standardService = true; qCDebug(QT_BT_QNX) << Q_FUNC_INFO << "Service" << next_service; QBluetoothServiceInfo serviceInfo; @@ -325,7 +343,38 @@ void QBluetoothServiceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) } } + if (standardService) // we need to pop back for the LE service scan + pps_decoder_pop(&ppsDecoder); + //Checking for Bluetooth Low Energy services + pps_decoder_push(&ppsDecoder, "gatt_available_services"); + + for (int service_count=0; pps_decoder_get_string(&ppsDecoder, 0, &next_service ) == PPS_DECODER_OK; service_count++) { + if (next_service == 0) + break; + + QString lowEnergyUuid(next_service); + qCDebug(QT_BT_QNX) << "LE Service: " << lowEnergyUuid << next_service; + QBluetoothUuid leUuid; + + //In case of custom UUIDs (e.g. Texas Instruments SenstorTag LE Device) + if ( lowEnergyUuid.length() > 4 ) { + leUuid = QBluetoothUuid(lowEnergyUuid); + } + else {// Official UUIDs are presented in 4 characters (for instance 180A) + lowEnergyUuid = QStringLiteral("0x") + lowEnergyUuid; + leUuid = QBluetoothUuid(lowEnergyUuid.toUShort(0,0)); + } + + QLowEnergyServiceInfo lowEnergyService(leUuid); + lowEnergyService.setDevice(discoveredDevices.at(0)); + qCDebug(QT_BT_QNX) << "Adding Low Energy service" << lowEnergyService.serviceUuid(); + q_ptr->serviceDiscovered(lowEnergyService); + } + pps_decoder_cleanup(&ppsDecoder); + //Deleting notifier since services will not change. + delete rdNotifier; + rdNotifier = 0; } void QBluetoothServiceDiscoveryAgentPrivate::controlReply(ppsResult result) @@ -338,6 +387,8 @@ void QBluetoothServiceDiscoveryAgentPrivate::controlReply(ppsResult result) if (!result.errorMsg.isEmpty()) { qCWarning(QT_BT_QNX) << Q_FUNC_INFO << result.errorMsg; errorString = result.errorMsg; + if (errorString == QObject::tr("Operation canceled")) + _q_serviceDiscoveryFinished(); error = QBluetoothServiceDiscoveryAgent::InputOutputError; q->error(error); } else { diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp index 85d48d49..92b20f2a 100644 --- a/src/bluetooth/qbluetoothuuid.cpp +++ b/src/bluetooth/qbluetoothuuid.cpp @@ -107,73 +107,293 @@ Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34 The list below explicitly states as what type each UUID shall be used. - \value ServiceDiscoveryServer Service discovery server UUID (service) - \value BrowseGroupDescriptor Browser group descriptor (service) - \value PublicBrowseGroup Public browse group service class. Services which have the public - browse group in their \l {QBluetoothServiceInfo::BrowseGroupList}{browse group list} - are discoverable by the remote devices. - \value SerialPort Serial Port Profile UUID (service & profile) - \value LANAccessUsingPPP LAN Access Profile UUID (service & profile) - \value DialupNetworking Dial-up Networking Profile UUID (service & profile) - \value IrMCSync Synchronization Profile UUID (service & profile) - \value ObexObjectPush OBEX object push service UUID (service & profile) - \value OBEXFileTransfer File Transfer Profile (FTP) UUID (service & profile) - \value IrMCSyncCommand Synchronization Profile UUID (profile) - \value Headset Headset Profile (HSP) UUID (service & profile) - \value AudioSource Advanced Audio Distribution Profile (A2DP) UUID (service) - \value AudioSink Advanced Audio Distribution Profile (A2DP) UUID (service) - \value AV_RemoteControlTarget Audio/Video Remote Control Profile (AVRCP) UUID (service) - \value AdvancedAudioDistribution Advanced Audio Distribution Profile (A2DP) UUID (profile) - \value AV_RemoteControl Audio/Video Remote Control Profile (AVRCP) UUID (service & profile) + \value ServiceDiscoveryServer Service discovery server UUID (service) + \value BrowseGroupDescriptor Browser group descriptor (service) + \value PublicBrowseGroup Public browse group service class. Services which have the public + browse group in their \l {QBluetoothServiceInfo::BrowseGroupList}{browse group list} + are discoverable by the remote devices. + \value SerialPort Serial Port Profile UUID (service & profile) + \value LANAccessUsingPPP LAN Access Profile UUID (service & profile) + \value DialupNetworking Dial-up Networking Profile UUID (service & profile) + \value IrMCSync Synchronization Profile UUID (service & profile) + \value ObexObjectPush OBEX object push service UUID (service & profile) + \value OBEXFileTransfer File Transfer Profile (FTP) UUID (service & profile) + \value IrMCSyncCommand Synchronization Profile UUID (profile) + \value Headset Headset Profile (HSP) UUID (service & profile) + \value AudioSource Advanced Audio Distribution Profile (A2DP) UUID (service) + \value AudioSink Advanced Audio Distribution Profile (A2DP) UUID (service) + \value AV_RemoteControlTarget Audio/Video Remote Control Profile (AVRCP) UUID (service) + \value AdvancedAudioDistribution Advanced Audio Distribution Profile (A2DP) UUID (profile) + \value AV_RemoteControl Audio/Video Remote Control Profile (AVRCP) UUID (service & profile) \value AV_RemoteControlController Audio/Video Remote Control Profile UUID (service) - \value HeadsetAG Headset Profile (HSP) UUID (service) - \value PANU Personal Area Networking Profile (PAN) UUID (service & profile) - \value NAP Personal Area Networking Profile (PAN) UUID (service & profile) - \value GN Personal Area Networking Profile (PAN) UUID (service & profile) - \value DirectPrinting Basic Printing Profile (BPP) UUID (service) - \value ReferencePrinting Related to Basic Printing Profile (BPP) UUID (service) - \value BasicImage Basic Imaging Profile (BIP) UUID (profile) - \value ImagingResponder Basic Imaging Profile (BIP) UUID (service) + \value HeadsetAG Headset Profile (HSP) UUID (service) + \value PANU Personal Area Networking Profile (PAN) UUID (service & profile) + \value NAP Personal Area Networking Profile (PAN) UUID (service & profile) + \value GN Personal Area Networking Profile (PAN) UUID (service & profile) + \value DirectPrinting Basic Printing Profile (BPP) UUID (service) + \value ReferencePrinting Related to Basic Printing Profile (BPP) UUID (service) + \value BasicImage Basic Imaging Profile (BIP) UUID (profile) + \value ImagingResponder Basic Imaging Profile (BIP) UUID (service) \value ImagingAutomaticArchive Basic Imaging Profile (BIP) UUID (service) \value ImagingReferenceObjects Basic Imaging Profile (BIP) UUID (service) - \value Handsfree Hands-Free Profile (HFP) UUID (service & profile) - \value HandsfreeAudioGateway Hands-Free Audio Gateway (HFP) UUID (service) + \value Handsfree Hands-Free Profile (HFP) UUID (service & profile) + \value HandsfreeAudioGateway Hands-Free Audio Gateway (HFP) UUID (service) \value DirectPrintingReferenceObjectsService Basic Printing Profile (BPP) UUID (service) - \value ReflectedUI Basic Printing Profile (BPP) UUID (service) - \value BasicPrinting Basic Printing Profile (BPP) UUID (profile) - \value PrintingStatus Basic Printing Profile (BPP) UUID (service) + \value ReflectedUI Basic Printing Profile (BPP) UUID (service) + \value BasicPrinting Basic Printing Profile (BPP) UUID (profile) + \value PrintingStatus Basic Printing Profile (BPP) UUID (service) \value HumanInterfaceDeviceService Human Interface Device (HID) UUID (service & profile) \value HardcopyCableReplacement Hardcopy Cable Replacement Profile (HCRP) (profile) - \value HCRPrint Hardcopy Cable Replacement Profile (HCRP) (service) - \value HCRScan Hardcopy Cable Replacement Profile (HCRP) (service) - \value SIMAccess SIM Access Profile (SAP) UUID (service and profile) - \value PhonebookAccessPCE Phonebook Access Profile (PBAP) UUID (service) - \value PhonebookAccessPSE Phonebook Access Profile (PBAP) UUID (service) - \value PhonebookAccess Phonebook Access Profile (PBAP) (profile) - \value HeadsetHS Headset Profile (HSP) UUID (service) - \value MessageAccessServer Message Access Profile (MAP) UUID (service) - \value MessageNotificationServer Message Access Profile (MAP) UUID (service) - \value MessageAccessProfile Message Access Profile (MAP) UUID (profile) - \value GNSS Global Navigation Satellite System UUID (profile) - \value GNSSServer Global Navigation Satellite System Server (UUID) (service) - \value Display3D 3D Synchronization Display UUID (service) - \value Glasses3D 3D Synchronization Glasses UUID (service) - \value Synchronization3D 3D Synchronization UUID (profile) - \value MPSProfile Multi-Profile Specification UUID (profile) - \value MPSService Multi-Profile Specification UUID (service) - \value PnPInformation Device Identification (DID) UUID (service & profile) - \value GenericNetworking Generic networking UUID (service) - \value GenericFileTransfer Generic file transfer UUID (service) - \value GenericAudio Generic audio UUID (service) - \value GenericTelephony Generic telephone UUID (service) - \value VideoSource Video Distribution Profile (VDP) UUID (service) - \value VideoSink Video Distribution Profile (VDP) UUID (service) - \value VideoDistribution Video Distribution Profile (VDP) UUID (profile) - \value HDP Health Device Profile (HDP) UUID (profile) - \value HDPSource Health Device Profile Source (HDP) UUID (service) - \value HDPSink Health Device Profile Sink (HDP) UUID (service) - - \sa QBluetoothServiceInfo::ServiceClassIds + \value HCRPrint Hardcopy Cable Replacement Profile (HCRP) (service) + \value HCRScan Hardcopy Cable Replacement Profile (HCRP) (service) + \value SIMAccess SIM Access Profile (SAP) UUID (service and profile) + \value PhonebookAccessPCE Phonebook Access Profile (PBAP) UUID (service) + \value PhonebookAccessPSE Phonebook Access Profile (PBAP) UUID (service) + \value PhonebookAccess Phonebook Access Profile (PBAP) (profile) + \value HeadsetHS Headset Profile (HSP) UUID (service) + \value MessageAccessServer Message Access Profile (MAP) UUID (service) + \value MessageNotificationServer Message Access Profile (MAP) UUID (service) + \value MessageAccessProfile Message Access Profile (MAP) UUID (profile) + \value GNSS Global Navigation Satellite System UUID (profile) + \value GNSSServer Global Navigation Satellite System Server (UUID) (service) + \value Display3D 3D Synchronization Display UUID (service) + \value Glasses3D 3D Synchronization Glasses UUID (service) + \value Synchronization3D 3D Synchronization UUID (profile) + \value MPSProfile Multi-Profile Specification UUID (profile) + \value MPSService Multi-Profile Specification UUID (service) + \value PnPInformation Device Identification (DID) UUID (service & profile) + \value GenericNetworking Generic networking UUID (service) + \value GenericFileTransfer Generic file transfer UUID (service) + \value GenericAudio Generic audio UUID (service) + \value GenericTelephony Generic telephone UUID (service) + \value VideoSource Video Distribution Profile (VDP) UUID (service) + \value VideoSink Video Distribution Profile (VDP) UUID (service) + \value VideoDistribution Video Distribution Profile (VDP) UUID (profile) + \value HDP Health Device Profile (HDP) UUID (profile) + \value HDPSource Health Device Profile Source (HDP) UUID (service) + \value HDPSink Health Device Profile Sink (HDP) UUID (service) + \value GenericAccess Generic access service for Bluetooth Low Energy devices UUID (service). + It contains generic information about the device. All available Characteristics are readonly. + \value GenericAttribute + \value ImmediateAlert Immediate Alert UUID (service). The service exposes a control point to allow a peer + device to cause the device to immediately alert. + \value LinkLoss Link Loss UUID (service). The service defines behavior when a link is lost between two devices. + \value TxPower Transmission Power UUID (service). The service exposes a device’s current + transmit power level when in a connection. + \value CurrentTimeService Current Time UUID (service). The service defines how the current time can be exposed using + the Generic Attribute Profile (GATT). + \value ReferenceTimeUpdateService Reference Time update UUID (service). The service defines how a client can request + an update from a reference time source from a time server. + \value NextDSTChangeService Next DST change UUID (service). The service defines how the information about an + upcoming DST change can be exposed. + \value Glucose Glucose UUID (service). The service exposes glucose and other data from a glucose sensor + for use in consumer and professional healthcare applications. + \value HealthThermometer Health Thermometer UUID (service). The Health Thermometer service exposes temperature + and other data from a thermometer intended for healthcare and fitness applications. + \value DeviceInformation Device Information UUID (service). The Device Information Service exposes manufacturer + and/or vendor information about a device. + \value HeartRate Heart Rate UUID (service). The service exposes the heart rate and other data from a + Heart Rate Sensor intended for fitness applications. + \value PhoneAlertStatusService Phone Alert Status UUID (service). The service exposes the phone alert status when + in a connection. + \value BatteryService Battery UUID (service). The Battery Service exposes the state of a battery within a device. + \value BloodPressure Blood Pressure UUID (service). The service exposes blood pressure and other data from a blood pressure + monitor intended for healthcare applications. + \value AlertNotificationService Alert Notification UUID (service). The Alert Notification service exposes alert + information on a device. + \value HumanInterfaceDevice Human Interface UUID (service). The service exposes the HID reports and other HID data + intended for HID Hosts and HID Devices. + \value ScanParameters Scan Parameters UUID (service). The Scan Parameters Service enables a GATT Server device + to expose a characteristic for the GATT Client to write its scan interval and scan window + on the GATT Server device. + \value RunningSpeedAndCadence Runnung Speed and Cadence UUID (service). The service exposes speed, cadence and other + data from a Running Speed and Cadence Sensor intended for fitness applications. + \value CyclingSpeedAndCadence Cycling Speed and Cadence UUID (service). The service exposes speed-related and + cadence-related data from a Cycling Speed and Cadence sensor intended for fitness + applications. + \value CyclingPower Cycling Speed UUID (service). The service exposes power- and force-related data and + optionally speed- and cadence-related data from a Cycling Power + sensor intended for sports and fitness applications. + \value LocationAndNavigation Location Navigation UUID (service). The service exposes location and navigation-related + data from a Location and Navigation sensor intended for outdoor activity applications. +*/ + +/*! + \enum QBluetoothUuid::CharacteristicId + + This enum is a convienience type for Bluetooth low energy service characteristics class UUIDs. Values of this type + will be implicitly converted into a QBluetoothUuid when necessary. + + \value AlertCategoryID Categories of alerts/messages. + \value AlertCategoryIDBitMask Categories of alerts/messages. + \value AlertLevel The level of an alert a device is to sound. + If this level is changed while the alert is being sounded, + the new level should take effect. + \value AlertNotificationControlPoint Control point of the Alert Notification server. + Client can write the command here to request the several + functions toward the server. + \value AlertStatus The Alert Status characteristic defines the Status of alert. + \value Appearance The external appearance of this device. The values are composed + of a category (10-bits) and sub-categories (6-bits). + \value BatteryLevel The current charge level of a battery. 100% represents fully charged + while 0% represents fully discharged. + \value BloodPressureFeature The Blood Pressure Feature characteristic is used to describe the supported + features of the Blood Pressure Sensor. + \value BloodPressureMeasurement The Blood Pressure Measurement characteristic is a variable length structure + containing a Flags field, a Blood Pressure Measurement Compound Value field, + and contains additional fields such as Time Stamp, Pulse Rate and User ID + as determined by the contents of the Flags field. + \value BodySensorLocation + \value BootKeyboardInputReport The Boot Keyboard Input Report characteristic is used to transfer fixed format + and length Input Report data between a HID Host operating in Boot Protocol Mode + and a HID Service corresponding to a boot keyboard. + \value BootKeyboardOutputReport The Boot Keyboard Output Report characteristic is used to transfer fixed format + and length Output Report data between a HID Host operating in Boot Protocol Mode + and a HID Service corresponding to a boot keyboard. + \value BootMouseInputReport The Boot Mouse Input Report characteristic is used to transfer fixed format and + length Input Report data between a HID Host operating in Boot Protocol Mode and + a HID Service corresponding to a boot mouse. + \value CSCFeature The CSC (Cycling Speed and Cadence) Feature characteristic is used to describe + the supported features of the Server. + \value CSCMeasurement The CSC Measurement characteristic (CSC refers to Cycling Speed and Cadence) + is a variable length structure containing a Flags field and, based on the contents + of the Flags field, may contain one or more additional fields as shown in the tables + below. + \value CurrentTime + \value CyclingPowerControlPoint The Cycling Power Control Point characteristic is used to request a specific function + to be executed on the receiving device. + \value CyclingPowerFeature The CP Feature characteristic is used to report a list of features supported by + the device. + \value CyclingPowerMeasurement The Cycling Power Measurement characteristic is a variable length structure containing + a Flags field, an Instantaneous Power field and, based on the contents of the Flags + field, may contain one or more additional fields as shown in the table below. + \value CyclingPowerVector The Cycling Power Vector characteristic is a variable length structure containing + a Flags fieldand based on the contents of the Flags field, may contain one or more + additional fields as shown in the table below. + \value DateTime The Date Time characteristic is used to represent time. + \value DayDateTime + \value DayOfWeek + \value DeviceName + \value DSTOffset + \value ExactTime256 + \value FirmwareRevisionString The value of this characteristic is a UTF-8 string representing the firmware revision + for the firmware within the device. + \value GlucoseFeature The Glucose Feature characteristic is used to describe the supported features + of the Server. When read, the Glucose Feature characteristic returns a value + that is used by a Client to determine the supported features of the Server. + \value GlucoseMeasurement The Glucose Measurement characteristic is a variable length structure containing + a Flags field, a Sequence Number field, a Base Time field and, based upon the contents + of the Flags field, may contain a Time Offset field, Glucose Concentration field, + Type-Sample Location field and a Sensor Status Annunciation field. + \value GlucoseMeasurementContext + \value HardwareRevisionString The value of this characteristic is a UTF-8 string representing the hardware revision + for the hardware within the device. + \value HeartRateControlPoint + \value HeartRateMeasurement + \value HIDControlPoint The HID Control Point characteristic is a control-point attribute that defines the + HID Commands when written. + \value HIDInformation The HID Information Characteristic returns the HID attributes when read. + \value IEEE1107320601RegulatoryCertificationDataList The value of the characteristic is an opaque structure listing + various regulatory and/or certification compliance items to which the device + claims adherence. + \value IntermediateCuffPressure This characteristic has the same format as the Blood Pressure Measurement + characteristic. + \value IntermediateTemperature The Intermediate Temperature characteristic has the same format as the + Temperature Measurement characteristic + \value LNControlPoint The LN Control Point characteristic is used to request a specific function + to be executed on the receiving device. + \value LNFeature The LN Feature characteristic is used to report a list of features supported + by the device. + \value LocalTimeInformation + \value LocationAndSpeed The Location and Speed characteristic is a variable length structure containing + a Flags field and, based on the contents of the Flags field, may contain a combination + of data fields. + \value ManufacturerNameString The value of this characteristic is a UTF-8 string representing the name of the + manufacturer of the device. + \value MeasurementInterval The Measurement Interval characteristic defines the time between measurements. + \value ModelNumberString The value of this characteristic is a UTF-8 string representing the model number + assigned by the device vendor. + \value Navigation The Navigation characteristic is a variable length structure containing a Flags field, + a Bearing field, a Heading field and, based on the contents of the Flags field. + \value NewAlert This characteristic defines the category of the alert and how many new alerts of + that category have occurred in the server device. + \value PeripheralPreferredConnectionParameters + \value PeripheralPrivacyFlag + \value PnPID The PnP_ID characteristic returns its value when read using the GATT Characteristic + Value Read procedure. + \value PositionQuality The Position Quality characteristic is a variable length structure containing a + Flags field and at least one of the optional data + \value ProtocolMode The Protocol Mode characteristic is used to expose the current protocol mode of + the HID Service with which it is associated, or to set the desired protocol + mode of the HID Service. + \value ReconnectionAddress The Information included in this page is informative. The normative descriptions + are contained in the applicable specification. + \value RecordAccessControlPoint This control point is used with a service to provide basic management functionality + for the Glucose Sensor patient record database. + \value ReferenceTimeInformation + \value Report The Report characteristic is used to exchange data between a HID Device and a HID Host. + \value ReportMap Only a single instance of this characteristic exists as part of a HID Service. + \value RingerControlPoint The Ringer Control Point characteristic defines the Control Point of Ringer. + \value RingerSetting The Ringer Setting characteristic defines the Setting of the Ringer. + \value RSCFeature The RSC (Running Speed and Cadence) Feature characteristic is used to describe the + supported features of the Server. + \value RSCMeasurement RSC refers to Running Speed and Cadence. + \value SCControlPoint The SC Control Point characteristic is used to request a specific function to be + executed on the receiving device. + \value ScanIntervalWindow The Scan Interval Window characteristic is used to store the scan parameters of + the GATT Client. + \value ScanRefresh The Scan Refresh characteristic is used to notify the Client that the Server + requires the Scan Interval Window characteristic to be written with the latest + values upon notification. + \value SensorLocation The Sensor Location characteristic is used to expose the location of the sensor. + \value SerialNumberString The value of this characteristic is a variable-length UTF-8 string representing + the serial number for a particular instance of the device. + \value ServiceChanged + \value SoftwareRevisionString The value of this characteristic is a UTF-8 string representing the software + revision for the software within the device. + \value SupportedNewAlertCategory Category that the server supports for new alert. + \value SupportedUnreadAlertCategory Category that the server supports for unread alert. + \value SystemID If the system ID is based of a Bluetooth Device Address with a Company Identifier + (OUI) is 0x123456 and the Company Assigned Identifier is 0x9ABCDE, then the System + Identifier is required to be 0x123456FFFE9ABCDE. + \value TemperatureMeasurement The Temperature Measurement characteristic is a variable length structure containing + a Flags field, a Temperature Measurement Value field and, based upon the contents of + the Flags field, optionally a Time Stamp field and/or a Temperature Type field. + \value TemperatureType The Temperature Type characteristic is an enumeration that indicates where the + temperature was measured. + \value TimeAccuracy + \value TimeSource + \value TimeUpdateControlPoint + \value TimeUpdateState + \value TimeWithDST + \value TimeZone + \value TxPowerLevel The value of the characteristic is a signed 8 bit integer that has a fixed point + exponent of 0. + \value UnreadAlertStatus This characteristic shows how many numbers of unread alerts exist in the specific + category in the device. +*/ + +/*! + \enum QBluetoothUuid::DescriptorID + + This enum is a convienience type for Bluetooth low energy service descriptor class UUIDs. Values of this type + will be implicitly converted into a QBluetoothUuid when necessary. + + \value CharacteristicExtendedProperties Descriptor defines additional Characteristic Properties. + \value CharacteristicUserDescription Descriptor provides a textual user description for a characteristic value. + \value ClientCharacteristicConfiguration Descriptor defines how the characteristic may be configured by a specific client. + \value ServerCharacteristicConfiguration Descriptor defines how the characteristic descriptor is associated with may be + configured for the server. + \value CharacteristicPresentationFormat Descriptor defines the format of the Characteristic Value. + \value CharacteristicAggregateFormat Descriptor defines the format of an aggregated Characteristic Value. + \value ValidRange descriptor is used for defining the range of a characteristics. + Two mandatory fields are contained (upper and lower bounds) which define the range. + \value ExternalReportReference Allows a HID Host to map information from the Report Map characteristic value for + Input Report, Output Report or Feature Report data to the Characteristic UUID of + external service characteristics used to transfer the associated data. + \value ReportReference Mapping information in the form of a Report ID and Report Type which maps the + current parent characteristic to the Report ID(s) and Report Type (s) defined + within the Report Map characteristic. */ /*! @@ -205,6 +425,16 @@ QBluetoothUuid::QBluetoothUuid(ServiceClassUuid uuid) } /*! + Constructs a new Bluetooth UUID from the characteristic id \a uuid. +*/ +QBluetoothUuid::QBluetoothUuid(CharacteristicId uuid) +: QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1], + baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5], + baseUuid()->data4[6], baseUuid()->data4[7]) +{ +} + +/*! Constructs a new Bluetooth UUID from the 16 bit \a uuid. */ QBluetoothUuid::QBluetoothUuid(quint16 uuid) diff --git a/src/bluetooth/qbluetoothuuid.h b/src/bluetooth/qbluetoothuuid.h index 014b975a..c67d2e31 100644 --- a/src/bluetooth/qbluetoothuuid.h +++ b/src/bluetooth/qbluetoothuuid.h @@ -151,12 +151,131 @@ public: VideoDistribution = 0x1305, HDP = 0x1400, HDPSource = 0x1401, - HDPSink = 0x1402 + HDPSink = 0x1402, + GenericAccess = 0x1800, + GenericAttribute = 0x1801, + ImmediateAlert = 0x1802, + LinkLoss = 0x1803, + TxPower = 0x1804, + CurrentTimeService = 0x1805, + ReferenceTimeUpdateService = 0x1806, + NextDSTChangeService = 0x1807, + Glucose = 0x1808, + HealthThermometer = 0x1809, + DeviceInformation = 0x180a, + HeartRate = 0x180d, + PhoneAlertStatusService = 0x180e, + BatteryService = 0x180f, + BloodPressure = 0x1810, + AlertNotificationService = 0x1811, + HumanInterfaceDevice = 0x1812, + ScanParameters = 0x1813, + RunningSpeedAndCadence = 0x1814, + CyclingSpeedAndCadence = 0x1816, + CyclingPower = 0x1818, + LocationAndNavigation = 0x1819, + }; + + enum CharacteristicId { + AlertCategoryID = 0x2a43, + AlertCategoryIDBitMask = 0x2a42, + AlertLevel = 0x2a06, + AlertNotificationControlPoint = 0x2a44, + AlertStatus = 0x2a3f, + Appearance = 0x2a01, + BatteryLevel = 0x2a19, + BloodPressureFeature = 0x2a49, + BloodPressureMeasurement = 0x2a35, + BodySensorLocation = 0x2a38, + BootKeyboardInputReport = 0x2a22, + BootKeyboardOutputReport = 0x2a32, + BootMouseInputReport = 0x2a33, + CSCFeature = 0x2a5c, + CSCMeasurement = 0x2a5b, + CurrentTime = 0x2a2b, + CyclingPowerControlPoint = 0x2a66, + CyclingPowerFeature = 0x2a65, + CyclingPowerMeasurement = 0x2a63, + CyclingPowerVector = 0x2a64, + DateTime = 0x2a08, + DayDateTime = 0x2a0a, + DayOfWeek = 0x2a09, + DeviceName = 0x2a00, + DSTOffset = 0x2a0d, + ExactTime256 = 0x2a0c, + FirmwareRevisionString = 0x2a26, + GlucoseFeature = 0x2a51, + GlucoseMeasurement = 0x2a18, + GlucoseMeasurementContext = 0x2a34, + HardwareRevisionString = 0x2a27, + HeartRateControlPoint = 0x2a39, + HeartRateMeasurement = 0x2a37, + HIDControlPoint = 0x2a4c, + HIDInformation = 0x2a4a, + IEEE1107320601RegulatoryCertificationDataList = 0x2a2a, + IntermediateCuffPressure = 0x2a36, + IntermediateTemperature = 0x2a1e, + LNControlPoint = 0x2a6b, + LNFeature = 0x2a6a, + LocalTimeInformation = 0x2a0f, + LocationAndSpeed = 0x2a67, + ManufacturerNameString = 0x2a29, + MeasurementInterval = 0x2a21, + ModelNumberString = 0x2a24, + Navigation = 0x2a68, + NewAlert = 0x2a46, + PeripheralPreferredConnectionParameters = 0x2a04, + PeripheralPrivacyFlag = 0x2a02, + PnPID = 0x2a50, + PositionQuality = 0x2a69, + ProtocolMode = 0x2a4e, + ReconnectionAddress = 0x2a03, + RecordAccessControlPoint = 0x2a52, + ReferenceTimeInformation = 0x2a14, + Report = 0x2a4d, + ReportMap = 0x2a4b, + RingerControlPoint = 0x2a40, + RingerSetting = 0x2a41, + RSCFeature = 0x2a54, + RSCMeasurement = 0x2a53, + SCControlPoint = 0x2a55, + ScanIntervalWindow = 0x2a4f, + ScanRefresh = 0x2a31, + SensorLocation = 0x2a5d, + SerialNumberString = 0x2a25, + ServiceChanged = 0x2a05, + SoftwareRevisionString = 0x2a28, + SupportedNewAlertCategory = 0x2a47, + SupportedUnreadAlertCategory = 0x2a48, + SystemID = 0x2a23, + TemperatureMeasurement = 0x2a1c, + TemperatureType = 0x2a1d, + TimeAccuracy = 0x2a12, + TimeSource = 0x2a13, + TimeUpdateControlPoint = 0x2a16, + TimeUpdateState = 0x2a17, + TimeWithDST = 0x2a11, + TimeZone = 0x2a0e, + TxPowerLevel = 0x2a07, + UnreadAlertStatus = 0x2a45 + }; + + enum DescriptorID { + CharacteristicExtendedProperties = 0x2900, + CharacteristicUserDescription = 0x2901, + ClientCharacteristicConfiguration = 0x2902, + ServerCharacteristicConfiguration = 0x2903, + CharacteristicPresentationFormat = 0x2904, + CharacteristicAggregateFormat = 0x2905, + ValidRange = 0x2906, + ExternalReportReference = 0x2907, + ReportReference = 0x2908 }; QBluetoothUuid(); QBluetoothUuid(ProtocolUuid uuid); QBluetoothUuid(ServiceClassUuid uuid); + QBluetoothUuid(CharacteristicId uuid); explicit QBluetoothUuid(quint16 uuid); explicit QBluetoothUuid(quint32 uuid); explicit QBluetoothUuid(quint128 uuid); diff --git a/src/bluetooth/qlowenergycharacteristicinfo.cpp b/src/bluetooth/qlowenergycharacteristicinfo.cpp new file mode 100644 index 00000000..66994131 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo.cpp @@ -0,0 +1,298 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include <QHash> + +QT_BEGIN_NAMESPACE + +/*! + \class QLowEnergyCharacteristicInfo + \inmodule QtBluetooth + \brief The QLowEnergyCharacteristicInfo class stores information about a Bluetooth + Low Energy service characteristic. + + QLowEnergyCharacteristicInfo provides information about a Bluetooth Low Energy + service characteristic's name, UUID, value, permissions, handle and descriptors. + To get the full characteristic specification and information it is necessary to + connect to the service using QLowEnergyServiceInfo and QLowEnergyController classes. + Some characteristics can contain none, one or more descriptors. +*/ + +/*! + \enum QLowEnergyCharacteristicInfo::Property + + This enum describes the properties of a characteristic. + + \value Broadcasting Allow for the broadcasting of Generic Attributes (GATT) characteristic values. + \value Read Allow the characteristic values to be read. + \value WriteNoResponse Allow characteristic values without responses to be written. + \value Write Allow for characteristic values to be written. + \value Notify Permits notification of characteristic values. + \value Indicate Permits indications of characteristic values. + \value WriteSigned Permits signed writes of the GATT characteristic values. + \value ExtendedProperty Additional characteristic properties are defined in the characteristic + extended properties descriptor. +*/ + +/*! + Method for parsing the characteristic name with given \a uuid. + * \brief parseUuid + * \param uuid + * \return + */ +QString parseUuid(QBluetoothUuid uuid) { + static QHash<int, QString> uuidnames; + if ( uuidnames.isEmpty() ) { + uuidnames[0x2a43] = QStringLiteral("Alert Category ID"); + uuidnames[0x2A42] = QStringLiteral("Alert Category ID Bit Mask"); + uuidnames[0x2A06] = QStringLiteral("Alert Level"); + uuidnames[0x2A44] = QStringLiteral("Alert Notification Control Point"); + uuidnames[0x2A3F] = QStringLiteral("Alert Status"); + uuidnames[0x2A01] = QStringLiteral("GAP Appearance"); + uuidnames[0x2A19] = QStringLiteral("Battery Level"); + uuidnames[0x2A49] = QStringLiteral("Blood Pressure Feature"); + uuidnames[0x2A35] = QStringLiteral("Blood Pressure Measurement"); + uuidnames[0x2A38] = QStringLiteral("Body Sensor Location"); + uuidnames[0x2A22] = QStringLiteral("Boot Keyboard Input Report"); + uuidnames[0x2A32] = QStringLiteral("Boot Keyboard Output Report"); + uuidnames[0x2A33] = QStringLiteral("Boot Mouse Input Report"); + uuidnames[0x2A2B] = QStringLiteral("Current Time"); + uuidnames[0x2A08] = QStringLiteral("Date Time"); + uuidnames[0x2A0A] = QStringLiteral("Day Date Time"); + uuidnames[0x2A09] = QStringLiteral("Day of Week"); + uuidnames[0x2A00] = QStringLiteral("GAP Device Name"); + uuidnames[0x2A0D] = QStringLiteral("DST Offset"); + uuidnames[0x2A0C] = QStringLiteral("Exact Time 256"); + uuidnames[0x2A26] = QStringLiteral("Firmware Revision String"); + uuidnames[0x2A51] = QStringLiteral("Glucose Feature"); + uuidnames[0x2A18] = QStringLiteral("Glucose Measurement"); + uuidnames[0x2A34] = QStringLiteral("Glucose Measurement Context"); + uuidnames[0x2A27] = QStringLiteral("Hardware Revision String"); + uuidnames[0x2A39] = QStringLiteral("Heart Rate Control Point"); + uuidnames[0x2A37] = QStringLiteral("Heart Rate Measurement"); + uuidnames[0x2A4C] = QStringLiteral("HID Control Point"); + uuidnames[0x2A4A] = QStringLiteral("HID Information"); + uuidnames[0x2A2A] = QStringLiteral("IEEE 11073 20601 Regulatory Certification Data List"); + uuidnames[0x2A36] = QStringLiteral("Intermediate Blood Pressure"); + uuidnames[0x2A1E] = QStringLiteral("Iintermediate Temperature"); + uuidnames[0x2A0F] = QStringLiteral("Local Time Information"); + uuidnames[0x2A29] = QStringLiteral("Manufacturer Name String"); + uuidnames[0x2A21] = QStringLiteral("Measurement Interval"); + uuidnames[0x2A24] = QStringLiteral("Model Number String"); + uuidnames[0x2A46] = QStringLiteral("New Alert"); + uuidnames[0x2A04] = QStringLiteral("GAP Peripheral Preferred Connection Parameters"); + uuidnames[0x2A02] = QStringLiteral("GAP Peripheral Privacy Flag"); + uuidnames[0x2A50] = QStringLiteral("PNP ID"); + uuidnames[0x2A4E] = QStringLiteral("Protocol Mode"); + uuidnames[0x2A03] = QStringLiteral("GAP Reconnection Address"); + uuidnames[0x2A52] = QStringLiteral("Record Access Control Point"); + uuidnames[0x2A14] = QStringLiteral("Reference Time Information"); + uuidnames[0x2A4D] = QStringLiteral("Report"); + uuidnames[0x2A4B] = QStringLiteral("Report Map"); + uuidnames[0x2A40] = QStringLiteral("Ringer Control Point"); + uuidnames[0x2A41] = QStringLiteral("Ringer Setting"); + uuidnames[0x2A4F] = QStringLiteral("Scan Interval Window"); + uuidnames[0x2A31] = QStringLiteral("Scan Refresh"); + uuidnames[0x2A25] = QStringLiteral("Serial Number String"); + uuidnames[0x2A05] = QStringLiteral("GATT Service Changed"); + uuidnames[0x2A28] = QStringLiteral("Software Revision String"); + uuidnames[0x2A47] = QStringLiteral("Supported New Alert Category"); + uuidnames[0x2A48] = QStringLiteral("Supported Unread Alert Category"); + uuidnames[0x2A23] = QStringLiteral("System ID"); + uuidnames[0x2A1C] = QStringLiteral("Temperature Measurement"); + uuidnames[0x2A1D] = QStringLiteral("Temperature Type"); + uuidnames[0x2A12] = QStringLiteral("Time Accuracy"); + uuidnames[0x2A13] = QStringLiteral("Time Source"); + uuidnames[0x2A16] = QStringLiteral("Time Update Control Point"); + uuidnames[0x2A17] = QStringLiteral("Time Update State"); + uuidnames[0x2A11] = QStringLiteral("Time With DST"); + uuidnames[0x2A0E] = QStringLiteral("Time Zone"); + uuidnames[0x2A07] = QStringLiteral("TX Power"); + uuidnames[0x2A45] = QStringLiteral("Unread Alert Status"); + } + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknown Characteristic")); + return name; + +} + +/*! + Construct a new QLowEnergyCharacteristicInfo. +*/ +QLowEnergyCharacteristicInfo::QLowEnergyCharacteristicInfo(): + d_ptr(new QLowEnergyCharacteristicInfoPrivate) +{ + +} + +/*! + Construct a new QLowEnergyCharacteristicInfo with given \a uuid. +*/ +QLowEnergyCharacteristicInfo::QLowEnergyCharacteristicInfo(const QBluetoothUuid &uuid): + d_ptr(new QLowEnergyCharacteristicInfoPrivate) +{ + d_ptr->uuid = uuid; +} + +/*! + Construct a new QLowEnergyCharacteristicInfo that is a copy of \a other. + + The two copies continue to share the same underlying data which does not detach + upon write. +*/ +QLowEnergyCharacteristicInfo::QLowEnergyCharacteristicInfo(const QLowEnergyCharacteristicInfo &other): + d_ptr(other.d_ptr) +{ + +} + +/*! + Destroys the QLowEnergyCharacteristicInfo object. +*/ +QLowEnergyCharacteristicInfo::~QLowEnergyCharacteristicInfo() +{ + +} + +/*! + Returns the name of the gatt characteristic. +*/ +QString QLowEnergyCharacteristicInfo::name() const +{ + d_ptr->name = parseUuid(d_ptr->uuid); + return d_ptr->name; +} + +/*! + Returns the UUID of the gatt characteristic. +*/ +QBluetoothUuid QLowEnergyCharacteristicInfo::uuid() const +{ + return d_ptr->uuid; +} + +/*! + Returns the properties value of the gatt characteristic. +*/ +QVariantMap QLowEnergyCharacteristicInfo::properties() const +{ + return d_ptr->properties; +} + +/*! + Returns permissions of the gatt characteristic. +*/ +int QLowEnergyCharacteristicInfo::permissions() const +{ + return d_ptr->permission; +} + +/*! + Returns value of the gatt characteristic. +*/ +QByteArray QLowEnergyCharacteristicInfo::value() const +{ + return d_ptr->value; +} + +/*! + Returns the handle of the gatt characteristic. +*/ +QString QLowEnergyCharacteristicInfo::handle() const +{ + return d_ptr->handle; +} + +/*! + Returns the true or false statement depending whether the characteristic is notification + (enables conctant updates when value is changed on LE device). +*/ +bool QLowEnergyCharacteristicInfo::isNotificationCharacteristic() const +{ + return d_ptr->notification; +} + +/*! + Sets the value \a value of the characteristic. This only caches the value. To write + a value directly to the device QLowEnergyController class must be used. + + \sa QLowEnergyController::writeCharacteristic() +*/ +void QLowEnergyCharacteristicInfo::setValue(const QByteArray &value) +{ + d_ptr->value = value; +} + +/*! + Makes a copy of the \a other and assigns it to this QLowEnergyCharacteristicInfo object. + The two copies continue to share the same service and registration details. +*/ +QLowEnergyCharacteristicInfo &QLowEnergyCharacteristicInfo::operator=(const QLowEnergyCharacteristicInfo &other) +{ + d_ptr = other.d_ptr; + return *this; +} + +/*! + Returns true if the QLowEnergyCharacteristicInfo object is valid, otherwise returns false. + If it returns false, it means that service that this characteristic belongs was not connected. +*/ +bool QLowEnergyCharacteristicInfo::isValid() const +{ + if (d_ptr->uuid == QBluetoothUuid()) + return false; + if (d_ptr->handle.toUShort(0,0) == 0) + return false; + if (!d_ptr->valid()) + return false; + return true; +} + +/*! + Returns the list of characteristic descriptors. +*/ +QList<QLowEnergyDescriptorInfo> QLowEnergyCharacteristicInfo::descriptors() const +{ + return d_ptr->descriptorsList; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycharacteristicinfo.h b/src/bluetooth/qlowenergycharacteristicinfo.h new file mode 100644 index 00000000..ceaac46e --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo.h @@ -0,0 +1,105 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYCHARACTERISTICINFO_H +#define QLOWENERGYCHARACTERISTICINFO_H +#include <QtCore/QSharedPointer> +#include <QtCore/QObject> +#include <QtBluetooth/QBluetoothUuid> +#include <QtBluetooth/QLowEnergyDescriptorInfo> + +QT_BEGIN_NAMESPACE + +class QBluetoothUuid; +class QLowEnergyCharacteristicInfoPrivate; + +class Q_BLUETOOTH_EXPORT QLowEnergyCharacteristicInfo +{ + friend class QLowEnergyServiceInfo; + friend class QLowEnergyServiceInfoPrivate; + friend class QLowEnergyController; + friend class QLowEnergyControllerPrivate; + friend class QLowEnergyCharacteristicInfoPrivate; +public: + + enum Property { + Broadcasting = 0x01, + Read = 0x02, + WriteNoResponse = 0x04, + Write = 0x08, + Notify = 0x10, + Indicate = 0x20, + WriteSigned = 0x40, + ExtendedProperty = 0x80 + }; + + QLowEnergyCharacteristicInfo(); + QLowEnergyCharacteristicInfo(const QBluetoothUuid &uuid); + QLowEnergyCharacteristicInfo(const QLowEnergyCharacteristicInfo &other); + ~QLowEnergyCharacteristicInfo(); + + QLowEnergyCharacteristicInfo &operator=(const QLowEnergyCharacteristicInfo &other); + + QString name() const; + + QBluetoothUuid uuid() const; + + void setValue(const QByteArray &value); + QByteArray value() const; + + int permissions() const; + QVariantMap properties() const; + QString handle() const; + + bool isNotificationCharacteristic() const; + + QList<QLowEnergyDescriptorInfo> descriptors() const; + + bool isValid() const; + +protected: + QSharedPointer<QLowEnergyCharacteristicInfoPrivate> d_ptr; + +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYCHARACTERISTICINFO_H diff --git a/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp b/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp new file mode 100644 index 00000000..a6592186 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp @@ -0,0 +1,101 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "bluez/characteristic_p.h" +#include "qlowenergyprocess_p.h" + +#include <QtDBus/QDBusPendingCallWatcher> + +//#define QT_LOWENERGYCHARACTERISTIC_DEBUG + +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG +#include <QtCore/QDebug> +#endif + +QT_BEGIN_NAMESPACE + +QLowEnergyCharacteristicInfoPrivate::QLowEnergyCharacteristicInfoPrivate() + : permission(0), notification (false), handle(QStringLiteral("0x0000")), + properties(QVariantMap()), characteristic(0), m_signalConnected(false) +{ + process = process->instance(); + t=0; +} + +QLowEnergyCharacteristicInfoPrivate::~QLowEnergyCharacteristicInfoPrivate() +{ + delete characteristic; +} + +void QLowEnergyCharacteristicInfoPrivate::setValue(const QByteArray &wantedValue) +{ + Q_UNUSED(wantedValue); + +} + +void QLowEnergyCharacteristicInfoPrivate::readDescriptors() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::readValue() +{ + +} + +bool QLowEnergyCharacteristicInfoPrivate::valid() +{ + return true; +} + +bool QLowEnergyCharacteristicInfoPrivate::enableNotification() +{ + return false; +} + +void QLowEnergyCharacteristicInfoPrivate::disableNotification() +{ + +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycharacteristicinfo_p.cpp b/src/bluetooth/qlowenergycharacteristicinfo_p.cpp new file mode 100644 index 00000000..092a2580 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_p.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo_p.h" + +QT_BEGIN_NAMESPACE + +QLowEnergyCharacteristicInfoPrivate::QLowEnergyCharacteristicInfoPrivate() +{ + +} + +QLowEnergyCharacteristicInfoPrivate::~QLowEnergyCharacteristicInfoPrivate() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::setValue(const QByteArray &wantedValue) +{ + Q_UNUSED(wantedValue); +} + +bool QLowEnergyCharacteristicInfoPrivate::enableNotification() +{ + return false; +} + +void QLowEnergyCharacteristicInfoPrivate::disableNotification() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::readDescriptors() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::readValue() +{ + +} + +bool QLowEnergyCharacteristicInfoPrivate::valid() +{ + return false; +} +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycharacteristicinfo_p.h b/src/bluetooth/qlowenergycharacteristicinfo_p.h new file mode 100644 index 00000000..59353d5f --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_p.h @@ -0,0 +1,117 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYCHARACTERISTICINFO_P_H +#define QLOWENERGYCHARACTERISTICINFO_P_H +#include "qbluetoothuuid.h" +#include "qlowenergycharacteristicinfo.h" + +#ifdef QT_BLUEZ_BLUETOOTH +#include <QtDBus/QtDBus> +#include <QObject> +#endif +#ifdef QT_QNX_BLUETOOTH +#include <btapi/btdevice.h> +#include <btapi/btgatt.h> +#include <btapi/btspp.h> +#include <btapi/btle.h> +#endif +#ifdef QT_BLUEZ_BLUETOOTH +class OrgBluezCharacteristicInterface; +QT_FORWARD_DECLARE_CLASS(QLowEnergyProcess); +#endif + +QT_BEGIN_NAMESPACE +class QBluetoothUuid; +class QLowEnergyCharacteristicInfo; + +class QLowEnergyCharacteristicInfoPrivate: public QObject +{ + Q_OBJECT +public: + QLowEnergyCharacteristicInfoPrivate(); + ~QLowEnergyCharacteristicInfoPrivate(); + + void setValue(const QByteArray &wantedValue); + void readValue(); + bool valid(); + void readDescriptors(); + bool enableNotification(); + void disableNotification(); + + QString name; + QBluetoothUuid uuid; + QByteArray value; + int permission; + bool notification; + QString handle; + QString notificationHandle; + int instance; + QVariantMap properties; + QString errorString; + QList<QLowEnergyDescriptorInfo> descriptorsList; +#ifdef QT_QNX_BLUETOOTH + bt_gatt_characteristic_t characteristic; + int characteristicMtu; + bt_gatt_char_prop_mask characteristicProperties; + static void serviceNotification(int, short unsigned int, const unsigned char*, short unsigned int, void *); +#endif +#ifdef QT_BLUEZ_BLUETOOTH + QString path; + int t; + QString startingHandle; +#endif + +Q_SIGNALS: + void notifyValue(const QBluetoothUuid &); + void error(const QBluetoothUuid &); + +private: +#ifdef QT_BLUEZ_BLUETOOTH + OrgBluezCharacteristicInterface *characteristic; + QLowEnergyProcess *process; + bool m_signalConnected; +#endif + +}; +QT_END_NAMESPACE + +#endif // QLOWENERGYCHARACTERISTICINFO_P_H diff --git a/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp b/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp new file mode 100644 index 00000000..09db7e67 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp @@ -0,0 +1,332 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QLoggingCategory> +#include "qlowenergycharacteristicinfo_p.h" +#include <btapi/btdevice.h> +#include <btapi/btgatt.h> +#include <btapi/btle.h> +#include <errno.h> +#include "qlowenergyserviceinfo.h" +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergydescriptorinfo_p.h" +#include "qnx/ppshelpers_p.h" + + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_BT_QNX) + +int hexValue(QChar inChar) +{ + if (inChar.isDigit()) + return (inChar.unicode() - '0'); + else + return (inChar.toUpper().unicode() - 'A' + 10); + return -1; +} + +int stringToBuffer(const QString &stringData, quint8 *buffer, int bufferLength) +{ + int consumed = 0; + for (int i = 0; i < bufferLength; i++) { + const int hex = hexValue(stringData.at(i).toLatin1()); + if (hex >= 0) { + if ((consumed % 2) == 0) { + buffer[(consumed / 2)] = hex << 4; + } else { + buffer[(consumed / 2)] |= hex; + } + + consumed++; + } + } + + // Round up the number of bytes we consumed to a multiple of 2. + if ((consumed % 2) != 0) + ++consumed; + + return consumed; +} + +QLowEnergyCharacteristicInfoPrivate::QLowEnergyCharacteristicInfoPrivate(): + permission(0), notification(false), handle(QStringLiteral("0x0000")), instance(-1) +{ + +} + +QLowEnergyCharacteristicInfoPrivate::~QLowEnergyCharacteristicInfoPrivate() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::serviceNotification(int instance, short unsigned int handle, const unsigned char*val, short unsigned int len, void *userData) +{ + if (val == 0) + return; + QPointer<QLowEnergyServiceInfoPrivate> *ClassPointer = static_cast<QPointer<QLowEnergyServiceInfoPrivate> *>(userData); + QLowEnergyServiceInfoPrivate *p = ClassPointer->data(); + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + qCDebug(QT_BT_QNX) << "[Notification] received (service uuid, handle, value, instance):" << p->uuid << handle << val << instance; + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + //Check if the notification from wanted characteristic + bool current = false; + QLowEnergyCharacteristicInfo chars; + for (int i = 0; i < p->characteristicList.size(); i++) { + QString charHandle; + charHandle.setNum(handle); + charHandle = charHandle; + if (charHandle == ((QLowEnergyCharacteristicInfo)p->characteristicList.at(i)).handle() ) { + chars = QLowEnergyCharacteristicInfo((QLowEnergyCharacteristicInfo)p->characteristicList.at(i)); + QByteArray receivedValue; + + for (int j = 0; j < len; j++) { + QByteArray hexadecimal; + hexadecimal.append(val[j]); + receivedValue.append(hexadecimal.toHex()); + } + + p->characteristicList.at(i).d_ptr->notification = true; + p->characteristicList.at(i).d_ptr->setValue(receivedValue); + current = true; + } + } + + if (!current) + qCDebug(QT_BT_QNX) << "Notificiation received and does not belong to this characteristic."; +} + +bool QLowEnergyCharacteristicInfoPrivate::enableNotification() +{ + if (instance == -1) { + qCDebug(QT_BT_QNX) << " GATT service not connected "; + errorString = QStringLiteral("Service is not connected"); + emit error(uuid); + return false; + } + if ( (permission & QLowEnergyCharacteristicInfo::Notify) == 0) { + qCDebug(QT_BT_QNX) << "Notification changes not allowed"; + errorString = QStringLiteral("This characteristic does not support notifications."); + emit error(uuid); + return false; + } + + int rc = bt_gatt_enable_notify(instance, &characteristic, 1); + if (rc != 0) { + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify errno=" << errno << strerror(errno); + errorString = QString::fromLatin1(strerror(errno)); + emit error(uuid); + return false; + } else { + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify was presumably OK"; + return true; + } +} + +void QLowEnergyCharacteristicInfoPrivate::setValue(const QByteArray &wantedValue) +{ + if (permission & QLowEnergyCharacteristicInfo::Write) { + const int characteristicLen = wantedValue.size(); + uint8_t *characteristicBuffer = (uint8_t *)alloca(characteristicLen / 2 + 1); + if (!characteristicBuffer) { + qCDebug(QT_BT_QNX) << "GATT characteristic: Not enough memory"; + errorString = QStringLiteral("Not enough memory."); + emit error(uuid); + bt_gatt_disconnect_instance(instance); + return; + } + + const int consumed = stringToBuffer(QString::fromLocal8Bit(wantedValue), characteristicBuffer, characteristicLen); + + if (consumed > 0) { + int byteCount; + byteCount = bt_gatt_write_value(instance, handle.toUShort(), 0, characteristicBuffer, (consumed / 2)); + + if (byteCount < 0) { + qCDebug(QT_BT_QNX) << "Unable to write characteristic value: " << errno << strerror(errno); + errorString = QStringLiteral("Unable to write characteristic value: ") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + } + } + } + else if (!notification) { + errorString = QStringLiteral("Characteristic does not allow write operations. The wanted value was not written to the device."); + emit error(uuid); + } + value = wantedValue; + properties[QStringLiteral("value")] = value; + emit notifyValue(uuid); + +} + +void QLowEnergyCharacteristicInfoPrivate::disableNotification() +{ + int rc = bt_gatt_enable_notify(instance, &characteristic, 0); + if (rc != 0) + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify errno=" << errno << strerror(errno); + else + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify was presumably OK"; + +} + +void QLowEnergyCharacteristicInfoPrivate::readDescriptors() +{ + descriptorsList.clear(); + int count = bt_gatt_descriptors_count(instance, &characteristic); + + if (count == -1) { + qWarning() << "GATT descriptors count failed:" << errno << "(" << strerror(errno) << ")"; + bt_gatt_disconnect_instance(instance); + return; + } + + bt_gatt_descriptor_t *descriptorList = 0; + if (count > 0) { + descriptorList = (bt_gatt_descriptor_t*)alloca(count * sizeof(bt_gatt_descriptor_t)); + if (!descriptorList) { + qCDebug(QT_BT_QNX) <<"GATT descriptors: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + /* BEGIN WORKAROUND - Temporary fix to address race condition */ + int number = 0; + do { + number = bt_gatt_descriptors(instance, &characteristic, descriptorList, count); + } while ((number == -1) && (errno == EBUSY)); + + count = number; + /* END WORKAROUND */ + } + + if (count == -1) { + qCDebug(QT_BT_QNX) << "GATT descriptors failed: %1 (%2)" << errno << strerror(errno); + bt_gatt_disconnect_instance(instance); + return; + } + + characteristicMtu = bt_gatt_get_mtu(instance); + + uint8_t *descriptorBuffer = (uint8_t *)alloca(characteristicMtu); + if (!descriptorBuffer) { + qCDebug(QT_BT_QNX) <<"GATT descriptors: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + for (int i = 0; i < count; i++) { + QVariantMap map; + + map[QStringLiteral("uuid")] = QString::fromLatin1(descriptorList[i].uuid); + + map[QStringLiteral("handle")] = descriptorList[i].handle; + QString descHanlde; + descHanlde.setNum(descriptorList[i].handle); + QString descriptorUuid(descriptorList[i].uuid); + QBluetoothUuid descUuid(descriptorUuid); + QLowEnergyDescriptorInfo descriptor(descUuid, descHanlde); + + uint8_t more = 1; + int byteCount; + for (int offset = 0; more; offset += byteCount) { + byteCount = bt_gatt_read_value(instance, descriptorList[i].handle, offset, descriptorBuffer, characteristicMtu, &more); + if (byteCount < 0) { + qCDebug(QT_BT_QNX) << "Unable to read descriptor value:"<< errno<< strerror(errno); + break; + } + descriptor.d_ptr->m_value = QByteArray(); + for (int j = 0; j < byteCount; j++) { + QString hexadecimal; + hexadecimal.setNum(descriptorBuffer[j], 16); + descriptor.d_ptr->m_value.append(hexadecimal.toLatin1()); + } + + } + + map[QStringLiteral("value")] = descriptor.d_ptr->m_value; + descriptor.d_ptr->m_properties = map; + descriptorsList.append(descriptor); + + } +} + +void QLowEnergyCharacteristicInfoPrivate::readValue() +{ + if ((permission & QLowEnergyCharacteristicInfo::Read) == 0) { + qCDebug(QT_BT_QNX) << "GATT characteristic: Read not permitted"; + return; + } + + uint8_t *characteristicBuffer = (uint8_t *)alloca(characteristicMtu); + if (!characteristicBuffer) { + qCDebug(QT_BT_QNX) << "GATT characteristic: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + QString descriptorString; + + int byteCount = 0; + uint8_t more = 1; + for (int offset = 0; more; offset += byteCount) { + byteCount = bt_gatt_read_value(instance, handle.toUShort(), offset, characteristicBuffer, characteristicMtu, &more); + if (byteCount < 0) { + qCDebug(QT_BT_QNX) << "Unable to read characteristic value: " << errno << strerror(errno); + break; + } + value = QByteArray(); + for (int j = 0; j < byteCount; j++) { + QString hexadecimal; + hexadecimal.setNum(characteristicBuffer[j], 16); + value.append(hexadecimal.toLatin1()); + } + properties["value"] = value; + } +} + +bool QLowEnergyCharacteristicInfoPrivate::valid() +{ + if (instance == -1) + return false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp new file mode 100644 index 00000000..16571a18 --- /dev/null +++ b/src/bluetooth/qlowenergycontroller.cpp @@ -0,0 +1,222 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycontroller.h" +#include "qlowenergycontroller_p.h" +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycharacteristicinfo_p.h" + +QT_BEGIN_NAMESPACE +/*! + \class QLowEnergyController + \inmodule QtBluetooth + \brief The QLowEnergyController class is used for connecting and reading data from LE device + services. + + To read data contained in LE service characteristics, the LE device must be paired and turned on. + First, connect necessary signals from the class and then connect to service by passing the wanted service + to \l connectoToService() function. \l connected() signal will be emitted on success or \l error() + signal in case of failure. It is possible to get error message by calling errorString function + in QLowEnergyServiceInfo class. + + In case of disconnecting from service, pass the wanted service to \l disconnectFromService() + function and \l disconnected signal will be emitted. + + It is enough to use one instance of this class to connect to more service on more devices, + but it is not possible to create more QLowEnergyController classes and connect to same + service on the same LE device. + + + \sa QLowEnergyServiceInfo, QLowEnergyCharacteristicInfo +*/ + +/*! + \fn void QLowEnergyController::connected(const QLowEnergyServiceInfo &) + + This signal is emitted when a LE service is connected, passing connected QLowEnergyServiceInfo + instance. + + \sa connectToService(const QLowEnergyServiceInfo &leService) +*/ + +/*! + \fn void QLowEnergyController::error(const QLowEnergyServiceInfo &) + + This signal is emitted when the service error occurs. + + \sa errorString() +*/ + +/*! + \fn void QLowEnergyController::error(const QLowEnergyCharacteristicInfo &) + + This signal is emitted when the characteristic error occurs. + + \sa errorString() +*/ + +/*! + \fn void QLowEnergyController::disconnected(const QLowEnergyServiceInfo &) + + Emits disconnected signal with disconnected LE service. +*/ + +/*! + \fn QLowEnergyController::valueChanged(const QLowEnergyCharacteristicInfo &) + + Emits a signal when the characteristic value is changed. This signal is emitted + after calling \l enableNotifications(const QLowEnergyCharacteristicInfo &characteristic) + function. + + \sa enableNotifications(const QLowEnergyCharacteristicInfo &characteristic) +*/ + + +/*! + Construct a new QLowEnergyInfo object with the \a parent. +*/ +QLowEnergyController::QLowEnergyController(QObject *parent): + QObject(parent), d_ptr(new QLowEnergyControllerPrivate) +{ + d_ptr->q_ptr = this; +} + +QLowEnergyController::~QLowEnergyController() +{ + +} + +/*! + Returns the list of all Bluetooth LE Services that were added. +*/ +QList<QLowEnergyServiceInfo> QLowEnergyController::services() const +{ + return d_ptr->m_leServices; +} + +/*! + Connects to the given \a leService. If the given service is not valid, or if + the given service is already connected, nothing will happen. + +*/ +void QLowEnergyController::connectToService(const QLowEnergyServiceInfo &leService) +{ + d_ptr->connectService(leService); +} + + +/*! + Disconnects the given \a leService. If the given service was not connected, nothing will be done. + + If the \a leService is not passed or it is invalid, all connected services will be disconnected. + +*/ +void QLowEnergyController::disconnectFromService(const QLowEnergyServiceInfo &leService) +{ + d_ptr->disconnectService(leService); +} + + +/*! + Enables receiving notifications from the given \a characteristic. If the service characteristic + does not belong to one of the services or characteristic permissions do not allow notifications, + the function will return false. +*/ +bool QLowEnergyController::enableNotifications(const QLowEnergyCharacteristicInfo &characteristic) +{ + return d_ptr->enableNotification(characteristic); +} + +/*! + Disables receiving notifications from the given \a characteristic. If the service characteristic + does not belong to one of the services, nothing wil lbe done. + + \sa addLeService +*/ +void QLowEnergyController::disableNotifications(const QLowEnergyCharacteristicInfo &characteristic) +{ + d_ptr->disableNotification(characteristic); +} + +/*! + Returns a human-readable description of the last error that occurred. + + \sa error(const QLowEnergyServiceInfo &), error(const QLowEnergyCharacteristicInfo &) +*/ +QString QLowEnergyController::errorString() const +{ + return d_ptr->errorString; +} + +/*! + This method is called for the Linux platform if a device has a random device address that + is used for connecting. + */ +void QLowEnergyController::setRandomAddress() +{ + d_ptr->m_randomAddress = true; +} + +/*! + This method writes the wanted \a characteristic taking its value. This value is written directly + to the Bluetooth Low Energy device. In case wanted characteristic is not connected or does not + have write permission, it will return false with the corresponding error string. + + \sa QLowEnergyCharacteristicInfo::setValue(), errorString(), error() + */ +bool QLowEnergyController::writeCharacteristic(const QLowEnergyCharacteristicInfo &characteristic) +{ + return d_ptr->write(characteristic); +} + +/*! + This method writes the wanted \a descriptor taking its value. This value is written directly + to the Bluetooth Low Energy device. In case wanted descriptor is not connected it will return + false with the corresponding error string. + + \sa QLowEnergyDescriptorInfo::setValue(), errorString(), error() + */ +bool QLowEnergyController::writeDescriptor(const QLowEnergyDescriptorInfo &descriptor) +{ + return d_ptr->write(descriptor); +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller.h b/src/bluetooth/qlowenergycontroller.h new file mode 100644 index 00000000..dcef728e --- /dev/null +++ b/src/bluetooth/qlowenergycontroller.h @@ -0,0 +1,97 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYCONTROLLER_H +#define QLOWENERGYCONTROLLER_H + +#include <QtCore/QObject> +#include <QtBluetooth/qbluetoothglobal.h> +#include <QtBluetooth/QBluetoothAddress> +#include <QtBluetooth/QLowEnergyCharacteristicInfo> +#include <QtBluetooth/QLowEnergyServiceInfo> +#include <QtBluetooth/QLowEnergyDescriptorInfo> + +QT_BEGIN_NAMESPACE + +class QLowEnergyControllerPrivate; + +class Q_BLUETOOTH_EXPORT QLowEnergyController: public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QLowEnergyController) +public: + QLowEnergyController(QObject *parent = 0); + ~QLowEnergyController(); + QList<QLowEnergyServiceInfo> services() const; + void connectToService(const QLowEnergyServiceInfo &leService); + void disconnectFromService(const QLowEnergyServiceInfo &leService = QLowEnergyServiceInfo()); + bool enableNotifications(const QLowEnergyCharacteristicInfo &characteristic); + void disableNotifications(const QLowEnergyCharacteristicInfo &characteristic); + bool writeCharacteristic(const QLowEnergyCharacteristicInfo &characteristic); + bool writeDescriptor(const QLowEnergyDescriptorInfo &descriptor); + QString errorString() const; + void setRandomAddress(); + +Q_SIGNALS: + void connected(const QLowEnergyServiceInfo &); + void error(const QLowEnergyServiceInfo &); + void error(const QLowEnergyCharacteristicInfo &); + void disconnected(const QLowEnergyServiceInfo &); + void valueChanged(const QLowEnergyCharacteristicInfo &); + + + +private: + QLowEnergyControllerPrivate *d_ptr; + + Q_PRIVATE_SLOT(d_func(), void _q_serviceConnected(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceError(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_characteristicError(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_valueReceived(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDisconnected(const QBluetoothUuid &uuid)) +#ifdef QT_BLUEZ_BLUETOOTH + Q_PRIVATE_SLOT(d_func(), void _q_replyReceived(const QString &reply)) +#endif +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYCONTROLLER_H diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp new file mode 100644 index 00000000..042ef5f4 --- /dev/null +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -0,0 +1,518 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycontroller.h" +#include "qlowenergycontroller_p.h" +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyprocess_p.h" +#include "qlowenergydescriptorinfo.h" +#include "qlowenergydescriptorinfo_p.h" +#include "moc_qlowenergycontroller.cpp" + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) + +QLowEnergyControllerPrivate::QLowEnergyControllerPrivate(): + m_randomAddress(false), m_step(0), m_commandStarted(false) +{ + +} + +QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate() +{ + +} + +void QLowEnergyControllerPrivate::_q_serviceConnected(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).serviceUuid() == uuid) + emit q_ptr->connected((QLowEnergyServiceInfo)m_leServices.at(i)); + + } +} + +void QLowEnergyControllerPrivate::_q_serviceError(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).serviceUuid() == uuid) { + QLowEnergyServiceInfo service((QLowEnergyServiceInfo)m_leServices.at(i)); + //errorString = service.d_ptr->errorString; + emit q_ptr->error(service); + } + } +} + +void QLowEnergyControllerPrivate::_q_characteristicError(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + QList<QLowEnergyCharacteristicInfo> characteristics = m_leServices.at(i).characteristics(); + for (int j = 0; j < characteristics.size(); j++) { + if (characteristics.at(j).uuid() == uuid) { + errorString = characteristics.at(j).d_ptr->errorString; + emit q_ptr->error(characteristics.at(j)); + } + } + } +} + + +void QLowEnergyControllerPrivate::_q_valueReceived(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + QList<QLowEnergyCharacteristicInfo> characteristics = m_leServices.at(i).characteristics(); + for (int j = 0; j < characteristics.size(); j++) { + if (characteristics.at(j).uuid() == uuid) + emit q_ptr->valueChanged(characteristics.at(j)); + } + } +} + +void QLowEnergyControllerPrivate::_q_serviceDisconnected(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).serviceUuid() == uuid) { + QObject::disconnect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(connectedToService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceConnected(QBluetoothUuid))); + QObject::disconnect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(error(QBluetoothUuid)), q_ptr, SLOT(_q_serviceError(QBluetoothUuid))); + QObject::disconnect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(disconnectedFromService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceDisconnected(QBluetoothUuid))); + emit q_ptr->disconnected((QLowEnergyServiceInfo)m_leServices.at(i)); + } + } +} + +void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &service) +{ + errorString = QString(); + service.d_ptr->characteristicList.clear(); + bool add = true; + for (int i = 0; i < m_leServices.size(); i++) { + if (m_leServices.at(i).serviceUuid() == service.serviceUuid()) { + m_leServices.replace(i, service); + add = false; + break; + } + } + if (add) + m_leServices.append(service); + process = process->instance(); + if (!process->isConnected()) { + if (m_commandStarted) + connectToTerminal(); + else { + QObject::connect(process, SIGNAL(replySend(const QString &)), q_ptr, SLOT(_q_replyReceived(const QString &))); + QString command = QStringLiteral("gatttool -i ") + service.d_ptr->adapterAddress.toString() + QStringLiteral(" -b ") + service.d_ptr->deviceInfo.address().toString() + QStringLiteral(" -I"); + if (m_randomAddress) + command += QStringLiteral(" -t random"); + qCDebug(QT_BT_BLUEZ) << "[REGISTER] uuid inside: " << service.d_ptr->uuid << command; + process->startCommand(command); + m_commandStarted = true; + } + process->addConnection(); + } + else + service.d_ptr->m_step = 1; +} + +void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo &service) +{ + if (service.isValid()) { + for (int i = 0; i < m_leServices.size(); i++) { + if (m_leServices.at(i).serviceUuid() == service.serviceUuid() && service.isConnected()) { + process = process->instance(); + process->endProcess(); + m_leServices.at(i).d_ptr->connected = false; + m_leServices.at(i).d_ptr->m_step = 0; + m_leServices.at(i).d_ptr->m_valueCounter = 0; + m_leServices.removeAt(i); + emit q_ptr->disconnected(service); + break; + } + } + } + else + disconnectAllServices(); +} + +void QLowEnergyControllerPrivate::_q_replyReceived(const QString &reply) +{ + qCDebug(QT_BT_BLUEZ) << "reply: " << reply; + // STEP 0 + if (m_step == 0 && !m_leServices.isEmpty()) + connectToTerminal(); + if (reply.contains(QStringLiteral("Connection refused (111)"))) { + errorString = QStringLiteral("Connection refused (111)"); + disconnectAllServices(); + } + else if (reply.contains(QStringLiteral("Device busy"))) { + errorString = QStringLiteral("Connection refused (111)"); + disconnectAllServices(); + } + else if (reply.contains(QStringLiteral("disconnected"))) { + errorString = QStringLiteral("Trying to execute command on disconnected service"); + disconnectAllServices(); + } + else { + // STEP 1 + if (reply.contains(QStringLiteral("[CON]"))) { + for (int i = 0; i < m_leServices.size(); i++) { + if (m_leServices.at(i).d_ptr->m_step == 1) { + setHandles(); + m_leServices.at(i).d_ptr->m_step++; + } + } + } + + // STEP 2 + if (reply.contains(QStringLiteral("attr")) && reply.contains(QStringLiteral("uuid"))){ + const QStringList handles = reply.split(QStringLiteral("\n")); + foreach (const QString &handle, handles) { + if (handle.contains(QStringLiteral("attr")) && handle.contains(QStringLiteral("uuid"))) { + const QStringList handleDetails = handle.split(QRegularExpression(QStringLiteral("[\\s+|,]")), + QString::SkipEmptyParts); + Q_ASSERT(handleDetails.count() == 9); + const QBluetoothUuid foundUuid(handleDetails.at(8)); + for (int i = 0; i < m_leServices.size(); i++) { + if (foundUuid == m_leServices.at(i).serviceUuid() && m_leServices.at(i).d_ptr->m_step == 2) { + m_leServices.at(i).d_ptr->startingHandle = handleDetails.at(2); + m_leServices.at(i).d_ptr->endingHandle = handleDetails.at(6); + setCharacteristics(i); + } + } + } + } + } + + // STEP 3 + if (reply.contains(QStringLiteral("char")) && reply.contains(QStringLiteral("uuid")) && reply.contains(QStringLiteral("properties"))) { + const QStringList handles = reply.split(QStringLiteral("\n")); + int stepSet = -1; + foreach (const QString& handle, handles) { + if (handle.contains(QStringLiteral("char")) && handle.contains(QStringLiteral("uuid"))) { + const QStringList handleDetails = handle.split(QRegularExpression(QStringLiteral("[\\s+|,]")), + QString::SkipEmptyParts); + Q_ASSERT(handleDetails.count() == 11); + const QString charHandle = handleDetails.at(8); + ushort charHandleId = charHandle.toUShort(0, 0); + for (int i = 0; i < m_leServices.size(); i++) { + if ( charHandleId >= m_leServices.at(i).d_ptr->startingHandle.toUShort(0,0) && + charHandleId <= m_leServices.at(i).d_ptr->endingHandle.toUShort(0,0)) + { + const QBluetoothUuid charUuid(handleDetails.at(10)); + QVariantMap map; + + QLowEnergyCharacteristicInfo charInfo(charUuid); + charInfo.d_ptr->handle = charHandle; + charInfo.d_ptr->startingHandle = handleDetails.at(1); + charInfo.d_ptr->permission = handleDetails.at(4).toUShort(0,0); + map[QStringLiteral("uuid")] = charUuid.toString(); + map[QStringLiteral("handle")] = charHandle; + map[QStringLiteral("permission")] = charInfo.d_ptr->permission; + charInfo.d_ptr->properties = map; + if (!(charInfo.d_ptr->permission & QLowEnergyCharacteristicInfo::Read)) + qCDebug(QT_BT_BLUEZ) << "GATT characteristic: Read not permitted: " << charInfo.d_ptr->uuid; + else + m_leServices.at(i).d_ptr->m_readCounter++; + m_leServices.at(i).d_ptr->characteristicList.append(charInfo); + stepSet = i; + break; + } + } + } + } + if ( stepSet != -1) + readCharacteristicValue(stepSet); + } + + // STEP 4 and STEP 5 + // This part is for reading characteristic values and setting the notifications + if (reply.contains(QStringLiteral("handle")) && reply.contains(QStringLiteral("value")) && !reply.contains(QStringLiteral("char"))) { + int index = -1; // setting characteristics values + int index1 = -1; // setting notifications and descriptors + for (int i = 0; i < m_leServices.size(); i++) { + if (m_leServices.at(i).d_ptr->m_step == 4) + index = i; + if (m_leServices.at(i).d_ptr->m_step == 5) + index1 = i; + } + const QStringList handles = reply.split(QStringLiteral("\n")); + bool lastStep = false; + foreach (const QString &handle, handles) { + if (handle.contains(QStringLiteral("handle")) && + handle.contains(QStringLiteral("value"))) + { + const QStringList handleDetails = handle.split(QRegularExpression(QStringLiteral("\\W+")), QString::SkipEmptyParts); + if (index != -1) { + if (!m_leServices.at(index).d_ptr->characteristicList.isEmpty()) { + for (int j = 0; j < m_leServices.at(index).d_ptr->characteristicList.size(); j++) { + const QLowEnergyCharacteristicInfo chars = m_leServices.at(index).d_ptr->characteristicList.at(j); + const QString handleId = handleDetails.at(1); + qCDebug(QT_BT_BLUEZ) << handleId << handleId.toUShort(0,0) << chars.handle() << chars.handle().toUShort(0,0); + if (handleId.toUShort(0,0) == chars.handle().toUShort(0,0)) { + QString value; + for ( int k = 3; k < handleDetails.size(); k++) + value = value + handleDetails.at(k); + m_leServices.at(index).d_ptr->characteristicList[j].d_ptr->value = value.toUtf8(); + qCDebug(QT_BT_BLUEZ) << "Characteristic value set." << m_leServices.at(index).d_ptr->characteristicList[j].uuid() << chars.d_ptr->handle << value; + m_leServices.at(index).d_ptr->m_valueCounter++; + } + } + } + if (m_leServices.at(index).d_ptr->m_valueCounter == m_leServices.at(index).d_ptr->m_readCounter) { + setNotifications(); + m_leServices.at(index).d_ptr->m_step++; + } + } + if (index1 != -1) { + for (int j = 0; j < (m_leServices.at(index1).d_ptr->characteristicList.size()-1); j++) { + QLowEnergyCharacteristicInfo chars = m_leServices.at(index1).d_ptr->characteristicList.at(j); + QLowEnergyCharacteristicInfo charsNext = m_leServices.at(index1).d_ptr->characteristicList.at(j+1); + const QString handleId = handleDetails.at(1); + ushort h = handleId.toUShort(0, 0); + qCDebug(QT_BT_BLUEZ) << handleId << h << chars.handle() << chars.handle().toUShort(0,0); + + if (h > chars.handle().toUShort(0,0) && h < charsNext.handle().toUShort(0,0)) { + chars.d_ptr->notificationHandle = handleId; + chars.d_ptr->notification = true; + QBluetoothUuid descUuid((ushort)0x2902); + QLowEnergyDescriptorInfo descriptor(descUuid, handleId); + QString val; + //TODO why do we start parsing value from k = 0? Shouldn't it be k = 2 + for (int k = 3; k < handleDetails.size(); k++) + val = val + handleDetails.at(k); + descriptor.d_ptr->m_value = val.toUtf8(); + QVariantMap map; + map[QStringLiteral("uuid")] = descUuid.toString(); + map[QStringLiteral("handle")] = handleId; + map[QStringLiteral("value")] = val.toUtf8(); + m_leServices.at(index1).d_ptr->characteristicList[j].d_ptr->descriptorsList.append(descriptor); + qCDebug(QT_BT_BLUEZ) << "Notification characteristic set." << chars.d_ptr->handle << chars.d_ptr->notificationHandle; + } + } + if (!lastStep) { + m_leServices.at(index1).d_ptr->m_step++; + m_leServices.at(index1).d_ptr->connected = true; + emit q_ptr->connected(m_leServices.at(index1)); + } + lastStep = true; + } + } + } + } + + // READING ADVERTISEMENT FROM THE BLE DEVICE + if (reply.contains(QStringLiteral("Notification handle"))) { + QStringList update, row; + update = reply.split(QStringLiteral("\n")); + for (int i = 0; i< update.size(); i ++) { + if (update.at(i).contains(QStringLiteral("Notification handle"))) { + row = update.at(i).split(QRegularExpression(QStringLiteral("\\W+")), QString::SkipEmptyParts); + for (int j = 0; j < m_leServices.size(); j++) { + for (int k = 0; k < m_leServices.at(j).characteristics().size(); k++) { + if (m_leServices.at(j).characteristics().at(k).handle() == row.at(2)) { + + QString notificationValue = QStringLiteral(""); + for (int s = 4 ; s< row.size(); s++) + notificationValue += row.at(s); + m_leServices.at(j).characteristics().at(k).d_ptr->value = notificationValue.toUtf8(); + m_leServices.at(j).characteristics().at(k).d_ptr->properties[QStringLiteral("value")] = notificationValue.toUtf8(); + emit q_ptr->valueChanged(m_leServices.at(j).characteristics().at(k)); + } + } + } + } + + } + } + } +} + +void QLowEnergyControllerPrivate::disconnectAllServices() +{ + for (int i = 0; i < m_leServices.size(); i++) { + process = process->instance(); + process->endProcess(); + m_leServices.at(i).d_ptr->m_step = 0; + m_leServices.at(i).d_ptr->m_valueCounter = 0; + if (m_leServices.at(i).isConnected()) { + m_leServices.at(i).d_ptr->connected = false; + emit q_ptr->disconnected(m_leServices.at(i)); + } + if (errorString != QString()) + emit q_ptr->error(m_leServices.at(i)); + m_step = 0; + } + m_leServices.clear(); +} + +void QLowEnergyControllerPrivate::connectToTerminal() +{ + process->executeCommand(QStringLiteral("connect")); + process->executeCommand(QStringLiteral("\n")); + for (int i = 0; i < m_leServices.size(); i++) + m_leServices.at(i).d_ptr->m_step = 1; + m_step++; +} + +void QLowEnergyControllerPrivate::setHandles() +{ + process->executeCommand(QStringLiteral("primary")); + process->executeCommand(QStringLiteral("\n")); + m_step++; +} + +void QLowEnergyControllerPrivate::setCharacteristics(int a) +{ + const QString command = QStringLiteral("characteristics ") + m_leServices.at(a).d_ptr->startingHandle + QStringLiteral(" ") + m_leServices.at(a).d_ptr->endingHandle; + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + m_leServices.at(a).d_ptr->m_step++; +} + +void QLowEnergyControllerPrivate::setNotifications() +{ + process->executeCommand(QStringLiteral("char-read-uuid 2902")); + process->executeCommand(QStringLiteral("\n")); +} + +void QLowEnergyControllerPrivate::readCharacteristicValue(int index) +{ + for (int i = 0; i < m_leServices.at(index).d_ptr->characteristicList.size(); i++) { + if ((m_leServices.at(index).d_ptr->characteristicList.at(i).d_ptr->permission & QLowEnergyCharacteristicInfo::Read)) { + const QString uuidHandle = m_leServices.at(index).d_ptr->characteristicList.at(i).uuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + const QString command = QStringLiteral("char-read-uuid ") + uuidHandle; + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + } + } + m_leServices.at(index).d_ptr->m_step++; +} + +void QLowEnergyControllerPrivate::writeValue(const QString &handle, const QByteArray &value) +{ + process = process->instance(); + QString command = QStringLiteral("char-write-req ") + handle + QStringLiteral(" ") + QString::fromLocal8Bit(value.constData()); + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + +} + +bool QLowEnergyControllerPrivate::enableNotification(const QLowEnergyCharacteristicInfo &characteristic) +{ + bool foundCharacteristic = false; + bool foundDescriptor = false; + const QBluetoothUuid descUuid((ushort)0x2902); + for (int i = 0; i < m_leServices.size(); i++) { + for (int j = 0; j < m_leServices.at(i).characteristics().size(); j++) { + if (m_leServices.at(i).characteristics().at(j).uuid() == characteristic.uuid()) { + foundCharacteristic = true; + for (int k = 0; k < m_leServices.at(i).characteristics().at(j).descriptors().size(); k++) { + if (m_leServices.at(i).characteristics().at(j).descriptors().at(k).uuid() == descUuid){ + foundDescriptor = true; + QByteArray val; + val.append(48); + val.append(49); + val.append(48); + val.append(48); + writeValue(m_leServices.at(i).characteristics().at(j).descriptors().at(k).handle(), val); + return true; + } + } + } + } + } + if (!foundDescriptor || !foundCharacteristic) { + errorString = QStringLiteral("Characteristic or notification descriptor not found."); + emit q_ptr->error(characteristic); + return false; + } + +} + +void QLowEnergyControllerPrivate::disableNotification(const QLowEnergyCharacteristicInfo &characteristic) +{ + const QBluetoothUuid descUuid((ushort)0x2902); + for (int i = 0; i < m_leServices.size(); i++) { + for (int j = 0; j < m_leServices.at(i).characteristics().size(); j++) { + if (m_leServices.at(i).characteristics().at(j).uuid() == characteristic.uuid()) { + for (int k = 0; k < m_leServices.at(i).characteristics().at(j).descriptors().size(); k++) { + if (m_leServices.at(i).characteristics().at(j).descriptors().at(k).uuid() == descUuid){ + QByteArray val; + val.append(48); + val.append(48); + val.append(48); + val.append(48); + writeValue(m_leServices.at(i).characteristics().at(j).descriptors().at(k).handle(), val); + } + } + } + } + } +} + +bool QLowEnergyControllerPrivate::write(const QLowEnergyCharacteristicInfo &characteristic) +{ + if (process->isConnected() && characteristic.isValid()) { + if (QLowEnergyCharacteristicInfo::Write & characteristic.permissions()) { + writeValue(characteristic.handle(), characteristic.value()); + return true; + } else { + errorString = QStringLiteral("This characteristic does not support write operations."); + emit q_ptr->error(characteristic); + return false; + } + } else { + errorString = QStringLiteral("The device is not connected or characteristic is not valid"); + emit q_ptr->error(characteristic); + return false; + } +} + +bool QLowEnergyControllerPrivate::write(const QLowEnergyDescriptorInfo &descriptor) +{ + if (process->isConnected()) { + writeValue(descriptor.handle(), descriptor.value()); + return true; + } +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller_p.cpp b/src/bluetooth/qlowenergycontroller_p.cpp new file mode 100644 index 00000000..66230585 --- /dev/null +++ b/src/bluetooth/qlowenergycontroller_p.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycontroller_p.h" +#include "moc_qlowenergycontroller.cpp" + +QT_BEGIN_NAMESPACE + +QLowEnergyControllerPrivate::QLowEnergyControllerPrivate() +{ + +} + +QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate() +{ + +} + +void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &service) +{ + Q_UNUSED(service); +} + +void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo &leService) +{ + Q_UNUSED(leService); +} + +void QLowEnergyControllerPrivate::disconnectAllServices() +{ + +} + +void QLowEnergyControllerPrivate::_q_characteristicError(const QBluetoothUuid &uuid) +{ + Q_UNUSED(uuid); +} + +void QLowEnergyControllerPrivate::_q_serviceConnected(const QBluetoothUuid &uuid) +{ + Q_UNUSED(uuid); +} + +void QLowEnergyControllerPrivate::_q_serviceDisconnected(const QBluetoothUuid &uuid) +{ + Q_UNUSED(uuid); +} + +void QLowEnergyControllerPrivate::_q_serviceError(const QBluetoothUuid &uuid) +{ + Q_UNUSED(uuid); +} + +void QLowEnergyControllerPrivate::_q_valueReceived(const QBluetoothUuid &uuid) +{ + Q_UNUSED(uuid); +} + +bool QLowEnergyControllerPrivate::enableNotification(const QLowEnergyCharacteristicInfo &characteristic) +{ + Q_UNUSED(characteristic); + return false; +} + +void QLowEnergyControllerPrivate::disableNotification(const QLowEnergyCharacteristicInfo &characteristic) +{ + Q_UNUSED(characteristic); +} + +bool QLowEnergyControllerPrivate::write(const QLowEnergyCharacteristicInfo &characteristic) +{ + Q_UNUSED(characteristic); + return false; +} + +bool QLowEnergyControllerPrivate::write(const QLowEnergyDescriptorInfo &descriptor) +{ + Q_UNUSED(descriptor); + return false; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h new file mode 100644 index 00000000..826f88c1 --- /dev/null +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -0,0 +1,94 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QLOWENERGYCONTROLLER_P_H +#define QLOWENERGYCONTROLLER_P_H +#include "qlowenergycontroller.h" + +QT_BEGIN_NAMESPACE + +class QLowEnergyController; +class QLowEnergyProcess; + +class QLowEnergyControllerPrivate +{ + Q_DECLARE_PUBLIC(QLowEnergyController) +public: + QLowEnergyControllerPrivate(); + ~QLowEnergyControllerPrivate(); + void connectService(const QLowEnergyServiceInfo &service); + void disconnectService(const QLowEnergyServiceInfo &leService = QLowEnergyServiceInfo()); + bool enableNotification(const QLowEnergyCharacteristicInfo &characteristic); + void disableNotification(const QLowEnergyCharacteristicInfo &characteristic); + bool write(const QLowEnergyCharacteristicInfo &characteristic); + bool write(const QLowEnergyDescriptorInfo &descriptor); + + void _q_serviceConnected(const QBluetoothUuid &uuid); + void _q_serviceError(const QBluetoothUuid &uuid); + void _q_characteristicError(const QBluetoothUuid &uuid); + void _q_valueReceived(const QBluetoothUuid &uuid); + void _q_serviceDisconnected(const QBluetoothUuid &uuid); + void disconnectAllServices(); + + QList<QLowEnergyServiceInfo> m_leServices; + QString errorString; + +#ifdef QT_BLUEZ_BLUETOOTH + void connectToTerminal(); + void setHandles(); + void setCharacteristics(int); + void setNotifications(); + void readCharacteristicValue(int); + void writeValue(const QString &, const QByteArray &); +public slots: + void _q_replyReceived(const QString &reply); +#endif +private: + bool m_randomAddress; +#ifdef QT_BLUEZ_BLUETOOTH + QLowEnergyProcess *process; + int m_step; + bool m_deviceConnected; + bool m_commandStarted; +#endif + QLowEnergyController *q_ptr; +}; +QT_END_NAMESPACE +#endif // QLOWENERGYCONTROLLER_P_H diff --git a/src/bluetooth/qlowenergydescriptorinfo.cpp b/src/bluetooth/qlowenergydescriptorinfo.cpp new file mode 100644 index 00000000..f18276ba --- /dev/null +++ b/src/bluetooth/qlowenergydescriptorinfo.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergydescriptorinfo.h" +#include "qlowenergydescriptorinfo_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QLowEnergyDescriptorInfo + \inmodule QtBluetooth + \brief The QLowEnergyDescriptorInfo class stores information about the Bluetooth + Low Energy descriptor. + + QLowEnergyDescriptorInfo provides information about a Bluetooth Low Energy + descriptor's name, UUID, value and handle. Descriptors are contained in the + Bluetooth Low Energy characteristic and they provide additional information + about the characteristic (data format, notification activation, etc). +*/ + +QString parseDescriptorUuid(const QBluetoothUuid &uuid) +{ + static QHash<int, QString> uuidnames; + if ( uuidnames.isEmpty() ) { + uuidnames[0x2905] = QStringLiteral("Characteristic Aggregate Format"); + uuidnames[0x2900] = QStringLiteral("Characteristic Extended Properties"); + uuidnames[0x2904] = QStringLiteral("Characteristic Presentation Format"); + uuidnames[0x2901] = QStringLiteral("Characteristic User Description"); + uuidnames[0x2902] = QStringLiteral("Client Characteristic Configuration"); + uuidnames[0x2907] = QStringLiteral("External Report Reference"); + uuidnames[0x2908] = QStringLiteral("Report Reference"); + uuidnames[0x2903] = QStringLiteral("Server Characteristic Configuration"); + uuidnames[0x2906] = QStringLiteral("Valid Range"); + } + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknow Descriptor")); + return name; +} + +QLowEnergyDescriptorInfoPrivate::QLowEnergyDescriptorInfoPrivate(const QBluetoothUuid &uuid, const QString &handle): + m_value(QByteArray()), m_uuid(uuid), m_handle(handle), m_properties(QVariantMap()), m_name(QStringLiteral("")) +{ + +} + +QLowEnergyDescriptorInfoPrivate::~QLowEnergyDescriptorInfoPrivate() +{ + +} + +/*! + Construct a new QLowEnergyCharacteristicInfo with given \a uuid. +*/ +QLowEnergyDescriptorInfo::QLowEnergyDescriptorInfo(const QBluetoothUuid &uuid): + d_ptr(new QLowEnergyDescriptorInfoPrivate(uuid, QStringLiteral("0x0000"))) +{ + +} + +/*! + Construct a new QLowEnergyDescriptorInfo with given \a uuid and the \a handle. +*/ +QLowEnergyDescriptorInfo::QLowEnergyDescriptorInfo(const QBluetoothUuid &uuid, const QString &handle): + d_ptr(new QLowEnergyDescriptorInfoPrivate(uuid, handle)) +{ + d_ptr->m_name = parseDescriptorUuid(uuid); +} + +/*! + Destroys the QLowEnergyDescriptorInfo object. +*/ +QLowEnergyDescriptorInfo::~QLowEnergyDescriptorInfo() +{ + +} + +/*! + Makes a copy of the \a other and assigns it to this QLowEnergyDescriptorInfo object. + The two copies continue to share the same service and registration details. +*/ +QLowEnergyDescriptorInfo &QLowEnergyDescriptorInfo::operator=(const QLowEnergyDescriptorInfo &other) +{ + d_ptr = other.d_ptr; + return *this; +} + +/*! + Returns the UUID of the descriptor. +*/ +QBluetoothUuid QLowEnergyDescriptorInfo::uuid() const +{ + return d_ptr->m_uuid; +} + +/*! + Returns the handle of the descriptor. +*/ +QString QLowEnergyDescriptorInfo::handle() const +{ + return d_ptr->m_handle; +} + +/*! + Returns the value of the descriptor. +*/ +QByteArray QLowEnergyDescriptorInfo::value() const +{ + return d_ptr->m_value; +} + +/*! + Returns the properties of the descriptor. +*/ +QVariantMap QLowEnergyDescriptorInfo::properties() const +{ + return d_ptr->m_properties; +} + +/*! + Returns the name of the descriptor. +*/ +QString QLowEnergyDescriptorInfo::name() const +{ + return d_ptr->m_name; +} + +/*! + Sets the value \a value of the descriptor. This only caches the value. To write + a value directly to the device QLowEnergyController class must be used. + + \sa QLowEnergyController::writeDescriptor() +*/ +void QLowEnergyDescriptorInfo::setValue(const QByteArray &value) +{ + d_ptr->m_value = value; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergydescriptorinfo.h b/src/bluetooth/qlowenergydescriptorinfo.h new file mode 100644 index 00000000..925ea122 --- /dev/null +++ b/src/bluetooth/qlowenergydescriptorinfo.h @@ -0,0 +1,79 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYDESCRIPTORINFO_H +#define QLOWENERGYDESCRIPTORINFO_H + +#include <QtCore/QSharedPointer> +#include <QtCore/QVariantMap> +#include <QtBluetooth/QBluetoothUuid> + +QT_BEGIN_NAMESPACE + +class QLowEnergyCharacteristicInfo; +class QLowEnergyDescriptorInfoPrivate; + +class Q_BLUETOOTH_EXPORT QLowEnergyDescriptorInfo +{ + friend class QLowEnergyCharacteristicInfo; + friend class QLowEnergyCharacteristicInfoPrivate; + friend class QLowEnergyServiceInfoPrivate; + friend class QLowEnergyControllerPrivate; +public: + explicit QLowEnergyDescriptorInfo(const QBluetoothUuid &uuid); + ~QLowEnergyDescriptorInfo(); + + QLowEnergyDescriptorInfo &operator=(const QLowEnergyDescriptorInfo &other); + QByteArray value() const; + QBluetoothUuid uuid() const; + QString handle() const; + QVariantMap properties() const; + QString name() const; + void setValue(const QByteArray &value); + +private: + QSharedPointer<QLowEnergyDescriptorInfoPrivate> d_ptr; + QLowEnergyDescriptorInfo(const QBluetoothUuid &uuid, const QString &handle); +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYDESCRIPTORINFO_H diff --git a/src/bluetooth/qlowenergydescriptorinfo_p.h b/src/bluetooth/qlowenergydescriptorinfo_p.h new file mode 100644 index 00000000..e167859f --- /dev/null +++ b/src/bluetooth/qlowenergydescriptorinfo_p.h @@ -0,0 +1,59 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYDESCRIPTORINFO_P_H +#define QLOWENERGYDESCRIPTORINFO_P_H + +QT_BEGIN_NAMESPACE + +class QLowEnergyDescriptorInfoPrivate +{ +public: + QLowEnergyDescriptorInfoPrivate(const QBluetoothUuid &uuid, const QString &handle); + ~QLowEnergyDescriptorInfoPrivate(); + QByteArray m_value; + QBluetoothUuid m_uuid; + QString m_handle; + QVariantMap m_properties; + QString m_name; +}; +QT_END_NAMESPACE +#endif // QLOWENERGYDESCRIPTORINFO_P_H diff --git a/src/bluetooth/qlowenergyprocess_bluez.cpp b/src/bluetooth/qlowenergyprocess_bluez.cpp new file mode 100644 index 00000000..26013273 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_bluez.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyprocess_p.h" + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QLowEnergyProcess, processInstance) + +/*! + * Private constructor. Constructs the new QLowEnergyProcess, sets variables and connects + * signal to a slot. + */ +QLowEnergyProcess::QLowEnergyProcess() +{ + m_process = new QProcess(); + connected = false; + m_counter = 0; + connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(replyRead())); +} + +/*! + Destroys the QLowEnergyProcess object. +*/ +QLowEnergyProcess::~QLowEnergyProcess() +{ + m_process->kill(); + delete m_process; +} + +/*! + Returns the instance of this clas. This class is a singleton class. +*/ + +QLowEnergyProcess *QLowEnergyProcess::instance() +{ + return processInstance(); +} + +/*! + Returns the QProcess that this class is using. +*/ +QProcess *QLowEnergyProcess::getProcess() +{ + return m_process; +} + +/*! + Slot that emits a signal replySend. This slot is connected with QProcess signal + and it is called whenever something comes to output. +*/ +void QLowEnergyProcess::replyRead() +{ + QByteArray result = m_process->readAll(); + QString back = QString::fromLocal8Bit(result.data()); + if (back.size() > 10) + emit replySend(back); +} + +/*! + Starts the process with \a command. This method is used only when starting the + process. + + \sa executeCommand() +*/ +void QLowEnergyProcess::startCommand(const QString &command) +{ + m_process->start(command); + if (!m_process->waitForStarted()) + qDebug() << "Could not start the process under the command: "<<command; +} + +/*! + Executes the \a command. This method is called after process started. + + \sa startCommand() +*/ +void QLowEnergyProcess::executeCommand(const QString &command) +{ + m_process->write(command.toUtf8().constData()); +} + +/*! + Terminate running process. +*/ +void QLowEnergyProcess::endProcess() +{ + m_counter--; + if (m_counter == 0) { + executeCommand(QStringLiteral("disconnect")); + executeCommand(QStringLiteral("\n")); + connected = false; + } +} + +bool QLowEnergyProcess::isConnected() const +{ + return connected; +} + +void QLowEnergyProcess::addConnection() +{ + m_counter++; + connected = true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyprocess_p.cpp b/src/bluetooth/qlowenergyprocess_p.cpp new file mode 100644 index 00000000..3303bef0 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_p.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyprocess_p.h" + +QLowEnergyProcess::QLowEnergyProcess() +{ + +} + +/*! + Destroys the QLowEnergyProcess object. +*/ +QLowEnergyProcess::~QLowEnergyProcess() +{ + +} + +/*! + Returns the instance of this class. This class is a singleton class. +*/ +QLowEnergyProcess *QLowEnergyProcess::instance() +{ + return 0; +} + +bool QLowEnergyProcess::isConnected() const +{ + return false; +} diff --git a/src/bluetooth/qlowenergyprocess_p.h b/src/bluetooth/qlowenergyprocess_p.h new file mode 100644 index 00000000..3f65b1e7 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_p.h @@ -0,0 +1,98 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYPROCESS_H +#define QLOWENERGYPROCESS_H + +#include <QtCore> +#include <QObject> +#ifdef QT_QNX_BLUETOOTH +#include <QList> +#include <QPointer> +#include "qlowenergyserviceinfo_p.h" +#endif +#ifdef QT_BLUEZ_BLUETOOTH +#include <QProcess> +#endif +QT_BEGIN_NAMESPACE + +class QLowEnergyProcess: public QObject +{ + Q_OBJECT + friend class QLowEnergyServiceInfoPrivate; +public: + QLowEnergyProcess(); + ~QLowEnergyProcess(); + + static QLowEnergyProcess *instance(); + bool isConnected() const; +#ifdef QT_QNX_BLUETOOTH + static void handleEvent(const int, const char *, const char *); + void addPointer(QLowEnergyServiceInfoPrivate* classPointer); +#endif +#ifdef QT_BLUEZ_BLUETOOTH + QProcess *getProcess(); + + void startCommand(const QString &command); + void executeCommand(const QString &command); + void endProcess(); + void addConnection(); + +Q_SIGNALS: + void replySend(const QString &reply); + +private slots: + void replyRead(); +#endif + +private: +#ifdef QT_BLUEZ_BLUETOOTH + QProcess *m_process; + int m_counter; +#endif +#ifdef QT_QNX_BLUETOOTH + QList<QObject*> m_classPointers; +#endif + bool connected; +}; +QT_END_NAMESPACE + +#endif // QLOWENERGYPROCESS_H diff --git a/src/bluetooth/qlowenergyprocess_qnx.cpp b/src/bluetooth/qlowenergyprocess_qnx.cpp new file mode 100644 index 00000000..1fa8cc48 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_qnx.cpp @@ -0,0 +1,96 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyprocess_p.h" +#include <btapi/btdevice.h> +#include <errno.h> +#include "qlowenergyserviceinfo.h" +#include "qlowenergyserviceinfo_p.h" +#include <btapi/btgatt.h> +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QLowEnergyProcess, processInstance) + +void QLowEnergyProcess::handleEvent(const int event, const char *bt_address, const char *event_data) +{ + qDebug() << "[HANDLE Event] (event, address, event data): " << event << bt_address << event_data; +} + +QLowEnergyProcess::QLowEnergyProcess() +{ + connected = false; + if (bt_device_init( &(this->handleEvent) ) < 0) + qDebug() << "[INIT] Init problem." << errno << strerror(errno); + else + connected = true; + +} + +/*! + Destroys the QLowEnergyProcess object. +*/ +QLowEnergyProcess::~QLowEnergyProcess() +{ + bt_device_deinit(); + bt_gatt_deinit(); + qDeleteAll(m_classPointers); + m_classPointers.clear(); +} + +/*! + Returns the instance of this clas. This class is a singleton class. +*/ + +QLowEnergyProcess *QLowEnergyProcess::instance() +{ + return processInstance(); +} + +bool QLowEnergyProcess::isConnected() const +{ + return connected; +} + +void QLowEnergyProcess::addPointer(QLowEnergyServiceInfoPrivate* classPointer) +{ + m_classPointers.append(classPointer); +} +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyserviceinfo.cpp b/src/bluetooth/qlowenergyserviceinfo.cpp new file mode 100644 index 00000000..23ead34e --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo.h" +#include "qlowenergyserviceinfo_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QLowEnergyServiceInfo + \inmodule QtBluetooth + \brief The QLowEnergyServiceInfo class stores information about the Bluetooth + Low Energy service. + + QLowEnergyServiceInfo provides information about a Bluetooth Low Energy + service's name, device, UUID, connection status, service type, handle + and characteristics. A Bluetooth Low Energy device can have one or more + low energy services. Each low energy service contains one or more + characteristics. The class is used with the QLowEnergyController + class. It is necessary to connect to the service first in order + to get the all service information and characteristics. +*/ + +/*! + \enum QLowEnergyServiceInfo::ServiceType + + This enum describes the type of the service. One LE device can have one or more primary services. + + \value PrimaryService The primary service. The primary service can have one or + more included services. + \value IncludedService The included service by primary services. +*/ + +/*! + Method for parsing the service name with given \a uuid. + * \brief parseUuid + * \param uuid + * \return + */ +QString parseUuid(const QBluetoothUuid &uuid) +{ + static QHash<int, QString> uuidnames; + if ( uuidnames.isEmpty() ) { + uuidnames[0x1800] = QStringLiteral("Generic Access"); + uuidnames[0x1801] = QStringLiteral("Generic Attribute"); + uuidnames[0x1802] = QStringLiteral("ImmediateAlert"); + uuidnames[0x1803] = QStringLiteral("Link Loss"); + uuidnames[0x1804] = QStringLiteral("Tx Power"); + uuidnames[0x1805] = QStringLiteral("Current Time Service"); + uuidnames[0x1806] = QStringLiteral("Reference Time Update Service"); + uuidnames[0x1807] = QStringLiteral("Next DST Change Service"); + uuidnames[0x1808] = QStringLiteral("Glucose"); + uuidnames[0x1809] = QStringLiteral("Health Thermometer"); + uuidnames[0x180A] = QStringLiteral("Device Information"); + uuidnames[0x180D] = QStringLiteral("Heart Rate"); + uuidnames[0x180E] = QStringLiteral("Phone Alert Status Service"); + uuidnames[0x180F] = QStringLiteral("Battery Service"); + uuidnames[0x1810] = QStringLiteral("Blood Pressure"); + uuidnames[0x1811] = QStringLiteral("Alert Notification Service"); + uuidnames[0x1812] = QStringLiteral("Human Interface Device"); + uuidnames[0x1813] = QStringLiteral("Scan Parameters"); + uuidnames[0x1814] = QStringLiteral("Running Speed and Cadance"); + uuidnames[0x1816] = QStringLiteral("Cycling Speed and Cadance"); + uuidnames[0x1818] = QStringLiteral("Cycling Power"); + uuidnames[0x1819] = QStringLiteral("Location and Navigation"); + } + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknow Service")); + return name; +} + +/*! + Construct a new QLowEnergyServiceInfo. +*/ +QLowEnergyServiceInfo::QLowEnergyServiceInfo(): + d_ptr(QSharedPointer<QLowEnergyServiceInfoPrivate>(new QLowEnergyServiceInfoPrivate)) +{ + +} + +/*! + Construct a new QLowEnergyServiceInfo object with the given \a uuid. + + Based on uuid, corresponsing service name is given. +*/ +QLowEnergyServiceInfo::QLowEnergyServiceInfo(const QBluetoothUuid &uuid): + d_ptr(QSharedPointer<QLowEnergyServiceInfoPrivate>(new QLowEnergyServiceInfoPrivate)) +{ + d_ptr->uuid = QBluetoothUuid(uuid); + d_ptr->serviceName = parseUuid(d_ptr->uuid); +} + +/*! + Construct a new QLowEnergyServiceInfo that is a copy of \a other. + + The two copies continue to share the same underlying data which does not detach + upon write. +*/ +QLowEnergyServiceInfo::QLowEnergyServiceInfo(const QLowEnergyServiceInfo &other): + d_ptr(other.d_ptr) +{ + +} + +/*! + Destroys the QLowEnergyServiceInfo object. +*/ +QLowEnergyServiceInfo::~QLowEnergyServiceInfo() +{ + +} + +/*! + Returns the gatt service uuid. +*/ +QBluetoothUuid QLowEnergyServiceInfo::serviceUuid() const +{ + return d_ptr->uuid; +} + +/*! + Returns the list of service characteristics. If service was not connected, an empty + list will be returned. +*/ +QList<QLowEnergyCharacteristicInfo> QLowEnergyServiceInfo::characteristics() const +{ + return d_ptr->characteristicList; +} + +/*! + Returns the service name. +*/ +QString QLowEnergyServiceInfo::serviceName() const +{ + return d_ptr->serviceName; +} + +/*! + Sets service type with \a type. +*/ +void QLowEnergyServiceInfo::setServiceType(QLowEnergyServiceInfo::ServiceType type) +{ + d_ptr->serviceType = type; +} + +/*! + Returns the service type. If setServiceType is not called default service type + (PrimaryService) is returned. +*/ +QLowEnergyServiceInfo::ServiceType QLowEnergyServiceInfo::serviceType() const +{ + return d_ptr->serviceType; +} + +/*! + Makes a copy of the \a other and assigns it to this QLowEnergyServiceInfo object. + The two copies continue to share the same service and registration details. +*/ +QLowEnergyServiceInfo &QLowEnergyServiceInfo::operator=(const QLowEnergyServiceInfo &other) +{ + d_ptr = other.d_ptr; + return *this; +} + +/*! + Checks whether service is connected. + */ +bool QLowEnergyServiceInfo::isConnected() const +{ + return d_ptr->connected; +} + +/*! + Returns the address of the Bluetooth device that provides this service. +*/ +QBluetoothDeviceInfo QLowEnergyServiceInfo::device() const +{ + return d_ptr->deviceInfo; +} + +/*! + Sets the Bluetooth device that provides this service to \a device. +*/ +void QLowEnergyServiceInfo::setDevice(const QBluetoothDeviceInfo &device) +{ + d_ptr->deviceInfo = device; +} + +/*! + Returns true if the QLowEnergyServiceInfo object is valid, otherwise returns false. +*/ +bool QLowEnergyServiceInfo::isValid() const +{ + if (d_ptr->uuid == QBluetoothUuid()) + return false; + if (!d_ptr->deviceInfo.isValid()) + return false; + if (!d_ptr->valid()) + return false; + return true; +} + +QT_END_NAMESPACE + + diff --git a/src/bluetooth/qlowenergyserviceinfo.h b/src/bluetooth/qlowenergyserviceinfo.h new file mode 100644 index 00000000..6fb2316a --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo.h @@ -0,0 +1,98 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYSERVICEINFO_H +#define QLOWENERGYSERVICEINFO_H +#include <QtCore/QSharedPointer> +#include <QtBluetooth/QBluetoothAddress> +#include <QtBluetooth/QBluetoothDeviceInfo> +#include <QtBluetooth/QBluetoothUuid> +#include <QtBluetooth/QLowEnergyCharacteristicInfo> + +QT_BEGIN_NAMESPACE + +class QLowEnergyServiceInfoPrivate; +class QBluetoothAddress; + +class Q_BLUETOOTH_EXPORT QLowEnergyServiceInfo +{ + friend class QBluetoothServiceDiscoveryAgent; + friend class QBluetoothServiceDiscoveryAgentPrivate; + friend class QLowEnergyController; + friend class QLowEnergyControllerPrivate; +public: + enum ServiceType { + PrimaryService = 0x00000001, + IncludedService = 0x00000002 + }; + + QLowEnergyServiceInfo(); + QLowEnergyServiceInfo(const QBluetoothUuid &uuid); + QLowEnergyServiceInfo(const QLowEnergyServiceInfo &other); + + ~QLowEnergyServiceInfo(); + + QLowEnergyServiceInfo &operator=(const QLowEnergyServiceInfo &other); + + void setDevice(const QBluetoothDeviceInfo &info); + QBluetoothDeviceInfo device() const; + + QBluetoothUuid serviceUuid() const; + + QList<QLowEnergyCharacteristicInfo> characteristics() const; + + QString serviceName() const; + + void setServiceType(QLowEnergyServiceInfo::ServiceType type); + QLowEnergyServiceInfo::ServiceType serviceType() const; + + bool isConnected() const; + + bool isValid() const; + +protected: + QSharedPointer<QLowEnergyServiceInfoPrivate> d_ptr; + +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYSERVICEINFO_H diff --git a/src/bluetooth/qlowenergyserviceinfo_bluez.cpp b/src/bluetooth/qlowenergyserviceinfo_bluez.cpp new file mode 100644 index 00000000..9e34fee4 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_bluez.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergyserviceinfo.h" +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyprocess_p.h" +#include "qbluetoothlocaldevice.h" +#include "bluez/characteristic_p.h" +#include "qlowenergydescriptorinfo.h" +#include "qlowenergydescriptorinfo_p.h" + +//#define QT_LOWENERGYSERVICE_DEBUG + +#ifdef QT_LOWENERGYSERVICE_DEBUG +#include <QtCore/QDebug> +#endif + +QT_BEGIN_NAMESPACE + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate(): + serviceType(QLowEnergyServiceInfo::PrimaryService), connected(false), characteristic(0), m_valueCounter(0), m_readCounter(0) +{ + m_step = 0; + QBluetoothLocalDevice localDevice; + adapterAddress = localDevice.address(); +} + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate(const QString &servicePath): + serviceType(QLowEnergyServiceInfo::PrimaryService), connected(false), path(servicePath), characteristic(0) +{ + m_step = 0; +} + +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() +{ + delete characteristic; +} + +bool QLowEnergyServiceInfoPrivate::valid() +{ + if (adapterAddress == QBluetoothAddress()) + return false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyserviceinfo_p.cpp b/src/bluetooth/qlowenergyserviceinfo_p.cpp new file mode 100644 index 00000000..0679278b --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_p.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo_p.h" + +QT_BEGIN_NAMESPACE + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate() +{ + +} + +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() +{ + +} + +void QLowEnergyServiceInfoPrivate::registerServiceWatcher() +{ + +} + +void QLowEnergyServiceInfoPrivate::unregisterServiceWatcher() +{ + +} + +bool QLowEnergyServiceInfoPrivate::valid() +{ + return false; +} +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyserviceinfo_p.h b/src/bluetooth/qlowenergyserviceinfo_p.h new file mode 100644 index 00000000..d033a613 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_p.h @@ -0,0 +1,118 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYSERVICEINFO_P_H +#define QLOWENERGYSERVICEINFO_P_H +#include "qbluetoothuuid.h" +#include "qlowenergyserviceinfo.h" +#include "qlowenergycharacteristicinfo.h" +#include <QPointer> + +#ifdef QT_BLUEZ_BLUETOOTH +class OrgBluezCharacteristicInterface; +#endif + +QT_BEGIN_NAMESPACE + +class QBluetoothUuid; +class QLowEnergyServiceInfo; +class QLowEnergyCharacteristicInfo; +class QLowEnergyProcess; + +class QLowEnergyServiceInfoPrivate: public QObject +{ + Q_OBJECT + friend class QLowEnergyControllerPrivate; + +public: + QLowEnergyServiceInfoPrivate(); +#ifdef QT_BLUEZ_BLUETOOTH + QLowEnergyServiceInfoPrivate(const QString &servicePath); +#endif + ~QLowEnergyServiceInfoPrivate(); + + void registerServiceWatcher(); + void unregisterServiceWatcher(); + bool valid(); + + QString serviceName; + + QBluetoothUuid uuid; + + QList<QLowEnergyCharacteristicInfo> characteristicList; + QLowEnergyServiceInfo::ServiceType serviceType; + bool connected; + QBluetoothDeviceInfo deviceInfo; +#ifdef QT_BLUEZ_BLUETOOTH + QString startingHandle; + QString endingHandle; + QString path; + QBluetoothAddress adapterAddress; +#endif + +#ifdef QT_QNX_BLUETOOTH + static void serviceConnected(const char*, const char*, int, int, short unsigned int, short unsigned int, short unsigned int, void*); + static void serviceUpdate(const char *, int , short unsigned int, short unsigned int, short unsigned int, void *); + static void serviceDisconnected(const char *, const char *, int, int, void *); + static void serviceNotification(int, short unsigned int, const char unsigned *, short unsigned int, void *); + //static void handleEvent(const int, const char *, const char *); +#endif + +Q_SIGNALS: + void finished(); + void connectedToService(const QBluetoothUuid &); + void error(const QBluetoothUuid &); + void disconnectedFromService(const QBluetoothUuid &); + +private: + QLowEnergyProcess *process; +#ifdef QT_BLUEZ_BLUETOOTH + OrgBluezCharacteristicInterface *characteristic; + int m_step; + int m_valueCounter; + int m_readCounter; +#endif + int m_instance; +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYSERVICEINFO_P_H diff --git a/src/bluetooth/qlowenergyserviceinfo_qnx.cpp b/src/bluetooth/qlowenergyserviceinfo_qnx.cpp new file mode 100644 index 00000000..5ab214de --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_qnx.cpp @@ -0,0 +1,268 @@ + +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QLoggingCategory> +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyprocess_p.h" +#include <btapi/btdevice.h> +#include <btapi/btgatt.h> +#include <btapi/btspp.h> +#include <btapi/btle.h> +#include <errno.h> +#include <QPointer> +#include "qnx/ppshelpers_p.h" + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_BT_QNX) + +void QLowEnergyServiceInfoPrivate::serviceConnected(const char *bdaddr, const char *service, int instance, int err, short unsigned int connInt, short unsigned int latency, short unsigned int superTimeout, void *userData) +{ + Q_UNUSED(latency); + Q_UNUSED(connInt); + Q_UNUSED(superTimeout); + QPointer<QLowEnergyServiceInfoPrivate> *classPointer = static_cast<QPointer<QLowEnergyServiceInfoPrivate> *>(userData); + QLowEnergyServiceInfoPrivate *p = classPointer->data(); + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] (service uuid, instance):" << p->uuid << instance; + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] Device address: " << bdaddr; + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] Device service: " << service; + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] Possible error: " << err; + if (err != 0) { + qCDebug(QT_BT_QNX) << "An error occurred in service connected callback: " << strerror(err); + p->errorString = QString::fromLatin1(strerror(err)); + p->error(p->uuid); + } + p->characteristicList.clear(); + bt_gatt_characteristic_t* data; + data = (bt_gatt_characteristic_t*) malloc(sizeof(bt_gatt_characteristic_t)); + if (0 == data) { + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] GATT characteristics: Not enough memory"; + bt_gatt_disconnect_instance(instance); + p->errorString = QStringLiteral("GATT characteristics: Not enough memory"); + p->error(p->uuid); + return; + } + + int num_characteristics = bt_gatt_characteristics_count(instance); + + if (num_characteristics > -1) { + qCDebug(QT_BT_QNX) << "Characteristics number: "<< num_characteristics; + bt_gatt_characteristic_t *allCharacteristicList; + + allCharacteristicList = (bt_gatt_characteristic_t*) malloc(num_characteristics * sizeof(bt_gatt_characteristic_t)); + if (0 == allCharacteristicList) { + qCDebug(QT_BT_QNX) <<" GATT characteristics: Not enough memory"; + bt_gatt_disconnect_instance(instance); + p->errorString = QStringLiteral("GATT characteristics: Not enough memory"); + p->error(p->uuid); + return; + } + + /* BEGIN WORKAROUND - Temporary fix to address race condition */ + int number = 0; + do { + number = bt_gatt_characteristics(instance, allCharacteristicList, num_characteristics); + } while ((number == -1) && (errno== EBUSY)); + //Using sub to subscribe notification callback only once + bool sub = false; + int characteristicListSize = number; + + for (int i = 0; i < characteristicListSize; i++) { + qCDebug(QT_BT_QNX) << "Characteristic: uuid,handle,value_handle, properties:" << allCharacteristicList[i].uuid << "," << allCharacteristicList[i].handle << "," << allCharacteristicList[i].value_handle << ", " << allCharacteristicList[i].properties; + QString charUuid = QString::fromLatin1(allCharacteristicList[i].uuid); + QString handleUuid; + handleUuid.setNum(allCharacteristicList[i].value_handle); + QBluetoothUuid characteristicUuid; + if (charUuid.toUShort(0,0) == 0) { + charUuid = charUuid.remove(0,2); + characteristicUuid = QBluetoothUuid(charUuid); + } + else + characteristicUuid = QBluetoothUuid(charUuid.toUShort(0,0)); + QVariantMap map; + QLowEnergyCharacteristicInfo characteristicInfo(characteristicUuid); + characteristicInfo.d_ptr->handle = handleUuid; + characteristicInfo.d_ptr->instance = instance; + characteristicInfo.d_ptr->characteristic = allCharacteristicList[i]; + characteristicInfo.d_ptr->permission = allCharacteristicList[i].properties; + map[QStringLiteral("uuid")] = characteristicUuid.toString(); + map[QStringLiteral("handle")] = handleUuid; + map[QStringLiteral("permission")] = characteristicInfo.d_ptr->permission; + characteristicInfo.d_ptr->properties = map; + characteristicInfo.d_ptr->readDescriptors(); + + characteristicInfo.d_ptr->readValue(); + //Subscribe only once since it is static function + if (sub == false) { + int rc = bt_gatt_reg_notifications(instance, &(characteristicInfo.d_ptr->serviceNotification)); + if (rc != 0) { + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] bt_gatt_reg_notifications failed." << errno << strerror(errno); + p->errorString = QString::fromLatin1(strerror(errno)); + p->error(p->uuid); + } + else + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] bt_gatt_reg_notifications was presumably OK"; + sub = true; + } + p->characteristicList.append(characteristicInfo); + + } + + if (allCharacteristicList != NULL) { + free(allCharacteristicList); + allCharacteristicList = NULL; + } + + /* END WORKAROUND */ + } + + p->connected = true; + qCDebug(QT_BT_QNX) << p; + emit p->connectedToService(p->uuid); + qCDebug(QT_BT_QNX) << "---------------------------------------------------------------------------------"; +} + +void QLowEnergyServiceInfoPrivate::serviceUpdate(const char *bdaddr, int instance, short unsigned int connInt, short unsigned int latency, short unsigned int superTimeout, void *userData) +{ + Q_UNUSED(latency); + Q_UNUSED(connInt); + Q_UNUSED(superTimeout); + Q_UNUSED(userData); + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + qCDebug(QT_BT_QNX) << "[SERVICE: Update] (instance):" << instance; + qCDebug(QT_BT_QNX) << "[SERVICE: Update] Device address: " << bdaddr; + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; +} + +void QLowEnergyServiceInfoPrivate::serviceDisconnected(const char *bdaddr, const char *service, int instance, int reason, void *userData) +{ + QPointer<QLowEnergyServiceInfoPrivate> *classPointer = static_cast<QPointer<QLowEnergyServiceInfoPrivate> *>(userData); + QLowEnergyServiceInfoPrivate *p = classPointer->data(); + emit p->disconnectedFromService(p->uuid); + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + qCDebug(QT_BT_QNX) << "[SERVICE: Disconnect] (service, instance, reason):" << service << instance << reason; + qCDebug(QT_BT_QNX) << "[SERVICE: Disconnect] Device address: " << bdaddr; + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + delete p; + delete classPointer; +} + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate(): + errorString(QString()), m_instance(0) +{ + qRegisterMetaType<QBluetoothUuid>("QBluetoothUuid"); +} + +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() +{ + +} + +void QLowEnergyServiceInfoPrivate::registerServiceWatcher() +{ + bt_gatt_callbacks_t gatt_callbacks = { &(this->serviceConnected), this->serviceDisconnected, this->serviceUpdate }; + errno=0; + process = process->instance(); + if (!process->isConnected()) { + qCDebug(QT_BT_QNX) << "[INIT] Init problem." << errno << strerror(errno); + errorString = QStringLiteral("Initialization of device falied. ") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + return; + } + + errno=0; + if (bt_gatt_init(&gatt_callbacks) < 0) { + qCDebug(QT_BT_QNX) << "[INIT] GAT Init problem." << errno << strerror(errno); + errorString = QStringLiteral("Callbacks initialization failed. ") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + return; + } + if (bt_le_init(0) != EOK) { + qWarning() << "LE initialization failure " << errno; + } + + QPointer<QLowEnergyServiceInfoPrivate> *classPointer = new QPointer<QLowEnergyServiceInfoPrivate>(this); + process->addPointer(classPointer->data()); + QString serviceUuid = uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (serviceUuid.contains(QStringLiteral("000000000000"))) + serviceUuid = QStringLiteral("0x") + serviceUuid.toUpper(); + else + serviceUuid = QStringLiteral("0x") + serviceUuid[4] + serviceUuid[5] + serviceUuid[6] + serviceUuid[7]; + errno=0; + bt_gatt_conn_parm_t conParm; + conParm.minConn = 0x30; + conParm.maxConn = 0x50; + conParm.latency = 0; + conParm.superTimeout = 50; + if (bt_gatt_connect_service(deviceInfo.address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData(), 0, &conParm, classPointer) < 0) { + qCDebug(QT_BT_QNX) << "[SERVICE] Connection to service failed." << errno << strerror(errno); + errorString = QStringLiteral("[SERVICE] Connection to service failed.") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + } + qCDebug(QT_BT_QNX) << "errno after connect: " << errno; +} + +void QLowEnergyServiceInfoPrivate::unregisterServiceWatcher() +{ + QString serviceUuid = uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (serviceUuid.contains(QStringLiteral("000000000000"))) + serviceUuid = QStringLiteral("0x") + serviceUuid.toUpper(); + else + serviceUuid = QStringLiteral("0x") + serviceUuid[4] + serviceUuid[5] + serviceUuid[6] + serviceUuid[7]; + if (bt_gatt_disconnect_service(deviceInfo.address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData()) < 0) { + qCDebug(QT_BT_QNX) << "[SERVICE] Disconnect service request failed. " << errno << strerror(errno); + emit error(uuid); + } else { + emit disconnectedFromService(uuid); + qCDebug(QT_BT_QNX) << "[SERVICE] Disconnected from service OK."; + } +} + +bool QLowEnergyServiceInfoPrivate::valid() +{ + return true; +} + +QT_END_NAMESPACE diff --git a/src/nfc/qnx/qnxnfcmanager.cpp b/src/nfc/qnx/qnxnfcmanager.cpp index d4736746..92152c26 100644 --- a/src/nfc/qnx/qnxnfcmanager.cpp +++ b/src/nfc/qnx/qnxnfcmanager.cpp @@ -44,6 +44,7 @@ #include <QMetaObject> #include "../qllcpsocket_qnx_p.h" #include <QCoreApplication> +#include <QStringList> QT_BEGIN_NAMESPACE diff --git a/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro b/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro index 43ca52ed..408628ea 100644 --- a/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro +++ b/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro @@ -4,3 +4,6 @@ CONFIG += testcase QT = core concurrent bluetooth testlib DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +qnx { + LIBS += -lbtapi +} diff --git a/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp b/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp index adc61199..6b99639e 100644 --- a/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp +++ b/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp @@ -52,6 +52,7 @@ QT_USE_NAMESPACE Q_DECLARE_METATYPE(QBluetoothDeviceInfo::ServiceClasses) Q_DECLARE_METATYPE(QBluetoothDeviceInfo::MajorDeviceClass) +Q_DECLARE_METATYPE(QBluetoothDeviceInfo::CoreConfiguration) class tst_QBluetoothDeviceInfo : public QObject { @@ -101,6 +102,7 @@ void tst_QBluetoothDeviceInfo::tst_construction_data() QTest::addColumn<QBluetoothDeviceInfo::ServiceClasses>("serviceClasses"); QTest::addColumn<QBluetoothDeviceInfo::MajorDeviceClass>("majorDeviceClass"); QTest::addColumn<quint8>("minorDeviceClass"); + QTest::addColumn<QBluetoothDeviceInfo::CoreConfiguration>("coreConfiguration"); // bits 12-8 Major // bits 7-2 Minor @@ -110,120 +112,144 @@ void tst_QBluetoothDeviceInfo::tst_construction_data() << quint32(0x000000) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::MiscellaneousDevice - << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous); + << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous) + << QBluetoothDeviceInfo::BaseRateCoreConfiguration; QTest::newRow("0x000100 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000100) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ComputerDevice - << quint8(QBluetoothDeviceInfo::UncategorizedComputer); + << quint8(QBluetoothDeviceInfo::UncategorizedComputer) + << QBluetoothDeviceInfo::BaseRateCoreConfiguration; QTest::newRow("0x000104 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000104) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ComputerDevice - << quint8(QBluetoothDeviceInfo::DesktopComputer); + << quint8(QBluetoothDeviceInfo::DesktopComputer) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000118 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000118) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ComputerDevice - << quint8(QBluetoothDeviceInfo::WearableComputer); + << quint8(QBluetoothDeviceInfo::WearableComputer) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000200 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000200) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::PhoneDevice - << quint8(QBluetoothDeviceInfo::UncategorizedPhone); + << quint8(QBluetoothDeviceInfo::UncategorizedPhone) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000204 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000204) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::PhoneDevice - << quint8(QBluetoothDeviceInfo::CellularPhone); + << quint8(QBluetoothDeviceInfo::CellularPhone) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000214 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000214) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::PhoneDevice - << quint8(QBluetoothDeviceInfo::CommonIsdnAccessPhone); + << quint8(QBluetoothDeviceInfo::CommonIsdnAccessPhone) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000300 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000300) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::LANAccessDevice - << quint8(QBluetoothDeviceInfo::NetworkFullService); + << quint8(QBluetoothDeviceInfo::NetworkFullService) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000320 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000320) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::LANAccessDevice - << quint8(QBluetoothDeviceInfo::NetworkLoadFactorOne); + << quint8(QBluetoothDeviceInfo::NetworkLoadFactorOne) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x0003E0 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x0003E0) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::LANAccessDevice - << quint8(QBluetoothDeviceInfo::NetworkNoService); + << quint8(QBluetoothDeviceInfo::NetworkNoService) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000400 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000400) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::AudioVideoDevice - << quint8(QBluetoothDeviceInfo::UncategorizedAudioVideoDevice); + << quint8(QBluetoothDeviceInfo::UncategorizedAudioVideoDevice) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000448 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000448) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::AudioVideoDevice - << quint8(QBluetoothDeviceInfo::GamingDevice); + << quint8(QBluetoothDeviceInfo::GamingDevice) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000500 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000500) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::PeripheralDevice - << quint8(QBluetoothDeviceInfo::UncategorizedPeripheral); + << quint8(QBluetoothDeviceInfo::UncategorizedPeripheral) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x0005D8 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x0005D8) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::PeripheralDevice - << quint8(QBluetoothDeviceInfo::KeyboardWithPointingDevicePeripheral | QBluetoothDeviceInfo::CardReaderPeripheral); + << quint8(QBluetoothDeviceInfo::KeyboardWithPointingDevicePeripheral | QBluetoothDeviceInfo::CardReaderPeripheral) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000600 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000600) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ImagingDevice - << quint8(QBluetoothDeviceInfo::UncategorizedImagingDevice); + << quint8(QBluetoothDeviceInfo::UncategorizedImagingDevice) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; QTest::newRow("0x000680 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000680) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ImagingDevice - << quint8(QBluetoothDeviceInfo::ImagePrinter); + << quint8(QBluetoothDeviceInfo::ImagePrinter) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x000700 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000700) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::WearableDevice - << quint8(QBluetoothDeviceInfo::UncategorizedWearableDevice); + << quint8(QBluetoothDeviceInfo::UncategorizedWearableDevice) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x000714 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000714) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::WearableDevice - << quint8(QBluetoothDeviceInfo::WearableGlasses); + << quint8(QBluetoothDeviceInfo::WearableGlasses) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x000800 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000800) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ToyDevice - << quint8(QBluetoothDeviceInfo::UncategorizedToy); + << quint8(QBluetoothDeviceInfo::UncategorizedToy) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x000814 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x000814) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::ToyDevice - << quint8(QBluetoothDeviceInfo::ToyGame); + << quint8(QBluetoothDeviceInfo::ToyGame) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x001f00 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x001f00) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::NoService) << QBluetoothDeviceInfo::UncategorizedDevice - << quint8(0); + << quint8(0) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x002000 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x002000) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::PositioningService) << QBluetoothDeviceInfo::MiscellaneousDevice - << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous); + << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0x100000 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0x100000) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::InformationService) << QBluetoothDeviceInfo::MiscellaneousDevice - << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous); + << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; QTest::newRow("0xFFE000 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" << quint32(0xFFE000) << QBluetoothDeviceInfo::ServiceClasses(QBluetoothDeviceInfo::AllServices) << QBluetoothDeviceInfo::MiscellaneousDevice - << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous); + << quint8(QBluetoothDeviceInfo::UncategorizedMiscellaneous) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; } void tst_QBluetoothDeviceInfo::tst_construction() @@ -241,6 +267,7 @@ void tst_QBluetoothDeviceInfo::tst_construction() QFETCH(QBluetoothDeviceInfo::ServiceClasses, serviceClasses); QFETCH(QBluetoothDeviceInfo::MajorDeviceClass, majorDeviceClass); QFETCH(quint8, minorDeviceClass); + QFETCH(QBluetoothDeviceInfo::CoreConfiguration, coreConfiguration); QBluetoothDeviceInfo deviceInfo(address, name, classOfDevice); @@ -251,9 +278,12 @@ void tst_QBluetoothDeviceInfo::tst_construction() QCOMPARE(deviceInfo.serviceClasses(), serviceClasses); QCOMPARE(deviceInfo.majorDeviceClass(), majorDeviceClass); QCOMPARE(deviceInfo.minorDeviceClass(), minorDeviceClass); + QCOMPARE(deviceInfo.coreConfiguration(), QBluetoothDeviceInfo::BaseRateCoreConfiguration); - QBluetoothDeviceInfo copyInfo(deviceInfo); + deviceInfo.setCoreConfiguration(coreConfiguration); + QCOMPARE(deviceInfo.coreConfiguration(), coreConfiguration); + QBluetoothDeviceInfo copyInfo(deviceInfo); QVERIFY(copyInfo.isValid()); QCOMPARE(copyInfo.address(), address); @@ -261,6 +291,7 @@ void tst_QBluetoothDeviceInfo::tst_construction() QCOMPARE(copyInfo.serviceClasses(), serviceClasses); QCOMPARE(copyInfo.majorDeviceClass(), majorDeviceClass); QCOMPARE(copyInfo.minorDeviceClass(), minorDeviceClass); + QCOMPARE(copyInfo.coreConfiguration(), coreConfiguration); } } @@ -277,8 +308,10 @@ void tst_QBluetoothDeviceInfo::tst_assignment() QFETCH(QBluetoothDeviceInfo::ServiceClasses, serviceClasses); QFETCH(QBluetoothDeviceInfo::MajorDeviceClass, majorDeviceClass); QFETCH(quint8, minorDeviceClass); + QFETCH(QBluetoothDeviceInfo::CoreConfiguration, coreConfiguration); QBluetoothDeviceInfo deviceInfo(address, name, classOfDevice); + deviceInfo.setCoreConfiguration(coreConfiguration); QVERIFY(deviceInfo.isValid()); @@ -292,6 +325,7 @@ void tst_QBluetoothDeviceInfo::tst_assignment() QCOMPARE(copyInfo.serviceClasses(), serviceClasses); QCOMPARE(copyInfo.majorDeviceClass(), majorDeviceClass); QCOMPARE(copyInfo.minorDeviceClass(), minorDeviceClass); + QCOMPARE(copyInfo.coreConfiguration(), coreConfiguration); } { @@ -308,6 +342,7 @@ void tst_QBluetoothDeviceInfo::tst_assignment() QCOMPARE(copyInfo.serviceClasses(), serviceClasses); QCOMPARE(copyInfo.majorDeviceClass(), majorDeviceClass); QCOMPARE(copyInfo.minorDeviceClass(), minorDeviceClass); + QCOMPARE(copyInfo.coreConfiguration(), coreConfiguration); } { @@ -333,6 +368,8 @@ void tst_QBluetoothDeviceInfo::tst_assignment() QCOMPARE(copyInfo2.majorDeviceClass(), majorDeviceClass); QCOMPARE(copyInfo1.minorDeviceClass(), minorDeviceClass); QCOMPARE(copyInfo2.minorDeviceClass(), minorDeviceClass); + QCOMPARE(copyInfo1.coreConfiguration(), coreConfiguration); + QCOMPARE(copyInfo2.coreConfiguration(), coreConfiguration); } { diff --git a/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro b/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro index 7b8ee74a..e678aa12 100644 --- a/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro +++ b/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro @@ -3,5 +3,8 @@ TARGET = tst_qbluetoothservicediscoveryagent CONFIG += testcase QT = core concurrent bluetooth testlib +qnx { + LIBS += -lbtapi +} DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp index 791bff8d..d7a6a6ef 100644 --- a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp +++ b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp @@ -51,11 +51,15 @@ #include <qbluetoothlocaldevice.h> #include <qbluetoothserver.h> #include <qbluetoothserviceinfo.h> +#include <qlowenergyserviceinfo.h> +#include <qlowenergycontroller.h> +#include <qlowenergycharacteristicinfo.h> QT_USE_NAMESPACE Q_DECLARE_METATYPE(QBluetoothDeviceInfo) Q_DECLARE_METATYPE(QBluetoothServiceDiscoveryAgent::Error) +Q_DECLARE_METATYPE(QLowEnergyServiceInfo) // Maximum time to for bluetooth device scan const int MaxScanTime = 5 * 60 * 1000; // 5 minutes in ms @@ -71,6 +75,7 @@ public: public slots: void deviceDiscoveryDebug(const QBluetoothDeviceInfo &info); void serviceDiscoveryDebug(const QBluetoothServiceInfo &info); + void leServiceDiscoveryDebug(const QLowEnergyServiceInfo &info); void serviceError(const QBluetoothServiceDiscoveryAgent::Error err); private slots: @@ -100,6 +105,7 @@ tst_QBluetoothServiceDiscoveryAgent::tst_QBluetoothServiceDiscoveryAgent() qRegisterMetaType<QBluetoothDeviceInfo>("QBluetoothDeviceInfo"); qRegisterMetaType<QBluetoothServiceInfo>("QBluetoothServiceInfo"); + qRegisterMetaType<QLowEnergyServiceInfo>("QLowEnergyServiceInfo"); qRegisterMetaType<QList<QBluetoothUuid> >("QList<QBluetoothUuid>"); qRegisterMetaType<QBluetoothServiceDiscoveryAgent::Error>("QBluetoothServiceDiscoveryAgent::Error"); qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>("QBluetoothDeviceDiscoveryAgent::Error"); @@ -180,6 +186,14 @@ void tst_QBluetoothServiceDiscoveryAgent::serviceDiscoveryDebug(const QBluetooth qDebug() << "\tRFCOMM server channel:" << info.serverChannel(); } +void tst_QBluetoothServiceDiscoveryAgent::leServiceDiscoveryDebug(const QLowEnergyServiceInfo &info) +{ + qDebug() << "Discovered LE service on" + << info.device().name() << info.device().address().toString(); + qDebug() << "\tService name:" << info.serviceName(); + qDebug() << "\tUUID:" << info.serviceUuid(); +} + static void dumpAttributeVariant(const QVariant &var, const QString indent) { if (!var.isValid()) { @@ -316,7 +330,7 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryAdapters() QVERIFY(serviceInfo.registerService()); QVERIFY(server.isListening()); - qDebug() << "Scanning address" << addresses[0].toString(); + qDebug() << "Scanning address " << addresses[0].toString(); QBluetoothServiceDiscoveryAgent discoveryAgent(addresses[1]); bool setAddress = discoveryAgent.setRemoteAddress(addresses[0]); @@ -362,9 +376,9 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery() QFETCH(QBluetoothDeviceInfo, deviceInfo); QFETCH(QList<QBluetoothUuid>, uuidFilter); QFETCH(QBluetoothServiceDiscoveryAgent::Error, serviceDiscoveryError); - + QLowEnergyController leController; + bool leDevice = false; QBluetoothLocalDevice localDevice; - qDebug() << "Scanning address" << deviceInfo.address().toString(); QBluetoothServiceDiscoveryAgent discoveryAgent(localDevice.address()); bool setAddress = discoveryAgent.setRemoteAddress(deviceInfo.address()); @@ -384,11 +398,16 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery() QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished())); QSignalSpy errorSpy(&discoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error))); QSignalSpy discoveredSpy(&discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo))); + QSignalSpy leDiscoveredSpy(&discoveryAgent, SIGNAL(serviceDiscovered(QLowEnergyServiceInfo))); // connect(&discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), // this, SLOT(serviceDiscoveryDebug(QBluetoothServiceInfo))); +// connect(&discoveryAgent, SIGNAL(serviceDiscovered(QLowEnergyServiceInfo)), +// this, SLOT(leServiceDiscoveryDebug(QLowEnergyServiceInfo))); connect(&discoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), this, SLOT(serviceError(QBluetoothServiceDiscoveryAgent::Error))); + QSignalSpy leConnectedSpy(&leController, SIGNAL(connected(QLowEnergyServiceInfo))); + discoveryAgent.start(); QVERIFY(discoveryAgent.isActive()); @@ -446,6 +465,79 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery() } } + int leCounter = 0; + while (!leDiscoveredSpy.isEmpty()) { + const QVariant v = leDiscoveredSpy.takeFirst().at(0); + if (v.userType() == qMetaTypeId<QLowEnergyServiceInfo>()) + { + const QLowEnergyServiceInfo info = + *reinterpret_cast<const QLowEnergyServiceInfo*>(v.constData()); + + QVERIFY(info.isValid()); + if (info.device().coreConfiguration() == QBluetoothDeviceInfo::LowEnergyCoreConfiguration || info.device().coreConfiguration() == QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration) { + leDevice = true; + leController.connectToService(info); + leCounter ++; + } + + } else { + QFAIL("Unknown type returned by service discovery"); + } + + } + + // In case it is not LE device next steps will be skipped. + // In case of regular Bluetooth devices there is no need to go in to the loop below. + if (leDevice) { + scanTime = MaxScanTime; + while (leConnectedSpy.count() != leCounter && scanTime > 0) { + QTest::qWait(1000); + scanTime -= 1000; + } + int leTestCounter = 0; + QSignalSpy leDisonnectedSpy(&leController, SIGNAL(disconnected(QLowEnergyServiceInfo))); + while (!leConnectedSpy.isEmpty()) { + const QVariant v = leConnectedSpy.takeFirst().at(0); + if (v.userType() == qMetaTypeId<QLowEnergyServiceInfo>()) + { + const QLowEnergyServiceInfo info = + *reinterpret_cast<const QLowEnergyServiceInfo*>(v.constData()); + + QVERIFY(info.isValid()); + QCOMPARE(leController.errorString(), QString()); + QVERIFY((info.characteristics().size() > 0)); + qDebug() << "LE Service Connected: " << info.serviceName() << info.serviceUuid(); + leTestCounter++; + for (int i = 0; i < info.characteristics().size(); i++) + QVERIFY(info.characteristics().at(i).isValid()); + leController.disconnectFromService(info); + } else { + QFAIL("Unknown type returned by service discovery"); + } + + } + QCOMPARE(leCounter, leTestCounter); + scanTime = MaxScanTime; + while (leDisonnectedSpy.count() != leTestCounter && scanTime > 0) { + QTest::qWait(1000); + scanTime -= 1000; + } + + while (!leDisonnectedSpy.isEmpty()) { + const QVariant v = leDisonnectedSpy.takeFirst().at(0); + if (v.userType() == qMetaTypeId<QLowEnergyServiceInfo>()) + { + const QLowEnergyServiceInfo info = + *reinterpret_cast<const QLowEnergyServiceInfo*>(v.constData()); + + QVERIFY(info.isValid()); + qDebug() << "LE Service Disconnected: " << info.serviceName() << info.serviceUuid(); + } else { + QFAIL("Unknown type returned by service discovery"); + } + + } + } QVERIFY(discoveryAgent.discoveredServices().count() != 0); discoveryAgent.clear(); diff --git a/tests/auto/qlowenergycharacteristicinfo/qlowenergycharacteristicinfo.pro b/tests/auto/qlowenergycharacteristicinfo/qlowenergycharacteristicinfo.pro new file mode 100644 index 00000000..aa4d5842 --- /dev/null +++ b/tests/auto/qlowenergycharacteristicinfo/qlowenergycharacteristicinfo.pro @@ -0,0 +1,9 @@ +SOURCES += tst_qlowenergycharacteristicinfo.cpp +TARGET = tst_qlowenergycharacteristicinfo +CONFIG += testcase + +QT = core bluetooth testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +qnx { + LIBS += -lbtapi +} diff --git a/tests/auto/qlowenergycharacteristicinfo/tst_qlowenergycharacteristicinfo.cpp b/tests/auto/qlowenergycharacteristicinfo/tst_qlowenergycharacteristicinfo.cpp new file mode 100644 index 00000000..fc8095bf --- /dev/null +++ b/tests/auto/qlowenergycharacteristicinfo/tst_qlowenergycharacteristicinfo.cpp @@ -0,0 +1,215 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QUuid> + +#include <QDebug> + +#include <qbluetoothdeviceinfo.h> +#include <qlowenergycharacteristicinfo.h> +#include <qbluetoothaddress.h> +#include <qbluetoothlocaldevice.h> +#include <qbluetoothuuid.h> + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QUuid) +Q_DECLARE_METATYPE(QLowEnergyCharacteristicInfo) +Q_DECLARE_METATYPE(QBluetoothUuid::CharacteristicId) + +class tst_QLowEnergyCharacteristicInfo : public QObject +{ + Q_OBJECT + +public: + tst_QLowEnergyCharacteristicInfo(); + ~tst_QLowEnergyCharacteristicInfo(); + +private slots: + void initTestCase(); + void tst_construction(); + void tst_assignment_data(); + void tst_assignment(); +}; + +tst_QLowEnergyCharacteristicInfo::tst_QLowEnergyCharacteristicInfo() +{ +} + +tst_QLowEnergyCharacteristicInfo::~tst_QLowEnergyCharacteristicInfo() +{ +} + +void tst_QLowEnergyCharacteristicInfo::initTestCase() +{ + // start Bluetooth if not started + QBluetoothLocalDevice *device = new QBluetoothLocalDevice(); + device->powerOn(); + delete device; +} + +void tst_QLowEnergyCharacteristicInfo::tst_construction() +{ + const QBluetoothUuid characteristicUuid(QBluetoothUuid::HIDControlPoint); + const QBluetoothUuid alternateCharacteristicUuid(QBluetoothUuid::TemperatureMeasurement); + + { + QLowEnergyCharacteristicInfo characteristicInfo; + + QVERIFY(!characteristicInfo.isValid()); + QCOMPARE(characteristicInfo.uuid().toString(), QBluetoothUuid().toString()); + QCOMPARE(characteristicInfo.value(), QByteArray()); + QCOMPARE(characteristicInfo.permissions(), 0); + QCOMPARE(characteristicInfo.handle(), QString("0x0000")); + QCOMPARE(characteristicInfo.name(), QString("")); + QCOMPARE(characteristicInfo.isNotificationCharacteristic(), false); + QCOMPARE(characteristicInfo.descriptors().count(), 0); + } + + { + QLowEnergyCharacteristicInfo characteristicInfo(characteristicUuid); + + QVERIFY(!characteristicInfo.isValid()); + + QCOMPARE(characteristicInfo.uuid().toString(), characteristicUuid.toString()); + QCOMPARE(characteristicInfo.value(), QByteArray()); + QCOMPARE(characteristicInfo.permissions(), 0); + QCOMPARE(characteristicInfo.handle(), QString("0x0000")); + QCOMPARE(characteristicInfo.name(), QString("")); + QCOMPARE(characteristicInfo.isNotificationCharacteristic(), false); + QCOMPARE(characteristicInfo.descriptors().count(), 0); + + QLowEnergyCharacteristicInfo copyInfo(characteristicInfo); + + QVERIFY(!copyInfo.isValid()); + + QCOMPARE(copyInfo.uuid().toString(), characteristicUuid.toString()); + + copyInfo = QLowEnergyCharacteristicInfo(alternateCharacteristicUuid); + QCOMPARE(copyInfo.uuid().toString(), alternateCharacteristicUuid.toString()); + + QCOMPARE(copyInfo.handle(), QString("0x0000")); + QCOMPARE(copyInfo.value(), QByteArray()); + QCOMPARE(copyInfo.permissions(), 0); + QCOMPARE(copyInfo.handle(), QString("0x0000")); + QCOMPARE(copyInfo.name(), QString("")); + QCOMPARE(copyInfo.isNotificationCharacteristic(), false); + QCOMPARE(copyInfo.descriptors().count(), 0); + copyInfo.writeValue("test"); + } +} + +void tst_QLowEnergyCharacteristicInfo::tst_assignment_data() +{ + QTest::addColumn<QBluetoothUuid>("characteristicClassUuid"); + + QTest::newRow("0x000000 COD") << QBluetoothUuid(QBluetoothUuid::AlertCategoryID); + QTest::newRow("0x001000 COD") << QBluetoothUuid(QBluetoothUuid::AlertCategoryIDBitMask); + QTest::newRow("0x002000 COD") << QBluetoothUuid(QBluetoothUuid::AlertLevel); + QTest::newRow("0x003000 COD") << QBluetoothUuid(QBluetoothUuid::AlertNotificationControlPoint); + QTest::newRow("0x004000 COD") << QBluetoothUuid(QBluetoothUuid::AlertStatus); + QTest::newRow("0x005000 COD") << QBluetoothUuid(QBluetoothUuid::Appearance); + QTest::newRow("0x006000 COD") << QBluetoothUuid(QBluetoothUuid::CSCFeature); + QTest::newRow("0x007000 COD") << QBluetoothUuid(QBluetoothUuid::CSCMeasurement); + QTest::newRow("0x008000 COD") << QBluetoothUuid(QBluetoothUuid::CurrentTime); + QTest::newRow("0x009000 COD") << QBluetoothUuid(QBluetoothUuid::DateTime); + QTest::newRow("0x010000 COD") << QBluetoothUuid(QBluetoothUuid::DayOfWeek); + QTest::newRow("0x011000 COD") << QBluetoothUuid(QBluetoothUuid::DeviceName); + QTest::newRow("0x012000 COD") << QBluetoothUuid(QBluetoothUuid::DSTOffset); + QTest::newRow("0x013000 COD") << QBluetoothUuid(QBluetoothUuid::ExactTime256); + QTest::newRow("0x014000 COD") << QBluetoothUuid(QBluetoothUuid::HeartRateControlPoint); + QTest::newRow("0x015000 COD") << QBluetoothUuid(QBluetoothUuid::IntermediateCuffPressure); + QTest::newRow("0x016000 COD") << QBluetoothUuid(QBluetoothUuid::Navigation); + QTest::newRow("0x017000 COD") << QBluetoothUuid(QBluetoothUuid::NewAlert); + QTest::newRow("0x018000 COD") << QBluetoothUuid(QBluetoothUuid::PeripheralPreferredConnectionParameters); +} + +void tst_QLowEnergyCharacteristicInfo::tst_assignment() +{ + QFETCH(QBluetoothUuid, characteristicClassUuid); + + QLowEnergyCharacteristicInfo characteristicInfo(characteristicClassUuid); + + QVERIFY(!characteristicInfo.isValid()); + + { + QLowEnergyCharacteristicInfo copyInfo = characteristicInfo; + + QVERIFY(!copyInfo.isValid()); + + QCOMPARE(copyInfo.uuid(), characteristicClassUuid); + QCOMPARE(copyInfo.value(), QByteArray()); + } + + { + QLowEnergyCharacteristicInfo copyInfo; + + QVERIFY(!copyInfo.isValid()); + + copyInfo = characteristicInfo; + + QVERIFY(!copyInfo.isValid()); + + QCOMPARE(copyInfo.uuid(), characteristicClassUuid); + } + + { + QLowEnergyCharacteristicInfo copyInfo1; + QLowEnergyCharacteristicInfo copyInfo2; + + QVERIFY(!copyInfo1.isValid()); + QVERIFY(!copyInfo2.isValid()); + + copyInfo1 = copyInfo2 = characteristicInfo; + + QVERIFY(!copyInfo1.isValid()); + QVERIFY(!copyInfo2.isValid()); + //QVERIFY(QLowEnergyCharacteristicInfo() != copyInfo1); + + QCOMPARE(copyInfo1.uuid(), characteristicClassUuid); + QCOMPARE(copyInfo2.uuid(), characteristicClassUuid); + } +} + +QTEST_MAIN(tst_QLowEnergyCharacteristicInfo) + +#include "tst_qlowenergycharacteristicinfo.moc" diff --git a/tests/auto/qlowenergydescriptorinfo/qlowenergydescriptorinfo.pro b/tests/auto/qlowenergydescriptorinfo/qlowenergydescriptorinfo.pro new file mode 100644 index 00000000..f25272a7 --- /dev/null +++ b/tests/auto/qlowenergydescriptorinfo/qlowenergydescriptorinfo.pro @@ -0,0 +1,9 @@ +SOURCES += tst_qlowenergydescriptorinfo.cpp +TARGET = tst_qlowenergydescriptorinfo +CONFIG += testcase + +QT = core bluetooth testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +qnx { + LIBS += -lbtapi +} diff --git a/tests/auto/qlowenergydescriptorinfo/tst_qlowenergydescriptorinfo.cpp b/tests/auto/qlowenergydescriptorinfo/tst_qlowenergydescriptorinfo.cpp new file mode 100644 index 00000000..d3abcedf --- /dev/null +++ b/tests/auto/qlowenergydescriptorinfo/tst_qlowenergydescriptorinfo.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QUuid> + +#include <QDebug> + +#include <qbluetoothdeviceinfo.h> +#include <qlowenergydescriptorinfo.h> +#include <qbluetoothlocaldevice.h> +#include "qbluetoothuuid.h" + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QUuid) +Q_DECLARE_METATYPE(QBluetoothUuid::DescriptorID) + +class tst_QLowEnergyDescriptorInfo : public QObject +{ + Q_OBJECT + +public: + tst_QLowEnergyDescriptorInfo(); + ~tst_QLowEnergyDescriptorInfo(); + +private slots: + void initTestCase(); + void tst_construction(); + void tst_assignment_data(); + void tst_assignment(); +}; + +tst_QLowEnergyDescriptorInfo::tst_QLowEnergyDescriptorInfo() +{ +} + +tst_QLowEnergyDescriptorInfo::~tst_QLowEnergyDescriptorInfo() +{ +} + +void tst_QLowEnergyDescriptorInfo::initTestCase() +{ + // start Bluetooth if not started + QBluetoothLocalDevice *device = new QBluetoothLocalDevice(); + device->powerOn(); + delete device; +} + +void tst_QLowEnergyDescriptorInfo::tst_construction() +{ + const QBluetoothUuid descriptorUuid(QString("0x2902").toUShort(0,0)); + const QBluetoothUuid alternateDescriptorUuid(QString("0x2906").toUShort(0,0)); + + { + QLowEnergyDescriptorInfo descriptorInfo = QLowEnergyDescriptorInfo(QBluetoothUuid()); + + QCOMPARE(descriptorInfo.uuid(), QBluetoothUuid()); + QCOMPARE(descriptorInfo.value(), QByteArray()); + QCOMPARE(descriptorInfo.properties(), QVariantMap()); + QCOMPARE(descriptorInfo.handle(), QString("0x0000")); + QCOMPARE(descriptorInfo.name(), QString("")); + } + + { + QLowEnergyDescriptorInfo descriptorInfo(descriptorUuid); + + QCOMPARE(descriptorInfo.uuid().toString(), descriptorUuid.toString()); + + QLowEnergyDescriptorInfo copyInfo = descriptorInfo; + + QCOMPARE(copyInfo.uuid().toString(), descriptorUuid.toString()); + + copyInfo = QLowEnergyDescriptorInfo(alternateDescriptorUuid); + QCOMPARE(copyInfo.uuid().toString(), alternateDescriptorUuid.toString()); + + QCOMPARE(copyInfo.uuid(), QBluetoothUuid()); + QCOMPARE(copyInfo.value(), QByteArray()); + QCOMPARE(copyInfo.properties(), QVariantMap()); + QCOMPARE(copyInfo.handle(), QString("0x0000")); + QCOMPARE(copyInfo.name(), QString("")); + + } +} + +void tst_QLowEnergyDescriptorInfo::tst_assignment_data() +{ + QTest::addColumn<QBluetoothUuid>("descriptorClassUuid"); + + QTest::newRow("0x000000 COD") << QBluetoothUuid(QString("0x2901").toUShort(0,0)); + QTest::newRow("0x001000 COD") << QBluetoothUuid(QString("0x2902").toUShort(0,0)); + QTest::newRow("0x002000 COD") << QBluetoothUuid(QString("0x2903").toUShort(0,0)); + QTest::newRow("0x003000 COD") << QBluetoothUuid(QString("0x2904").toUShort(0,0)); + QTest::newRow("0x004000 COD") << QBluetoothUuid(QString("0x2905").toUShort(0,0)); + QTest::newRow("0x005000 COD") << QBluetoothUuid(QString("0x2906").toUShort(0,0)); + QTest::newRow("0x006000 COD") << QBluetoothUuid(QString("0x2907").toUShort(0,0)); + QTest::newRow("0x007000 COD") << QBluetoothUuid(QString("0x2908").toUShort(0,0)); + QTest::newRow("0x008000 COD") << QBluetoothUuid(QString("0x2900").toUShort(0,0)); +} + +void tst_QLowEnergyDescriptorInfo::tst_assignment() +{ + QFETCH(QBluetoothUuid, descriptorClassUuid); + + QLowEnergyDescriptorInfo descriptorInfo(descriptorClassUuid); + + + { + QLowEnergyDescriptorInfo copyInfo = descriptorInfo; + + QCOMPARE(copyInfo.uuid(), descriptorClassUuid); + QCOMPARE(copyInfo.value(), QByteArray()); + } + + { + QLowEnergyDescriptorInfo copyInfo = QLowEnergyDescriptorInfo(QBluetoothUuid()); + + copyInfo = descriptorInfo; + + QCOMPARE(copyInfo.uuid(), descriptorClassUuid); + } + + { + QLowEnergyDescriptorInfo copyInfo1 = QLowEnergyDescriptorInfo(QBluetoothUuid()); + QLowEnergyDescriptorInfo copyInfo2 = QLowEnergyDescriptorInfo(QBluetoothUuid()); + + copyInfo1 = copyInfo2 = descriptorInfo; + + QCOMPARE(copyInfo1.uuid(), descriptorClassUuid); + QCOMPARE(copyInfo2.uuid(), descriptorClassUuid); + } + +} + +QTEST_MAIN(tst_QLowEnergyDescriptorInfo) + +#include "tst_qlowenergydescriptorinfo.moc" + diff --git a/tests/auto/qlowenergyserviceinfo/qlowenergyserviceinfo.pro b/tests/auto/qlowenergyserviceinfo/qlowenergyserviceinfo.pro new file mode 100644 index 00000000..3fa99d76 --- /dev/null +++ b/tests/auto/qlowenergyserviceinfo/qlowenergyserviceinfo.pro @@ -0,0 +1,9 @@ +SOURCES += tst_qlowenergyserviceinfo.cpp +TARGET = tst_qlowenergyserviceinfo +CONFIG += testcase + +QT = core bluetooth testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +qnx { + LIBS += -lbtapi +} diff --git a/tests/auto/qlowenergyserviceinfo/tst_qlowenergyserviceinfo.cpp b/tests/auto/qlowenergyserviceinfo/tst_qlowenergyserviceinfo.cpp new file mode 100644 index 00000000..fc3ba25d --- /dev/null +++ b/tests/auto/qlowenergyserviceinfo/tst_qlowenergyserviceinfo.cpp @@ -0,0 +1,277 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QUuid> + +#include <QDebug> + +#include <qbluetoothdeviceinfo.h> +#include <qlowenergyserviceinfo.h> +#include <qbluetoothaddress.h> +#include <qbluetoothlocaldevice.h> +#include <qbluetoothuuid.h> + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QUuid) +Q_DECLARE_METATYPE(QLowEnergyServiceInfo::ServiceType) +Q_DECLARE_METATYPE(QBluetoothDeviceInfo::CoreConfiguration) +Q_DECLARE_METATYPE(QLowEnergyServiceInfo) +Q_DECLARE_METATYPE(QBluetoothUuid::ServiceClassUuid) + +class tst_QLowEnergyServiceInfo : public QObject +{ + Q_OBJECT + +public: + tst_QLowEnergyServiceInfo(); + ~tst_QLowEnergyServiceInfo(); + +private slots: + void initTestCase(); + void tst_construction(); + void tst_assignment_data(); + void tst_assignment(); +}; + +tst_QLowEnergyServiceInfo::tst_QLowEnergyServiceInfo() +{ +} + +tst_QLowEnergyServiceInfo::~tst_QLowEnergyServiceInfo() +{ +} + +void tst_QLowEnergyServiceInfo::initTestCase() +{ + // start Bluetooth if not started + QBluetoothLocalDevice *device = new QBluetoothLocalDevice(); + device->powerOn(); + delete device; +} + +void tst_QLowEnergyServiceInfo::tst_construction() +{ + const QBluetoothUuid serviceUuid(QBluetoothUuid::HeartRate); + const QBluetoothUuid alternateServiceUuid(QBluetoothUuid::BatteryService); + const QBluetoothDeviceInfo deviceInfo(QBluetoothAddress("001122334455"), "Test Device", 0); + const QBluetoothDeviceInfo alternatedeviceInfo(QBluetoothAddress("554433221100"), "Test Device2", 0); + + { + QLowEnergyServiceInfo serviceInfo; + + QVERIFY(!serviceInfo.isValid()); + QCOMPARE(serviceInfo.serviceName(), QString()); + QCOMPARE(serviceInfo.serviceUuid().toString(), QBluetoothUuid().toString()); + QCOMPARE(serviceInfo.serviceType(), QLowEnergyServiceInfo::PrimaryService); + QCOMPARE(serviceInfo.isConnected(), false); + QCOMPARE(serviceInfo.characteristics().size(), 0); + QCOMPARE(serviceInfo.device(), QBluetoothDeviceInfo()); + } + + { + QLowEnergyServiceInfo serviceInfo(serviceUuid); + serviceInfo.setDevice(deviceInfo); + + QVERIFY(serviceInfo.isValid()); + + QCOMPARE(serviceInfo.serviceUuid().toString(), serviceUuid.toString()); + QCOMPARE(serviceInfo.device().address(), deviceInfo.address()); + + QLowEnergyServiceInfo copyInfo(serviceInfo); + + QVERIFY(copyInfo.isValid()); + + QCOMPARE(copyInfo.serviceUuid().toString(), serviceUuid.toString()); + QCOMPARE(copyInfo.device().address(), deviceInfo.address()); + + + copyInfo = QLowEnergyServiceInfo(alternateServiceUuid); + copyInfo.setDevice(alternatedeviceInfo); + QCOMPARE(copyInfo.serviceUuid(), alternateServiceUuid); + + QCOMPARE(copyInfo.device().address(), alternatedeviceInfo.address()); + + } +} + +void tst_QLowEnergyServiceInfo::tst_assignment_data() +{ + QTest::addColumn<QBluetoothAddress>("address"); + QTest::addColumn<QString>("name"); + QTest::addColumn<quint32>("classOfDevice"); + QTest::addColumn<QBluetoothUuid>("serviceClassUuid"); + QTest::addColumn<QLowEnergyServiceInfo::ServiceType>("serviceType"); + QTest::addColumn<QBluetoothDeviceInfo::CoreConfiguration>("coreConfiguration"); + + // bits 12-8 Major + // bits 7-2 Minor + // bits 1-0 0 + + QTest::newRow("0x000000 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000000) + << QBluetoothUuid(QBluetoothUuid::GenericAccess) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; + QTest::newRow("0x000100 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000100) + << QBluetoothUuid(QBluetoothUuid::GenericAttribute) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; + QTest::newRow("0x000104 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000104) + << QBluetoothUuid(QBluetoothUuid::HeartRate) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; + QTest::newRow("0x000118 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000118) + << QBluetoothUuid(QBluetoothUuid::CyclingSpeedAndCadence) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration; + QTest::newRow("0x000200 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000200) + << QBluetoothUuid(QBluetoothUuid::CyclingPower) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; + QTest::newRow("0x000204 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000204) + << QBluetoothUuid(QBluetoothUuid::ScanParameters) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; + QTest::newRow("0x000214 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000214) + << QBluetoothUuid(QBluetoothUuid::DeviceInformation) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; + QTest::newRow("0x000300 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000300) + << QBluetoothUuid(QBluetoothUuid::CurrentTimeService) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; + QTest::newRow("0x000320 COD") << QBluetoothAddress("000000000000") << "My Bluetooth Device" + << quint32(0x000320) + << QBluetoothUuid(QBluetoothUuid::LocationAndNavigation) + << QLowEnergyServiceInfo::ServiceType(QLowEnergyServiceInfo::PrimaryService) + << QBluetoothDeviceInfo::LowEnergyCoreConfiguration; +} + +void tst_QLowEnergyServiceInfo::tst_assignment() +{ + QFETCH(QBluetoothAddress, address); + QFETCH(QString, name); + QFETCH(quint32, classOfDevice); + QFETCH(QBluetoothUuid, serviceClassUuid); + QFETCH(QLowEnergyServiceInfo::ServiceType, serviceType); + QFETCH(QBluetoothDeviceInfo::CoreConfiguration, coreConfiguration); + + QBluetoothDeviceInfo deviceInfo(address, name, classOfDevice); + deviceInfo.setCoreConfiguration(coreConfiguration); + QCOMPARE(deviceInfo.coreConfiguration(), coreConfiguration); + + QLowEnergyServiceInfo serviceInfo(serviceClassUuid); + serviceInfo.setDevice(deviceInfo); + QCOMPARE(serviceInfo.device(), deviceInfo); + + QVERIFY(serviceInfo.isValid()); + + { + QLowEnergyServiceInfo copyInfo = serviceInfo; + + QVERIFY(copyInfo.isValid()); + + QCOMPARE(copyInfo.device().address(), address); + QCOMPARE(copyInfo.serviceUuid(), serviceClassUuid); + QCOMPARE(copyInfo.device().coreConfiguration(), coreConfiguration); + QCOMPARE(copyInfo.serviceType(), serviceType); + QCOMPARE(copyInfo.isConnected(), false); + QCOMPARE(copyInfo.characteristics().size(), 0); + QCOMPARE(copyInfo.device(), deviceInfo); + } + + { + QLowEnergyServiceInfo copyInfo; + + QVERIFY(!copyInfo.isValid()); + + copyInfo = serviceInfo; + + QVERIFY(copyInfo.isValid()); + + QCOMPARE(copyInfo.device().address(), address); + QCOMPARE(copyInfo.serviceUuid(), serviceClassUuid); + QCOMPARE(copyInfo.device().coreConfiguration(), coreConfiguration); + QCOMPARE(copyInfo.serviceType(), serviceType); + } + + { + QLowEnergyServiceInfo copyInfo1; + QLowEnergyServiceInfo copyInfo2; + + QVERIFY(!copyInfo1.isValid()); + QVERIFY(!copyInfo2.isValid()); + + copyInfo1 = copyInfo2 = serviceInfo; + + QVERIFY(copyInfo1.isValid()); + QVERIFY(copyInfo2.isValid()); + //QVERIFY(QLowEnergyServiceInfo() != copyInfo1); + + QCOMPARE(copyInfo1.device().address(), address); + QCOMPARE(copyInfo2.device().address(), address); + QCOMPARE(copyInfo1.serviceUuid(), serviceClassUuid); + QCOMPARE(copyInfo2.serviceUuid(), serviceClassUuid); + QCOMPARE(copyInfo1.serviceType(), serviceType); + QCOMPARE(copyInfo2.serviceType(), serviceType); + QCOMPARE(copyInfo1.device().coreConfiguration(), coreConfiguration); + QCOMPARE(copyInfo2.device().coreConfiguration(), coreConfiguration); + QCOMPARE(copyInfo1.isConnected(), false); + QCOMPARE(copyInfo2.isConnected(), false); + QCOMPARE(copyInfo1.characteristics().size(), 0); + QCOMPARE(copyInfo2.characteristics().size(), 0); + QCOMPARE(copyInfo1.device(), deviceInfo); + QCOMPARE(copyInfo2.device(), deviceInfo); + } +} + +QTEST_MAIN(tst_QLowEnergyServiceInfo) + +#include "tst_qlowenergyserviceinfo.moc" diff --git a/tests/bttestui/btlocaldevice.cpp b/tests/bttestui/btlocaldevice.cpp index 3a9b52b5..148ba1aa 100644 --- a/tests/bttestui/btlocaldevice.cpp +++ b/tests/bttestui/btlocaldevice.cpp @@ -80,6 +80,8 @@ BtLocalDevice::BtLocalDevice(QObject *parent) : serviceAgent = new QBluetoothServiceDiscoveryAgent(this); connect(serviceAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), this, SLOT(serviceDiscovered(QBluetoothServiceInfo))); + connect(serviceAgent, SIGNAL(serviceDiscovered(QLowEnergyServiceInfo)), + this, SLOT(leServiceDiscovered(QLowEnergyServiceInfo))); connect(serviceAgent, SIGNAL(finished()), this, SLOT(serviceDiscoveryFinished())); connect(serviceAgent, SIGNAL(canceled()), @@ -271,11 +273,11 @@ void BtLocalDevice::stopServiceDiscovery() void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info) { - QString classIds; - foreach (const QBluetoothUuid uuid, info.serviceClassUuids()) - classIds += uuid.toString() + QLatin1Char(' '); + QStringList classIds; + foreach (const QBluetoothUuid &uuid, info.serviceClassUuids()) + classIds.append(uuid.toString()); qDebug() << "$$ Found new service" << info.device().address().toString() - << info.serviceUuid() << info.serviceName() << classIds; + << info.serviceUuid() << info.serviceName() << info.serviceDescription() << classIds; if (info.serviceUuid() == QBluetoothUuid(QString(TEST_SERVICE_UUID)) || info.serviceClassUuids().contains(QBluetoothUuid(QString(TEST_SERVICE_UUID)))) @@ -296,6 +298,12 @@ void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info) } } +void BtLocalDevice::leServiceDiscovered(const QLowEnergyServiceInfo &info) +{ + qDebug() << "$$ Found new BTLE service" << info.device().address().toString() + << info.serviceUuid() << info.serviceName(); +} + void BtLocalDevice::serviceDiscoveryFinished() { qDebug() << "###### Service Discovery Finished"; diff --git a/tests/bttestui/btlocaldevice.h b/tests/bttestui/btlocaldevice.h index 759599b7..a9571ecc 100644 --- a/tests/bttestui/btlocaldevice.h +++ b/tests/bttestui/btlocaldevice.h @@ -89,6 +89,7 @@ public slots: void startServiceDiscovery(bool isMinimalDiscovery); void stopServiceDiscovery(); void serviceDiscovered(const QBluetoothServiceInfo &info); + void leServiceDiscovered(const QLowEnergyServiceInfo &leInfo); void serviceDiscoveryFinished(); void serviceDiscoveryCanceled(); void serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error error); |