diff options
author | Nedim Hadzic <nhadzic@blackberry.com> | 2014-03-12 13:53:59 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-14 12:50:51 +0100 |
commit | 140e8172f7cb8b2482d626aaf3af2f1d032070ea (patch) | |
tree | a17debeace5a4901301f6bf1773c424a14bede4a /src | |
parent | 4439541b05ae88a30159a5597d40f569328783ca (diff) |
QNX BLE communication moved to controller class
Moving communication with device to QLowEnergyController class.
Change-Id: Id783d3aac81c215fbda7c1390bb2abf8ecd2fb2a
Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/bluetooth.pro | 3 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp | 25 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycharacteristicinfo_p.cpp | 24 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycharacteristicinfo_p.h | 14 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp | 256 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller.h | 6 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 57 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.cpp | 25 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.h | 18 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_qnx.cpp | 667 | ||||
-rw-r--r-- | src/bluetooth/qlowenergydescriptorinfo.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/qlowenergydescriptorinfo_p.h | 3 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyprocess_p.h | 6 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyprocess_qnx.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyserviceinfo.cpp | 2 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyserviceinfo_p.cpp | 10 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyserviceinfo_p.h | 15 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyserviceinfo_qnx.cpp | 194 |
18 files changed, 695 insertions, 638 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index bb4e6266..2220ced1 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -113,7 +113,8 @@ config_bluez:qtHaveModule(dbus) { qbluetoothtransferreply_qnx.cpp \ qlowenergycharacteristicinfo_qnx.cpp \ qlowenergyserviceinfo_qnx.cpp \ - qlowenergyprocess_qnx.cpp + qlowenergyprocess_qnx.cpp \ + qlowenergycontroller_qnx.cpp } else:android:!android-no-sdk { include(android/android.pri) diff --git a/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp b/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp index a6592186..8a9707bc 100644 --- a/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp +++ b/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp @@ -67,35 +67,10 @@ 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 index 092a2580..8ae4ef8b 100644 --- a/src/bluetooth/qlowenergycharacteristicinfo_p.cpp +++ b/src/bluetooth/qlowenergycharacteristicinfo_p.cpp @@ -53,30 +53,6 @@ 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() { diff --git a/src/bluetooth/qlowenergycharacteristicinfo_p.h b/src/bluetooth/qlowenergycharacteristicinfo_p.h index 59353d5f..c0fe7025 100644 --- a/src/bluetooth/qlowenergycharacteristicinfo_p.h +++ b/src/bluetooth/qlowenergycharacteristicinfo_p.h @@ -63,19 +63,12 @@ QT_BEGIN_NAMESPACE class QBluetoothUuid; class QLowEnergyCharacteristicInfo; -class QLowEnergyCharacteristicInfoPrivate: public QObject +class QLowEnergyCharacteristicInfoPrivate { - Q_OBJECT public: QLowEnergyCharacteristicInfoPrivate(); ~QLowEnergyCharacteristicInfoPrivate(); - - void setValue(const QByteArray &wantedValue); - void readValue(); bool valid(); - void readDescriptors(); - bool enableNotification(); - void disableNotification(); QString name; QBluetoothUuid uuid; @@ -92,7 +85,6 @@ public: 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; @@ -100,10 +92,6 @@ public: QString startingHandle; #endif -Q_SIGNALS: - void notifyValue(const QBluetoothUuid &); - void error(const QBluetoothUuid &); - private: #ifdef QT_BLUEZ_BLUETOOTH OrgBluezCharacteristicInterface *characteristic; diff --git a/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp b/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp index 09db7e67..c0051ea9 100644 --- a/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp +++ b/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp @@ -55,38 +55,6 @@ 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) { @@ -98,230 +66,6 @@ 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) diff --git a/src/bluetooth/qlowenergycontroller.h b/src/bluetooth/qlowenergycontroller.h index dcef728e..7146ccd8 100644 --- a/src/bluetooth/qlowenergycontroller.h +++ b/src/bluetooth/qlowenergycontroller.h @@ -81,12 +81,6 @@ Q_SIGNALS: 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 diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 042ef5f4..0ad8d875 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -63,63 +63,6 @@ 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(); diff --git a/src/bluetooth/qlowenergycontroller_p.cpp b/src/bluetooth/qlowenergycontroller_p.cpp index 66230585..de634133 100644 --- a/src/bluetooth/qlowenergycontroller_p.cpp +++ b/src/bluetooth/qlowenergycontroller_p.cpp @@ -69,31 +69,6 @@ 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); diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index 826f88c1..63cee79a 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -59,17 +59,21 @@ public: 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_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 *); + void readDescriptors(QLowEnergyCharacteristicInfo &characteristic); + void readValue(QLowEnergyCharacteristicInfo &characteristic); + void writeValue(const int &instance, const QString &handle, const QByteArray &value); +#endif + #ifdef QT_BLUEZ_BLUETOOTH void connectToTerminal(); void setHandles(); @@ -82,8 +86,8 @@ public slots: #endif private: bool m_randomAddress; -#ifdef QT_BLUEZ_BLUETOOTH QLowEnergyProcess *process; +#ifdef QT_BLUEZ_BLUETOOTH int m_step; bool m_deviceConnected; bool m_commandStarted; diff --git a/src/bluetooth/qlowenergycontroller_qnx.cpp b/src/bluetooth/qlowenergycontroller_qnx.cpp new file mode 100644 index 00000000..bf1a57d7 --- /dev/null +++ b/src/bluetooth/qlowenergycontroller_qnx.cpp @@ -0,0 +1,667 @@ +/*************************************************************************** +** +** 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 "qlowenergycontroller_p.h" +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergydescriptorinfo.h" +#include "qlowenergydescriptorinfo_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 <QSharedPointer> + +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; +} + +void QLowEnergyControllerPrivate::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); + QSharedPointer<QLowEnergyControllerPrivate> *classPointer = + static_cast<QSharedPointer<QLowEnergyControllerPrivate> *>(userData); + QLowEnergyControllerPrivate *p = classPointer->data(); + + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] (instance):" << 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; + + QString lowEnergyUuid(service); + QBluetoothUuid leUuid; + + //In case of custom UUIDs (e.g. Texas Instruments SenstorTag LE Device) + if (lowEnergyUuid.length() > 6) { + lowEnergyUuid.remove(0,2); + leUuid = QBluetoothUuid(lowEnergyUuid); + } else { // Official UUIDs are presented in 6 characters (for instance 0x180A) + leUuid = QBluetoothUuid(lowEnergyUuid.toUShort(0,0)); + } + qCDebug(QT_BT_QNX) << leUuid; + + int index = -1; + for (int i = 0; i < p->m_leServices.size(); i++) { + if (p->m_leServices.at(i).serviceUuid() == leUuid) { + index = i; + break; + } + } + + if (err != 0) { + qCDebug(QT_BT_QNX) << "An error occurred in service connected callback: " << qt_error_string(err); + p->errorString = qt_error_string(err); + p->q_ptr->error(p->m_leServices.at(index)); + } + if (index != -1) { + p->m_leServices.at(index).d_ptr->characteristicList.clear(); + bt_gatt_characteristic_t* data; + data = (bt_gatt_characteristic_t*) malloc(sizeof(bt_gatt_characteristic_t)); + if (!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->q_ptr->error(p->m_leServices.at(index)); + 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 (!allCharacteristicList) { + qCDebug(QT_BT_QNX) <<" GATT characteristics: Not enough memory"; + bt_gatt_disconnect_instance(instance); + p->errorString = QStringLiteral("GATT characteristics: Not enough memory"); + p->q_ptr->error(p->m_leServices.at(index)); + 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)) { + 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; + p->readDescriptors(characteristicInfo); + p->readValue(characteristicInfo); + //Subscribe only once since it is static function + if (!sub) { + int rc = bt_gatt_reg_notifications(instance, &(p->serviceNotification)); + if (!rc) { + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] bt_gatt_reg_notifications failed." << errno << qt_error_string(errno); + p->errorString = qt_error_string(errno); + p->q_ptr->error(p->m_leServices.at(index)); + } else { + qCDebug(QT_BT_QNX) << "[SERVICE: Connected] bt_gatt_reg_notifications was presumably OK"; + } + sub = true; + } + p->m_leServices.at(index).d_ptr->characteristicList.append(characteristicInfo); + + } + + if (!allCharacteristicList) { + free(allCharacteristicList); + allCharacteristicList = 0; + } + + /* END WORKAROUND */ + } + + p->m_leServices.at(index).d_ptr->connected = true; + + qCDebug(QT_BT_QNX) << p; + emit p->q_ptr->connected(p->m_leServices.at(index)); + qCDebug(QT_BT_QNX) << "---------------------------------------------------------------------------------"; + } else { + qCDebug(QT_BT_QNX) << "Unregistered service connected"; + } +} + +void QLowEnergyControllerPrivate::serviceNotification(int instance, short unsigned int handle, + const unsigned char*val, short unsigned int len, void *userData) +{ + if (!val) + return; + QSharedPointer<QLowEnergyControllerPrivate> *ClassPointer + = static_cast<QSharedPointer<QLowEnergyControllerPrivate> *>(userData); + QLowEnergyControllerPrivate *p = ClassPointer->data(); + + qCDebug(QT_BT_QNX) << "---------------------------------------------------"; + qCDebug(QT_BT_QNX) << "[Notification] received (handle, value, instance):" << 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->m_leServices.size(); i++) { + for (int j = 0; j < p->m_leServices.at(i).characteristics().size(); j++) { + + QString charHandle; + charHandle.setNum(handle); + charHandle = charHandle; + if (charHandle == p->m_leServices.at(i).d_ptr->characteristicList.at(j).handle() ) { + chars = QLowEnergyCharacteristicInfo(p->m_leServices.at(i).d_ptr->characteristicList.at(j)); + QByteArray receivedValue; + + for (int k = 0; k < len; k++) { + QByteArray hexadecimal; + hexadecimal.append(val[k]); + receivedValue.append(hexadecimal.toHex()); + } + + p->m_leServices.at(i).d_ptr->characteristicList.at(j).d_ptr->notification = true; + p->m_leServices.at(i).d_ptr->characteristicList.at(j).d_ptr->value = receivedValue; + p->q_ptr->valueChanged(p->m_leServices.at(i).d_ptr->characteristicList.at(j)); + current = true; + } + } + } + + if (!current) + qCDebug(QT_BT_QNX) << "Notificiation received and does not belong to this characteristic."; +} + +void QLowEnergyControllerPrivate::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 QLowEnergyControllerPrivate::serviceDisconnected(const char *bdaddr, const char *service, + int instance, int reason, void *userData) +{ + QSharedPointer<QLowEnergyControllerPrivate> *classPointer = static_cast<QSharedPointer<QLowEnergyControllerPrivate> *>(userData); + QLowEnergyControllerPrivate *p = classPointer->data(); + QString lowEnergyUuid(service); + qCDebug(QT_BT_QNX) << "LE Service: " << lowEnergyUuid << 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 leService(leUuid); + emit p->q_ptr->connected(leService); + + 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; +} + +QLowEnergyControllerPrivate::QLowEnergyControllerPrivate() +{ + qRegisterMetaType<QLowEnergyServiceInfo>("QLowEnergyServiceInfo"); + qRegisterMetaType<QLowEnergyCharacteristicInfo>("QLowEnergyCharacteristicInfo"); +} + +QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate() +{ + +} + +void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &service) +{ + if (!service.isValid()) { + errorString = QStringLiteral("Service not valid."); + emit q_ptr->error(service); + return; + } + + bool add = true; + for (int i = 0; i < m_leServices.size(); i++) { + if (m_leServices.at(i).serviceUuid() == service.serviceUuid()) { + if (m_leServices.at(i).isConnected()) { + errorString = QStringLiteral("Service already connected"); + emit q_ptr->error(m_leServices.at(i)); + } + else { + m_leServices.replace(i, service); + add = false; + break; + } + } + } + if (add) + m_leServices.append(service); + + 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 << qt_error_string(errno); + errorString = QStringLiteral("Initialization of device falied. ") + qt_error_string(errno); + emit q_ptr->error(service); + return; + } + + errno = 0; + if (bt_gatt_init(&gatt_callbacks) < 0) { + qCDebug(QT_BT_QNX) << "[INIT] GAT Init problem." << errno << qt_error_string(errno); + errorString = QStringLiteral("Callbacks initialization failed. ") + qt_error_string(errno); + emit q_ptr->error(service); + return; + } + if (bt_le_init(0) != EOK) { + qWarning() << "LE initialization failure " << errno; + } + + QSharedPointer<QLowEnergyControllerPrivate> *classPointer = new QSharedPointer<QLowEnergyControllerPrivate>(this); + process->addPointer(classPointer->data()); + QString serviceUuid = service.serviceUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (service.serviceName() == QStringLiteral("Unknown Service")) + 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(service.device().address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData(), 0, &conParm, classPointer) < 0) { + qCDebug(QT_BT_QNX) << "[SERVICE] Connection to service failed." << errno << qt_error_string(errno); + errorString = QStringLiteral("[SERVICE] Connection to service failed.") + qt_error_string(errno); + emit q_ptr->error(service); + } + qCDebug(QT_BT_QNX) << "errno after connect: " << errno; +} + +void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo &leService) +{ + if (leService.isValid()){ + QString serviceUuid = leService.serviceUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (leService.serviceName() == QStringLiteral("Unknown Service")) + serviceUuid = QStringLiteral("0x") + serviceUuid.toUpper(); + else + serviceUuid = QStringLiteral("0x") + serviceUuid[4] + serviceUuid[5] + serviceUuid[6] + serviceUuid[7]; + if (leService.isConnected()) { + if (bt_gatt_disconnect_service(leService.device().address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData()) < 0) { + qCDebug(QT_BT_QNX) << "[SERVICE] Disconnect service request failed. " << errno << qt_error_string(errno); + errorString = QStringLiteral("[SERVICE] Disconnect service request failed. ") + qt_error_string(errno); + emit q_ptr->error(leService); + } else { + for (int i = 0; i < m_leServices.size(); i++) { + if (leService.serviceUuid() == m_leServices.at(i).serviceUuid()) { + m_leServices.removeAt(i); + break; + } + } + leService.d_ptr->connected = false; + emit q_ptr->disconnected(leService); + qCDebug(QT_BT_QNX) << "[SERVICE] Disconnected from service OK."; + } + } else { + errorString = QStringLiteral("Service is not connected"); + q_ptr->error(leService); + } + } else { + disconnectAllServices(); + } +} + +void QLowEnergyControllerPrivate::disconnectAllServices() +{ + for (int i = 0; i < m_leServices.size(); i++) { + QString serviceUuid = m_leServices.at(i).serviceUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (m_leServices.at(i).serviceName() == QStringLiteral("Unknown Service")) + serviceUuid = QStringLiteral("0x") + serviceUuid.toUpper(); + else + serviceUuid = QStringLiteral("0x") + serviceUuid[4] + serviceUuid[5] + serviceUuid[6] + serviceUuid[7]; + + if (m_leServices.at(i).isConnected()) { + qCDebug(QT_BT_QNX) << m_leServices.at(i).device().address().toString().toLocal8Bit().constData() << serviceUuid.toLocal8Bit().constData(); + if (bt_gatt_disconnect_service( m_leServices.at(i).device().address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData()) < 0) { + qCDebug(QT_BT_QNX) << "[SERVICE] Disconnect service request failed. " << errno << qt_error_string(errno); + errorString = QStringLiteral("[SERVICE] Disconnect service request failed. ") + qt_error_string(errno); + emit q_ptr->error( m_leServices.at(i)); + } else { + m_leServices.at(i).d_ptr->connected = false; + emit q_ptr->disconnected(m_leServices.at(i)); + qCDebug(QT_BT_QNX) << "[SERVICE] Disconnected from service OK."; + } + } + } + m_leServices.clear(); +} + +bool QLowEnergyControllerPrivate::enableNotification(const QLowEnergyCharacteristicInfo &characteristic) +{ + if (characteristic.d_ptr->instance == -1) { + qCDebug(QT_BT_QNX) << " GATT service not connected "; + errorString = QStringLiteral("Service is not connected"); + emit q_ptr->error(characteristic); + return false; + } + if (!(characteristic.d_ptr->permission & QLowEnergyCharacteristicInfo::Notify)) { + qCDebug(QT_BT_QNX) << "Notification changes not allowed"; + errorString = QStringLiteral("This characteristic does not support notifications."); + emit q_ptr->error(characteristic); + return false; + } + + int rc = bt_gatt_enable_notify(characteristic.d_ptr->instance, &characteristic.d_ptr->characteristic, 1); + if (!rc) { + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify errno=" << errno << qt_error_string(errno); + errorString = qt_error_string(errno); + emit q_ptr->error(characteristic); + return false; + } else { + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify was presumably OK"; + return true; + } +} + +void QLowEnergyControllerPrivate::disableNotification(const QLowEnergyCharacteristicInfo &characteristic) +{ + int rc = bt_gatt_enable_notify(characteristic.d_ptr->instance, &characteristic.d_ptr->characteristic, 0); + if (!rc) + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify errno=" << errno << qt_error_string(errno); + else + qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify was presumably OK"; +} + +bool QLowEnergyControllerPrivate::write(const QLowEnergyCharacteristicInfo &characteristic) +{ + if (!characteristic.isValid()) { + errorString = QStringLiteral("Characteristic not valid."); + emit q_ptr->error(characteristic); + return false; + } + + if (characteristic.permissions() & QLowEnergyCharacteristicInfo::Write) { + writeValue(characteristic.d_ptr->instance, characteristic.d_ptr->handle, characteristic.d_ptr->value); + if (errorString == QString()) { + return true; + } else { + emit q_ptr->error(characteristic); + return false; + } + } else { + errorString = QStringLiteral("Characteristic does not allow write operations. The wanted value was not written to the device."); + emit q_ptr->error(characteristic); + return false; + } + +} + +bool QLowEnergyControllerPrivate::write(const QLowEnergyDescriptorInfo &descriptor) +{ + Q_UNUSED(descriptor); + return false; +} + +void QLowEnergyControllerPrivate::readDescriptors(QLowEnergyCharacteristicInfo &characteristic) +{ + characteristic.d_ptr->descriptorsList.clear(); + int count = bt_gatt_descriptors_count(characteristic.d_ptr->instance, &characteristic.d_ptr->characteristic); + + if (count == -1) { + qWarning() << "GATT descriptors count failed:" << errno << "(" << qt_error_string(errno) << ")"; + bt_gatt_disconnect_instance(characteristic.d_ptr->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(characteristic.d_ptr->instance); + return; + } + + /* BEGIN WORKAROUND - Temporary fix to address race condition */ + int number = 0; + do { + number = bt_gatt_descriptors(characteristic.d_ptr->instance, &characteristic.d_ptr->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 << qt_error_string(errno); + bt_gatt_disconnect_instance(characteristic.d_ptr->instance); + return; + } + + characteristic.d_ptr->characteristicMtu = bt_gatt_get_mtu(characteristic.d_ptr->instance); + + uint8_t *descriptorBuffer = (uint8_t *)alloca(characteristic.d_ptr->characteristicMtu); + if (!descriptorBuffer) { + qCDebug(QT_BT_QNX) <<"GATT descriptors: Not enough memory"; + bt_gatt_disconnect_instance(characteristic.d_ptr->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(characteristic.d_ptr->instance, descriptorList[i].handle, offset, descriptorBuffer, characteristic.d_ptr->characteristicMtu, &more); + if (byteCount < 0) { + qCDebug(QT_BT_QNX) << "Unable to read descriptor value:"<< errno<< qt_error_string(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()); + } + + } + descriptor.d_ptr->instance = characteristic.d_ptr->instance; + map[QStringLiteral("value")] = descriptor.d_ptr->m_value; + descriptor.d_ptr->m_properties = map; + characteristic.d_ptr->descriptorsList.append(descriptor); + } + + if (!descriptorList) { + free(descriptorList); + descriptorList = 0; + } +} + +void QLowEnergyControllerPrivate::readValue(QLowEnergyCharacteristicInfo &characteristic) +{ + if ((characteristic.d_ptr->permission & QLowEnergyCharacteristicInfo::Read) == 0) { + qCDebug(QT_BT_QNX) << "GATT characteristic: Read not permitted"; + return; + } + + uint8_t *characteristicBuffer = (uint8_t *)alloca(characteristic.d_ptr->characteristicMtu); + if (!characteristicBuffer) { + qCDebug(QT_BT_QNX) << "GATT characteristic: Not enough memory"; + bt_gatt_disconnect_instance(characteristic.d_ptr->instance); + return; + } + + int byteCount = 0; + uint8_t more = 1; + for (int offset = 0; more; offset += byteCount) { + byteCount = bt_gatt_read_value(characteristic.d_ptr->instance, + characteristic.d_ptr->handle.toUShort(), offset, characteristicBuffer, + characteristic.d_ptr->characteristicMtu, &more); + if (byteCount < 0) { + qCDebug(QT_BT_QNX) << "Unable to read characteristic value: " << errno << qt_error_string(errno); + break; + } + characteristic.d_ptr->value = QByteArray(); + for (int j = 0; j < byteCount; j++) { + QString hexadecimal; + hexadecimal.setNum(characteristicBuffer[j], 16); + characteristic.d_ptr->value.append(hexadecimal.toLatin1()); + } + characteristic.d_ptr->properties["value"] = characteristic.d_ptr->value; + } +} + +void QLowEnergyControllerPrivate::writeValue(const int &instance, const QString &handle, const QByteArray &value) +{ + errorString = QString(); + const int characteristicLen = value.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."); + bt_gatt_disconnect_instance(instance); + return; + } + + const int consumed = stringToBuffer(QString::fromLocal8Bit(value), 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 << qt_error_string(errno); + errorString = QStringLiteral("Unable to write characteristic value: ") + qt_error_string(errno); + } + } +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergydescriptorinfo.cpp b/src/bluetooth/qlowenergydescriptorinfo.cpp index f18276ba..c72ee946 100644 --- a/src/bluetooth/qlowenergydescriptorinfo.cpp +++ b/src/bluetooth/qlowenergydescriptorinfo.cpp @@ -77,7 +77,9 @@ QString parseDescriptorUuid(const QBluetoothUuid &uuid) QLowEnergyDescriptorInfoPrivate::QLowEnergyDescriptorInfoPrivate(const QBluetoothUuid &uuid, const QString &handle): m_value(QByteArray()), m_uuid(uuid), m_handle(handle), m_properties(QVariantMap()), m_name(QStringLiteral("")) { - +#ifdef QT_QNX_BLUETOOTH + instance = -1; +#endif } QLowEnergyDescriptorInfoPrivate::~QLowEnergyDescriptorInfoPrivate() diff --git a/src/bluetooth/qlowenergydescriptorinfo_p.h b/src/bluetooth/qlowenergydescriptorinfo_p.h index e167859f..2cf8b36e 100644 --- a/src/bluetooth/qlowenergydescriptorinfo_p.h +++ b/src/bluetooth/qlowenergydescriptorinfo_p.h @@ -54,6 +54,9 @@ public: QString m_handle; QVariantMap m_properties; QString m_name; +#ifdef QT_QNX_BLUETOOTH + int instance; +#endif }; QT_END_NAMESPACE #endif // QLOWENERGYDESCRIPTORINFO_P_H diff --git a/src/bluetooth/qlowenergyprocess_p.h b/src/bluetooth/qlowenergyprocess_p.h index 3f65b1e7..eaea0a68 100644 --- a/src/bluetooth/qlowenergyprocess_p.h +++ b/src/bluetooth/qlowenergyprocess_p.h @@ -47,7 +47,7 @@ #ifdef QT_QNX_BLUETOOTH #include <QList> #include <QPointer> -#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycontroller_p.h" #endif #ifdef QT_BLUEZ_BLUETOOTH #include <QProcess> @@ -66,7 +66,7 @@ public: bool isConnected() const; #ifdef QT_QNX_BLUETOOTH static void handleEvent(const int, const char *, const char *); - void addPointer(QLowEnergyServiceInfoPrivate* classPointer); + void addPointer(QLowEnergyControllerPrivate* classPointer); #endif #ifdef QT_BLUEZ_BLUETOOTH QProcess *getProcess(); @@ -89,7 +89,7 @@ private: int m_counter; #endif #ifdef QT_QNX_BLUETOOTH - QList<QObject*> m_classPointers; + QList<QLowEnergyControllerPrivate*> m_classPointers; #endif bool connected; }; diff --git a/src/bluetooth/qlowenergyprocess_qnx.cpp b/src/bluetooth/qlowenergyprocess_qnx.cpp index 1fa8cc48..05ef2e4e 100644 --- a/src/bluetooth/qlowenergyprocess_qnx.cpp +++ b/src/bluetooth/qlowenergyprocess_qnx.cpp @@ -42,8 +42,6 @@ #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 @@ -89,7 +87,7 @@ bool QLowEnergyProcess::isConnected() const return connected; } -void QLowEnergyProcess::addPointer(QLowEnergyServiceInfoPrivate* classPointer) +void QLowEnergyProcess::addPointer(QLowEnergyControllerPrivate* classPointer) { m_classPointers.append(classPointer); } diff --git a/src/bluetooth/qlowenergyserviceinfo.cpp b/src/bluetooth/qlowenergyserviceinfo.cpp index 23ead34e..a869ccfc 100644 --- a/src/bluetooth/qlowenergyserviceinfo.cpp +++ b/src/bluetooth/qlowenergyserviceinfo.cpp @@ -102,7 +102,7 @@ QString parseUuid(const QBluetoothUuid &uuid) uuidnames[0x1818] = QStringLiteral("Cycling Power"); uuidnames[0x1819] = QStringLiteral("Location and Navigation"); } - QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknow Service")); + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknown Service")); return name; } diff --git a/src/bluetooth/qlowenergyserviceinfo_p.cpp b/src/bluetooth/qlowenergyserviceinfo_p.cpp index 0679278b..6b902843 100644 --- a/src/bluetooth/qlowenergyserviceinfo_p.cpp +++ b/src/bluetooth/qlowenergyserviceinfo_p.cpp @@ -53,16 +53,6 @@ QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() } -void QLowEnergyServiceInfoPrivate::registerServiceWatcher() -{ - -} - -void QLowEnergyServiceInfoPrivate::unregisterServiceWatcher() -{ - -} - bool QLowEnergyServiceInfoPrivate::valid() { return false; diff --git a/src/bluetooth/qlowenergyserviceinfo_p.h b/src/bluetooth/qlowenergyserviceinfo_p.h index d033a613..cee55534 100644 --- a/src/bluetooth/qlowenergyserviceinfo_p.h +++ b/src/bluetooth/qlowenergyserviceinfo_p.h @@ -57,9 +57,8 @@ class QLowEnergyServiceInfo; class QLowEnergyCharacteristicInfo; class QLowEnergyProcess; -class QLowEnergyServiceInfoPrivate: public QObject +class QLowEnergyServiceInfoPrivate { - Q_OBJECT friend class QLowEnergyControllerPrivate; public: @@ -69,8 +68,6 @@ public: #endif ~QLowEnergyServiceInfoPrivate(); - void registerServiceWatcher(); - void unregisterServiceWatcher(); bool valid(); QString serviceName; @@ -89,19 +86,9 @@ public: #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 diff --git a/src/bluetooth/qlowenergyserviceinfo_qnx.cpp b/src/bluetooth/qlowenergyserviceinfo_qnx.cpp index 5ab214de..f09e1124 100644 --- a/src/bluetooth/qlowenergyserviceinfo_qnx.cpp +++ b/src/bluetooth/qlowenergyserviceinfo_qnx.cpp @@ -57,208 +57,18 @@ 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() + m_instance(0) { } -void QLowEnergyServiceInfoPrivate::registerServiceWatcher() +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() { - 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() { |