From 7de7fa293b6eb8def92ecfecc1c1aea63a269624 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:45:42 +0200 Subject: [PATCH 1/9] Optimize trailing slash check (#2503) * Optimize trailing slash check --- .../services/storage/storage_processing.c | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 59527e7696..a3076f2711 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -2,6 +2,17 @@ #include #include +#define STORAGE_PATH_PREFIX_LEN 4u +_Static_assert( + sizeof(STORAGE_ANY_PATH_PREFIX) == STORAGE_PATH_PREFIX_LEN + 1, + "Any path prefix len mismatch"); +_Static_assert( + sizeof(STORAGE_EXT_PATH_PREFIX) == STORAGE_PATH_PREFIX_LEN + 1, + "Ext path prefix len mismatch"); +_Static_assert( + sizeof(STORAGE_INT_PATH_PREFIX) == STORAGE_PATH_PREFIX_LEN + 1, + "Int path prefix len mismatch"); + #define FS_CALL(_storage, _fn) ret = _storage->fs_api->_fn; static bool storage_type_is_valid(StorageType type) { @@ -26,34 +37,29 @@ static StorageData* get_storage_by_file(File* file, StorageData* storages) { static const char* cstr_path_without_vfs_prefix(FuriString* path) { const char* path_cstr = furi_string_get_cstr(path); - return path_cstr + MIN(4u, strlen(path_cstr)); + return path_cstr + MIN(STORAGE_PATH_PREFIX_LEN, strlen(path_cstr)); } static StorageType storage_get_type_by_path(FuriString* path) { StorageType type = ST_ERROR; const char* path_cstr = furi_string_get_cstr(path); - if(furi_string_size(path) == 4) { - if(memcmp(path_cstr, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) { - type = ST_EXT; - } else if(memcmp(path_cstr, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) { - type = ST_INT; - } else if(memcmp(path_cstr, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) { - type = ST_ANY; - } - } else if(furi_string_size(path) > 4) { - if(memcmp(path_cstr, EXT_PATH(""), strlen(EXT_PATH(""))) == 0) { - type = ST_EXT; - } else if(memcmp(path_cstr, INT_PATH(""), strlen(INT_PATH(""))) == 0) { - type = ST_INT; - } else if(memcmp(path_cstr, ANY_PATH(""), strlen(ANY_PATH(""))) == 0) { - type = ST_ANY; + if(furi_string_size(path) > STORAGE_PATH_PREFIX_LEN) { + if(path_cstr[STORAGE_PATH_PREFIX_LEN] != '/') { + return ST_ERROR; } } + if(memcmp(path_cstr, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) { + type = ST_EXT; + } else if(memcmp(path_cstr, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) { + type = ST_INT; + } else if(memcmp(path_cstr, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) { + type = ST_ANY; + } + return type; } - static void storage_path_change_to_real_storage(FuriString* path, StorageType real_storage) { if(furi_string_search(path, STORAGE_ANY_PATH_PREFIX) == 0) { switch(real_storage) { From 9941457cdb3fc1000f83260a58bc57569f01f03e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 17 Mar 2023 22:51:59 +0300 Subject: [PATCH 2/9] Fix issue #387 --- applications/external/snake_game/application.fam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/snake_game/application.fam b/applications/external/snake_game/application.fam index c736a4ddcf..4c15c309b2 100644 --- a/applications/external/snake_game/application.fam +++ b/applications/external/snake_game/application.fam @@ -1,5 +1,5 @@ App( - appid="snake_game", + appid="Snake", name="Snake Game", apptype=FlipperAppType.EXTERNAL, entry_point="snake_game_app", From 3444c5245ee743e0b3100e1859bbb4b728e1bece Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 18 Mar 2023 01:16:34 +0300 Subject: [PATCH 3/9] Tertiary favourite app --- CHANGELOG.md | 33 +------------ .../animations/views/bubble_animation_view.c | 8 ++-- .../services/desktop/desktop_settings.h | 3 +- .../desktop/scenes/desktop_scene_main.c | 19 ++++++++ .../services/desktop/views/desktop_events.h | 1 + .../desktop/views/desktop_view_main.c | 2 + .../scenes/desktop_settings_scene_favorite.c | 48 +++++++++++++++---- .../scenes/desktop_settings_scene_start.c | 22 +++++++-- 8 files changed, 84 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb0d4fe73..7e88bc878d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,35 +1,6 @@ ### New changes -* SubGHz: New protocols support: CAME Space, Stilmatic / Schellenberg -* SubGHz: Add Manually - new protocols -> Beninca, Sommer(FSK), IronLogic, DTM Neo, Gibidi, Elmes Electronic (Elmes Poland), CAME Space -* SubGHz: Security+ 2.0 -> Ability to send custom buttons codes (0x80, 0x81, 0xE2) -* SubGHz: Remember last external module setting and power setting, so if you turn off flipper it will remember last external module settings (only for subghz app) -* SubGHz: Fix issues when external module is not found but plugins tries to use it, now they will fallback to internal in that case -* SubGHz: Fixed external CC1101 module power issues, added more checks, fixed issues when launching subghz favourites -* SubGHz: Removed 330MHz from default freq hopper to make it faster, to change freq hopper settings and remove/add your freqs see -> [Instruction](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) -* SubGHz: Small UI text fixes -* GUI: Fix submenu elements text size, now we can fit more symbols -* Plugins: Added delay and retries to avoid power issues in plugins -> WiFi Scanner, ESP8266 Deauther -* Plugins: Update for WiFi Marauder companion -> `sniff` saves pcaps in `YourFlippersMicroSD/apps_data/marauder/` -> Only with custom marauder build (It is necessary to uncomment "#define WRITE_PACKETS_SERIAL" in configs.h (in marauder fw) and compile the firmware for the wifi board.) Or download precompiled build -> [Download esp32_marauder_ver_flipper_sd_serial.bin](https://github.com/justcallmekoko/ESP32Marauder/releases/latest) - [(by tcpassos)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion/pull/7) -* Plugins: Removed `cdefines` from external plugins as it was not used in any way -* Plugins: Updated **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) (fixed issue #379) -* Plugins: Update for SubGHz Bruteforcer, added - Holtek HT12X 12bit AM 433.920MHz/315MHz/868MHz/915MHz (TE: 433us) -* OFW: iButton: Add support for Dallas DS1971 -* OFW: fbt: explicitly set dist suffix length, not depending on environment settings -* OFW: NFC -> Skip the read when the card is not present -* OFW: NFC -> Mark keys as not found when they couldn't auth successfully -* OFW: Storage -> Require the trailing slash for root paths -* OFW: gh: use shallow clones whenever possible -* OFW: Add new nfc apdu cli command -* OFW: Picopass standard KDF dictionary -* OFW: Nfc: fixes for latest PVS-studio 7.23 -* OFW: Dolphin: new spring animation, weight adjust, drop winter animation. -* OFW: fbt, faploader: minimal app module implementation -> **All plugins now should have** `apptype=FlipperAppType.EXTERNAL` -* OFW: Fbt: fix broken resource deployment -* OFW: NFC: Fix 0 block write possibility in Mifare Classic emulation -* OFW: BadUSB: updated parser and added stringln, hold and release -* OFW: Upside down / left handed orientation support -* OFW: Embed assets in elf file -* OFW: Dumb mode menu freeze fix +* Desktop: Option to set Tertiary favourite app (Hold right arrow on desktop) - **Desktop settings (pin code, favourite app, autolock time) will be resetted!!! Only one time after installing - due to changes in settings structure, after installing of this release desktop settings will not be reset with next release** +* OFW: Optimize trailing slash check #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) diff --git a/applications/services/desktop/animations/views/bubble_animation_view.c b/applications/services/desktop/animations/views/bubble_animation_view.c index 607862d113..bd13bd34aa 100644 --- a/applications/services/desktop/animations/views/bubble_animation_view.c +++ b/applications/services/desktop/animations/views/bubble_animation_view.c @@ -126,13 +126,11 @@ static bool bubble_animation_input_callback(InputEvent* event, void* context) { bubble_animation_activate(animation_view, false); } - if(event->key == InputKeyRight) { + if(event->key == InputKeyRight && event->type == InputTypeShort) { /* Right button reserved for animation activation, so consume */ consumed = true; - if(event->type == InputTypeShort) { - if(animation_view->interact_callback) { - animation_view->interact_callback(animation_view->interact_callback_context); - } + if(animation_view->interact_callback) { + animation_view->interact_callback(animation_view->interact_callback_context); } } diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 26c39f6114..4b4bca0004 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (7) +#define DESKTOP_SETTINGS_VER (8) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) @@ -58,6 +58,7 @@ typedef struct { typedef struct { FavoriteApp favorite_primary; FavoriteApp favorite_secondary; + FavoriteApp favorite_tertiary; PinCode pin_code; uint8_t is_locked; uint32_t auto_lock_delay_ms; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 129270dc34..fd04ff917e 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -170,6 +170,25 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } consumed = true; break; + case DesktopMainEventOpenFavoriteTertiary: + DESKTOP_SETTINGS_LOAD(&desktop->settings); + if(desktop->settings.favorite_tertiary.is_external) { + LoaderStatus status = loader_start( + desktop->loader, + FAP_LOADER_APP_NAME, + desktop->settings.favorite_tertiary.name_or_path); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + } else { + LoaderStatus status = loader_start( + desktop->loader, desktop->settings.favorite_tertiary.name_or_path, NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + } + consumed = true; + break; case DesktopAnimationEventCheckAnimation: animation_manager_check_blocking_process(desktop->animation_manager); consumed = true; diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index 6917dbe73f..f0200ca804 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -5,6 +5,7 @@ typedef enum { DesktopMainEventOpenArchive, DesktopMainEventOpenFavoritePrimary, DesktopMainEventOpenFavoriteSecondary, + DesktopMainEventOpenFavoriteTertiary, DesktopMainEventOpenMenu, DesktopMainEventOpenDebug, DesktopMainEventOpenPassport, diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index 7e68cd4cac..0a1c72ca62 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -67,6 +67,8 @@ bool desktop_main_input_callback(InputEvent* event, void* context) { main_view->callback(DesktopMainEventOpenDebug, main_view->context); } else if(event->key == InputKeyLeft) { main_view->callback(DesktopMainEventOpenFavoriteSecondary, main_view->context); + } else if(event->key == InputKeyRight) { + main_view->callback(DesktopMainEventOpenFavoriteTertiary, main_view->context); } else if(event->key == InputKeyUp) { main_view->callback(DesktopMainEventLock, main_view->context); } else if(event->key == InputKeyOk) { diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 94c5ee9f04..822c6c7a9a 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -53,23 +53,34 @@ void desktop_settings_scene_favorite_on_enter(void* context) { desktop_settings_scene_favorite_submenu_callback, app); - if(primary_favorite) { // Select favorite item in submenu + if(primary_favorite == 0) { // Select favorite item in submenu if((app->settings.favorite_primary.is_external && !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_primary.name_or_path))) { pre_select_item = i; } - } else { + } else if(primary_favorite == 1) { if((app->settings.favorite_secondary.is_external && !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_secondary.name_or_path))) { pre_select_item = i; } + } else if(primary_favorite == 2) { + if((app->settings.favorite_tertiary.is_external && + !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || + (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_tertiary.name_or_path))) { + pre_select_item = i; + } } } - submenu_set_header( - submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); + if(primary_favorite == 0) { + submenu_set_header(submenu, "Primary favorite app:"); + } else if(primary_favorite == 1) { + submenu_set_header(submenu, "Secondary favorite app:"); + } else if(primary_favorite == 2) { + submenu_set_header(submenu, "Tertiary favorite app:"); + } submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch. view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); @@ -85,18 +96,24 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e if(event.type == SceneManagerEventTypeCustom) { if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME) != 0) { - if(primary_favorite) { + if(primary_favorite == 0) { app->settings.favorite_primary.is_external = false; strncpy( app->settings.favorite_primary.name_or_path, FLIPPER_APPS[event.event].name, MAX_APP_LENGTH); - } else { + } else if(primary_favorite == 1) { app->settings.favorite_secondary.is_external = false; strncpy( app->settings.favorite_secondary.name_or_path, FLIPPER_APPS[event.event].name, MAX_APP_LENGTH); + } else if(primary_favorite == 2) { + app->settings.favorite_tertiary.is_external = false; + strncpy( + app->settings.favorite_tertiary.name_or_path, + FLIPPER_APPS[event.event].name, + MAX_APP_LENGTH); } } else { const DialogsFileBrowserOptions browser_options = { @@ -109,32 +126,43 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e .base_path = EXT_PATH("apps"), }; - if(primary_favorite) { // Select favorite fap in file browser + if(primary_favorite == 0) { // Select favorite fap in file browser if(favorite_fap_selector_file_exists( app->settings.favorite_primary.name_or_path)) { furi_string_set_str(temp_path, app->settings.favorite_primary.name_or_path); } - } else { + } else if(primary_favorite == 1) { if(favorite_fap_selector_file_exists( app->settings.favorite_secondary.name_or_path)) { furi_string_set_str(temp_path, app->settings.favorite_secondary.name_or_path); } + } else if(primary_favorite == 2) { + if(favorite_fap_selector_file_exists( + app->settings.favorite_tertiary.name_or_path)) { + furi_string_set_str(temp_path, app->settings.favorite_tertiary.name_or_path); + } } submenu_reset(app->submenu); if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) { - if(primary_favorite) { + if(primary_favorite == 0) { app->settings.favorite_primary.is_external = true; strncpy( app->settings.favorite_primary.name_or_path, furi_string_get_cstr(temp_path), MAX_APP_LENGTH); - } else { + } else if(primary_favorite == 1) { app->settings.favorite_secondary.is_external = true; strncpy( app->settings.favorite_secondary.name_or_path, furi_string_get_cstr(temp_path), MAX_APP_LENGTH); + } else if(primary_favorite == 2) { + app->settings.favorite_tertiary.is_external = true; + strncpy( + app->settings.favorite_tertiary.name_or_path, + furi_string_get_cstr(temp_path), + MAX_APP_LENGTH); } } } diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index e3f83d275a..49c2e74221 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -6,9 +6,11 @@ #define SCENE_EVENT_SELECT_FAVORITE_PRIMARY 0 #define SCENE_EVENT_SELECT_FAVORITE_SECONDARY 1 -#define SCENE_EVENT_SELECT_PIN_SETUP 2 -#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 3 -#define SCENE_EVENT_SELECT_BATTERY_DISPLAY 4 +#define SCENE_EVENT_SELECT_FAVORITE_TERTIARY 2 +#define SCENE_EVENT_SELECT_PIN_SETUP 3 +#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 4 +#define SCENE_EVENT_SELECT_AUTO_LOCK_PIN 5 +#define SCENE_EVENT_SELECT_BATTERY_DISPLAY 6 #define AUTO_LOCK_DELAY_COUNT 9 const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { @@ -79,6 +81,8 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_list_add(variable_item_list, "Secondary Favorite App", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "Tertiary Favorite App", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "PIN Setup", 1, NULL, NULL); item = variable_item_list_add( @@ -129,12 +133,17 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SCENE_EVENT_SELECT_FAVORITE_PRIMARY: - scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 1); + scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 0); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); consumed = true; break; case SCENE_EVENT_SELECT_FAVORITE_SECONDARY: - scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 0); + scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 1); + scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); + consumed = true; + break; + case SCENE_EVENT_SELECT_FAVORITE_TERTIARY: + scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 2); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); consumed = true; break; @@ -145,6 +154,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY: consumed = true; break; + case SCENE_EVENT_SELECT_AUTO_LOCK_PIN: + consumed = true; + break; case SCENE_EVENT_SELECT_BATTERY_DISPLAY: consumed = true; break; From eb355d4a16ed83fa78fcebf31b545e76054163ce Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Fri, 17 Mar 2023 21:16:06 +0300 Subject: [PATCH 4/9] Fix a typo: right shift instead of greater than --- lib/one_wire/ibutton/protocols/dallas/dallas_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/one_wire/ibutton/protocols/dallas/dallas_common.c b/lib/one_wire/ibutton/protocols/dallas/dallas_common.c index 22b25db848..ebf57e555f 100644 --- a/lib/one_wire/ibutton/protocols/dallas/dallas_common.c +++ b/lib/one_wire/ibutton/protocols/dallas/dallas_common.c @@ -85,7 +85,7 @@ bool dallas_common_read_mem(OneWireHost* host, uint16_t address, uint8_t* data, onewire_host_write(host, DALLAS_COMMON_CMD_READ_MEM); onewire_host_write(host, (uint8_t)address); - onewire_host_write(host, (uint8_t)(address > BITS_IN_BYTE)); + onewire_host_write(host, (uint8_t)(address >> BITS_IN_BYTE)); onewire_host_read_bytes(host, data, (uint16_t)data_size); From 58d4f3b53198784b77c8b9186ffe050a3052d4f0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 18 Mar 2023 02:50:05 +0300 Subject: [PATCH 5/9] OFW PR: 2493 - SD Driver: reinit sd card on error No issues was found during my own testing and running sd benchmarks, sorry for rushing, I may miss something, usually I prefer to wait for official review --- applications/services/storage/storage_glue.c | 61 ++--- applications/services/storage/storage_glue.h | 2 +- .../services/storage/storage_processing.c | 6 +- .../services/storage/storages/storage_ext.c | 2 +- firmware/targets/f18/furi_hal/furi_hal.c | 2 +- firmware/targets/f7/fatfs/fatfs.c | 27 +-- firmware/targets/f7/fatfs/fatfs.h | 28 +-- firmware/targets/f7/fatfs/ffconf.h | 2 +- firmware/targets/f7/fatfs/syscall.c | 116 ---------- firmware/targets/f7/fatfs/user_diskio.c | 210 +++++++++--------- firmware/targets/f7/fatfs/user_diskio.h | 21 +- firmware/targets/f7/furi_hal/furi_hal.c | 2 +- firmware/targets/f7/src/update.c | 2 +- 13 files changed, 153 insertions(+), 328 deletions(-) delete mode 100644 firmware/targets/f7/fatfs/syscall.c diff --git a/applications/services/storage/storage_glue.c b/applications/services/storage/storage_glue.c index 5dabfa3860..63e44c9d7d 100644 --- a/applications/services/storage/storage_glue.c +++ b/applications/services/storage/storage_glue.c @@ -73,29 +73,34 @@ uint32_t storage_data_get_timestamp(StorageData* storage) { /****************** storage glue ******************/ -bool storage_has_file(const File* file, StorageData* storage_data) { - bool result = false; +static StorageFile* storage_get_file(const File* file, StorageData* storage) { + StorageFile* storage_file_ref = NULL; StorageFileList_it_t it; - for(StorageFileList_it(it, storage_data->files); !StorageFileList_end_p(it); + for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it); StorageFileList_next(it)) { - const StorageFile* storage_file = StorageFileList_cref(it); + StorageFile* storage_file = StorageFileList_ref(it); if(storage_file->file->file_id == file->file_id) { - result = true; + storage_file_ref = storage_file; break; } } - return result; + return storage_file_ref; +} + +bool storage_has_file(const File* file, StorageData* storage) { + return storage_get_file(file, storage) != NULL; } -bool storage_path_already_open(FuriString* path, StorageFileList_t array) { +bool storage_path_already_open(FuriString* path, StorageData* storage) { bool open = false; StorageFileList_it_t it; - for(StorageFileList_it(it, array); !StorageFileList_end_p(it); StorageFileList_next(it)) { + for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it); + StorageFileList_next(it)) { const StorageFile* storage_file = StorageFileList_cref(it); if(furi_string_cmp(storage_file->path, path) == 0) { @@ -108,43 +113,15 @@ bool storage_path_already_open(FuriString* path, StorageFileList_t array) { } void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage) { - StorageFile* founded_file = NULL; - - StorageFileList_it_t it; - - for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it); - StorageFileList_next(it)) { - StorageFile* storage_file = StorageFileList_ref(it); - - if(storage_file->file->file_id == file->file_id) { - founded_file = storage_file; - break; - } - } - - furi_check(founded_file != NULL); - - founded_file->file_data = file_data; + StorageFile* storage_file_ref = storage_get_file(file, storage); + furi_check(storage_file_ref != NULL); + storage_file_ref->file_data = file_data; } void* storage_get_storage_file_data(const File* file, StorageData* storage) { - const StorageFile* founded_file = NULL; - - StorageFileList_it_t it; - - for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it); - StorageFileList_next(it)) { - const StorageFile* storage_file = StorageFileList_cref(it); - - if(storage_file->file->file_id == file->file_id) { - founded_file = storage_file; - break; - } - } - - furi_check(founded_file != NULL); - - return founded_file->file_data; + StorageFile* storage_file_ref = storage_get_file(file, storage); + furi_check(storage_file_ref != NULL); + return storage_file_ref->file_data; } void storage_push_storage_file(File* file, FuriString* path, StorageData* storage) { diff --git a/applications/services/storage/storage_glue.h b/applications/services/storage/storage_glue.h index bf0a1c69ed..f10640345d 100644 --- a/applications/services/storage/storage_glue.h +++ b/applications/services/storage/storage_glue.h @@ -60,7 +60,7 @@ struct StorageData { }; bool storage_has_file(const File* file, StorageData* storage_data); -bool storage_path_already_open(FuriString* path, StorageFileList_t files); +bool storage_path_already_open(FuriString* path, StorageData* storage_data); void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage); void* storage_get_storage_file_data(const File* file, StorageData* storage); diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index a3076f2711..dd0fdc2a76 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -111,7 +111,7 @@ bool storage_process_file_open( file->error_id = storage_get_data(app, path, &storage); if(file->error_id == FSE_OK) { - if(storage_path_already_open(path, storage->files)) { + if(storage_path_already_open(path, storage)) { file->error_id = FSE_ALREADY_OPEN; } else { if(access_mode & FSAM_WRITE) { @@ -268,7 +268,7 @@ bool storage_process_dir_open(Storage* app, File* file, FuriString* path) { file->error_id = storage_get_data(app, path, &storage); if(file->error_id == FSE_OK) { - if(storage_path_already_open(path, storage->files)) { + if(storage_path_already_open(path, storage)) { file->error_id = FSE_ALREADY_OPEN; } else { storage_push_storage_file(file, path, storage); @@ -357,7 +357,7 @@ static FS_Error storage_process_common_remove(Storage* app, FuriString* path) { FS_Error ret = storage_get_data(app, path, &storage); do { - if(storage_path_already_open(path, storage->files)) { + if(storage_path_already_open(path, storage)) { ret = FSE_ALREADY_OPEN; break; } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index 530c88f851..f6a650d34d 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -619,7 +619,7 @@ static const FS_Api fs_api = { void storage_ext_init(StorageData* storage) { SDData* sd_data = malloc(sizeof(SDData)); - sd_data->fs = &USERFatFS; + sd_data->fs = &fatfs_object; sd_data->path = "0:/"; sd_data->sd_was_present = true; diff --git a/firmware/targets/f18/furi_hal/furi_hal.c b/firmware/targets/f18/furi_hal/furi_hal.c index 0a68fdb696..387963c1c3 100644 --- a/firmware/targets/f18/furi_hal/furi_hal.c +++ b/firmware/targets/f18/furi_hal/furi_hal.c @@ -76,7 +76,7 @@ void furi_hal_init() { furi_hal_compress_icon_init(); // FatFS driver initialization - MX_FATFS_Init(); + fatfs_init(); FURI_LOG_I(TAG, "FATFS OK"); } diff --git a/firmware/targets/f7/fatfs/fatfs.c b/firmware/targets/f7/fatfs/fatfs.c index 1aa5fe44bc..66ddbca061 100644 --- a/firmware/targets/f7/fatfs/fatfs.c +++ b/firmware/targets/f7/fatfs/fatfs.c @@ -18,22 +18,13 @@ #include "fatfs.h" -uint8_t retUSER; /* Return value for USER */ -char USERPath[4]; /* USER logical drive path */ -FATFS USERFatFS; /* File system object for USER logical drive */ -FIL USERFile; /* File object for USER */ +/** logical drive path */ +char fatfs_path[4]; +/** File system object */ +FATFS fatfs_object; -/* USER CODE BEGIN Variables */ - -/* USER CODE END Variables */ - -void MX_FATFS_Init(void) { - /*## FatFS: Link the USER driver ###########################*/ - retUSER = FATFS_LinkDriver(&USER_Driver, USERPath); - - /* USER CODE BEGIN Init */ - /* additional user code for init */ - /* USER CODE END Init */ +void fatfs_init(void) { + FATFS_LinkDriver(&sd_fatfs_driver, fatfs_path); } /** @@ -42,13 +33,7 @@ void MX_FATFS_Init(void) { * @retval Time in DWORD */ DWORD get_fattime(void) { - /* USER CODE BEGIN get_fattime */ return 0; - /* USER CODE END get_fattime */ } -/* USER CODE BEGIN Application */ - -/* USER CODE END Application */ - /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/fatfs/fatfs.h b/firmware/targets/f7/fatfs/fatfs.h index a0775d88b3..199f0150fc 100644 --- a/firmware/targets/f7/fatfs/fatfs.h +++ b/firmware/targets/f7/fatfs/fatfs.h @@ -16,34 +16,24 @@ ****************************************************************************** */ -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __fatfs_H -#define __fatfs_H -#ifdef __cplusplus -extern "C" { -#endif +#pragma once #include "fatfs/ff.h" #include "fatfs/ff_gen_drv.h" -#include "user_diskio.h" /* defines USER_Driver as external */ - -/* USER CODE BEGIN Includes */ +#include "user_diskio.h" -/* USER CODE END Includes */ - -extern uint8_t retUSER; /* Return value for USER */ -extern char USERPath[4]; /* USER logical drive path */ -extern FATFS USERFatFS; /* File system object for USER logical drive */ -extern FIL USERFile; /* File object for USER */ +#ifdef __cplusplus +extern "C" { +#endif -void MX_FATFS_Init(void); +/** File system object */ +extern FATFS fatfs_object; -/* USER CODE BEGIN Prototypes */ +/** Init file system driver */ +void fatfs_init(void); -/* USER CODE END Prototypes */ #ifdef __cplusplus } #endif -#endif /*__fatfs_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/fatfs/ffconf.h b/firmware/targets/f7/fatfs/ffconf.h index 9410cedc86..a44521550d 100644 --- a/firmware/targets/f7/fatfs/ffconf.h +++ b/firmware/targets/f7/fatfs/ffconf.h @@ -164,7 +164,7 @@ /* USER CODE BEGIN Volumes */ #define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */ -#define _VOLUME_STRS "RAM", "NAND", "CF", "SD1", "SD2", "USB1", "USB2", "USB3" +#define _VOLUME_STRS "SD" /* _STR_VOLUME_ID switches string support of volume ID. / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each diff --git a/firmware/targets/f7/fatfs/syscall.c b/firmware/targets/f7/fatfs/syscall.c deleted file mode 100644 index 00eb8aedea..0000000000 --- a/firmware/targets/f7/fatfs/syscall.c +++ /dev/null @@ -1,116 +0,0 @@ -/*------------------------------------------------------------------------*/ -/* Sample code of OS dependent controls for FatFs */ -/* (C)ChaN, 2014 */ -/* Portions COPYRIGHT 2017 STMicroelectronics */ -/* Portions Copyright (C) 2014, ChaN, all right reserved */ -/*------------------------------------------------------------------------*/ - -/** - ****************************************************************************** - * @attention - * - * Copyright (c) 2017 STMicroelectronics. All rights reserved. - * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** -**/ - -#include "fatfs/ff.h" - -#if _FS_REENTRANT -/*------------------------------------------------------------------------*/ -/* Create a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to create a new -/ synchronization object, such as semaphore and mutex. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_cre_syncobj(/* 1:Function succeeded, 0:Could not create the sync object */ - BYTE vol, /* Corresponding volume (logical drive number) */ - _SYNC_t* sobj /* Pointer to return the created sync object */ -) { - int ret; - - //osSemaphoreDef(SEM); - //*sobj = osSemaphoreCreate(osSemaphore(SEM), 1); - *sobj = furi_mutex_alloc(FuriMutexTypeNormal); - ret = (*sobj != NULL); - - return ret; -} - -/*------------------------------------------------------------------------*/ -/* Delete a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to delete a synchronization -/ object that created with ff_cre_syncobj() function. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_del_syncobj(/* 1:Function succeeded, 0:Could not delete due to any error */ - _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ -) { - furi_mutex_free(sobj); - return 1; -} - -/*------------------------------------------------------------------------*/ -/* Request Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on entering file functions to lock the volume. -/ When a 0 is returned, the file function fails with FR_TIMEOUT. -*/ - -int ff_req_grant(/* 1:Got a grant to access the volume, 0:Could not get a grant */ - _SYNC_t sobj /* Sync object to wait */ -) { - int ret = 0; - - if(furi_mutex_acquire(sobj, _FS_TIMEOUT) == FuriStatusOk) { - ret = 1; - } - - return ret; -} - -/*------------------------------------------------------------------------*/ -/* Release Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on leaving file functions to unlock the volume. -*/ - -void ff_rel_grant(_SYNC_t sobj /* Sync object to be signaled */ -) { - furi_mutex_release(sobj); -} - -#endif - -#if _USE_LFN == 3 /* LFN with a working buffer on the heap */ -/*------------------------------------------------------------------------*/ -/* Allocate a memory block */ -/*------------------------------------------------------------------------*/ -/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. -*/ - -void* ff_memalloc(/* Returns pointer to the allocated memory block */ - UINT msize /* Number of bytes to allocate */ -) { - return ff_malloc(msize); /* Allocate a new memory block with POSIX API */ -} - -/*------------------------------------------------------------------------*/ -/* Free a memory block */ -/*------------------------------------------------------------------------*/ - -void ff_memfree(void* mblock /* Pointer to the memory block to free */ -) { - ff_free(mblock); /* Discard the memory block with POSIX API */ -} - -#endif diff --git a/firmware/targets/f7/fatfs/user_diskio.c b/firmware/targets/f7/fatfs/user_diskio.c index d7be09c531..b1250fcc20 100644 --- a/firmware/targets/f7/fatfs/user_diskio.c +++ b/firmware/targets/f7/fatfs/user_diskio.c @@ -1,4 +1,3 @@ -/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file user_diskio.c @@ -16,35 +15,14 @@ * ****************************************************************************** */ -/* USER CODE END Header */ - -#ifdef USE_OBSOLETE_USER_CODE_SECTION_0 -/* - * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0) - * To be suppressed in the future. - * Kept to ensure backward compatibility with previous CubeMx versions when - * migrating projects. - * User code previously added there should be copied in the new user sections before - * the section contents can be deleted. - */ -/* USER CODE BEGIN 0 */ -/* USER CODE END 0 */ -#endif - -/* USER CODE BEGIN DECL */ -/* Includes ------------------------------------------------------------------*/ #include "user_diskio.h" #include #include "sector_cache.h" -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Disk status */ static volatile DSTATUS Stat = STA_NOINIT; -static DSTATUS User_CheckStatus(BYTE lun) { +static DSTATUS driver_check_status(BYTE lun) { UNUSED(lun); Stat = STA_NOINIT; if(sd_get_card_state() == SdSpiStatusOK) { @@ -54,32 +32,20 @@ static DSTATUS User_CheckStatus(BYTE lun) { return Stat; } -/* USER CODE END DECL */ - -/* Private function prototypes -----------------------------------------------*/ -DSTATUS USER_initialize(BYTE pdrv); -DSTATUS USER_status(BYTE pdrv); -DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count); -#if _USE_WRITE == 1 -DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); -#endif /* _USE_WRITE == 1 */ -#if _USE_IOCTL == 1 -DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff); -#endif /* _USE_IOCTL == 1 */ - -Diskio_drvTypeDef USER_Driver = { - USER_initialize, - USER_status, - USER_read, -#if _USE_WRITE - USER_write, -#endif /* _USE_WRITE == 1 */ -#if _USE_IOCTL == 1 - USER_ioctl, -#endif /* _USE_IOCTL == 1 */ +static DSTATUS driver_initialize(BYTE pdrv); +static DSTATUS driver_status(BYTE pdrv); +static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff); + +Diskio_drvTypeDef sd_fatfs_driver = { + driver_initialize, + driver_status, + driver_read, + driver_write, + driver_ioctl, }; -/* Private functions ---------------------------------------------------------*/ static inline bool sd_cache_get(uint32_t address, uint32_t* data) { uint8_t* cached_data = sector_cache_get(address); if(cached_data) { @@ -101,24 +67,73 @@ static inline void sd_cache_invalidate_all() { sector_cache_init(); } +static bool sd_device_read(uint32_t* buff, uint32_t sector, uint32_t count) { + bool result = false; + + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); + furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; + + if(sd_read_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) { + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000); + + /* wait until the read operation is finished */ + result = true; + while(sd_get_card_state() != SdSpiStatusOK) { + if(furi_hal_cortex_timer_is_expired(timer)) { + result = false; + break; + } + } + } + + furi_hal_sd_spi_handle = NULL; + furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); + + return result; +} + +static bool sd_device_write(uint32_t* buff, uint32_t sector, uint32_t count) { + bool result = false; + + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); + furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; + + if(sd_write_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) { + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000); + + /* wait until the Write operation is finished */ + result = true; + while(sd_get_card_state() != SdSpiStatusOK) { + if(furi_hal_cortex_timer_is_expired(timer)) { + sd_cache_invalidate_all(); + + result = false; + break; + } + } + } + + furi_hal_sd_spi_handle = NULL; + furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); + + return result; +} + /** * @brief Initializes a Drive * @param pdrv: Physical drive number (0..) * @retval DSTATUS: Operation status */ -DSTATUS USER_initialize(BYTE pdrv) { - /* USER CODE BEGIN INIT */ - +static DSTATUS driver_initialize(BYTE pdrv) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; - DSTATUS status = User_CheckStatus(pdrv); + DSTATUS status = driver_check_status(pdrv); furi_hal_sd_spi_handle = NULL; furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); return status; - /* USER CODE END INIT */ } /** @@ -126,11 +141,9 @@ DSTATUS USER_initialize(BYTE pdrv) { * @param pdrv: Physical drive number (0..) * @retval DSTATUS: Operation status */ -DSTATUS USER_status(BYTE pdrv) { - /* USER CODE BEGIN STATUS */ +static DSTATUS driver_status(BYTE pdrv) { UNUSED(pdrv); return Stat; - /* USER CODE END STATUS */ } /** @@ -141,11 +154,10 @@ DSTATUS USER_status(BYTE pdrv) { * @param count: Number of sectors to read (1..128) * @retval DRESULT: Operation result */ -DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { - /* USER CODE BEGIN READ */ +static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { UNUSED(pdrv); - DRESULT res = RES_ERROR; + bool result; bool single_sector = count == 1; if(single_sector) { @@ -154,32 +166,33 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { } } - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); - furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; + result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count); - if(sd_read_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) == - SdSpiStatusOK) { - FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000); + if(!result) { + uint8_t counter = sd_max_mount_retry_count(); - /* wait until the read operation is finished */ - res = RES_OK; - while(sd_get_card_state() != SdSpiStatusOK) { - if(furi_hal_cortex_timer_is_expired(timer)) { - res = RES_ERROR; - break; + while(result == false && counter > 0 && hal_sd_detect()) { + SdSpiStatus status; + + if((counter % 2) == 0) { + // power reset sd card + status = sd_init(true); + } else { + status = sd_init(false); } + + if(status == SdSpiStatusOK) { + result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count); + } + counter--; } } - furi_hal_sd_spi_handle = NULL; - furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); - - if(single_sector && res == RES_OK) { + if(single_sector && result == true) { sd_cache_put(sector, (uint32_t*)buff); } - return res; - /* USER CODE END READ */ + return result ? RES_OK : RES_ERROR; } /** @@ -190,41 +203,36 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { * @param count: Number of sectors to write (1..128) * @retval DRESULT: Operation result */ -#if _USE_WRITE == 1 -DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { - /* USER CODE BEGIN WRITE */ - /* USER CODE HERE */ +static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { UNUSED(pdrv); - DRESULT res = RES_ERROR; + bool result; sd_cache_invalidate_range(sector, sector + count); - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); - furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; + result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count); - if(sd_write_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) == - SdSpiStatusOK) { - FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000); + if(!result) { + uint8_t counter = sd_max_mount_retry_count(); - /* wait until the Write operation is finished */ - res = RES_OK; - while(sd_get_card_state() != SdSpiStatusOK) { - if(furi_hal_cortex_timer_is_expired(timer)) { - sd_cache_invalidate_all(); + while(result == false && counter > 0 && hal_sd_detect()) { + SdSpiStatus status; - res = RES_ERROR; - break; + if((counter % 2) == 0) { + // power reset sd card + status = sd_init(true); + } else { + status = sd_init(false); + } + + if(status == SdSpiStatusOK) { + result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count); } + counter--; } } - furi_hal_sd_spi_handle = NULL; - furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); - - return res; - /* USER CODE END WRITE */ + return result ? RES_OK : RES_ERROR; } -#endif /* _USE_WRITE == 1 */ /** * @brief I/O control operation @@ -233,9 +241,7 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { * @param *buff: Buffer to send/receive control data * @retval DRESULT: Operation result */ -#if _USE_IOCTL == 1 -DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) { - /* USER CODE BEGIN IOCTL */ +static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) { UNUSED(pdrv); DRESULT res = RES_ERROR; SD_CardInfo CardInfo; @@ -280,8 +286,6 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) { furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); return res; - /* USER CODE END IOCTL */ } -#endif /* _USE_IOCTL == 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/fatfs/user_diskio.h b/firmware/targets/f7/fatfs/user_diskio.h index 12e0f27dc6..1aa50e7c4f 100644 --- a/firmware/targets/f7/fatfs/user_diskio.h +++ b/firmware/targets/f7/fatfs/user_diskio.h @@ -1,4 +1,3 @@ -/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file user_diskio.h @@ -17,32 +16,18 @@ * ****************************************************************************** */ -/* USER CODE END Header */ -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USER_DISKIO_H -#define __USER_DISKIO_H +#pragma once #ifdef __cplusplus extern "C" { #endif -/* USER CODE BEGIN 0 */ - -/* Includes ------------------------------------------------------------------*/ #include "sd_spi_io.h" #include "fatfs/ff_gen_drv.h" -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -extern Diskio_drvTypeDef USER_Driver; -/* USER CODE END 0 */ +extern Diskio_drvTypeDef sd_fatfs_driver; #ifdef __cplusplus } -#endif - -#endif /* __USER_DISKIO_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index a887de5cd8..bc06a4ab11 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -82,7 +82,7 @@ void furi_hal_init() { #endif // FatFS driver initialization - MX_FATFS_Init(); + fatfs_init(); FURI_LOG_I(TAG, "FATFS OK"); } diff --git a/firmware/targets/f7/src/update.c b/firmware/targets/f7/src/update.c index d8d26eb7ce..c1e1084c21 100644 --- a/firmware/targets/f7/src/update.c +++ b/firmware/targets/f7/src/update.c @@ -44,7 +44,7 @@ static bool flipper_update_init() { furi_hal_spi_config_init(); - MX_FATFS_Init(); + fatfs_init(); if(!hal_sd_detect()) { return false; } From 147a1c7aaa40d1c79f1e42ee52e4d9bba169e535 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 18 Mar 2023 03:36:56 +0300 Subject: [PATCH 6/9] iButton: Add DS1420 / Update changelog --- CHANGELOG.md | 4 + .../protocols/dallas/protocol_ds1420.c | 144 ++++++++++++++++++ .../protocols/dallas/protocol_ds1420.h | 5 + .../dallas/protocol_group_dallas_defs.c | 2 + .../dallas/protocol_group_dallas_defs.h | 1 + 5 files changed, 156 insertions(+) create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e88bc878d..41f89f0f81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ### New changes +* iButton: Add support for DS1420 (not fully tested) * Desktop: Option to set Tertiary favourite app (Hold right arrow on desktop) - **Desktop settings (pin code, favourite app, autolock time) will be resetted!!! Only one time after installing - due to changes in settings structure, after installing of this release desktop settings will not be reset with next release** +* Desktop: Fix issue #387 (Ok button was showing invalid file error in dummy mode) +* OFW PR: SD Driver: reinit sd card on error (by DrZlo13 | OFW PR 2493) +* OFW PR: iButton -> Fix a typo: use right shift instead of greater than (by gsurkov | OFW PR 2506) * OFW: Optimize trailing slash check #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.c b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.c new file mode 100644 index 0000000000..ebfb700ce4 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.c @@ -0,0 +1,144 @@ +#include "protocol_ds1420.h" + +#include +#include + +#include "dallas_common.h" + +#include "../blanks/rw1990.h" +#include "../blanks/tm2004.h" + +#define DS1420_FAMILY_CODE 0x81U +#define DS1420_FAMILY_NAME "DS1420" + +#define DS1420_CMD_READ_ROM 0x0FU + +typedef struct { + OneWireSlave* bus; +} DS1420ProtocolState; + +typedef struct { + DallasCommonRomData rom_data; + DS1420ProtocolState state; +} DS1420ProtocolData; + +static bool dallas_ds1420_read(OneWireHost*, iButtonProtocolData*); +static bool dallas_ds1420_write_blank(OneWireHost*, iButtonProtocolData*); +static void dallas_ds1420_emulate(OneWireSlave*, iButtonProtocolData*); +static bool dallas_ds1420_load(FlipperFormat*, uint32_t, iButtonProtocolData*); +static bool dallas_ds1420_save(FlipperFormat*, const iButtonProtocolData*); +static void dallas_ds1420_render_brief_data(FuriString*, const iButtonProtocolData*); +static void dallas_ds1420_render_error(FuriString*, const iButtonProtocolData*); +static bool dallas_ds1420_is_data_valid(const iButtonProtocolData*); +static void dallas_ds1420_get_editable_data(iButtonEditableData*, iButtonProtocolData*); +static void dallas_ds1420_apply_edits(iButtonProtocolData*); + +const iButtonProtocolDallasBase ibutton_protocol_ds1420 = { + .family_code = DS1420_FAMILY_CODE, + .features = iButtonProtocolFeatureWriteBlank, + .data_size = sizeof(DS1420ProtocolData), + .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, + .name = DS1420_FAMILY_NAME, + + .read = dallas_ds1420_read, + .write_blank = dallas_ds1420_write_blank, + .write_copy = NULL, /* No data to write a copy */ + .emulate = dallas_ds1420_emulate, + .save = dallas_ds1420_save, + .load = dallas_ds1420_load, + .render_data = NULL, /* No data to render */ + .render_brief_data = dallas_ds1420_render_brief_data, + .render_error = dallas_ds1420_render_error, + .is_valid = dallas_ds1420_is_data_valid, + .get_editable_data = dallas_ds1420_get_editable_data, + .apply_edits = dallas_ds1420_apply_edits, +}; + +bool dallas_ds1420_read(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1420ProtocolData* data = protocol_data; + return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data); +} + +bool dallas_ds1420_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1420ProtocolData* data = protocol_data; + + return rw1990_write_v1(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) || + rw1990_write_v2(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) || + tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); +} + +static bool dallas_ds1420_command_callback(uint8_t command, void* context) { + furi_assert(context); + DS1420ProtocolData* data = context; + OneWireSlave* bus = data->state.bus; + + switch(command) { + case DALLAS_COMMON_CMD_SEARCH_ROM: + dallas_common_emulate_search_rom(bus, &data->rom_data); + break; + case DALLAS_COMMON_CMD_READ_ROM: + case DS1420_CMD_READ_ROM: + dallas_common_emulate_read_rom(bus, &data->rom_data); + break; + default: + break; + } + + // No support for multiple consecutive commands + return false; +} + +void dallas_ds1420_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { + DS1420ProtocolData* data = protocol_data; + data->state.bus = bus; + + onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_command_callback(bus, dallas_ds1420_command_callback, protocol_data); +} + +bool dallas_ds1420_save(FlipperFormat* ff, const iButtonProtocolData* protocol_data) { + const DS1420ProtocolData* data = protocol_data; + return dallas_common_save_rom_data(ff, &data->rom_data); +} + +bool dallas_ds1420_load( + FlipperFormat* ff, + uint32_t format_version, + iButtonProtocolData* protocol_data) { + DS1420ProtocolData* data = protocol_data; + return dallas_common_load_rom_data(ff, format_version, &data->rom_data); +} + +void dallas_ds1420_render_brief_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1420ProtocolData* data = protocol_data; + + for(size_t i = 0; i < sizeof(DallasCommonRomData); ++i) { + furi_string_cat_printf(result, "%02X ", data->rom_data.bytes[i]); + } +} + +void dallas_ds1420_render_error(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1420ProtocolData* data = protocol_data; + + if(!dallas_common_is_valid_crc(&data->rom_data)) { + dallas_common_render_crc_error(result, &data->rom_data); + } +} + +bool dallas_ds1420_is_data_valid(const iButtonProtocolData* protocol_data) { + const DS1420ProtocolData* data = protocol_data; + return dallas_common_is_valid_crc(&data->rom_data); +} + +void dallas_ds1420_get_editable_data( + iButtonEditableData* editable_data, + iButtonProtocolData* protocol_data) { + DS1420ProtocolData* data = protocol_data; + editable_data->ptr = data->rom_data.bytes; + editable_data->size = sizeof(DallasCommonRomData); +} + +void dallas_ds1420_apply_edits(iButtonProtocolData* protocol_data) { + DS1420ProtocolData* data = protocol_data; + dallas_common_apply_edits(&data->rom_data, DS1420_FAMILY_CODE); +} diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.h b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.h new file mode 100644 index 0000000000..63c239738d --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1420.h @@ -0,0 +1,5 @@ +#pragma once + +#include "protocol_dallas_base.h" + +extern const iButtonProtocolDallasBase ibutton_protocol_ds1420; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c index b4dd51ce71..a33db51439 100644 --- a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c @@ -4,6 +4,7 @@ #include "protocol_ds1992.h" #include "protocol_ds1996.h" #include "protocol_ds1971.h" +#include "protocol_ds1420.h" #include "protocol_ds_generic.h" const iButtonProtocolDallasBase* ibutton_protocols_dallas[] = { @@ -11,6 +12,7 @@ const iButtonProtocolDallasBase* ibutton_protocols_dallas[] = { [iButtonProtocolDS1992] = &ibutton_protocol_ds1992, [iButtonProtocolDS1996] = &ibutton_protocol_ds1996, [iButtonProtocolDS1971] = &ibutton_protocol_ds1971, + [iButtonProtocolDS1420] = &ibutton_protocol_ds1420, /* Add new 1-Wire protocols here */ /* Default catch-all 1-Wire protocol */ diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h index 2ba1dd39ac..ca789a10c4 100644 --- a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h @@ -7,6 +7,7 @@ typedef enum { iButtonProtocolDS1992, iButtonProtocolDS1996, iButtonProtocolDS1971, + iButtonProtocolDS1420, /* Add new 1-Wire protocols here */ /* Default catch-all 1-Wire protocol */ From 9a93551a2dc620b06c0c715a6d07a312393d993c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:13:04 +0300 Subject: [PATCH 7/9] Add ability to disable favourite app in desktop settings And update changelog --- CHANGELOG.md | 1 + .../scenes/desktop_settings_scene_favorite.c | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f89f0f81..049af9b5c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### New changes * iButton: Add support for DS1420 (not fully tested) * Desktop: Option to set Tertiary favourite app (Hold right arrow on desktop) - **Desktop settings (pin code, favourite app, autolock time) will be resetted!!! Only one time after installing - due to changes in settings structure, after installing of this release desktop settings will not be reset with next release** +* Desktop: Ability to disable favourite app (use last element in a main list `None (disable)`) * Desktop: Fix issue #387 (Ok button was showing invalid file error in dummy mode) * OFW PR: SD Driver: reinit sd card on error (by DrZlo13 | OFW PR 2493) * OFW PR: iButton -> Fix a typo: use right shift instead of greater than (by gsurkov | OFW PR 2506) diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 822c6c7a9a..c014c97f78 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -73,6 +73,12 @@ void desktop_settings_scene_favorite_on_enter(void* context) { } } } + submenu_add_item( + submenu, + "None (disable)", + FLIPPER_APPS_COUNT + 1, + desktop_settings_scene_favorite_submenu_callback, + app); if(primary_favorite == 0) { submenu_set_header(submenu, "Primary favorite app:"); @@ -95,6 +101,23 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); if(event.type == SceneManagerEventTypeCustom) { + if(event.event >= (FLIPPER_APPS_COUNT + 1)) { + if(primary_favorite == 0) { + app->settings.favorite_primary.is_external = false; + strncpy(app->settings.favorite_primary.name_or_path, "", MAX_APP_LENGTH); + } else if(primary_favorite == 1) { + app->settings.favorite_secondary.is_external = false; + strncpy(app->settings.favorite_secondary.name_or_path, "", MAX_APP_LENGTH); + } else if(primary_favorite == 2) { + app->settings.favorite_tertiary.is_external = false; + strncpy(app->settings.favorite_tertiary.name_or_path, "", MAX_APP_LENGTH); + } + + scene_manager_previous_scene(app->scene_manager); + consumed = true; + furi_string_free(temp_path); + return consumed; + } if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME) != 0) { if(primary_favorite == 0) { app->settings.favorite_primary.is_external = false; From 682ac85e0a3d355a656761a5d86dbfccf3a22a7b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 18 Mar 2023 04:19:53 +0300 Subject: [PATCH 8/9] Update docs --- documentation/file_formats/iButtonFileFormat.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/file_formats/iButtonFileFormat.md b/documentation/file_formats/iButtonFileFormat.md index 63743f0637..225072629f 100644 --- a/documentation/file_formats/iButtonFileFormat.md +++ b/documentation/file_formats/iButtonFileFormat.md @@ -26,7 +26,7 @@ Changelog: | Name | Type | Description | | ----------- | ------ | -------------------------------------------- | -| Protocol | string | Currently supported: DS1990, DS1992, DS1996, DS1971, DSGeneric*, Cyfral, Metakom | +| Protocol | string | Currently supported: DS1990, DS1992, DS1996, DS1971, DS1420, DSGeneric, Cyfral, Metakom | | Rom Data | hex | Read-only memory data (Dallas protocols only) | | Sram Data | hex | Static RAM data (DS1992 and DS1996 only) | Eeprom Data | hex | EEPROM data (DS1971 only) @@ -37,6 +37,8 @@ It can also be used if a key with a deliberately invalid family code or checksum NOTE 2: When adding new protocols, it is not necessarily to increase the format version, define the format in the protocol implementation instead. +**DS1420 is fully compatible with DS1990, only difference is a familiy code 0x01 for DS1990 and 0x81 for DS1420** + ### 1. Initial version. Deprecated, will be converted to current version upon saving. From 9e94b1fae080ef005cf4d57dc4d3cf0f376f729f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 18 Mar 2023 06:05:22 +0300 Subject: [PATCH 9/9] Testing links --- .drone.yml | 10 ++++++++-- CHANGELOG.md | 2 +- ReadMe.md | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.drone.yml b/.drone.yml index 06881b1ab3..9f8991c665 100644 --- a/.drone.yml +++ b/.drone.yml @@ -192,6 +192,9 @@ steps: Version: {{build.tag}} + [-> Sponsor our project](https://boosty.to/mmxdev) + + [-Github - Changelog-](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG}) @@ -220,7 +223,7 @@ steps: commands: - wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh" - chmod +x ./discord.sh - - ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' + - ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' - name: "Send extra pack build to telegram" image: appleboy/drone-telegram @@ -385,6 +388,9 @@ steps: Commit: {{commit.message}} + [-> Sponsor our project](https://boosty.to/mmxdev) + + [-Version with extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER}e) @@ -413,7 +419,7 @@ steps: commands: - wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh" - chmod +x ./discord.sh - - ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nSHA - '${DRONE_COMMIT_SHA}'\n\n[-Version with extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')' + - ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nSHA - '${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')' trigger: branch: diff --git a/CHANGELOG.md b/CHANGELOG.md index 049af9b5c5..c373d4b3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ [-> Download qFlipper (official link)](https://flipperzero.one/update) ## Please support development of the project -* Boosty: https://boosty.to/mmxdev +* **Boosty** (patreon alternative): https://boosty.to/mmxdev * Ko-Fi: https://ko-fi.com/masterx * cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65 * YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209 diff --git a/ReadMe.md b/ReadMe.md index 8c1a57142b..12cca67153 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -111,7 +111,7 @@ Our team is small and the guys are working on this project as much as they can s The amount of work done on this project is huge and we need your support, no matter how large or small. Even if you just say, "Thank you Unleashed firmware developers!" somewhere. Doing so will help us continue our work and will help drive us to make the firmware better every time. Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen. You can support us by using links or addresses below: -* Boosty: https://boosty.to/mmxdev +* **Boosty** (patreon alternative): https://boosty.to/mmxdev * Ko-Fi: https://ko-fi.com/masterx * cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65 * YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209