From ec4aa0bcb592e9668b0767906157a1a51915d76c Mon Sep 17 00:00:00 2001
From: Nedim Hadzic <nhadzic@blackberry.com>
Date: Thu, 20 Mar 2014 12:08:08 +0100
Subject: [PATCH] Added and improved error handling in controller class

Error enums added and implemented together with examples.

Change-Id: I912c396080ee9a6b87f41104eb7e41f8c62abf8b
Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
---
 .../btfiletransfer/btfiletransfer.pro         |  2 +-
 .../bluetooth/heartlistener/heartrate.cpp     | 14 ++--
 examples/bluetooth/heartlistener/heartrate.h  |  5 +-
 .../bluetooth/lowenergyscanner/device.cpp     |  7 +-
 examples/bluetooth/lowenergyscanner/device.h  |  4 +-
 src/bluetooth/qlowenergycontroller.cpp        | 29 +++++++-
 src/bluetooth/qlowenergycontroller.h          | 13 +++-
 src/bluetooth/qlowenergycontroller_bluez.cpp  | 19 +++--
 src/bluetooth/qlowenergycontroller_p.cpp      |  3 +-
 src/bluetooth/qlowenergycontroller_p.h        |  1 +
 src/bluetooth/qlowenergycontroller_qnx.cpp    | 72 ++++++++++++-------
 .../tst_qbluetoothservicediscoveryagent.cpp   |  1 +
 12 files changed, 117 insertions(+), 53 deletions(-)

diff --git a/examples/bluetooth/btfiletransfer/btfiletransfer.pro b/examples/bluetooth/btfiletransfer/btfiletransfer.pro
index 00b16415..e5d47302 100644
--- a/examples/bluetooth/btfiletransfer/btfiletransfer.pro
+++ b/examples/bluetooth/btfiletransfer/btfiletransfer.pro
@@ -26,5 +26,5 @@ OTHER_FILES += \
 RESOURCES += \
     btfiletransfer.qrc
 
-target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/scanner
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/btfiletransfer
 INSTALLS += target
diff --git a/examples/bluetooth/heartlistener/heartrate.cpp b/examples/bluetooth/heartlistener/heartrate.cpp
index a1f80121..7d135e5b 100644
--- a/examples/bluetooth/heartlistener/heartrate.cpp
+++ b/examples/bluetooth/heartlistener/heartrate.cpp
@@ -145,8 +145,10 @@ void HeartRate::connectToService(const QString &address)
             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(error(QLowEnergyServiceInfo,QLowEnergyController::Error)),
+                    this, SLOT(errorReceived(QLowEnergyServiceInfo,QLowEnergyController::Error)));
+            connect(m_leInfo, SIGNAL(error(QLowEnergyCharacteristicInfo,QLowEnergyController::Error)),
+                    this, SLOT(errorReceivedCharacteristic(QLowEnergyCharacteristicInfo,QLowEnergyController::Error)));
             connect(m_leInfo, SIGNAL(valueChanged(QLowEnergyCharacteristicInfo)), this, SLOT(receiveMeasurement(QLowEnergyCharacteristicInfo)));
         }
         //! [Connect signals]
@@ -253,15 +255,15 @@ int HeartRate::hR() const
 }
 
 //! [Error handling]
-void HeartRate::errorReceived(const QLowEnergyServiceInfo &leService)
+void HeartRate::errorReceived(const QLowEnergyServiceInfo &leService, QLowEnergyController::Error error)
 {
-    qWarning() << "Error: " << leService.serviceUuid() << m_leInfo->errorString();
+    qWarning() << "Error: " << leService.serviceUuid() << m_leInfo->errorString() << error;
     setMessage(QStringLiteral("Error: ") + m_leInfo->errorString());
 }
 
-void HeartRate::errorReceivedCharacteristic(const QLowEnergyCharacteristicInfo &leCharacteristic)
+void HeartRate::errorReceivedCharacteristic(const QLowEnergyCharacteristicInfo &leCharacteristic, QLowEnergyController::Error error)
 {
-    qWarning() << "Error: " << leCharacteristic.uuid() << m_leInfo->errorString();
+    qWarning() << "Error: " << leCharacteristic.uuid() << m_leInfo->errorString() << error;
     setMessage(QStringLiteral("Error: ") + m_leInfo->errorString());
 }
 //! [Error handling]
diff --git a/examples/bluetooth/heartlistener/heartrate.h b/examples/bluetooth/heartlistener/heartrate.h
index 33e3181c..581000ad 100644
--- a/examples/bluetooth/heartlistener/heartrate.h
+++ b/examples/bluetooth/heartlistener/heartrate.h
@@ -59,7 +59,6 @@
 
 QT_FORWARD_DECLARE_CLASS (QLowEnergyServiceInfo)
 QT_FORWARD_DECLARE_CLASS (QLowEnergyCharacteristicInfo)
-QT_FORWARD_DECLARE_CLASS (QLowEnergyController)
 
 QT_USE_NAMESPACE
 class HeartRate: public QObject
@@ -98,8 +97,8 @@ public slots:
     void serviceScanError(QBluetoothServiceDiscoveryAgent::Error);
     void serviceConnected(const QLowEnergyServiceInfo &);
     void receiveMeasurement(const QLowEnergyCharacteristicInfo &);
-    void errorReceived(const QLowEnergyServiceInfo &);
-    void errorReceivedCharacteristic(const QLowEnergyCharacteristicInfo &);
+    void errorReceived(const QLowEnergyServiceInfo &, QLowEnergyController::Error);
+    void errorReceivedCharacteristic(const QLowEnergyCharacteristicInfo &, QLowEnergyController::Error);
     void serviceDisconnected(const QLowEnergyServiceInfo &);
     void disconnectService();
     void obtainResults();
diff --git a/examples/bluetooth/lowenergyscanner/device.cpp b/examples/bluetooth/lowenergyscanner/device.cpp
index 44cd3512..d137fd40 100644
--- a/examples/bluetooth/lowenergyscanner/device.cpp
+++ b/examples/bluetooth/lowenergyscanner/device.cpp
@@ -152,7 +152,8 @@ void Device::scanServices(QString address)
         // 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(error(QLowEnergyServiceInfo, QLowEnergyCOntroller::Error)),
+                this, SLOT(errorReceived(QLowEnergyServiceInfo,QLowEnergyCOntroller::Error)));
         connect(info, SIGNAL(disconnected(QLowEnergyServiceInfo)), this, SLOT(serviceDisconnected(QLowEnergyServiceInfo)));
     }
 }
@@ -195,9 +196,9 @@ void Device::serviceConnected(const QLowEnergyServiceInfo &service)
     emit characteristicsDone();
 }
 
-void Device::errorReceived(const QLowEnergyServiceInfo &service)
+void Device::errorReceived(const QLowEnergyServiceInfo &service, QLowEnergyController::Error error)
 {
-    qWarning() << "Error: " << info->errorString() << service.serviceUuid();
+    qWarning() << "Error: " << info->errorString() << service.serviceUuid() << error;
     setUpdate(info->errorString());
 }
 
diff --git a/examples/bluetooth/lowenergyscanner/device.h b/examples/bluetooth/lowenergyscanner/device.h
index 307b0fb9..3ac28c8f 100644
--- a/examples/bluetooth/lowenergyscanner/device.h
+++ b/examples/bluetooth/lowenergyscanner/device.h
@@ -49,6 +49,7 @@
 #include <QBluetoothServiceDiscoveryAgent>
 #include <QBluetoothDeviceDiscoveryAgent>
 #include "deviceinfo.h"
+#include "qlowenergycontroller.h"
 #include "qlowenergyserviceinfo.h"
 #include "serviceinfo.h"
 #include "characteristicinfo.h"
@@ -56,7 +57,6 @@
 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
@@ -86,7 +86,7 @@ public slots:
     void serviceScanDone();
     void serviceConnected(const QLowEnergyServiceInfo &service);
     void connectToService(const QString &uuid);
-    void errorReceived(const QLowEnergyServiceInfo &service);
+    void errorReceived(const QLowEnergyServiceInfo &service, QLowEnergyController::Error);
     void disconnectFromService();
     void serviceDisconnected(const QLowEnergyServiceInfo &service);
     void serviceScanError(QBluetoothServiceDiscoveryAgent::Error);
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index 3ff8e131..d993e205 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -65,7 +65,20 @@ QT_BEGIN_NAMESPACE
     service on the same LE device.
 
 
-    \sa QLowEnergyServiceInfo, QLowEnergyCharacteristicInfo
+    \sa QLowEnergyServiceInfo, QLowEnergyCharacteristicInfo, QLowEnergyDescriptorInfo
+*/
+
+/*!
+    \enum QLowEnergyController::Error
+
+    Indicates all possible error conditions found during Bluetooth Low Energy communication.
+
+    \value NoError      No error has occurred.
+    \value UnknownError     An unknown error has occurred.
+    \value InputOutputError     BLE device is not responding.
+    \value OperationError       The error occurred while communicating with the BLE device
+                                (connecting, disconnecting, receiving updates,etc).
+    \value PermissionError      Characteristic does not have required permissions.
 */
 
 /*!
@@ -78,7 +91,7 @@ QT_BEGIN_NAMESPACE
 */
 
 /*!
-    \fn void QLowEnergyController::error(const QLowEnergyServiceInfo &)
+    \fn void QLowEnergyController::error(const QLowEnergyServiceInfo &, QLowEnergyController::Error)
 
     This signal is emitted when the service error occurs.
 
@@ -86,7 +99,7 @@ QT_BEGIN_NAMESPACE
 */
 
 /*!
-    \fn void QLowEnergyController::error(const QLowEnergyCharacteristicInfo &)
+    \fn void QLowEnergyController::error(const QLowEnergyCharacteristicInfo &, QLowEnergyController::Error)
 
     This signal is emitted when the characteristic error occurs.
 
@@ -235,4 +248,14 @@ bool QLowEnergyController::writeDescriptor(const QLowEnergyDescriptorInfo &descr
     return d_ptr->write(descriptor);
 }
 
+/*!
+    This method returns the last error that was emitted.
+
+    \sa errorString(), error()
+ */
+QLowEnergyController::Error QLowEnergyController::error() const
+{
+    return d_ptr->error;
+}
+
 QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller.h b/src/bluetooth/qlowenergycontroller.h
index e993d8d7..53e29343 100644
--- a/src/bluetooth/qlowenergycontroller.h
+++ b/src/bluetooth/qlowenergycontroller.h
@@ -57,6 +57,13 @@ class Q_BLUETOOTH_EXPORT QLowEnergyController: public QObject
 {
     Q_OBJECT
 public:
+    enum Error {
+        NoError,
+        UnknownError,
+        OperationError,
+        InputOutputError,
+        PermissionError
+    };
     QLowEnergyController(QObject *parent = 0);
     QLowEnergyController(const QBluetoothAddress &localAdapter, QObject *parent = 0);
     ~QLowEnergyController();
@@ -75,15 +82,15 @@ public:
     QString errorString() const;
 
     void setRandomAddress();
+    Error error() const;
 
 Q_SIGNALS:
     void connected(const QLowEnergyServiceInfo &);
+    void error(const QLowEnergyServiceInfo &, QLowEnergyController::Error);
+    void error(const QLowEnergyCharacteristicInfo &, QLowEnergyController::Error);
     void disconnected(const QLowEnergyServiceInfo &);
-
     void valueChanged(const QLowEnergyCharacteristicInfo &);
 
-    void error(const QLowEnergyServiceInfo &);
-    void error(const QLowEnergyCharacteristicInfo &);
 private:
     Q_DECLARE_PRIVATE(QLowEnergyController)
     QLowEnergyControllerPrivate *d_ptr;
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index fcf94bda..8fc7bf23 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
 Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
 
 QLowEnergyControllerPrivate::QLowEnergyControllerPrivate():
-    m_randomAddress(false), m_step(0), m_commandStarted(false)
+    error(QLowEnergyController::NoError), m_randomAddress(false), m_step(0), m_commandStarted(false)
 {
 
 }
@@ -132,14 +132,17 @@ void QLowEnergyControllerPrivate::_q_replyReceived(const QString &reply)
         connectToTerminal();
     if (reply.contains(QStringLiteral("Connection refused (111)"))) {
         errorString = QStringLiteral("Connection refused (111)");
+        error = QLowEnergyController::InputOutputError;
         disconnectAllServices();
     }
     else if (reply.contains(QStringLiteral("Device busy"))) {
-        errorString = QStringLiteral("Connection refused (111)");
+        errorString = QStringLiteral("Device busy");
+        error = QLowEnergyController::InputOutputError;
         disconnectAllServices();
     }
     else if (reply.contains(QStringLiteral("disconnected"))) {
         errorString = QStringLiteral("Trying to execute command on disconnected service");
+        error = QLowEnergyController::OperationError;
         disconnectAllServices();
     }
     else {
@@ -328,8 +331,8 @@ void QLowEnergyControllerPrivate::disconnectAllServices()
             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));
+        if (error != QLowEnergyController::NoError)
+            emit q_ptr->error(m_leServices.at(i), error);
         m_step = 0;
     }
     m_leServices.clear();
@@ -404,9 +407,9 @@ bool QLowEnergyControllerPrivate::enableNotification(const QLowEnergyCharacteris
             }
         }
     }
-
+    error = QLowEnergyController::UnknownError;
     errorString = QStringLiteral("Characteristic or notification descriptor not found.");
-    emit q_ptr->error(characteristic);
+    emit q_ptr->error(characteristic, error);
     return false;
 }
 
@@ -438,13 +441,15 @@ bool QLowEnergyControllerPrivate::write(const QLowEnergyCharacteristicInfo &char
             writeValue(characteristic.handle(), characteristic.value());
             return true;
         } else {
+            error = QLowEnergyController::PermissionError;
             errorString = QStringLiteral("This characteristic does not support write operations.");
         }
     } else {
+        error = QLowEnergyController::OperationError;
         errorString = QStringLiteral("The device is not connected or characteristic is not valid");
     }
 
-    emit q_ptr->error(characteristic);
+    emit q_ptr->error(characteristic, error);
     return false;
 }
 
diff --git a/src/bluetooth/qlowenergycontroller_p.cpp b/src/bluetooth/qlowenergycontroller_p.cpp
index de634133..07d58fdd 100644
--- a/src/bluetooth/qlowenergycontroller_p.cpp
+++ b/src/bluetooth/qlowenergycontroller_p.cpp
@@ -44,7 +44,8 @@
 
 QT_BEGIN_NAMESPACE
 
-QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
+QLowEnergyControllerPrivate::QLowEnergyControllerPrivate():
+    error(QLowEnergyController::NoError)
 {
 
 }
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h
index 971cd7dd..45cefdc8 100644
--- a/src/bluetooth/qlowenergycontroller_p.h
+++ b/src/bluetooth/qlowenergycontroller_p.h
@@ -62,6 +62,7 @@ public:
 
     QList<QLowEnergyServiceInfo> m_leServices;
     QString errorString;
+    QLowEnergyController::Error error;
 
 #ifdef QT_QNX_BLUETOOTH
     static void serviceConnected(const char*, const char*, int, int, short unsigned int, short unsigned int, short unsigned int, void*);
diff --git a/src/bluetooth/qlowenergycontroller_qnx.cpp b/src/bluetooth/qlowenergycontroller_qnx.cpp
index bf1a57d7..ac8bb551 100644
--- a/src/bluetooth/qlowenergycontroller_qnx.cpp
+++ b/src/bluetooth/qlowenergycontroller_qnx.cpp
@@ -129,8 +129,9 @@ void QLowEnergyControllerPrivate::serviceConnected(const char *bdaddr, const cha
 
     if (err != 0) {
         qCDebug(QT_BT_QNX) << "An error occurred in service connected callback: " << qt_error_string(err);
+        p->error = QLowEnergyController::OperationError;
         p->errorString = qt_error_string(err);
-        p->q_ptr->error(p->m_leServices.at(index));
+        Q_EMIT p->q_ptr->error(p->m_leServices.at(index), p->error);
     }
     if (index != -1) {
         p->m_leServices.at(index).d_ptr->characteristicList.clear();
@@ -139,8 +140,9 @@ void QLowEnergyControllerPrivate::serviceConnected(const char *bdaddr, const cha
         if (!data) {
             qCDebug(QT_BT_QNX) << "[SERVICE: Connected] GATT characteristics: Not enough memory";
             bt_gatt_disconnect_instance(instance);
+            p->error = QLowEnergyController::OperationError;
             p->errorString = QStringLiteral("GATT characteristics: Not enough memory");
-            p->q_ptr->error(p->m_leServices.at(index));
+            Q_EMIT p->q_ptr->error(p->m_leServices.at(index), p->error);
             return;
         }
 
@@ -154,8 +156,9 @@ void QLowEnergyControllerPrivate::serviceConnected(const char *bdaddr, const cha
             if (!allCharacteristicList) {
                 qCDebug(QT_BT_QNX) <<" GATT characteristics: Not enough memory";
                 bt_gatt_disconnect_instance(instance);
+                p->error = QLowEnergyController::OperationError;
                 p->errorString = QStringLiteral("GATT characteristics: Not enough memory");
-                p->q_ptr->error(p->m_leServices.at(index));
+                Q_EMIT p->q_ptr->error(p->m_leServices.at(index), p->error);
                 return;
             }
 
@@ -200,8 +203,9 @@ void QLowEnergyControllerPrivate::serviceConnected(const char *bdaddr, const cha
                     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->error = QLowEnergyController::OperationError;
                         p->errorString = qt_error_string(errno);
-                        p->q_ptr->error(p->m_leServices.at(index));
+                        Q_EMIT p->q_ptr->error(p->m_leServices.at(index), p->error);
                     } else {
                         qCDebug(QT_BT_QNX) << "[SERVICE: Connected] bt_gatt_reg_notifications was presumably OK";
                     }
@@ -222,7 +226,7 @@ void QLowEnergyControllerPrivate::serviceConnected(const char *bdaddr, const cha
         p->m_leServices.at(index).d_ptr->connected = true;
 
         qCDebug(QT_BT_QNX) << p;
-        emit p->q_ptr->connected(p->m_leServices.at(index));
+        Q_EMIT p->q_ptr->connected(p->m_leServices.at(index));
         qCDebug(QT_BT_QNX) << "---------------------------------------------------------------------------------";
     } else {
         qCDebug(QT_BT_QNX) << "Unregistered service connected";
@@ -263,7 +267,7 @@ void QLowEnergyControllerPrivate::serviceNotification(int instance, short unsign
 
                 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));
+                Q_EMIT p->q_ptr->valueChanged(p->m_leServices.at(i).d_ptr->characteristicList.at(j));
                 current = true;
             }
         }
@@ -305,7 +309,7 @@ void QLowEnergyControllerPrivate::serviceDisconnected(const char *bdaddr, const
         leUuid = QBluetoothUuid(lowEnergyUuid.toUShort(0,0));
     }
     QLowEnergyServiceInfo leService(leUuid);
-    emit p->q_ptr->connected(leService);
+    Q_EMIT p->q_ptr->connected(leService);
 
     qCDebug(QT_BT_QNX) << "---------------------------------------------------";
     qCDebug(QT_BT_QNX) << "[SERVICE: Disconnect] (service, instance, reason):" << service << instance << reason;
@@ -315,7 +319,8 @@ void QLowEnergyControllerPrivate::serviceDisconnected(const char *bdaddr, const
     delete classPointer;
 }
 
-QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
+QLowEnergyControllerPrivate::QLowEnergyControllerPrivate():
+    error(QLowEnergyController::NoError)
 {
     qRegisterMetaType<QLowEnergyServiceInfo>("QLowEnergyServiceInfo");
     qRegisterMetaType<QLowEnergyCharacteristicInfo>("QLowEnergyCharacteristicInfo");
@@ -328,9 +333,11 @@ QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate()
 
 void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &service)
 {
+    Q_Q(QLowEnergyController);
     if (!service.isValid()) {
+        error = QLowEnergyController::UnknownError;
         errorString = QStringLiteral("Service not valid.");
-        emit q_ptr->error(service);
+        Q_EMIT q->error(service, error);
         return;
     }
 
@@ -338,8 +345,9 @@ void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &se
     for (int i = 0; i < m_leServices.size(); i++) {
         if (m_leServices.at(i).serviceUuid() == service.serviceUuid()) {
             if (m_leServices.at(i).isConnected()) {
+                error = QLowEnergyController::OperationError;
                 errorString = QStringLiteral("Service already connected");
-                emit q_ptr->error(m_leServices.at(i));
+                Q_EMIT q->error(m_leServices.at(i), error);
             }
             else {
                 m_leServices.replace(i, service);
@@ -357,16 +365,18 @@ void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &se
     process = process->instance();
     if (!process->isConnected()) {
         qCDebug(QT_BT_QNX) << "[INIT] Init problem." << errno << qt_error_string(errno);
+        error = QLowEnergyController::InputOutputError;
         errorString = QStringLiteral("Initialization of device falied. ") + qt_error_string(errno);
-        emit q_ptr->error(service);
+        Q_EMIT q->error(service, error);
         return;
     }
 
     errno = 0;
     if (bt_gatt_init(&gatt_callbacks) < 0) {
         qCDebug(QT_BT_QNX) << "[INIT] GAT Init problem." << errno << qt_error_string(errno);
+        error = QLowEnergyController::UnknownError;
         errorString = QStringLiteral("Callbacks initialization failed. ") + qt_error_string(errno);
-        emit q_ptr->error(service);
+        Q_EMIT q->error(service, error);
         return;
     }
     if (bt_le_init(0) != EOK) {
@@ -390,14 +400,16 @@ void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &se
 
     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);
+        error = QLowEnergyController::OperationError;
         errorString = QStringLiteral("[SERVICE] Connection to service failed.") + qt_error_string(errno);
-        emit q_ptr->error(service);
+        Q_EMIT q->error(service, error);
     }
     qCDebug(QT_BT_QNX) << "errno after connect: " << errno;
 }
 
 void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo &leService)
 {
+    Q_Q(QLowEnergyController);
     if (leService.isValid()){
         QString serviceUuid = leService.serviceUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}'));
         if (leService.serviceName() == QStringLiteral("Unknown Service"))
@@ -407,8 +419,9 @@ void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo
         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);
+                error = QLowEnergyController::OperationError;
                 errorString = QStringLiteral("[SERVICE] Disconnect service request failed. ") + qt_error_string(errno);
-                emit q_ptr->error(leService);
+                Q_EMIT q->error(leService, error);
             } else {
                 for (int i = 0; i < m_leServices.size(); i++) {
                     if (leService.serviceUuid() == m_leServices.at(i).serviceUuid()) {
@@ -417,12 +430,13 @@ void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo
                     }
                 }
                 leService.d_ptr->connected = false;
-                emit q_ptr->disconnected(leService);
+                Q_EMIT q->disconnected(leService);
                 qCDebug(QT_BT_QNX) << "[SERVICE] Disconnected from service OK.";
             }
         } else {
+            error = QLowEnergyController::UnknownError;
             errorString = QStringLiteral("Service is not connected");
-            q_ptr->error(leService);
+            Q_EMIT q->error(leService, error);
         }
     } else {
         disconnectAllServices();
@@ -431,6 +445,7 @@ void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo
 
 void QLowEnergyControllerPrivate::disconnectAllServices()
 {
+    Q_Q(QLowEnergyController);
     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"))
@@ -442,11 +457,12 @@ void QLowEnergyControllerPrivate::disconnectAllServices()
             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);
+                error = QLowEnergyController::OperationError;
                 errorString = QStringLiteral("[SERVICE] Disconnect service request failed. ") + qt_error_string(errno);
-                emit q_ptr->error( m_leServices.at(i));
+                Q_EMIT q->error( m_leServices.at(i), error);
             } else {
                 m_leServices.at(i).d_ptr->connected = false;
-                emit q_ptr->disconnected(m_leServices.at(i));
+                Q_EMIT q->disconnected(m_leServices.at(i));
                 qCDebug(QT_BT_QNX) << "[SERVICE] Disconnected from service OK.";
             }
         }
@@ -456,24 +472,28 @@ void QLowEnergyControllerPrivate::disconnectAllServices()
 
 bool QLowEnergyControllerPrivate::enableNotification(const QLowEnergyCharacteristicInfo &characteristic)
 {
+    Q_Q(QLowEnergyController);
     if (characteristic.d_ptr->instance == -1) {
         qCDebug(QT_BT_QNX) << " GATT service not connected ";
+        error = QLowEnergyController::UnknownError;
         errorString = QStringLiteral("Service is not connected");
-        emit q_ptr->error(characteristic);
+        Q_EMIT q->error(characteristic, error);
         return false;
     }
     if (!(characteristic.d_ptr->permission & QLowEnergyCharacteristicInfo::Notify)) {
         qCDebug(QT_BT_QNX) << "Notification changes not allowed";
+        error = QLowEnergyController::PermissionError;
         errorString = QStringLiteral("This characteristic does not support notifications.");
-        emit q_ptr->error(characteristic);
+        Q_EMIT q->error(characteristic, error);
         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);
+        error = QLowEnergyController::OperationError;
         errorString = qt_error_string(errno);
-        emit q_ptr->error(characteristic);
+        Q_EMIT q->error(characteristic, error);
         return false;
     } else {
         qCDebug(QT_BT_QNX) << "bt_gatt_enable_notify was presumably OK";
@@ -492,9 +512,11 @@ void QLowEnergyControllerPrivate::disableNotification(const QLowEnergyCharacteri
 
 bool QLowEnergyControllerPrivate::write(const QLowEnergyCharacteristicInfo &characteristic)
 {
+    Q_Q(QLowEnergyController);
     if (!characteristic.isValid()) {
+        error = QLowEnergyController::UnknownError;
         errorString = QStringLiteral("Characteristic not valid.");
-        emit q_ptr->error(characteristic);
+        Q_EMIT q->error(characteristic, error);
         return false;
     }
 
@@ -503,12 +525,14 @@ bool QLowEnergyControllerPrivate::write(const QLowEnergyCharacteristicInfo &char
         if (errorString == QString()) {
             return true;
         } else {
-            emit q_ptr->error(characteristic);
+            error = QLowEnergyController::OperationError;
+            Q_EMIT q->error(characteristic, error);
             return false;
         }
     } else {
+        error = QLowEnergyController::PermissionError;
         errorString = QStringLiteral("Characteristic does not allow write operations. The wanted value was not written to the device.");
-        emit q_ptr->error(characteristic);
+        Q_EMIT q->error(characteristic, error);
         return false;
     }
 
diff --git a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
index d7a6a6ef..20a38772 100644
--- a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
+++ b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
@@ -505,6 +505,7 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
 
                 QVERIFY(info.isValid());
                 QCOMPARE(leController.errorString(), QString());
+                QCOMPARE(leController.error(), QLowEnergyController::NoError);
                 QVERIFY((info.characteristics().size() > 0));
                 qDebug() << "LE Service Connected: " << info.serviceName() << info.serviceUuid();
                 leTestCounter++;
-- 
GitLab