Timeout ZCL replies

This is basically the same as #41 does with ZDO replies but for ZCL replies.

Working with a z-stack dongle and a Gewiss binary input device a lot of
timeouts happen during the device interview. While basic device interview
timeouts are caught by the ZDO timeouts, later interview steps like
cluster attribute reading run into the same issue with this device and
the interview process never finishes.
This commit is contained in:
Michael Zanetti 2022-04-25 14:31:10 +02:00
parent 187278cf7c
commit b96f9fa98f
3 changed files with 26 additions and 14 deletions

View File

@ -183,7 +183,7 @@ ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QB
ZigbeeClusterReply *zclReply = createClusterReply(request, frame); ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ connect(networkReply, &ZigbeeNetworkReply::finished, zclReply, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) { if (!verifyNetworkError(zclReply, networkReply)) {
finishZclReply(zclReply); finishZclReply(zclReply);
return; return;
@ -203,9 +203,12 @@ ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QB
ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame) ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame)
{ {
ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this); ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this);
connect(zclReply, &ZigbeeClusterReply::finished, zclReply, &ZigbeeClusterReply::deleteLater, Qt::QueuedConnection);
zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber; zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply); m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply);
connect(zclReply, &ZigbeeClusterReply::finished, this, [this, zclReply](){
zclReply->deleteLater();
m_pendingReplies.remove(zclReply->transactionSequenceNumber());
}, Qt::QueuedConnection);
return zclReply; return zclReply;
} }
@ -237,7 +240,7 @@ ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const Q
ZigbeeClusterReply *zclReply = createClusterReply(request, frame); ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
qCDebug(dcZigbeeCluster()) << "Executing command" << ZigbeeUtils::convertByteToHexString(command) << ZigbeeUtils::convertByteArrayToHexString(payload); qCDebug(dcZigbeeCluster()) << "Executing command" << ZigbeeUtils::convertByteToHexString(command) << ZigbeeUtils::convertByteArrayToHexString(payload);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ connect(networkReply, &ZigbeeNetworkReply::finished, zclReply, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) { if (!verifyNetworkError(zclReply, networkReply)) {
finishZclReply(zclReply); finishZclReply(zclReply);
return; return;
@ -282,7 +285,7 @@ ZigbeeClusterReply *ZigbeeCluster::sendClusterServerResponse(quint8 command, qui
ZigbeeClusterReply *zclReply = createClusterReply(request, frame); ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
qCDebug(dcZigbeeCluster()) << "Send command response" << ZigbeeUtils::convertByteToHexString(command) << "TSN:" << ZigbeeUtils::convertByteToHexString(transactionSequenceNumber) << ZigbeeUtils::convertByteArrayToHexString(payload); qCDebug(dcZigbeeCluster()) << "Send command response" << ZigbeeUtils::convertByteToHexString(command) << "TSN:" << ZigbeeUtils::convertByteToHexString(transactionSequenceNumber) << ZigbeeUtils::convertByteArrayToHexString(payload);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ connect(networkReply, &ZigbeeNetworkReply::finished, zclReply, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) { if (!verifyNetworkError(zclReply, networkReply)) {
finishZclReply(zclReply); finishZclReply(zclReply);
return; return;
@ -328,7 +331,7 @@ ZigbeeClusterReply *ZigbeeCluster::sendDefaultResponse(quint8 transactionSequenc
ZigbeeClusterReply *zclReply = createClusterReply(request, frame); ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
qCDebug(dcZigbeeCluster()) << "Send default response" << "TSN:" << ZigbeeUtils::convertByteToHexString(transactionSequenceNumber) << ZigbeeUtils::convertByteArrayToHexString(payload); qCDebug(dcZigbeeCluster()) << "Send default response" << "TSN:" << ZigbeeUtils::convertByteToHexString(transactionSequenceNumber) << ZigbeeUtils::convertByteArrayToHexString(payload);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){ connect(networkReply, &ZigbeeNetworkReply::finished, zclReply, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) { if (!verifyNetworkError(zclReply, networkReply)) {
finishZclReply(zclReply); finishZclReply(zclReply);
return; return;
@ -365,6 +368,9 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo
// The request has been transported successfully to he destination, now // The request has been transported successfully to he destination, now
// wait for the expected indication or check if we already recieved it // wait for the expected indication or check if we already recieved it
zclReply->m_apsConfirmReceived = true; zclReply->m_apsConfirmReceived = true;
if (!zclReply->m_zclIndicationReceived) {
zclReply->m_timeoutTimer.start();
}
success = true; success = true;
break; break;
case ZigbeeNetworkReply::ErrorTimeout: case ZigbeeNetworkReply::ErrorTimeout:
@ -404,7 +410,6 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo
void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply) void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply)
{ {
m_pendingReplies.remove(zclReply->transactionSequenceNumber());
qCDebug(dcZigbeeCluster()) << "ZigbeeClusterReply finished" << zclReply->request() << zclReply->requestFrame() << zclReply->responseFrame(); qCDebug(dcZigbeeCluster()) << "ZigbeeClusterReply finished" << zclReply->request() << zclReply->requestFrame() << zclReply->responseFrame();
// FIXME: Set the status // FIXME: Set the status
emit zclReply->finished(); emit zclReply->finished();

View File

@ -27,6 +27,18 @@
#include "zigbeeclusterreply.h" #include "zigbeeclusterreply.h"
ZigbeeClusterReply::ZigbeeClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame requestFrame, QObject *parent) :
QObject(parent),
m_request(request),
m_requestFrame(requestFrame)
{
m_timeoutTimer.setInterval(10000);
connect(&m_timeoutTimer, &QTimer::timeout, this, [this](){
m_error = ErrorTimeout;
emit finished();
});
}
ZigbeeClusterReply::Error ZigbeeClusterReply::error() const ZigbeeClusterReply::Error ZigbeeClusterReply::error() const
{ {
return m_error; return m_error;
@ -76,11 +88,3 @@ bool ZigbeeClusterReply::isComplete() const
{ {
return m_apsConfirmReceived && m_zclIndicationReceived; return m_apsConfirmReceived && m_zclIndicationReceived;
} }
ZigbeeClusterReply::ZigbeeClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame requestFrame, QObject *parent) :
QObject(parent),
m_request(request),
m_requestFrame(requestFrame)
{
}

View File

@ -29,6 +29,7 @@
#define ZIGBEECLUSTERREPLY_H #define ZIGBEECLUSTERREPLY_H
#include <QObject> #include <QObject>
#include <QTimer>
#include "zigbeenetworkrequest.h" #include "zigbeenetworkrequest.h"
#include "zigbeeclusterlibrary.h" #include "zigbeeclusterlibrary.h"
@ -73,6 +74,8 @@ private:
Error m_error = ErrorNoError; Error m_error = ErrorNoError;
QTimer m_timeoutTimer;
// Request // Request
quint8 m_transactionSequenceNumber = 0; quint8 m_transactionSequenceNumber = 0;
ZigbeeNetworkRequest m_request; ZigbeeNetworkRequest m_request;