Implement initially flashed property and reqork update provider
parent
09fdd20dbd
commit
7918d4de2d
|
|
@ -34,10 +34,16 @@
|
|||
#include <QJsonParseError>
|
||||
|
||||
/*
|
||||
* [UpdateProvider]
|
||||
* updateBinary=/usr/bin/maveo-zigbee-flasher
|
||||
* updateReleaseFile=/usr/share/maveo-zigbee-flasher/firmware/release.json
|
||||
*/
|
||||
|
||||
Example update provider configuration, if initiallyFlashed is false, a factory reset will be performed in any case
|
||||
|
||||
[UpdateProvider]
|
||||
updateCommand=/usr/bin/maveo-zigbee-flasher -s /dev/ttymxc2 -p 131 -r 132
|
||||
updateReleaseFile=/usr/share/maveo-zigbee-flasher/firmware/release.json
|
||||
factoryResetCommand=/usr/bin/maveo-zigbee-flasher -s /dev/ttymxc2 -p 131 -r 132 -e
|
||||
initiallyFlashed=false
|
||||
|
||||
*/
|
||||
|
||||
FirmwareUpdateHandlerNxp::FirmwareUpdateHandlerNxp(QObject *parent) :
|
||||
QObject(parent)
|
||||
|
|
@ -49,26 +55,68 @@ FirmwareUpdateHandlerNxp::FirmwareUpdateHandlerNxp(const QFileInfo &updateProvid
|
|||
QObject(parent),
|
||||
m_updateProviderConfgigurationFileInfo(updateProviderConfgigurationFileInfo)
|
||||
{
|
||||
qCDebug(dcZigbeeController()) << "Initialize NXP firmware update provider";
|
||||
qCDebug(dcZigbeeController()) << "Initialize NXP firmware update provider from" << updateProviderConfgigurationFileInfo.absoluteFilePath();
|
||||
|
||||
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();
|
||||
// Verify the update command
|
||||
QString updateCommand = configuration.value("updateCommand").toString();
|
||||
if (updateCommand.isEmpty()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the update command 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();
|
||||
QStringList updateCommandTokens = updateCommand.split(" ");
|
||||
qCDebug(dcZigbeeController()) << "Update command tokens" << updateCommandTokens;
|
||||
if (updateCommandTokens.count() == 0) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the update command could not be parsed correctly" << m_updateProviderConfgigurationFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!updateBinaryFileInfo.isExecutable()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the update binary is not executable" << updateBinaryFileInfo.absoluteFilePath();
|
||||
m_updateProgram = updateCommandTokens.takeFirst();
|
||||
m_updateProgramParameters << updateCommandTokens;
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Update program:" << m_updateProgram << "Parameters:" << m_updateProgramParameters;
|
||||
|
||||
QFileInfo updateProgramFileInfo(m_updateProgram);
|
||||
if (!updateProgramFileInfo.exists()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the update binary does not exist" << updateProgramFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!updateProgramFileInfo.isExecutable()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the update binary is not executable" << updateProgramFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify the factory reset command
|
||||
QString factoryResetCommand = configuration.value("factoryResetCommand").toString();
|
||||
if (factoryResetCommand.isEmpty()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the factory reset command is not specified in" << m_updateProviderConfgigurationFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList factoryResetCommandTokens = factoryResetCommand.split(" ");
|
||||
qCDebug(dcZigbeeController()) << "Factory reset command tokens" << factoryResetCommandTokens;
|
||||
if (factoryResetCommandTokens.count() == 0) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the factory reset command could not be parsed correctly" << m_updateProviderConfgigurationFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
m_factoryResetProgram = factoryResetCommandTokens.takeFirst();
|
||||
m_factoryResetParameters << factoryResetCommandTokens;
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Factory reset program:" << m_factoryResetProgram << "Parameters:" << m_factoryResetParameters;
|
||||
|
||||
QFileInfo factoryResetProgramFileInfo(m_factoryResetProgram);
|
||||
if (!factoryResetProgramFileInfo.exists()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the factory reset binary does not exist" << factoryResetProgramFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!factoryResetProgramFileInfo.isExecutable()) {
|
||||
qCWarning(dcZigbeeController()) << "Update provider configuration available but the factory reset binary is not executable" << updateProgramFileInfo.absoluteFilePath();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -126,12 +174,18 @@ FirmwareUpdateHandlerNxp::FirmwareUpdateHandlerNxp(const QFileInfo &updateProvid
|
|||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Firmware update prvider available:" << firmwareFileInfo.absoluteFilePath() << "Version:" << m_availableFirmwareVersion;
|
||||
// Check if the controller has been initially flashed
|
||||
m_initiallyFlashed = configuration.value("initiallyFlashed", false).toBool();
|
||||
|
||||
configuration.endGroup();
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Firmware update provider available:" << firmwareFileInfo.fileName() << "Version:" << m_availableFirmwareVersion << "Initially flashed:" << m_initiallyFlashed;
|
||||
|
||||
// Set up update process
|
||||
m_updateProcess = new QProcess(this);
|
||||
m_updateProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_updateProcess->setProgram(m_updateBinary);
|
||||
m_updateProcess->setProgram(m_updateProgram);
|
||||
m_updateProcess->setArguments(m_updateProgramParameters);
|
||||
|
||||
connect(m_updateProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qCDebug(dcZigbeeController()) << "Update process finihed" << exitCode << exitStatus;
|
||||
|
|
@ -143,12 +197,45 @@ FirmwareUpdateHandlerNxp::FirmwareUpdateHandlerNxp(const QFileInfo &updateProvid
|
|||
});
|
||||
|
||||
connect(m_updateProcess, &QProcess::readyRead, [=]() {
|
||||
qCDebug(dcZigbeeController()) << "Update process:" << qUtf8Printable(m_updateProcess->readAll().replace(0x1B, '\r'));
|
||||
qCDebug(dcZigbeeController()) << "Update process:" << qUtf8Printable(m_updateProcess->readAll());
|
||||
});
|
||||
|
||||
|
||||
// Set up factory reset process
|
||||
m_factoryResetProcess = new QProcess(this);
|
||||
m_factoryResetProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_factoryResetProcess->setProgram(m_factoryResetProgram);
|
||||
m_factoryResetProcess->setArguments(m_factoryResetParameters);
|
||||
|
||||
connect(m_factoryResetProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qCDebug(dcZigbeeController()) << "Factory reset process finihed" << exitCode << exitStatus;
|
||||
if (exitCode != 0) {
|
||||
emit updateFinished(false);
|
||||
} else {
|
||||
// The factory reset has been finished successfully
|
||||
QSettings configuration(m_updateProviderConfgigurationFileInfo.absoluteFilePath(), QSettings::IniFormat, this);
|
||||
configuration.beginGroup("UpdateProvider");
|
||||
configuration.setValue("initiallyFlashed", true);
|
||||
configuration.endGroup();
|
||||
m_initiallyFlashed = true;
|
||||
emit initiallyFlashedChanged(m_initiallyFlashed);
|
||||
|
||||
emit updateFinished(true);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_factoryResetProcess, &QProcess::readyRead, [=]() {
|
||||
qCDebug(dcZigbeeController()) << "Factory reset process:" << qUtf8Printable(m_factoryResetProcess->readAll());
|
||||
});
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
bool FirmwareUpdateHandlerNxp::initiallyFlashed() const
|
||||
{
|
||||
return m_initiallyFlashed;
|
||||
}
|
||||
|
||||
bool FirmwareUpdateHandlerNxp::updateRunning() const
|
||||
{
|
||||
return m_updateProcess->state() != QProcess::NotRunning;
|
||||
|
|
@ -159,11 +246,6 @@ bool FirmwareUpdateHandlerNxp::isValid() const
|
|||
return m_valid;
|
||||
}
|
||||
|
||||
QString FirmwareUpdateHandlerNxp::updateBinary() const
|
||||
{
|
||||
return m_updateBinary;
|
||||
}
|
||||
|
||||
QString FirmwareUpdateHandlerNxp::availableFirmwareFileName() const
|
||||
{
|
||||
return m_availableFirmwareFileName;
|
||||
|
|
@ -186,3 +268,16 @@ void FirmwareUpdateHandlerNxp::startUpdate()
|
|||
qCDebug(dcZigbeeController()) << "Firmware version:" << m_availableFirmwareVersion;
|
||||
m_updateProcess->start();
|
||||
}
|
||||
|
||||
void FirmwareUpdateHandlerNxp::startFactoryReset()
|
||||
{
|
||||
if (!m_factoryResetProcess) {
|
||||
qCWarning(dcZigbeeController()) << "Cannot start factory reset process. The update provider is not vaild.";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Starting factory reset for NXP controller";
|
||||
qCDebug(dcZigbeeController()) << "Firmware file:" << m_availableFirmwareFileName;
|
||||
qCDebug(dcZigbeeController()) << "Firmware version:" << m_availableFirmwareVersion;
|
||||
m_factoryResetProcess->start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,25 +39,36 @@ public:
|
|||
explicit FirmwareUpdateHandlerNxp(QObject *parent = nullptr);
|
||||
FirmwareUpdateHandlerNxp(const QFileInfo &updateProviderConfgigurationFileInfo, QObject *parent = nullptr);
|
||||
|
||||
bool initiallyFlashed() const;
|
||||
bool updateRunning() const;
|
||||
bool isValid() const;
|
||||
|
||||
QString updateBinary() const;
|
||||
QString availableFirmwareFileName() const;
|
||||
QString availableFirmwareVersion() const;
|
||||
|
||||
void startUpdate();
|
||||
void startFactoryReset();
|
||||
|
||||
signals:
|
||||
void updateRunningChanged(bool updateRunning);
|
||||
void updateFinished(bool success);
|
||||
void initiallyFlashedChanged(bool initiallyFlashed);
|
||||
|
||||
private:
|
||||
QFileInfo m_updateProviderConfgigurationFileInfo;
|
||||
bool m_valid = false;
|
||||
QProcess *m_updateProcess = nullptr;
|
||||
|
||||
QString m_updateBinary;
|
||||
bool m_initiallyFlashed = false;
|
||||
bool m_valid = false;
|
||||
|
||||
QProcess *m_updateProcess = nullptr;
|
||||
QProcess *m_factoryResetProcess = nullptr;
|
||||
|
||||
QString m_updateProgram;
|
||||
QStringList m_updateProgramParameters;
|
||||
|
||||
QString m_factoryResetProgram;
|
||||
QStringList m_factoryResetParameters;
|
||||
|
||||
QString m_updateReleaseFilePath;
|
||||
QString m_availableFirmwareFileName;
|
||||
QString m_availableFirmwareVersion;
|
||||
|
|
|
|||
|
|
@ -266,6 +266,20 @@ void ZigbeeBridgeControllerNxp::startFirmwareUpdate()
|
|||
m_firmwareUpdateHandler->startUpdate();
|
||||
}
|
||||
|
||||
void ZigbeeBridgeControllerNxp::startFactoryResetUpdate()
|
||||
{
|
||||
if (!m_firmwareUpdateHandler)
|
||||
return;
|
||||
|
||||
m_updateRunning = true;
|
||||
emit updateRunningChanged(m_updateRunning);
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Disable UART interface for factory reset update...";
|
||||
m_interface->disable();
|
||||
|
||||
m_firmwareUpdateHandler->startFactoryReset();
|
||||
}
|
||||
|
||||
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent)
|
||||
{
|
||||
// Create the reply
|
||||
|
|
@ -440,9 +454,16 @@ void ZigbeeBridgeControllerNxp::initializeUpdateProvider()
|
|||
}
|
||||
});
|
||||
|
||||
connect(m_firmwareUpdateHandler, &FirmwareUpdateHandlerNxp::initiallyFlashedChanged, this, [this](bool initiallyFlashed){
|
||||
qCDebug(dcZigbeeController()) << "Firmware initially flashed changed to" << initiallyFlashed;
|
||||
m_initiallyFlashed = initiallyFlashed;
|
||||
});
|
||||
|
||||
qCDebug(dcZigbeeController()) << "The firmware update provider is valid. The firmware of this NXP controller can be updated.";
|
||||
m_canUpdate = true;
|
||||
emit canUpdateChanged(m_canUpdate);
|
||||
|
||||
m_initiallyFlashed = m_firmwareUpdateHandler->initiallyFlashed();
|
||||
}
|
||||
|
||||
void ZigbeeBridgeControllerNxp::onInterfaceAvailableChanged(bool available)
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ public:
|
|||
bool updateAvailable(const QString ¤tVersion) override;
|
||||
QString updateFirmwareVersion() const override;
|
||||
void startFirmwareUpdate() override;
|
||||
void startFactoryResetUpdate() override;
|
||||
|
||||
signals:
|
||||
void controllerStateChanged(ControllerState controllerState);
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ bool ZigbeeNetworkNxp::processVersionReply(ZigbeeInterfaceNxpReply *reply)
|
|||
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.";
|
||||
// FIXME: try 3 times, then give up or perform a factory flash
|
||||
if (!m_controller->updateRunning()) {
|
||||
clearSettings();
|
||||
qCDebug(dcZigbeeNetwork()) << "Starting firmware update...";
|
||||
|
|
@ -249,6 +250,12 @@ void ZigbeeNetworkNxp::onControllerAvailableChanged(bool available)
|
|||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Controller is" << (available ? "now available" : "not available any more");
|
||||
if (available) {
|
||||
if (m_controller->canUpdate() && !m_controller->initiallyFlashed()) {
|
||||
qCDebug(dcZigbeeNetwork()) << "The firmware of the controller can be updated and has not been initially flashed. Perform a factory reset flash procedure...";
|
||||
m_controller->startFactoryResetUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
m_reconnectCounter = 0;
|
||||
ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
|
||||
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ bool ZigbeeBridgeController::canUpdate() const
|
|||
return m_canUpdate;
|
||||
}
|
||||
|
||||
bool ZigbeeBridgeController::initiallyFlashed() const
|
||||
{
|
||||
return m_initiallyFlashed;
|
||||
}
|
||||
|
||||
bool ZigbeeBridgeController::updateRunning() const
|
||||
{
|
||||
return m_updateRunning;
|
||||
|
|
@ -69,9 +74,14 @@ void ZigbeeBridgeController::startFirmwareUpdate()
|
|||
qCWarning(dcZigbeeController()) << "Cannot start firmware update. The feature is not implemented for this controller.";
|
||||
}
|
||||
|
||||
void ZigbeeBridgeController::startFactoryResetUpdate()
|
||||
{
|
||||
qCWarning(dcZigbeeController()) << "Cannot start firmware factory reset update. The feature is not implemented for this controller.";
|
||||
}
|
||||
|
||||
void ZigbeeBridgeController::setSettingsDirectory(const QDir &settingsDirectory)
|
||||
{
|
||||
qCDebug(dcZigbeeController()) << "Using settings directory" << settingsDirectory.canonicalPath();
|
||||
qCDebug(dcZigbeeController()) << "Using settings directory" << settingsDirectory.absolutePath();
|
||||
m_settingsDirectory = settingsDirectory;
|
||||
|
||||
// Check if we have an update provider for the controller, if so,
|
||||
|
|
|
|||
|
|
@ -49,16 +49,20 @@ public:
|
|||
bool available() const;
|
||||
|
||||
bool canUpdate() const;
|
||||
bool initiallyFlashed() const;
|
||||
bool updateRunning() const;
|
||||
|
||||
// Optional update/initialize procedure for the zigbee controller
|
||||
virtual bool updateAvailable(const QString ¤tVersion);
|
||||
virtual QString updateFirmwareVersion() const;
|
||||
virtual void startFirmwareUpdate();
|
||||
virtual void startFactoryResetUpdate();
|
||||
|
||||
protected:
|
||||
QString m_firmwareVersion;
|
||||
bool m_available = false;
|
||||
bool m_canUpdate = false;
|
||||
bool m_initiallyFlashed = false;
|
||||
bool m_updateRunning = false;
|
||||
QDir m_settingsDirectory = QDir("/etc/nymea/");
|
||||
|
||||
|
|
|
|||
|
|
@ -56,10 +56,11 @@ QString ZigbeeNetwork::settingsFilenName() const
|
|||
|
||||
void ZigbeeNetwork::setSettingsFileName(const QString &settingsFileName)
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Using settings file" << settingsFileName;
|
||||
m_settingsFileName = settingsFileName;
|
||||
emit settingsFileNameChanged(m_settingsFileName);
|
||||
|
||||
m_settingsDirectory = QFileInfo(m_settingsFileName).canonicalPath();
|
||||
m_settingsDirectory = QDir(QFileInfo(m_settingsFileName).absolutePath());
|
||||
bridgeController()->setSettingsDirectory(m_settingsDirectory);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ private:
|
|||
|
||||
// Network storage
|
||||
QString m_settingsFileName = "/etc/nymea/nymea-zigbee.conf";
|
||||
QDir m_settingsDirectory;
|
||||
QDir m_settingsDirectory = QDir("/etc/nymea/");
|
||||
QList<ZigbeeNode *> m_nodes;
|
||||
QList<ZigbeeNode *> m_uninitializedNodes;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue