diff --git a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp index 66015d4..6561511 100644 --- a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp +++ b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp @@ -84,7 +84,7 @@ ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, m_timer(new QTimer(this)), m_command(command) { - m_timer->setInterval(5000); + m_timer->setInterval(10000); m_timer->setSingleShot(true); connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout); } diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp index d76dfd7..c236697 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp @@ -233,9 +233,13 @@ void ZigbeeBridgeControllerDeconz::sendNextRequest() if (m_currentReply) return; - // // FIXME: If the controler request queue is full, wait until it's free again - // if (!m_apsFreeSlotsAvailable) - // return; + // If the controler request queue is full, wait until it's free again + if (!m_apsFreeSlotsAvailable) + return; + + if (!m_available) { + return; + } // Get the next reply, set the sequence number, send the request data over the interface and start waiting m_currentReply = m_replyQueue.dequeue(); @@ -864,14 +868,15 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt } if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) { - m_apsFreeSlotsAvailable = deviceState.apsDataRequestFreeSlots; - if (!m_apsFreeSlotsAvailable) { + if (!deviceState.apsDataRequestFreeSlots) { // Warn only if the network is up if (m_networkState == Deconz::NetworkStateConnected) { qCWarning(dcZigbeeController()) << "The APS request table is full on the device. Cannot send requests until the queue gets processed on the controller."; + m_apsFreeSlotsAvailable = false; } return; } else { + m_apsFreeSlotsAvailable = true; qCDebug(dcZigbeeController()) << "The APS request table is free again. Sending the next request"; sendNextRequest(); } @@ -1021,6 +1026,14 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray & // Check if this is the response to the current active reply if (m_currentReply && m_currentReply->sequenceNumber() == sequenceNumber && m_currentReply->command() == command) { + // If the controller is busy, let's try again once the device state reports free slots + if (status == Deconz::StatusCodeBusy) { + qCWarning(dcZigbeeController()) << "Controller busy. Rescheduling command."; + m_apsFreeSlotsAvailable = false; + m_replyQueue.prepend(m_currentReply); + m_currentReply = nullptr; + return; + } m_currentReply->m_responseData = data; m_currentReply->m_statusCode = status; emit m_currentReply->finished(); diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp index b3f511a..9342031 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp @@ -76,6 +76,14 @@ ZigbeeNetworkReply *ZigbeeNetworkDeconz::sendRequest(const ZigbeeNetworkRequest return reply; } + if (state() == ZigbeeNetwork::StateStarting) { + m_requestQueue.append(reply); + connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){ + m_requestQueue.removeAll(reply); + }); + return reply; + } + ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(request); connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, reply, [this, reply, interfaceReply](){ if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) { @@ -157,6 +165,25 @@ ZigbeeNetworkReply *ZigbeeNetworkDeconz::requestSetPermitJoin(quint16 shortAddre return sendRequest(request); } +void ZigbeeNetworkDeconz::sendPendingRequests() +{ + while (!m_requestQueue.isEmpty()) { + ZigbeeNetworkReply *reply = m_requestQueue.takeFirst(); + + ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(reply->request()); + connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, reply, [this, reply, interfaceReply](){ + if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not send request to controller. SQN:" << interfaceReply->sequenceNumber() << interfaceReply->statusCode(); + finishNetworkReply(reply, ZigbeeNetworkReply::ErrorInterfaceError); + return; + } + + // The request has been sent successfully to the device, start the timeout timer now + startWaitingReply(reply); + }); + } +} + void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetworkState state) { if (m_createState == state) @@ -379,19 +406,21 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo setState(StateRunning); setPermitJoining(0); + sendPendingRequests(); return; } + m_initializing = false; + setState(StateRunning); + setPermitJoining(0); + ZigbeeNode *coordinatorNode = createNode(m_controller->networkConfiguration().shortAddress, m_controller->networkConfiguration().ieeeAddress, this); m_coordinatorNode = coordinatorNode; - // Network creation done when coordinator node is initialized connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){ if (state == ZigbeeNode::StateInitialized) { qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode; - m_initializing = false; - setState(StateRunning); - setPermitJoining(0); + sendPendingRequests(); return; } }); @@ -534,6 +563,7 @@ void ZigbeeNetworkDeconz::runNetworkInitProcess() qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode(); setState(StateRunning); + sendPendingRequests(); }); } else if (m_controller->networkState() == Deconz::NetworkStateOffline) { diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h index 6a5b271..eb36fcc 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h @@ -68,6 +68,7 @@ private: QString m_protocolVersion; QString m_firmwareVersion; + QList m_requestQueue; QHash m_pendingReplies; QTimer *m_pollNetworkStateTimer = nullptr; @@ -79,6 +80,8 @@ private: ZigbeeNetworkReply *requestSetPermitJoin(quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, quint8 duration = 0xfe); + void sendPendingRequests(); + protected: void startNetworkInternally();