Skip to content

Commit

Permalink
[FL-3109] Better radio stack update (flipperdevices#166)
Browse files Browse the repository at this point in the history
* Try to install the firmware regardless of wireless stack failures

* Re-check wireless status several times before trying to reinstall it
  • Loading branch information
gsurkov authored Mar 9, 2023
1 parent b910a18 commit c4f1b13
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 60 deletions.
10 changes: 6 additions & 4 deletions backend/abstractoperationrunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Q_LOGGING_CATEGORY(CATEGORY_DEFAULT, "DEF")

AbstractOperationRunner::AbstractOperationRunner(QObject *parent):
QObject(parent),
m_state(State::Idle)
m_state(Idle)
{}

const QLoggingCategory &AbstractOperationRunner::loggingCategory() const
Expand All @@ -20,8 +20,8 @@ const QLoggingCategory &AbstractOperationRunner::loggingCategory() const

void AbstractOperationRunner::enqueueOperation(AbstractOperation *operation)
{
if(m_state == State::Idle) {
m_state = State::Running;
if(m_state == Idle) {
m_state = Running;
QTimer::singleShot(0, this, &AbstractOperationRunner::processQueue);
}

Expand All @@ -46,7 +46,7 @@ void AbstractOperationRunner::enqueueOperation(AbstractOperation *operation)
void AbstractOperationRunner::processQueue()
{
if(m_queue.isEmpty()) {
m_state = State::Idle;
m_state = Idle;
return;
}

Expand All @@ -60,4 +60,6 @@ void AbstractOperationRunner::clearQueue()
while(!m_queue.isEmpty()) {
m_queue.dequeue()->deleteLater();
}

m_state = Idle;
}
2 changes: 1 addition & 1 deletion backend/abstractoperationrunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AbstractOperationRunner : public QObject
{
Q_OBJECT

enum class State {
enum State {
Idle,
Running
};
Expand Down
73 changes: 48 additions & 25 deletions backend/flipperzero/recovery/wirelessstackdownloadoperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_RECOVERY)
using namespace Flipper;
using namespace Zero;

static constexpr int INSTALL_TRY_COUNT = 3;
static constexpr int CHECK_TRY_COUNT = 3;
static constexpr int TIMER_INTERVAL_MS = 1000;

WirelessStackDownloadOperation::WirelessStackDownloadOperation(Recovery *recovery, QIODevice *file, uint32_t targetAddress, QObject *parent):
AbstractRecoveryOperation(recovery, parent),
m_file(file),
m_loopTimer(new QTimer(this)),
m_targetAddress(targetAddress),
m_retryCount(3)
m_installTryCount(INSTALL_TRY_COUNT)
{
m_loopTimer->setInterval(TIMER_INTERVAL_MS);

connect(m_loopTimer, &QTimer::timeout, this, &WirelessStackDownloadOperation::nextStateLogic);
connect(this, &AbstractOperation::finished, m_loopTimer, &QTimer::stop);
}

const QString WirelessStackDownloadOperation::description() const
Expand All @@ -32,34 +39,35 @@ const QString WirelessStackDownloadOperation::description() const

void WirelessStackDownloadOperation::nextStateLogic()
{
if(operationState() == AbstractOperation::Ready) {
setOperationState(WirelessStackDownloadOperation::StartingFUS);
if(operationState() == Ready) {
setOperationState(StartingFUS);
startFUS();

} else if(operationState() == WirelessStackDownloadOperation::StartingFUS) {
setOperationState(WirelessStackDownloadOperation::DeletingWirelessStack);
} else if(operationState() == StartingFUS) {
setOperationState(DeletingWirelessStack);
deleteWirelessStack();

} else if(operationState() == WirelessStackDownloadOperation::DeletingWirelessStack) {
} else if(operationState() == DeletingWirelessStack) {
if(isWirelessStackDeleted()) {
setOperationState(WirelessStackDownloadOperation::DownloadingWirelessStack);
setOperationState(DownloadingWirelessStack);
downloadWirelessStack();
}

} else if(operationState() == WirelessStackDownloadOperation::DownloadingWirelessStack) {
setOperationState(WirelessStackDownloadOperation::UpgradingWirelessStack);
} else if(operationState() == DownloadingWirelessStack) {
setOperationState(UpgradingWirelessStack);
upgradeWirelessStack();

} else if(operationState() == WirelessStackDownloadOperation::UpgradingWirelessStack) {
if(!isWirelessStackUpgraded()) {
return;

} else if(!isWirelessStackOK()) {
setOperationState(AbstractOperation::Ready);
tryAgain();
} else if(operationState() == UpgradingWirelessStack) {
if(isWirelessStackUpgraded()) {
setOperationState(CheckingWirelessStack);
checkWirelessStack();
}

} else {
} else if(operationState() == CheckingWirelessStack) {
if(isWirelessStackOK()) {
finish();
} else {
tryAgain();
}
}
}
Expand All @@ -68,11 +76,11 @@ void WirelessStackDownloadOperation::onOperationTimeout()
{
QString msg;

if(operationState() == WirelessStackDownloadOperation::StartingFUS) {
if(operationState() == StartingFUS) {
msg = QStringLiteral("Failed to start Firmware Upgrade Service: Operation timeout.");
} else if(operationState() == WirelessStackDownloadOperation::DeletingWirelessStack) {
} else if(operationState() == DeletingWirelessStack) {
msg = QStringLiteral("Failed to delete existing Wireless Stack: Operation timeout.");
} else if(operationState() == WirelessStackDownloadOperation::UpgradingWirelessStack) {
} else if(operationState() == UpgradingWirelessStack) {
msg = QStringLiteral("Failed to upgrade Wireless Stack: Operation timeout.");
} else {
msg = QStringLiteral("Should not have timed out here, probably a bug.");
Expand Down Expand Up @@ -100,7 +108,7 @@ void WirelessStackDownloadOperation::deleteWirelessStack()
if(!recovery()->deleteWirelessStack()) {
finishWithError(BackendError::RecoveryError, recovery()->errorString());
} else {
m_loopTimer->start(1000);
m_loopTimer->start();
}
}

Expand Down Expand Up @@ -150,7 +158,7 @@ void WirelessStackDownloadOperation::upgradeWirelessStack()
if(!recovery()->upgradeWirelessStack()) {
finishWithError(BackendError::RecoveryError, recovery()->errorString());
} else {
m_loopTimer->start(1000);
m_loopTimer->start();
}
}

Expand All @@ -174,18 +182,33 @@ bool WirelessStackDownloadOperation::isWirelessStackUpgraded()
return !errorOccured;
}

void WirelessStackDownloadOperation::checkWirelessStack()
{
m_checkTryCount = CHECK_TRY_COUNT;
m_loopTimer->start();

advanceOperationState();
}

bool WirelessStackDownloadOperation::isWirelessStackOK()
{
return recovery()->checkWirelessStack();
}

void WirelessStackDownloadOperation::tryAgain()
{
if(--m_retryCount == 0) {
finishWithError(BackendError::RecoveryError, QStringLiteral("Could not install wireless stack after several tries, giving up"));
if(--m_checkTryCount > 0) {
qCDebug(LOG_RECOVERY) << "Wireless stack check seems to have failed, retrying...";

} else {
} else if(--m_installTryCount > 0) {
qCDebug(LOG_RECOVERY) << "Wireless stack installation seems to have failed, retrying...";

m_loopTimer->stop();

setOperationState(Ready);
advanceOperationState();

} else {
finishWithError(BackendError::RecoveryError, QStringLiteral("Could not install wireless stack after several tries, giving up"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ private slots:
void downloadWirelessStack();
void upgradeWirelessStack();
bool isWirelessStackUpgraded();
void checkWirelessStack();
bool isWirelessStackOK();
void tryAgain();

QIODevice *m_file;
QTimer *m_loopTimer;
uint32_t m_targetAddress;
int m_retryCount;
int m_installTryCount;
int m_checkTryCount;
};

}
Expand Down
15 changes: 15 additions & 0 deletions backend/flipperzero/toplevel/fullrepairoperation.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "fullrepairoperation.h"

#include <QFile>
#include <QDebug>
#include <QLoggingCategory>

#include "flipperzero/devicestate.h"

Expand All @@ -17,6 +19,8 @@

#include "flipperzero/helper/firmwarehelper.h"

Q_DECLARE_LOGGING_CATEGORY(CATEGORY_DEFAULT)

using namespace Flipper;
using namespace Zero;

Expand Down Expand Up @@ -127,3 +131,14 @@ void FullRepairOperation::restartDevice()
{
registerSubOperation(m_utility->restartDevice());
}

void FullRepairOperation::onSubOperationError(AbstractOperation *operation)
{
if(operationState() == DownloadingRadioFirmware) {
qCInfo(CATEGORY_DEFAULT) << operation->description() << "failed with reason:" << operation->errorString() << "Attempting to install the firmware anyway...";
advanceOperationState();

} else {
AbstractTopLevelOperation::onSubOperationError(operation);
}
}
2 changes: 2 additions & 0 deletions backend/flipperzero/toplevel/fullrepairoperation.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ private slots:
void provisionRegion();
void restartDevice();

void onSubOperationError(AbstractOperation *operation) override;

RecoveryInterface *m_recovery;
UtilityInterface *m_utility;
FirmwareHelper *m_helper;
Expand Down
66 changes: 37 additions & 29 deletions backend/flipperzero/toplevel/legacyupdateoperation.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include "legacyupdateoperation.h"

#include <QFile>
#include <QDebug>
#include <QDateTime>
#include <QTemporaryFile>
#include <QLoggingCategory>

#include "flipperzero/devicestate.h"

Expand All @@ -27,6 +29,8 @@

#define SHIPPED_VERSION QStringLiteral("0.43.1") // Old version that is shipped by default

Q_DECLARE_LOGGING_CATEGORY(CATEGORY_DEFAULT)

using namespace Flipper;
using namespace Zero;

Expand All @@ -46,66 +50,66 @@ const QString LegacyUpdateOperation::description() const

void LegacyUpdateOperation::nextStateLogic()
{
if(operationState() == LegacyUpdateOperation::Ready) {
setOperationState(LegacyUpdateOperation::FetchingFirmware);
if(operationState() == Ready) {
setOperationState(FetchingFirmware);
fetchFirmware();

} else if(operationState() == LegacyUpdateOperation::FetchingFirmware) {
setOperationState(LegacyUpdateOperation::SavingBackup);
} else if(operationState() == FetchingFirmware) {
setOperationState(SavingBackup);
saveBackup();

} else if(operationState() == LegacyUpdateOperation::SavingBackup) {
setOperationState(LegacyUpdateOperation::StartingRecovery);
} else if(operationState() == SavingBackup) {
setOperationState(StartingRecovery);
startRecovery();

} else if(operationState() == LegacyUpdateOperation::StartingRecovery) {
} else if(operationState() == StartingRecovery) {

if(m_helper->hasRadioUpdate()) {
setOperationState(LegacyUpdateOperation::SettingBootMode);
setOperationState(SettingBootMode);
setBootMode();

} else{
setOperationState(LegacyUpdateOperation::DownloadingRadioFirmware);
setOperationState(DownloadingRadioFirmware);
advanceOperationState();
}

} else if(operationState() == LegacyUpdateOperation::SettingBootMode) {
setOperationState(LegacyUpdateOperation::DownloadingRadioFirmware);
} else if(operationState() == SettingBootMode) {
setOperationState(DownloadingRadioFirmware);
downloadRadioFirmware();

} else if(operationState() == LegacyUpdateOperation::DownloadingRadioFirmware) {
setOperationState(LegacyUpdateOperation::DownloadingFirmware);
} else if(operationState() == DownloadingRadioFirmware) {
setOperationState(DownloadingFirmware);
downloadFirmware();

} else if(operationState() == LegacyUpdateOperation::DownloadingFirmware) {
} else if(operationState() == DownloadingFirmware) {

if(m_helper->hasRadioUpdate()) {
setOperationState(LegacyUpdateOperation::CorrectingOptionBytes);
setOperationState(CorrectingOptionBytes);
correctOptionBytes();

} else {
setOperationState(LegacyUpdateOperation::ExitingRecovery);
setOperationState(ExitingRecovery);
exitRecovery();
}

} else if((operationState() == LegacyUpdateOperation::ExitingRecovery) ||
(operationState() == LegacyUpdateOperation::CorrectingOptionBytes)) {
setOperationState(LegacyUpdateOperation::DownloadingAssets);
} else if((operationState() == ExitingRecovery) ||
(operationState() == CorrectingOptionBytes)) {
setOperationState(DownloadingAssets);
downloadAssets();

} else if(operationState() == LegacyUpdateOperation::DownloadingAssets) {
setOperationState(LegacyUpdateOperation::ProvisioningRegion);
} else if(operationState() == DownloadingAssets) {
setOperationState(ProvisioningRegion);
provisionRegion();

} else if(operationState() == LegacyUpdateOperation::ProvisioningRegion) {
setOperationState(LegacyUpdateOperation::RestoringBackup);
} else if(operationState() == ProvisioningRegion) {
setOperationState(RestoringBackup);
restoreBackup();

} else if(operationState() == LegacyUpdateOperation::RestoringBackup) {
setOperationState(LegacyUpdateOperation::RestartingDevice);
} else if(operationState() == RestoringBackup) {
setOperationState(RestartingDevice);
restartDevice();

} else if(operationState() == LegacyUpdateOperation::RestartingDevice) {
} else if(operationState() == RestartingDevice) {
finish();
}
}
Expand Down Expand Up @@ -196,8 +200,12 @@ void LegacyUpdateOperation::restartDevice()

void LegacyUpdateOperation::onSubOperationError(AbstractOperation *operation)
{
const auto keepError = operationState() == LegacyUpdateOperation::SavingBackup ||
operationState() == LegacyUpdateOperation::StartingRecovery;
if(operationState() == DownloadingRadioFirmware) {
qCInfo(CATEGORY_DEFAULT) << operation->description() << "failed with reason:" << operation->errorString() << "Attempting to install the firmware anyway...";
advanceOperationState();

finishWithError(keepError ? operation->error() : BackendError::OperationError, operation->errorString());
} else {
const auto keepError = operationState() == SavingBackup || operationState() == StartingRecovery;
finishWithError(keepError ? operation->error() : BackendError::OperationError, operation->errorString());
}
}

0 comments on commit c4f1b13

Please sign in to comment.