Implement NWL Layer error handling

pull/7/head
Simon Stürz 2020-05-30 16:30:39 +02:00
parent 71675df1c7
commit 74995ce401
13 changed files with 130 additions and 27 deletions

View File

@ -81,7 +81,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion()
stream << static_cast<quint16>(5); // Frame length
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(Deconz::CommandVersion, sequenceNumber, this);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection);
m_pendingReplies.insert(sequenceNumber, reply);
m_interface->sendPackage(message);
@ -105,7 +105,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestDeviceState()
stream << static_cast<quint8>(0); // Reserverd
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(Deconz::CommandDeviceState, sequenceNumber, this);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection);
m_pendingReplies.insert(sequenceNumber, reply);
m_interface->sendPackage(message);
@ -381,7 +381,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Co
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, sequenceNumber, parent);
// Auto delete the object on finished
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection);
// Add it to the pending list
m_pendingReplies.insert(sequenceNumber, reply);
@ -402,7 +402,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
// Create an independent reply for finishing the entire read sequence
ZigbeeInterfaceDeconzReply *readNetworkParametersReply = new ZigbeeInterfaceDeconzReply(Deconz::CommandReadParameter, m_sequenceNumber, this);
connect(readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::finished, readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::deleteLater);
connect(readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::finished, readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection);
// Read MAC address of the bridge
ZigbeeInterfaceDeconzReply *replyMacAddress = requestReadParameter(Deconz::ParameterMacAddress);

View File

@ -137,9 +137,7 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << m_endpoint << this << networkReply->error()
<< networkReply->zigbeeApsStatus();
qCWarning(dcZigbeeClusterLibrary()) << "Failed to read attributes from" << m_node << m_endpoint << this << networkReply->error();
finishZclReply(zclReply);
return;
}
@ -158,7 +156,7 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame)
{
ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this);
connect(zclReply, &ZigbeeClusterReply::finished, zclReply, &ZigbeeClusterReply::deleteLater);
connect(zclReply, &ZigbeeClusterReply::finished, zclReply, &ZigbeeClusterReply::deleteLater, Qt::QueuedConnection);
zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply);
return zclReply;
@ -189,6 +187,7 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo
// wait for the expected indication or check if we already recieved it
zclReply->m_apsConfirmReceived = true;
zclReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus();
zclReply->m_zigbeeNwkStatus = networkReply->zigbeeNwkStatus();
success = true;
break;
case ZigbeeNetworkReply::ErrorInterfaceError:
@ -198,10 +197,15 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo
zclReply->m_error = ZigbeeClusterReply::ErrorNetworkOffline;
break;
case ZigbeeNetworkReply::ErrorZigbeeApsStatusError:
zclReply->m_error = ZigbeeClusterReply::ErrorZigbeeApsStatusError;
zclReply->m_apsConfirmReceived = true;
zclReply->m_error = ZigbeeClusterReply::ErrorZigbeeApsStatusError;
zclReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus();
break;
case ZigbeeNetworkReply::ErrorZigbeeNwkStatusError:
zclReply->m_apsConfirmReceived = true;
zclReply->m_error = ZigbeeClusterReply::ErrorZigbeeNwkStatusError;
zclReply->m_zigbeeNwkStatus = networkReply->zigbeeNwkStatus();
break;
}
return success;

View File

@ -32,6 +32,16 @@ ZigbeeClusterReply::Error ZigbeeClusterReply::error() const
return m_error;
}
Zigbee::ZigbeeApsStatus ZigbeeClusterReply::zigbeeApsStatus() const
{
return m_zigbeeApsStatus;
}
Zigbee::ZigbeeNwkLayerStatus ZigbeeClusterReply::zigbeeNwkStatus() const
{
return m_zigbeeNwkStatus;
}
ZigbeeNetworkRequest ZigbeeClusterReply::request() const
{
return m_request;

View File

@ -44,12 +44,15 @@ public:
ErrorNoError, // All OK, no error occured, the message was transported successfully
ErrorTimeout, // The request timeouted
ErrorZigbeeApsStatusError, // An APS transport error occured. See zigbeeApsStatus()
ErrorZigbeeNwkStatusError, // An NWK layer error occured. See zigbeeNwkStatus()
ErrorInterfaceError, // A transport interface error occured. Could not communicate with the hardware.
ErrorNetworkOffline // The network is offline. Cannot send any requests
};
Q_ENUM(Error)
Error error() const;
Zigbee::ZigbeeApsStatus zigbeeApsStatus() const;
Zigbee::ZigbeeNwkLayerStatus zigbeeNwkStatus() const;
ZigbeeNetworkRequest request() const;
ZigbeeClusterLibrary::Frame requestFrame() const;
@ -74,6 +77,7 @@ private:
// Response
bool m_apsConfirmReceived = false;
Zigbee::ZigbeeApsStatus m_zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess;
Zigbee::ZigbeeNwkLayerStatus m_zigbeeNwkStatus = Zigbee::ZigbeeNwkLayerStatusSuccess;
ZigbeeClusterLibrary::Command m_expectedResponse;

View File

@ -295,7 +295,7 @@ ZigbeeNetworkRequest ZigbeeDeviceObject::buildZdoRequest(quint16 zdoRequest)
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::createZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &request, quint8 transactionSequenceNumber)
{
ZigbeeDeviceObjectReply *zdoReply = new ZigbeeDeviceObjectReply(request, this);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, zdoReply, &ZigbeeDeviceObjectReply::deleteLater);
connect(zdoReply, &ZigbeeDeviceObjectReply::finished, zdoReply, &ZigbeeDeviceObjectReply::deleteLater, Qt::QueuedConnection);
zdoReply->m_expectedResponse = static_cast<ZigbeeDeviceProfile::ZdoCommand>(request.clusterId() | 0x8000);
zdoReply->m_transactionSequenceNumber = transactionSequenceNumber;
m_pendingReplies.insert(transactionSequenceNumber, zdoReply);
@ -311,6 +311,7 @@ bool ZigbeeDeviceObject::verifyNetworkError(ZigbeeDeviceObjectReply *zdoReply, Z
// wait for the expected indication or check if we already recieved it
zdoReply->m_apsConfirmReceived = true;
zdoReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus();
zdoReply->m_zigbeeNwkStatus = networkReply->zigbeeNwkStatus();
success = true;
break;
case ZigbeeNetworkReply::ErrorInterfaceError:
@ -320,10 +321,15 @@ bool ZigbeeDeviceObject::verifyNetworkError(ZigbeeDeviceObjectReply *zdoReply, Z
zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorNetworkOffline;
break;
case ZigbeeNetworkReply::ErrorZigbeeApsStatusError:
zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorZigbeeApsStatusError;
zdoReply->m_apsConfirmReceived = true;
zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorZigbeeApsStatusError;
zdoReply->m_zigbeeApsStatus = networkReply->zigbeeApsStatus();
break;
case ZigbeeNetworkReply::ErrorZigbeeNwkStatusError:
zdoReply->m_apsConfirmReceived = true;
zdoReply->m_error = ZigbeeDeviceObjectReply::ErrorZigbeeNwkStatusError;
zdoReply->m_zigbeeNwkStatus = networkReply->zigbeeNwkStatus();
break;
}
return success;
@ -331,6 +337,21 @@ bool ZigbeeDeviceObject::verifyNetworkError(ZigbeeDeviceObjectReply *zdoReply, Z
void ZigbeeDeviceObject::finishZdoReply(ZigbeeDeviceObjectReply *zdoReply)
{
switch(zdoReply->error()) {
case ZigbeeDeviceObjectReply::ErrorNoError:
qCDebug(dcZigbeeDeviceObject()) << "Reply finished successfully" << zdoReply->request();
break;
case ZigbeeDeviceObjectReply::ErrorZigbeeApsStatusError:
qCWarning(dcZigbeeDeviceObject()) << "Failed to send request to device" << zdoReply->request() << zdoReply->error() << zdoReply->zigbeeApsStatus();
break;
case ZigbeeDeviceObjectReply::ErrorZigbeeNwkStatusError:
qCWarning(dcZigbeeDeviceObject()) << "Failed to send request to device" << zdoReply->request() << zdoReply->error() << zdoReply->zigbeeNwkStatus();
break;
default:
qCWarning(dcZigbeeDeviceObject()) << "Failed to send request to device" << zdoReply->request() << zdoReply->error();
break;
}
m_pendingReplies.remove(zdoReply->transactionSequenceNumber());
zdoReply->finished();
}

View File

@ -39,6 +39,16 @@ ZigbeeDeviceObjectReply::Error ZigbeeDeviceObjectReply::error() const
return m_error;
}
Zigbee::ZigbeeApsStatus ZigbeeDeviceObjectReply::zigbeeApsStatus() const
{
return m_zigbeeApsStatus;
}
Zigbee::ZigbeeNwkLayerStatus ZigbeeDeviceObjectReply::zigbeeNwkStatus() const
{
return m_zigbeeNwkStatus;
}
ZigbeeNetworkRequest ZigbeeDeviceObjectReply::request() const
{
return m_request;
@ -64,11 +74,6 @@ ZigbeeDeviceProfile::Adpu ZigbeeDeviceObjectReply::responseAdpu() const
return m_responseAdpu;
}
Zigbee::ZigbeeApsStatus ZigbeeDeviceObjectReply::zigbeeApsStatus() const
{
return m_zigbeeApsStatus;
}
bool ZigbeeDeviceObjectReply::isComplete() const
{
return m_apsConfirmReceived && m_zdpIndicationReceived;

View File

@ -44,12 +44,15 @@ public:
ErrorNoError, // All OK, no error occured, the message was transported successfully
ErrorTimeout, // The request timeouted
ErrorZigbeeApsStatusError, // An APS transport error occured. See zigbeeApsStatus()
ErrorZigbeeNwkStatusError, // An NWK layer error occured. See zigbeeNwkStatus()
ErrorInterfaceError, // A transport interface error occured. Could not communicate with the hardware.
ErrorNetworkOffline // The network is offline. Cannot send any requests
};
Q_ENUM(Error)
Error error() const;
Zigbee::ZigbeeApsStatus zigbeeApsStatus() const;
Zigbee::ZigbeeNwkLayerStatus zigbeeNwkStatus() const;
ZigbeeNetworkRequest request() const;
quint8 transactionSequenceNumber() const;
@ -58,7 +61,6 @@ public:
QByteArray responseData() const;
ZigbeeDeviceProfile::Adpu responseAdpu() const;
Zigbee::ZigbeeApsStatus zigbeeApsStatus() const;
bool isComplete() const;
@ -74,6 +76,7 @@ private:
// APS transport
bool m_apsConfirmReceived = false;
Zigbee::ZigbeeApsStatus m_zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess;
Zigbee::ZigbeeNwkLayerStatus m_zigbeeNwkStatus = Zigbee::ZigbeeNwkLayerStatusSuccess;
// ZDP response data
bool m_zdpIndicationReceived = false;

View File

@ -391,8 +391,7 @@ public:
Q_ENUM(Manufacturer)
enum ZigbeeNwkLayerStatus {
ZigbeeNwkLayerStatusJointNetwork = 0x00,
ZigbeeNwkLayerStatusFormedNetwork = 0x01,
ZigbeeNwkLayerStatusSuccess = 0x00,
ZigbeeNwkLayerStatusInvalidParameter = 0xc1,
ZigbeeNwkLayerStatusInvalidRequest = 0xc2,
ZigbeeNwkLayerStatusNotPermitted = 0xc3,
@ -403,10 +402,13 @@ public:
ZigbeeNwkLayerStatusUnknownDevice = 0xc8,
ZigbeeNwkLayerStatusUnsupportedAttribute = 0xc9,
ZigbeeNwkLayerStatusNoNetworks = 0xca,
ZigbeeNwkLayerStatusLeaveUnconfirmed = 0xcb,
ZigbeeNwkLayerStatusMaxFrmCntr = 0xcc,
ZigbeeNwkLayerStatusNoKey = 0xcd,
ZigbeeNwkLayerStatusBadCcmOutput = 0xce
ZigbeeNwkLayerStatusBadCcmOutput = 0xce,
ZigbeeNwkLayerStatusRouteDiscoveryFailed = 0xd0,
ZigbeeNwkLayerStatusRouteError = 0xd1,
ZigbeeNwkLayerStatusBtTableFull = 0xd2,
ZigbeeNwkLayerStatusFrameNotBuffered = 0xd3
};
Q_ENUM(ZigbeeNwkLayerStatus)

View File

@ -541,25 +541,46 @@ ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest
{
ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this);
// Make sure the reply will be deleted
connect(reply, &ZigbeeNetworkReply::finished, reply, &ZigbeeNetworkReply::deleteLater);
connect(reply, &ZigbeeNetworkReply::finished, reply, &ZigbeeNetworkReply::deleteLater, Qt::QueuedConnection);
return reply;
}
void ZigbeeNetwork::setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus)
{
reply->m_zigbeeApsStatus = zigbeeApsStatus;
if (reply->m_zigbeeApsStatus == Zigbee::ZigbeeApsStatusSuccess) {
if (zigbeeApsStatus == Zigbee::ZigbeeApsStatusSuccess) {
// The request has been sent successfully to the device
finishNetworkReply(reply);
} else {
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeApsStatusError);
// There has been an error while transporting the request to the device
// Note: if the APS status is >= 0xc1, it has to interpreted as NWK layer error
if (zigbeeApsStatus >= 0xc1) {
reply->m_zigbeeNwkStatus = static_cast<Zigbee::ZigbeeNwkLayerStatus>(static_cast<quint8>(zigbeeApsStatus));
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeNwkStatusError);
} else {
reply->m_zigbeeApsStatus = zigbeeApsStatus;
finishNetworkReply(reply, ZigbeeNetworkReply::ErrorZigbeeApsStatusError);
}
}
}
void ZigbeeNetwork::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error)
{
qCDebug(dcZigbeeNetwork()) << "Reply finished" << error << reply->request();
reply->m_error = error;
switch(reply->error()) {
case ZigbeeNetworkReply::ErrorNoError:
qCDebug(dcZigbeeNetwork()) << "Network request sent successfully to device" << reply->request();
break;
case ZigbeeNetworkReply::ErrorZigbeeApsStatusError:
qCWarning(dcZigbeeNetwork()) << "Failed to send request to device" << reply->request() << reply->error() << reply->zigbeeApsStatus();
break;
case ZigbeeNetworkReply::ErrorZigbeeNwkStatusError:
qCWarning(dcZigbeeNetwork()) << "Failed to send request to device" << reply->request() << reply->error() << reply->zigbeeNwkStatus();
break;
default:
qCWarning(dcZigbeeNetwork()) << "Failed to send request to device" << reply->request() << reply->error();
break;
}
reply->finished();
}

View File

@ -42,6 +42,11 @@ Zigbee::ZigbeeApsStatus ZigbeeNetworkReply::zigbeeApsStatus() const
return m_zigbeeApsStatus;
}
Zigbee::ZigbeeNwkLayerStatus ZigbeeNetworkReply::zigbeeNwkStatus() const
{
return m_zigbeeNwkStatus;
}
ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) :
QObject(parent),
m_request(request)

View File

@ -44,6 +44,7 @@ public:
enum Error {
ErrorNoError,
ErrorZigbeeApsStatusError,
ErrorZigbeeNwkStatusError,
ErrorInterfaceError,
ErrorNetworkOffline
};
@ -53,6 +54,7 @@ public:
ZigbeeNetworkRequest request() const;
Zigbee::ZigbeeApsStatus zigbeeApsStatus() const;
Zigbee::ZigbeeNwkLayerStatus zigbeeNwkStatus() const;
private:
explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr);
@ -60,6 +62,7 @@ private:
Error m_error = ErrorNoError;
Zigbee::ZigbeeApsStatus m_zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess;
Zigbee::ZigbeeNwkLayerStatus m_zigbeeNwkStatus = Zigbee::ZigbeeNwkLayerStatusSuccess;
signals:
void finished();

View File

@ -122,6 +122,24 @@ bool ZigbeeNodeEndpoint::hasOutputCluster(Zigbee::ClusterId clusterId) const
return m_outputClusters.keys().contains(clusterId);
}
void ZigbeeNodeEndpoint::createInputCluster(quint16 clusterId)
{
Zigbee::ClusterId id = static_cast<Zigbee::ClusterId>(clusterId);
if (hasInputCluster(id))
return;
addInputCluster(createCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Server));
}
void ZigbeeNodeEndpoint::createOutputCluster(quint16 clusterId)
{
Zigbee::ClusterId id = static_cast<Zigbee::ClusterId>(clusterId);
if (hasInputCluster(id))
return;
addOutputCluster(createCluster(static_cast<Zigbee::ClusterId>(clusterId), ZigbeeCluster::Client));
}
ZigbeeNodeEndpoint::ZigbeeNodeEndpoint(ZigbeeNetwork *network, ZigbeeNode *node, quint8 endpointId, QObject *parent) :
QObject(parent),
m_network(network),

View File

@ -108,6 +108,13 @@ public:
return qobject_cast<T *>(getOutputCluster(clusterId));
}
// Note: these methods can be used for devices which do not
// show the clusters in the simple descriptor. By default these methods
// should not be neccessary
void createInputCluster(quint16 clusterId);
void createOutputCluster(quint16 clusterId);
private:
explicit ZigbeeNodeEndpoint(ZigbeeNetwork *network, ZigbeeNode *node, quint8 endpointId, QObject *parent = nullptr);
~ZigbeeNodeEndpoint();