diff --git a/libnymea-zigbee/backends/ti/interface/zigbeeinterfaceti.cpp b/libnymea-zigbee/backends/ti/interface/zigbeeinterfaceti.cpp index 06fe741..78453e5 100644 --- a/libnymea-zigbee/backends/ti/interface/zigbeeinterfaceti.cpp +++ b/libnymea-zigbee/backends/ti/interface/zigbeeinterfaceti.cpp @@ -99,6 +99,7 @@ void ZigbeeInterfaceTi::setAvailable(bool available) void ZigbeeInterfaceTi::onReconnectTimeout() { + qCDebug(dcZigbeeInterface()) << "Reconnecting to serial port..."; if (m_serialPort && !m_serialPort->isOpen()) { if (!m_serialPort->open(QSerialPort::ReadWrite)) { setAvailable(false); @@ -169,9 +170,7 @@ void ZigbeeInterfaceTi::onError(const QSerialPort::SerialPortError &error) { if (error != QSerialPort::NoError && m_serialPort->isOpen()) { qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString(); - m_reconnectTimer->start(); - m_serialPort->close(); - setAvailable(false); + reconnectController(); } } @@ -207,7 +206,7 @@ void ZigbeeInterfaceTi::sendPacket(Ti::CommandType type, Ti::SubSystem subSystem bool ZigbeeInterfaceTi::enable(const QString &serialPort, qint32 baudrate) { - qCDebug(dcZigbeeInterface()) << "Start UART interface " << serialPort << baudrate; + qCDebug(dcZigbeeInterface()) << "Starting UART interface " << serialPort << baudrate; if (m_serialPort) { delete m_serialPort; @@ -243,13 +242,18 @@ void ZigbeeInterfaceTi::reconnectController() if (!m_serialPort) return; - if (m_serialPort->isOpen()) + if (m_serialPort->isOpen()) { m_serialPort->close(); + } + + QString portName = m_serialPort->portName(); + int baudrate = m_serialPort->baudRate(); + setAvailable(false); delete m_serialPort; m_serialPort = nullptr; - setAvailable(false); - m_reconnectTimer->start(); + + enable(portName, baudrate); } void ZigbeeInterfaceTi::disable() diff --git a/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.cpp b/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.cpp index cad4ba7..a755b87 100644 --- a/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.cpp +++ b/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.cpp @@ -52,7 +52,7 @@ Ti::StatusCode ZigbeeInterfaceTiReply::statusCode() const return m_statusCode; } -bool ZigbeeInterfaceTiReply::timendOut() const +bool ZigbeeInterfaceTiReply::timedOut() const { return m_timeout; } diff --git a/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.h b/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.h index b9bec18..b36115c 100644 --- a/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.h +++ b/libnymea-zigbee/backends/ti/interface/zigbeeinterfacetireply.h @@ -54,7 +54,7 @@ public: // Response content Ti::StatusCode statusCode() const; - bool timendOut() const; + bool timedOut() const; bool aborted() const; void abort(); diff --git a/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.cpp b/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.cpp index 9c01eeb..b087c55 100644 --- a/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.cpp +++ b/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.cpp @@ -72,14 +72,22 @@ ZigbeeInterfaceTiReply* ZigbeeBridgeControllerTi::reset() stream << static_cast(Ti::ResetTypeSoft); ZigbeeInterfaceTiReply *resetReply = sendCommand(Ti::SubSystemSys, Ti::SYSCommandResetReq, payload); waitFor(resetReply, Ti::SubSystemSys, Ti::SYSCommandResetInd); + connect(resetReply, &ZigbeeInterfaceTiReply::finished, this, [=](){ + m_interface->reconnectController(); + }); return resetReply; } ZigbeeInterfaceTiReply *ZigbeeBridgeControllerTi::init() { + m_registeredEndpointIds.clear(); + ZigbeeInterfaceTiReply *initReply = new ZigbeeInterfaceTiReply(this, 15000); - ZigbeeInterfaceTiReply *resetReply = reset(); + // Not using public reset() as that will start the init from scratch by reconnecting the controller + NEW_PAYLOAD + stream << static_cast(Ti::ResetTypeSoft); + ZigbeeInterfaceTiReply *resetReply = sendCommand(Ti::SubSystemSys, Ti::SYSCommandResetReq, payload); connect(resetReply, &ZigbeeInterfaceTiReply::finished, initReply, [=]() { qCDebug(dcZigbeeController()) << "Skipping CC2530/CC2531 bootloader."; @@ -486,17 +494,25 @@ void ZigbeeBridgeControllerTi::sendNextRequest() ZigbeeInterfaceTiReply *ZigbeeBridgeControllerTi::sendCommand(Ti::SubSystem subSystem, quint8 command, const QByteArray &payload, int timeout) { - // Create the reply ZigbeeInterfaceTiReply *reply = new ZigbeeInterfaceTiReply(subSystem, command, this, payload, timeout); - // Make sure we clean up on timeout - connect(reply, &ZigbeeInterfaceTiReply::timeout, this, [reply](){ - qCWarning(dcZigbeeController()) << "Reply timeout" << reply; - // Note: send next reply with the finished signal - }); + connect(reply, &ZigbeeInterfaceTiReply::finished, reply, [=](){ + + if (reply->timedOut()) { + if (m_controllerState == ControllerStateRunning) { + qCWarning(dcZigbeeController()) << "Interface command timed out."; + if (++m_timeouts < 5) { + qCInfo(dcZigbeeController()) << "Retrying..." << m_timeouts << "/" << 5; + sendCommand(subSystem, command, payload, timeout); + } else { + qCInfo(dcZigbeeController()) << "Resetting ZigBee interface"; + m_interface->reconnectController(); + } + } + } else { + m_timeouts = 0; + } - // Auto delete the object on finished - connect(reply, &ZigbeeInterfaceTiReply::finished, reply, [this, reply](){ if (m_currentReply == reply) { m_currentReply = nullptr; QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection); @@ -731,6 +747,9 @@ void ZigbeeBridgeControllerTi::onInterfaceAvailableChanged(bool available) ZigbeeInterfaceTiReply *reply = m_replyQueue.dequeue(); reply->abort(); } + + m_controllerState = ControllerStateDown; + emit controllerStateChanged(m_controllerState); } setAvailable(available); diff --git a/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.h b/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.h index afdaa12..e5d7717 100644 --- a/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.h +++ b/libnymea-zigbee/backends/ti/zigbeebridgecontrollerti.h @@ -144,6 +144,7 @@ private: QTimer m_permitJoinTimer; QList m_registeredEndpointIds; + int m_timeouts = 0; void finishRequest(Ti::StatusCode statusCode = Ti::StatusCodeSuccess); }; diff --git a/libnymea-zigbee/zcl/zigbeecluster.cpp b/libnymea-zigbee/zcl/zigbeecluster.cpp index 27e1f5c..a3bb0b9 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.cpp +++ b/libnymea-zigbee/zcl/zigbeecluster.cpp @@ -206,6 +206,7 @@ ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber; m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply); connect(zclReply, &ZigbeeClusterReply::finished, this, [this, zclReply](){ + qCDebug(dcZigbeeCluster()) << "ZCL request to" << zclReply->request().destinationShortAddress() << "finished with status:" << zclReply->error(); zclReply->deleteLater(); m_pendingReplies.remove(zclReply->transactionSequenceNumber()); }); @@ -367,6 +368,7 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo case ZigbeeNetworkReply::ErrorNoError: // The request has been transported successfully to he destination, now // wait for the expected indication or check if we already recieved it + qCDebug(dcZigbeeCluster()) << "ZCL request sent. Waiting for response data indication..."; zclReply->m_apsConfirmReceived = true; if (!zclReply->m_zclIndicationReceived) { zclReply->m_timeoutTimer.start();