From bbfc20c3ff4b741cd21b162389905a59a8e22f3f Mon Sep 17 00:00:00 2001 From: JF Date: Tue, 11 Aug 2020 17:50:00 +0200 Subject: Add new screen that allows the user to manually validate the new firmware he's just OTA'ed. Still need to find a way to display this screen when needed. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d6d6e8..10c2818 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -337,6 +337,7 @@ list(APPEND SOURCE_FILES DisplayApp/Screens/Label.cpp DisplayApp/Screens/FirmwareUpdate.cpp DisplayApp/Screens/Music.cpp + DisplayApp/Screens/FirmwareValidation.cpp main.cpp drivers/St7789.cpp drivers/SpiNorFlash.cpp @@ -358,6 +359,7 @@ list(APPEND SOURCE_FILES Components/Ble/CurrentTimeService.cpp Components/Ble/AlertNotificationService.cpp Components/Ble/MusicService.cpp + Components/FirmwareValidator/FirmwareValidator.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -415,6 +417,7 @@ set(INCLUDE_FILES DisplayApp/Screens/ScreenList.h DisplayApp/Screens/Label.h DisplayApp/Screens/FirmwareUpdate.h + DisplayApp/Screens/FirmwareValidation.h drivers/St7789.h drivers/SpiNorFlash.h drivers/SpiMaster.h @@ -432,7 +435,8 @@ set(INCLUDE_FILES Components/Ble/CurrentTimeClient.h Components/Ble/AlertNotificationClient.h Components/Ble/DfuService.h - drivers/Cst816s.h + Components/FirmwareValidator/FirmwareValidator.h + drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h libs/date/includes/date/tz.h diff --git a/src/Components/FirmwareValidator/FirmwareValidator.cpp b/src/Components/FirmwareValidator/FirmwareValidator.cpp new file mode 100644 index 0000000..244d5c0 --- /dev/null +++ b/src/Components/FirmwareValidator/FirmwareValidator.cpp @@ -0,0 +1,20 @@ +#include +#include + +#include "FirmwareValidator.h" + +using namespace Pinetime::Controllers; + +bool FirmwareValidator::IsValidated() const { + auto* imageOkPtr = reinterpret_cast(validBitAdress); + return (*imageOkPtr) == validBitValue; +} + +void FirmwareValidator::Validate() { + if(!IsValidated()) + Pinetime::Drivers::InternalFlash::WriteWord(validBitAdress, validBitValue); +} + +void FirmwareValidator::Reset() { + NVIC_SystemReset(); +} diff --git a/src/Components/FirmwareValidator/FirmwareValidator.h b/src/Components/FirmwareValidator/FirmwareValidator.h new file mode 100644 index 0000000..aa576d8 --- /dev/null +++ b/src/Components/FirmwareValidator/FirmwareValidator.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace Pinetime { + namespace Controllers { + class FirmwareValidator { + public: + void Validate(); + bool IsValidated() const; + + void Reset(); + private: + static constexpr uint32_t validBitAdress {0x7BFE8}; + static constexpr uint32_t validBitValue {1}; + }; + } +} diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 46a9638..a24688b 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "../SystemTask/SystemTask.h" using namespace Pinetime::Applications; diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index 23f0493..6af9cf2 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "TouchEvents.h" @@ -80,6 +81,7 @@ namespace Pinetime { Controllers::BrightnessController brightnessController; std::unique_ptr modal; Pinetime::Controllers::NotificationManager& notificationManager; + Pinetime::Controllers::FirmwareValidator validator; }; } } diff --git a/src/DisplayApp/Screens/FirmwareValidation.cpp b/src/DisplayApp/Screens/FirmwareValidation.cpp new file mode 100644 index 0000000..70d3257 --- /dev/null +++ b/src/DisplayApp/Screens/FirmwareValidation.cpp @@ -0,0 +1,91 @@ +#include +#include "FirmwareValidation.h" +#include "../DisplayApp.h" +#include "../../Version.h" +#include "../../Components/FirmwareValidator/FirmwareValidator.h" + +using namespace Pinetime::Applications::Screens; +extern lv_font_t jetbrains_mono_extrabold_compressed; +extern lv_font_t jetbrains_mono_bold_20; + +namespace { + static void ButtonEventHandler(lv_obj_t * obj, lv_event_t event) + { + FirmwareValidation* screen = static_cast(obj->user_data); + screen->OnButtonEvent(obj, event); + } + +} + +FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app, + Pinetime::Controllers::FirmwareValidator &validator) + : Screen{app}, validator{validator} { + labelVersionInfo = lv_label_create(lv_scr_act(), NULL); + lv_obj_align(labelVersionInfo, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_label_set_text(labelVersionInfo, "Version : "); + lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT); + + + labelVersionValue = lv_label_create(lv_scr_act(), NULL); + lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + lv_label_set_recolor(labelVersionValue, true); + sprintf(version, "%d.%d.%d", Version::Major(), Version::Minor(), Version::Patch()); + lv_label_set_text(labelVersionValue, version); + + labelIsValidated = lv_label_create(lv_scr_act(), NULL); + lv_obj_align(labelIsValidated, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 50); + lv_label_set_recolor(labelIsValidated, true); + lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK); + lv_obj_set_width(labelIsValidated, 240); + + if(validator.IsValidated()) + lv_label_set_text(labelIsValidated, "You have already\n#00ff00 validated# this firmware#"); + else { + lv_label_set_text(labelIsValidated, + "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version."); + + buttonValidate = lv_btn_create(lv_scr_act(), NULL); + lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + buttonValidate->user_data = this; + lv_obj_set_event_cb(buttonValidate, ButtonEventHandler); + + labelButtonValidate = lv_label_create(buttonValidate, NULL); + lv_label_set_recolor(labelButtonValidate, true); + lv_label_set_text(labelButtonValidate, "#00ff00 Validate#"); + + buttonReset = lv_btn_create(lv_scr_act(), NULL); + buttonReset->user_data = this; + lv_obj_align(buttonReset, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_event_cb(buttonReset, ButtonEventHandler); + + labelButtonReset = lv_label_create(buttonReset, NULL); + lv_label_set_recolor(labelButtonReset, true); + lv_label_set_text(labelButtonReset, "#ff0000 Reset#"); + } +} + + +FirmwareValidation::~FirmwareValidation() { + lv_obj_clean(lv_scr_act()); +} + +bool FirmwareValidation::Refresh() { + return running; +} + +bool FirmwareValidation::OnButtonPushed() { + running = false; + return true; +} + +void FirmwareValidation::OnButtonEvent(lv_obj_t *object, lv_event_t event) { + if(object == buttonValidate && event == LV_EVENT_PRESSED) { + validator.Validate(); + running = false; + } else if(object == buttonReset && event == LV_EVENT_PRESSED) { + validator.Reset(); + } + +} + + diff --git a/src/DisplayApp/Screens/FirmwareValidation.h b/src/DisplayApp/Screens/FirmwareValidation.h new file mode 100644 index 0000000..947f557 --- /dev/null +++ b/src/DisplayApp/Screens/FirmwareValidation.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include "Screen.h" +#include +#include +#include + +namespace Pinetime { + namespace Controllers { + class FirmwareValidator; + } + + namespace Applications { + namespace Screens { + + class FirmwareValidation : public Screen{ + public: + FirmwareValidation(DisplayApp* app, Pinetime::Controllers::FirmwareValidator& validator); + ~FirmwareValidation() override; + + bool Refresh() override; + bool OnButtonPushed() override; + + void OnButtonEvent(lv_obj_t *object, lv_event_t event); + + private: + Pinetime::Controllers::FirmwareValidator& validator; + + lv_obj_t* labelVersionInfo; + lv_obj_t* labelVersionValue; + char version[9]; + lv_obj_t* labelIsValidated; + lv_obj_t* buttonValidate; + lv_obj_t* labelButtonValidate; + lv_obj_t* buttonReset; + lv_obj_t* labelButtonReset; + bool running = true; + }; + } + } +} diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 9f57f6f..d4b7818 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -58,14 +58,6 @@ void SystemTask::Work() { spi.Init(); spiNorFlash.Init(); - - // Write the 'image OK' flag if it's not already done - // TODO implement a better verification mecanism for the image (ask for user confirmation via UI/BLE ?) - uint32_t* imageOkPtr = reinterpret_cast(0x7BFE8); - uint32_t imageOk = *imageOkPtr; - if(imageOk != 1) - Pinetime::Drivers::InternalFlash::WriteWord(0x7BFE8, 1); - nimbleController.Init(); nimbleController.StartAdvertising(); lcd.Init(); -- cgit v0.10.2 From 41c36d3a422fd08867f743de78c0aeee4418b622 Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 14 Aug 2020 20:47:21 +0200 Subject: Re-order apps in application menu on 2 pages. Add firmware validation app. diff --git a/src/DisplayApp/Apps.h b/src/DisplayApp/Apps.h index 2ee7429..2666d90 100644 --- a/src/DisplayApp/Apps.h +++ b/src/DisplayApp/Apps.h @@ -2,6 +2,6 @@ namespace Pinetime { namespace Applications { - enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music}; + enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music, FirmwareValidation}; } } \ No newline at end of file diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index bbd99a3..9355780 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -190,6 +190,7 @@ void DisplayApp::RunningState() { case Apps::Gauge: currentScreen.reset(new Screens::Gauge(this)); break; case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break; case Apps::Music : currentScreen.reset(new Screens::Music(this, systemTask.nimble().music())); break; + case Apps::FirmwareValidation: currentScreen.reset(new Screens::FirmwareValidation(this, validator)); break; } nextApp = Apps::None; } diff --git a/src/DisplayApp/Screens/ApplicationList.cpp b/src/DisplayApp/Screens/ApplicationList.cpp index c7c096f..575426f 100644 --- a/src/DisplayApp/Screens/ApplicationList.cpp +++ b/src/DisplayApp/Screens/ApplicationList.cpp @@ -11,7 +11,7 @@ ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app) : Screen(app), screens{app, { [this]() -> std::unique_ptr { return CreateScreen1(); }, - //[this]() -> std::unique_ptr { return CreateScreen2(); }, + [this]() -> std::unique_ptr { return CreateScreen2(); }, //[this]() -> std::unique_ptr { return CreateScreen3(); } } } {} @@ -39,13 +39,15 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) { std::unique_ptr ApplicationList::CreateScreen1() { std::array applications { - {{Symbols::asterisk, Apps::Meter}, - {Symbols::tachometer, Apps::Gauge}, - {Symbols::clock, Apps::Clock}, - {Symbols::music, Apps::Music}, - {Symbols::list, Apps::SysInfo}, - {Symbols::sun, Apps::Brightness} + {{Symbols::clock, Apps::Clock}, + {Symbols::music, Apps::Music}, + {Symbols::sun, Apps::Brightness}, + {Symbols::list, Apps::SysInfo}, + {Symbols::check, Apps::FirmwareValidation}, + {Symbols::none, Apps::None} } + + }; return std::unique_ptr(new Screens::Tile(app, applications)); @@ -53,12 +55,12 @@ std::unique_ptr ApplicationList::CreateScreen1() { std::unique_ptr ApplicationList::CreateScreen2() { std::array applications { - {{"0", Apps::Meter}, - {"1", Apps::Gauge}, - {"2", Apps::Clock}, - {"3", Apps::Music}, - {"4", Apps::SysInfo}, - {"5", Apps::Brightness} + {{Symbols::tachometer, Apps::Gauge}, + {Symbols::asterisk, Apps::Meter}, + {Symbols::none, Apps::None}, + {Symbols::none, Apps::None}, + {Symbols::none, Apps::None}, + {Symbols::none, Apps::None} } }; diff --git a/src/DisplayApp/Screens/ApplicationList.h b/src/DisplayApp/Screens/ApplicationList.h index 372cbb7..a1e6811 100644 --- a/src/DisplayApp/Screens/ApplicationList.h +++ b/src/DisplayApp/Screens/ApplicationList.h @@ -22,7 +22,7 @@ namespace Pinetime { private: bool running = true; - ScreenList<1> screens; + ScreenList<2> screens; std::unique_ptr CreateScreen1(); std::unique_ptr CreateScreen2(); std::unique_ptr CreateScreen3(); diff --git a/src/DisplayApp/Screens/Symbols.h b/src/DisplayApp/Screens/Symbols.h index 940006d..54c3f8f 100644 --- a/src/DisplayApp/Screens/Symbols.h +++ b/src/DisplayApp/Screens/Symbols.h @@ -4,6 +4,7 @@ namespace Pinetime { namespace Applications { namespace Screens { namespace Symbols { + static constexpr char* none = ""; static constexpr char* batteryFull = "\xEF\x89\x80"; static constexpr char* batteryEmpty = "\xEF\x89\x84"; static constexpr char* batteryThreeQuarter = "\xEF\x89\x81"; -- cgit v0.10.2 From bfc3f07a374a78603405a50885a0109b491bfd3f Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 14 Aug 2020 21:46:34 +0200 Subject: Add doc about firmware validation diff --git a/bootloader/README.md b/bootloader/README.md index 7911207..61e7ed6 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -113,4 +113,25 @@ Use NRFConnect or dfu.py (in /bootloader/ota-dfu-python) to upload sudo dfu.py -z /home/jf/nrf52/bootloader/dfu.zip -a --legacy ` -**Note** : dfu.py is a slightly modified version of [this repo](https://github.com/daniel-thompson/ota-dfu-python). \ No newline at end of file +**Note** : dfu.py is a slightly modified version of [this repo](https://github.com/daniel-thompson/ota-dfu-python). + +See [this page](../doc/CompanionApps/NrfconnectOTA.md) for more info about OTA with NRFConect + +### Firmware validation +Once the OTA is done, InfiniTime will reset the watch to apply the update. When the watch reboots, the new firmware is running. + +One last step is needed to finalize the upgrade : the new firmware must be manually validated. If the watch resets while the image is not validated, the bootloader will automatically revert to the previous version of the firmware. + +If the new firmware is working correctly, open the application menu and tap on the 'check' app. This apps displays the version of the firmware that is currently running, and allows you to validate the firmware, of reset the device to rollback to the previous version. + +Firmware validation application in the menu: + +![Firmware Validation App](../doc/CompanionApps/firmwareValidationApp.jpg "Firmware Validation App") + +The firmware is not validated yet. Tap 'Validate' to validate it, or 'Reset' to rollback to the previous version. + +![Firmware Not Validated](../doc/CompanionApps/firmwareNoValidated.jpg "Firmware Not Validated") + +The firmware is validated! + +![Firmware Validated](../doc/CompanionApps/firmwareValidated.jpg "Firmware Validated") diff --git a/doc/CompanionApps/firmwareNoValidated.jpg b/doc/CompanionApps/firmwareNoValidated.jpg new file mode 100644 index 0000000..28df7ea Binary files /dev/null and b/doc/CompanionApps/firmwareNoValidated.jpg differ diff --git a/doc/CompanionApps/firmwareValidated.jpg b/doc/CompanionApps/firmwareValidated.jpg new file mode 100644 index 0000000..0d6f99b Binary files /dev/null and b/doc/CompanionApps/firmwareValidated.jpg differ diff --git a/doc/CompanionApps/firmwareValidationApp.jpg b/doc/CompanionApps/firmwareValidationApp.jpg new file mode 100644 index 0000000..d78ad0c Binary files /dev/null and b/doc/CompanionApps/firmwareValidationApp.jpg differ -- cgit v0.10.2 From 1eceafee1c97c64a1fa936e29915daca4051bb05 Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 14 Aug 2020 21:58:35 +0200 Subject: Fix typo. diff --git a/bootloader/README.md b/bootloader/README.md index 61e7ed6..34846f1 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -122,7 +122,7 @@ Once the OTA is done, InfiniTime will reset the watch to apply the update. When One last step is needed to finalize the upgrade : the new firmware must be manually validated. If the watch resets while the image is not validated, the bootloader will automatically revert to the previous version of the firmware. -If the new firmware is working correctly, open the application menu and tap on the 'check' app. This apps displays the version of the firmware that is currently running, and allows you to validate the firmware, of reset the device to rollback to the previous version. +If the new firmware is working correctly, open the application menu and tap on the 'check' app. This apps displays the version of the firmware that is currently running, and allows you to validate the firmware, or reset the device to rollback to the previous version. Firmware validation application in the menu: -- cgit v0.10.2