From b96f9fa98f751d70b787404e39982e60eba795d6 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 25 Apr 2022 14:31:10 +0200 Subject: [PATCH] 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. --- libnymea-zigbee/zcl/zigbeecluster.cpp | 17 +++++++++++------ libnymea-zigbee/zcl/zigbeeclusterreply.cpp | 20 ++++++++++++-------- libnymea-zigbee/zcl/zigbeeclusterreply.h | 3 +++ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/libnymea-zigbee/zcl/zigbeecluster.cpp b/libnymea-zigbee/zcl/zigbeecluster.cpp index a74e8d2..280d86e 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.cpp +++ b/libnymea-zigbee/zcl/zigbeecluster.cpp @@ -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(); diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp index fc36d1b..510b162 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp @@ -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) -{ - -} diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.h b/libnymea-zigbee/zcl/zigbeeclusterreply.h index 9d47d9e..a37c5a3 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.h +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.h @@ -29,6 +29,7 @@ #define ZIGBEECLUSTERREPLY_H #include +#include #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;