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:
parent
57b3397078
commit
0a0f28fff4
5 changed files with 52 additions and 17 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
return running;
|
if (xTaskGetTickCount() - startTime > (5 * 1024)) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
doNotGoToSleep = false;
|
// Make sure that exiting an app doesn't enable sleeping,
|
||||||
|
// if the exiting was caused by a firmware update
|
||||||
|
if (!bleController.IsFirmwareUpdating()) {
|
||||||
|
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();
|
||||||
|
|
Loading…
Reference in a new issue