Merge PR #67: Deconz: Fixes for command queuing

This commit is contained in:
jenkins 2022-10-17 11:19:57 +02:00
commit 6200856678
4 changed files with 56 additions and 10 deletions

View File

@ -84,7 +84,7 @@ ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command,
m_timer(new QTimer(this)), m_timer(new QTimer(this)),
m_command(command) m_command(command)
{ {
m_timer->setInterval(5000); m_timer->setInterval(10000);
m_timer->setSingleShot(true); m_timer->setSingleShot(true);
connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout); connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout);
} }

View File

@ -233,9 +233,13 @@ void ZigbeeBridgeControllerDeconz::sendNextRequest()
if (m_currentReply) if (m_currentReply)
return; return;
// // FIXME: If the controler request queue is full, wait until it's free again // If the controler request queue is full, wait until it's free again
// if (!m_apsFreeSlotsAvailable) if (!m_apsFreeSlotsAvailable)
// return; return;
if (!m_available) {
return;
}
// Get the next reply, set the sequence number, send the request data over the interface and start waiting // Get the next reply, set the sequence number, send the request data over the interface and start waiting
m_currentReply = m_replyQueue.dequeue(); m_currentReply = m_replyQueue.dequeue();
@ -864,14 +868,15 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt
} }
if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) { if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) {
m_apsFreeSlotsAvailable = deviceState.apsDataRequestFreeSlots; if (!deviceState.apsDataRequestFreeSlots) {
if (!m_apsFreeSlotsAvailable) {
// Warn only if the network is up // Warn only if the network is up
if (m_networkState == Deconz::NetworkStateConnected) { 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."; 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; return;
} else { } else {
m_apsFreeSlotsAvailable = true;
qCDebug(dcZigbeeController()) << "The APS request table is free again. Sending the next request"; qCDebug(dcZigbeeController()) << "The APS request table is free again. Sending the next request";
sendNextRequest(); sendNextRequest();
} }
@ -1021,6 +1026,14 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
// Check if this is the response to the current active reply // Check if this is the response to the current active reply
if (m_currentReply && m_currentReply->sequenceNumber() == sequenceNumber && m_currentReply->command() == command) { 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_responseData = data;
m_currentReply->m_statusCode = status; m_currentReply->m_statusCode = status;
emit m_currentReply->finished(); emit m_currentReply->finished();

View File

@ -76,6 +76,14 @@ ZigbeeNetworkReply *ZigbeeNetworkDeconz::sendRequest(const ZigbeeNetworkRequest
return reply; 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); ZigbeeInterfaceDeconzReply *interfaceReply = m_controller->requestSendRequest(request);
connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, reply, [this, reply, interfaceReply](){ connect(interfaceReply, &ZigbeeInterfaceDeconzReply::finished, reply, [this, reply, interfaceReply](){
if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) { if (interfaceReply->statusCode() != Deconz::StatusCodeSuccess) {
@ -157,6 +165,25 @@ ZigbeeNetworkReply *ZigbeeNetworkDeconz::requestSetPermitJoin(quint16 shortAddre
return sendRequest(request); 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) void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetworkState state)
{ {
if (m_createState == state) if (m_createState == state)
@ -379,19 +406,21 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
setState(StateRunning); setState(StateRunning);
setPermitJoining(0); setPermitJoining(0);
sendPendingRequests();
return; return;
} }
m_initializing = false;
setState(StateRunning);
setPermitJoining(0);
ZigbeeNode *coordinatorNode = createNode(m_controller->networkConfiguration().shortAddress, m_controller->networkConfiguration().ieeeAddress, this); ZigbeeNode *coordinatorNode = createNode(m_controller->networkConfiguration().shortAddress, m_controller->networkConfiguration().ieeeAddress, this);
m_coordinatorNode = coordinatorNode; m_coordinatorNode = coordinatorNode;
// Network creation done when coordinator node is initialized
connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){ connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){
if (state == ZigbeeNode::StateInitialized) { if (state == ZigbeeNode::StateInitialized) {
qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode; qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode;
m_initializing = false; sendPendingRequests();
setState(StateRunning);
setPermitJoining(0);
return; return;
} }
}); });
@ -534,6 +563,7 @@ void ZigbeeNetworkDeconz::runNetworkInitProcess()
qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode(); qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode();
setState(StateRunning); setState(StateRunning);
sendPendingRequests();
}); });
} else if (m_controller->networkState() == Deconz::NetworkStateOffline) { } else if (m_controller->networkState() == Deconz::NetworkStateOffline) {

View File

@ -68,6 +68,7 @@ private:
QString m_protocolVersion; QString m_protocolVersion;
QString m_firmwareVersion; QString m_firmwareVersion;
QList<ZigbeeNetworkReply*> m_requestQueue;
QHash<quint8, ZigbeeNetworkReply *> m_pendingReplies; QHash<quint8, ZigbeeNetworkReply *> m_pendingReplies;
QTimer *m_pollNetworkStateTimer = nullptr; QTimer *m_pollNetworkStateTimer = nullptr;
@ -79,6 +80,8 @@ private:
ZigbeeNetworkReply *requestSetPermitJoin(quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, quint8 duration = 0xfe); ZigbeeNetworkReply *requestSetPermitJoin(quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, quint8 duration = 0xfe);
void sendPendingRequests();
protected: protected:
void startNetworkInternally(); void startNetworkInternally();