From a75bf9c18aa97f06258bce2a531304c86167d5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 25 Jan 2021 15:42:55 +0100 Subject: [PATCH] Rework init process and fix firmware version request to make it work on newest firmware revisions. Fix firmware version read request --- .../interface/zigbeeinterfacedeconz.cpp | 1 + .../deconz/zigbeebridgecontrollerdeconz.cpp | 9 +- .../deconz/zigbeebridgecontrollerdeconz.h | 1 + .../backends/deconz/zigbeenetworkdeconz.cpp | 181 ++++++++++-------- .../backends/deconz/zigbeenetworkdeconz.h | 2 + 5 files changed, 117 insertions(+), 77 deletions(-) diff --git a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp index fbb43dd..fb19e3b 100644 --- a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp +++ b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp @@ -146,6 +146,7 @@ void ZigbeeInterfaceDeconz::onReconnectTimeout() if (m_serialPort && !m_serialPort->isOpen()) { if (!m_serialPort->open(QSerialPort::ReadWrite)) { setAvailable(false); + qCDebug(dcZigbeeInterface()) << "Interface reconnected failed" << m_serialPort->portName() << m_serialPort->baudRate(); m_reconnectTimer->start(); } else { qCDebug(dcZigbeeInterface()) << "Interface reconnected successfully on" << m_serialPort->portName() << m_serialPort->baudRate(); diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp index 9e5b057..9023a77 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp @@ -76,7 +76,9 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion() stream << static_cast(Deconz::CommandVersion); stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd - stream << static_cast(5); // Frame length + stream << static_cast(9); // Frame length + stream << static_cast(0); + stream << static_cast(0); return createReply(Deconz::CommandVersion, "Request controller version", message, this); } @@ -747,6 +749,11 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi return state; } +void ZigbeeBridgeControllerDeconz::reconnectConrtroller() +{ + m_interface->reconnectController(); +} + void ZigbeeBridgeControllerDeconz::readDataIndication() { if (m_readIndicationReply) { diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h index e174628..3fc7f32 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h @@ -135,6 +135,7 @@ private: // Device state helper DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag); + void reconnectConrtroller(); void readDataIndication(); void readDataConfirm(); diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp index d3d67b1..b7654ac 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp @@ -392,118 +392,147 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo void ZigbeeNetworkDeconz::runNetworkInitProcess() { + // - Read the network state (until success) // - Read the firmware version // - Read the network configuration parameters - // - Read the network state // - If network running and we don't have configurations, write them // - If network running and configurations match, we are done // Read the firmware version - qCDebug(dcZigbeeNetwork()) << "Reading current firmware version..."; - ZigbeeInterfaceDeconzReply *reply = m_controller->requestVersion(); + qCDebug(dcZigbeeNetwork()) << "Request current device state..."; + ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode(); m_initRetry++; + if (!m_controller->available()) { + m_initRetry = 0; + return; + } + if (m_initRetry < 10) { qCDebug(dcZigbeeNetwork()) << "Retry to initialize network" << m_initRetry << "/ 10"; runNetworkInitProcess(); } else { - qCWarning(dcZigbeeNetwork()) << "Failed to read firmware version after 10 attempts. Giving up"; - m_controller->disable(); + qCWarning(dcZigbeeNetwork()) << "Failed to read device state after 10 attempts. Giving up"; + m_controller->reconnectConrtroller(); } return; } m_initRetry = 0; - qCDebug(dcZigbeeNetwork()) << "Version request finished successfully" << ZigbeeUtils::convertByteArrayToHexString(reply->responseData()); - // Note: version is an uint32 value, little endian, but we can read the individual bytes in reversed order - quint8 majorVersion = static_cast(reply->responseData().at(3)); - quint8 minorVersion = static_cast(reply->responseData().at(2)); - Deconz::Platform platform = static_cast(reply->responseData().at(1)); - QString firmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion); - qCDebug(dcZigbeeNetwork()) << "Firmware version" << firmwareVersion << platform; // Read all network parameters qCDebug(dcZigbeeNetwork()) << "Start reading controller network parameters..."; ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters(); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply, firmwareVersion](){ + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up." << reply->statusCode(); - // FIXME: set an appropriate error + m_initRetry++; + if (m_initRetry < 3) { + qCDebug(dcZigbeeNetwork()) << "Retry to read network parameters" << m_initRetry << "/ 3"; + runNetworkInitProcess(); + } else { + qCWarning(dcZigbeeNetwork()) << "Failed to read network parameters after 3 attempts. Giving up"; + m_controller->reconnectConrtroller(); + } return; } qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully."; - QString protocolVersion = QString("%1.%2").arg(m_controller->networkConfiguration().protocolVersion >> 8 & 0xFF) - .arg(m_controller->networkConfiguration().protocolVersion & 0xFF); - qCDebug(dcZigbeeNetwork()) << "Controller API protocol version" << ZigbeeUtils::convertUint16ToHexString(m_controller->networkConfiguration().protocolVersion) << protocolVersion; - - m_controller->setFirmwareVersionString(QString("%1 - %2").arg(firmwareVersion).arg(protocolVersion)); - qCDebug(dcZigbeeNetwork()) << m_controller->networkConfiguration(); - qCDebug(dcZigbeeNetwork()) << "Reading current network state"; - ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); + + m_protocolVersion = QString("%1.%2").arg(m_controller->networkConfiguration().protocolVersion >> 8 & 0xFF) + .arg(m_controller->networkConfiguration().protocolVersion & 0xFF); + qCDebug(dcZigbeeNetwork()) << "Controller API protocol version" << ZigbeeUtils::convertUint16ToHexString(m_controller->networkConfiguration().protocolVersion) << m_protocolVersion; + + // Try read firmware version (changed with firmware 0x26680700) + qCDebug(dcZigbeeNetwork()) << "Request current firmware version..."; + ZigbeeInterfaceDeconzReply *reply = m_controller->requestVersion(); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + QString firmwareVersion; if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); - // FIXME: set an appropriate error - return; - } - - qCDebug(dcZigbeeNetwork()) << "Reading current network state finished successfully." << "SQN:" << reply->sequenceNumber(); - - QDataStream stream(reply->responseData()); - stream.setByteOrder(QDataStream::LittleEndian); - quint8 deviceStateFlag = 0; - stream >> deviceStateFlag; - DeconzDeviceState deviceState = m_controller->parseDeviceStateFlag(deviceStateFlag); - qCDebug(dcZigbeeNetwork()) << deviceState; - - // Update the device state in the controller - m_controller->processDeviceState(deviceState); - - if (m_createNewNetwork) { - // Set offline - // Write configurations - // Set online - // Read configurations - // Create and initialize coordinator node - // Done. Save network - setCreateNetworkState(CreateNetworkStateStopNetwork); + qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode(); } else { - // Get the network state and start the network if required - if (m_controller->networkState() == Deconz::NetworkStateConnected) { - qCDebug(dcZigbeeNetwork()) << "The network is already running."; - m_initializing = false; - setPermitJoiningEnabled(false); - // Set the permit joining timeout network configuration parameter - QByteArray parameterData; - QDataStream stream(¶meterData, QIODevice::WriteOnly); - stream.setByteOrder(QDataStream::LittleEndian); - stream << static_cast(0); + qCDebug(dcZigbeeNetwork()) << "Version request finished successfully" << ZigbeeUtils::convertByteArrayToHexString(reply->responseData()); + // Note: version is an uint32 value, little endian, but we can read the individual bytes in reversed order + quint8 majorVersion = static_cast(reply->responseData().at(3)); + quint8 minorVersion = static_cast(reply->responseData().at(2)); + Deconz::Platform platform = static_cast(reply->responseData().at(1)); + m_firmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion); + qCDebug(dcZigbeeNetwork()) << "Firmware version" << firmwareVersion << platform; - ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPermitJoin, parameterData); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ - if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode(); - // FIXME: set an appropriate error - return; - } - - qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode(); - setState(StateRunning); - }); - - } else if (m_controller->networkState() == Deconz::NetworkStateOffline) { - m_initializing = true; - qCDebug(dcZigbeeNetwork()) << "The network is offline. Lets start it"; - setCreateNetworkState(CreateNetworkStateStartNetwork); - } else { - // The network is not running yet, lets wait for the state changed - } } + + if (!m_firmwareVersion.isEmpty()) { + m_controller->setFirmwareVersionString(QString("%1 - %2").arg(m_firmwareVersion).arg(m_protocolVersion)); + } else { + m_controller->setFirmwareVersionString(m_protocolVersion); + } + + qCDebug(dcZigbeeNetwork()) << "Reading current network state"; + ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Reading current network state finished successfully." << "SQN:" << reply->sequenceNumber(); + + QDataStream stream(reply->responseData()); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 deviceStateFlag = 0; + stream >> deviceStateFlag; + DeconzDeviceState deviceState = m_controller->parseDeviceStateFlag(deviceStateFlag); + qCDebug(dcZigbeeNetwork()) << deviceState; + + // Update the device state in the controller + m_controller->processDeviceState(deviceState); + + if (m_createNewNetwork) { + // Set offline + // Write configurations + // Set online + // Read configurations + // Create and initialize coordinator node + // Done. Save network + setCreateNetworkState(CreateNetworkStateStopNetwork); + } else { + // Get the network state and start the network if required + if (m_controller->networkState() == Deconz::NetworkStateConnected) { + qCDebug(dcZigbeeNetwork()) << "The network is already running."; + m_initializing = false; + setPermitJoiningEnabled(false); + // Set the permit joining timeout network configuration parameter + QByteArray parameterData; + QDataStream stream(¶meterData, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(0); + + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPermitJoin, parameterData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode(); + setState(StateRunning); + }); + + } else if (m_controller->networkState() == Deconz::NetworkStateOffline) { + m_initializing = true; + qCDebug(dcZigbeeNetwork()) << "The network is offline. Lets start it"; + setCreateNetworkState(CreateNetworkStateStartNetwork); + } else { + // The network is not running yet, lets wait for the state changed + } + } + }); }); }); }); diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h index 55d5b85..6a5b271 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h @@ -65,6 +65,8 @@ private: CreateNetworkState m_createState = CreateNetworkStateIdle; bool m_createNewNetwork = false; bool m_initializing = false; + QString m_protocolVersion; + QString m_firmwareVersion; QHash m_pendingReplies;