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

View File

@ -27,6 +27,18 @@
#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
{
return m_error;
@ -76,11 +88,3 @@ bool ZigbeeClusterReply::isComplete() const
{
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
#include <QObject>
#include <QTimer>
#include "zigbeenetworkrequest.h"
#include "zigbeeclusterlibrary.h"
@ -73,6 +74,8 @@ private:
Error m_error = ErrorNoError;
QTimer m_timeoutTimer;
// Request
quint8 m_transactionSequenceNumber = 0;
ZigbeeNetworkRequest m_request;