diff --git a/libnymea-zigbee/backends/nxp/firmwareupdatehandlernxp.cpp b/libnymea-zigbee/backends/nxp/firmwareupdatehandlernxp.cpp
new file mode 100644
index 0000000..bf368ef
--- /dev/null
+++ b/libnymea-zigbee/backends/nxp/firmwareupdatehandlernxp.cpp
@@ -0,0 +1,188 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "firmwareupdatehandlernxp.h"
+#include "loggingcategory.h"
+
+#include
+#include
+#include
+#include
+
+/*
+ * [UpdateProvider]
+ * updateBinary=/usr/bin/maveo-zigbee-flasher
+ * updateReleaseFile=/usr/share/maveo-zigbee-flasher/firmware/release.json
+ */
+
+FirmwareUpdateHandlerNxp::FirmwareUpdateHandlerNxp(QObject *parent) :
+ QObject(parent)
+{
+
+}
+
+FirmwareUpdateHandlerNxp::FirmwareUpdateHandlerNxp(const QFileInfo &updateProviderConfgigurationFileInfo, QObject *parent) :
+ QObject(parent),
+ m_updateProviderConfgigurationFileInfo(updateProviderConfgigurationFileInfo)
+{
+ qCDebug(dcZigbeeController()) << "Initialize NXP firmware update provider";
+
+ QSettings configuration(updateProviderConfgigurationFileInfo.absoluteFilePath(), QSettings::IniFormat, this);
+ configuration.beginGroup("UpdateProvider");
+
+ // Verify the update provider binary
+ m_updateBinary = configuration.value("updateBinary").toString();
+ if (m_updateBinary.isEmpty()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the update binary is not specified in" << m_updateProviderConfgigurationFileInfo.absoluteFilePath();
+ return;
+ }
+
+ QFileInfo updateBinaryFileInfo(m_updateBinary);
+ if (!updateBinaryFileInfo.exists()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the update binary does not exist" << updateBinaryFileInfo.absoluteFilePath();
+ return;
+ }
+
+ if (!updateBinaryFileInfo.isExecutable()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the update binary is not executable" << updateBinaryFileInfo.absoluteFilePath();
+ return;
+ }
+
+ // Verify update release file and corresponding update file and version
+ m_updateReleaseFilePath = configuration.value("updateReleaseFile").toString();
+ QFileInfo releaseFileInfo(m_updateReleaseFilePath);
+ if (! releaseFileInfo.exists()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the release file does not exist" << releaseFileInfo.absoluteFilePath();
+ return;
+ }
+
+ // Read the release file
+ QFile releaseFile(releaseFileInfo.absoluteFilePath());
+ if (!releaseFile.open(QFile::ReadOnly)) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but could not open update release file" << releaseFileInfo.absoluteFilePath() << releaseFile.errorString();
+ return;
+ }
+
+ QByteArray releaseFileData = releaseFile.readAll();
+ releaseFile.close();
+
+ QJsonParseError jsonError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(releaseFileData, &jsonError);
+ if (jsonError.error != QJsonParseError::NoError) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but could not parse the release file" << releaseFileInfo.absoluteFilePath() << jsonError.errorString();
+ return;
+ }
+
+ QVariantMap releaseMap = jsonDoc.toVariant().toMap();
+ if (!releaseMap.contains("version")) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the release file does not contain available version information" << releaseFileInfo.absoluteFilePath();
+ return;
+ }
+
+ m_availableFirmwareVersion = releaseMap.value("version").toString();
+ if (m_availableFirmwareVersion.isEmpty()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the version in the release file is empty" << releaseFileInfo.absoluteFilePath();
+ return;
+ }
+
+ if (!releaseMap.contains("firmware")) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the release file does not contain available firmware file name" << releaseFileInfo.absoluteFilePath();
+ return;
+ }
+
+ m_availableFirmwareFileName = releaseMap.value("firmware").toString();
+ if (m_availableFirmwareFileName.isEmpty()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the firmware file path in the release file is empty" << releaseFileInfo.absoluteFilePath();
+ return;
+ }
+
+ QFileInfo firmwareFileInfo(releaseFileInfo.canonicalPath() + QDir::separator() + m_availableFirmwareFileName);
+ if (!firmwareFileInfo.exists()) {
+ qCWarning(dcZigbeeController()) << "Update provider configuration available but the update firmware file does not exist" << firmwareFileInfo.absoluteFilePath();
+ return;
+ }
+
+ qCDebug(dcZigbeeController()) << "Firmware update prvider available:" << firmwareFileInfo.absoluteFilePath() << "Version:" << m_availableFirmwareVersion;
+ configuration.endGroup();
+
+ m_updateProcess = new QProcess(this);
+ m_updateProcess->setProcessChannelMode(QProcess::MergedChannels);
+ m_updateProcess->setProgram(m_updateBinary);
+
+ connect(m_updateProcess, QOverload::of(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus) {
+ qCDebug(dcZigbeeController()) << "Update process finihed" << exitCode << exitStatus;
+ if (exitCode != 0) {
+ emit updateFinished(false);
+ } else {
+ emit updateFinished(true);
+ }
+ });
+
+ connect(m_updateProcess, &QProcess::readyRead, [=]() {
+ qCDebug(dcZigbeeController()) << "Update process:" << qUtf8Printable(m_updateProcess->readAll().replace(0x1B, '\r'));
+ });
+
+ m_valid = true;
+}
+
+bool FirmwareUpdateHandlerNxp::updateRunning() const
+{
+ return m_updateProcess->state() != QProcess::NotRunning;
+}
+
+bool FirmwareUpdateHandlerNxp::isValid() const
+{
+ return m_valid;
+}
+
+QString FirmwareUpdateHandlerNxp::updateBinary() const
+{
+ return m_updateBinary;
+}
+
+QString FirmwareUpdateHandlerNxp::availableFirmwareFileName() const
+{
+ return m_availableFirmwareFileName;
+}
+
+QString FirmwareUpdateHandlerNxp::availableFirmwareVersion() const
+{
+ return m_availableFirmwareVersion;
+}
+
+void FirmwareUpdateHandlerNxp::startUpdate()
+{
+ if (!m_updateProcess) {
+ qCWarning(dcZigbeeController()) << "Cannot start update process. The updater is not vaild.";
+ return;
+ }
+
+ qCDebug(dcZigbeeController()) << "Starting firmware update for NXP controller";
+ qCDebug(dcZigbeeController()) << "Firmware file:" << m_availableFirmwareFileName;
+ qCDebug(dcZigbeeController()) << "Firmware version:" << m_availableFirmwareVersion;
+ m_updateProcess->start();
+}
diff --git a/libnymea-zigbee/backends/nxp/firmwareupdatehandlernxp.h b/libnymea-zigbee/backends/nxp/firmwareupdatehandlernxp.h
new file mode 100644
index 0000000..b42e7f0
--- /dev/null
+++ b/libnymea-zigbee/backends/nxp/firmwareupdatehandlernxp.h
@@ -0,0 +1,67 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef FIRMWAREUPDATEHANDLERNXP_H
+#define FIRMWAREUPDATEHANDLERNXP_H
+
+#include
+#include
+#include
+
+class FirmwareUpdateHandlerNxp : public QObject
+{
+ Q_OBJECT
+public:
+ explicit FirmwareUpdateHandlerNxp(QObject *parent = nullptr);
+ FirmwareUpdateHandlerNxp(const QFileInfo &updateProviderConfgigurationFileInfo, QObject *parent = nullptr);
+
+ bool updateRunning() const;
+ bool isValid() const;
+
+ QString updateBinary() const;
+ QString availableFirmwareFileName() const;
+ QString availableFirmwareVersion() const;
+
+ void startUpdate();
+
+signals:
+ void updateRunningChanged(bool updateRunning);
+ void updateFinished(bool success);
+
+private:
+ QFileInfo m_updateProviderConfgigurationFileInfo;
+ bool m_valid = false;
+ QProcess *m_updateProcess = nullptr;
+
+ QString m_updateBinary;
+ QString m_updateReleaseFilePath;
+ QString m_availableFirmwareFileName;
+ QString m_availableFirmwareVersion;
+
+};
+
+#endif // FIRMWAREUPDATEHANDLERNXP_H
diff --git a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp
index 98eacae..f76232b 100644
--- a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp
+++ b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxp.cpp
@@ -298,6 +298,7 @@ void ZigbeeInterfaceNxp::disable()
delete m_serialPort;
m_serialPort = nullptr;
+
+ qCDebug(dcZigbeeInterface()) << "Interface disabled.";
setAvailable(false);
- qCDebug(dcZigbeeInterface()) << "Interface disabled";
}
diff --git a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.cpp b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.cpp
index a865511..043d77b 100644
--- a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.cpp
+++ b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.cpp
@@ -1,3 +1,30 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
#include "zigbeeinterfacenxpreply.h"
ZigbeeNetworkRequest ZigbeeInterfaceNxpReply::networkRequest() const
diff --git a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.h b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.h
index 42f829a..4864520 100644
--- a/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.h
+++ b/libnymea-zigbee/backends/nxp/interface/zigbeeinterfacenxpreply.h
@@ -1,3 +1,30 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
#ifndef ZIGBEEINTERFACENXPREPLY_H
#define ZIGBEEINTERFACENXPREPLY_H
diff --git a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp
index af031e5..92861c6 100644
--- a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp
+++ b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp
@@ -1,4 +1,31 @@
-#include "zigbeebridgecontrollernxp.h"
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "zigbeebridgecontrollernxp.h"
#include "loggingcategory.h"
#include "zigbeeutils.h"
@@ -205,6 +232,40 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestSendRequest(const Zig
return interfaceReply;
}
+bool ZigbeeBridgeControllerNxp::updateAvailable(const QString ¤tVersion)
+{
+ if (!m_firmwareUpdateHandler)
+ return false;
+
+ if (m_firmwareUpdateHandler->availableFirmwareVersion() != currentVersion) {
+ return true;
+ }
+
+ return false;
+}
+
+QString ZigbeeBridgeControllerNxp::updateFirmwareVersion() const
+{
+ if (!m_firmwareUpdateHandler)
+ return QString();
+
+ return m_firmwareUpdateHandler->availableFirmwareVersion();
+}
+
+void ZigbeeBridgeControllerNxp::startFirmwareUpdate()
+{
+ if (!m_firmwareUpdateHandler)
+ return;
+
+ m_updateRunning = true;
+ emit updateRunningChanged(m_updateRunning);
+
+ qCDebug(dcZigbeeController()) << "Disable UART interface for update...";
+ m_interface->disable();
+
+ m_firmwareUpdateHandler->startUpdate();
+}
+
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent)
{
// Create the reply
@@ -346,6 +407,44 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestEnqueueSendDataIeeeAd
return createReply(Nxp::CommandSendApsDataRequest, m_sequenceNumber, "Request send ASP data request to IEEE address", message, this);
}
+void ZigbeeBridgeControllerNxp::initializeUpdateProvider()
+{
+ QFileInfo updateProviderConfigurationFileInfo = QFileInfo(m_settingsDirectory.canonicalPath() + QDir::separator() + "zigbee-update-provider-nxp.conf");
+ if (!updateProviderConfigurationFileInfo.exists()) {
+ qCDebug(dcZigbeeController()) << "No firmware update provider configured for this controller.";
+ return;
+ }
+
+ qCDebug(dcZigbeeController()) << "Found update provider configuration" << updateProviderConfigurationFileInfo.absoluteFilePath();
+ m_firmwareUpdateHandler = new FirmwareUpdateHandlerNxp(updateProviderConfigurationFileInfo, this);
+ if (!m_firmwareUpdateHandler->isValid()) {
+ qCWarning(dcZigbeeController()) << "The firmware update provider is not valid. The firmware update is not available for this NXP zigbee controller.";
+ m_firmwareUpdateHandler->deleteLater();
+ m_firmwareUpdateHandler = nullptr;
+ return;
+ }
+
+ connect(m_firmwareUpdateHandler, &FirmwareUpdateHandlerNxp::updateFinished, this, [this](bool success){
+ if (success) {
+ qCDebug(dcZigbeeController()) << "Update finished successfully. Reenable controller";
+ enable(m_serialPort, m_baudrate);
+ m_updateRunning = false;
+ emit updateRunningChanged(m_updateRunning);
+ } else {
+ qCWarning(dcZigbeeController()) << "Update finished with errors. Can not continue.";
+ m_updateRunning = false;
+ emit updateRunningChanged(m_updateRunning);
+
+ // Fixme: check if we should to retry
+ disable();
+ }
+ });
+
+ qCDebug(dcZigbeeController()) << "The firmware update provider is valid. The firmware of this NXP controller can be updated.";
+ m_canUpdate = true;
+ emit canUpdateChanged(m_canUpdate);
+}
+
void ZigbeeBridgeControllerNxp::onInterfaceAvailableChanged(bool available)
{
qCDebug(dcZigbeeController()) << "Interface available changed" << available;
@@ -501,6 +600,8 @@ void ZigbeeBridgeControllerNxp::sendNextRequest()
bool ZigbeeBridgeControllerNxp::enable(const QString &serialPort, qint32 baudrate)
{
+ m_serialPort = serialPort;
+ m_baudrate = baudrate;
return m_interface->enable(serialPort, baudrate);
}
diff --git a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h
index e1cd2ed..e39f42f 100644
--- a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h
+++ b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h
@@ -1,3 +1,30 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
#ifndef ZIGBEEBRIDGECONTROLLERNXP_H
#define ZIGBEEBRIDGECONTROLLERNXP_H
@@ -11,6 +38,7 @@
#include "zigbeenetworkkey.h"
#include "zigbeenetworkrequest.h"
#include "zigbeebridgecontroller.h"
+#include "firmwareupdatehandlernxp.h"
#include "interface/zigbeeinterfacenxp.h"
#include "interface/zigbeeinterfacenxpreply.h"
@@ -55,6 +83,9 @@ public:
// APS
ZigbeeInterfaceNxpReply *requestSendRequest(const ZigbeeNetworkRequest &request);
+ bool updateAvailable(const QString ¤tVersion) override;
+ QString updateFirmwareVersion() const override;
+ void startFirmwareUpdate() override;
signals:
void controllerStateChanged(ControllerState controllerState);
@@ -62,6 +93,10 @@ signals:
private:
ZigbeeInterfaceNxp *m_interface = nullptr;
+ FirmwareUpdateHandlerNxp *m_firmwareUpdateHandler = nullptr;
+ QString m_serialPort;
+ qint32 m_baudrate;
+
ControllerState m_controllerState = ControllerStateNotRunning;
quint8 m_sequenceNumber = 0;
@@ -75,6 +110,8 @@ private:
ZigbeeInterfaceNxpReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
ZigbeeInterfaceNxpReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0);
+protected:
+ void initializeUpdateProvider() override;
private slots:
void onInterfaceAvailableChanged(bool available);
diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp
index 3c0e002..35fcb55 100644
--- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp
+++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp
@@ -1,3 +1,30 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
#include "zigbeenetworknxp.h"
#include "loggingcategory.h"
#include "zigbeeutils.h"
@@ -13,6 +40,20 @@ ZigbeeNetworkNxp::ZigbeeNetworkNxp(QObject *parent) :
connect(m_controller, &ZigbeeBridgeControllerNxp::controllerStateChanged, this, &ZigbeeNetworkNxp::onControllerStateChanged);
connect(m_controller, &ZigbeeBridgeControllerNxp::apsDataConfirmReceived, this, &ZigbeeNetworkNxp::onApsDataConfirmReceived);
connect(m_controller, &ZigbeeBridgeControllerNxp::apsDataIndicationReceived, this, &ZigbeeNetworkNxp::onApsDataIndicationReceived);
+ connect(m_controller, &ZigbeeBridgeControllerNxp::canUpdateChanged, this, [](bool canUpdate){
+ if (canUpdate) {
+ qCDebug(dcZigbeeNetwork()) << "The controller of this network can be updated.";
+ } else {
+ qCDebug(dcZigbeeNetwork()) << "The controller of this network can not be updated.";
+ }
+ });
+
+ connect(m_controller, &ZigbeeBridgeControllerNxp::updateRunningChanged, this, [this](bool updateRunning){
+ if (updateRunning) {
+ qCDebug(dcZigbeeNetwork()) << "The controller is performing an update.";
+ setState(StateUpdating);
+ }
+ });
m_permitJoinRefreshTimer = new QTimer(this);
m_permitJoinRefreshTimer->setInterval(250 * 1000);
@@ -97,6 +138,64 @@ ZigbeeNetworkReply *ZigbeeNetworkNxp::setPermitJoin(quint16 shortAddress, quint8
return sendRequest(request);
}
+bool ZigbeeNetworkNxp::processVersionReply(ZigbeeInterfaceNxpReply *reply)
+{
+ qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status();
+
+ if (reply->timendOut()) {
+ m_reconnectCounter++;
+ if (m_reconnectCounter >= 3) {
+ if (m_controller->canUpdate()) {
+ qCDebug(dcZigbeeNetwork()) << "Unable to get controller version.";
+ qCDebug(dcZigbeeNetwork()) << "Firmware update provider available. Try to flash the firmware, maybe that fixes the problem.";
+ if (!m_controller->updateRunning()) {
+ clearSettings();
+ qCDebug(dcZigbeeNetwork()) << "Starting firmware update...";
+ m_controller->startFirmwareUpdate();
+ } else {
+ qCWarning(dcZigbeeNetwork()) << "There is already an update running...";
+ }
+ return false;
+ } else {
+ qCDebug(dcZigbeeNetwork()) << "Unable to get controller version. There is no firmware upgrade available. Giving up.";
+ return false;
+ }
+ }
+
+ qCWarning(dcZigbeeNetwork()) << "Failed to read firmware version. Retry" << m_reconnectCounter << "/ 3";
+ ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
+ connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
+ processVersionReply(reply);
+ });
+
+ return false;
+ }
+
+ QByteArray payload = reply->responseData();
+ QDataStream stream(&payload, QIODevice::ReadOnly);
+ stream.setByteOrder(QDataStream::LittleEndian);
+ quint8 major = 0; quint8 minor = 0; quint8 patch = 0; quint16 sdkVersion = 0;
+ stream >> major >> minor >> patch >> sdkVersion;
+
+ QString version = QString("%1.%2.%3").arg(major).arg(minor).arg(patch);
+ QString versionString = QString("%1 - %2").arg(version).arg(sdkVersion);
+ qCDebug(dcZigbeeNetwork()) << "Controller version" << versionString;
+ m_controller->setFirmwareVersion(versionString);
+
+ if (m_controller->canUpdate()) {
+ if (m_controller->updateAvailable(version)) {
+ qCDebug(dcZigbeeNetwork()) << "There is an update available for the this zigbee controller:" << version << "-->" << m_controller->updateFirmwareVersion();
+ qCDebug(dcZigbeeNetwork()) << "Starting firmware update...";
+ m_controller->startFirmwareUpdate();
+ return false;
+ } else {
+ qCDebug(dcZigbeeNetwork()) << "The current firmware is up to date.";
+ }
+ }
+
+ return true;
+}
+
void ZigbeeNetworkNxp::handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication)
{
// Check if this is a device announcement
@@ -150,12 +249,15 @@ void ZigbeeNetworkNxp::onControllerAvailableChanged(bool available)
{
qCDebug(dcZigbeeNetwork()) << "Controller is" << (available ? "now available" : "not available any more");
if (available) {
+ m_reconnectCounter = 0;
+ ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
+ connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
+ // Retry or firmware upgrade if available
+ if (!processVersionReply(reply))
+ return;
- m_controller->refreshControllerState();
- // Get network state, depending on the controller state
-
- //reset();
- //factoryResetNetwork();
+ m_controller->refreshControllerState();
+ });
} else {
setState(StateOffline);
}
@@ -167,19 +269,14 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
switch (controllerState) {
case ZigbeeBridgeControllerNxp::ControllerStateRunning: {
setState(StateStarting);
+ m_reconnectCounter = 0;
+
qCDebug(dcZigbeeNetwork()) << "Request controller version";
ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
- qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status();
- QByteArray payload = reply->responseData();
- QDataStream stream(&payload, QIODevice::ReadOnly);
- stream.setByteOrder(QDataStream::LittleEndian);
- quint8 major = 0; quint8 minor = 0; quint8 patch = 0; quint16 sdkVersion = 0;
- stream >> major >> minor >> patch >> sdkVersion;
-
- QString versionString = QString ("%1.%2.%3 - %4").arg(major).arg(minor).arg(patch).arg(sdkVersion);
- qCDebug(dcZigbeeNetwork()) << "Controller version" << versionString;
- m_controller->setFirmwareVersion(versionString);
+ // Retry or firmware upgrade if available
+ if (!processVersionReply(reply))
+ return;
qCDebug(dcZigbeeNetwork()) << "Get the current network state";
ZigbeeInterfaceNxpReply *reply = m_controller->requestNetworkState();
@@ -201,7 +298,6 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
setPanId(panId);
setChannel(channel);
-
// Initialize the coordinator node if not already done.
if (m_coordinatorNode) {
@@ -242,8 +338,9 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
qCDebug(dcZigbeeNetwork()) << "Request controller version";
ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
- qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status();
- //FIXME: error handling
+ // Retry or firmware upgrade if available
+ if (!processVersionReply(reply))
+ return;
QByteArray payload = reply->responseData();
QDataStream stream(&payload, QIODevice::ReadOnly);
diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h
index b46e55b..205eb0d 100644
--- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h
+++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h
@@ -1,3 +1,30 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea-zigbee.
+* This project including source code and documentation is protected by copyright law, and
+* remains the property of nymea GmbH. All rights, including reproduction, publication,
+* editing and translation, are reserved. The use of this project is subject to the terms of a
+* license agreement to be concluded with nymea GmbH in accordance with the terms
+* of use of nymea GmbH, available under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
+* Lesser General Public License as published by the Free Software Foundation; version 3.
+* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along with this project.
+* If not, see .
+*
+* For any further details and any questions please contact us under contact@nymea.io
+* or see our FAQ/Licensing Information on https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
#ifndef ZIGBEENETWORKNXP_H
#define ZIGBEENETWORKNXP_H
@@ -25,9 +52,12 @@ private:
ZigbeeBridgeControllerNxp *m_controller = nullptr;
bool m_networkRunning = false;
QHash m_pendingReplies;
+ int m_reconnectCounter = 0;
QTimer *m_permitJoinRefreshTimer = nullptr;
+ bool processVersionReply(ZigbeeInterfaceNxpReply *reply);
+
// ZDO
void handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication);
diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro
index 403df96..602d43d 100644
--- a/libnymea-zigbee/libnymea-zigbee.pro
+++ b/libnymea-zigbee/libnymea-zigbee.pro
@@ -8,6 +8,7 @@ SOURCES += \
backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \
backends/deconz/zigbeebridgecontrollerdeconz.cpp \
backends/deconz/zigbeenetworkdeconz.cpp \
+ backends/nxp/firmwareupdatehandlernxp.cpp \
backends/nxp/interface/zigbeeinterfacenxp.cpp \
backends/nxp/interface/zigbeeinterfacenxpreply.cpp \
backends/nxp/zigbeebridgecontrollernxp.cpp \
@@ -63,6 +64,7 @@ HEADERS += \
backends/deconz/interface/zigbeeinterfacedeconzreply.h \
backends/deconz/zigbeebridgecontrollerdeconz.h \
backends/deconz/zigbeenetworkdeconz.h \
+ backends/nxp/firmwareupdatehandlernxp.h \
backends/nxp/interface/nxp.h \
backends/nxp/interface/zigbeeinterfacenxp.h \
backends/nxp/interface/zigbeeinterfacenxpreply.h \
diff --git a/libnymea-zigbee/zigbeebridgecontroller.cpp b/libnymea-zigbee/zigbeebridgecontroller.cpp
index 004ad82..271e8ee 100644
--- a/libnymea-zigbee/zigbeebridgecontroller.cpp
+++ b/libnymea-zigbee/zigbeebridgecontroller.cpp
@@ -43,6 +43,43 @@ bool ZigbeeBridgeController::available() const
return m_available;
}
+bool ZigbeeBridgeController::canUpdate() const
+{
+ return m_canUpdate;
+}
+
+bool ZigbeeBridgeController::updateRunning() const
+{
+ return m_updateRunning;
+}
+
+bool ZigbeeBridgeController::updateAvailable(const QString ¤tVersion)
+{
+ Q_UNUSED(currentVersion)
+ return false;
+}
+
+QString ZigbeeBridgeController::updateFirmwareVersion() const
+{
+ return QString();
+}
+
+void ZigbeeBridgeController::startFirmwareUpdate()
+{
+ qCWarning(dcZigbeeController()) << "Cannot start firmware update. The feature is not implemented for this controller.";
+}
+
+void ZigbeeBridgeController::setSettingsDirectory(const QDir &settingsDirectory)
+{
+ qCDebug(dcZigbeeController()) << "Using settings directory" << settingsDirectory.canonicalPath();
+ m_settingsDirectory = settingsDirectory;
+
+ // Check if we have an update provider for the controller, if so,
+ // we can perform an automatic updates
+
+ initializeUpdateProvider();
+}
+
void ZigbeeBridgeController::setAvailable(bool available)
{
if (m_available == available)
@@ -62,3 +99,8 @@ void ZigbeeBridgeController::setFirmwareVersion(const QString &firmwareVersion)
m_firmwareVersion = firmwareVersion;
emit firmwareVersionChanged(m_firmwareVersion);
}
+
+void ZigbeeBridgeController::initializeUpdateProvider()
+{
+ qCDebug(dcZigbeeController()) << "No firmware update provider configured for this controller.";
+}
diff --git a/libnymea-zigbee/zigbeebridgecontroller.h b/libnymea-zigbee/zigbeebridgecontroller.h
index ac54e34..102c700 100644
--- a/libnymea-zigbee/zigbeebridgecontroller.h
+++ b/libnymea-zigbee/zigbeebridgecontroller.h
@@ -28,8 +28,10 @@
#ifndef ZIGBEEBRIDGECONTROLLER_H
#define ZIGBEEBRIDGECONTROLLER_H
+#include
#include
#include
+
#include "zigbee.h"
Q_DECLARE_METATYPE(QSerialPort::SerialPortError);
@@ -37,6 +39,8 @@ Q_DECLARE_METATYPE(QSerialPort::SerialPortError);
class ZigbeeBridgeController : public QObject
{
Q_OBJECT
+ friend class ZigbeeNetwork;
+
public:
explicit ZigbeeBridgeController(QObject *parent = nullptr);
~ZigbeeBridgeController() = default;
@@ -44,17 +48,35 @@ public:
QString firmwareVersion() const;
bool available() const;
+ bool canUpdate() const;
+ bool updateRunning() const;
+
+ virtual bool updateAvailable(const QString ¤tVersion);
+ virtual QString updateFirmwareVersion() const;
+ virtual void startFirmwareUpdate();
+
protected:
QString m_firmwareVersion;
bool m_available = false;
+ bool m_canUpdate = false;
+ bool m_updateRunning = false;
+ QDir m_settingsDirectory;
void setAvailable(bool available);
void setFirmwareVersion(const QString &firmwareVersion);
+ virtual void initializeUpdateProvider();
+
+private:
+ void setSettingsDirectory(const QDir &settingsDirectory);
+
signals:
void availableChanged(bool available);
void firmwareVersionChanged(const QString &firmwareVersion);
+ void canUpdateChanged(bool canUpdate);
+ void updateRunningChanged(bool updateRunning);
+ // APS notifications
void apsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm);
void apsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication);
diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp
index 1d98193..b157c94 100644
--- a/libnymea-zigbee/zigbeenetwork.cpp
+++ b/libnymea-zigbee/zigbeenetwork.cpp
@@ -56,11 +56,11 @@ QString ZigbeeNetwork::settingsFilenName() const
void ZigbeeNetwork::setSettingsFileName(const QString &settingsFileName)
{
- if (m_settingsFileName == settingsFileName)
- return;
-
m_settingsFileName = settingsFileName;
emit settingsFileNameChanged(m_settingsFileName);
+
+ m_settingsDirectory = QFileInfo(m_settingsFileName).canonicalPath();
+ bridgeController()->setSettingsDirectory(m_settingsDirectory);
}
QString ZigbeeNetwork::serialPortName() const
diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h
index 6cfb801..6ff911f 100644
--- a/libnymea-zigbee/zigbeenetwork.h
+++ b/libnymea-zigbee/zigbeenetwork.h
@@ -28,6 +28,7 @@
#ifndef ZIGBEENETWORK_H
#define ZIGBEENETWORK_H
+#include
#include
#include
@@ -49,6 +50,7 @@ public:
StateUninitialized,
StateOffline,
StateStarting,
+ StateUpdating,
StateRunning,
StateStopping
};
@@ -134,6 +136,7 @@ private:
// Network storage
QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf";
+ QDir m_settingsDirectory;
QList m_nodes;
QList m_uninitializedNodes;