[FL-3629] fbt: reworked assets & resources handling (#3160)

* fbt: reworking targets & assets handling WIP
* fbt: dist fixes
* fbt: moved SD card resources to owning apps
* unit_tests: moved resources to app folder
* github: updated unit_tests paths
* github: packaging fixes
* unit_tests: fixes
* fbt: assets: internal cleanup
* fbt: reworked assets handling
* github: unit_tests: reintroducing fixes
* minor cleanup
* fbt: naming changes to reflect private nature of scons tools
* fbt: resources: fixed dist archive paths
* docs: updated paths
* docs: updated more paths
* docs: included "resources" parameter in app manifest docs; updated assets readme
* updated gitignore for assets
* github: updated action versions
* unit_tests: restored timeout; scripts: assets: logging changes
* gh: don't upload desktop animations for unit test run

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger
2023-10-31 00:17:30 +09:00
committed by GitHub
co-authored by あく
parent 176fb21f5f
commit 917410a0a8
345 changed files with 466 additions and 394 deletions
+39
View File
@@ -0,0 +1,39 @@
#include <furi.h>
#include <furi_hal.h>
#include <flipper.h>
#include <alt_boot.h>
#include <assets_icons.h>
#include <toolbox/compress.h>
#include <gui/canvas.h>
#include <gui/canvas_i.h>
void flipper_boot_dfu_show_splash() {
// Initialize
Canvas* canvas = canvas_init();
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_icon(canvas, 0, 64 - 50, &I_DFU_128x50);
canvas_draw_str(canvas, 2, 8, "Update & Recovery Mode");
canvas_draw_str(canvas, 2, 21, "DFU Started");
canvas_commit(canvas);
canvas_free(canvas);
}
void flipper_boot_dfu_exec() {
// Show DFU splashscreen
flipper_boot_dfu_show_splash();
// Errata 2.2.9, Flash OPTVERR flag is always set after system reset
WRITE_REG(FLASH->SR, FLASH_SR_OPTVERR);
// Cleanup before jumping to DFU
furi_hal_deinit_early();
// Remap memory to system bootloader
LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SYSTEMFLASH);
// Jump
furi_hal_switch(0x0);
}
+77
View File
@@ -0,0 +1,77 @@
#include <furi.h>
#include <furi_hal.h>
#include <flipper.h>
#include <alt_boot.h>
#include <semphr.h>
#include <update_util/update_operation.h>
#define TAG "Main"
int32_t init_task(void* context) {
UNUSED(context);
// Flipper FURI HAL
furi_hal_init();
// Init flipper
flipper_init();
return 0;
}
int main() {
// Initialize FURI layer
furi_init();
// Flipper critical FURI HAL
furi_hal_init_early();
FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL);
#ifdef FURI_RAM_EXEC
// Prevent entering sleep mode when executed from RAM
furi_hal_power_insomnia_enter();
furi_thread_start(main_thread);
#else
furi_hal_light_sequence("RGB");
// Delay is for button sampling
furi_delay_ms(100);
FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode();
if(boot_mode == FuriHalRtcBootModeDfu || !furi_hal_gpio_read(&gpio_button_left)) {
furi_hal_light_sequence("rgb WB");
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal);
flipper_boot_dfu_exec();
furi_hal_power_reset();
} else if(boot_mode == FuriHalRtcBootModeUpdate) {
furi_hal_light_sequence("rgb BR");
// Do update
flipper_boot_update_exec();
// if things go nice, we shouldn't reach this point.
// But if we do, abandon to avoid bootloops
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal);
furi_hal_power_reset();
} else if(!furi_hal_gpio_read(&gpio_button_up)) {
furi_hal_light_sequence("rgb WR");
flipper_boot_recovery_exec();
furi_hal_power_reset();
} else {
furi_hal_light_sequence("rgb G");
furi_thread_start(main_thread);
}
#endif
// Run Kernel
furi_run();
furi_crash("Kernel is Dead");
}
void Error_Handler(void) {
furi_crash("ErrorHandler");
}
void abort() {
furi_crash("AbortHandler");
}
+63
View File
@@ -0,0 +1,63 @@
#include <furi.h>
#include <furi_hal.h>
#include <flipper.h>
#include <alt_boot.h>
#include <assets_icons.h>
#include <toolbox/compress.h>
#include <gui/canvas.h>
#include <gui/canvas_i.h>
#define COUNTER_VALUE (136U)
static void flipper_boot_recovery_draw_progress(Canvas* canvas, size_t progress) {
if(progress < COUNTER_VALUE) {
// Fill the progress bar while the progress is going down
canvas_draw_rframe(canvas, 59, 41, 69, 8, 2);
size_t width = (COUNTER_VALUE - progress) * 68 / COUNTER_VALUE;
canvas_draw_box(canvas, 60, 42, width, 6);
} else {
canvas_draw_rframe(canvas, 59, 41, 69, 8, 2);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 60, 42, 67, 6);
canvas_set_color(canvas, ColorBlack);
}
canvas_commit(canvas);
}
void flipper_boot_recovery_draw_splash(Canvas* canvas) {
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_icon(canvas, 0, 0, &I_Erase_pin_128x64);
canvas_commit(canvas);
}
void flipper_boot_recovery_exec() {
Canvas* canvas = canvas_init();
// Show recovery splashscreen
flipper_boot_recovery_draw_splash(canvas);
size_t counter = COUNTER_VALUE;
while(counter) {
if(!furi_hal_gpio_read(&gpio_button_down)) {
break;
}
if(!furi_hal_gpio_read(&gpio_button_right)) {
counter--;
} else {
counter = COUNTER_VALUE;
}
flipper_boot_recovery_draw_progress(canvas, counter);
}
if(!counter) {
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset);
furi_hal_rtc_set_pin_fails(0);
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
}
}
+97
View File
@@ -0,0 +1,97 @@
#include "stm32wbxx.h"
/*!< Uncomment the following line if you need to relocate your vector Table in Internal SRAM. */
/* #define VECT_TAB_SRAM */
#ifndef VECT_TAB_OFFSET
#define VECT_TAB_OFFSET \
0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
#endif
#define VECT_TAB_BASE_ADDRESS \
SRAM1_BASE /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
/* The SystemCoreClock variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = 4000000UL; /*CPU1: M4 on MSI clock after startup (4MHz)*/
const uint32_t AHBPrescTable[16UL] =
{1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL};
const uint32_t APBPrescTable[8UL] = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL};
const uint32_t MSIRangeTable[16UL] = {
100000UL,
200000UL,
400000UL,
800000UL,
1000000UL,
2000000UL,
4000000UL,
8000000UL,
16000000UL,
24000000UL,
32000000UL,
48000000UL,
0UL,
0UL,
0UL,
0UL}; /* 0UL values are incorrect cases */
/**
* @brief Setup the microcontroller system.
* @param None
* @retval None
*/
void SystemInit(void) {
/* Configure the Vector Table location add offset address ------------------*/
#if defined(VECT_TAB_SRAM) && defined(VECT_TAB_BASE_ADDRESS)
/* program in SRAMx */
SCB->VTOR = VECT_TAB_BASE_ADDRESS |
VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAMx for CPU1 */
#else /* program in FLASH */
SCB->VTOR = VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
/* FPU settings ------------------------------------------------------------*/
#if(__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |=
((3UL << (10UL * 2UL)) | (3UL << (11UL * 2UL))); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set MSION bit */
RCC->CR |= RCC_CR_MSION;
/* Reset CFGR register */
RCC->CFGR = 0x00070000U;
/* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */
RCC->CR &= (uint32_t)0xFAF6FEFBU;
/*!< Reset LSI1 and LSI2 bits */
RCC->CSR &= (uint32_t)0xFFFFFFFAU;
/*!< Reset HSI48ON bit */
RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x22041000U;
#if defined(STM32WB55xx) || defined(STM32WB5Mxx)
/* Reset PLLSAI1CFGR register */
RCC->PLLSAI1CFGR = 0x22041000U;
#endif
/* Reset HSEBYP bit */
RCC->CR &= 0xFFFBFFFFU;
/* Disable all interrupts */
RCC->CIER = 0x00000000;
}
+209
View File
@@ -0,0 +1,209 @@
#include <furi.h>
#include <furi_hal.h>
#include <flipper.h>
#include <alt_boot.h>
#include <fatfs.h>
#include <flipper_format/flipper_format.h>
#include <update_util/update_manifest.h>
#include <update_util/update_operation.h>
#include <toolbox/path.h>
#include <toolbox/crc32_calc.h>
#define UPDATE_POINTER_FILE_PATH "/" UPDATE_MANIFEST_POINTER_FILE_NAME
static FATFS* pfs = NULL;
#define CHECK_FRESULT(result) \
{ \
if((result) != FR_OK) { \
return false; \
} \
}
static bool flipper_update_mount_sd() {
for(int i = 0; i < furi_hal_sd_max_mount_retry_count(); ++i) {
if(furi_hal_sd_init((i % 2) == 0) != FuriStatusOk) {
/* Next attempt will be without card reset, let it settle */
furi_delay_ms(1000);
continue;
}
if(f_mount(pfs, "/", 1) == FR_OK) {
return true;
}
}
return false;
}
static bool flipper_update_init() {
// TODO FL-3504: Configure missing peripherals properly
furi_hal_bus_enable(FuriHalBusHSEM);
furi_hal_bus_enable(FuriHalBusIPCC);
furi_hal_bus_enable(FuriHalBusRNG);
furi_hal_bus_enable(FuriHalBusUSART1);
furi_hal_clock_init();
furi_hal_rtc_init();
furi_hal_interrupt_init();
furi_hal_spi_config_init();
fatfs_init();
if(!furi_hal_sd_is_present()) {
return false;
}
pfs = malloc(sizeof(FATFS));
return flipper_update_mount_sd();
}
static bool flipper_update_load_stage(const FuriString* work_dir, UpdateManifest* manifest) {
FIL file;
FILINFO stat;
FuriString* loader_img_path;
loader_img_path = furi_string_alloc_set(work_dir);
path_append(loader_img_path, furi_string_get_cstr(manifest->staged_loader_file));
if((f_stat(furi_string_get_cstr(loader_img_path), &stat) != FR_OK) ||
(f_open(&file, furi_string_get_cstr(loader_img_path), FA_OPEN_EXISTING | FA_READ) !=
FR_OK) ||
(stat.fsize == 0)) {
furi_string_free(loader_img_path);
return false;
}
furi_string_free(loader_img_path);
void* img = malloc(stat.fsize);
uint32_t bytes_read = 0;
const uint16_t MAX_READ = 0xFFFF;
uint32_t crc = 0;
do {
uint16_t size_read = 0;
if(f_read(&file, img + bytes_read, MAX_READ, &size_read) != FR_OK) { //-V769
break;
}
crc = crc32_calc_buffer(crc, img + bytes_read, size_read);
bytes_read += size_read;
} while(bytes_read == MAX_READ);
do {
if((bytes_read != stat.fsize) || (crc != manifest->staged_loader_crc)) {
break;
}
/* Point of no return. Literally
*
* NB: we MUST disable IRQ, otherwise handlers from flash
* will change global variables (like tick count)
* that are located in .data. And we move staged loader
* to the same memory region. So, IRQ handlers will mess up
* memmove'd .text section and ruin your day.
* We don't want that to happen.
*/
__disable_irq();
memmove((void*)(SRAM1_BASE), img, stat.fsize);
LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SRAM);
furi_hal_switch((void*)SRAM1_BASE);
return true;
} while(false);
free(img);
return false;
}
static bool flipper_update_get_manifest_path(FuriString* out_path) {
FIL file;
FILINFO stat;
uint16_t size_read = 0;
char manifest_name_buf[UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN] = {0};
furi_string_reset(out_path);
CHECK_FRESULT(f_stat(UPDATE_POINTER_FILE_PATH, &stat));
CHECK_FRESULT(f_open(&file, UPDATE_POINTER_FILE_PATH, FA_OPEN_EXISTING | FA_READ));
do {
if(f_read(&file, manifest_name_buf, UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN, &size_read) !=
FR_OK) {
break;
}
if((size_read == 0) || (size_read == UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN)) {
break;
}
furi_string_set(out_path, manifest_name_buf);
furi_string_right(out_path, strlen(STORAGE_EXT_PATH_PREFIX));
} while(0);
f_close(&file);
return !furi_string_empty(out_path);
}
static UpdateManifest* flipper_update_process_manifest(const FuriString* manifest_path) {
FIL file;
FILINFO stat;
CHECK_FRESULT(f_stat(furi_string_get_cstr(manifest_path), &stat));
CHECK_FRESULT(f_open(&file, furi_string_get_cstr(manifest_path), FA_OPEN_EXISTING | FA_READ));
uint8_t* manifest_data = malloc(stat.fsize);
uint32_t bytes_read = 0;
const uint16_t MAX_READ = 0xFFFF;
do {
uint16_t size_read = 0;
if(f_read(&file, manifest_data + bytes_read, MAX_READ, &size_read) != FR_OK) { //-V769
break;
}
bytes_read += size_read;
} while(bytes_read == MAX_READ);
UpdateManifest* manifest = NULL;
do {
if(bytes_read != stat.fsize) {
break;
}
manifest = update_manifest_alloc();
if(!update_manifest_init_mem(manifest, manifest_data, bytes_read)) {
update_manifest_free(manifest);
manifest = NULL;
}
} while(false);
f_close(&file);
free(manifest_data);
return manifest;
}
void flipper_boot_update_exec() {
if(!flipper_update_init()) {
return;
}
FuriString* work_dir = furi_string_alloc();
FuriString* manifest_path = furi_string_alloc();
do {
if(!flipper_update_get_manifest_path(manifest_path)) {
break;
}
UpdateManifest* manifest = flipper_update_process_manifest(manifest_path);
if(!manifest) {
break;
}
path_extract_dirname(furi_string_get_cstr(manifest_path), work_dir);
if(!flipper_update_load_stage(work_dir, manifest)) {
update_manifest_free(manifest);
}
} while(false);
furi_string_free(manifest_path);
furi_string_free(work_dir);
free(pfs);
}