Fixes reconnecting the ZigBee controller after a reset during runtime
Resets may occur by unplugging the stick or calling a softReset() from the software side. Additionally resets the stick when 5 subsequent timeouts happen as there are firmwares of the CC2652 available which tend to crash occationally.
This commit is contained in:
parent
0f18424d6d
commit
22837865f1
@ -99,6 +99,7 @@ void ZigbeeInterfaceTi::setAvailable(bool available)
|
|||||||
|
|
||||||
void ZigbeeInterfaceTi::onReconnectTimeout()
|
void ZigbeeInterfaceTi::onReconnectTimeout()
|
||||||
{
|
{
|
||||||
|
qCDebug(dcZigbeeInterface()) << "Reconnecting to serial port...";
|
||||||
if (m_serialPort && !m_serialPort->isOpen()) {
|
if (m_serialPort && !m_serialPort->isOpen()) {
|
||||||
if (!m_serialPort->open(QSerialPort::ReadWrite)) {
|
if (!m_serialPort->open(QSerialPort::ReadWrite)) {
|
||||||
setAvailable(false);
|
setAvailable(false);
|
||||||
@ -169,9 +170,7 @@ void ZigbeeInterfaceTi::onError(const QSerialPort::SerialPortError &error)
|
|||||||
{
|
{
|
||||||
if (error != QSerialPort::NoError && m_serialPort->isOpen()) {
|
if (error != QSerialPort::NoError && m_serialPort->isOpen()) {
|
||||||
qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString();
|
qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString();
|
||||||
m_reconnectTimer->start();
|
reconnectController();
|
||||||
m_serialPort->close();
|
|
||||||
setAvailable(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +206,7 @@ void ZigbeeInterfaceTi::sendPacket(Ti::CommandType type, Ti::SubSystem subSystem
|
|||||||
|
|
||||||
bool ZigbeeInterfaceTi::enable(const QString &serialPort, qint32 baudrate)
|
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) {
|
if (m_serialPort) {
|
||||||
delete m_serialPort;
|
delete m_serialPort;
|
||||||
@ -243,13 +242,18 @@ void ZigbeeInterfaceTi::reconnectController()
|
|||||||
if (!m_serialPort)
|
if (!m_serialPort)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_serialPort->isOpen())
|
if (m_serialPort->isOpen()) {
|
||||||
m_serialPort->close();
|
m_serialPort->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString portName = m_serialPort->portName();
|
||||||
|
int baudrate = m_serialPort->baudRate();
|
||||||
|
setAvailable(false);
|
||||||
|
|
||||||
delete m_serialPort;
|
delete m_serialPort;
|
||||||
m_serialPort = nullptr;
|
m_serialPort = nullptr;
|
||||||
setAvailable(false);
|
|
||||||
m_reconnectTimer->start();
|
enable(portName, baudrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeInterfaceTi::disable()
|
void ZigbeeInterfaceTi::disable()
|
||||||
|
|||||||
@ -52,7 +52,7 @@ Ti::StatusCode ZigbeeInterfaceTiReply::statusCode() const
|
|||||||
return m_statusCode;
|
return m_statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZigbeeInterfaceTiReply::timendOut() const
|
bool ZigbeeInterfaceTiReply::timedOut() const
|
||||||
{
|
{
|
||||||
return m_timeout;
|
return m_timeout;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ public:
|
|||||||
// Response content
|
// Response content
|
||||||
Ti::StatusCode statusCode() const;
|
Ti::StatusCode statusCode() const;
|
||||||
|
|
||||||
bool timendOut() const;
|
bool timedOut() const;
|
||||||
bool aborted() const;
|
bool aborted() const;
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
|
|||||||
@ -72,14 +72,22 @@ ZigbeeInterfaceTiReply* ZigbeeBridgeControllerTi::reset()
|
|||||||
stream << static_cast<quint8>(Ti::ResetTypeSoft);
|
stream << static_cast<quint8>(Ti::ResetTypeSoft);
|
||||||
ZigbeeInterfaceTiReply *resetReply = sendCommand(Ti::SubSystemSys, Ti::SYSCommandResetReq, payload);
|
ZigbeeInterfaceTiReply *resetReply = sendCommand(Ti::SubSystemSys, Ti::SYSCommandResetReq, payload);
|
||||||
waitFor(resetReply, Ti::SubSystemSys, Ti::SYSCommandResetInd);
|
waitFor(resetReply, Ti::SubSystemSys, Ti::SYSCommandResetInd);
|
||||||
|
connect(resetReply, &ZigbeeInterfaceTiReply::finished, this, [=](){
|
||||||
|
m_interface->reconnectController();
|
||||||
|
});
|
||||||
return resetReply;
|
return resetReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeInterfaceTiReply *ZigbeeBridgeControllerTi::init()
|
ZigbeeInterfaceTiReply *ZigbeeBridgeControllerTi::init()
|
||||||
{
|
{
|
||||||
|
m_registeredEndpointIds.clear();
|
||||||
|
|
||||||
ZigbeeInterfaceTiReply *initReply = new ZigbeeInterfaceTiReply(this, 15000);
|
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<quint8>(Ti::ResetTypeSoft);
|
||||||
|
ZigbeeInterfaceTiReply *resetReply = sendCommand(Ti::SubSystemSys, Ti::SYSCommandResetReq, payload);
|
||||||
connect(resetReply, &ZigbeeInterfaceTiReply::finished, initReply, [=]() {
|
connect(resetReply, &ZigbeeInterfaceTiReply::finished, initReply, [=]() {
|
||||||
|
|
||||||
qCDebug(dcZigbeeController()) << "Skipping CC2530/CC2531 bootloader.";
|
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)
|
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);
|
ZigbeeInterfaceTiReply *reply = new ZigbeeInterfaceTiReply(subSystem, command, this, payload, timeout);
|
||||||
|
|
||||||
// Make sure we clean up on timeout
|
connect(reply, &ZigbeeInterfaceTiReply::finished, reply, [=](){
|
||||||
connect(reply, &ZigbeeInterfaceTiReply::timeout, this, [reply](){
|
|
||||||
qCWarning(dcZigbeeController()) << "Reply timeout" << reply;
|
if (reply->timedOut()) {
|
||||||
// Note: send next reply with the finished signal
|
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) {
|
if (m_currentReply == reply) {
|
||||||
m_currentReply = nullptr;
|
m_currentReply = nullptr;
|
||||||
QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection);
|
||||||
@ -731,6 +747,9 @@ void ZigbeeBridgeControllerTi::onInterfaceAvailableChanged(bool available)
|
|||||||
ZigbeeInterfaceTiReply *reply = m_replyQueue.dequeue();
|
ZigbeeInterfaceTiReply *reply = m_replyQueue.dequeue();
|
||||||
reply->abort();
|
reply->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_controllerState = ControllerStateDown;
|
||||||
|
emit controllerStateChanged(m_controllerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAvailable(available);
|
setAvailable(available);
|
||||||
|
|||||||
@ -144,6 +144,7 @@ private:
|
|||||||
QTimer m_permitJoinTimer;
|
QTimer m_permitJoinTimer;
|
||||||
|
|
||||||
QList<int> m_registeredEndpointIds;
|
QList<int> m_registeredEndpointIds;
|
||||||
|
int m_timeouts = 0;
|
||||||
|
|
||||||
void finishRequest(Ti::StatusCode statusCode = Ti::StatusCodeSuccess);
|
void finishRequest(Ti::StatusCode statusCode = Ti::StatusCodeSuccess);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -206,6 +206,7 @@ ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest
|
|||||||
zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
|
zclReply->m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
|
||||||
m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply);
|
m_pendingReplies.insert(zclReply->transactionSequenceNumber(), zclReply);
|
||||||
connect(zclReply, &ZigbeeClusterReply::finished, this, [this, zclReply](){
|
connect(zclReply, &ZigbeeClusterReply::finished, this, [this, zclReply](){
|
||||||
|
qCDebug(dcZigbeeCluster()) << "ZCL request to" << zclReply->request().destinationShortAddress() << "finished with status:" << zclReply->error();
|
||||||
zclReply->deleteLater();
|
zclReply->deleteLater();
|
||||||
m_pendingReplies.remove(zclReply->transactionSequenceNumber());
|
m_pendingReplies.remove(zclReply->transactionSequenceNumber());
|
||||||
});
|
});
|
||||||
@ -367,6 +368,7 @@ bool ZigbeeCluster::verifyNetworkError(ZigbeeClusterReply *zclReply, ZigbeeNetwo
|
|||||||
case ZigbeeNetworkReply::ErrorNoError:
|
case ZigbeeNetworkReply::ErrorNoError:
|
||||||
// The request has been transported successfully to he destination, now
|
// The request has been transported successfully to he destination, now
|
||||||
// wait for the expected indication or check if we already recieved it
|
// 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;
|
zclReply->m_apsConfirmReceived = true;
|
||||||
if (!zclReply->m_zclIndicationReceived) {
|
if (!zclReply->m_zclIndicationReceived) {
|
||||||
zclReply->m_timeoutTimer.start();
|
zclReply->m_timeoutTimer.start();
|
||||||
|
|||||||
Reference in New Issue
Block a user