Make firmware updating more foolproof (#469)

* Make firmware updating more foolproof and fix bugs
* No need to manually handle overflow
* Make startTime TickType_t
* Don't process TouchEvents::None
* Fix sleep getting re-enabled issue more directly
This commit is contained in:
Riku Isokoski 2021-07-22 22:57:45 +03:00 committed by GitHub
parent 57b3397078
commit 0a0f28fff4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 17 deletions

View file

@ -266,13 +266,14 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
static_cast<uint8_t>(ErrorCodes::NoError)}; static_cast<uint8_t>(ErrorCodes::NoError)};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
} else { } else {
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
NRF_LOG_INFO("Image Error : bad CRC"); NRF_LOG_INFO("Image Error : bad CRC");
uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response), uint8_t data[3] {static_cast<uint8_t>(Opcodes::Response),
static_cast<uint8_t>(Opcodes::ValidateFirmware), static_cast<uint8_t>(Opcodes::ValidateFirmware),
static_cast<uint8_t>(ErrorCodes::CrcError)}; static_cast<uint8_t>(ErrorCodes::CrcError)};
notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3); notificationManager.AsyncSend(connectionHandle, controlPointCharacteristicHandle, data, 3);
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
Reset();
} }
return 0; return 0;
@ -283,10 +284,8 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
return 0; return 0;
} }
NRF_LOG_INFO("[DFU] -> Activate image and reset!"); NRF_LOG_INFO("[DFU] -> Activate image and reset!");
bleController.StopFirmwareUpdate();
systemTask.PushMessage(Pinetime::System::Messages::BleFirmwareUpdateFinished);
Reset();
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated); bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated);
Reset();
return 0; return 0;
default: default:
return 0; return 0;
@ -294,6 +293,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
} }
void DfuService::OnTimeout() { void DfuService::OnTimeout() {
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
Reset(); Reset();
} }
@ -307,7 +307,6 @@ void DfuService::Reset() {
applicationSize = 0; applicationSize = 0;
expectedCrc = 0; expectedCrc = 0;
notificationManager.Reset(); notificationManager.Reset();
bleController.State(Pinetime::Controllers::Ble::FirmwareUpdateStates::Error);
bleController.StopFirmwareUpdate(); bleController.StopFirmwareUpdate();
systemTask.PushMessage(Pinetime::System::Messages::BleFirmwareUpdateFinished); systemTask.PushMessage(Pinetime::System::Messages::BleFirmwareUpdateFinished);
} }

View file

@ -177,9 +177,13 @@ void DisplayApp::Refresh() {
} }
break; break;
case Messages::TouchEvent: { case Messages::TouchEvent: {
if (state != States::Running) if (state != States::Running) {
break; break;
}
auto gesture = OnTouchEvent(); auto gesture = OnTouchEvent();
if (gesture == TouchEvents::None) {
break;
}
if (!currentScreen->OnTouchEvent(gesture)) { if (!currentScreen->OnTouchEvent(gesture)) {
if (currentApp == Apps::Clock) { if (currentApp == Apps::Clock) {
switch (gesture) { switch (gesture) {
@ -286,6 +290,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
break; break;
case Apps::FirmwareUpdate: case Apps::FirmwareUpdate:
currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController); currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController);
ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
break; break;
case Apps::Notifications: case Apps::Notifications:

View file

@ -27,9 +27,10 @@ FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp* app, Pinetime
lv_bar_set_value(bar1, 0, LV_ANIM_OFF); lv_bar_set_value(bar1, 0, LV_ANIM_OFF);
percentLabel = lv_label_create(lv_scr_act(), nullptr); percentLabel = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text(percentLabel, ""); lv_label_set_text(percentLabel, "Waiting...");
lv_obj_set_auto_realign(percentLabel, true); lv_obj_set_auto_realign(percentLabel, true);
lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60); lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60);
startTime = xTaskGetTickCount();
} }
FirmwareUpdate::~FirmwareUpdate() { FirmwareUpdate::~FirmwareUpdate() {
@ -40,26 +41,42 @@ bool FirmwareUpdate::Refresh() {
switch (bleController.State()) { switch (bleController.State()) {
default: default:
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Idle:
// This condition makes sure that the app is exited if somehow it got
// launched without a firmware update. This should never happen.
if (state != States::Error) {
if (xTaskGetTickCount() - startTime > (60 * 1024)) {
UpdateError();
state = States::Error;
}
} else if (xTaskGetTickCount() - startTime > (5 * 1024)) {
running = false;
}
break;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Running:
if (state != States::Running) if (state != States::Running)
state = States::Running; state = States::Running;
return DisplayProgression(); DisplayProgression();
break;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated:
if (state != States::Validated) { if (state != States::Validated) {
UpdateValidated(); UpdateValidated();
state = States::Validated; state = States::Validated;
} }
return running; break;
case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error: case Pinetime::Controllers::Ble::FirmwareUpdateStates::Error:
if (state != States::Error) { if (state != States::Error) {
UpdateError(); UpdateError();
state = States::Error; state = States::Error;
} }
if (xTaskGetTickCount() - startTime > (5 * 1024)) {
running = false;
}
break;
}
return running; return running;
} }
}
bool FirmwareUpdate::DisplayProgression() const { void FirmwareUpdate::DisplayProgression() const {
float current = bleController.FirmwareUpdateCurrentBytes() / 1024.0f; float current = bleController.FirmwareUpdateCurrentBytes() / 1024.0f;
float total = bleController.FirmwareUpdateTotalBytes() / 1024.0f; float total = bleController.FirmwareUpdateTotalBytes() / 1024.0f;
int16_t pc = (current / total) * 100.0f; int16_t pc = (current / total) * 100.0f;
@ -67,7 +84,6 @@ bool FirmwareUpdate::DisplayProgression() const {
lv_label_set_text(percentLabel, percentStr); lv_label_set_text(percentLabel, percentStr);
lv_bar_set_value(bar1, pc, LV_ANIM_OFF); lv_bar_set_value(bar1, pc, LV_ANIM_OFF);
return running;
} }
void FirmwareUpdate::UpdateValidated() { void FirmwareUpdate::UpdateValidated() {
@ -78,4 +94,9 @@ void FirmwareUpdate::UpdateValidated() {
void FirmwareUpdate::UpdateError() { void FirmwareUpdate::UpdateError() {
lv_label_set_recolor(percentLabel, true); lv_label_set_recolor(percentLabel, true);
lv_label_set_text(percentLabel, "#ff0000 Error!#"); lv_label_set_text(percentLabel, "#ff0000 Error!#");
startTime = xTaskGetTickCount();
}
bool FirmwareUpdate::OnButtonPushed() {
return true;
} }

View file

@ -2,6 +2,7 @@
#include "Screen.h" #include "Screen.h"
#include <lvgl/src/lv_core/lv_obj.h> #include <lvgl/src/lv_core/lv_obj.h>
#include "FreeRTOS.h"
namespace Pinetime { namespace Pinetime {
namespace Controllers { namespace Controllers {
@ -25,13 +26,17 @@ namespace Pinetime {
lv_obj_t* titleLabel; lv_obj_t* titleLabel;
mutable char percentStr[10]; mutable char percentStr[10];
States state; States state = States::Idle;
bool DisplayProgression() const; void DisplayProgression() const;
bool OnButtonPushed() override;
void UpdateValidated(); void UpdateValidated();
void UpdateError(); void UpdateError();
TickType_t startTime;
}; };
} }
} }

View file

@ -198,7 +198,11 @@ void SystemTask::Work() {
Messages message = static_cast<Messages>(msg); Messages message = static_cast<Messages>(msg);
switch (message) { switch (message) {
case Messages::EnableSleeping: case Messages::EnableSleeping:
// Make sure that exiting an app doesn't enable sleeping,
// if the exiting was caused by a firmware update
if (!bleController.IsFirmwareUpdating()) {
doNotGoToSleep = false; doNotGoToSleep = false;
}
break; break;
case Messages::DisableSleeping: case Messages::DisableSleeping:
doNotGoToSleep = true; doNotGoToSleep = true;
@ -275,10 +279,11 @@ void SystemTask::Work() {
displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted); displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted);
break; break;
case Messages::BleFirmwareUpdateFinished: case Messages::BleFirmwareUpdateFinished:
if (bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated) {
NVIC_SystemReset();
}
doNotGoToSleep = false; doNotGoToSleep = false;
xTimerStart(idleTimer, 0); xTimerStart(idleTimer, 0);
if (bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated)
NVIC_SystemReset();
break; break;
case Messages::OnTouchEvent: case Messages::OnTouchEvent:
ReloadIdleTimer(); ReloadIdleTimer();