From aa20a78b0e760fe0d0ad74dc2632b95590b901a3 Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Mon, 19 Apr 2021 19:30:25 +0300 Subject: [PATCH] [FL-164] Add bootloader version (#417) * Add bootloader versioning * Move some logic to api-hal-version * Backport to f4 * Dolphin: update version screen layout, make it more readable Co-authored-by: Aleksandr Kutuzov --- applications/cli/cli.c | 29 ++++++-- applications/dolphin/dolphin.c | 32 +++++++- applications/dolphin/dolphin_views.c | 43 ++++++++--- applications/dolphin/dolphin_views.h | 4 + .../targets/f4/stm32wb55xx_flash_cm4.ld | 2 +- bootloader/targets/f4/target.c | 7 ++ bootloader/targets/f4/target.mk | 4 + .../targets/f5/stm32wb55xx_flash_cm4.ld | 2 +- bootloader/targets/f5/target.c | 6 ++ bootloader/targets/f5/target.mk | 3 + core/flipper.c | 31 ++++++-- .../targets/api-hal-include/api-hal-boot.h | 1 + .../targets/api-hal-include/api-hal-version.h | 15 ++++ firmware/targets/f4/api-hal/api-hal-boot.c | 3 +- firmware/targets/f4/api-hal/api-hal-version.c | 15 ++++ firmware/targets/f5/api-hal/api-hal-boot.c | 3 +- firmware/targets/f5/api-hal/api-hal-version.c | 15 ++++ lib/lib.mk | 5 ++ lib/version/version.c | 50 +++++++++++++ lib/version/version.h | 73 +++++++++++++++++++ make/git.mk | 4 +- 21 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 lib/version/version.c create mode 100644 lib/version/version.h diff --git a/applications/cli/cli.c b/applications/cli/cli.c index 63ec6503..fb48413d 100644 --- a/applications/cli/cli.c +++ b/applications/cli/cli.c @@ -1,5 +1,7 @@ #include "cli_i.h" #include "cli_commands.h" +#include +#include Cli* cli_alloc() { Cli* cli = furi_alloc(sizeof(Cli)); @@ -48,16 +50,31 @@ size_t cli_read(Cli* cli, uint8_t* buffer, size_t size) { return api_hal_vcp_rx(buffer, size); } -void cli_print_version() { - printf("Build date:" BUILD_DATE ". " - "Git Commit:" GIT_COMMIT ". " - "Git Branch:" GIT_BRANCH ". " - "Commit Number:" GIT_BRANCH_NUM "."); +void cli_print_version(const Version* version) { + if(version) { + printf("\tVersion:\t%s\r\n", version_get_version(version)); + printf("\tBuild date:\t%s\r\n", version_get_builddate(version)); + printf( + "\tGit Commit:\t%s (%s)\r\n", + version_get_githash(version), + version_get_gitbranchnum(version)); + printf("\tGit Branch:\t%s\r\n", version_get_gitbranch(version)); + } else { + printf("\tNo build info\r\n"); + } } void cli_motd() { + const Version* version; printf("Flipper cli.\r\n"); - cli_print_version(); + + version = (const Version*)api_hal_version_get_boot_version(); + printf("Bootloader\r\n"); + cli_print_version(version); + + version = (const Version*)api_hal_version_get_fw_version(); + printf("Firmware\r\n"); + cli_print_version(version); } void cli_nl() { diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index ad3f70ab..9247d71b 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -191,6 +191,33 @@ bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { return true; } +bool dolphin_view_idle_down_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + Dolphin* dolphin = context; + + if(event->type != InputTypeShort) return false; + + if((event->key == InputKeyLeft) || (event->key == InputKeyRight)) { + with_view_model( + dolphin->idle_view_down, (DolphinViewIdleDownModel * model) { + model->show_fw_or_boot = !model->show_fw_or_boot; + return true; + }); + } + + if(event->key == InputKeyBack) { + with_view_model( + dolphin->idle_view_down, (DolphinViewIdleDownModel * model) { + model->show_fw_or_boot = 0; + return true; + }); + view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); + } + + return false; +} + Dolphin* dolphin_alloc() { Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); // Message queue @@ -255,11 +282,14 @@ Dolphin* dolphin_alloc() { // Down Idle View dolphin->idle_view_down = view_alloc(); + view_set_context(dolphin->idle_view_down, dolphin); + view_allocate_model( + dolphin->idle_view_down, ViewModelTypeLockFree, sizeof(DolphinViewIdleDownModel)); view_set_draw_callback(dolphin->idle_view_down, dolphin_view_idle_down_draw); + view_set_input_callback(dolphin->idle_view_down, dolphin_view_idle_down_input); view_set_previous_callback(dolphin->idle_view_down, dolphin_view_idle_back); view_dispatcher_add_view( dolphin->idle_view_dispatcher, DolphinViewIdleDown, dolphin->idle_view_down); - // HW Mismatch dolphin->view_hw_mismatch = view_alloc(); view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw); diff --git a/applications/dolphin/dolphin_views.c b/applications/dolphin/dolphin_views.c index 345e664b..8173b49a 100644 --- a/applications/dolphin/dolphin_views.c +++ b/applications/dolphin/dolphin_views.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include static char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"}; @@ -92,25 +94,46 @@ void dolphin_view_lockmenu_draw(Canvas* canvas, void* model) { } void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { - canvas_clear(canvas); + DolphinViewIdleDownModel* m = model; + const Version* ver; + char buffer[64]; + canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 15, "Version info:"); + canvas_draw_str(canvas, 2, 13, m->show_fw_or_boot ? "Boot Version info:" : "FW Version info:"); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 5, 25, TARGET " " BUILD_DATE); - canvas_draw_str(canvas, 5, 35, GIT_BRANCH); - canvas_draw_str(canvas, 5, 45, GIT_BRANCH_NUM " " GIT_COMMIT); - char buffer[64]; + // Hardware version snprintf( buffer, - 64, - "HW: %d.F%dB%dC%d", + sizeof(buffer), + "HW: %d.F%dB%dC%d %s", api_hal_version_get_hw_version(), api_hal_version_get_hw_target(), api_hal_version_get_hw_body(), - api_hal_version_get_hw_connect()); - canvas_draw_str(canvas, 5, 55, buffer); + api_hal_version_get_hw_connect(), + api_hal_version_get_name_ptr()); + canvas_draw_str(canvas, 5, 23, buffer); + + ver = m->show_fw_or_boot ? api_hal_version_get_boot_version() : + api_hal_version_get_fw_version(); + + if(!ver) { + canvas_draw_str(canvas, 5, 33, "No info"); + return; + } + + snprintf( + buffer, sizeof(buffer), "%s [%s]", version_get_version(ver), version_get_builddate(ver)); + canvas_draw_str(canvas, 5, 33, buffer); + + snprintf( + buffer, sizeof(buffer), "%s [%s]", version_get_githash(ver), version_get_gitbranchnum(ver)); + canvas_draw_str(canvas, 5, 43, buffer); + + snprintf( + buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver)); + canvas_draw_str(canvas, 5, 53, buffer); } void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model) { diff --git a/applications/dolphin/dolphin_views.h b/applications/dolphin/dolphin_views.h index 9d53626f..49f0f887 100644 --- a/applications/dolphin/dolphin_views.h +++ b/applications/dolphin/dolphin_views.h @@ -28,6 +28,10 @@ typedef struct { uint32_t butthurt; } DolphinViewIdleUpModel; +typedef struct { + bool show_fw_or_boot; +} DolphinViewIdleDownModel; + typedef struct { uint8_t idx; } DolphinViewMenuModel; diff --git a/bootloader/targets/f4/stm32wb55xx_flash_cm4.ld b/bootloader/targets/f4/stm32wb55xx_flash_cm4.ld index ce970b16..41d36b11 100644 --- a/bootloader/targets/f4/stm32wb55xx_flash_cm4.ld +++ b/bootloader/targets/f4/stm32wb55xx_flash_cm4.ld @@ -55,7 +55,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ /* Specify the memory areas */ MEMORY { -FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/bootloader/targets/f4/target.c b/bootloader/targets/f4/target.c index 7060e2e5..cd90400c 100644 --- a/bootloader/targets/f4/target.c +++ b/bootloader/targets/f4/target.c @@ -9,6 +9,8 @@ #include #include +#include + // Boot request enum #define BOOT_REQUEST_NONE 0x00000000 #define BOOT_REQUEST_DFU 0xDF00B000 @@ -128,6 +130,10 @@ void rtc_init() { LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); } +void version_save(void) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR1, (uint32_t)version_get()); +} + void lcd_backlight_on() { LL_GPIO_SetOutputPin(BOOT_LCD_BL_PORT, BOOT_LCD_BL_PIN); } @@ -142,6 +148,7 @@ void target_init() { clock_init(); gpio_init(); rtc_init(); + version_save(); usb_wire_reset(); // Errata 2.2.9, Flash OPTVERR flag is always set after system reset diff --git a/bootloader/targets/f4/target.mk b/bootloader/targets/f4/target.mk index 3acf372f..92220ca8 100644 --- a/bootloader/targets/f4/target.mk +++ b/bootloader/targets/f4/target.mk @@ -24,6 +24,10 @@ CFLAGS += -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc LDFLAGS += -T$(TARGET_DIR)/stm32wb55xx_flash_cm4.ld +# Version generation +CFLAGS += -I../lib/version +C_SOURCES += ../lib/version/version.c + ASM_SOURCES += $(wildcard $(TARGET_DIR)/*.s) C_SOURCES += $(wildcard $(TARGET_DIR)/*.c) CPP_SOURCES += $(wildcard $(TARGET_DIR)/*.cpp) diff --git a/bootloader/targets/f5/stm32wb55xx_flash_cm4.ld b/bootloader/targets/f5/stm32wb55xx_flash_cm4.ld index ce970b16..41d36b11 100644 --- a/bootloader/targets/f5/stm32wb55xx_flash_cm4.ld +++ b/bootloader/targets/f5/stm32wb55xx_flash_cm4.ld @@ -55,7 +55,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ /* Specify the memory areas */ MEMORY { -FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/bootloader/targets/f5/target.c b/bootloader/targets/f5/target.c index 3007c91e..d515e985 100644 --- a/bootloader/targets/f5/target.c +++ b/bootloader/targets/f5/target.c @@ -9,6 +9,7 @@ #include #include +#include #include // Boot request enum @@ -110,6 +111,10 @@ void rtc_init() { LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); } +void version_save(void) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR1, (uint32_t)version_get()); +} + void usb_wire_reset() { LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN); LL_mDelay(10); @@ -122,6 +127,7 @@ void target_init() { api_hal_init(); target_led_control("RGB"); rtc_init(); + version_save(); usb_wire_reset(); // Errata 2.2.9, Flash OPTVERR flag is always set after system reset diff --git a/bootloader/targets/f5/target.mk b/bootloader/targets/f5/target.mk index 4e23c951..d8ba9c2a 100644 --- a/bootloader/targets/f5/target.mk +++ b/bootloader/targets/f5/target.mk @@ -37,6 +37,9 @@ C_SOURCES += $(DRIVERS_DIR)/lp5562.c CFLAGS += -I$(TARGET_DIR)/api-hal C_SOURCES += $(wildcard $(TARGET_DIR)/api-hal/*.c) +# Version generation +CFLAGS += -I../lib/version +C_SOURCES += ../lib/version/version.c ASM_SOURCES += $(wildcard $(TARGET_DIR)/*.s) C_SOURCES += $(wildcard $(TARGET_DIR)/*.c) diff --git a/core/flipper.c b/core/flipper.c index 55b66027..60e76f34 100644 --- a/core/flipper.c +++ b/core/flipper.c @@ -1,12 +1,33 @@ #include "flipper.h" #include #include +#include +#include + +static void flipper_print_version(const Version* version) { + if(version) { + printf("\tVersion:\t%s\r\n", version_get_version(version)); + printf("\tBuild date:\t%s\r\n", version_get_builddate(version)); + printf( + "\tGit Commit:\t%s (%s)\r\n", + version_get_githash(version), + version_get_gitbranchnum(version)); + printf("\tGit Branch:\t%s\r\n", version_get_gitbranch(version)); + } else { + printf("\tNo build info\r\n"); + } +} void flipper_init() { - printf("[flipper] Build date:" BUILD_DATE ". " - "Git Commit:" GIT_COMMIT ". " - "Git Branch:" GIT_BRANCH ". " - "Commit Number:" GIT_BRANCH_NUM "\r\n"); + const Version* version; + + version = (const Version*)api_hal_version_get_boot_version(); + printf("Bootloader\r\n"); + flipper_print_version(version); + + version = (const Version*)api_hal_version_get_fw_version(); + printf("Firmware\r\n"); + flipper_print_version(version); printf("[flipper] starting services\r\n"); @@ -23,4 +44,4 @@ void flipper_init() { } printf("[flipper] services startup complete\r\n"); -} \ No newline at end of file +} diff --git a/firmware/targets/api-hal-include/api-hal-boot.h b/firmware/targets/api-hal-include/api-hal-boot.h index 797b3ac7..0b247c5c 100644 --- a/firmware/targets/api-hal-include/api-hal-boot.h +++ b/firmware/targets/api-hal-include/api-hal-boot.h @@ -1,4 +1,5 @@ #pragma once +#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/api-hal-include/api-hal-version.h b/firmware/targets/api-hal-include/api-hal-version.h index 88e5bcb2..19e1c3f3 100644 --- a/firmware/targets/api-hal-include/api-hal-version.h +++ b/firmware/targets/api-hal-include/api-hal-version.h @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -29,6 +30,20 @@ const uint32_t api_hal_version_get_hw_timestamp(); /** Get pointer to target name */ const char * api_hal_version_get_name_ptr(); +/** + * Get address of version structure of bootloader, stored in chip flash. + * + * @return Address of boot version structure. + */ +const struct Version* api_hal_version_get_boot_version(void); + +/** + * Get address of version structure of firmware. + * + * @return Address of firmware version structure. + */ +const struct Version* api_hal_version_get_fw_version(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f4/api-hal/api-hal-boot.c b/firmware/targets/f4/api-hal/api-hal-boot.c index b47e8a8a..9193b939 100644 --- a/firmware/targets/f4/api-hal/api-hal-boot.c +++ b/firmware/targets/f4/api-hal/api-hal-boot.c @@ -10,4 +10,5 @@ void api_hal_boot_set_mode(ApiHalBootMode mode) { } else if (mode == ApiHalBootModeDFU) { LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU); } -} \ No newline at end of file +} + diff --git a/firmware/targets/f4/api-hal/api-hal-version.c b/firmware/targets/f4/api-hal/api-hal-version.c index 7ccf23eb..a09eeceb 100644 --- a/firmware/targets/f4/api-hal/api-hal-version.c +++ b/firmware/targets/f4/api-hal/api-hal-version.c @@ -1,5 +1,6 @@ #include #include +#include typedef struct { uint8_t version; @@ -38,3 +39,17 @@ const char * api_hal_version_get_name_ptr() { char * name = ((ApiHalVersionOTP*)OTP_AREA_BASE)->name; return *name == 0xFFU ? NULL : name; } + +const struct Version* api_hal_version_get_fw_version(void) { + return version_get(); +} + +const struct Version* api_hal_version_get_boot_version(void) { +#ifdef NO_BOOTLOADER + return 0; +#else + /* Backup register which points to structure in flash memory */ + return (const struct Version*) LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); +#endif +} + diff --git a/firmware/targets/f5/api-hal/api-hal-boot.c b/firmware/targets/f5/api-hal/api-hal-boot.c index b47e8a8a..9193b939 100644 --- a/firmware/targets/f5/api-hal/api-hal-boot.c +++ b/firmware/targets/f5/api-hal/api-hal-boot.c @@ -10,4 +10,5 @@ void api_hal_boot_set_mode(ApiHalBootMode mode) { } else if (mode == ApiHalBootModeDFU) { LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU); } -} \ No newline at end of file +} + diff --git a/firmware/targets/f5/api-hal/api-hal-version.c b/firmware/targets/f5/api-hal/api-hal-version.c index 1e0b1d31..19fdbc3d 100644 --- a/firmware/targets/f5/api-hal/api-hal-version.c +++ b/firmware/targets/f5/api-hal/api-hal-version.c @@ -1,5 +1,6 @@ #include #include +#include typedef struct { uint8_t version; @@ -38,3 +39,17 @@ const char * api_hal_version_get_name_ptr() { char * name = ((ApiHalVersionOTP*)OTP_AREA_BASE)->name; return *name == 0xFFU ? NULL : name; } + +const struct Version* api_hal_version_get_fw_version(void) { + return version_get(); +} + +const struct Version* api_hal_version_get_boot_version(void) { +#ifdef NO_BOOTLOADER + return 0; +#else + /* Backup register which points to structure in flash memory */ + return (const struct Version*) LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); +#endif +} + diff --git a/lib/lib.mk b/lib/lib.mk index 470447b7..d2cc6ee1 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -82,3 +82,8 @@ CFLAGS += -I$(LIB_DIR)/common-api # drivers CFLAGS += -I$(LIB_DIR)/drivers C_SOURCES += $(wildcard $(LIB_DIR)/drivers/*.c) + +#version +CFLAGS += -I$(LIB_DIR)/version +C_SOURCES += $(LIB_DIR)/version/version.c + diff --git a/lib/version/version.c b/lib/version/version.c new file mode 100644 index 00000000..db29ca42 --- /dev/null +++ b/lib/version/version.c @@ -0,0 +1,50 @@ +#include "version.h" + +struct Version { + const char* git_hash; + const char* git_branch; + const char* git_branch_num; + const char* build_date; + const char* version; + const char* target; +}; + +/* version of current running firmware (bootloader/flipper) */ +static const Version version = { + .git_hash = GIT_COMMIT, + .git_branch = GIT_BRANCH, + .git_branch_num = GIT_BRANCH_NUM, + .build_date = BUILD_DATE, + .version = VERSION, + .target = TARGET, +}; + + +const Version* version_get(void) { + return &version; +} + +const char* version_get_githash(const Version* v) { + return v ? v->git_hash : version.git_hash; +} + +const char* version_get_gitbranch(const Version* v) { + return v ? v->git_branch : version.git_branch; +} + +const char* version_get_gitbranchnum(const Version* v) { + return v ? v->git_branch_num : version.git_branch_num; +} + +const char* version_get_builddate(const Version* v) { + return v ? v->build_date : version.build_date; +} + +const char* version_get_version(const Version* v) { + return v ? v->version : version.version; +} + +const char* version_get_target(const Version* v) { + return v ? v->target : version.target; +} + diff --git a/lib/version/version.h b/lib/version/version.h new file mode 100644 index 00000000..c4b27c97 --- /dev/null +++ b/lib/version/version.h @@ -0,0 +1,73 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Version Version; + +/** + * Gets current running firmware version handle. + * You can store it somewhere. But if you want to retrieve data, + * you have to use 'version_*_get()' set of functions. + * Also, 'version_*_get()' imply to use this + * handle if no handle (NULL_PTR) provided. + * + * @return Handle to version data. + */ +const Version* version_get(void); + +/** + * Gets git hash of build commit. + * + * @param v - ptr to version handle. If zero - gets current running fw info. + * @return git hash + */ +const char* version_get_githash(const Version* v); + +/** + * Gets git branch of build commit. + * + * @param v - ptr to version handle. If zero - gets current running fw info. + * @return git branch + */ +const char* version_get_gitbranch(const Version* v); + +/** + * Gets git number of build commit. + * + * @param v - ptr to version handle. If zero - gets current running fw info. + * @return number of commit + */ +const char* version_get_gitbranchnum(const Version* v); + +/** + * Gets build date. + * + * @param v - ptr to version handle. If zero - gets current running fw info. + * @return build date + */ +const char* version_get_builddate(const Version* v); + +/** + * Gets build version. + * Build version is last tag in git history. + * + * @param v - ptr to version handle. If zero - gets current running fw info. + * @return build date + */ +const char* version_get_version(const Version* v); + +/** + * Gets firmware target. + * Build version is last tag for build commit. + * + * @param v - ptr to version handle. If zero - gets current running fw info. + * @return build date + */ +const char* version_get_target(const Version* v); + +#ifdef __cplusplus +} +#endif + diff --git a/make/git.mk b/make/git.mk index 8f5c9bb4..7e871756 100644 --- a/make/git.mk +++ b/make/git.mk @@ -2,6 +2,8 @@ GIT_COMMIT = $(shell git describe --always --exclude '*' || echo 'unknown') GIT_BRANCH = $(shell git rev-parse --abbrev-ref HEAD || echo 'unknown') GIT_BRANCH_NUM = $(shell git rev-list --count $(GIT_BRANCH) || echo 'nan') BUILD_DATE = $(shell date '+%d-%m-%Y' || echo 'unknown') +VERSION = $(shell git describe --tags --abbrev=0 || echo 'unknown') CFLAGS += -DGIT_COMMIT="\"$(GIT_COMMIT)\"" -DGIT_BRANCH="\"$(GIT_BRANCH)\"" -DGIT_BRANCH_NUM="\"$(GIT_BRANCH_NUM)\"" -CFLAGS += -DBUILD_DATE="\"$(BUILD_DATE)\"" -DTARGET="\"$(TARGET)\"" +CFLAGS += -DBUILD_DATE="\"$(BUILD_DATE)\"" -DTARGET="\"$(TARGET)\"" -DVERSION="\"$(VERSION)\"" +