From 28272f7a7a472540543eafa690a0dc8621500edc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:18:51 +0300 Subject: [PATCH] Storage: remove LFS (#3577) * Storage: drop internal storage * Storage: rollback some unnecessary changes * Storage: rollback some unnecessary changes part 2 * Storage: cleanup various defines and int handling. Ble: allow short connection interval if internal flash is not used. * Storage: do not return storage if it is not ready * Save PIN code to RTC, update settings * Simplify the code, clean up includes * Rearrange some code * apps: storage_move_to_sd: conditionally enable with --extra-define=STORAGE_INT_ON_LFS * Load Desktop settings automatically * Redirect /any to /ext * Abolish storage_move_to_sd app * Remove as many mentions of ANY_PATH as possible * Fix desktop settings wrongly not loading * Improve desktop settings handling and strings * Load BLE settings and keys automatically * Improve BLE configuration procedure * Do not load bluetooth keys twice if they were already loaded * Load dolphin state automatically * Fix merge artifact * Load notification settings automatically * Update desktop settings strings * Load expansion settings automatically * Do not use thread signals to reload desktop settings * Load region data automatically, separate to its own hook * Improve ble behaviour with no keys * Fix Dolphin state not resetting correctly * Add a status check * Make Desktop save its own settings * Check result when taking and releasing mutex * Improve default thread signal handling in FuriEventLoop * Make bt service in charge of saving settings, add settings api * Fix a deadlock due to timer thread not receiving time * Lock core2 when reinitialising bt * Update clang-format * Revert "Update clang-format" This reverts commit d61295ac063c6ec879375ceeab54d6ff2c90a9a1. * Format sources with clang-format * Revert old stack size for desktop settings * Allocate big struct dynamically * Simplify PIN comparison * Save pointer to storage in Desktop object * Fix region provisioning for hardware regions * Remove stale TODO + siimplify code * Clean up region.c * Use sizeof instead of macro define * Limit PIN length to 10 for consistency * Emit a warning upon usage of /any * Add delay after finding flipper * Remove unnecessary delay * Remove all mentions of STORAGE_INT_ON_LFS * Remove littlefs and internal storage * Remove all possible LittleFS mentions * Fix browser tab in Archive * Ble: fix connection interval explanation * Bump API Symbols * BLE: Update comments interval connection comments * Storage: clear FuriHalRtcFlagStorageFormatInternal if set --------- Co-authored-by: Georgii Surkov Co-authored-by: hedger Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> --- .gitmodules | 3 - .pvsoptions | 2 +- .../scenes/file_browser_scene_start.c | 2 +- .../main/archive/helpers/archive_apps.c | 8 +- .../main/archive/helpers/archive_browser.c | 12 +- .../main/archive/helpers/archive_favorites.h | 4 +- applications/main/ibutton/ibutton_i.h | 2 +- applications/main/infrared/infrared_app_i.h | 2 +- applications/main/lfrfid/lfrfid_i.h | 2 +- applications/main/nfc/helpers/mf_user_dict.c | 2 +- applications/main/nfc/nfc_app_i.h | 2 +- applications/main/subghz/subghz_cli.c | 2 +- applications/main/u2f/u2f.c | 7 +- applications/services/bt/bt_service/bt.c | 134 +++- applications/services/bt/bt_service/bt_api.c | 36 + applications/services/bt/bt_service/bt_i.h | 5 + .../services/bt/bt_service/bt_keys_storage.c | 107 ++- .../services/bt/bt_service/bt_keys_storage.h | 2 + .../bt/bt_service/bt_settings_api_i.h | 8 + applications/services/bt/bt_settings.c | 23 +- applications/services/bt/bt_settings.h | 7 +- .../desktop/animations/animation_manager.c | 7 +- applications/services/desktop/desktop.c | 319 ++++---- applications/services/desktop/desktop.h | 14 +- applications/services/desktop/desktop_i.h | 31 +- .../services/desktop/desktop_settings.c | 79 ++ .../services/desktop/desktop_settings.h | 19 +- applications/services/desktop/helpers/pin.c | 72 -- applications/services/desktop/helpers/pin.h | 11 - .../services/desktop/helpers/pin_code.c | 103 +++ .../services/desktop/helpers/pin_code.h | 25 + .../services/desktop/scenes/desktop_scene_i.h | 4 - .../desktop/scenes/desktop_scene_lock_menu.c | 8 +- .../desktop/scenes/desktop_scene_locked.c | 12 +- .../desktop/scenes/desktop_scene_locked.h | 6 + .../desktop/scenes/desktop_scene_main.c | 5 - .../desktop/scenes/desktop_scene_pin_input.c | 8 +- .../desktop/scenes/desktop_scene_slideshow.c | 7 +- .../services/desktop/views/desktop_events.h | 2 + .../desktop/views/desktop_view_pin_input.c | 18 +- .../desktop/views/desktop_view_pin_input.h | 7 +- applications/services/dolphin/dolphin.c | 33 +- applications/services/dolphin/dolphin_i.h | 1 + .../services/dolphin/helpers/dolphin_state.c | 28 +- .../services/dolphin/helpers/dolphin_state.h | 8 +- applications/services/expansion/expansion.c | 60 +- .../services/expansion/expansion_settings.c | 39 +- .../services/expansion/expansion_settings.h | 8 +- .../gui/modules/file_browser_worker.c | 2 +- .../services/notification/notification_app.c | 53 +- .../services/notification/notification_app.h | 1 + applications/services/region/application.fam | 10 + applications/services/region/region.c | 147 ++++ applications/services/storage/storage.c | 9 +- applications/services/storage/storage.h | 4 +- applications/services/storage/storage_cli.c | 2 +- .../services/storage/storage_internal_api.c | 2 +- .../services/storage/storage_processing.c | 47 +- .../services/storage/storages/storage_int.c | 744 ------------------ .../services/storage/storages/storage_int.h | 13 - .../bt_settings_app/bt_settings_app.c | 6 +- .../bt_settings_app/bt_settings_app.h | 9 +- .../scenes/bt_settings_scene_start.c | 3 +- .../desktop_settings/desktop_settings_app.c | 22 +- .../desktop_settings/desktop_settings_app.h | 2 +- .../scenes/desktop_settings_scene_favorite.c | 10 +- .../scenes/desktop_settings_scene_pin_auth.c | 14 +- .../desktop_settings_scene_pin_disable.c | 5 +- .../scenes/desktop_settings_scene_pin_error.c | 4 +- .../scenes/desktop_settings_scene_pin_menu.c | 2 +- .../scenes/desktop_settings_scene_pin_setup.c | 6 +- .../desktop_settings_scene_pin_setup_done.c | 8 +- .../expansion_settings_app.c | 2 + .../storage_settings_scene_internal_info.c | 2 +- applications/system/application.fam | 1 - .../system/storage_move_to_sd/application.fam | 18 - .../scenes/storage_move_to_sd_scene.c | 30 - .../scenes/storage_move_to_sd_scene.h | 29 - .../scenes/storage_move_to_sd_scene_config.h | 2 - .../scenes/storage_move_to_sd_scene_confirm.c | 70 -- .../storage_move_to_sd_scene_progress.c | 31 - .../storage_move_to_sd/storage_move_to_sd.c | 203 ----- .../storage_move_to_sd/storage_move_to_sd.h | 48 -- .../system/updater/util/update_task.c | 1 - .../updater/util/update_task_worker_flasher.c | 1 - documentation/Doxyfile | 1 - furi/core/event_loop.c | 14 +- furi/core/thread.c | 6 + furi/core/thread.h | 10 +- lib/ReadMe.md | 1 - lib/SConscript | 1 - lib/ble_profile/extra_profiles/hid_profile.c | 10 +- lib/lfs_config.h | 204 ----- lib/littlefs | 1 - lib/littlefs.scons | 22 - lib/subghz/devices/registry.c | 4 +- lib/toolbox/crc32_calc.c | 32 +- lib/toolbox/stream/file_stream.c | 4 +- lib/toolbox/tar/tar_archive.c | 4 +- lib/toolbox/tar/tar_archive.h | 4 +- scripts/testops.py | 2 + targets/f18/api_symbols.csv | 10 +- targets/f18/target.json | 1 - targets/f7/api_symbols.csv | 10 +- targets/f7/ble_glue/extra_beacon.c | 6 +- targets/f7/ble_glue/hw_ipcc.c | 4 +- targets/f7/ble_glue/profiles/serial_profile.c | 10 +- targets/f7/furi_hal/furi_hal_bt.c | 11 +- targets/f7/furi_hal/furi_hal_crypto.c | 58 +- targets/f7/furi_hal/furi_hal_region.c | 7 +- targets/f7/furi_hal/furi_hal_rtc.c | 8 + targets/f7/furi_hal/furi_hal_rtc.h | 22 +- targets/f7/target.json | 1 - targets/furi_hal_include/furi_hal_region.h | 1 - 114 files changed, 1353 insertions(+), 1985 deletions(-) create mode 100644 applications/services/bt/bt_service/bt_settings_api_i.h create mode 100644 applications/services/desktop/desktop_settings.c delete mode 100644 applications/services/desktop/helpers/pin.c delete mode 100644 applications/services/desktop/helpers/pin.h create mode 100644 applications/services/desktop/helpers/pin_code.c create mode 100644 applications/services/desktop/helpers/pin_code.h delete mode 100644 applications/services/desktop/scenes/desktop_scene_i.h create mode 100644 applications/services/desktop/scenes/desktop_scene_locked.h create mode 100644 applications/services/region/application.fam create mode 100644 applications/services/region/region.c delete mode 100644 applications/services/storage/storages/storage_int.c delete mode 100644 applications/services/storage/storages/storage_int.h delete mode 100644 applications/system/storage_move_to_sd/application.fam delete mode 100644 applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c delete mode 100644 applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h delete mode 100644 applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h delete mode 100644 applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c delete mode 100644 applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c delete mode 100644 applications/system/storage_move_to_sd/storage_move_to_sd.c delete mode 100644 applications/system/storage_move_to_sd/storage_move_to_sd.h delete mode 100644 lib/lfs_config.h delete mode 160000 lib/littlefs delete mode 100644 lib/littlefs.scons diff --git a/.gitmodules b/.gitmodules index df5bf648f..c9373c093 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/mlib"] path = lib/mlib url = https://github.com/P-p-H-d/mlib.git -[submodule "lib/littlefs"] - path = lib/littlefs - url = https://github.com/littlefs-project/littlefs.git [submodule "lib/nanopb"] path = lib/nanopb url = https://github.com/nanopb/nanopb.git diff --git a/.pvsoptions b/.pvsoptions index 8606eef15..4040dcb91 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/* +--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/* diff --git a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c index 9eb26944f..0ff6303bf 100644 --- a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c +++ b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c @@ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt")); + furi_string_set(app->file_path, EXT_PATH("badusb/demo_windows.txt")); scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser); consumed = true; } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/main/archive/helpers/archive_apps.c b/applications/main/archive/helpers/archive_apps.c index 43befc055..7aca29364 100644 --- a/applications/main/archive/helpers/archive_apps.c +++ b/applications/main/archive/helpers/archive_apps.c @@ -30,8 +30,8 @@ bool archive_app_is_available(void* context, const char* path) { bool file_exists = false; Storage* storage = furi_record_open(RECORD_STORAGE); - if(storage_file_exists(storage, ANY_PATH("u2f/key.u2f"))) { - file_exists = storage_file_exists(storage, ANY_PATH("u2f/cnt.u2f")); + if(storage_file_exists(storage, EXT_PATH("u2f/key.u2f"))) { + file_exists = storage_file_exists(storage, EXT_PATH("u2f/cnt.u2f")); } furi_record_close(RECORD_STORAGE); @@ -68,8 +68,8 @@ void archive_app_delete_file(void* context, const char* path) { if(app == ArchiveAppTypeU2f) { Storage* fs_api = furi_record_open(RECORD_STORAGE); - res = (storage_common_remove(fs_api, ANY_PATH("u2f/key.u2f")) == FSE_OK); - res |= (storage_common_remove(fs_api, ANY_PATH("u2f/cnt.u2f")) == FSE_OK); + res = (storage_common_remove(fs_api, EXT_PATH("u2f/key.u2f")) == FSE_OK); + res |= (storage_common_remove(fs_api, EXT_PATH("u2f/cnt.u2f")) == FSE_OK); furi_record_close(RECORD_STORAGE); if(archive_is_favorite("/app:u2f/U2F Token")) { diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index bd9b00745..96518cd7a 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -450,16 +450,14 @@ void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { } static bool archive_is_dir_exists(FuriString* path) { - if(furi_string_equal(path, STORAGE_ANY_PATH_PREFIX)) { - return true; - } bool state = false; FileInfo file_info; Storage* storage = furi_record_open(RECORD_STORAGE); - if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { - if(file_info_is_dir(&file_info)) { - state = true; - } + + if(furi_string_equal(path, STORAGE_EXT_PATH_PREFIX)) { + state = storage_sd_status(storage) == FSE_OK; + } else if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { + state = file_info_is_dir(&file_info); } furi_record_close(RECORD_STORAGE); return state; diff --git a/applications/main/archive/helpers/archive_favorites.h b/applications/main/archive/helpers/archive_favorites.h index 64ffcdd7b..75070c44d 100644 --- a/applications/main/archive/helpers/archive_favorites.h +++ b/applications/main/archive/helpers/archive_favorites.h @@ -2,8 +2,8 @@ #include -#define ARCHIVE_FAV_PATH ANY_PATH("favorites.txt") -#define ARCHIVE_FAV_TEMP_PATH ANY_PATH("favorites.tmp") +#define ARCHIVE_FAV_PATH EXT_PATH("favorites.txt") +#define ARCHIVE_FAV_TEMP_PATH EXT_PATH("favorites.tmp") uint16_t archive_favorites_count(void* context); bool archive_favorites_read(void* context); diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index 454837e97..fc2324c63 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -28,7 +28,7 @@ #include "ibutton_custom_event.h" #include "scenes/ibutton_scene.h" -#define IBUTTON_APP_FOLDER ANY_PATH("ibutton") +#define IBUTTON_APP_FOLDER EXT_PATH("ibutton") #define IBUTTON_APP_FILENAME_PREFIX "iBtn" #define IBUTTON_APP_FILENAME_EXTENSION ".ibtn" diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index d353b2503..75d4e230d 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -46,7 +46,7 @@ #define INFRARED_MAX_BUTTON_NAME_LENGTH 22 #define INFRARED_MAX_REMOTE_NAME_LENGTH 22 -#define INFRARED_APP_FOLDER ANY_PATH("infrared") +#define INFRARED_APP_FOLDER EXT_PATH("infrared") #define INFRARED_APP_EXTENSION ".ir" #define INFRARED_DEFAULT_REMOTE_NAME "Remote" diff --git a/applications/main/lfrfid/lfrfid_i.h b/applications/main/lfrfid/lfrfid_i.h index f949e73e6..913b7358b 100644 --- a/applications/main/lfrfid/lfrfid_i.h +++ b/applications/main/lfrfid/lfrfid_i.h @@ -38,7 +38,7 @@ #define LFRFID_KEY_NAME_SIZE 22 #define LFRFID_TEXT_STORE_SIZE 40 -#define LFRFID_APP_FOLDER ANY_PATH("lfrfid") +#define LFRFID_APP_FOLDER EXT_PATH("lfrfid") #define LFRFID_SD_FOLDER EXT_PATH("lfrfid") #define LFRFID_APP_FILENAME_PREFIX "RFID" #define LFRFID_APP_FILENAME_EXTENSION ".rfid" diff --git a/applications/main/nfc/helpers/mf_user_dict.c b/applications/main/nfc/helpers/mf_user_dict.c index 70b111472..7f60d339e 100644 --- a/applications/main/nfc/helpers/mf_user_dict.c +++ b/applications/main/nfc/helpers/mf_user_dict.c @@ -4,7 +4,7 @@ #include #include -#define NFC_APP_FOLDER ANY_PATH("nfc") +#define NFC_APP_FOLDER EXT_PATH("nfc") #define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc") struct MfUserDict { diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 867d0eb4f..1c174986e 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -67,7 +67,7 @@ #define NFC_TEXT_STORE_SIZE 128 #define NFC_BYTE_INPUT_STORE_SIZE 10 #define NFC_LOG_SIZE_MAX (1024) -#define NFC_APP_FOLDER ANY_PATH("nfc") +#define NFC_APP_FOLDER EXT_PATH("nfc") #define NFC_APP_EXTENSION ".nfc" #define NFC_APP_SHADOW_EXTENSION ".shd" #define NFC_APP_FILENAME_PREFIX "NFC" diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 43bb25ab8..e8601dc5d 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -592,7 +592,7 @@ void subghz_cli_command_tx_from_file(Cli* cli, FuriString* args, void* context) UNUSED(context); FuriString* file_name; file_name = furi_string_alloc(); - furi_string_set(file_name, ANY_PATH("subghz/test.sub")); + furi_string_set(file_name, EXT_PATH("subghz/test.sub")); uint32_t repeat = 10; uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index 6a37769a8..0143eb245 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -4,7 +4,6 @@ #include #include #include -#include // for lfs_tobe32 #include #include @@ -319,6 +318,10 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { return sizeof(U2fRegisterResp) + cert_len + signature_len + 2; } +static inline uint32_t u2f_to_big_endian(uint32_t a) { + return __builtin_bswap32(a); +} + static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { U2fAuthReq* req = (U2fAuthReq*)buf; U2fAuthResp* resp = (U2fAuthResp*)buf; @@ -348,7 +351,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { U2F->user_present = false; // The 4 byte counter is represented in big endian. Increment it before use - be_u2f_counter = lfs_tobe32(U2F->counter + 1); + be_u2f_counter = u2f_to_big_endian(U2F->counter + 1); // Generate hash { diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 36e7446fb..db058ce42 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -61,6 +61,21 @@ static void bt_pin_code_view_port_input_callback(InputEvent* event, void* contex } } +static void bt_storage_callback(const void* message, void* context) { + furi_assert(context); + Bt* bt = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + const BtMessage msg = { + .type = BtMessageTypeReloadKeysSettings, + }; + + furi_check( + furi_message_queue_put(bt->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + } +} + static ViewPort* bt_pin_code_view_port_alloc(Bt* bt) { ViewPort* view_port = view_port_alloc(); view_port_draw_callback_set(view_port, bt_pin_code_view_port_draw_callback, bt); @@ -143,8 +158,6 @@ Bt* bt_alloc(void) { // Init default maximum packet size bt->max_packet_size = BLE_PROFILE_SERIAL_PACKET_SIZE_MAX; bt->current_profile = NULL; - // Load settings - bt_settings_load(&bt->bt_settings); // Keys storage bt->keys_storage = bt_keys_storage_alloc(BT_KEYS_STORAGE_PATH); // Alloc queue @@ -396,6 +409,8 @@ void bt_close_rpc_connection(Bt* bt) { static void bt_change_profile(Bt* bt, BtMessage* message) { if(furi_hal_bt_is_gatt_gap_supported()) { + bt_settings_load(&bt->bt_settings); + bt_close_rpc_connection(bt); bt_keys_storage_load(bt->keys_storage); @@ -439,6 +454,87 @@ static void bt_close_connection(Bt* bt, BtMessage* message) { if(message->lock) api_lock_unlock(message->lock); } +static void bt_apply_settings(Bt* bt) { + if(bt->bt_settings.enabled) { + furi_hal_bt_start_advertising(); + } else { + furi_hal_bt_stop_advertising(); + } +} + +static void bt_load_keys(Bt* bt) { + if(!furi_hal_bt_is_gatt_gap_supported()) { + bt_show_warning(bt, "Unsupported radio stack"); + bt->status = BtStatusUnavailable; + return; + + } else if(bt_keys_storage_is_changed(bt->keys_storage)) { + FURI_LOG_I(TAG, "Loading new keys"); + + bt_close_rpc_connection(bt); + bt_keys_storage_load(bt->keys_storage); + + bt->current_profile = NULL; + + } else { + FURI_LOG_I(TAG, "Keys unchanged"); + } +} + +static void bt_start_application(Bt* bt) { + if(!bt->current_profile) { + bt->current_profile = + furi_hal_bt_change_app(ble_profile_serial, NULL, bt_on_gap_event_callback, bt); + + if(!bt->current_profile) { + FURI_LOG_E(TAG, "BLE App start failed"); + bt->status = BtStatusUnavailable; + } + } +} + +static void bt_load_settings(Bt* bt) { + bt_settings_load(&bt->bt_settings); + bt_apply_settings(bt); +} + +static void bt_handle_get_settings(Bt* bt, BtMessage* message) { + furi_assert(message->lock); + *message->data.settings = bt->bt_settings; + api_lock_unlock(message->lock); +} + +static void bt_handle_set_settings(Bt* bt, BtMessage* message) { + furi_assert(message->lock); + bt->bt_settings = *message->data.csettings; + + bt_apply_settings(bt); + bt_settings_save(&bt->bt_settings); + + api_lock_unlock(message->lock); +} + +static void bt_handle_reload_keys_settings(Bt* bt) { + bt_load_keys(bt); + bt_start_application(bt); + bt_load_settings(bt); +} + +static void bt_init_keys_settings(Bt* bt) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), bt_storage_callback, bt); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + + // Just start the BLE serial application without loading the keys or settings + bt_start_application(bt); + return; + } + + bt_handle_reload_keys_settings(bt); +} + bool bt_remote_rssi(Bt* bt, uint8_t* rssi) { furi_assert(bt); @@ -465,35 +561,18 @@ int32_t bt_srv(void* p) { return 0; } - // Load keys - if(!bt_keys_storage_load(bt->keys_storage)) { - FURI_LOG_W(TAG, "Failed to load bonding keys"); - } + if(furi_hal_bt_start_radio_stack()) { + bt_init_keys_settings(bt); + furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); - // Start radio stack - if(!furi_hal_bt_start_radio_stack()) { - FURI_LOG_E(TAG, "Radio stack start failed"); - } - - if(furi_hal_bt_is_gatt_gap_supported()) { - bt->current_profile = - furi_hal_bt_start_app(ble_profile_serial, NULL, bt_on_gap_event_callback, bt); - if(!bt->current_profile) { - FURI_LOG_E(TAG, "BLE App start failed"); - } else { - if(bt->bt_settings.enabled) { - furi_hal_bt_start_advertising(); - } - furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); - } } else { - bt_show_warning(bt, "Unsupported radio stack"); - bt->status = BtStatusUnavailable; + FURI_LOG_E(TAG, "Radio stack start failed"); } furi_record_create(RECORD_BT, bt); BtMessage message; + while(1) { furi_check( furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); @@ -523,7 +602,14 @@ int32_t bt_srv(void* p) { bt_close_connection(bt, &message); } else if(message.type == BtMessageTypeForgetBondedDevices) { bt_keys_storage_delete(bt->keys_storage); + } else if(message.type == BtMessageTypeGetSettings) { + bt_handle_get_settings(bt, &message); + } else if(message.type == BtMessageTypeSetSettings) { + bt_handle_set_settings(bt, &message); + } else if(message.type == BtMessageTypeReloadKeysSettings) { + bt_handle_reload_keys_settings(bt); } } + return 0; } diff --git a/applications/services/bt/bt_service/bt_api.c b/applications/services/bt/bt_service/bt_api.c index f0e792d42..39b9a099d 100644 --- a/applications/services/bt/bt_service/bt_api.c +++ b/applications/services/bt/bt_service/bt_api.c @@ -77,3 +77,39 @@ void bt_keys_storage_set_default_path(Bt* bt) { bt_keys_storage_set_file_path(bt->keys_storage, BT_KEYS_STORAGE_PATH); } + +/* + * Private API for the Settings app + */ + +void bt_get_settings(Bt* bt, BtSettings* settings) { + furi_assert(bt); + furi_assert(settings); + + BtMessage message = { + .lock = api_lock_alloc_locked(), + .type = BtMessageTypeGetSettings, + .data.settings = settings, + }; + + furi_check( + furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); + + api_lock_wait_unlock_and_free(message.lock); +} + +void bt_set_settings(Bt* bt, const BtSettings* settings) { + furi_assert(bt); + furi_assert(settings); + + BtMessage message = { + .lock = api_lock_alloc_locked(), + .type = BtMessageTypeSetSettings, + .data.csettings = settings, + }; + + furi_check( + furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); + + api_lock_wait_unlock_and_free(message.lock); +} diff --git a/applications/services/bt/bt_service/bt_i.h b/applications/services/bt/bt_service/bt_i.h index eb9428388..58a60e275 100644 --- a/applications/services/bt/bt_service/bt_i.h +++ b/applications/services/bt/bt_service/bt_i.h @@ -32,6 +32,9 @@ typedef enum { BtMessageTypeSetProfile, BtMessageTypeDisconnect, BtMessageTypeForgetBondedDevices, + BtMessageTypeGetSettings, + BtMessageTypeSetSettings, + BtMessageTypeReloadKeysSettings, } BtMessageType; typedef struct { @@ -49,6 +52,8 @@ typedef union { } profile; FuriHalBleProfileParams profile_params; BtKeyStorageUpdateData key_storage_data; + BtSettings* settings; + const BtSettings* csettings; } BtMessageData; typedef struct { diff --git a/applications/services/bt/bt_service/bt_keys_storage.c b/applications/services/bt/bt_service/bt_keys_storage.c index 6392c2d67..57742e8e2 100644 --- a/applications/services/bt/bt_service/bt_keys_storage.c +++ b/applications/services/bt/bt_service/bt_keys_storage.c @@ -13,6 +13,7 @@ struct BtKeysStorage { uint8_t* nvm_sram_buff; uint16_t nvm_sram_buff_size; + uint16_t current_size; FuriString* file_path; }; @@ -66,44 +67,114 @@ void bt_keys_storage_set_ram_params(BtKeysStorage* instance, uint8_t* buff, uint instance->nvm_sram_buff_size = size; } +static bool bt_keys_storage_file_exists(const char* file_path) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FileInfo file_info; + const bool ret = storage_common_stat(storage, file_path, &file_info) == FSE_OK && + file_info.size != 0; + furi_record_close(RECORD_STORAGE); + return ret; +} + +static bool bt_keys_storage_validate_file(const char* file_path, size_t* payload_size) { + uint8_t magic, version; + size_t size; + + if(!saved_struct_get_metadata(file_path, &magic, &version, &size)) { + FURI_LOG_E(TAG, "Failed to get metadata"); + return false; + + } else if(magic != BT_KEYS_STORAGE_MAGIC || version != BT_KEYS_STORAGE_VERSION) { + FURI_LOG_E(TAG, "File version mismatch"); + return false; + } + + *payload_size = size; + return true; +} + +bool bt_keys_storage_is_changed(BtKeysStorage* instance) { + furi_assert(instance); + + bool is_changed = false; + uint8_t* data_buffer = NULL; + + do { + const char* file_path = furi_string_get_cstr(instance->file_path); + size_t payload_size; + + if(!bt_keys_storage_file_exists(file_path)) { + FURI_LOG_W(TAG, "Missing or empty file"); + break; + + } else if(!bt_keys_storage_validate_file(file_path, &payload_size)) { + FURI_LOG_E(TAG, "Invalid or corrupted file"); + break; + } + + data_buffer = malloc(payload_size); + + const bool data_loaded = saved_struct_load( + file_path, data_buffer, payload_size, BT_KEYS_STORAGE_MAGIC, BT_KEYS_STORAGE_VERSION); + + if(!data_loaded) { + FURI_LOG_E(TAG, "Failed to load file"); + break; + + } else if(payload_size == instance->current_size) { + furi_hal_bt_nvm_sram_sem_acquire(); + is_changed = memcmp(data_buffer, instance->nvm_sram_buff, payload_size); + furi_hal_bt_nvm_sram_sem_release(); + + } else { + FURI_LOG_D(TAG, "Size mismatch"); + is_changed = true; + } + } while(false); + + if(data_buffer) { + free(data_buffer); + } + + return is_changed; +} + bool bt_keys_storage_load(BtKeysStorage* instance) { furi_assert(instance); bool loaded = false; + do { + const char* file_path = furi_string_get_cstr(instance->file_path); + // Get payload size - uint8_t magic = 0, version = 0; - size_t payload_size = 0; - if(!saved_struct_get_metadata( - furi_string_get_cstr(instance->file_path), &magic, &version, &payload_size)) { - FURI_LOG_E(TAG, "Failed to read payload size"); + size_t payload_size; + if(!bt_keys_storage_validate_file(file_path, &payload_size)) { + FURI_LOG_E(TAG, "Invalid or corrupted file"); break; - } - if(magic != BT_KEYS_STORAGE_MAGIC || version != BT_KEYS_STORAGE_VERSION) { - FURI_LOG_E(TAG, "Saved data version is mismatched"); - break; - } - - if(payload_size > instance->nvm_sram_buff_size) { - FURI_LOG_E(TAG, "Saved data doesn't fit ram buffer"); + } else if(payload_size > instance->nvm_sram_buff_size) { + FURI_LOG_E(TAG, "NVM RAM buffer overflow"); break; } // Load saved data to ram furi_hal_bt_nvm_sram_sem_acquire(); - bool data_loaded = saved_struct_load( - furi_string_get_cstr(instance->file_path), + const bool data_loaded = saved_struct_load( + file_path, instance->nvm_sram_buff, payload_size, BT_KEYS_STORAGE_MAGIC, BT_KEYS_STORAGE_VERSION); furi_hal_bt_nvm_sram_sem_release(); + if(!data_loaded) { - FURI_LOG_E(TAG, "Failed to load struct"); + FURI_LOG_E(TAG, "Failed to load file"); break; } + instance->current_size = payload_size; + loaded = true; } while(false); @@ -130,6 +201,8 @@ bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32 break; } + instance->current_size = new_size; + furi_hal_bt_nvm_sram_sem_acquire(); bool data_updated = saved_struct_save( furi_string_get_cstr(instance->file_path), @@ -138,10 +211,12 @@ bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32 BT_KEYS_STORAGE_MAGIC, BT_KEYS_STORAGE_VERSION); furi_hal_bt_nvm_sram_sem_release(); + if(!data_updated) { FURI_LOG_E(TAG, "Failed to update key storage"); break; } + updated = true; } while(false); diff --git a/applications/services/bt/bt_service/bt_keys_storage.h b/applications/services/bt/bt_service/bt_keys_storage.h index 587dd570d..b7a127035 100644 --- a/applications/services/bt/bt_service/bt_keys_storage.h +++ b/applications/services/bt/bt_service/bt_keys_storage.h @@ -17,6 +17,8 @@ void bt_keys_storage_set_file_path(BtKeysStorage* instance, const char* path); void bt_keys_storage_set_ram_params(BtKeysStorage* instance, uint8_t* buff, uint16_t size); +bool bt_keys_storage_is_changed(BtKeysStorage* instance); + bool bt_keys_storage_load(BtKeysStorage* instance); bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32_t size); diff --git a/applications/services/bt/bt_service/bt_settings_api_i.h b/applications/services/bt/bt_service/bt_settings_api_i.h new file mode 100644 index 000000000..441295893 --- /dev/null +++ b/applications/services/bt/bt_service/bt_settings_api_i.h @@ -0,0 +1,8 @@ +#pragma once + +#include "bt.h" +#include "../bt_settings.h" + +void bt_get_settings(Bt* bt, BtSettings* settings); + +void bt_set_settings(Bt* bt, const BtSettings* settings); diff --git a/applications/services/bt/bt_settings.c b/applications/services/bt/bt_settings.c index 3602cf497..abdc97f7e 100644 --- a/applications/services/bt/bt_settings.c +++ b/applications/services/bt/bt_settings.c @@ -1,23 +1,36 @@ #include "bt_settings.h" +#include "bt_settings_filename.h" #include -#include #include +#include + +#define TAG "BtSettings" #define BT_SETTINGS_PATH INT_PATH(BT_SETTINGS_FILE_NAME) #define BT_SETTINGS_VERSION (0) #define BT_SETTINGS_MAGIC (0x19) -bool bt_settings_load(BtSettings* bt_settings) { +void bt_settings_load(BtSettings* bt_settings) { furi_assert(bt_settings); - return saved_struct_load( + const bool success = saved_struct_load( BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load settings, using defaults"); + memset(bt_settings, 0, sizeof(BtSettings)); + bt_settings_save(bt_settings); + } } -bool bt_settings_save(const BtSettings* bt_settings) { +void bt_settings_save(const BtSettings* bt_settings) { furi_assert(bt_settings); - return saved_struct_save( + const bool success = saved_struct_save( BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save settings"); + } } diff --git a/applications/services/bt/bt_settings.h b/applications/services/bt/bt_settings.h index a4e76a12c..c63220abb 100644 --- a/applications/services/bt/bt_settings.h +++ b/applications/services/bt/bt_settings.h @@ -1,8 +1,5 @@ #pragma once -#include "bt_settings_filename.h" - -#include #include #ifdef __cplusplus @@ -13,9 +10,9 @@ typedef struct { bool enabled; } BtSettings; -bool bt_settings_load(BtSettings* bt_settings); +void bt_settings_load(BtSettings* bt_settings); -bool bt_settings_save(const BtSettings* bt_settings); +void bt_settings_save(const BtSettings* bt_settings); #ifdef __cplusplus } diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index 8e04e7894..dd2ae76a1 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -97,8 +97,11 @@ void animation_manager_set_interact_callback( void animation_manager_set_dummy_mode_state(AnimationManager* animation_manager, bool enabled) { furi_assert(animation_manager); - animation_manager->dummy_mode = enabled; - animation_manager_start_new_idle(animation_manager); + // Prevent change of animations if mode is the same + if(animation_manager->dummy_mode != enabled) { + animation_manager->dummy_mode = enabled; + animation_manager_start_new_idle(animation_manager); + } } static void animation_manager_check_blocking_callback(const void* message, void* context) { diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 53e2d29c8..66e503e96 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -1,31 +1,24 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "desktop_i.h" + #include #include -#include -#include "animations/animation_manager.h" -#include "desktop/scenes/desktop_scene.h" -#include "desktop/scenes/desktop_scene_i.h" -#include "desktop/views/desktop_view_locked.h" -#include "desktop/views/desktop_view_pin_input.h" -#include "desktop/views/desktop_view_pin_timeout.h" -#include "desktop_i.h" -#include "helpers/pin.h" -#include "helpers/slideshow_filename.h" +#include + +#include +#include + +#include + +#include "scenes/desktop_scene.h" +#include "scenes/desktop_scene_locked.h" #define TAG "Desktop" static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); +static void desktop_apply_settings(Desktop*); static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); @@ -42,6 +35,16 @@ static void desktop_loader_callback(const void* message, void* context) { } } +static void desktop_storage_callback(const void* message, void* context) { + furi_assert(context); + Desktop* desktop = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalReloadSettings); + } +} + static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); furi_assert(canvas); @@ -122,31 +125,39 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { furi_assert(context); Desktop* desktop = (Desktop*)context; - switch(event) { - case DesktopGlobalBeforeAppStarted: + if(event == DesktopGlobalBeforeAppStarted) { if(animation_manager_is_animation_loaded(desktop->animation_manager)) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } - desktop_auto_lock_inhibit(desktop); - furi_semaphore_release(desktop->animation_semaphore); - return true; - case DesktopGlobalAfterAppFinished: - animation_manager_load_and_continue_animation(desktop->animation_manager); - DESKTOP_SETTINGS_LOAD(&desktop->settings); - desktop_clock_reconfigure(desktop); - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { - desktop_auto_lock_arm(desktop); - } - return true; - case DesktopGlobalAutoLock: - if(!loader_is_locked(desktop->loader) && !desktop->locked) { + desktop_auto_lock_inhibit(desktop); + desktop->app_running = true; + + furi_semaphore_release(desktop->animation_semaphore); + + } else if(event == DesktopGlobalAfterAppFinished) { + animation_manager_load_and_continue_animation(desktop->animation_manager); + desktop_auto_lock_arm(desktop); + desktop->app_running = false; + + } else if(event == DesktopGlobalAutoLock) { + if(!desktop->app_running && !desktop->locked) { desktop_lock(desktop); } - return true; + + } else if(event == DesktopGlobalSaveSettings) { + desktop_settings_save(&desktop->settings); + desktop_apply_settings(desktop); + + } else if(event == DesktopGlobalReloadSettings) { + desktop_settings_load(&desktop->settings); + desktop_apply_settings(desktop); + + } else { + return scene_manager_handle_custom_event(desktop->scene_manager, event); } - return scene_manager_handle_custom_event(desktop->scene_manager, event); + return true; } static bool desktop_back_event_callback(void* context) { @@ -206,84 +217,45 @@ static void desktop_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; - if(gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6) { + const bool clock_enabled = gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6; + + if(clock_enabled) { desktop_clock_update(desktop); - - view_port_enabled_set(desktop->clock_viewport, true); - } else { - view_port_enabled_set(desktop->clock_viewport, false); - } -} - -void desktop_lock(Desktop* desktop) { - furi_assert(!desktop->locked); - - furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - - if(desktop->settings.pin_code.length) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_close(cli); - furi_record_close(RECORD_CLI); } - desktop_auto_lock_inhibit(desktop); - scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); - - DesktopStatus status = {.locked = true}; - furi_pubsub_publish(desktop->status_pubsub, &status); - - desktop->locked = true; + view_port_enabled_set(desktop->clock_viewport, clock_enabled); } -void desktop_unlock(Desktop* desktop) { - furi_assert(desktop->locked); - - view_port_enabled_set(desktop->lock_icon_viewport, false); - Gui* gui = furi_record_open(RECORD_GUI); - gui_set_lockdown(gui, false); - furi_record_close(RECORD_GUI); - desktop_view_locked_unlock(desktop->locked_view); - scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain); - desktop_auto_lock_arm(desktop); - furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); - furi_hal_rtc_set_pin_fails(0); - - if(desktop->settings.pin_code.length) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_open(cli, &cli_vcp); - furi_record_close(RECORD_CLI); - } - - DesktopStatus status = {.locked = false}; - furi_pubsub_publish(desktop->status_pubsub, &status); - - desktop->locked = false; -} - -void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { +static void desktop_apply_settings(Desktop* desktop) { desktop->in_transition = true; - view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled); - desktop_main_set_dummy_mode_state(desktop->main_view, enabled); - animation_manager_set_dummy_mode_state(desktop->animation_manager, enabled); - desktop->settings.dummy_mode = enabled; - DESKTOP_SETTINGS_SAVE(&desktop->settings); + + desktop_clock_reconfigure(desktop); + + view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); + desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); + animation_manager_set_dummy_mode_state( + desktop->animation_manager, desktop->settings.dummy_mode); + + if(!desktop->app_running && !desktop->locked) { + desktop_auto_lock_arm(desktop); + } + desktop->in_transition = false; } -void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { - desktop->in_transition = true; - if(enabled) { - furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); - } else { - furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); +static void desktop_init_settings(Desktop* desktop) { + furi_pubsub_subscribe(storage_get_pubsub(desktop->storage), desktop_storage_callback, desktop); + + if(storage_sd_status(desktop->storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; } - view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); - desktop->in_transition = false; + + desktop_settings_load(&desktop->settings); + desktop_apply_settings(desktop); } -Desktop* desktop_alloc(void) { +static Desktop* desktop_alloc(void) { Desktop* desktop = malloc(sizeof(Desktop)); desktop->animation_semaphore = furi_semaphore_alloc(1, 0); @@ -392,14 +364,13 @@ Desktop* desktop_alloc(void) { } gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft); + // Unload animations before starting an application desktop->loader = furi_record_open(RECORD_LOADER); + furi_pubsub_subscribe(loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop); + desktop->storage = furi_record_open(RECORD_STORAGE); desktop->notification = furi_record_open(RECORD_NOTIFICATION); - desktop->app_start_stop_subscription = furi_pubsub_subscribe( - loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop); - desktop->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); - desktop->input_events_subscription = NULL; desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); @@ -409,19 +380,95 @@ Desktop* desktop_alloc(void) { desktop->update_clock_timer = furi_timer_alloc(desktop_clock_timer_callback, FuriTimerTypePeriodic, desktop); + desktop->app_running = loader_is_locked(desktop->loader); + furi_record_create(RECORD_DESKTOP, desktop); return desktop; } -static bool desktop_check_file_flag(const char* flag_path) { - Storage* storage = furi_record_open(RECORD_STORAGE); - bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK; - furi_record_close(RECORD_STORAGE); +/* + * Private API + */ - return exists; +void desktop_lock(Desktop* desktop) { + furi_assert(!desktop->locked); + + furi_hal_rtc_set_flag(FuriHalRtcFlagLock); + + if(desktop_pin_code_is_set()) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + furi_record_close(RECORD_CLI); + } + + desktop_auto_lock_inhibit(desktop); + scene_manager_set_scene_state( + desktop->scene_manager, DesktopSceneLocked, DesktopSceneLockedStateFirstEnter); + scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); + + DesktopStatus status = {.locked = true}; + furi_pubsub_publish(desktop->status_pubsub, &status); + + desktop->locked = true; } +void desktop_unlock(Desktop* desktop) { + furi_assert(desktop->locked); + + view_port_enabled_set(desktop->lock_icon_viewport, false); + Gui* gui = furi_record_open(RECORD_GUI); + gui_set_lockdown(gui, false); + furi_record_close(RECORD_GUI); + desktop_view_locked_unlock(desktop->locked_view); + scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain); + desktop_auto_lock_arm(desktop); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); + furi_hal_rtc_set_pin_fails(0); + + if(desktop_pin_code_is_set()) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_open(cli, &cli_vcp); + furi_record_close(RECORD_CLI); + } + + DesktopStatus status = {.locked = false}; + furi_pubsub_publish(desktop->status_pubsub, &status); + + desktop->locked = false; +} + +void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { + desktop->in_transition = true; + + view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled); + desktop_main_set_dummy_mode_state(desktop->main_view, enabled); + animation_manager_set_dummy_mode_state(desktop->animation_manager, enabled); + desktop->settings.dummy_mode = enabled; + + desktop->in_transition = false; + + desktop_settings_save(&desktop->settings); +} + +void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { + desktop->in_transition = true; + + if(enabled) { + furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); + } else { + furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); + } + + view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); + + desktop->in_transition = false; +} + +/* + * Public API + */ + bool desktop_api_is_locked(Desktop* instance) { furi_assert(instance); return furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock); @@ -437,6 +484,30 @@ FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance) { return instance->status_pubsub; } +void desktop_api_reload_settings(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopGlobalReloadSettings); +} + +void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings) { + furi_assert(instance); + furi_assert(settings); + + *settings = instance->settings; +} + +void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings) { + furi_assert(instance); + furi_assert(settings); + + instance->settings = *settings; + view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopGlobalSaveSettings); +} + +/* + * Application thread + */ + int32_t desktop_srv(void* p) { UNUSED(p); @@ -449,31 +520,15 @@ int32_t desktop_srv(void* p) { Desktop* desktop = desktop_alloc(); - bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(!loaded) { - memset(&desktop->settings, 0, sizeof(desktop->settings)); - DESKTOP_SETTINGS_SAVE(&desktop->settings); - } - - view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); - - desktop_clock_reconfigure(desktop); - - desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); - animation_manager_set_dummy_mode_state( - desktop->animation_manager, desktop->settings.dummy_mode); + desktop_init_settings(desktop); scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { desktop_lock(desktop); - } else { - if(!loader_is_locked(desktop->loader)) { - desktop_auto_lock_arm(desktop); - } } - if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) { + if(storage_file_exists(desktop->storage, SLIDESHOW_FS_PATH)) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow); } @@ -497,14 +552,12 @@ int32_t desktop_srv(void* p) { } // Special case: autostart application is already running - if(loader_is_locked(desktop->loader) && - animation_manager_is_animation_loaded(desktop->animation_manager)) { + if(desktop->app_running && animation_manager_is_animation_loaded(desktop->animation_manager)) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } view_dispatcher_run(desktop->view_dispatcher); - furi_crash("That was unexpected"); - + // Should never get here (a service thread will crash automatically if it returns) return 0; } diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index 4eab24fcc..e83bc3ee4 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -2,16 +2,22 @@ #include -typedef struct Desktop Desktop; +#include "desktop_settings.h" #define RECORD_DESKTOP "desktop" -bool desktop_api_is_locked(Desktop* instance); - -void desktop_api_unlock(Desktop* instance); +typedef struct Desktop Desktop; typedef struct { bool locked; } DesktopStatus; +bool desktop_api_is_locked(Desktop* instance); + +void desktop_api_unlock(Desktop* instance); + FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); + +void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings); + +void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 4bcbb6585..1dc7c7d21 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -1,6 +1,8 @@ #pragma once #include "desktop.h" +#include "desktop_settings.h" + #include "animations/animation_manager.h" #include "views/desktop_view_pin_timeout.h" #include "views/desktop_view_pin_input.h" @@ -9,9 +11,7 @@ #include "views/desktop_view_lock_menu.h" #include "views/desktop_view_debug.h" #include "views/desktop_view_slideshow.h" -#include -#include #include #include #include @@ -42,9 +42,8 @@ typedef struct { } DesktopClock; struct Desktop { - // Scene FuriThread* scene_thread; - // GUI + Gui* gui; ViewDispatcher* view_dispatcher; SceneManager* scene_manager; @@ -56,42 +55,38 @@ struct Desktop { DesktopMainView* main_view; DesktopViewPinTimeout* pin_timeout_view; DesktopSlideshowView* slideshow_view; + DesktopViewPinInput* pin_input_view; ViewStack* main_view_stack; ViewStack* locked_view_stack; - DesktopSettings settings; - DesktopViewPinInput* pin_input_view; - ViewPort* lock_icon_viewport; ViewPort* dummy_mode_icon_viewport; ViewPort* clock_viewport; ViewPort* stealth_mode_icon_viewport; - AnimationManager* animation_manager; - Loader* loader; + Storage* storage; NotificationApp* notification; - FuriPubSubSubscription* app_start_stop_subscription; + FuriPubSub* status_pubsub; FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; + FuriTimer* auto_lock_timer; FuriTimer* update_clock_timer; - FuriPubSub* status_pubsub; + AnimationManager* animation_manager; + FuriSemaphore* animation_semaphore; DesktopClock clock; + DesktopSettings settings; - bool in_transition : 1; - bool locked : 1; - - FuriSemaphore* animation_semaphore; + bool in_transition; + bool app_running; + bool locked; }; -Desktop* desktop_alloc(void); - -void desktop_free(Desktop* desktop); void desktop_lock(Desktop* desktop); void desktop_unlock(Desktop* desktop); void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled); diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c new file mode 100644 index 000000000..f66fdeda7 --- /dev/null +++ b/applications/services/desktop/desktop_settings.c @@ -0,0 +1,79 @@ +#include "desktop_settings.h" +#include "desktop_settings_filename.h" + +#include +#include + +#define TAG "DesktopSettings" + +#define DESKTOP_SETTINGS_VER_10 (10) +#define DESKTOP_SETTINGS_VER (11) + +#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) +#define DESKTOP_SETTINGS_MAGIC (0x17) + +typedef struct { + uint8_t reserved[11]; + DesktopSettings settings; +} DesktopSettingsV10; + +// Actual size of DesktopSettings v10 +static_assert(sizeof(DesktopSettingsV10) == 1044); + +void desktop_settings_load(DesktopSettings* settings) { + furi_assert(settings); + + bool success = false; + + do { + uint8_t version; + if(!saved_struct_get_metadata(DESKTOP_SETTINGS_PATH, NULL, &version, NULL)) break; + + if(version == DESKTOP_SETTINGS_VER) { + success = saved_struct_load( + DESKTOP_SETTINGS_PATH, + settings, + sizeof(DesktopSettings), + DESKTOP_SETTINGS_MAGIC, + DESKTOP_SETTINGS_VER); + + } else if(version == DESKTOP_SETTINGS_VER_10) { + DesktopSettingsV10* settings_v10 = malloc(sizeof(DesktopSettingsV10)); + + success = saved_struct_load( + DESKTOP_SETTINGS_PATH, + settings_v10, + sizeof(DesktopSettingsV10), + DESKTOP_SETTINGS_MAGIC, + DESKTOP_SETTINGS_VER_10); + + if(success) { + *settings = settings_v10->settings; + } + + free(settings_v10); + } + + } while(false); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load file, using defaults"); + memset(settings, 0, sizeof(DesktopSettings)); + desktop_settings_save(settings); + } +} + +void desktop_settings_save(const DesktopSettings* settings) { + furi_assert(settings); + + const bool success = saved_struct_save( + DESKTOP_SETTINGS_PATH, + settings, + sizeof(DesktopSettings), + DESKTOP_SETTINGS_MAGIC, + DESKTOP_SETTINGS_VER); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save file"); + } +} diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 4c848117a..49c2cd20c 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -1,12 +1,6 @@ #pragma once -#include "desktop_settings_filename.h" - -#include #include -#include -#include -#include #define DESKTOP_SETTINGS_VER (13) @@ -44,7 +38,7 @@ #define DISPLAY_BATTERY_BAR_PERCENT 5 typedef enum { - FavoriteAppLeftShort = 0, + FavoriteAppLeftShort, FavoriteAppLeftLong, FavoriteAppRightShort, FavoriteAppRightLong, @@ -67,16 +61,10 @@ typedef enum { } DummyAppShortcut; typedef struct { - InputKey data[MAX_PIN_SIZE]; - uint8_t length; -} PinCode; - -typedef struct { - char name_or_path[MAX_APP_LENGTH]; + char name_or_path[128]; } FavoriteApp; typedef struct { - PinCode pin_code; uint32_t auto_lock_delay_ms; uint8_t displayBatteryPercentage; uint8_t dummy_mode; @@ -84,3 +72,6 @@ typedef struct { FavoriteApp favorite_apps[FavoriteAppNumber]; FavoriteApp dummy_apps[DummyAppNumber]; } DesktopSettings; + +void desktop_settings_load(DesktopSettings* settings); +void desktop_settings_save(const DesktopSettings* settings); diff --git a/applications/services/desktop/helpers/pin.c b/applications/services/desktop/helpers/pin.c deleted file mode 100644 index 0b1149d6c..000000000 --- a/applications/services/desktop/helpers/pin.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "pin.h" - -#include -#include -#include -#include -#include -#include - -static const NotificationSequence sequence_pin_fail = { - &message_display_backlight_on, - - &message_red_255, - &message_vibro_on, - &message_delay_100, - &message_vibro_off, - &message_red_0, - - &message_delay_250, - - &message_red_255, - &message_vibro_on, - &message_delay_100, - &message_vibro_off, - &message_red_0, - NULL, -}; - -static const uint8_t desktop_helpers_fails_timeout[] = { - 0, - 0, - 0, - 0, - 30, - 60, - 90, - 120, - 150, - 180, - /* +60 for every next fail */ -}; - -void desktop_pin_lock_error_notify(void) { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_pin_fail); - furi_record_close(RECORD_NOTIFICATION); -} - -uint32_t desktop_pin_lock_get_fail_timeout(void) { - uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); - uint32_t pin_timeout = 0; - uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; - if(pin_fails <= max_index) { - pin_timeout = desktop_helpers_fails_timeout[pin_fails]; - } else { - pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; - } - - return pin_timeout; -} - -bool desktop_pin_compare(const PinCode* pin_code1, const PinCode* pin_code2) { - furi_assert(pin_code1); - furi_assert(pin_code2); - bool result = false; - - if(pin_code1->length == pin_code2->length) { - result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length); - } - - return result; -} diff --git a/applications/services/desktop/helpers/pin.h b/applications/services/desktop/helpers/pin.h deleted file mode 100644 index 23d16b0aa..000000000 --- a/applications/services/desktop/helpers/pin.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include -#include -#include "../desktop.h" -#include - -void desktop_pin_lock_error_notify(void); - -uint32_t desktop_pin_lock_get_fail_timeout(void); - -bool desktop_pin_compare(const PinCode* pin_code1, const PinCode* pin_code2); diff --git a/applications/services/desktop/helpers/pin_code.c b/applications/services/desktop/helpers/pin_code.c new file mode 100644 index 000000000..d1a37ed24 --- /dev/null +++ b/applications/services/desktop/helpers/pin_code.c @@ -0,0 +1,103 @@ +#include "pin_code.h" + +#include + +#include +#include + +#define DESKTOP_PIN_CODE_DIGIT_BIT_WIDTH (2) +#define DESKTOP_PIN_CODE_LENGTH_OFFSET (28) + +static const NotificationSequence sequence_pin_fail = { + &message_display_backlight_on, + + &message_red_255, + &message_vibro_on, + &message_delay_100, + &message_vibro_off, + &message_red_0, + + &message_delay_250, + + &message_red_255, + &message_vibro_on, + &message_delay_100, + &message_vibro_off, + &message_red_0, + NULL, +}; + +static const uint8_t desktop_helpers_fails_timeout[] = { + 0, + 0, + 0, + 0, + 30, + 60, + 90, + 120, + 150, + 180, + /* +60 for every next fail */ +}; + +static uint32_t desktop_pin_code_pack(const DesktopPinCode* pin_code) { + furi_check(pin_code); + furi_check(pin_code->length <= sizeof(pin_code->data)); + + uint32_t reg_value = 0; + + for(uint8_t i = 0; i < pin_code->length; ++i) { + furi_check(pin_code->data[i] < (1 << DESKTOP_PIN_CODE_DIGIT_BIT_WIDTH)); + reg_value |= (uint32_t)pin_code->data[i] << (i * DESKTOP_PIN_CODE_DIGIT_BIT_WIDTH); + } + + reg_value |= (uint32_t)pin_code->length << DESKTOP_PIN_CODE_LENGTH_OFFSET; + + return reg_value; +} + +bool desktop_pin_code_is_set(void) { + return furi_hal_rtc_get_pin_value() >> DESKTOP_PIN_CODE_LENGTH_OFFSET; +} + +void desktop_pin_code_set(const DesktopPinCode* pin_code) { + furi_hal_rtc_set_pin_value(desktop_pin_code_pack(pin_code)); +} + +void desktop_pin_code_reset(void) { + furi_hal_rtc_set_pin_value(0); +} + +bool desktop_pin_code_check(const DesktopPinCode* pin_code) { + return furi_hal_rtc_get_pin_value() == desktop_pin_code_pack(pin_code); +} + +bool desktop_pin_code_is_equal(const DesktopPinCode* pin_code1, const DesktopPinCode* pin_code2) { + furi_check(pin_code1); + furi_check(pin_code1->length <= sizeof(pin_code1->data)); + furi_check(pin_code2); + furi_check(pin_code2->length <= sizeof(pin_code2->data)); + + return pin_code1->length == pin_code2->length && + memcmp(pin_code1->data, pin_code2->data, pin_code1->length) == 0; +} + +void desktop_pin_lock_error_notify(void) { + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message(notification, &sequence_pin_fail); + furi_record_close(RECORD_NOTIFICATION); +} + +uint32_t desktop_pin_lock_get_fail_timeout(void) { + uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); + uint32_t pin_timeout = 0; + uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; + if(pin_fails <= max_index) { + pin_timeout = desktop_helpers_fails_timeout[pin_fails]; + } else { + pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; + } + + return pin_timeout; +} diff --git a/applications/services/desktop/helpers/pin_code.h b/applications/services/desktop/helpers/pin_code.h new file mode 100644 index 000000000..848c915b6 --- /dev/null +++ b/applications/services/desktop/helpers/pin_code.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#define DESKTOP_PIN_CODE_MAX_LEN (10) + +typedef struct { + uint8_t data[DESKTOP_PIN_CODE_MAX_LEN]; + uint8_t length; +} DesktopPinCode; + +bool desktop_pin_code_is_set(void); + +void desktop_pin_code_set(const DesktopPinCode* pin_code); + +void desktop_pin_code_reset(void); + +bool desktop_pin_code_check(const DesktopPinCode* pin_code); + +bool desktop_pin_code_is_equal(const DesktopPinCode* pin_code1, const DesktopPinCode* pin_code2); + +void desktop_pin_lock_error_notify(void); + +uint32_t desktop_pin_lock_get_fail_timeout(void); diff --git a/applications/services/desktop/scenes/desktop_scene_i.h b/applications/services/desktop/scenes/desktop_scene_i.h deleted file mode 100644 index f481733ac..000000000 --- a/applications/services/desktop/scenes/desktop_scene_i.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#define SCENE_LOCKED_FIRST_ENTER 0 -#define SCENE_LOCKED_REPEAT_ENTER 1 diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index 5951a8e4e..5ca95c4c5 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -20,7 +20,6 @@ void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) { void desktop_scene_lock_menu_on_enter(void* context) { Desktop* desktop = (Desktop*)context; - DESKTOP_SETTINGS_LOAD(&desktop->settings); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); @@ -38,11 +37,8 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeTick) { bool check_pin_changed = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); - if(check_pin_changed) { - DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.pin_code.length > 0) { - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); - } + if(check_pin_changed && desktop_pin_code_is_set()) { + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); } } else if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { diff --git a/applications/services/desktop/scenes/desktop_scene_locked.c b/applications/services/desktop/scenes/desktop_scene_locked.c index 846b2b541..e7eeebca6 100644 --- a/applications/services/desktop/scenes/desktop_scene_locked.c +++ b/applications/services/desktop/scenes/desktop_scene_locked.c @@ -6,12 +6,12 @@ #include "../desktop.h" #include "../desktop_i.h" -#include "../helpers/pin.h" +#include "../helpers/pin_code.h" #include "../animations/animation_manager.h" #include "../views/desktop_events.h" #include "../views/desktop_view_locked.h" #include "desktop_scene.h" -#include "desktop_scene_i.h" +#include "desktop_scene_locked.h" #define WRONG_PIN_HEADER_TIMEOUT 3000 #define INPUT_PIN_VIEW_TIMEOUT 15000 @@ -42,15 +42,13 @@ void desktop_scene_locked_on_enter(void* context) { bool switch_to_timeout_scene = false; uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked); - if(state == SCENE_LOCKED_FIRST_ENTER) { - bool pin_locked = desktop->settings.pin_code.length > 0; + if(state == DesktopSceneLockedStateFirstEnter) { view_port_enabled_set(desktop->lock_icon_viewport, true); Gui* gui = furi_record_open(RECORD_GUI); gui_set_lockdown(gui, true); furi_record_close(RECORD_GUI); - if(pin_locked) { - DESKTOP_SETTINGS_LOAD(&desktop->settings); + if(desktop_pin_code_is_set()) { desktop_view_locked_lock(desktop->locked_view, true); uint32_t pin_timeout = desktop_pin_lock_get_fail_timeout(); if(pin_timeout > 0) { @@ -65,7 +63,7 @@ void desktop_scene_locked_on_enter(void* context) { desktop_view_locked_close_doors(desktop->locked_view); } scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_REPEAT_ENTER); + desktop->scene_manager, DesktopSceneLocked, DesktopSceneLockedStateRepeatEnter); } if(switch_to_timeout_scene) { diff --git a/applications/services/desktop/scenes/desktop_scene_locked.h b/applications/services/desktop/scenes/desktop_scene_locked.h new file mode 100644 index 000000000..7d5b6b7bc --- /dev/null +++ b/applications/services/desktop/scenes/desktop_scene_locked.h @@ -0,0 +1,6 @@ +#pragma once + +typedef enum { + DesktopSceneLockedStateFirstEnter, + DesktopSceneLockedStateRepeatEnter, +} DesktopSceneLockedState; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 5cc2033c3..25c100ed7 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -155,25 +155,21 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } case DesktopMainEventOpenFavoriteLeftShort: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppLeftShort]); consumed = true; break; case DesktopMainEventOpenFavoriteLeftLong: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppLeftLong]); consumed = true; break; case DesktopMainEventOpenFavoriteRightShort: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppRightShort]); consumed = true; break; case DesktopMainEventOpenFavoriteRightLong: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppRightLong]); consumed = true; @@ -189,7 +185,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopAnimationEventInteractAnimation: if(!animation_manager_interact_process(desktop->animation_manager)) { - DESKTOP_SETTINGS_LOAD(&desktop->settings); if(!desktop->settings.dummy_mode) { desktop_scene_main_open_app_or_profile( desktop, &desktop->settings.favorite_apps[FavoriteAppRightShort]); diff --git a/applications/services/desktop/scenes/desktop_scene_pin_input.c b/applications/services/desktop/scenes/desktop_scene_pin_input.c index 6f5bfe8cb..449dd97f1 100644 --- a/applications/services/desktop/scenes/desktop_scene_pin_input.c +++ b/applications/services/desktop/scenes/desktop_scene_pin_input.c @@ -10,7 +10,7 @@ #include "../desktop_i.h" #include "../views/desktop_events.h" #include "../views/desktop_view_pin_input.h" -#include "../helpers/pin.h" +#include "../helpers/pin_code.h" #include "desktop_scene.h" #define WRONG_PIN_HEADER_TIMEOUT 3000 @@ -49,10 +49,12 @@ static void desktop_scene_pin_input_back_callback(void* context) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventBack); } -static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) { +static void desktop_scene_pin_input_done_callback(const DesktopPinCode* pin_code, void* context) { Desktop* desktop = (Desktop*)context; - if(desktop_pin_compare(&desktop->settings.pin_code, pin_code)) { + + if(desktop_pin_code_check(pin_code)) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked); + } else { uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); furi_hal_rtc_set_pin_fails(pin_fails + 1); diff --git a/applications/services/desktop/scenes/desktop_scene_slideshow.c b/applications/services/desktop/scenes/desktop_scene_slideshow.c index 012aff751..759924116 100644 --- a/applications/services/desktop/scenes/desktop_scene_slideshow.c +++ b/applications/services/desktop/scenes/desktop_scene_slideshow.c @@ -45,9 +45,6 @@ bool desktop_scene_slideshow_on_event(void* context, SceneManagerEvent event) { } void desktop_scene_slideshow_on_exit(void* context) { - UNUSED(context); - - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_remove(storage, SLIDESHOW_FS_PATH); - furi_record_close(RECORD_STORAGE); + Desktop* desktop = context; + storage_common_remove(desktop->storage, SLIDESHOW_FS_PATH); } diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index c22b19acc..ba91a30cc 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -60,4 +60,6 @@ typedef enum { DesktopGlobalAfterAppFinished, DesktopGlobalAutoLock, DesktopGlobalApiUnlock, + DesktopGlobalSaveSettings, + DesktopGlobalReloadSettings, } DesktopEvent; diff --git a/applications/services/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c index 965b5cceb..c89a143c8 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -6,7 +6,6 @@ #include #include "desktop_view_pin_input.h" -#include #define NO_ACTIVITY_TIMEOUT 15000 @@ -14,6 +13,9 @@ #define DEFAULT_PIN_X 64 #define DEFAULT_PIN_Y 32 +#define MIN_PIN_LENGTH 4 +#define MAX_PIN_LENGTH DESKTOP_PIN_CODE_MAX_LEN + struct DesktopViewPinInput { View* view; DesktopViewPinInputCallback back_callback; @@ -24,7 +26,7 @@ struct DesktopViewPinInput { }; typedef struct { - PinCode pin; + DesktopPinCode pin; bool pin_hidden; bool locked_input; uint8_t pin_x; @@ -50,7 +52,7 @@ static bool desktop_view_pin_input_input(InputEvent* event, void* context) { bool call_back_callback = false; bool call_done_callback = false; - PinCode pin_code = {0}; + DesktopPinCode pin_code = {0}; if(event->type == InputTypeShort) { switch(event->key) { @@ -59,13 +61,13 @@ static bool desktop_view_pin_input_input(InputEvent* event, void* context) { case InputKeyDown: case InputKeyUp: if(!model->locked_input) { - if(model->pin.length < MAX_PIN_SIZE) { + if(model->pin.length < MAX_PIN_LENGTH) { model->pin.data[model->pin.length++] = event->key; } } break; case InputKeyOk: - if(model->pin.length >= MIN_PIN_SIZE) { + if(model->pin.length >= MIN_PIN_LENGTH) { call_done_callback = true; pin_code = model->pin; } @@ -102,7 +104,7 @@ static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInpu furi_assert(model); uint8_t draw_pin_size = MAX(4, model->pin.length + 1); - if(model->locked_input || (model->pin.length == MAX_PIN_SIZE)) { + if(model->locked_input || (model->pin.length == MAX_PIN_LENGTH)) { draw_pin_size = model->pin.length; } @@ -155,7 +157,7 @@ static void desktop_view_pin_input_draw(Canvas* canvas, void* context) { canvas_draw_str(canvas, 16, 60, "= clear"); } - if(model->button_label && ((model->pin.length >= MIN_PIN_SIZE) || model->locked_input)) { + if(model->button_label && ((model->pin.length >= MIN_PIN_LENGTH) || model->locked_input)) { elements_button_center(canvas, model->button_label); } @@ -247,7 +249,7 @@ void desktop_view_pin_input_unlock_input(DesktopViewPinInput* pin_input) { view_commit_model(pin_input->view, true); } -void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin) { +void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const DesktopPinCode* pin) { furi_assert(pin_input); furi_assert(pin); diff --git a/applications/services/desktop/views/desktop_view_pin_input.h b/applications/services/desktop/views/desktop_view_pin_input.h index c430aff9f..4605b6ff1 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.h +++ b/applications/services/desktop/views/desktop_view_pin_input.h @@ -1,16 +1,17 @@ #pragma once #include -#include + +#include "../helpers/pin_code.h" typedef void (*DesktopViewPinInputCallback)(void*); -typedef void (*DesktopViewPinInputDoneCallback)(const PinCode* pin_code, void*); +typedef void (*DesktopViewPinInputDoneCallback)(const DesktopPinCode* pin_code, void*); typedef struct DesktopViewPinInput DesktopViewPinInput; DesktopViewPinInput* desktop_view_pin_input_alloc(void); void desktop_view_pin_input_free(DesktopViewPinInput*); -void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin); +void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const DesktopPinCode* pin_code); void desktop_view_pin_input_reset_pin(DesktopViewPinInput* pin_input); void desktop_view_pin_input_hide_pin(DesktopViewPinInput* pin_input, bool pin_hidden); void desktop_view_pin_input_set_label_button(DesktopViewPinInput* pin_input, const char* label); diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 95982f1af..198c1483a 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -1,6 +1,7 @@ #include "dolphin_i.h" #include +#include #define TAG "Dolphin" @@ -223,6 +224,10 @@ static bool dolphin_process_event(FuriMessageQueue* queue, void* context) { dolphin_state_increase_level(dolphin->state); furi_event_loop_timer_start(dolphin->flush_timer, FLUSH_TIMEOUT_TICKS); + } else if(event.type == DolphinEventTypeReloadState) { + dolphin_state_load(dolphin->state); + furi_event_loop_timer_start(dolphin->butthurt_timer, BUTTHURT_INCREASE_PERIOD_TICKS); + } else { furi_crash(); } @@ -232,6 +237,32 @@ static bool dolphin_process_event(FuriMessageQueue* queue, void* context) { return true; } +static void dolphin_storage_callback(const void* message, void* context) { + furi_assert(context); + Dolphin* dolphin = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + DolphinEvent event = { + .type = DolphinEventTypeReloadState, + }; + + dolphin_event_send_async(dolphin, &event); + } +} + +static void dolphin_init_state(Dolphin* dolphin) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), dolphin_storage_callback, dolphin); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping state"); + return; + } + + dolphin_state_load(dolphin->state); +} + // Application thread int32_t dolphin_srv(void* p) { @@ -247,7 +278,7 @@ int32_t dolphin_srv(void* p) { Dolphin* dolphin = dolphin_alloc(); furi_record_create(RECORD_DOLPHIN, dolphin); - dolphin_state_load(dolphin->state); + dolphin_init_state(dolphin); furi_event_loop_message_queue_subscribe( dolphin->event_loop, diff --git a/applications/services/dolphin/dolphin_i.h b/applications/services/dolphin/dolphin_i.h index d4add808a..6a6b3dfd8 100644 --- a/applications/services/dolphin/dolphin_i.h +++ b/applications/services/dolphin/dolphin_i.h @@ -12,6 +12,7 @@ typedef enum { DolphinEventTypeStats, DolphinEventTypeFlush, DolphinEventTypeLevel, + DolphinEventTypeReloadState, } DolphinEventType; typedef struct { diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index 5216b961d..5cbc51145 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -1,11 +1,10 @@ #include "dolphin_state.h" -#include "dolphin/helpers/dolphin_deed.h" #include "dolphin_state_filename.h" -#include -#include #include #include + +#include #include #define TAG "DolphinState" @@ -26,29 +25,28 @@ void dolphin_state_free(DolphinState* dolphin_state) { free(dolphin_state); } -bool dolphin_state_save(DolphinState* dolphin_state) { +void dolphin_state_save(DolphinState* dolphin_state) { if(!dolphin_state->dirty) { - return true; + return; } - bool result = saved_struct_save( + bool success = saved_struct_save( DOLPHIN_STATE_PATH, &dolphin_state->data, sizeof(DolphinStoreData), DOLPHIN_STATE_HEADER_MAGIC, DOLPHIN_STATE_HEADER_VERSION); - if(result) { + if(success) { FURI_LOG_I(TAG, "State saved"); dolphin_state->dirty = false; + } else { FURI_LOG_E(TAG, "Failed to save state"); } - - return result; } -bool dolphin_state_load(DolphinState* dolphin_state) { +void dolphin_state_load(DolphinState* dolphin_state) { bool success = saved_struct_load( DOLPHIN_STATE_PATH, &dolphin_state->data, @@ -64,12 +62,12 @@ bool dolphin_state_load(DolphinState* dolphin_state) { } if(!success) { - FURI_LOG_W(TAG, "Reset dolphin-state"); - memset(dolphin_state, 0, sizeof(*dolphin_state)); - dolphin_state->dirty = true; - } + FURI_LOG_W(TAG, "Reset Dolphin state"); + memset(dolphin_state, 0, sizeof(DolphinState)); - return success; + dolphin_state->dirty = true; + dolphin_state_save(dolphin_state); + } } uint64_t dolphin_state_timestamp(void) { diff --git a/applications/services/dolphin/helpers/dolphin_state.h b/applications/services/dolphin/helpers/dolphin_state.h index a8d8406be..bdbd98d47 100644 --- a/applications/services/dolphin/helpers/dolphin_state.h +++ b/applications/services/dolphin/helpers/dolphin_state.h @@ -1,9 +1,9 @@ #pragma once -#include "dolphin_deed.h" #include #include -#include + +#include "dolphin_deed.h" typedef struct DolphinState DolphinState; typedef struct { @@ -25,9 +25,9 @@ DolphinState* dolphin_state_alloc(void); void dolphin_state_free(DolphinState* dolphin_state); -bool dolphin_state_save(DolphinState* dolphin_state); +void dolphin_state_save(DolphinState* dolphin_state); -bool dolphin_state_load(DolphinState* dolphin_state); +void dolphin_state_load(DolphinState* dolphin_state); void dolphin_state_clear_limits(DolphinState* dolphin_state); diff --git a/applications/services/expansion/expansion.c b/applications/services/expansion/expansion.c index 9b0b31cf7..4731cb244 100644 --- a/applications/services/expansion/expansion.c +++ b/applications/services/expansion/expansion.c @@ -4,6 +4,7 @@ #include #include +#include #include #include "expansion_worker.h" @@ -25,6 +26,7 @@ typedef enum { ExpansionMessageTypeEnable, ExpansionMessageTypeDisable, ExpansionMessageTypeSetListenSerial, + ExpansionMessageTypeReloadSettings, ExpansionMessageTypeModuleConnected, ExpansionMessageTypeModuleDisconnected, ExpansionMessageTypeConnectionEstablished, @@ -103,7 +105,10 @@ static void return; } - if(instance->settings.uart_index < FuriHalSerialIdMax) { + ExpansionSettings settings; + expansion_settings_load(&settings); + + if(settings.uart_index < FuriHalSerialIdMax) { instance->state = ExpansionStateEnabled; instance->serial_id = instance->settings.uart_index; furi_hal_serial_control_set_expansion_callback( @@ -116,7 +121,6 @@ static void static void expansion_control_handler_disable(Expansion* instance, const ExpansionMessageData* data) { UNUSED(data); - if(instance->state == ExpansionStateDisabled) { return; } else if( @@ -136,10 +140,10 @@ static void static void expansion_control_handler_set_listen_serial( Expansion* instance, const ExpansionMessageData* data) { - furi_check(data->serial_id < FuriHalSerialIdMax); + if(instance->state != ExpansionStateDisabled && instance->serial_id == data->serial_id) { + return; - if(instance->state == ExpansionStateRunning || - instance->state == ExpansionStateConnectionEstablished) { + } else if(instance->state == ExpansionStateRunning) { expansion_worker_stop(instance->worker); expansion_worker_free(instance->worker); @@ -156,6 +160,26 @@ static void expansion_control_handler_set_listen_serial( FURI_LOG_D(TAG, "Listen serial changed to %s", expansion_uart_names[instance->serial_id]); } +static void expansion_control_handler_reload_settings( + Expansion* instance, + const ExpansionMessageData* data) { + UNUSED(data); + + ExpansionSettings settings; + expansion_settings_load(&settings); + + if(settings.uart_index < FuriHalSerialIdMax) { + const ExpansionMessageData data = { + .serial_id = settings.uart_index, + }; + + expansion_control_handler_set_listen_serial(instance, &data); + + } else { + expansion_control_handler_disable(instance, NULL); + } +} + static void expansion_control_handler_module_connected( Expansion* instance, const ExpansionMessageData* data) { @@ -211,6 +235,7 @@ static const ExpansionControlHandler expansion_control_handlers[] = { [ExpansionMessageTypeEnable] = expansion_control_handler_enable, [ExpansionMessageTypeDisable] = expansion_control_handler_disable, [ExpansionMessageTypeSetListenSerial] = expansion_control_handler_set_listen_serial, + [ExpansionMessageTypeReloadSettings] = expansion_control_handler_reload_settings, [ExpansionMessageTypeModuleConnected] = expansion_control_handler_module_connected, [ExpansionMessageTypeModuleDisconnected] = expansion_control_handler_module_disconnected, [ExpansionMessageTypeConnectionEstablished] = expansion_control_handler_connection_established, @@ -249,6 +274,22 @@ static Expansion* expansion_alloc(void) { return instance; } +static void expansion_storage_callback(const void* message, void* context) { + furi_assert(context); + + const StorageEvent* event = message; + Expansion* instance = context; + + if(event->type == StorageEventTypeCardMount) { + ExpansionMessage em = { + .type = ExpansionMessageTypeReloadSettings, + .api_lock = NULL, + }; + + furi_check(furi_message_queue_put(instance->queue, &em, FuriWaitForever) == FuriStatusOk); + } +} + void expansion_on_system_start(void* arg) { UNUSED(arg); @@ -256,7 +297,14 @@ void expansion_on_system_start(void* arg) { furi_record_create(RECORD_EXPANSION, instance); furi_thread_start(instance->thread); - expansion_settings_load(&instance->settings); + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), expansion_storage_callback, instance); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + expansion_enable(instance); } diff --git a/applications/services/expansion/expansion_settings.c b/applications/services/expansion/expansion_settings.c index c00b8fe24..061d630a7 100644 --- a/applications/services/expansion/expansion_settings.c +++ b/applications/services/expansion/expansion_settings.c @@ -6,29 +6,40 @@ #include "expansion_settings_filename.h" +#define TAG "ExpansionSettings" + #define EXPANSION_SETTINGS_PATH INT_PATH(EXPANSION_SETTINGS_FILE_NAME) #define EXPANSION_SETTINGS_VERSION (0) #define EXPANSION_SETTINGS_MAGIC (0xEA) -bool expansion_settings_load(ExpansionSettings* settings) { +void expansion_settings_load(ExpansionSettings* settings) { furi_assert(settings); - if(!saved_struct_load( - EXPANSION_SETTINGS_PATH, - settings, - sizeof(ExpansionSettings), - EXPANSION_SETTINGS_MAGIC, - EXPANSION_SETTINGS_VERSION)) { - settings->uart_index = FuriHalSerialIdMax; - } - return true; -} -bool expansion_settings_save(const ExpansionSettings* settings) { - furi_assert(settings); - return saved_struct_save( + const bool success = saved_struct_load( EXPANSION_SETTINGS_PATH, settings, sizeof(ExpansionSettings), EXPANSION_SETTINGS_MAGIC, EXPANSION_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load file, using defaults"); + memset(settings, 0, sizeof(ExpansionSettings)); + expansion_settings_save(settings); + } +} + +void expansion_settings_save(const ExpansionSettings* settings) { + furi_assert(settings); + + const bool success = saved_struct_save( + EXPANSION_SETTINGS_PATH, + settings, + sizeof(ExpansionSettings), + EXPANSION_SETTINGS_MAGIC, + EXPANSION_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save file"); + } } diff --git a/applications/services/expansion/expansion_settings.h b/applications/services/expansion/expansion_settings.h index 38e9f8d02..4594918e3 100644 --- a/applications/services/expansion/expansion_settings.h +++ b/applications/services/expansion/expansion_settings.h @@ -25,18 +25,16 @@ typedef struct { /** * @brief Load expansion module support settings from file. * - * @param[out] settings pointer to an ExpansionSettings instance to load settings into. - * @returns true if the settings were successfully loaded, false otherwise. + * @param[in,out] settings pointer to an ExpansionSettings instance to load settings into. */ -bool expansion_settings_load(ExpansionSettings* settings); +void expansion_settings_load(ExpansionSettings* settings); /** * @brief Save expansion module support settings to file. * * @param[in] settings pointer to an ExpansionSettings instance to save settings from. - * @returns true if the settings were successfully saved, false otherwise. */ -bool expansion_settings_save(const ExpansionSettings* settings); +void expansion_settings_save(const ExpansionSettings* settings); #ifdef __cplusplus } diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 7092e15da..bcd43b45a 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -15,7 +15,7 @@ #define TAG "BrowserWorker" #define ASSETS_DIR "assets" -#define BROWSER_ROOT STORAGE_ANY_PATH_PREFIX +#define BROWSER_ROOT STORAGE_EXT_PATH_PREFIX #define FILE_NAME_LEN_MAX 256 #define LONG_LOAD_THRESHOLD 100 diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index d4c5b91c8..35d2fe675 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -438,7 +438,7 @@ static bool notification_load_settings(NotificationApp* app) { File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); const size_t settings_size = sizeof(NotificationSettings); - FURI_LOG_I(TAG, "loading settings from \"%s\"", NOTIFICATION_SETTINGS_PATH); + FURI_LOG_I(TAG, "Loading \"%s\"", NOTIFICATION_SETTINGS_PATH); bool fs_result = storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); @@ -451,8 +451,6 @@ static bool notification_load_settings(NotificationApp* app) { } if(fs_result) { - FURI_LOG_I(TAG, "load success"); - if(settings.version != NOTIFICATION_SETTINGS_VERSION) { FURI_LOG_E( TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); @@ -462,7 +460,7 @@ static bool notification_load_settings(NotificationApp* app) { furi_kernel_unlock(); } } else { - FURI_LOG_E(TAG, "load failed, %s", storage_file_get_error_desc(file)); + FURI_LOG_E(TAG, "Load failed, %s", storage_file_get_error_desc(file)); } storage_file_close(file); @@ -477,7 +475,7 @@ static bool notification_save_settings(NotificationApp* app) { File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); const size_t settings_size = sizeof(NotificationSettings); - FURI_LOG_I(TAG, "saving settings to \"%s\"", NOTIFICATION_SETTINGS_PATH); + FURI_LOG_I(TAG, "Saving \"%s\"", NOTIFICATION_SETTINGS_PATH); furi_kernel_lock(); memcpy(&settings, &app->settings, settings_size); @@ -495,9 +493,8 @@ static bool notification_save_settings(NotificationApp* app) { } if(fs_result) { - FURI_LOG_I(TAG, "save success"); } else { - FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); + FURI_LOG_E(TAG, "Save failed, %s", storage_file_get_error_desc(file)); } storage_file_close(file); @@ -556,14 +553,46 @@ static NotificationApp* notification_app_alloc(void) { return app; } +static void notification_storage_callback(const void* message, void* context) { + furi_assert(context); + NotificationApp* app = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + NotificationAppMessage m = { + .type = LoadSettingsMessage, + }; + + furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); + } +} + +static void notification_apply_settings(NotificationApp* app) { + if(!notification_load_settings(app)) { + notification_save_settings(app); + } + + notification_apply_lcd_contrast(app); +} + +static void notification_init_settings(NotificationApp* app) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), notification_storage_callback, app); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + + notification_apply_settings(app); +} + // App int32_t notification_srv(void* p) { UNUSED(p); NotificationApp* app = notification_app_alloc(); - if(!notification_load_settings(app)) { - notification_save_settings(app); - } + notification_init_settings(app); notification_vibro_off(); notification_sound_off(); @@ -571,7 +600,6 @@ int32_t notification_srv(void* p) { notification_apply_internal_led_layer(&app->led[0], 0x00); notification_apply_internal_led_layer(&app->led[1], 0x00); notification_apply_internal_led_layer(&app->led[2], 0x00); - notification_apply_lcd_contrast(app); furi_record_create(RECORD_NOTIFICATION, app); @@ -589,6 +617,9 @@ int32_t notification_srv(void* p) { case SaveSettingsMessage: notification_save_settings(app); break; + case LoadSettingsMessage: + notification_load_settings(app); + break; } if(message.back_event != NULL) { diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 434773f2e..e19546574 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -11,6 +11,7 @@ typedef enum { NotificationLayerMessage, InternalLayerMessage, SaveSettingsMessage, + LoadSettingsMessage, } NotificationAppMessageType; typedef struct { diff --git a/applications/services/region/application.fam b/applications/services/region/application.fam new file mode 100644 index 000000000..a4cdc94ea --- /dev/null +++ b/applications/services/region/application.fam @@ -0,0 +1,10 @@ +App( + appid="region", + name="RegionSrv", + apptype=FlipperAppType.STARTUP, + targets=["f7"], + entry_point="region_on_system_start", + cdefines=["SRV_REGION"], + requires=["storage"], + order=170, +) diff --git a/applications/services/region/region.c b/applications/services/region/region.c new file mode 100644 index 000000000..dffcc6b2d --- /dev/null +++ b/applications/services/region/region.c @@ -0,0 +1,147 @@ +#include + +#include +#include + +#include +#include + +#define TAG "RegionSrv" + +#define SUBGHZ_REGION_FILENAME INT_PATH(".region_data") + +static bool region_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { + File* file = istream->state; + size_t ret = storage_file_read(file, buf, count); + return count == ret; +} + +static bool region_istream_decode_band(pb_istream_t* stream, const pb_field_t* field, void** arg) { + UNUSED(field); + + FuriHalRegion* region = *arg; + + PB_Region_Band band = {0}; + if(!pb_decode(stream, PB_Region_Band_fields, &band)) { + FURI_LOG_E(TAG, "PB Region band decode error: %s", PB_GET_ERROR(stream)); + return false; + } + + region->bands_count += 1; + region = realloc( //-V701 + region, + sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); + size_t pos = region->bands_count - 1; + region->bands[pos].start = band.start; + region->bands[pos].end = band.end; + region->bands[pos].power_limit = band.power_limit; + region->bands[pos].duty_cycle = band.duty_cycle; + *arg = region; + + FURI_LOG_I( + TAG, + "Add allowed band: start %luHz, stop %luHz, power_limit %ddBm, duty_cycle %u%%", + band.start, + band.end, + band.power_limit, + band.duty_cycle); + return true; +} + +static int32_t region_load_file(void* context) { + UNUSED(context); + + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + + PB_Region pb_region = {0}; + pb_region.bands.funcs.decode = region_istream_decode_band; + + do { + FileInfo fileinfo = {0}; + + if(storage_common_stat(storage, SUBGHZ_REGION_FILENAME, &fileinfo) != FSE_OK || + fileinfo.size == 0) { + FURI_LOG_W(TAG, "Region file missing or empty"); + break; + + } else if(!storage_file_open(file, SUBGHZ_REGION_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "Failed to open region file"); + break; + } + + pb_istream_t istream = { + .callback = region_istream_read, + .state = file, + .errmsg = NULL, + .bytes_left = fileinfo.size, + }; + + pb_region.bands.arg = malloc(sizeof(FuriHalRegion)); + + if(!pb_decode(&istream, PB_Region_fields, &pb_region)) { + FURI_LOG_E(TAG, "Failed to decode region file"); + free(pb_region.bands.arg); + break; + } + + FuriHalRegion* region = pb_region.bands.arg; + + memcpy( + region->country_code, + pb_region.country_code->bytes, + MIN(pb_region.country_code->size, sizeof(region->country_code) - 1)); + + furi_hal_region_set(region); + + FURI_LOG_I(TAG, "Dynamic region set: %s", region->country_code); + } while(0); + + pb_release(PB_Region_fields, &pb_region); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + return 0; +} + +static void region_loader_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); + + FuriThread* loader = context; + furi_thread_join(loader); + furi_thread_free(loader); +} + +static void region_loader_state_callback(FuriThreadState state, void* context) { + UNUSED(context); + + if(state == FuriThreadStateStopped) { + furi_timer_pending_callback(region_loader_pending_callback, furi_thread_get_current(), 0); + } +} + +static void region_storage_callback(const void* message, void* context) { + UNUSED(context); + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + FuriThread* loader = furi_thread_alloc_ex(NULL, 2048, region_load_file, NULL); + furi_thread_set_state_callback(loader, region_loader_state_callback); + furi_thread_start(loader); + } +} + +int32_t region_on_system_start(void* p) { + UNUSED(p); + + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), region_storage_callback, NULL); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping dynamic region"); + return 0; + } + + region_load_file(NULL); + return 0; +} diff --git a/applications/services/storage/storage.c b/applications/services/storage/storage.c index 21f8789ce..bfe2a08b2 100644 --- a/applications/services/storage/storage.c +++ b/applications/services/storage/storage.c @@ -3,7 +3,6 @@ #include "storage_message.h" #include "storage_processing.h" #include "storage/storage_glue.h" -#include "storages/storage_int.h" #include "storages/storage_ext.h" #include @@ -42,9 +41,6 @@ Storage* storage_app_alloc(void) { storage_data_timestamp(&app->storage[i]); } -#ifndef FURI_RAM_EXEC - storage_int_init(&app->storage[ST_INT]); -#endif storage_ext_init(&app->storage[ST_EXT]); // sd icon gui @@ -106,6 +102,11 @@ int32_t storage_srv(void* p) { Storage* app = storage_app_alloc(); furi_record_create(RECORD_STORAGE, app); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStorageFormatInternal)) { + FURI_LOG_W(TAG, "Format Internal not supported, clearing flag"); + furi_hal_rtc_reset_flag(FuriHalRtcFlagStorageFormatInternal); + } + StorageMessage message; while(1) { if(furi_message_queue_get(app->message_queue, &message, STORAGE_TICK) == FuriStatusOk) { diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index a4dffe633..6dbeb0d36 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -506,7 +506,7 @@ FS_Error storage_sd_status(Storage* storage); /******************* Internal LFS Functions *******************/ -typedef void (*Storage_name_converter)(FuriString*); +typedef void (*StorageNameConverter)(FuriString*); /** * @brief Back up the internal storage contents to a *.tar archive. @@ -526,7 +526,7 @@ FS_Error storage_int_backup(Storage* storage, const char* dstname); * @return FSE_OK if the storage was successfully restored, any other error code on failure. */ FS_Error - storage_int_restore(Storage* storage, const char* dstname, Storage_name_converter converter); + storage_int_restore(Storage* storage, const char* dstname, StorageNameConverter converter); /***************** Simplified Functions ******************/ diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index 918e796ce..17fd4eae4 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -33,7 +33,7 @@ static void storage_cli_info(Cli* cli, FuriString* path, FuriString* args) { storage_cli_print_error(error); } else { printf( - "Label: %s\r\nType: LittleFS\r\n%luKiB total\r\n%luKiB free\r\n", + "Label: %s\r\nType: Virtual\r\n%luKiB total\r\n%luKiB free\r\n", furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown", (uint32_t)(total_space / 1024), (uint32_t)(free_space / 1024)); diff --git a/applications/services/storage/storage_internal_api.c b/applications/services/storage/storage_internal_api.c index 4cbce7546..defab966c 100644 --- a/applications/services/storage/storage_internal_api.c +++ b/applications/services/storage/storage_internal_api.c @@ -14,7 +14,7 @@ FS_Error storage_int_backup(Storage* storage, const char* dstname) { } FS_Error - storage_int_restore(Storage* storage, const char* srcname, Storage_name_converter converter) { + storage_int_restore(Storage* storage, const char* srcname, StorageNameConverter converter) { furi_check(storage); TarArchive* archive = tar_archive_alloc(storage); diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 9e96765b6..564589930 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -2,6 +2,8 @@ #include #include +#define TAG "Storage" + #define STORAGE_PATH_PREFIX_LEN 4u _Static_assert( sizeof(STORAGE_ANY_PATH_PREFIX) == STORAGE_PATH_PREFIX_LEN + 1, @@ -60,36 +62,27 @@ static StorageType storage_get_type_by_path(FuriString* path) { 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) { - case ST_EXT: - furi_string_replace_at( - path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); - break; - case ST_INT: - furi_string_replace_at( - path, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_INT_PATH_PREFIX); - break; - default: - break; - } - } -} static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) { StorageType type = storage_get_type_by_path(path); if(storage_type_is_valid(type)) { + // Any storage phase-out: redirect "/any" to "/ext" if(type == ST_ANY) { - type = ST_INT; - if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) { - type = ST_EXT; - } - storage_path_change_to_real_storage(path, type); + FURI_LOG_W( + TAG, + STORAGE_ANY_PATH_PREFIX " is deprecated, use " STORAGE_EXT_PATH_PREFIX " instead"); + furi_string_replace_at( + path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); + type = ST_EXT; + } + + furi_assert(type == ST_EXT); + + if(storage_data_status(&app->storage[type]) != StorageStatusOK) { + return FSE_NOT_READY; } - furi_assert(type == ST_EXT || type == ST_INT); *storage = &app->storage[type]; return FSE_OK; @@ -559,6 +552,16 @@ void storage_process_alias( furi_string_get_cstr(apps_assets_path_with_appsid)); furi_string_free(apps_assets_path_with_appsid); + + } else if(furi_string_start_with(path, STORAGE_INT_PATH_PREFIX)) { + furi_string_replace_at( + path, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX "/.int"); + + FuriString* int_on_ext_path = furi_string_alloc_set(STORAGE_EXT_PATH_PREFIX "/.int"); + if(storage_process_common_stat(app, int_on_ext_path, NULL) != FSE_OK) { + storage_process_common_mkdir(app, int_on_ext_path); + } + furi_string_free(int_on_ext_path); } } diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c deleted file mode 100644 index 324ce6328..000000000 --- a/applications/services/storage/storages/storage_int.c +++ /dev/null @@ -1,744 +0,0 @@ -#include "storage_int.h" -#include -#include -#include - -#define TAG "StorageInt" - -#define STORAGE_PATH STORAGE_INT_PATH_PREFIX -#define LFS_CLEAN_FINGERPRINT 0 - -/* When less than LFS_RESERVED_PAGES_COUNT are left free, creation & - * modification of non-dot files is restricted */ -#define LFS_RESERVED_PAGES_COUNT 3 - -typedef struct { - const size_t start_address; - const size_t start_page; - struct lfs_config config; - lfs_t lfs; -} LFSData; - -typedef struct { - void* data; - bool open; -} LFSHandle; - -static LFSHandle* lfs_handle_alloc_file(void) { - LFSHandle* handle = malloc(sizeof(LFSHandle)); - handle->data = malloc(sizeof(lfs_file_t)); - return handle; -} - -static LFSHandle* lfs_handle_alloc_dir(void) { - LFSHandle* handle = malloc(sizeof(LFSHandle)); - handle->data = malloc(sizeof(lfs_dir_t)); - return handle; -} - -/* INTERNALS */ - -static lfs_dir_t* lfs_handle_get_dir(LFSHandle* handle) { - return handle->data; -} - -static lfs_file_t* lfs_handle_get_file(LFSHandle* handle) { - return handle->data; -} - -static void lfs_handle_free(LFSHandle* handle) { - free(handle->data); - free(handle); -} - -static void lfs_handle_set_open(LFSHandle* handle) { - handle->open = true; -} - -static bool lfs_handle_is_open(LFSHandle* handle) { - return handle->open; -} - -static lfs_t* lfs_get_from_storage(StorageData* storage) { - return &((LFSData*)storage->data)->lfs; -} - -static LFSData* lfs_data_get_from_storage(StorageData* storage) { - return (LFSData*)storage->data; -} - -static int storage_int_device_read( - const struct lfs_config* c, - lfs_block_t block, - lfs_off_t off, - void* buffer, - lfs_size_t size) { - LFSData* lfs_data = c->context; - size_t address = lfs_data->start_address + block * c->block_size + off; - - FURI_LOG_T( - TAG, - "Device read: block %lu, off %lu, buffer: %p, size %lu, translated address: %p", - block, - off, - buffer, - size, - (void*)address); - - memcpy(buffer, (void*)address, size); - - return 0; -} - -static int storage_int_device_prog( - const struct lfs_config* c, - lfs_block_t block, - lfs_off_t off, - const void* buffer, - lfs_size_t size) { - LFSData* lfs_data = c->context; - size_t address = lfs_data->start_address + block * c->block_size + off; - - FURI_LOG_T( - TAG, - "Device prog: block %lu, off %lu, buffer: %p, size %lu, translated address: %p", - block, - off, - buffer, - size, - (void*)address); - - int ret = 0; - while(size > 0) { - furi_hal_flash_write_dword(address, *(uint64_t*)buffer); - address += c->prog_size; - buffer += c->prog_size; - size -= c->prog_size; - } - - return ret; -} - -static int storage_int_device_erase(const struct lfs_config* c, lfs_block_t block) { - LFSData* lfs_data = c->context; - size_t page = lfs_data->start_page + block; - - FURI_LOG_D(TAG, "Device erase: page %lu, translated page: %zx", block, page); - - furi_hal_flash_erase(page); - return 0; -} - -static int storage_int_device_sync(const struct lfs_config* c) { - UNUSED(c); - FURI_LOG_D(TAG, "Device sync: skipping"); - return 0; -} - -static LFSData* storage_int_lfs_data_alloc(void) { - LFSData* lfs_data = malloc(sizeof(LFSData)); - - // Internal storage start address - *(size_t*)(&lfs_data->start_address) = furi_hal_flash_get_free_page_start_address(); - *(size_t*)(&lfs_data->start_page) = - (lfs_data->start_address - furi_hal_flash_get_base()) / furi_hal_flash_get_page_size(); - - // LFS configuration - // Glue and context - lfs_data->config.context = lfs_data; - lfs_data->config.read = storage_int_device_read; - lfs_data->config.prog = storage_int_device_prog; - lfs_data->config.erase = storage_int_device_erase; - lfs_data->config.sync = storage_int_device_sync; - - // Block device description - lfs_data->config.read_size = furi_hal_flash_get_read_block_size(); - lfs_data->config.prog_size = furi_hal_flash_get_write_block_size(); - lfs_data->config.block_size = furi_hal_flash_get_page_size(); - lfs_data->config.block_count = furi_hal_flash_get_free_page_count(); - lfs_data->config.block_cycles = furi_hal_flash_get_cycles_count(); - lfs_data->config.cache_size = 16; - lfs_data->config.lookahead_size = 16; - - return lfs_data; -} - -// Returns true if fingerprint was invalid and LFS reformatting is needed -static bool storage_int_check_and_set_fingerprint(LFSData* lfs_data) { - bool value = false; - - uint32_t os_fingerprint = 0; - os_fingerprint |= ((lfs_data->start_page & 0xFF) << 0); - os_fingerprint |= ((lfs_data->config.block_count & 0xFF) << 8); - os_fingerprint |= ((LFS_DISK_VERSION_MAJOR & 0xFFFF) << 16); - - uint32_t rtc_fingerprint = furi_hal_rtc_get_register(FuriHalRtcRegisterLfsFingerprint); - if(rtc_fingerprint == LFS_CLEAN_FINGERPRINT) { - FURI_LOG_I(TAG, "Storing LFS fingerprint in RTC"); - furi_hal_rtc_set_register(FuriHalRtcRegisterLfsFingerprint, os_fingerprint); - } else if(rtc_fingerprint != os_fingerprint) { - FURI_LOG_E(TAG, "LFS fingerprint mismatch"); - furi_hal_rtc_set_register(FuriHalRtcRegisterLfsFingerprint, os_fingerprint); - value = true; - } - - return value; -} - -static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { - int err; - lfs_t* lfs = &lfs_data->lfs; - - bool was_fingerprint_outdated = storage_int_check_and_set_fingerprint(lfs_data); - bool need_format = furi_hal_rtc_is_flag_set(FuriHalRtcFlagStorageFormatInternal) || - was_fingerprint_outdated; - - if(need_format) { - // Format storage - err = lfs_format(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Factory reset: Format successful, trying to mount"); - furi_hal_rtc_reset_flag(FuriHalRtcFlagStorageFormatInternal); - err = lfs_mount(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Factory reset: Mounted"); - storage->status = StorageStatusOK; - } else { - FURI_LOG_E(TAG, "Factory reset: Mount after format failed"); - storage->status = StorageStatusNotMounted; - } - } else { - FURI_LOG_E(TAG, "Factory reset: Format failed"); - storage->status = StorageStatusNoFS; - } - } else { - // Normal - err = lfs_mount(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Mounted"); - storage->status = StorageStatusOK; - } else { - FURI_LOG_E(TAG, "Mount failed, formatting"); - err = lfs_format(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Format successful, trying to mount"); - err = lfs_mount(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Mounted"); - storage->status = StorageStatusOK; - } else { - FURI_LOG_E(TAG, "Mount after format failed"); - storage->status = StorageStatusNotMounted; - } - } else { - FURI_LOG_E(TAG, "Format failed"); - storage->status = StorageStatusNoFS; - } - } - } -} - -/****************** Common Functions ******************/ - -static FS_Error storage_int_parse_error(int error) { - FS_Error result; - - if(error >= LFS_ERR_OK) { - result = FSE_OK; - } else { - switch(error) { - case LFS_ERR_NOENT: - result = FSE_NOT_EXIST; - break; - case LFS_ERR_EXIST: - result = FSE_EXIST; - break; - case LFS_ERR_NOTEMPTY: - result = FSE_DENIED; - break; - case LFS_ERR_INVAL: - case LFS_ERR_NOATTR: - result = FSE_INVALID_PARAMETER; - break; - case LFS_ERR_BADF: - case LFS_ERR_ISDIR: - case LFS_ERR_NOTDIR: - case LFS_ERR_NAMETOOLONG: - result = FSE_INVALID_NAME; - break; - case LFS_ERR_IO: - case LFS_ERR_FBIG: - case LFS_ERR_NOSPC: - case LFS_ERR_NOMEM: - case LFS_ERR_CORRUPT: - default: - result = FSE_INTERNAL; - } - } - - return result; -} - -/* Returns false if less than reserved space is left free */ -static bool storage_int_check_for_free_space(StorageData* storage) { - LFSData* lfs_data = lfs_data_get_from_storage(storage); - - lfs_ssize_t result = lfs_fs_size(lfs_get_from_storage(storage)); - if(result >= 0) { - lfs_size_t free_space = - (lfs_data->config.block_count - result) * lfs_data->config.block_size; - - return free_space > LFS_RESERVED_PAGES_COUNT * furi_hal_flash_get_page_size(); - } - - return false; -} -/******************* File Functions *******************/ - -static bool storage_int_file_open( - void* ctx, - File* file, - const char* path, - FS_AccessMode access_mode, - FS_OpenMode open_mode) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - - bool enough_free_space = storage_int_check_for_free_space(storage); - - int flags = 0; - - if(access_mode & FSAM_READ) flags |= LFS_O_RDONLY; - if(access_mode & FSAM_WRITE) flags |= LFS_O_WRONLY; - - if(open_mode & FSOM_OPEN_EXISTING) flags |= 0; - if(open_mode & FSOM_OPEN_ALWAYS) flags |= LFS_O_CREAT; - if(open_mode & FSOM_OPEN_APPEND) flags |= LFS_O_CREAT | LFS_O_APPEND; - if(open_mode & FSOM_CREATE_NEW) flags |= LFS_O_CREAT | LFS_O_EXCL; - if(open_mode & FSOM_CREATE_ALWAYS) flags |= LFS_O_CREAT | LFS_O_TRUNC; - - LFSHandle* handle = lfs_handle_alloc_file(); - storage_set_storage_file_data(file, handle, storage); - - if(!enough_free_space) { - FuriString* filename; - filename = furi_string_alloc(); - path_extract_basename(path, filename); - bool is_dot_file = - (!furi_string_empty(filename) && (furi_string_get_char(filename, 0) == '.')); - furi_string_free(filename); - - /* Restrict write & creation access to all non-dot files */ - if(!is_dot_file && (flags & (LFS_O_CREAT | LFS_O_WRONLY))) { - file->internal_error_id = LFS_ERR_NOSPC; - file->error_id = FSE_DENIED; - FURI_LOG_W(TAG, "Denied access to '%s': no free space", path); - return false; - } - } - - file->internal_error_id = lfs_file_open(lfs, lfs_handle_get_file(handle), path, flags); - - if(file->internal_error_id >= LFS_ERR_OK) { - lfs_handle_set_open(handle); - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - return file->error_id == FSE_OK; -} - -static bool storage_int_file_close(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_close(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - lfs_handle_free(handle); - return file->error_id == FSE_OK; -} - -static uint16_t - storage_int_file_read(void* ctx, File* file, void* buff, uint16_t const bytes_to_read) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - uint16_t bytes_read = 0; - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = - lfs_file_read(lfs, lfs_handle_get_file(handle), buff, bytes_to_read); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - if(file->error_id == FSE_OK) { - bytes_read = file->internal_error_id; - file->internal_error_id = 0; - } - return bytes_read; -} - -static uint16_t - storage_int_file_write(void* ctx, File* file, const void* buff, uint16_t const bytes_to_write) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - uint16_t bytes_written = 0; - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = - lfs_file_write(lfs, lfs_handle_get_file(handle), buff, bytes_to_write); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - if(file->error_id == FSE_OK) { - bytes_written = file->internal_error_id; - file->internal_error_id = 0; - } - return bytes_written; -} - -static bool - storage_int_file_seek(void* ctx, File* file, const uint32_t offset, const bool from_start) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - if(from_start) { - file->internal_error_id = - lfs_file_seek(lfs, lfs_handle_get_file(handle), offset, LFS_SEEK_SET); - } else { - file->internal_error_id = - lfs_file_seek(lfs, lfs_handle_get_file(handle), offset, LFS_SEEK_CUR); - } - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -static uint64_t storage_int_file_tell(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_tell(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - int32_t position = 0; - if(file->error_id == FSE_OK) { - position = file->internal_error_id; - file->internal_error_id = 0; - } - - return position; -} - -static bool storage_int_file_truncate(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_tell(lfs, lfs_handle_get_file(handle)); - file->error_id = storage_int_parse_error(file->internal_error_id); - - if(file->error_id == FSE_OK) { - uint32_t position = file->internal_error_id; - file->internal_error_id = - lfs_file_truncate(lfs, lfs_handle_get_file(handle), position); - file->error_id = storage_int_parse_error(file->internal_error_id); - } - } else { - file->internal_error_id = LFS_ERR_BADF; - file->error_id = storage_int_parse_error(file->internal_error_id); - } - - return file->error_id == FSE_OK; -} - -static bool storage_int_file_sync(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_sync(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -static uint64_t storage_int_file_size(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_size(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - uint32_t size = 0; - if(file->error_id == FSE_OK) { - size = file->internal_error_id; - file->internal_error_id = 0; - } - - return size; -} - -static bool storage_int_file_eof(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - bool eof = true; - - if(lfs_handle_is_open(handle)) { - int32_t position = lfs_file_tell(lfs, lfs_handle_get_file(handle)); - int32_t size = lfs_file_size(lfs, lfs_handle_get_file(handle)); - - if(position < 0) { - file->internal_error_id = position; - } else if(size < 0) { - file->internal_error_id = size; - } else { - file->internal_error_id = LFS_ERR_OK; - eof = (position >= size); - } - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return eof; -} - -/******************* Dir Functions *******************/ - -static bool storage_int_dir_open(void* ctx, File* file, const char* path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - - LFSHandle* handle = lfs_handle_alloc_dir(); - storage_set_storage_file_data(file, handle, storage); - - file->internal_error_id = lfs_dir_open(lfs, lfs_handle_get_dir(handle), path); - if(file->internal_error_id >= LFS_ERR_OK) { - lfs_handle_set_open(handle); - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -static bool storage_int_dir_close(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_dir_close(lfs, lfs_handle_get_dir(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - lfs_handle_free(handle); - return file->error_id == FSE_OK; -} - -static bool storage_int_dir_read( - void* ctx, - File* file, - FileInfo* fileinfo, - char* name, - const uint16_t name_length) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - struct lfs_info _fileinfo; - - // LFS returns virtual directories "." and "..", so we read until we get something meaningful or an empty string - do { - file->internal_error_id = lfs_dir_read(lfs, lfs_handle_get_dir(handle), &_fileinfo); - file->error_id = storage_int_parse_error(file->internal_error_id); - } while(strcmp(_fileinfo.name, ".") == 0 || strcmp(_fileinfo.name, "..") == 0); - - if(fileinfo != NULL) { - fileinfo->size = _fileinfo.size; - fileinfo->flags = 0; - if(_fileinfo.type & LFS_TYPE_DIR) fileinfo->flags |= FSF_DIRECTORY; - } - - if(name != NULL) { - snprintf(name, name_length, "%s", _fileinfo.name); - } - - // set FSE_NOT_EXIST error on end of directory - if(file->internal_error_id == 0) { - file->error_id = FSE_NOT_EXIST; - } - } else { - file->internal_error_id = LFS_ERR_BADF; - file->error_id = storage_int_parse_error(file->internal_error_id); - } - - return file->error_id == FSE_OK; -} - -static bool storage_int_dir_rewind(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_dir_rewind(lfs, lfs_handle_get_dir(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -/******************* Common FS Functions *******************/ - -static FS_Error storage_int_common_stat(void* ctx, const char* path, FileInfo* fileinfo) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - struct lfs_info _fileinfo; - int result = lfs_stat(lfs, path, &_fileinfo); - - if(fileinfo != NULL) { - fileinfo->size = _fileinfo.size; - fileinfo->flags = 0; - if(_fileinfo.type & LFS_TYPE_DIR) fileinfo->flags |= FSF_DIRECTORY; - } - - return storage_int_parse_error(result); -} - -static FS_Error storage_int_common_remove(void* ctx, const char* path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - int result = lfs_remove(lfs, path); - return storage_int_parse_error(result); -} - -static FS_Error storage_int_common_mkdir(void* ctx, const char* path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - int result = lfs_mkdir(lfs, path); - return storage_int_parse_error(result); -} - -static FS_Error storage_int_common_fs_info( - void* ctx, - const char* fs_path, - uint64_t* total_space, - uint64_t* free_space) { - UNUSED(fs_path); - StorageData* storage = ctx; - - lfs_t* lfs = lfs_get_from_storage(storage); - LFSData* lfs_data = lfs_data_get_from_storage(storage); - - if(total_space) { - *total_space = lfs_data->config.block_size * lfs_data->config.block_count; - } - - lfs_ssize_t result = lfs_fs_size(lfs); - if(free_space && (result >= 0)) { - *free_space = (lfs_data->config.block_count - result) * lfs_data->config.block_size; - } - - return storage_int_parse_error(result); -} - -static bool storage_int_common_equivalent_path(const char* path1, const char* path2) { - return strcmp(path1, path2) == 0; -} - -/******************* Init Storage *******************/ -static const FS_Api fs_api = { - .file = - { - .open = storage_int_file_open, - .close = storage_int_file_close, - .read = storage_int_file_read, - .write = storage_int_file_write, - .seek = storage_int_file_seek, - .tell = storage_int_file_tell, - .truncate = storage_int_file_truncate, - .size = storage_int_file_size, - .sync = storage_int_file_sync, - .eof = storage_int_file_eof, - }, - .dir = - { - .open = storage_int_dir_open, - .close = storage_int_dir_close, - .read = storage_int_dir_read, - .rewind = storage_int_dir_rewind, - }, - .common = - { - .stat = storage_int_common_stat, - .mkdir = storage_int_common_mkdir, - .remove = storage_int_common_remove, - .fs_info = storage_int_common_fs_info, - .equivalent_path = storage_int_common_equivalent_path, - }, -}; - -void storage_int_init(StorageData* storage) { - FURI_LOG_I(TAG, "Starting"); - LFSData* lfs_data = storage_int_lfs_data_alloc(); - FURI_LOG_I( - TAG, - "Config: start %p, read %lu, write %lu, page size: %lu, page count: %lu, cycles: %ld", - (void*)lfs_data->start_address, - lfs_data->config.read_size, - lfs_data->config.prog_size, - lfs_data->config.block_size, - lfs_data->config.block_count, - lfs_data->config.block_cycles); - - storage_int_lfs_mount(lfs_data, storage); - - storage->data = lfs_data; - storage->api.tick = NULL; - storage->fs_api = &fs_api; -} diff --git a/applications/services/storage/storages/storage_int.h b/applications/services/storage/storages/storage_int.h deleted file mode 100644 index 456d72408..000000000 --- a/applications/services/storage/storages/storage_int.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include -#include "../storage_glue.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void storage_int_init(StorageData* storage); - -#ifdef __cplusplus -} -#endif diff --git a/applications/settings/bt_settings_app/bt_settings_app.c b/applications/settings/bt_settings_app/bt_settings_app.c index d86c9df64..897282064 100644 --- a/applications/settings/bt_settings_app/bt_settings_app.c +++ b/applications/settings/bt_settings_app/bt_settings_app.c @@ -15,8 +15,6 @@ static bool bt_settings_back_event_callback(void* context) { BtSettingsApp* bt_settings_app_alloc(void) { BtSettingsApp* app = malloc(sizeof(BtSettingsApp)); - // Load settings - bt_settings_load(&app->settings); app->gui = furi_record_open(RECORD_GUI); app->bt = furi_record_open(RECORD_BT); @@ -48,6 +46,8 @@ BtSettingsApp* bt_settings_app_alloc(void) { view_dispatcher_add_view( app->view_dispatcher, BtSettingsAppViewPopup, popup_get_view(app->popup)); + bt_get_settings(app->bt, &app->settings); + // Set first scene scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart); return app; @@ -55,6 +55,7 @@ BtSettingsApp* bt_settings_app_alloc(void) { void bt_settings_app_free(BtSettingsApp* app) { furi_assert(app); + bt_set_settings(app->bt, &app->settings); // Gui modules view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList); variable_item_list_free(app->var_item_list); @@ -79,7 +80,6 @@ extern int32_t bt_settings_app(void* p) { UNUSED(p); BtSettingsApp* app = bt_settings_app_alloc(); view_dispatcher_run(app->view_dispatcher); - bt_settings_save(&app->settings); bt_settings_app_free(app); return 0; } diff --git a/applications/settings/bt_settings_app/bt_settings_app.h b/applications/settings/bt_settings_app/bt_settings_app.h index b79e36951..5255945ff 100644 --- a/applications/settings/bt_settings_app/bt_settings_app.h +++ b/applications/settings/bt_settings_app/bt_settings_app.h @@ -1,18 +1,21 @@ #pragma once #include -#include + #include #include #include #include -#include #include #include #include -#include +#include +#include + +#include + #include "scenes/bt_settings_scene.h" enum BtSettingsCustomEvent { diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c index 1d72a9e6f..a76740bd1 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c @@ -70,18 +70,17 @@ bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == BtSettingOn) { - furi_hal_bt_start_advertising(); app->settings.enabled = true; consumed = true; } else if(event.event == BtSettingOff) { app->settings.enabled = false; - furi_hal_bt_stop_advertising(); consumed = true; } else if(event.event == BtSettingsCustomEventForgetDevices) { scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevConfirm); consumed = true; } } + return consumed; } diff --git a/applications/settings/desktop_settings/desktop_settings_app.c b/applications/settings/desktop_settings/desktop_settings_app.c index 35ee2a3f1..b6f719f00 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.c +++ b/applications/settings/desktop_settings/desktop_settings_app.c @@ -5,9 +5,11 @@ #include #include +#include +#include + #include "desktop_settings_app.h" #include "scenes/desktop_settings_scene.h" -#include static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -131,18 +133,20 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { } extern int32_t desktop_settings_app(void* p) { - DesktopSettingsApp* app = desktop_settings_app_alloc(); - DESKTOP_SETTINGS_LOAD(&app->settings); + UNUSED(p); - if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) { - scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); - } else { - scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); - } + DesktopSettingsApp* app = desktop_settings_app_alloc(); + Desktop* desktop = furi_record_open(RECORD_DESKTOP); + + desktop_api_get_settings(desktop, &app->settings); + + scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); view_dispatcher_run(app->view_dispatcher); - DESKTOP_SETTINGS_SAVE(&app->settings); + desktop_api_set_settings(desktop, &app->settings); + furi_record_close(RECORD_DESKTOP); + desktop_settings_app_free(app); return 0; diff --git a/applications/settings/desktop_settings/desktop_settings_app.h b/applications/settings/desktop_settings/desktop_settings_app.h index 48adb9cfb..c9d765fd4 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.h +++ b/applications/settings/desktop_settings/desktop_settings_app.h @@ -40,7 +40,7 @@ typedef struct { DesktopSettingsViewPinSetupHowto* pin_setup_howto_view; DesktopSettingsViewPinSetupHowto2* pin_setup_howto2_view; - PinCode pincode_buffer; + DesktopPinCode pincode_buffer; bool pincode_buffer_filled; bool save_name; 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 ee6af0bd9..9f2dce3fc 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -194,19 +194,25 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e strncpy( curr_favorite_app->name_or_path, furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); + sizeof(curr_favorite_app->name_or_path)); consumed = true; } } else { size_t app_index = event.event - MAIN_LIST_APPLICATION_OFFSET; const char* name = favorite_fap_get_app_name(app_index); - if(name) strncpy(curr_favorite_app->name_or_path, name, MAX_APP_LENGTH); + if(name) + strncpy( + curr_favorite_app->name_or_path, + name, + sizeof(curr_favorite_app->name_or_path)); consumed = true; } if(consumed) { scene_manager_previous_scene(app->scene_manager); }; consumed = true; + + desktop_settings_save(&app->settings); } furi_string_free(temp_path); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c index 5af25cd61..1e6416531 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../desktop_settings_app.h" #include #include @@ -12,13 +12,14 @@ #define SCENE_EVENT_PINS_EQUAL (1U) #define SCENE_EVENT_PINS_DIFFERENT (2U) -static void pin_auth_done_callback(const PinCode* pin_code, void* context) { +static void pin_auth_done_callback(const DesktopPinCode* pin_code, void* context) { furi_assert(pin_code); furi_assert(context); - DesktopSettingsApp* app = context; + DesktopSettingsApp* app = context; app->pincode_buffer = *pin_code; - if(desktop_pin_compare(&app->settings.pin_code, pin_code)) { + + if(desktop_pin_code_check(pin_code)) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); } else { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); @@ -31,10 +32,9 @@ static void pin_auth_back_callback(void* context) { } void desktop_settings_scene_pin_auth_on_enter(void* context) { - DesktopSettingsApp* app = context; + furi_assert(desktop_pin_code_is_set()); - DESKTOP_SETTINGS_LOAD(&app->settings); - furi_assert(app->settings.pin_code.length > 0); + DesktopSettingsApp* app = context; desktop_view_pin_input_set_context(app->pin_input_view, app); desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_auth_back_callback); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c index f31a96894..abcce66da 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c @@ -17,9 +17,8 @@ static void pin_disable_back_callback(void* context) { void desktop_settings_scene_pin_disable_on_enter(void* context) { furi_assert(context); DesktopSettingsApp* app = context; - app->settings.pin_code.length = 0; - memset(app->settings.pin_code.data, '0', sizeof(app->settings.pin_code.data)); - DESKTOP_SETTINGS_SAVE(&app->settings); + + desktop_pin_code_reset(); popup_set_context(app->popup, app); popup_set_callback(app->popup, pin_disable_back_callback); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c index 1ba3c1b2d..711683c3f 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c @@ -6,7 +6,7 @@ #include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include +#include #include "../desktop_settings_app.h" #define SCENE_EVENT_EXIT (0U) @@ -17,7 +17,7 @@ static void pin_error_back_callback(void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); } -static void pin_error_done_callback(const PinCode* pin_code, void* context) { +static void pin_error_done_callback(const DesktopPinCode* pin_code, void* context) { UNUSED(pin_code); furi_assert(context); DesktopSettingsApp* app = context; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c index 7375edd3f..e0c66cb28 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c @@ -19,7 +19,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) { Submenu* submenu = app->submenu; submenu_reset(submenu); - if(!app->settings.pin_code.length) { + if(!desktop_pin_code_is_set()) { submenu_add_item( submenu, "Set PIN", diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c index 93012330a..08f5fcb3f 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c @@ -7,14 +7,14 @@ #include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include +#include #define SCENE_EVENT_EXIT (0U) #define SCENE_EVENT_1ST_PIN_ENTERED (1U) #define SCENE_EVENT_PINS_EQUAL (2U) #define SCENE_EVENT_PINS_DIFFERENT (3U) -static void pin_setup_done_callback(const PinCode* pin_code, void* context) { +static void pin_setup_done_callback(const DesktopPinCode* pin_code, void* context) { furi_assert(pin_code); furi_assert(context); DesktopSettingsApp* app = context; @@ -25,7 +25,7 @@ static void pin_setup_done_callback(const PinCode* pin_code, void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_1ST_PIN_ENTERED); } else { app->pincode_buffer_filled = false; - if(desktop_pin_compare(&app->pincode_buffer, pin_code)) { + if(desktop_pin_code_is_equal(&app->pincode_buffer, pin_code)) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); } else { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c index 170e6bca5..aa3d2214e 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c @@ -11,7 +11,7 @@ #define SCENE_EVENT_DONE (0U) -static void pin_setup_done_callback(const PinCode* pin_code, void* context) { +static void pin_setup_done_callback(const DesktopPinCode* pin_code, void* context) { furi_assert(pin_code); furi_assert(context); DesktopSettingsApp* app = context; @@ -22,8 +22,8 @@ static void pin_setup_done_callback(const PinCode* pin_code, void* context) { void desktop_settings_scene_pin_setup_done_on_enter(void* context) { DesktopSettingsApp* app = context; - app->settings.pin_code = app->pincode_buffer; - DESKTOP_SETTINGS_SAVE(&app->settings); + desktop_pin_code_set(&app->pincode_buffer); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); notification_message(notification, &sequence_single_vibro); notification_message(notification, &sequence_blink_green_10); @@ -32,7 +32,7 @@ void desktop_settings_scene_pin_setup_done_on_enter(void* context) { desktop_view_pin_input_set_context(app->pin_input_view, app); desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback); - desktop_view_pin_input_set_pin(app->pin_input_view, &app->settings.pin_code); + desktop_view_pin_input_set_pin(app->pin_input_view, &app->pincode_buffer); desktop_view_pin_input_set_label_button(app->pin_input_view, "Done"); desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN Activated!"); desktop_view_pin_input_set_label_secondary( diff --git a/applications/settings/expansion_settings_app/expansion_settings_app.c b/applications/settings/expansion_settings_app/expansion_settings_app.c index fe0e3ca2c..629c9a0a0 100644 --- a/applications/settings/expansion_settings_app/expansion_settings_app.c +++ b/applications/settings/expansion_settings_app/expansion_settings_app.c @@ -27,6 +27,8 @@ static uint32_t expansion_settings_app_exit(void* context) { static ExpansionSettingsApp* expansion_settings_app_alloc(void) { ExpansionSettingsApp* app = malloc(sizeof(ExpansionSettingsApp)); + expansion_settings_load(&app->settings); + app->gui = furi_record_open(RECORD_GUI); app->expansion = furi_record_open(RECORD_EXPANSION); app->settings = expansion_get_settings(app->expansion); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c index b7620b6e8..5a367afce 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c @@ -27,7 +27,7 @@ void storage_settings_scene_internal_info_on_enter(void* context) { } else { furi_string_printf( app->text_string, - "Name: %s\nType: LittleFS\nTotal: %lu KiB\nFree: %lu KiB", + "Name: %s\nType: Virtual\nTotal: %lu KiB\nFree: %lu KiB", furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown", (uint32_t)(total_space / 1024), (uint32_t)(free_space / 1024)); diff --git a/applications/system/application.fam b/applications/system/application.fam index 095ca1ab2..c5f81defa 100644 --- a/applications/system/application.fam +++ b/applications/system/application.fam @@ -4,7 +4,6 @@ App( apptype=FlipperAppType.METAPACKAGE, provides=[ "updater_app", - "storage_move_to_sd", "js_app", "js_app_start", # "archive", diff --git a/applications/system/storage_move_to_sd/application.fam b/applications/system/storage_move_to_sd/application.fam deleted file mode 100644 index de47de055..000000000 --- a/applications/system/storage_move_to_sd/application.fam +++ /dev/null @@ -1,18 +0,0 @@ -App( - appid="storage_move_to_sd", - name="StorageMoveToSd", - apptype=FlipperAppType.SYSTEM, - entry_point="storage_move_to_sd_app", - requires=["gui", "storage"], - provides=["storage_move_to_sd_start"], - stack_size=2 * 1024, - order=30, -) - -App( - appid="storage_move_to_sd_start", - apptype=FlipperAppType.STARTUP, - entry_point="storage_move_to_sd_start", - requires=["storage"], - order=120, -) diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c deleted file mode 100644 index 011bf47df..000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "storage_move_to_sd_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const storage_move_to_sd_on_enter_handlers[])(void*) = { -#include "storage_move_to_sd_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_event handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, -bool (*const storage_move_to_sd_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "storage_move_to_sd_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_exit handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, -void (*const storage_move_to_sd_on_exit_handlers[])(void* context) = { -#include "storage_move_to_sd_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers storage_move_to_sd_scene_handlers = { - .on_enter_handlers = storage_move_to_sd_on_enter_handlers, - .on_event_handlers = storage_move_to_sd_on_event_handlers, - .on_exit_handlers = storage_move_to_sd_on_exit_handlers, - .scene_num = StorageMoveToSdSceneNum, -}; diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h deleted file mode 100644 index bdeb4a843..000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -// Generate scene id and total number -#define ADD_SCENE(prefix, name, id) StorageMoveToSd##id, -typedef enum { -#include "storage_move_to_sd_scene_config.h" - StorageMoveToSdSceneNum, -} StorageMoveToSdScene; -#undef ADD_SCENE - -extern const SceneManagerHandlers storage_move_to_sd_scene_handlers; - -// Generate scene on_enter handlers declaration -#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "storage_move_to_sd_scene_config.h" -#undef ADD_SCENE - -// Generate scene on_event handlers declaration -#define ADD_SCENE(prefix, name, id) \ - bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); -#include "storage_move_to_sd_scene_config.h" -#undef ADD_SCENE - -// Generate scene on_exit handlers declaration -#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); -#include "storage_move_to_sd_scene_config.h" -#undef ADD_SCENE diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h deleted file mode 100644 index 1d7b2d25b..000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h +++ /dev/null @@ -1,2 +0,0 @@ -ADD_SCENE(storage_move_to_sd, confirm, Confirm) -ADD_SCENE(storage_move_to_sd, progress, Progress) diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c deleted file mode 100644 index 08c9e2d7f..000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "../storage_move_to_sd.h" -#include -#include -#include - -static void storage_move_to_sd_scene_confirm_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - StorageMoveToSd* app = context; - furi_assert(app); - if(type == InputTypeShort) { - if(result == GuiButtonTypeRight) { - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventConfirm); - } else if(result == GuiButtonTypeLeft) { - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); - } - } -} - -void storage_move_to_sd_scene_confirm_on_enter(void* context) { - StorageMoveToSd* app = context; - - widget_add_button_element( - app->widget, - GuiButtonTypeLeft, - "Cancel", - storage_move_to_sd_scene_confirm_widget_callback, - app); - widget_add_button_element( - app->widget, - GuiButtonTypeRight, - "Confirm", - storage_move_to_sd_scene_confirm_widget_callback, - app); - - widget_add_string_element( - app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "SD card inserted"); - widget_add_string_multiline_element( - app->widget, - 64, - 32, - AlignCenter, - AlignCenter, - FontSecondary, - "Move data from\ninternal storage to SD card?"); - - view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); -} - -bool storage_move_to_sd_scene_confirm_on_event(void* context, SceneManagerEvent event) { - StorageMoveToSd* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == MoveToSdCustomEventConfirm) { - scene_manager_next_scene(app->scene_manager, StorageMoveToSdProgress); - consumed = true; - } else if(event.event == MoveToSdCustomEventExit) { - view_dispatcher_stop(app->view_dispatcher); - } - } - - return consumed; -} - -void storage_move_to_sd_scene_confirm_on_exit(void* context) { - StorageMoveToSd* app = context; - widget_reset(app->widget); -} diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c deleted file mode 100644 index 7aa951bd8..000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "../storage_move_to_sd.h" - -void storage_move_to_sd_scene_progress_on_enter(void* context) { - StorageMoveToSd* app = context; - - widget_add_string_element( - app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving..."); - - view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); - - storage_move_to_sd_perform(); - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); -} - -bool storage_move_to_sd_scene_progress_on_event(void* context, SceneManagerEvent event) { - StorageMoveToSd* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - view_dispatcher_stop(app->view_dispatcher); - } else if(event.type == SceneManagerEventTypeBack) { - consumed = true; - } - - return consumed; -} - -void storage_move_to_sd_scene_progress_on_exit(void* context) { - StorageMoveToSd* app = context; - widget_reset(app->widget); -} diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c deleted file mode 100644 index 44e73c689..000000000 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.c +++ /dev/null @@ -1,203 +0,0 @@ -#include "storage_move_to_sd.h" - -#include -#include -#include -#include -#include -#include - -#define TAG "MoveToSd" - -#define MOVE_SRC STORAGE_INT_PATH_PREFIX -#define MOVE_DST STORAGE_EXT_PATH_PREFIX - -static bool storage_move_to_sd_check_entry(const char* name, FileInfo* fileinfo, void* ctx) { - UNUSED(ctx); - if(file_info_is_dir(fileinfo)) { - return true; - } - - return name && (*name != '.'); -} - -static void storage_move_to_sd_remove_region() { - if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) return; - Storage* storage = furi_record_open(RECORD_STORAGE); - - if(storage_common_exists(storage, INT_PATH(".region_data"))) { - storage_common_remove(storage, INT_PATH(".region_data")); - } - - furi_record_close(RECORD_STORAGE); -} - -bool storage_move_to_sd_perform(void) { - Storage* storage = furi_record_open(RECORD_STORAGE); - - DirWalk* dir_walk = dir_walk_alloc(storage); - dir_walk_set_recursive(dir_walk, false); - dir_walk_set_filter_cb(dir_walk, storage_move_to_sd_check_entry, NULL); - - FuriString *path_src, *path_dst; - - path_dst = furi_string_alloc(); - path_src = furi_string_alloc(); - - if(dir_walk_open(dir_walk, STORAGE_INT_PATH_PREFIX)) { - while(dir_walk_read(dir_walk, path_src, NULL) == DirWalkOK) { - furi_string_set(path_dst, path_src); - furi_string_replace_at( - path_dst, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); - - storage_common_merge( - storage, furi_string_get_cstr(path_src), furi_string_get_cstr(path_dst)); - storage_simply_remove_recursive(storage, furi_string_get_cstr(path_src)); - } - } - - dir_walk_free(dir_walk); - furi_string_free(path_dst); - furi_string_free(path_src); - - furi_record_close(RECORD_STORAGE); - - return false; -} - -static bool storage_move_to_sd_check(void) { - Storage* storage = furi_record_open(RECORD_STORAGE); - - bool should_migrate = false; - - DirWalk* dir_walk = dir_walk_alloc(storage); - dir_walk_set_recursive(dir_walk, false); - dir_walk_set_filter_cb(dir_walk, storage_move_to_sd_check_entry, NULL); - - FuriString* name; - name = furi_string_alloc(); - - if(dir_walk_open(dir_walk, STORAGE_INT_PATH_PREFIX)) { - // if at least 1 entry is present, we should migrate - should_migrate = (dir_walk_read(dir_walk, name, NULL) == DirWalkOK); - } - - dir_walk_free(dir_walk); - furi_string_free(name); - - furi_record_close(RECORD_STORAGE); - - return should_migrate; -} - -static bool storage_move_to_sd_custom_event_callback(void* context, uint32_t event) { - furi_assert(context); - StorageMoveToSd* app = context; - return scene_manager_handle_custom_event(app->scene_manager, event); -} - -static bool storage_move_to_sd_back_event_callback(void* context) { - furi_assert(context); - StorageMoveToSd* app = context; - return scene_manager_handle_back_event(app->scene_manager); -} - -static void storage_move_to_sd_unmount_callback(const void* message, void* context) { - StorageMoveToSd* app = context; - furi_assert(app); - const StorageEvent* storage_event = message; - - if((storage_event->type == StorageEventTypeCardUnmount) || - (storage_event->type == StorageEventTypeCardMountError)) { - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); - } -} - -static StorageMoveToSd* storage_move_to_sd_alloc(void) { - StorageMoveToSd* app = malloc(sizeof(StorageMoveToSd)); - - app->gui = furi_record_open(RECORD_GUI); - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - app->view_dispatcher = view_dispatcher_alloc(); - app->scene_manager = scene_manager_alloc(&storage_move_to_sd_scene_handlers, app); - - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_set_event_callback_context(app->view_dispatcher, app); - - view_dispatcher_set_custom_event_callback( - app->view_dispatcher, storage_move_to_sd_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, storage_move_to_sd_back_event_callback); - - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, StorageMoveToSdViewWidget, widget_get_view(app->widget)); - - scene_manager_next_scene(app->scene_manager, StorageMoveToSdConfirm); - - Storage* storage = furi_record_open(RECORD_STORAGE); - app->sub = furi_pubsub_subscribe( - storage_get_pubsub(storage), storage_move_to_sd_unmount_callback, app); - furi_record_close(RECORD_STORAGE); - - return app; -} - -static void storage_move_to_sd_free(StorageMoveToSd* app) { - Storage* storage = furi_record_open(RECORD_STORAGE); - furi_pubsub_unsubscribe(storage_get_pubsub(storage), app->sub); - furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_NOTIFICATION); - - view_dispatcher_remove_view(app->view_dispatcher, StorageMoveToSdViewWidget); - widget_free(app->widget); - view_dispatcher_free(app->view_dispatcher); - scene_manager_free(app->scene_manager); - - furi_record_close(RECORD_GUI); - - free(app); -} - -int32_t storage_move_to_sd_app(void* p) { - UNUSED(p); - - if(storage_move_to_sd_check()) { - StorageMoveToSd* app = storage_move_to_sd_alloc(); - notification_message(app->notifications, &sequence_display_backlight_on); - view_dispatcher_run(app->view_dispatcher); - storage_move_to_sd_free(app); - } else { - FURI_LOG_I(TAG, "Nothing to move"); - } - - // Remove unused region file from int memory - storage_move_to_sd_remove_region(); - - return 0; -} - -static void storage_move_to_sd_mount_callback(const void* message, void* context) { - UNUSED(context); - - const StorageEvent* storage_event = message; - - if(storage_event->type == StorageEventTypeCardMount) { - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "StorageMoveToSd", NULL, NULL); - furi_record_close(RECORD_LOADER); - } -} - -int32_t storage_move_to_sd_start(void* p) { - UNUSED(p); - Storage* storage = furi_record_open(RECORD_STORAGE); - - furi_pubsub_subscribe(storage_get_pubsub(storage), storage_move_to_sd_mount_callback, NULL); - - furi_record_close(RECORD_STORAGE); - return 0; -} diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.h b/applications/system/storage_move_to_sd/storage_move_to_sd.h deleted file mode 100644 index 135f3e9b0..000000000 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scenes/storage_move_to_sd_scene.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - MoveToSdCustomEventExit, - MoveToSdCustomEventConfirm, -} MoveToSdCustomEvent; - -typedef struct { - // records - Gui* gui; - Widget* widget; - NotificationApp* notifications; - - // view management - SceneManager* scene_manager; - ViewDispatcher* view_dispatcher; - - FuriPubSubSubscription* sub; - -} StorageMoveToSd; - -typedef enum { - StorageMoveToSdViewWidget, -} StorageMoveToSdView; - -bool storage_move_to_sd_perform(void); - -#ifdef __cplusplus -} -#endif diff --git a/applications/system/updater/util/update_task.c b/applications/system/updater/util/update_task.c index 0eae0eaf5..8f051ff77 100644 --- a/applications/system/updater/util/update_task.c +++ b/applications/system/updater/util/update_task.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #define TAG "UpdWorker" diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 848cc5494..e7e1bbbed 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/documentation/Doxyfile b/documentation/Doxyfile index 5b93cf8b1..f980c42f0 100644 --- a/documentation/Doxyfile +++ b/documentation/Doxyfile @@ -1021,7 +1021,6 @@ RECURSIVE = YES EXCLUDE = $(DOXY_SRC_ROOT)/lib/mlib \ $(DOXY_SRC_ROOT)/lib/STM32CubeWB \ - $(DOXY_SRC_ROOT)/lib/littlefs \ $(DOXY_SRC_ROOT)/lib/nanopb \ $(DOXY_SRC_ROOT)/assets/protobuf \ $(DOXY_SRC_ROOT)/lib/libusb_stm32 \ diff --git a/furi/core/event_loop.c b/furi/core/event_loop.c index 26401c84b..feed8d6f4 100644 --- a/furi/core/event_loop.c +++ b/furi/core/event_loop.c @@ -107,10 +107,13 @@ void furi_event_loop_run(FuriEventLoop* instance) { furi_check(instance); furi_check(instance->thread_id == furi_thread_get_current_id()); - furi_event_loop_init_tick(instance); + // Set the default signal callback if none was previously set + if(furi_thread_get_signal_callback(instance->thread_id) == NULL) { + furi_thread_set_signal_callback( + instance->thread_id, furi_event_loop_signal_callback, instance); + } - furi_thread_set_signal_callback( - instance->thread_id, furi_event_loop_signal_callback, instance); + furi_event_loop_init_tick(instance); while(true) { instance->state = FuriEventLoopStateIdle; @@ -177,7 +180,10 @@ void furi_event_loop_run(FuriEventLoop* instance) { } } - furi_thread_set_signal_callback(instance->thread_id, NULL, NULL); + // Disable the default signal callback + if(furi_thread_get_signal_callback(instance->thread_id) == furi_event_loop_signal_callback) { + furi_thread_set_signal_callback(instance->thread_id, NULL, NULL); + } } void furi_event_loop_stop(FuriEventLoop* instance) { diff --git a/furi/core/thread.c b/furi/core/thread.c index c47df55e4..69c6b0f04 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -318,6 +318,12 @@ void furi_thread_set_signal_callback( thread->signal_context = context; } +FuriThreadSignalCallback furi_thread_get_signal_callback(const FuriThread* thread) { + furi_check(thread); + + return thread->signal_callback; +} + bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg) { furi_check(thread); diff --git a/furi/core/thread.h b/furi/core/thread.h index be09e040e..e8cdeaeaf 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -270,7 +270,7 @@ FuriThreadState furi_thread_get_state(FuriThread* thread); /** * @brief Set a signal handler callback for a FuriThread instance. * - * The thread MUST be stopped when calling this function. + * The thread MUST be stopped when calling this function if calling it from another thread. * * @param[in,out] thread pointer to the FuriThread instance to be modified * @param[in] callback pointer to a user-specified callback function @@ -281,6 +281,14 @@ void furi_thread_set_signal_callback( FuriThreadSignalCallback callback, void* context); +/** + * @brief Get a signal callback for a FuriThread instance. + * + * @param[in] thread pointer to the FuriThread instance to be queried + * @return pointer to the callback function or NULL if none has been set + */ +FuriThreadSignalCallback furi_thread_get_signal_callback(const FuriThread* thread); + /** * @brief Send a signal to a FuriThread instance. * diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 64da39e35..4656f187b 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -18,7 +18,6 @@ - `infrared` - Infrared library, used by Infrared application - `lfrfid` - LF-RFID library, used by LF RFID application - `libusb_stm32` - LibUSB for STM32 series MCU -- `littlefs` - LittleFS file system driver, used by internal storage - `mbedtls` - MbedTLS cryptography library - `microtar` - MicroTAR library - `mjs` - MJs, javascript engine library diff --git a/lib/SConscript b/lib/SConscript index f331198a4..7f13aad44 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -27,7 +27,6 @@ libs = env.BuildModules( "one_wire", "ibutton", "infrared", - "littlefs", "subghz", "nfc", "digital_signal", diff --git a/lib/ble_profile/extra_profiles/hid_profile.c b/lib/ble_profile/extra_profiles/hid_profile.c index 85fb101b8..f559a741a 100644 --- a/lib/ble_profile/extra_profiles/hid_profile.c +++ b/lib/ble_profile/extra_profiles/hid_profile.c @@ -373,6 +373,12 @@ bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta) return state; } +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 7.5ms +#define CONNECTION_INTERVAL_MIN (0x0006) +// Up to 45 ms +#define CONNECTION_INTERVAL_MAX (0x24) + static GapConfig template_config = { .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, .appearance_char = GAP_APPEARANCE_KEYBOARD, @@ -380,8 +386,8 @@ static GapConfig template_config = { .pairing_method = GapPairingPinCodeVerifyYesNo, .conn_param = { - .conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms - .conn_int_max = 0x24, // 45 ms + .conn_int_min = CONNECTION_INTERVAL_MIN, + .conn_int_max = CONNECTION_INTERVAL_MAX, .slave_latency = 0, .supervisor_timeout = 0, }, diff --git a/lib/lfs_config.h b/lib/lfs_config.h deleted file mode 100644 index ff8bc4b23..000000000 --- a/lib/lfs_config.h +++ /dev/null @@ -1,204 +0,0 @@ -#pragma once - -#include - -#ifdef FURI_NDEBUG -#define LFS_NO_ASSERT -#define LFS_ASSERT(x) -#else -#define LFS_ASSERT furi_assert -#endif - -#define LFS_TAG "Lfs" - -#ifdef FURI_LFS_DEBUG -#define LFS_TRACE(...) FURI_LOG_T(LFS_TAG, __VA_ARGS__); - -#define LFS_DEBUG(...) FURI_LOG_D(LFS_TAG, __VA_ARGS__); -#else -#define LFS_TRACE(...) - -#define LFS_DEBUG(...) -#endif // FURI_LFS_DEBUG - -#define LFS_WARN(...) FURI_LOG_W(LFS_TAG, __VA_ARGS__); - -#define LFS_ERROR(...) FURI_LOG_E(LFS_TAG, __VA_ARGS__); - -// Because crc -#undef LFS_CONFIG - -// System includes -#include -#include -#include -#include - -#ifndef LFS_NO_MALLOC -#include -#endif -#ifndef LFS_NO_ASSERT -#include -#endif -#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) || \ - defined(LFS_YES_TRACE) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// Builtin functions, these may be replaced by more efficient -// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more -// expensive basic C implementation for debugging purposes - -// Min/max functions for unsigned 32-bit numbers -static inline uint32_t lfs_max(uint32_t a, uint32_t b) { - return (a > b) ? a : b; -} - -static inline uint32_t lfs_min(uint32_t a, uint32_t b) { - return (a < b) ? a : b; -} - -// Align to nearest multiple of a size -static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { - return a - (a % alignment); -} - -static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { - return lfs_aligndown(a + alignment - 1, alignment); -} - -// Find the smallest power of 2 greater than or equal to a -static inline uint32_t lfs_npw2(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return 32 - __builtin_clz(a - 1); -#else - uint32_t r = 0; - uint32_t s; - a -= 1; - s = (a > 0xffff) << 4; - a >>= s; - r |= s; - s = (a > 0xff) << 3; - a >>= s; - r |= s; - s = (a > 0xf) << 2; - a >>= s; - r |= s; - s = (a > 0x3) << 1; - a >>= s; - r |= s; - return (r | (a >> 1)) + 1; -#endif -} - -// Count the number of trailing binary zeros in a -// lfs_ctz(0) may be undefined -static inline uint32_t lfs_ctz(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) - return __builtin_ctz(a); -#else - return lfs_npw2((a & -a) + 1) - 1; -#endif -} - -// Count the number of binary ones in a -static inline uint32_t lfs_popc(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return __builtin_popcount(a); -#else - a = a - ((a >> 1) & 0x55555555); - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); - return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; -#endif -} - -// Find the sequence comparison of a and b, this is the distance -// between a and b ignoring overflow -static inline int lfs_scmp(uint32_t a, uint32_t b) { - return (int)(unsigned)(a - b); -} - -// Convert between 32-bit little-endian and native order -static inline uint32_t lfs_fromle32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ - BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ - __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - return a; -#elif !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ - __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - return __builtin_bswap32(a); -#else - return (((uint8_t*)&a)[0] << 0) | (((uint8_t*)&a)[1] << 8) | (((uint8_t*)&a)[2] << 16) | - (((uint8_t*)&a)[3] << 24); -#endif -} - -static inline uint32_t lfs_tole32(uint32_t a) { - return lfs_fromle32(a); -} - -// Convert between 32-bit big-endian and native order -static inline uint32_t lfs_frombe32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ - BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ - __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - return __builtin_bswap32(a); -#elif !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ - __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - return a; -#else - return (((uint8_t*)&a)[0] << 24) | (((uint8_t*)&a)[1] << 16) | (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); -#endif -} - -static inline uint32_t lfs_tobe32(uint32_t a) { - return lfs_frombe32(a); -} - -// Calculate CRC-32 with polynomial = 0x04c11db7 -uint32_t lfs_crc(uint32_t crc, const void* buffer, size_t size); - -// Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned -static inline void* lfs_malloc(size_t size) { -#ifndef LFS_NO_MALLOC - return malloc(size); -#else - (void)size; - return NULL; -#endif -} - -// Deallocate memory, only used if buffers are not provided to littlefs -static inline void lfs_free(void* p) { -#ifndef LFS_NO_MALLOC - free(p); -#else - (void)p; -#endif -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/lib/littlefs b/lib/littlefs deleted file mode 160000 index 611c9b20d..000000000 --- a/lib/littlefs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 611c9b20db2b99faee261daa7cc9bbe175d3eaca diff --git a/lib/littlefs.scons b/lib/littlefs.scons deleted file mode 100644 index 3d68e07ba..000000000 --- a/lib/littlefs.scons +++ /dev/null @@ -1,22 +0,0 @@ -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/littlefs", - ], -) - - -libenv = env.Clone(FW_LIB_NAME="littlefs") -libenv.ApplyLibFlags() -libenv.Append( - CPPDEFINES=[ - ("LFS_CONFIG", "lfs_config.h"), - ], -) - -sources = Glob("littlefs/*.c", source=True) - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/subghz/devices/registry.c b/lib/subghz/devices/registry.c index cf044c98a..9722c1501 100644 --- a/lib/subghz/devices/registry.c +++ b/lib/subghz/devices/registry.c @@ -23,8 +23,8 @@ void subghz_device_registry_init(void) { firmware_api_interface); //TODO FL-3556: fix path to plugins - //if(plugin_manager_load_all(subghz_device->manager, APP_DATA_PATH("plugins")) != - if(plugin_manager_load_all(subghz_device->manager, "/ext/apps_data/subghz/plugins") != + if(plugin_manager_load_all(subghz_device->manager, EXT_PATH("apps_data/subghz/plugins")) != + //if(plugin_manager_load_all(subghz_device->manager, APP_DATA_PATH("plugins")) != PluginManagerErrorNone) { FURI_LOG_E(TAG, "Failed to load all libs"); } diff --git a/lib/toolbox/crc32_calc.c b/lib/toolbox/crc32_calc.c index 78295167f..60d709a36 100644 --- a/lib/toolbox/crc32_calc.c +++ b/lib/toolbox/crc32_calc.c @@ -1,11 +1,37 @@ #include "crc32_calc.h" -#include #define CRC_DATA_BUFFER_MAX_LEN 512 uint32_t crc32_calc_buffer(uint32_t crc, const void* buffer, size_t size) { - // TODO FL-3547: consider removing dependency on LFS - return ~lfs_crc(~crc, buffer, size); + crc = ~crc; + + static const uint32_t rtable[16] = { + 0x00000000, + 0x1db71064, + 0x3b6e20c8, + 0x26d930ac, + 0x76dc4190, + 0x6b6b51f4, + 0x4db26158, + 0x5005713c, + 0xedb88320, + 0xf00f9344, + 0xd6d6a3e8, + 0xcb61b38c, + 0x9b64c2b0, + 0x86d3d2d4, + 0xa00ae278, + 0xbdbdf21c, + }; + + const uint8_t* data = buffer; + + for(size_t i = 0; i < size; i++) { + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; + } + + return ~crc; } uint32_t crc32_calc_file(File* file, const FileCrcProgressCb progress_cb, void* context) { diff --git a/lib/toolbox/stream/file_stream.c b/lib/toolbox/stream/file_stream.c index 80cbb7d5f..a0dfda3eb 100644 --- a/lib/toolbox/stream/file_stream.c +++ b/lib/toolbox/stream/file_stream.c @@ -159,8 +159,8 @@ static bool file_stream_delete_and_insert( FuriString* tmp_name; tmp_name = furi_string_alloc(); storage_get_next_filename( - _stream->storage, STORAGE_ANY_PATH_PREFIX, ".scratch", ".pad", tmp_name, 255); - scratch_name = furi_string_alloc_printf(ANY_PATH("%s.pad"), furi_string_get_cstr(tmp_name)); + _stream->storage, STORAGE_EXT_PATH_PREFIX, ".scratch", ".pad", tmp_name, 255); + scratch_name = furi_string_alloc_printf(EXT_PATH("%s.pad"), furi_string_get_cstr(tmp_name)); furi_string_free(tmp_name); do { diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index 80144a0f4..db1d5177f 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -289,7 +289,7 @@ bool tar_archive_file_finalize(TarArchive* archive) { typedef struct { TarArchive* archive; const char* work_dir; - Storage_name_converter converter; + TarArchiveNameConverter converter; } TarArchiveDirectoryOpParams; static bool archive_extract_current_file(TarArchive* archive, const char* dst_path) { @@ -386,7 +386,7 @@ static int archive_extract_foreach_cb(mtar_t* tar, const mtar_header_t* header, bool tar_archive_unpack_to( TarArchive* archive, const char* destination, - Storage_name_converter converter) { + TarArchiveNameConverter converter) { furi_check(archive); TarArchiveDirectoryOpParams param = { .archive = archive, diff --git a/lib/toolbox/tar/tar_archive.h b/lib/toolbox/tar/tar_archive.h index 3eb97391e..fd0b28b87 100644 --- a/lib/toolbox/tar/tar_archive.h +++ b/lib/toolbox/tar/tar_archive.h @@ -54,6 +54,8 @@ bool tar_archive_open(TarArchive* archive, const char* path, TarOpenMode mode); */ void tar_archive_free(TarArchive* archive); +typedef void (*TarArchiveNameConverter)(FuriString*); + /* High-level API - assumes archive is open */ /** Unpack tar archive to destination @@ -67,7 +69,7 @@ void tar_archive_free(TarArchive* archive); bool tar_archive_unpack_to( TarArchive* archive, const char* destination, - Storage_name_converter converter); + TarArchiveNameConverter converter); /** Add file to tar archive * diff --git a/scripts/testops.py b/scripts/testops.py index bf02feaad..4ae10c7f4 100644 --- a/scripts/testops.py +++ b/scripts/testops.py @@ -39,7 +39,9 @@ class Main(App): if port := resolve_port(self.logger, self.args.port): self.logger.info(f"Found flipper at {port}") + time.sleep(1) break + time.sleep(1) if not port: diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index d2a145de5..9e58a6746 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,70.0,, +Version,+,71.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -687,6 +687,7 @@ Function,+,bt_forget_bonded_devices,void,Bt* Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char* Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage* Function,+,bt_keys_storage_free,void,BtKeysStorage* +Function,+,bt_keys_storage_is_changed,_Bool,BtKeysStorage* Function,+,bt_keys_storage_load,_Bool,BtKeysStorage* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*" @@ -1372,6 +1373,7 @@ Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate, Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice, Function,+,furi_hal_rtc_get_log_level,uint8_t, Function,+,furi_hal_rtc_get_pin_fails,uint32_t, +Function,-,furi_hal_rtc_get_pin_value,uint32_t, Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, @@ -1391,6 +1393,7 @@ Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t +Function,-,furi_hal_rtc_set_pin_value,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_sd_get_card_state,FuriStatus, @@ -1626,6 +1629,7 @@ Function,+,furi_thread_get_id,FuriThreadId,FuriThread* Function,+,furi_thread_get_name,const char*,FuriThreadId Function,+,furi_thread_get_priority,FuriThreadPriority,FuriThread* Function,+,furi_thread_get_return_code,int32_t,FuriThread* +Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, @@ -2509,7 +2513,7 @@ Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" -Function,+,storage_int_restore,FS_Error,"Storage*, const char*, Storage_name_converter" +Function,+,storage_int_restore,FS_Error,"Storage*, const char*, StorageNameConverter" Function,+,storage_sd_format,FS_Error,Storage* Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*" Function,+,storage_sd_mount,FS_Error,Storage* @@ -2641,7 +2645,7 @@ Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode" Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*" Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t" Function,+,tar_archive_unpack_file,_Bool,"TarArchive*, const char*, const char*" -Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter" +Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, TarArchiveNameConverter" Function,-,tempnam,char*,"const char*, const char*" Function,+,text_box_alloc,TextBox*, Function,+,text_box_free,void,TextBox* diff --git a/targets/f18/target.json b/targets/f18/target.json index 229ec0a7a..9c450aa83 100644 --- a/targets/f18/target.json +++ b/targets/f18/target.json @@ -17,7 +17,6 @@ "stm32wb", "hwdrivers", "fatfs", - "littlefs", "toolbox", "digital_signal", "signal_reader", diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index a34c3db0c..3c6a9e4db 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,70.0,, +Version,+,71.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -768,6 +768,7 @@ Function,+,bt_forget_bonded_devices,void,Bt* Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char* Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage* Function,+,bt_keys_storage_free,void,BtKeysStorage* +Function,+,bt_keys_storage_is_changed,_Bool,BtKeysStorage* Function,+,bt_keys_storage_load,_Bool,BtKeysStorage* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*" @@ -1589,6 +1590,7 @@ Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate, Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice, Function,+,furi_hal_rtc_get_log_level,uint8_t, Function,+,furi_hal_rtc_get_pin_fails,uint32_t, +Function,-,furi_hal_rtc_get_pin_value,uint32_t, Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, @@ -1608,6 +1610,7 @@ Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t +Function,-,furi_hal_rtc_set_pin_value,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_sd_get_card_state,FuriStatus, @@ -1880,6 +1883,7 @@ Function,+,furi_thread_get_id,FuriThreadId,FuriThread* Function,+,furi_thread_get_name,const char*,FuriThreadId Function,+,furi_thread_get_priority,FuriThreadPriority,FuriThread* Function,+,furi_thread_get_return_code,int32_t,FuriThread* +Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, @@ -3234,7 +3238,7 @@ Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" -Function,+,storage_int_restore,FS_Error,"Storage*, const char*, Storage_name_converter" +Function,+,storage_int_restore,FS_Error,"Storage*, const char*, StorageNameConverter" Function,+,storage_sd_format,FS_Error,Storage* Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*" Function,+,storage_sd_mount,FS_Error,Storage* @@ -3550,7 +3554,7 @@ Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode" Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*" Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t" Function,+,tar_archive_unpack_file,_Bool,"TarArchive*, const char*, const char*" -Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter" +Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, TarArchiveNameConverter" Function,-,tempnam,char*,"const char*, const char*" Function,+,text_box_alloc,TextBox*, Function,+,text_box_free,void,TextBox* diff --git a/targets/f7/ble_glue/extra_beacon.c b/targets/f7/ble_glue/extra_beacon.c index 0fd452a5a..f9b9b13ef 100644 --- a/targets/f7/ble_glue/extra_beacon.c +++ b/targets/f7/ble_glue/extra_beacon.c @@ -8,9 +8,9 @@ #define GAP_MS_TO_SCAN_INTERVAL(x) ((uint16_t)((x) / 0.625)) -// Also used as an indicator of whether the beacon had ever been configured -// AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms -#define GAP_MIN_ADV_INTERVAL_MS (30u) +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 20ms +#define GAP_MIN_ADV_INTERVAL_MS (20U) typedef struct { GapExtraBeaconConfig last_config; diff --git a/targets/f7/ble_glue/hw_ipcc.c b/targets/f7/ble_glue/hw_ipcc.c index 4daaa7e49..43785a1b4 100644 --- a/targets/f7/ble_glue/hw_ipcc.c +++ b/targets/f7/ble_glue/hw_ipcc.c @@ -15,6 +15,8 @@ (LL_C2_IPCC_IsActiveFlag_CHx(IPCC, channel) && \ LL_C1_IPCC_IsEnabledReceiveChannel(IPCC, channel)) +#define IPCC_SEND_CMD_TIMEOUT_US (33UL * 1000UL * 1000UL) + static void (*FreeBufCb)(void); static void HW_IPCC_BLE_EvtHandler(void); @@ -113,7 +115,7 @@ void HW_IPCC_SYS_Init(void) { void HW_IPCC_SYS_SendCmd(void) { LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL); - FuriHalCortexTimer timer = furi_hal_cortex_timer_get(33000000); + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(IPCC_SEND_CMD_TIMEOUT_US); while(LL_C1_IPCC_IsActiveFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) { furi_check(!furi_hal_cortex_timer_is_expired(timer), "HW_IPCC_SYS_SendCmd timeout"); diff --git a/targets/f7/ble_glue/profiles/serial_profile.c b/targets/f7/ble_glue/profiles/serial_profile.c index 118a76e8c..1d414889f 100644 --- a/targets/f7/ble_glue/profiles/serial_profile.c +++ b/targets/f7/ble_glue/profiles/serial_profile.c @@ -40,14 +40,20 @@ static void ble_profile_serial_stop(FuriHalBleProfileBase* profile) { ble_svc_serial_stop(serial_profile->serial_svc); } +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 7.5ms +#define CONNECTION_INTERVAL_MIN (0x06) +// Up to 45 ms +#define CONNECTION_INTERVAL_MAX (0x24) + static GapConfig serial_template_config = { .adv_service_uuid = 0x3080, .appearance_char = 0x8600, .bonding_mode = true, .pairing_method = GapPairingPinCodeShow, .conn_param = { - .conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms - .conn_int_max = 0x24, // 45 ms + .conn_int_min = CONNECTION_INTERVAL_MIN, + .conn_int_max = CONNECTION_INTERVAL_MAX, .slave_latency = 0, .supervisor_timeout = 0, }}; diff --git a/targets/f7/furi_hal/furi_hal_bt.c b/targets/f7/furi_hal/furi_hal_bt.c index 30a4ee7ed..05a066630 100644 --- a/targets/f7/furi_hal/furi_hal_bt.c +++ b/targets/f7/furi_hal/furi_hal_bt.c @@ -87,10 +87,9 @@ static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) { } bool furi_hal_bt_start_radio_stack(void) { - bool res = false; - furi_check(furi_hal_bt.core2_mtx); + furi_hal_bt_lock_core2(); - furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever); + bool res = false; // Explicitly tell that we are in charge of CLK48 domain furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); @@ -123,7 +122,8 @@ bool furi_hal_bt_start_radio_stack(void) { } res = true; } while(false); - furi_mutex_release(furi_hal_bt.core2_mtx); + + furi_hal_bt_unlock_core2(); gap_extra_beacon_init(); return res; @@ -198,6 +198,8 @@ FuriHalBleProfileBase* furi_hal_bt_start_app( } void furi_hal_bt_reinit(void) { + furi_hal_bt_lock_core2(); + furi_hal_power_insomnia_enter(); FURI_LOG_I(TAG, "Disconnect and stop advertising"); furi_hal_bt_stop_advertising(); @@ -229,6 +231,7 @@ void furi_hal_bt_reinit(void) { furi_hal_bus_disable(FuriHalBusCRC); furi_hal_bt_init(); + furi_hal_bt_unlock_core2(); furi_hal_bt_start_radio_stack(); furi_hal_power_insomnia_exit(); } diff --git a/targets/f7/furi_hal/furi_hal_crypto.c b/targets/f7/furi_hal/furi_hal_crypto.c index 1879eb2ca..4deda293a 100644 --- a/targets/f7/furi_hal/furi_hal_crypto.c +++ b/targets/f7/furi_hal/furi_hal_crypto.c @@ -262,36 +262,54 @@ bool furi_hal_crypto_enclave_load_key(uint8_t slot, const uint8_t* iv) { furi_hal_bus_enable(FuriHalBusAES1); - if(!furi_hal_bt_is_alive()) { - return false; - } + bool success = false; - furi_hal_crypto_mode_init_done = false; - crypto_key_init(NULL, (uint32_t*)iv); + furi_hal_bt_lock_core2(); - if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { - return true; - } else { - CLEAR_BIT(AES1->CR, AES_CR_EN); - furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); - return false; - } + do { + if(!furi_hal_bt_is_alive()) { + break; + } + + furi_hal_crypto_mode_init_done = false; + crypto_key_init(NULL, (uint32_t*)iv); + + if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { + success = true; + } else { + CLEAR_BIT(AES1->CR, AES_CR_EN); + furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + } + + } while(false); + + furi_hal_bt_unlock_core2(); + return success; } bool furi_hal_crypto_enclave_unload_key(uint8_t slot) { - if(!furi_hal_bt_is_alive()) { - return false; - } + furi_hal_bt_lock_core2(); - CLEAR_BIT(AES1->CR, AES_CR_EN); + bool success = false; - SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); + do { + if(!furi_hal_bt_is_alive()) { + break; + } - furi_hal_bus_disable(FuriHalBusAES1); + CLEAR_BIT(AES1->CR, AES_CR_EN); - furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); - return shci_state == SHCI_Success; + furi_hal_bus_disable(FuriHalBusAES1); + + furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + + success = (shci_state == SHCI_Success); + } while(false); + + furi_hal_bt_unlock_core2(); + return success; } bool furi_hal_crypto_load_key(const uint8_t* key, const uint8_t* iv) { diff --git a/targets/f7/furi_hal/furi_hal_region.c b/targets/f7/furi_hal/furi_hal_region.c index c8af57a19..6e138b41b 100644 --- a/targets/f7/furi_hal/furi_hal_region.c +++ b/targets/f7/furi_hal/furi_hal_region.c @@ -29,10 +29,9 @@ const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency) { return NULL; } - for(size_t i = 0; i < furi_hal_region->bands_count; i++) { - if(furi_hal_region->bands[i].start <= frequency && - furi_hal_region->bands[i].end >= frequency) { - return &furi_hal_region->bands[i]; + for(size_t i = 0; i < region->bands_count; i++) { + if(region->bands[i].start <= frequency && region->bands[i].end >= frequency) { + return ®ion->bands[i]; } } diff --git a/targets/f7/furi_hal/furi_hal_rtc.c b/targets/f7/furi_hal/furi_hal_rtc.c index f5f7bdf2d..d5cda7476 100644 --- a/targets/f7/furi_hal/furi_hal_rtc.c +++ b/targets/f7/furi_hal/furi_hal_rtc.c @@ -411,6 +411,14 @@ uint32_t furi_hal_rtc_get_pin_fails(void) { return furi_hal_rtc_get_register(FuriHalRtcRegisterPinFails); } +void furi_hal_rtc_set_pin_value(uint32_t value) { + furi_hal_rtc_set_register(FuriHalRtcRegisterPinValue, value); +} + +uint32_t furi_hal_rtc_get_pin_value(void) { + return furi_hal_rtc_get_register(FuriHalRtcRegisterPinValue); +} + uint32_t furi_hal_rtc_get_timestamp(void) { DateTime datetime = {0}; furi_hal_rtc_get_datetime(&datetime); diff --git a/targets/f7/furi_hal/furi_hal_rtc.h b/targets/f7/furi_hal/furi_hal_rtc.h index 3bdbb0c72..030b464cf 100644 --- a/targets/f7/furi_hal/furi_hal_rtc.h +++ b/targets/f7/furi_hal/furi_hal_rtc.h @@ -46,9 +46,10 @@ typedef enum { FuriHalRtcRegisterVersion, /**< Pointer to Version */ FuriHalRtcRegisterLfsFingerprint, /**< LFS geometry fingerprint */ FuriHalRtcRegisterFaultData, /**< Pointer to last fault message */ - FuriHalRtcRegisterPinFails, /**< Failed pins count */ + FuriHalRtcRegisterPinFails, /**< Failed PINs count */ /* Index of FS directory entry corresponding to FW update to be applied */ FuriHalRtcRegisterUpdateFolderFSIndex, + FuriHalRtcRegisterPinValue, /**< Encoded value of the currently set PIN */ FuriHalRtcRegisterMAX, /**< Service value, do not use */ } FuriHalRtcRegister; @@ -257,18 +258,29 @@ void furi_hal_rtc_set_fault_data(uint32_t value); */ uint32_t furi_hal_rtc_get_fault_data(void); -/** Set Pin Fails count +/** Set PIN Fails count * - * @param[in] value The Pin Fails count + * @param[in] value The PIN Fails count */ void furi_hal_rtc_set_pin_fails(uint32_t value); -/** Get Pin Fails count +/** Get PIN Fails count * - * @return Pin Fails Count + * @return PIN Fails Count */ uint32_t furi_hal_rtc_get_pin_fails(void); +/** Set encoded PIN value + * + * @param[in] value new PIN code value to be set + */ +void furi_hal_rtc_set_pin_value(uint32_t value); + +/** Get the current PIN encoded value + * + */ +uint32_t furi_hal_rtc_get_pin_value(void); + /** Get UNIX Timestamp * * @return Unix Timestamp in seconds from UNIX epoch start diff --git a/targets/f7/target.json b/targets/f7/target.json index 665864d7d..35f1766c1 100644 --- a/targets/f7/target.json +++ b/targets/f7/target.json @@ -25,7 +25,6 @@ "stm32wb", "hwdrivers", "fatfs", - "littlefs", "subghz", "toolbox", "nfc", diff --git a/targets/furi_hal_include/furi_hal_region.h b/targets/furi_hal_include/furi_hal_region.h index b6a6d425e..f37059649 100644 --- a/targets/furi_hal_include/furi_hal_region.h +++ b/targets/furi_hal_include/furi_hal_region.h @@ -2,7 +2,6 @@ #include #include -#include #ifdef __cplusplus extern "C" {