From cb7d43f7e1464ed3276a2772b7a0142f9252f181 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Fri, 1 Apr 2022 15:10:21 +0400 Subject: [PATCH 01/12] [FL-2410] SubGhz: fix launching an incorrect Sub-GHz key from the archive. (#1080) --- applications/subghz/subghz.c | 30 ++++++++++++++++++------------ applications/subghz/subghz_i.c | 1 - 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 0fb2f6d9..a6c6e24f 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -309,20 +309,26 @@ int32_t subghz_app(void* p) { subghz_environment_load_keystore( subghz->txrx->environment, "/ext/subghz/assets/keeloq_mfcodes_user"); // Check argument and run corresponding scene - if(p && subghz_key_load(subghz, p)) { - string_t filename; - string_init(filename); + if(p) { + if(subghz_key_load(subghz, p)) { + string_t filename; + string_init(filename); - path_extract_filename_no_ext(p, filename); - strcpy(subghz->file_name, string_get_cstr(filename)); - string_clear(filename); - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { - //Load Raw TX - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); + path_extract_filename_no_ext(p, filename); + strcpy(subghz->file_name, string_get_cstr(filename)); + string_clear(filename); + if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + //Load Raw TX + subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); + } else { + //Load transmitter TX + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + } } else { - //Load transmitter TX - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + //exit app + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); } } else { if(load_database) { diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 56ce7e97..01ecebe8 100755 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -277,7 +277,6 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { } string_clear(temp_str); - //string_clear(path); flipper_format_free(fff_data_file); furi_record_close("storage"); From 855f2584ab8529212fb3f6b720ba68269194781f Mon Sep 17 00:00:00 2001 From: SG Date: Fri, 1 Apr 2022 22:21:31 +1000 Subject: [PATCH 02/12] [FL-2415] Storage: blocking file open (#1078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Storage: correct replacement for "/any" path in path holder * Unit tests: storage, blocking file open test * File stream: error getter * Storage: common copy and common remove now executes in external thread * Filesystems: got rid of unused functions * Storage: untangle dependencies, ram-frendly filesystem api * iButton: context assertions * Storage: pubsub messages * Storage: wait for the file to close if it was open * Storage: fix folder copying * Storage: unit test * Storage: pubsub documentation * Fix merge error * Fix memleak in storage test * Storage: remove unused define Co-authored-by: あく --- applications/archive/helpers/archive_files.h | 1 + .../desktop/animations/animation_manager.c | 19 +- applications/ibutton/ibutton_cli.c | 2 + .../ibutton/scene/ibutton_scene_add_type.cpp | 1 + .../ibutton/scene/ibutton_scene_add_value.cpp | 1 + .../scene/ibutton_scene_delete_confirm.cpp | 1 + .../scene/ibutton_scene_delete_success.cpp | 1 + .../ibutton/scene/ibutton_scene_emulate.cpp | 1 + .../ibutton/scene/ibutton_scene_info.cpp | 1 + .../ibutton/scene/ibutton_scene_read.cpp | 1 + .../scene/ibutton_scene_read_crc_error.cpp | 1 + .../ibutton_scene_read_not_key_error.cpp | 1 + .../scene/ibutton_scene_read_success.cpp | 1 + .../scene/ibutton_scene_readed_key_menu.cpp | 1 + .../ibutton/scene/ibutton_scene_save_name.cpp | 1 + .../scene/ibutton_scene_save_success.cpp | 1 + .../scene/ibutton_scene_saved_key_menu.cpp | 1 + .../ibutton/scene/ibutton_scene_start.cpp | 1 + .../ibutton/scene/ibutton_scene_write.cpp | 1 + .../scene/ibutton_scene_write_success.cpp | 1 + applications/storage/filesystem_api_defines.h | 2 +- .../storage/filesystem_api_internal.h | 63 +++--- applications/storage/storage.c | 21 +- applications/storage/storage.h | 20 +- applications/storage/storage_external_api.c | 92 ++++++-- applications/storage/storage_glue.c | 26 +-- applications/storage/storage_glue.h | 12 +- applications/storage/storage_i.h | 1 - applications/storage/storage_message.h | 8 - applications/storage/storage_processing.c | 196 ++++++++---------- applications/storage/storage_sd_api.h | 11 +- applications/storage/storages/storage_ext.c | 75 ++++--- applications/storage/storages/storage_int.c | 58 +++--- applications/tests/storage/storage_test.c | 80 +++++++ applications/tests/test_index.c | 6 +- lib/toolbox/stream/file_stream.c | 7 + lib/toolbox/stream/file_stream.h | 7 + 37 files changed, 443 insertions(+), 281 deletions(-) create mode 100644 applications/tests/storage/storage_test.c diff --git a/applications/archive/helpers/archive_files.h b/applications/archive/helpers/archive_files.h index c8b16c53..64549d09 100644 --- a/applications/archive/helpers/archive_files.h +++ b/applications/archive/helpers/archive_files.h @@ -1,5 +1,6 @@ #pragma once #include "file_worker.h" +#include #define MAX_FILES 100 //temp diff --git a/applications/desktop/animations/animation_manager.c b/applications/desktop/animations/animation_manager.c index afc9c42e..4c99724e 100644 --- a/applications/desktop/animations/animation_manager.c +++ b/applications/desktop/animations/animation_manager.c @@ -94,10 +94,21 @@ void animation_manager_set_interact_callback( } static void animation_manager_check_blocking_callback(const void* message, void* context) { - furi_assert(context); - AnimationManager* animation_manager = context; - if(animation_manager->check_blocking_callback) { - animation_manager->check_blocking_callback(animation_manager->context); + const StorageEvent* storage_event = message; + + switch(storage_event->type) { + case StorageEventTypeCardMount: + case StorageEventTypeCardUnmount: + case StorageEventTypeCardMountError: + furi_assert(context); + AnimationManager* animation_manager = context; + if(animation_manager->check_blocking_callback) { + animation_manager->check_blocking_callback(animation_manager->context); + } + break; + + default: + break; } } diff --git a/applications/ibutton/ibutton_cli.c b/applications/ibutton/ibutton_cli.c index 44d7025c..243ee36b 100644 --- a/applications/ibutton/ibutton_cli.c +++ b/applications/ibutton/ibutton_cli.c @@ -63,6 +63,7 @@ void ibutton_cli_print_key_data(iButtonKey* key) { #define EVENT_FLAG_IBUTTON_COMPLETE (1 << 0) static void ibutton_cli_worker_read_cb(void* context) { + furi_assert(context); osEventFlagsId_t event = context; osEventFlagsSet(event, EVENT_FLAG_IBUTTON_COMPLETE); } @@ -112,6 +113,7 @@ typedef struct { } iButtonWriteContext; static void ibutton_cli_worker_write_cb(void* context, iButtonWorkerWriteResult result) { + furi_assert(context); iButtonWriteContext* write_context = (iButtonWriteContext*)context; write_context->result = result; osEventFlagsSet(write_context->event, EVENT_FLAG_IBUTTON_COMPLETE); diff --git a/applications/ibutton/scene/ibutton_scene_add_type.cpp b/applications/ibutton/scene/ibutton_scene_add_type.cpp index aa76d3c0..c9537768 100644 --- a/applications/ibutton/scene/ibutton_scene_add_type.cpp +++ b/applications/ibutton/scene/ibutton_scene_add_type.cpp @@ -9,6 +9,7 @@ typedef enum { } SubmenuIndex; static void submenu_callback(void* context, uint32_t index) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_add_value.cpp b/applications/ibutton/scene/ibutton_scene_add_value.cpp index 95d5f82f..cb1e287c 100755 --- a/applications/ibutton/scene/ibutton_scene_add_value.cpp +++ b/applications/ibutton/scene/ibutton_scene_add_value.cpp @@ -3,6 +3,7 @@ #include static void byte_input_callback(void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp index 91e471df..8b1aa9f5 100755 --- a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp +++ b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp @@ -2,6 +2,7 @@ #include "../ibutton_app.h" static void widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_delete_success.cpp b/applications/ibutton/scene/ibutton_scene_delete_success.cpp index e2b64999..b2241141 100644 --- a/applications/ibutton/scene/ibutton_scene_delete_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_delete_success.cpp @@ -2,6 +2,7 @@ #include "../ibutton_app.h" static void popup_callback(void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; event.type = iButtonEvent::Type::EventTypeBack; diff --git a/applications/ibutton/scene/ibutton_scene_emulate.cpp b/applications/ibutton/scene/ibutton_scene_emulate.cpp index 8f517c78..e1b08e84 100644 --- a/applications/ibutton/scene/ibutton_scene_emulate.cpp +++ b/applications/ibutton/scene/ibutton_scene_emulate.cpp @@ -3,6 +3,7 @@ #include static void emulate_callback(void* context, bool emulated) { + furi_assert(context); if(emulated) { iButtonApp* app = static_cast(context); iButtonEvent event = {.type = iButtonEvent::Type::EventTypeWorkerEmulated}; diff --git a/applications/ibutton/scene/ibutton_scene_info.cpp b/applications/ibutton/scene/ibutton_scene_info.cpp index f4cbd809..afc8c050 100755 --- a/applications/ibutton/scene/ibutton_scene_info.cpp +++ b/applications/ibutton/scene/ibutton_scene_info.cpp @@ -2,6 +2,7 @@ #include "../ibutton_app.h" static void widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_read.cpp b/applications/ibutton/scene/ibutton_scene_read.cpp index b5c7ac8f..1353ef96 100644 --- a/applications/ibutton/scene/ibutton_scene_read.cpp +++ b/applications/ibutton/scene/ibutton_scene_read.cpp @@ -3,6 +3,7 @@ #include static void read_callback(void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event = {.type = iButtonEvent::Type::EventTypeWorkerRead}; app->get_view_manager()->send_event(&event); diff --git a/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp b/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp index 9d67e442..1371334b 100644 --- a/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp @@ -3,6 +3,7 @@ #include static void dialog_ex_callback(DialogExResult result, void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp b/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp index fab3c3f2..b88f4655 100644 --- a/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp @@ -3,6 +3,7 @@ #include static void dialog_ex_callback(DialogExResult result, void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_read_success.cpp b/applications/ibutton/scene/ibutton_scene_read_success.cpp index 818f7e38..6eb95721 100644 --- a/applications/ibutton/scene/ibutton_scene_read_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_success.cpp @@ -3,6 +3,7 @@ #include static void dialog_ex_callback(DialogExResult result, void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp index 63af10ad..19eec4e2 100644 --- a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp @@ -9,6 +9,7 @@ typedef enum { } SubmenuIndex; static void submenu_callback(void* context, uint32_t index) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_save_name.cpp b/applications/ibutton/scene/ibutton_scene_save_name.cpp index bde6133d..94ca45d4 100644 --- a/applications/ibutton/scene/ibutton_scene_save_name.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_name.cpp @@ -3,6 +3,7 @@ #include static void text_input_callback(void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_save_success.cpp b/applications/ibutton/scene/ibutton_scene_save_success.cpp index 891b020a..0a1fc153 100644 --- a/applications/ibutton/scene/ibutton_scene_save_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_success.cpp @@ -3,6 +3,7 @@ #include static void popup_callback(void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; event.type = iButtonEvent::Type::EventTypeBack; diff --git a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp index 1d87e85f..d9d042d9 100644 --- a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp @@ -11,6 +11,7 @@ typedef enum { } SubmenuIndex; static void submenu_callback(void* context, uint32_t index) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_start.cpp b/applications/ibutton/scene/ibutton_scene_start.cpp index 2dbe9878..4b877dd2 100644 --- a/applications/ibutton/scene/ibutton_scene_start.cpp +++ b/applications/ibutton/scene/ibutton_scene_start.cpp @@ -8,6 +8,7 @@ typedef enum { } SubmenuIndex; static void submenu_callback(void* context, uint32_t index) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton_scene_write.cpp b/applications/ibutton/scene/ibutton_scene_write.cpp index af86a148..847e7f01 100644 --- a/applications/ibutton/scene/ibutton_scene_write.cpp +++ b/applications/ibutton/scene/ibutton_scene_write.cpp @@ -2,6 +2,7 @@ #include "../ibutton_app.h" static void ibutton_worker_write_cb(void* context, iButtonWorkerWriteResult result) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; event.type = iButtonEvent::Type::EventTypeWorkerWrite; diff --git a/applications/ibutton/scene/ibutton_scene_write_success.cpp b/applications/ibutton/scene/ibutton_scene_write_success.cpp index 48acaaa4..dbeb595d 100644 --- a/applications/ibutton/scene/ibutton_scene_write_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_write_success.cpp @@ -2,6 +2,7 @@ #include "../ibutton_app.h" static void popup_callback(void* context) { + furi_assert(context); iButtonApp* app = static_cast(context); iButtonEvent event; event.type = iButtonEvent::Type::EventTypeBack; diff --git a/applications/storage/filesystem_api_defines.h b/applications/storage/filesystem_api_defines.h index e90e642f..cc33de26 100644 --- a/applications/storage/filesystem_api_defines.h +++ b/applications/storage/filesystem_api_defines.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { diff --git a/applications/storage/filesystem_api_internal.h b/applications/storage/filesystem_api_internal.h index c67e5395..29098e59 100644 --- a/applications/storage/filesystem_api_internal.h +++ b/applications/storage/filesystem_api_internal.h @@ -75,21 +75,21 @@ struct File { * @return end of file flag */ typedef struct { - bool (*open)( + bool (*const open)( void* context, File* file, const char* path, FS_AccessMode access_mode, FS_OpenMode open_mode); - bool (*close)(void* context, File* file); + bool (*const close)(void* context, File* file); uint16_t (*read)(void* context, File* file, void* buff, uint16_t bytes_to_read); uint16_t (*write)(void* context, File* file, const void* buff, uint16_t bytes_to_write); - bool (*seek)(void* context, File* file, uint32_t offset, bool from_start); + bool (*const seek)(void* context, File* file, uint32_t offset, bool from_start); uint64_t (*tell)(void* context, File* file); - bool (*truncate)(void* context, File* file); + bool (*const truncate)(void* context, File* file); uint64_t (*size)(void* context, File* file); - bool (*sync)(void* context, File* file); - bool (*eof)(void* context, File* file); + bool (*const sync)(void* context, File* file); + bool (*const eof)(void* context, File* file); } FS_File_Api; /** Dir api structure @@ -118,10 +118,15 @@ typedef struct { * @return success flag */ typedef struct { - bool (*open)(void* context, File* file, const char* path); - bool (*close)(void* context, File* file); - bool (*read)(void* context, File* file, FileInfo* fileinfo, char* name, uint16_t name_length); - bool (*rewind)(void* context, File* file); + bool (*const open)(void* context, File* file, const char* path); + bool (*const close)(void* context, File* file); + bool (*const read)( + void* context, + File* file, + FileInfo* fileinfo, + char* name, + uint16_t name_length); + bool (*const rewind)(void* context, File* file); } FS_Dir_Api; /** Common api structure @@ -141,12 +146,6 @@ typedef struct { * @param path path to file/directory * @return FS_Error error info * - * @var FS_Common_Api::rename - * @brief Rename file/directory, - * file/directory must not be opened - * @param path path to file/directory - * @return FS_Error error info - * * @var FS_Common_Api::mkdir * @brief Create new directory * @param path path to new directory @@ -160,31 +159,21 @@ typedef struct { * @return FS_Error error info */ typedef struct { - FS_Error (*stat)(void* context, const char* path, FileInfo* fileinfo); - FS_Error (*remove)(void* context, const char* path); - FS_Error (*rename)(void* context, const char* old_path, const char* new_path); - FS_Error (*mkdir)(void* context, const char* path); - FS_Error ( - *fs_info)(void* context, const char* fs_path, uint64_t* total_space, uint64_t* free_space); + FS_Error (*const stat)(void* context, const char* path, FileInfo* fileinfo); + FS_Error (*const remove)(void* context, const char* path); + FS_Error (*const mkdir)(void* context, const char* path); + FS_Error (*const fs_info)( + void* context, + const char* fs_path, + uint64_t* total_space, + uint64_t* free_space); } FS_Common_Api; -/** Errors api structure - * @var FS_Error_Api::get_desc - * @brief Get error description text - * @param error_id FS_Error error id (for fire/dir functions result can be obtained from File.error_id) - * @return pointer to description text - */ -typedef struct { - const char* (*get_desc)(void* context, FS_Error error_id); -} FS_Error_Api; - /** Full filesystem api structure */ typedef struct { - FS_File_Api file; - FS_Dir_Api dir; - FS_Common_Api common; - FS_Error_Api error; - void* context; + const FS_File_Api file; + const FS_Dir_Api dir; + const FS_Common_Api common; } FS_Api; #ifdef __cplusplus diff --git a/applications/storage/storage.c b/applications/storage/storage.c index 9ce8d958..4aa5f105 100644 --- a/applications/storage/storage.c +++ b/applications/storage/storage.c @@ -11,6 +11,8 @@ #define ICON_SD_MOUNTED &I_SDcardMounted_11x8 #define ICON_SD_ERROR &I_SDcardFail_11x8 +#define TAG "Storage" + static void storage_app_sd_icon_draw_callback(Canvas* canvas, void* context) { furi_assert(canvas); furi_assert(context); @@ -63,15 +65,14 @@ void storage_tick(Storage* app) { } } - if(app->storage[ST_EXT].status != app->prev_ext_storage_status) { - app->prev_ext_storage_status = app->storage[ST_EXT].status; - furi_pubsub_publish(app->pubsub, &app->storage[ST_EXT].status); - } - // storage not enabled but was enabled (sd card unmount) if(app->storage[ST_EXT].status == StorageStatusNotReady && app->sd_gui.enabled == true) { app->sd_gui.enabled = false; view_port_enabled_set(app->sd_gui.view_port, false); + + FURI_LOG_I(TAG, "SD card unmount"); + StorageEvent event = {.type = StorageEventTypeCardUnmount}; + furi_pubsub_publish(app->pubsub, &event); } // storage enabled (or in error state) but was not enabled (sd card mount) @@ -83,6 +84,16 @@ void storage_tick(Storage* app) { app->sd_gui.enabled == false) { app->sd_gui.enabled = true; view_port_enabled_set(app->sd_gui.view_port, true); + + if(app->storage[ST_EXT].status == StorageStatusOK) { + FURI_LOG_I(TAG, "SD card mount"); + StorageEvent event = {.type = StorageEventTypeCardMount}; + furi_pubsub_publish(app->pubsub, &event); + } else { + FURI_LOG_I(TAG, "SD card mount error"); + StorageEvent event = {.type = StorageEventTypeCardMountError}; + furi_pubsub_publish(app->pubsub, &event); + } } } diff --git a/applications/storage/storage.h b/applications/storage/storage.h index f70827cb..cf18d485 100644 --- a/applications/storage/storage.h +++ b/applications/storage/storage.h @@ -1,5 +1,6 @@ #pragma once -#include +#include +#include #include "filesystem_api_defines.h" #include "storage_sd_api.h" @@ -18,6 +19,23 @@ File* storage_file_alloc(Storage* storage); */ void storage_file_free(File* file); +typedef enum { + StorageEventTypeCardMount, + StorageEventTypeCardUnmount, + StorageEventTypeCardMountError, + StorageEventTypeFileClose, +} StorageEventType; + +typedef struct { + StorageEventType type; +} StorageEvent; + +/** + * Get storage pubsub. + * Storage will send StorageEvent messages. + * @param storage + * @return FuriPubSub* + */ FuriPubSub* storage_get_pubsub(Storage* storage); /******************* File Functions *******************/ diff --git a/applications/storage/storage_external_api.c b/applications/storage/storage_external_api.c index 9acc9ea4..927bc80e 100644 --- a/applications/storage/storage_external_api.c +++ b/applications/storage/storage_external_api.c @@ -3,6 +3,7 @@ #include "storage.h" #include "storage_i.h" #include "storage_message.h" +#include #define MAX_NAME_LENGTH 256 @@ -49,9 +50,12 @@ #define FILE_OPENED 1 #define FILE_CLOSED 0 +typedef enum { + StorageEventFlagFileClose = (1 << 0), +} StorageEventFlag; /****************** FILE ******************/ -bool storage_file_open( +static bool storage_file_open_internal( File* file, const char* path, FS_AccessMode access_mode, @@ -75,6 +79,41 @@ bool storage_file_open( return S_RETURN_BOOL; } +static void storage_file_close_callback(const void* message, void* context) { + const StorageEvent* storage_event = message; + + if(storage_event->type == StorageEventTypeFileClose) { + furi_assert(context); + osEventFlagsId_t event = context; + osEventFlagsSet(event, StorageEventFlagFileClose); + } +} + +bool storage_file_open( + File* file, + const char* path, + FS_AccessMode access_mode, + FS_OpenMode open_mode) { + bool result; + osEventFlagsId_t event = osEventFlagsNew(NULL); + FuriPubSubSubscription* subscription = furi_pubsub_subscribe( + storage_get_pubsub(file->storage), storage_file_close_callback, event); + + do { + result = storage_file_open_internal(file, path, access_mode, open_mode); + + if(!result && file->error_id == FSE_ALREADY_OPEN) { + osEventFlagsWait(event, StorageEventFlagFileClose, osFlagsWaitAny, osWaitForever); + } else { + break; + } + } while(true); + + furi_pubsub_unsubscribe(storage_get_pubsub(file->storage), subscription); + osEventFlagsDelete(event); + return result; +} + bool storage_file_close(File* file) { S_FILE_API_PROLOGUE; S_API_PROLOGUE; @@ -259,31 +298,44 @@ FS_Error storage_common_remove(Storage* storage, const char* path) { } FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path) { - S_API_PROLOGUE; + FS_Error error = storage_common_copy(storage, old_path, new_path); + if(error == FSE_OK) { + error = storage_common_remove(storage, old_path); + } - SAData data = { - .cpaths = { - .old = old_path, - .new = new_path, - }}; - - S_API_MESSAGE(StorageCommandCommonRename); - S_API_EPILOGUE; - return S_RETURN_ERROR; + return error; } FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path) { - S_API_PROLOGUE; + FS_Error error; - SAData data = { - .cpaths = { - .old = old_path, - .new = new_path, - }}; + FileInfo fileinfo; + error = storage_common_stat(storage, old_path, &fileinfo); - S_API_MESSAGE(StorageCommandCommonCopy); - S_API_EPILOGUE; - return S_RETURN_ERROR; + if(error == FSE_OK) { + if(fileinfo.flags & FSF_DIRECTORY) { + error = storage_common_mkdir(storage, new_path); + } else { + Stream* stream_from = file_stream_alloc(storage); + Stream* stream_to = file_stream_alloc(storage); + + do { + if(!file_stream_open(stream_from, old_path, FSAM_READ, FSOM_OPEN_EXISTING)) break; + if(!file_stream_open(stream_to, new_path, FSAM_WRITE, FSOM_CREATE_NEW)) break; + stream_copy_full(stream_from, stream_to); + } while(false); + + error = file_stream_get_error(stream_from); + if(error == FSE_OK) { + error = file_stream_get_error(stream_to); + } + + stream_free(stream_from); + stream_free(stream_to); + } + } + + return error; } FS_Error storage_common_mkdir(Storage* storage, const char* path) { diff --git a/applications/storage/storage_glue.c b/applications/storage/storage_glue.c index 6271fbd8..7ce8ec2c 100644 --- a/applications/storage/storage_glue.c +++ b/applications/storage/storage_glue.c @@ -103,25 +103,7 @@ bool storage_has_file(const File* file, StorageData* storage_data) { return result; } -StorageType storage_get_type_by_path(const char* path) { - StorageType type = ST_ERROR; - - const char* ext_path = "/ext"; - const char* int_path = "/int"; - const char* any_path = "/any"; - - if(strlen(path) >= strlen(ext_path) && memcmp(path, ext_path, strlen(ext_path)) == 0) { - type = ST_EXT; - } else if(strlen(path) >= strlen(int_path) && memcmp(path, int_path, strlen(int_path)) == 0) { - type = ST_INT; - } else if(strlen(path) >= strlen(any_path) && memcmp(path, any_path, strlen(any_path)) == 0) { - type = ST_ANY; - } - - return type; -} - -bool storage_path_already_open(const char* path, StorageFileList_t array) { +bool storage_path_already_open(string_t path, StorageFileList_t array) { bool open = false; StorageFileList_it_t it; @@ -178,11 +160,7 @@ void* storage_get_storage_file_data(const File* file, StorageData* storage) { return founded_file->file_data; } -void storage_push_storage_file( - File* file, - const char* path, - StorageType type, - StorageData* storage) { +void storage_push_storage_file(File* file, string_t path, StorageType type, StorageData* storage) { StorageFile* storage_file = StorageFileList_push_new(storage->files); furi_check(storage_file != NULL); diff --git a/applications/storage/storage_glue.h b/applications/storage/storage_glue.h index bd8f317b..21147dce 100644 --- a/applications/storage/storage_glue.h +++ b/applications/storage/storage_glue.h @@ -3,7 +3,6 @@ #include #include "filesystem_api_internal.h" #include -#include #include #ifdef __cplusplus @@ -54,7 +53,7 @@ LIST_DEF( CLEAR(API_2(storage_file_clear)))) struct StorageData { - FS_Api fs_api; + const FS_Api* fs_api; StorageApi api; void* data; osMutexId_t mutex; @@ -63,17 +62,12 @@ struct StorageData { }; bool storage_has_file(const File* file, StorageData* storage_data); -StorageType storage_get_type_by_path(const char* path); -bool storage_path_already_open(const char* path, StorageFileList_t files); +bool storage_path_already_open(string_t path, StorageFileList_t files); void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage); void* storage_get_storage_file_data(const File* file, StorageData* storage); -void storage_push_storage_file( - File* file, - const char* path, - StorageType type, - StorageData* storage); +void storage_push_storage_file(File* file, string_t path, StorageType type, StorageData* storage); bool storage_pop_storage_file(File* file, StorageData* storage); #ifdef __cplusplus diff --git a/applications/storage/storage_i.h b/applications/storage/storage_i.h index d69a0ef8..0db5218d 100644 --- a/applications/storage/storage_i.h +++ b/applications/storage/storage_i.h @@ -19,7 +19,6 @@ typedef struct { struct Storage { osMessageQueueId_t message_queue; StorageData storage[STORAGE_COUNT]; - StorageStatus prev_ext_storage_status; StorageSDGui sd_gui; FuriPubSub* pubsub; }; diff --git a/applications/storage/storage_message.h b/applications/storage/storage_message.h index 0d409587..0e58fff2 100644 --- a/applications/storage/storage_message.h +++ b/applications/storage/storage_message.h @@ -47,11 +47,6 @@ typedef struct { FileInfo* fileinfo; } SADataCStat; -typedef struct { - const char* old; - const char* new; -} SADataCPaths; - typedef struct { const char* fs_path; uint64_t* total_space; @@ -84,7 +79,6 @@ typedef union { SADataDRead dread; SADataCStat cstat; - SADataCPaths cpaths; SADataCFSInfo cfsinfo; SADataError error; @@ -120,8 +114,6 @@ typedef enum { StorageCommandDirRewind, StorageCommandCommonStat, StorageCommandCommonRemove, - StorageCommandCommonRename, - StorageCommandCommonCopy, StorageCommandCommonMkDir, StorageCommandCommonFSInfo, StorageCommandSDFormat, diff --git a/applications/storage/storage_processing.c b/applications/storage/storage_processing.c index ccf7de9a..a96d9cfc 100644 --- a/applications/storage/storage_processing.c +++ b/applications/storage/storage_processing.c @@ -1,8 +1,11 @@ #include "storage_processing.h" +#include +#include +#include #define FS_CALL(_storage, _fn) \ storage_data_lock(_storage); \ - ret = _storage->fs_api._fn; \ + ret = _storage->fs_api->_fn; \ storage_data_unlock(_storage); #define ST_CALL(_storage, _fn) \ @@ -11,18 +14,8 @@ storage_data_unlock(_storage); static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) { - StorageData* storage; - - if(type == ST_ANY) { - type = ST_INT; - StorageData* ext_storage = &app->storage[ST_EXT]; - - if(storage_data_status(ext_storage) == StorageStatusOK) { - type = ST_EXT; - } - } - storage = &app->storage[type]; - + furi_check(type == ST_EXT || type == ST_INT); + StorageData* storage = &app->storage[type]; return storage; } @@ -42,10 +35,55 @@ static StorageData* get_storage_by_file(File* file, StorageData* storages) { return storage_data; } -const char* remove_vfs(const char* path) { +static const char* remove_vfs(const char* path) { return path + MIN(4, strlen(path)); } +static const char* ext_path = "/ext"; +static const char* int_path = "/int"; +static const char* any_path = "/any"; + +static StorageType storage_get_type_by_path(Storage* app, const char* path) { + StorageType type = ST_ERROR; + if(strlen(path) >= strlen(ext_path) && memcmp(path, ext_path, strlen(ext_path)) == 0) { + type = ST_EXT; + } else if(strlen(path) >= strlen(int_path) && memcmp(path, int_path, strlen(int_path)) == 0) { + type = ST_INT; + } else if(strlen(path) >= strlen(any_path) && memcmp(path, any_path, strlen(any_path)) == 0) { + type = ST_ANY; + } + + if(type == ST_ANY) { + type = ST_INT; + if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) { + type = ST_EXT; + } + } + + return type; +} + +static void storage_path_change_to_real_storage(string_t path, StorageType real_storage) { + if(memcmp(string_get_cstr(path), any_path, strlen(any_path)) == 0) { + switch(real_storage) { + case ST_EXT: + string_set_char(path, 0, ext_path[0]); + string_set_char(path, 1, ext_path[1]); + string_set_char(path, 2, ext_path[2]); + string_set_char(path, 3, ext_path[3]); + break; + case ST_INT: + string_set_char(path, 0, int_path[0]); + string_set_char(path, 1, int_path[1]); + string_set_char(path, 2, int_path[2]); + string_set_char(path, 3, int_path[3]); + break; + default: + break; + } + } +} + /******************* File Functions *******************/ bool storage_process_file_open( @@ -55,7 +93,7 @@ bool storage_process_file_open( FS_AccessMode access_mode, FS_OpenMode open_mode) { bool ret = false; - StorageType type = storage_get_type_by_path(path); + StorageType type = storage_get_type_by_path(app, path); StorageData* storage; file->error_id = FSE_OK; @@ -63,12 +101,18 @@ bool storage_process_file_open( file->error_id = FSE_INVALID_NAME; } else { storage = storage_get_storage_by_type(app, type); - if(storage_path_already_open(path, storage->files)) { + string_t real_path; + string_init_set(real_path, path); + storage_path_change_to_real_storage(real_path, type); + + if(storage_path_already_open(real_path, storage->files)) { file->error_id = FSE_ALREADY_OPEN; } else { - storage_push_storage_file(file, path, type, storage); + storage_push_storage_file(file, real_path, type, storage); FS_CALL(storage, file.open(storage, file, remove_vfs(path), access_mode, open_mode)); } + + string_clear(real_path); } return ret; @@ -83,6 +127,9 @@ bool storage_process_file_close(Storage* app, File* file) { } else { FS_CALL(storage, file.close(storage, file)); storage_pop_storage_file(file, storage); + + StorageEvent event = {.type = StorageEventTypeFileClose}; + furi_pubsub_publish(app->pubsub, &event); } return ret; @@ -205,7 +252,7 @@ static bool storage_process_file_eof(Storage* app, File* file) { bool storage_process_dir_open(Storage* app, File* file, const char* path) { bool ret = false; - StorageType type = storage_get_type_by_path(path); + StorageType type = storage_get_type_by_path(app, path); StorageData* storage; file->error_id = FSE_OK; @@ -213,12 +260,17 @@ bool storage_process_dir_open(Storage* app, File* file, const char* path) { file->error_id = FSE_INVALID_NAME; } else { storage = storage_get_storage_by_type(app, type); - if(storage_path_already_open(path, storage->files)) { + string_t real_path; + string_init_set(real_path, path); + storage_path_change_to_real_storage(real_path, type); + + if(storage_path_already_open(real_path, storage->files)) { file->error_id = FSE_ALREADY_OPEN; } else { - storage_push_storage_file(file, path, type, storage); + storage_push_storage_file(file, real_path, type, storage); FS_CALL(storage, dir.open(storage, file, remove_vfs(path))); } + string_clear(real_path); } return ret; @@ -273,7 +325,7 @@ bool storage_process_dir_rewind(Storage* app, File* file) { static FS_Error storage_process_common_stat(Storage* app, const char* path, FileInfo* fileinfo) { FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(path); + StorageType type = storage_get_type_by_path(app, path); if(storage_type_is_not_valid(type)) { ret = FSE_INVALID_NAME; @@ -287,7 +339,11 @@ static FS_Error storage_process_common_stat(Storage* app, const char* path, File static FS_Error storage_process_common_remove(Storage* app, const char* path) { FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(path); + StorageType type = storage_get_type_by_path(app, path); + + string_t real_path; + string_init_set(real_path, path); + storage_path_change_to_real_storage(real_path, type); do { if(storage_type_is_not_valid(type)) { @@ -296,7 +352,7 @@ static FS_Error storage_process_common_remove(Storage* app, const char* path) { } StorageData* storage = storage_get_storage_by_type(app, type); - if(storage_path_already_open(path, storage->files)) { + if(storage_path_already_open(real_path, storage->files)) { ret = FSE_ALREADY_OPEN; break; } @@ -304,12 +360,14 @@ static FS_Error storage_process_common_remove(Storage* app, const char* path) { FS_CALL(storage, common.remove(storage, remove_vfs(path))); } while(false); + string_clear(real_path); + return ret; } static FS_Error storage_process_common_mkdir(Storage* app, const char* path) { FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(path); + StorageType type = storage_get_type_by_path(app, path); if(storage_type_is_not_valid(type)) { ret = FSE_INVALID_NAME; @@ -321,86 +379,13 @@ static FS_Error storage_process_common_mkdir(Storage* app, const char* path) { return ret; } -static FS_Error storage_process_common_copy(Storage* app, const char* old, const char* new) { - FS_Error ret = FSE_INTERNAL; - File file_old; - File file_new; - - FileInfo fileinfo; - ret = storage_process_common_stat(app, old, &fileinfo); - - if(ret == FSE_OK) { - if(fileinfo.flags & FSF_DIRECTORY) { - ret = storage_process_common_mkdir(app, new); - } else { - do { - if(!storage_process_file_open(app, &file_old, old, FSAM_READ, FSOM_OPEN_EXISTING)) { - ret = storage_file_get_error(&file_old); - storage_process_file_close(app, &file_old); - break; - } - - if(!storage_process_file_open(app, &file_new, new, FSAM_WRITE, FSOM_CREATE_NEW)) { - ret = storage_file_get_error(&file_new); - storage_process_file_close(app, &file_new); - storage_process_file_close(app, &file_old); - break; - } - - const uint16_t buffer_size = 64; - uint8_t* buffer = malloc(buffer_size); - uint16_t readed_size = 0; - uint16_t writed_size = 0; - - while(true) { - readed_size = storage_process_file_read(app, &file_old, buffer, buffer_size); - ret = storage_file_get_error(&file_old); - if(readed_size == 0) break; - - writed_size = storage_process_file_write(app, &file_new, buffer, readed_size); - ret = storage_file_get_error(&file_new); - if(writed_size < readed_size) break; - } - - free(buffer); - storage_process_file_close(app, &file_old); - storage_process_file_close(app, &file_new); - } while(false); - } - } - - return ret; -} - -static FS_Error storage_process_common_rename(Storage* app, const char* old, const char* new) { - FS_Error ret = FSE_INTERNAL; - StorageType type_old = storage_get_type_by_path(old); - StorageType type_new = storage_get_type_by_path(new); - - if(storage_type_is_not_valid(type_old) || storage_type_is_not_valid(type_new)) { - ret = FSE_INVALID_NAME; - } else { - if(type_old != type_new) { - ret = storage_process_common_copy(app, old, new); - if(ret == FSE_OK) { - ret = storage_process_common_remove(app, old); - } - } else { - StorageData* storage = storage_get_storage_by_type(app, type_old); - FS_CALL(storage, common.rename(storage, remove_vfs(old), remove_vfs(new))); - } - } - - return ret; -} - static FS_Error storage_process_common_fs_info( Storage* app, const char* fs_path, uint64_t* total_space, uint64_t* free_space) { FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(fs_path); + StorageType type = storage_get_type_by_path(app, fs_path); if(storage_type_is_not_valid(type)) { ret = FSE_INVALID_NAME; @@ -472,8 +457,7 @@ static FS_Error storage_process_sd_status(Storage* app) { } /****************** API calls processing ******************/ - -void storage_process_message(Storage* app, StorageMessage* message) { +void storage_process_message_internal(Storage* app, StorageMessage* message) { switch(message->command) { case StorageCommandFileOpen: message->return_data->bool_value = storage_process_file_open( @@ -556,14 +540,6 @@ void storage_process_message(Storage* app, StorageMessage* message) { message->return_data->error_value = storage_process_common_remove(app, message->data->path.path); break; - case StorageCommandCommonRename: - message->return_data->error_value = storage_process_common_rename( - app, message->data->cpaths.old, message->data->cpaths.new); - break; - case StorageCommandCommonCopy: - message->return_data->error_value = - storage_process_common_copy(app, message->data->cpaths.old, message->data->cpaths.new); - break; case StorageCommandCommonMkDir: message->return_data->error_value = storage_process_common_mkdir(app, message->data->path.path); @@ -592,3 +568,7 @@ void storage_process_message(Storage* app, StorageMessage* message) { osSemaphoreRelease(message->semaphore); } + +void storage_process_message(Storage* app, StorageMessage* message) { + storage_process_message_internal(app, message); +} diff --git a/applications/storage/storage_sd_api.h b/applications/storage/storage_sd_api.h index fe6f94af..2db35866 100644 --- a/applications/storage/storage_sd_api.h +++ b/applications/storage/storage_sd_api.h @@ -1,8 +1,6 @@ #pragma once #include #include "filesystem_api_defines.h" -#include -#include "storage_glue.h" #ifdef __cplusplus extern "C" { @@ -11,10 +9,11 @@ extern "C" { #define SD_LABEL_LENGTH 34 typedef enum { - FST_FAT12 = FS_FAT12, - FST_FAT16 = FS_FAT16, - FST_FAT32 = FS_FAT32, - FST_EXFAT = FS_EXFAT, + FST_UNKNOWN, + FST_FAT12, + FST_FAT16, + FST_FAT32, + FST_EXFAT, } SDFsType; typedef struct { diff --git a/applications/storage/storages/storage_ext.c b/applications/storage/storages/storage_ext.c index 1b76ef6c..8a3d21ca 100644 --- a/applications/storage/storages/storage_ext.c +++ b/applications/storage/storages/storage_ext.c @@ -164,7 +164,24 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) { sector_size = fs->ssize; #endif - sd_info->fs_type = fs->fs_type; + switch(fs->fs_type) { + case FS_FAT12: + sd_info->fs_type = FST_FAT12; + break; + case FS_FAT16: + sd_info->fs_type = FST_FAT16; + break; + case FS_FAT32: + sd_info->fs_type = FST_FAT32; + break; + case FS_EXFAT: + sd_info->fs_type = FST_EXFAT; + break; + + default: + sd_info->fs_type = FST_UNKNOWN; + break; + } sd_info->kb_total = total_sectors / 1024 * sector_size; sd_info->kb_free = free_sectors / 1024 * sector_size; @@ -466,11 +483,6 @@ static FS_Error storage_ext_common_remove(void* ctx, const char* path) { return storage_ext_parse_error(result); } -static FS_Error storage_ext_common_rename(void* ctx, const char* old_path, const char* new_path) { - SDError result = f_rename(old_path, new_path); - return storage_ext_parse_error(result); -} - static FS_Error storage_ext_common_mkdir(void* ctx, const char* path) { SDError result = f_mkdir(path); return storage_ext_parse_error(result); @@ -510,6 +522,35 @@ static FS_Error storage_ext_common_fs_info( } /******************* Init Storage *******************/ +static const FS_Api fs_api = { + .file = + { + .open = storage_ext_file_open, + .close = storage_ext_file_close, + .read = storage_ext_file_read, + .write = storage_ext_file_write, + .seek = storage_ext_file_seek, + .tell = storage_ext_file_tell, + .truncate = storage_ext_file_truncate, + .size = storage_ext_file_size, + .sync = storage_ext_file_sync, + .eof = storage_ext_file_eof, + }, + .dir = + { + .open = storage_ext_dir_open, + .close = storage_ext_dir_close, + .read = storage_ext_dir_read, + .rewind = storage_ext_dir_rewind, + }, + .common = + { + .stat = storage_ext_common_stat, + .mkdir = storage_ext_common_mkdir, + .remove = storage_ext_common_remove, + .fs_info = storage_ext_common_fs_info, + }, +}; void storage_ext_init(StorageData* storage) { SDData* sd_data = malloc(sizeof(SDData)); @@ -519,27 +560,7 @@ void storage_ext_init(StorageData* storage) { storage->data = sd_data; storage->api.tick = storage_ext_tick; - storage->fs_api.file.open = storage_ext_file_open; - storage->fs_api.file.close = storage_ext_file_close; - storage->fs_api.file.read = storage_ext_file_read; - storage->fs_api.file.write = storage_ext_file_write; - storage->fs_api.file.seek = storage_ext_file_seek; - storage->fs_api.file.tell = storage_ext_file_tell; - storage->fs_api.file.truncate = storage_ext_file_truncate; - storage->fs_api.file.size = storage_ext_file_size; - storage->fs_api.file.sync = storage_ext_file_sync; - storage->fs_api.file.eof = storage_ext_file_eof; - - storage->fs_api.dir.open = storage_ext_dir_open; - storage->fs_api.dir.close = storage_ext_dir_close; - storage->fs_api.dir.read = storage_ext_dir_read; - storage->fs_api.dir.rewind = storage_ext_dir_rewind; - - storage->fs_api.common.stat = storage_ext_common_stat; - storage->fs_api.common.mkdir = storage_ext_common_mkdir; - storage->fs_api.common.rename = storage_ext_common_rename; - storage->fs_api.common.remove = storage_ext_common_remove; - storage->fs_api.common.fs_info = storage_ext_common_fs_info; + storage->fs_api = &fs_api; hal_sd_detect_init(); diff --git a/applications/storage/storages/storage_int.c b/applications/storage/storages/storage_int.c index 811a1d6a..2f610929 100644 --- a/applications/storage/storages/storage_int.c +++ b/applications/storage/storages/storage_int.c @@ -636,13 +636,6 @@ static FS_Error storage_int_common_remove(void* ctx, const char* path) { return storage_int_parse_error(result); } -static FS_Error storage_int_common_rename(void* ctx, const char* old_path, const char* new_path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - int result = lfs_rename(lfs, old_path, new_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); @@ -671,6 +664,35 @@ static FS_Error storage_int_common_fs_info( } /******************* 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, + }, +}; void storage_int_init(StorageData* storage) { FURI_LOG_I(TAG, "Starting"); @@ -689,25 +711,5 @@ void storage_int_init(StorageData* storage) { storage->data = lfs_data; storage->api.tick = NULL; - storage->fs_api.file.open = storage_int_file_open; - storage->fs_api.file.close = storage_int_file_close; - storage->fs_api.file.read = storage_int_file_read; - storage->fs_api.file.write = storage_int_file_write; - storage->fs_api.file.seek = storage_int_file_seek; - storage->fs_api.file.tell = storage_int_file_tell; - storage->fs_api.file.truncate = storage_int_file_truncate; - storage->fs_api.file.size = storage_int_file_size; - storage->fs_api.file.sync = storage_int_file_sync; - storage->fs_api.file.eof = storage_int_file_eof; - - storage->fs_api.dir.open = storage_int_dir_open; - storage->fs_api.dir.close = storage_int_dir_close; - storage->fs_api.dir.read = storage_int_dir_read; - storage->fs_api.dir.rewind = storage_int_dir_rewind; - - storage->fs_api.common.stat = storage_int_common_stat; - storage->fs_api.common.mkdir = storage_int_common_mkdir; - storage->fs_api.common.rename = storage_int_common_rename; - storage->fs_api.common.remove = storage_int_common_remove; - storage->fs_api.common.fs_info = storage_int_common_fs_info; + storage->fs_api = &fs_api; } diff --git a/applications/tests/storage/storage_test.c b/applications/tests/storage/storage_test.c new file mode 100644 index 00000000..e6ae8c81 --- /dev/null +++ b/applications/tests/storage/storage_test.c @@ -0,0 +1,80 @@ +#include "../minunit.h" +#include +#include +#include + +#define STORAGE_LOCKED_FILE "/ext/locked_file.test" + +static void storage_file_open_lock_setup() { + Storage* storage = furi_record_open("storage"); + File* file = storage_file_alloc(storage); + storage_simply_remove(storage, STORAGE_LOCKED_FILE); + mu_check(storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_WRITE, FSOM_CREATE_NEW)); + mu_check(storage_file_write(file, "0123", 4) == 4); + mu_check(storage_file_close(file)); + storage_file_free(file); + furi_record_close("storage"); +} + +static void storage_file_open_lock_teardown() { + Storage* storage = furi_record_open("storage"); + mu_check(storage_simply_remove(storage, STORAGE_LOCKED_FILE)); + furi_record_close("storage"); +} + +static int32_t storage_file_locker(void* ctx) { + Storage* storage = furi_record_open("storage"); + osSemaphoreId_t semaphore = ctx; + File* file = storage_file_alloc(storage); + furi_check(storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)); + osSemaphoreRelease(semaphore); + furi_hal_delay_ms(1000); + + furi_check(storage_file_close(file)); + furi_record_close("storage"); + storage_file_free(file); + return 0; +} + +MU_TEST(storage_file_open_lock) { + Storage* storage = furi_record_open("storage"); + bool result = false; + osSemaphoreId_t semaphore = osSemaphoreNew(1, 0, NULL); + File* file = storage_file_alloc(storage); + + // file_locker thread start + FuriThread* locker_thread = furi_thread_alloc(); + furi_thread_set_name(locker_thread, "StorageFileLocker"); + furi_thread_set_stack_size(locker_thread, 2048); + furi_thread_set_context(locker_thread, semaphore); + furi_thread_set_callback(locker_thread, storage_file_locker); + mu_check(furi_thread_start(locker_thread)); + + // wait for file lock + osSemaphoreAcquire(semaphore, osWaitForever); + osSemaphoreDelete(semaphore); + + result = storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING); + storage_file_close(file); + + // file_locker thread stop + mu_check(furi_thread_join(locker_thread) == osOK); + furi_thread_free(locker_thread); + + // clean data + storage_file_free(file); + furi_record_close("storage"); + + mu_assert(result, "cannot open locked file"); +} + +MU_TEST_SUITE(storage_file) { + storage_file_open_lock_setup(); + MU_RUN_TEST(storage_file_open_lock); + storage_file_open_lock_teardown(); +} + +int run_minunit_test_storage() { + MU_RUN_SUITE(storage_file); + return MU_EXIT_CODE; +} \ No newline at end of file diff --git a/applications/tests/test_index.c b/applications/tests/test_index.c index 391f759e..16e75414 100644 --- a/applications/tests/test_index.c +++ b/applications/tests/test_index.c @@ -16,6 +16,7 @@ int run_minunit_test_rpc(); int run_minunit_test_flipper_format(); int run_minunit_test_flipper_format_string(); int run_minunit_test_stream(); +int run_minunit_test_storage(); void minunit_print_progress(void) { static char progress[] = {'\\', '|', '/', '-'}; @@ -53,11 +54,12 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { uint32_t cycle_counter = DWT->CYCCNT; test_result |= run_minunit(); - test_result |= run_minunit_test_infrared_decoder_encoder(); - test_result |= run_minunit_test_rpc(); + test_result |= run_minunit_test_storage(); test_result |= run_minunit_test_stream(); test_result |= run_minunit_test_flipper_format(); test_result |= run_minunit_test_flipper_format_string(); + test_result |= run_minunit_test_infrared_decoder_encoder(); + test_result |= run_minunit_test_rpc(); cycle_counter = (DWT->CYCCNT - cycle_counter); FURI_LOG_I(TAG, "Consumed: %0.2fs", (float)cycle_counter / (SystemCoreClock)); diff --git a/lib/toolbox/stream/file_stream.c b/lib/toolbox/stream/file_stream.c index 56dc1de8..f38ae898 100644 --- a/lib/toolbox/stream/file_stream.c +++ b/lib/toolbox/stream/file_stream.c @@ -61,6 +61,13 @@ bool file_stream_close(Stream* _stream) { return storage_file_close(stream->file); } +FS_Error file_stream_get_error(Stream* _stream) { + furi_assert(_stream); + FileStream* stream = (FileStream*)_stream; + furi_check(stream->stream_base.vtable == &file_stream_vtable); + return storage_file_get_error(stream->file); +} + static void file_stream_free(FileStream* stream) { storage_file_free(stream->file); free(stream); diff --git a/lib/toolbox/stream/file_stream.h b/lib/toolbox/stream/file_stream.h index 3f19d07b..ec371a53 100644 --- a/lib/toolbox/stream/file_stream.h +++ b/lib/toolbox/stream/file_stream.h @@ -35,6 +35,13 @@ bool file_stream_open( */ bool file_stream_close(Stream* stream); +/** + * Retrieves the error id from the file object + * @param stream pointer to stream object. + * @return FS_Error error id + */ +FS_Error file_stream_get_error(Stream* stream); + #ifdef __cplusplus } #endif \ No newline at end of file From 88cb90783d649661513dfff3c43e42bb2942ca95 Mon Sep 17 00:00:00 2001 From: Arman Yeghiazaryan Date: Sun, 3 Apr 2022 22:06:20 +0400 Subject: [PATCH 03/12] Corrected variables name's typos #1082 Co-authored-by: SG --- applications/subghz/helpers/subghz_custom_event.h | 6 +++--- applications/subghz/scenes/subghz_scene_receiver.c | 6 +++--- applications/subghz/views/receiver.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/applications/subghz/helpers/subghz_custom_event.h b/applications/subghz/helpers/subghz_custom_event.h index e9890910..97920015 100644 --- a/applications/subghz/helpers/subghz_custom_event.h +++ b/applications/subghz/helpers/subghz_custom_event.h @@ -23,9 +23,9 @@ typedef enum { SubGhzCustomEventSceneExit, SubGhzCustomEventSceneStay, - SubGhzCustomEventViewReceverOK, - SubGhzCustomEventViewReceverConfig, - SubGhzCustomEventViewReceverBack, + SubGhzCustomEventViewReceiverOK, + SubGhzCustomEventViewReceiverConfig, + SubGhzCustomEventViewReceiverBack, SubGhzCustomEventViewReadRAWBack, SubGhzCustomEventViewReadRAWIDLE, diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index ac545e31..dc6b9968 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -111,7 +111,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case SubGhzCustomEventViewReceverBack: + case SubGhzCustomEventViewReceiverBack: // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; @@ -134,13 +134,13 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { } return true; break; - case SubGhzCustomEventViewReceverOK: + case SubGhzCustomEventViewReceiverOK: subghz->txrx->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); return true; break; - case SubGhzCustomEventViewReceverConfig: + case SubGhzCustomEventViewReceiverConfig: subghz->state_notifications = SubGhzNotificationStateIDLE; subghz->txrx->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); diff --git a/applications/subghz/views/receiver.c b/applications/subghz/views/receiver.c index 20ee37d3..03ba5bd2 100644 --- a/applications/subghz/views/receiver.c +++ b/applications/subghz/views/receiver.c @@ -181,7 +181,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiver* subghz_receiver = context; if(event->key == InputKeyBack && event->type == InputTypeShort) { - subghz_receiver->callback(SubGhzCustomEventViewReceverBack, subghz_receiver->context); + subghz_receiver->callback(SubGhzCustomEventViewReceiverBack, subghz_receiver->context); } else if( event->key == InputKeyUp && (event->type == InputTypeShort || event->type == InputTypeRepeat)) { @@ -199,13 +199,13 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { return true; }); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { - subghz_receiver->callback(SubGhzCustomEventViewReceverConfig, subghz_receiver->context); + subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context); } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( subghz_receiver->view, (SubGhzViewReceiverModel * model) { if(model->history_item != 0) { subghz_receiver->callback( - SubGhzCustomEventViewReceverOK, subghz_receiver->context); + SubGhzCustomEventViewReceiverOK, subghz_receiver->context); } return false; }); From e5a1f20fd4e1a9ac86160ed776d9a68c72011975 Mon Sep 17 00:00:00 2001 From: SG Date: Mon, 4 Apr 2022 22:27:48 +1000 Subject: [PATCH 04/12] [FL-2423] Storage: blocking dir open (#1083) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Storage: more unit tests * Storage: blocking dir open, differentiate file and dir when freed. Co-authored-by: あく --- applications/storage/storage.h | 7 ++ applications/storage/storage_external_api.c | 43 ++++++++-- applications/storage/storage_processing.c | 3 + applications/tests/storage/storage_test.c | 91 +++++++++++++++++++++ 4 files changed, 138 insertions(+), 6 deletions(-) diff --git a/applications/storage/storage.h b/applications/storage/storage.h index cf18d485..1ff832e6 100644 --- a/applications/storage/storage.h +++ b/applications/storage/storage.h @@ -24,6 +24,7 @@ typedef enum { StorageEventTypeCardUnmount, StorageEventTypeCardMountError, StorageEventTypeFileClose, + StorageEventTypeDirClose, } StorageEventType; typedef struct { @@ -65,6 +66,12 @@ bool storage_file_close(File* file); */ bool storage_file_is_open(File* file); +/** Tells if the file is a directory + * @param file pointer to a file object + * @return bool true if file is a directory + */ +bool storage_file_is_dir(File* file); + /** Reads bytes from a file into a buffer * @param file pointer to file object. * @param buff pointer to a buffer, for reading diff --git a/applications/storage/storage_external_api.c b/applications/storage/storage_external_api.c index 927bc80e..c6aa2714 100644 --- a/applications/storage/storage_external_api.c +++ b/applications/storage/storage_external_api.c @@ -47,7 +47,8 @@ #define S_RETURN_ERROR (return_data.error_value); #define S_RETURN_CSTRING (return_data.cstring_value); -#define FILE_OPENED 1 +#define FILE_OPENED_FILE 1 +#define FILE_OPENED_DIR 2 #define FILE_CLOSED 0 typedef enum { @@ -71,7 +72,7 @@ static bool storage_file_open_internal( .open_mode = open_mode, }}; - file->file_id = FILE_OPENED; + file->file_id = FILE_OPENED_FILE; S_API_MESSAGE(StorageCommandFileOpen); S_API_EPILOGUE; @@ -82,7 +83,8 @@ static bool storage_file_open_internal( static void storage_file_close_callback(const void* message, void* context) { const StorageEvent* storage_event = message; - if(storage_event->type == StorageEventTypeFileClose) { + if(storage_event->type == StorageEventTypeFileClose || + storage_event->type == StorageEventTypeDirClose) { furi_assert(context); osEventFlagsId_t event = context; osEventFlagsSet(event, StorageEventFlagFileClose); @@ -222,7 +224,7 @@ bool storage_file_eof(File* file) { /****************** DIR ******************/ -bool storage_dir_open(File* file, const char* path) { +static bool storage_dir_open_internal(File* file, const char* path) { S_FILE_API_PROLOGUE; S_API_PROLOGUE; @@ -232,13 +234,34 @@ bool storage_dir_open(File* file, const char* path) { .path = path, }}; - file->file_id = FILE_OPENED; + file->file_id = FILE_OPENED_DIR; S_API_MESSAGE(StorageCommandDirOpen); S_API_EPILOGUE; return S_RETURN_BOOL; } +bool storage_dir_open(File* file, const char* path) { + bool result; + osEventFlagsId_t event = osEventFlagsNew(NULL); + FuriPubSubSubscription* subscription = furi_pubsub_subscribe( + storage_get_pubsub(file->storage), storage_file_close_callback, event); + + do { + result = storage_dir_open_internal(file, path); + + if(!result && file->error_id == FSE_ALREADY_OPEN) { + osEventFlagsWait(event, StorageEventFlagFileClose, osFlagsWaitAny, osWaitForever); + } else { + break; + } + } while(true); + + furi_pubsub_unsubscribe(storage_get_pubsub(file->storage), subscription); + osEventFlagsDelete(event); + return result; +} + bool storage_dir_close(File* file) { S_FILE_API_PROLOGUE; S_API_PROLOGUE; @@ -435,9 +458,17 @@ bool storage_file_is_open(File* file) { return (file->file_id != FILE_CLOSED); } +bool storage_file_is_dir(File* file) { + return (file->file_id == FILE_OPENED_DIR); +} + void storage_file_free(File* file) { if(storage_file_is_open(file)) { - storage_file_close(file); + if(storage_file_is_dir(file)) { + storage_dir_close(file); + } else { + storage_file_close(file); + } } free(file); diff --git a/applications/storage/storage_processing.c b/applications/storage/storage_processing.c index a96d9cfc..bb1ac9c3 100644 --- a/applications/storage/storage_processing.c +++ b/applications/storage/storage_processing.c @@ -285,6 +285,9 @@ bool storage_process_dir_close(Storage* app, File* file) { } else { FS_CALL(storage, dir.close(storage, file)); storage_pop_storage_file(file, storage); + + StorageEvent event = {.type = StorageEventTypeDirClose}; + furi_pubsub_publish(app->pubsub, &event); } return ret; diff --git a/applications/tests/storage/storage_test.c b/applications/tests/storage/storage_test.c index e6ae8c81..3fccc68f 100644 --- a/applications/tests/storage/storage_test.c +++ b/applications/tests/storage/storage_test.c @@ -4,6 +4,7 @@ #include #define STORAGE_LOCKED_FILE "/ext/locked_file.test" +#define STORAGE_LOCKED_DIR "/int" static void storage_file_open_lock_setup() { Storage* storage = furi_record_open("storage"); @@ -68,13 +69,103 @@ MU_TEST(storage_file_open_lock) { mu_assert(result, "cannot open locked file"); } +MU_TEST(storage_file_open_close) { + Storage* storage = furi_record_open("storage"); + File* file; + + file = storage_file_alloc(storage); + mu_check(storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)); + storage_file_close(file); + storage_file_free(file); + + for(size_t i = 0; i < 10; i++) { + file = storage_file_alloc(storage); + mu_check( + storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)); + storage_file_free(file); + } + + furi_record_close("storage"); +} + MU_TEST_SUITE(storage_file) { storage_file_open_lock_setup(); + MU_RUN_TEST(storage_file_open_close); MU_RUN_TEST(storage_file_open_lock); storage_file_open_lock_teardown(); } +MU_TEST(storage_dir_open_close) { + Storage* storage = furi_record_open("storage"); + File* file; + + file = storage_file_alloc(storage); + mu_check(storage_dir_open(file, STORAGE_LOCKED_DIR)); + storage_dir_close(file); + storage_file_free(file); + + for(size_t i = 0; i < 10; i++) { + file = storage_file_alloc(storage); + mu_check(storage_dir_open(file, STORAGE_LOCKED_DIR)); + storage_file_free(file); + } + + furi_record_close("storage"); +} + +static int32_t storage_dir_locker(void* ctx) { + Storage* storage = furi_record_open("storage"); + osSemaphoreId_t semaphore = ctx; + File* file = storage_file_alloc(storage); + furi_check(storage_dir_open(file, STORAGE_LOCKED_DIR)); + osSemaphoreRelease(semaphore); + furi_hal_delay_ms(1000); + + furi_check(storage_dir_close(file)); + furi_record_close("storage"); + storage_file_free(file); + return 0; +} + +MU_TEST(storage_dir_open_lock) { + Storage* storage = furi_record_open("storage"); + bool result = false; + osSemaphoreId_t semaphore = osSemaphoreNew(1, 0, NULL); + File* file = storage_file_alloc(storage); + + // file_locker thread start + FuriThread* locker_thread = furi_thread_alloc(); + furi_thread_set_name(locker_thread, "StorageDirLocker"); + furi_thread_set_stack_size(locker_thread, 2048); + furi_thread_set_context(locker_thread, semaphore); + furi_thread_set_callback(locker_thread, storage_dir_locker); + mu_check(furi_thread_start(locker_thread)); + + // wait for dir lock + osSemaphoreAcquire(semaphore, osWaitForever); + osSemaphoreDelete(semaphore); + + result = storage_dir_open(file, STORAGE_LOCKED_DIR); + storage_dir_close(file); + + // file_locker thread stop + mu_check(furi_thread_join(locker_thread) == osOK); + furi_thread_free(locker_thread); + + // clean data + storage_file_free(file); + furi_record_close("storage"); + + mu_assert(result, "cannot open locked dir"); +} + +MU_TEST_SUITE(storage_dir) { + MU_RUN_TEST(storage_dir_open_close); + MU_RUN_TEST(storage_dir_open_lock); +} + int run_minunit_test_storage() { MU_RUN_SUITE(storage_file); + MU_RUN_SUITE(storage_dir); return MU_EXIT_CODE; } \ No newline at end of file From 1cf3c5c78f33b7c3af10952e152a5f2c620137e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 5 Apr 2022 17:03:13 +0300 Subject: [PATCH 05/12] Add roadmap (#1086) * Add roadmap * correct NFC description Co-authored-by: gornekich --- RoadMap.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 RoadMap.md diff --git a/RoadMap.md b/RoadMap.md new file mode 100644 index 00000000..b075d05c --- /dev/null +++ b/RoadMap.md @@ -0,0 +1,52 @@ +# RoadMap + +# Where we are (0.x.x branch) + +Our goal for 0.x.x branch is to build stable usable apps and API. +First public release that we support in this branch is 0.43.1. Your device most likely came with this version. +You can develop applications but keep in mind that API is not fixed yet. + +## What's already implemented + +**Applications** + +- SubGhz: all most common protocols, RAW for everything else +- 125kHz RFID: all most common protocols +- NFC: Mifare Ultralight read/emulate, MiFare Classic and DESFire read, basic EMV, basic NFC-B,F,V +- Infrared: all most common RC protocols, RAW format for everything else +- GPIO: UART bridge, basic gpio controls +- iButton: DS1990, Cyfral, Metacom +- Bad USB: Full USB Rubber Ducky support, some extras for windows alt codes +- U2F: Full U2F specification support + +**Extras** + +- BLE Keyboard +- Snake game + +**System and HAL** + +- Furi Core +- Furi HAL - hardware abstraction layer that + +# Where we going (Version 1) + +Main goal for 1.0.0 is to provide first stable version for both Users ans Developers. + +## What we plannig to implement for 1.0.0 + +- Update from SD (work in progress, almost done) +- Loading applications from SD (tested as PoC, work scheduled for Q2) +- More protocols (gathering feedback) +- User documentation (work in progress) +- FuriCore: replace CMSIS API, replace hard realtime timers, improve stability and performance (work in progress) +- FuriHal: deep sleep mode, stable API, examples, documentation (work in progress) +- Application improvments (there are a lot of things that we want to add and improve) + +## When it will happen and where I can see progress + +Release 1.0.0 most likely will happen around the end of Q3 + +Development progress can be tracked in our public Miro board: + +https://miro.com/app/board/uXjVO_3D6xU=/?moveToWidget=3458764522498020058&cot=14 From 796e66c29e0d5ac1cb804f160e59408c42f6a5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 5 Apr 2022 17:44:03 +0300 Subject: [PATCH 06/12] Correct spelling in RoadMap (#1088) --- RoadMap.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RoadMap.md b/RoadMap.md index b075d05c..0b45f749 100644 --- a/RoadMap.md +++ b/RoadMap.md @@ -14,7 +14,7 @@ You can develop applications but keep in mind that API is not fixed yet. - 125kHz RFID: all most common protocols - NFC: Mifare Ultralight read/emulate, MiFare Classic and DESFire read, basic EMV, basic NFC-B,F,V - Infrared: all most common RC protocols, RAW format for everything else -- GPIO: UART bridge, basic gpio controls +- GPIO: UART bridge, basic GPIO controls - iButton: DS1990, Cyfral, Metacom - Bad USB: Full USB Rubber Ducky support, some extras for windows alt codes - U2F: Full U2F specification support @@ -33,15 +33,15 @@ You can develop applications but keep in mind that API is not fixed yet. Main goal for 1.0.0 is to provide first stable version for both Users ans Developers. -## What we plannig to implement for 1.0.0 +## What we planning to implement for 1.0.0 - Update from SD (work in progress, almost done) - Loading applications from SD (tested as PoC, work scheduled for Q2) - More protocols (gathering feedback) - User documentation (work in progress) -- FuriCore: replace CMSIS API, replace hard realtime timers, improve stability and performance (work in progress) +- FuriCore: replace CMSIS API, replace hard real time timers, improve stability and performance (work in progress) - FuriHal: deep sleep mode, stable API, examples, documentation (work in progress) -- Application improvments (there are a lot of things that we want to add and improve) +- Application improvements (there are a lot of things that we want to add and improve) ## When it will happen and where I can see progress From 5a8961764e870cf918b0ddc12f576d67d7492dd9 Mon Sep 17 00:00:00 2001 From: agathakazar <34287035+agathakazar@users.noreply.github.com> Date: Wed, 6 Apr 2022 13:40:29 +0300 Subject: [PATCH 07/12] Minor grammar and spelling fixes (#1091) * Minor grammar and spelling fixes in RoadMap * TV's to TVs because grammar --- RoadMap.md | 24 +++++++++---------- .../scene/infrared_app_scene_universal.cpp | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/RoadMap.md b/RoadMap.md index 0b45f749..e8b2bf09 100644 --- a/RoadMap.md +++ b/RoadMap.md @@ -4,15 +4,15 @@ Our goal for 0.x.x branch is to build stable usable apps and API. First public release that we support in this branch is 0.43.1. Your device most likely came with this version. -You can develop applications but keep in mind that API is not fixed yet. +You can develop applications but keep in mind that API is not final yet. ## What's already implemented **Applications** -- SubGhz: all most common protocols, RAW for everything else +- SubGhz: all most common protocols, reading RAW for everything else - 125kHz RFID: all most common protocols -- NFC: Mifare Ultralight read/emulate, MiFare Classic and DESFire read, basic EMV, basic NFC-B,F,V +- NFC: reading/emulating Mifare Ultralight, reading MiFare Classic and DESFire, basic EMV, basic NFC-B,F,V - Infrared: all most common RC protocols, RAW format for everything else - GPIO: UART bridge, basic GPIO controls - iButton: DS1990, Cyfral, Metacom @@ -27,25 +27,25 @@ You can develop applications but keep in mind that API is not fixed yet. **System and HAL** - Furi Core -- Furi HAL - hardware abstraction layer that +- Furi HAL -# Where we going (Version 1) +# Where we're going (Version 1) -Main goal for 1.0.0 is to provide first stable version for both Users ans Developers. +Main goal for 1.0.0 is to provide first stable version for both Users and Developers. -## What we planning to implement for 1.0.0 +## What we're planning to implement in 1.0.0 -- Update from SD (work in progress, almost done) +- Updating firmware from SD (work in progress, almost done) - Loading applications from SD (tested as PoC, work scheduled for Q2) - More protocols (gathering feedback) - User documentation (work in progress) -- FuriCore: replace CMSIS API, replace hard real time timers, improve stability and performance (work in progress) +- FuriCore: get rid of CMSIS API, replace hard real time timers, improve stability and performance (work in progress) - FuriHal: deep sleep mode, stable API, examples, documentation (work in progress) -- Application improvements (there are a lot of things that we want to add and improve) +- Application improvements (a ton of things that we want to add and improve that are too numerous to list here) -## When it will happen and where I can see progress +## When will it happen and where I can see the progress? -Release 1.0.0 most likely will happen around the end of Q3 +Release 1.0.0 will most likely happen around the end of Q3 Development progress can be tracked in our public Miro board: diff --git a/applications/infrared/scene/infrared_app_scene_universal.cpp b/applications/infrared/scene/infrared_app_scene_universal.cpp index b97724fc..57b5653a 100644 --- a/applications/infrared/scene/infrared_app_scene_universal.cpp +++ b/applications/infrared/scene/infrared_app_scene_universal.cpp @@ -20,7 +20,7 @@ void InfraredAppSceneUniversal::on_enter(InfraredApp* app) { InfraredAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - submenu_add_item(submenu, "TV's", SubmenuIndexUniversalTV, submenu_callback, app); + submenu_add_item(submenu, "TVs", SubmenuIndexUniversalTV, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); submenu_item_selected = 0; From b43dcbd74fd5c67ba9ca556adb2f82019abe6b24 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 6 Apr 2022 20:44:06 +0300 Subject: [PATCH 08/12] [FL-2414, FL-2417] Archive: Unlimited file list and various fixes (#1089) * Archive: unlimited file list and various fixes * Recursive remove fix --- applications/archive/helpers/archive_apps.c | 2 + .../archive/helpers/archive_browser.c | 188 +++++++++++++----- .../archive/helpers/archive_browser.h | 11 +- .../archive/helpers/archive_favorites.c | 14 +- applications/archive/helpers/archive_files.c | 87 +++++--- applications/archive/helpers/archive_files.h | 14 +- .../archive/scenes/archive_scene_browser.c | 12 +- .../archive/views/archive_browser_view.c | 102 +++++++--- .../archive/views/archive_browser_view.h | 21 +- .../targets/f7/furi_hal/furi_hal_crypto.c | 5 + 10 files changed, 322 insertions(+), 134 deletions(-) diff --git a/applications/archive/helpers/archive_apps.c b/applications/archive/helpers/archive_apps.c index 9293d225..d3cabd56 100644 --- a/applications/archive/helpers/archive_apps.c +++ b/applications/archive/helpers/archive_apps.c @@ -39,6 +39,8 @@ bool archive_app_read_dir(void* context, const char* path) { furi_assert(path); ArchiveBrowserView* browser = context; + archive_file_array_rm_all(browser); + ArchiveAppTypeEnum app = archive_get_app_type(path); if(app == ArchiveAppTypeU2f) { diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index c1e9cacb..c8e78dca 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -3,25 +3,31 @@ #include "archive_browser.h" #include +bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx) { + size_t array_size = files_array_size(model->files); + + if((idx >= model->array_offset + array_size) || (idx < model->array_offset)) { + return false; + } + + return true; +} + void archive_update_offset(ArchiveBrowserView* browser) { furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - size_t array_size = files_array_size(model->files); - uint16_t bounds = array_size > 3 ? 2 : array_size; + uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt; - if(array_size > 3 && model->idx >= array_size - 1) { - model->list_offset = model->idx - 3; - } else if( - model->last_offset && model->last_offset != model->list_offset && - model->tab_idx == model->last_tab) { - model->list_offset = model->last_offset; - model->last_offset = !model->last_offset; - } else if(model->list_offset < model->idx - bounds) { - model->list_offset = CLAMP(model->idx - 2, array_size - bounds, 0); - } else if(model->list_offset > model->idx - bounds) { - model->list_offset = CLAMP(model->idx - 1, array_size - bounds, 0); + if(model->item_cnt > 3 && model->item_idx >= model->item_cnt - 1) { + model->list_offset = model->item_idx - 3; + } else if(model->list_offset < model->item_idx - bounds) { + model->list_offset = CLAMP(model->item_idx - 2, model->item_cnt - bounds, 0); + } else if(model->list_offset > model->item_idx - bounds) { + model->list_offset = CLAMP(model->item_idx - 1, model->item_cnt - bounds, 0); } + return true; }); } @@ -32,8 +38,8 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) { archive_get_filenames(browser, string_get_cstr(browser->path)); - if(!archive_file_array_size(browser) && !archive_get_depth(browser)) { - archive_switch_tab(browser, DEFAULT_TAB_DIR); + if(!archive_file_get_array_size(browser) && !archive_get_depth(browser)) { + archive_switch_tab(browser, TAB_RIGHT); } else { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { @@ -41,7 +47,7 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) { while(idx < files_array_size(model->files)) { ArchiveFile_t* current = files_array_get(model->files, idx); if(!string_search(current->name, target)) { - model->idx = idx; + model->item_idx = idx + model->array_offset; break; } ++idx; @@ -53,7 +59,9 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) { } } -size_t archive_file_array_size(ArchiveBrowserView* browser) { +size_t archive_file_get_array_size(ArchiveBrowserView* browser) { + furi_assert(browser); + uint16_t size = 0; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { @@ -63,40 +71,60 @@ size_t archive_file_array_size(ArchiveBrowserView* browser) { return size; } -void archive_file_array_rm_selected(ArchiveBrowserView* browser) { +void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) { + furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - files_array_remove_v(model->files, model->idx, model->idx + 1); - model->idx = CLAMP(model->idx, files_array_size(model->files) - 1, 0); + model->item_cnt = count; + return false; + }); +} + +void archive_file_array_rm_selected(ArchiveBrowserView* browser) { + furi_assert(browser); + uint32_t items_cnt = 0; + + with_view_model( + browser->view, (ArchiveBrowserViewModel * model) { + files_array_remove_v( + model->files, + model->item_idx - model->array_offset, + model->item_idx - model->array_offset + 1); + model->item_cnt--; + model->item_idx = CLAMP(model->item_idx, model->item_cnt - 1, 0); + items_cnt = model->item_cnt; return false; }); - if(!archive_file_array_size(browser) && !archive_get_depth(browser)) { - archive_switch_tab(browser, DEFAULT_TAB_DIR); + if((items_cnt == 0) && (archive_get_depth(browser) == 0)) { + archive_switch_tab(browser, TAB_RIGHT); } archive_update_offset(browser); } -void archive_file_array_swap(ArchiveBrowserView* browser, int8_t d) { +void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) { + furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { ArchiveFile_t temp; size_t array_size = files_array_size(model->files) - 1; - uint8_t swap_idx = CLAMP(model->idx + d, array_size, 0); + uint8_t swap_idx = CLAMP(model->item_idx + dir, array_size, 0); - if(model->idx == 0 && d < 0) { + if(model->item_idx == 0 && dir < 0) { ArchiveFile_t_init(&temp); files_array_pop_at(&temp, model->files, array_size); - files_array_push_at(model->files, model->idx, temp); + files_array_push_at(model->files, model->item_idx, temp); ArchiveFile_t_clear(&temp); - } else if(model->idx == array_size && d > 0) { + } else if(model->item_idx == array_size && dir > 0) { ArchiveFile_t_init(&temp); - files_array_pop_at(&temp, model->files, model->last_idx); + files_array_pop_at(&temp, model->files, model->item_idx); files_array_push_at(model->files, array_size, temp); ArchiveFile_t_clear(&temp); } else { - files_array_swap_at(model->files, model->idx, swap_idx); + files_array_swap_at(model->files, model->item_idx, swap_idx); } return false; @@ -104,6 +132,8 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t d) { } void archive_file_array_rm_all(ArchiveBrowserView* browser) { + furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_reset(model->files); @@ -111,23 +141,61 @@ void archive_file_array_rm_all(ArchiveBrowserView* browser) { }); } +bool archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { + furi_assert(browser); + + int32_t offset_new = 0; + + with_view_model( + browser->view, (ArchiveBrowserViewModel * model) { + if(model->item_cnt > FILE_LIST_BUF_LEN) { + if(dir < 0) { + offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 3; + } else if(dir == 0) { + offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 2; + } else { + offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 1; + } + offset_new = CLAMP(offset_new, model->item_cnt - FILE_LIST_BUF_LEN, 0); + } + return false; + }); + + bool res = archive_dir_read_items( + browser, string_get_cstr(browser->path), offset_new, FILE_LIST_BUF_LEN); + + with_view_model( + browser->view, (ArchiveBrowserViewModel * model) { + model->array_offset = offset_new; + model->list_loading = false; + return true; + }); + + return res; +} + ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) { + furi_assert(browser); + ArchiveFile_t* selected; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - selected = files_array_size(model->files) ? files_array_get(model->files, model->idx) : - NULL; + selected = files_array_size(model->files) ? + files_array_get(model->files, model->item_idx - model->array_offset) : + NULL; return false; }); return selected; } ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { + furi_assert(browser); + ArchiveFile_t* selected; - idx = CLAMP(idx, archive_file_array_size(browser), 0); with_view_model( browser->view, (ArchiveBrowserViewModel * model) { + idx = CLAMP(idx - model->array_offset, files_array_size(model->files), 0); selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL; return false; }); @@ -135,6 +203,8 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { } ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) { + furi_assert(browser); + ArchiveTabEnum tab_id; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { @@ -145,10 +215,12 @@ ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) { } uint8_t archive_get_depth(ArchiveBrowserView* browser) { + furi_assert(browser); + uint8_t depth; with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - depth = model->depth; + depth = idx_last_array_size(model->idx_last); return false; }); @@ -165,6 +237,8 @@ const char* archive_get_name(ArchiveBrowserView* browser) { } void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { + furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { model->tab_idx = tab; @@ -172,6 +246,8 @@ void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { }); } void archive_set_last_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { + furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { model->last_tab = model->tab_idx; @@ -198,11 +274,12 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { ArchiveFile_t_init(&item); string_init_set_str(item.name, name); - set_file_type(&item, NULL, app_name + 1, true); + archive_set_file_type(&item, NULL, app_name + 1, true); with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_push_back(model->files, item); + model->item_cnt = files_array_size(model->files); return false; }); ArchiveFile_t_clear(&item); @@ -216,10 +293,11 @@ void archive_add_file_item(ArchiveBrowserView* browser, FileInfo* file_info, con ArchiveFile_t item; - if(filter_by_extension(file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) { + if(archive_filter_by_extension( + file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) { ArchiveFile_t_init(&item); string_init_set_str(item.name, name); - set_file_type(&item, file_info, archive_get_path(browser), false); + archive_set_file_type(&item, file_info, archive_get_path(browser), false); with_view_model( browser->view, (ArchiveBrowserViewModel * model) { @@ -234,12 +312,17 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { furi_assert(browser); with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - model->menu = show; - model->menu_idx = 0; - if(show) { - ArchiveFile_t* selected = files_array_get(model->files, model->idx); - selected->fav = archive_is_favorite("%s", string_get_cstr(selected->name)); + if(archive_is_item_in_array(model, model->item_idx)) { + model->menu = true; + model->menu_idx = 0; + ArchiveFile_t* selected = + files_array_get(model->files, model->item_idx - model->array_offset); + selected->fav = archive_is_favorite("%s", string_get_cstr(selected->name)); + } + } else { + model->menu = false; + model->menu_idx = 0; } return true; @@ -247,6 +330,8 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { } void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { + furi_assert(browser); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { model->move_fav = active; @@ -282,7 +367,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { } else if(strncmp(path, "/app:", 5) == 0) { if(archive_app_is_available(browser, path)) tab_empty = false; } else { - if(archive_dir_not_empty(browser, archive_get_default_path(tab))) tab_empty = false; + uint32_t files_cnt = archive_dir_count_items(browser, archive_get_default_path(tab)); + if(files_cnt > 0) tab_empty = false; } if((tab_empty) && (tab != ArchiveTabBrowser)) { @@ -291,8 +377,9 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { if(model->last_tab != model->tab_idx) { - model->idx = 0; - model->depth = 0; + model->item_idx = 0; + model->array_offset = 0; + idx_last_array_reset(model->idx_last); } return false; }); @@ -305,11 +392,13 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) { furi_assert(browser); furi_assert(name); + archive_dir_count_items(browser, string_get_cstr(name)); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - model->last_idx = model->idx; - model->idx = 0; - model->depth = CLAMP(model->depth + 1, MAX_DEPTH, 0); + idx_last_array_push_back(model->idx_last, model->item_idx); + model->array_offset = 0; + model->item_idx = 0; return false; }); @@ -329,10 +418,11 @@ void archive_leave_dir(ArchiveBrowserView* browser) { string_left(browser->path, pos); } + archive_dir_count_items(browser, path); + with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - model->depth = CLAMP(model->depth - 1, MAX_DEPTH, 0); - model->idx = model->last_idx; + idx_last_array_pop_back(&model->item_idx, model->idx_last); return false; }); diff --git a/applications/archive/helpers/archive_browser.h b/applications/archive/helpers/archive_browser.h index aa42a34a..968564cd 100644 --- a/applications/archive/helpers/archive_browser.h +++ b/applications/archive/helpers/archive_browser.h @@ -2,7 +2,8 @@ #include "../archive_i.h" -#define DEFAULT_TAB_DIR InputKeyRight //default tab swith direction +#define TAB_RIGHT InputKeyRight //default tab swith direction +#define FILE_LIST_BUF_LEN 100 static const char* tab_default_paths[] = { [ArchiveTabFavorites] = "/any/favorites", @@ -56,14 +57,18 @@ inline bool archive_is_known_app(ArchiveFileTypeEnum type) { return (type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown); } +bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx); void archive_update_offset(ArchiveBrowserView* browser); void archive_update_focus(ArchiveBrowserView* browser, const char* target); -size_t archive_file_array_size(ArchiveBrowserView* browser); +bool archive_file_array_load(ArchiveBrowserView* browser, int8_t dir); +size_t archive_file_get_array_size(ArchiveBrowserView* browser); void archive_file_array_rm_selected(ArchiveBrowserView* browser); -void archive_file_array_swap(ArchiveBrowserView* browser, int8_t d); +void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir); void archive_file_array_rm_all(ArchiveBrowserView* browser); +void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count); + ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser); ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx); ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser); diff --git a/applications/archive/helpers/archive_favorites.c b/applications/archive/helpers/archive_favorites.c index 97bf9149..e2777f5e 100644 --- a/applications/archive/helpers/archive_favorites.c +++ b/applications/archive/helpers/archive_favorites.c @@ -84,6 +84,9 @@ bool archive_favorites_read(void* context) { string_init(buffer); bool need_refresh = false; + uint16_t file_count = 0; + + archive_file_array_rm_all(browser); bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); @@ -99,6 +102,7 @@ bool archive_favorites_read(void* context) { if(string_search(buffer, "/app:") == 0) { if(archive_app_is_available(browser, string_get_cstr(buffer))) { archive_add_app_item(browser, string_get_cstr(buffer)); + file_count++; } else { need_refresh = true; } @@ -106,10 +110,12 @@ bool archive_favorites_read(void* context) { bool file_exists = false; file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); - if(file_exists) + if(file_exists) { archive_add_file_item(browser, &file_info, string_get_cstr(buffer)); - else + file_count++; + } else { need_refresh = true; + } } string_reset(buffer); @@ -119,6 +125,8 @@ bool archive_favorites_read(void* context) { file_worker_close(file_worker); file_worker_free(file_worker); + archive_set_item_count(browser, file_count); + if(need_refresh) { archive_favourites_rescan(); } @@ -257,7 +265,7 @@ void archive_favorites_save(void* context) { ArchiveBrowserView* browser = context; FileWorker* file_worker = file_worker_alloc(true); - for(size_t i = 0; i < archive_file_array_size(browser); i++) { + for(size_t i = 0; i < archive_file_get_array_size(browser); i++) { ArchiveFile_t* item = archive_get_file_at(browser, i); archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->name)); } diff --git a/applications/archive/helpers/archive_files.c b/applications/archive/helpers/archive_files.c index 08542bfe..96286519 100644 --- a/applications/archive/helpers/archive_files.c +++ b/applications/archive/helpers/archive_files.c @@ -6,7 +6,7 @@ #define ASSETS_DIR "assets" -bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { +bool archive_filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { furi_assert(file_info); furi_assert(tab_ext); furi_assert(name); @@ -45,7 +45,7 @@ void archive_get_file_extension(char* name, char* ext) { strncpy(ext, dot, MAX_EXT_LEN); } -void set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app) { +void archive_set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app) { furi_assert(file); file->is_app = is_app; @@ -83,21 +83,19 @@ bool archive_get_filenames(void* context, const char* path) { bool res; ArchiveBrowserView* browser = context; - archive_file_array_rm_all(browser); if(archive_get_tab(browser) == ArchiveTabFavorites) { res = archive_favorites_read(browser); } else if(strncmp(path, "/app:", 5) == 0) { res = archive_app_read_dir(browser, path); } else { - res = archive_read_dir(browser, path); + res = archive_file_array_load(browser, 0); } return res; } -bool archive_dir_not_empty(void* context, const char* path) { // can be simpler? +uint32_t archive_dir_count_items(void* context, const char* path) { furi_assert(context); - ArchiveBrowserView* browser = context; FileInfo file_info; @@ -108,23 +106,19 @@ bool archive_dir_not_empty(void* context, const char* path) { // can be simpler? if(!storage_dir_open(directory, path)) { storage_dir_close(directory); storage_file_free(directory); - return false; + return 0; } - bool files_found = false; + uint32_t files_found = 0; while(1) { if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) { break; } - if(files_found) { - break; - } else if((storage_file_get_error(directory) == FSE_OK) && (name[0])) { - if(filter_by_extension( + if((storage_file_get_error(directory) == FSE_OK) && (name[0])) { + if(archive_filter_by_extension( &file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) { - files_found = true; + files_found++; } - } else { - return false; } } storage_dir_close(directory); @@ -132,10 +126,12 @@ bool archive_dir_not_empty(void* context, const char* path) { // can be simpler? furi_record_close("storage"); + archive_set_item_count(browser, files_found); + return files_found; } -bool archive_read_dir(void* context, const char* path) { +uint32_t archive_dir_read_items(void* context, const char* path, uint32_t offset, uint32_t count) { furi_assert(context); ArchiveBrowserView* browser = context; @@ -145,7 +141,6 @@ bool archive_read_dir(void* context, const char* path) { char name[MAX_NAME_LEN]; snprintf(name, MAX_NAME_LEN, "%s/", path); size_t path_len = strlen(name); - size_t files_cnt = 0; if(!storage_dir_open(directory, path)) { storage_dir_close(directory); @@ -153,28 +148,48 @@ bool archive_read_dir(void* context, const char* path) { return false; } - while(1) { + // Skip items before offset + uint32_t items_cnt = 0; + while(items_cnt < offset) { + if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN)) { + break; + } + if(storage_file_get_error(directory) == FSE_OK) { + if(archive_filter_by_extension( + &file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) { + items_cnt++; + } + } else { + break; + } + } + if(items_cnt != offset) { + storage_dir_close(directory); + storage_file_free(directory); + furi_record_close("storage"); + + return false; + } + + items_cnt = 0; + archive_file_array_rm_all(browser); + while(items_cnt < count) { if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN - path_len)) { break; } - if(files_cnt > MAX_FILES) { - break; - } else if(storage_file_get_error(directory) == FSE_OK) { + if(storage_file_get_error(directory) == FSE_OK) { archive_add_file_item(browser, &file_info, name); - ++files_cnt; + items_cnt++; } else { - storage_dir_close(directory); - storage_file_free(directory); - return false; + break; } } storage_dir_close(directory); storage_file_free(directory); - furi_record_close("storage"); - return true; + return (items_cnt == count); } void archive_file_append(const char* path, const char* format, ...) { @@ -210,10 +225,20 @@ void archive_delete_file(void* context, const char* format, ...) { va_end(args); ArchiveBrowserView* browser = context; - FileWorker* file_worker = file_worker_alloc(true); + Storage* fs_api = furi_record_open("storage"); - bool res = file_worker_remove(file_worker, string_get_cstr(filename)); - file_worker_free(file_worker); + FileInfo fileinfo; + storage_common_stat(fs_api, string_get_cstr(filename), &fileinfo); + + bool res = false; + + if(fileinfo.flags & FSF_DIRECTORY) { + res = storage_simply_remove_recursive(fs_api, string_get_cstr(filename)); + } else { + res = (storage_common_remove(fs_api, string_get_cstr(filename)) == FSE_OK); + } + + furi_record_close("storage"); if(archive_is_favorite("%s", string_get_cstr(filename))) { archive_favorites_delete("%s", string_get_cstr(filename)); @@ -224,4 +249,4 @@ void archive_delete_file(void* context, const char* format, ...) { } string_clear(filename); -} \ No newline at end of file +} diff --git a/applications/archive/helpers/archive_files.h b/applications/archive/helpers/archive_files.h index 64549d09..e6f6eaa1 100644 --- a/applications/archive/helpers/archive_files.h +++ b/applications/archive/helpers/archive_files.h @@ -2,8 +2,6 @@ #include "file_worker.h" #include -#define MAX_FILES 100 //temp - typedef enum { ArchiveFileTypeIButton, ArchiveFileTypeNFC, @@ -14,7 +12,7 @@ typedef enum { ArchiveFileTypeU2f, ArchiveFileTypeFolder, ArchiveFileTypeUnknown, - ArchiveFileTypesTotal, + ArchiveFileTypeLoading, } ArchiveFileTypeEnum; typedef struct { @@ -57,12 +55,12 @@ ARRAY_DEF( INIT_SET(API_6(ArchiveFile_t_init_set)), CLEAR(API_2(ArchiveFile_t_clear)))) -bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name); -void set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app); +bool archive_filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name); +void archive_set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app); void archive_trim_file_path(char* name, bool ext); void archive_get_file_extension(char* name, char* ext); bool archive_get_filenames(void* context, const char* path); -bool archive_dir_not_empty(void* context, const char* path); -bool archive_read_dir(void* context, const char* path); +uint32_t archive_dir_count_items(void* context, const char* path); +uint32_t archive_dir_read_items(void* context, const char* path, uint32_t offset, uint32_t count); void archive_file_append(const char* path, const char* format, ...); -void archive_delete_file(void* context, const char* format, ...); \ No newline at end of file +void archive_delete_file(void* context, const char* format, ...); diff --git a/applications/archive/scenes/archive_scene_browser.c b/applications/archive/scenes/archive_scene_browser.c index 462fecbd..9410062d 100644 --- a/applications/archive/scenes/archive_scene_browser.c +++ b/applications/archive/scenes/archive_scene_browser.c @@ -105,7 +105,9 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case ArchiveBrowserEventFileMenuDelete: - scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete); + if(archive_get_tab(browser) != ArchiveTabFavorites) { + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete); + } consumed = true; break; case ArchiveBrowserEventEnterDir: @@ -136,6 +138,14 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { archive_favorites_save(archive->browser); consumed = true; break; + case ArchiveBrowserEventLoadPrevItems: + archive_file_array_load(archive->browser, -1); + consumed = true; + break; + case ArchiveBrowserEventLoadNextItems: + archive_file_array_load(archive->browser, 1); + consumed = true; + break; case ArchiveBrowserEventExit: if(archive_get_depth(browser)) { diff --git a/applications/archive/views/archive_browser_view.c b/applications/archive/views/archive_browser_view.c index fd81124e..cd63c4d7 100644 --- a/applications/archive/views/archive_browser_view.c +++ b/applications/archive/views/archive_browser_view.c @@ -24,6 +24,7 @@ static const Icon* ArchiveItemIcons[] = { [ArchiveFileTypeU2f] = &I_u2f_10px, [ArchiveFileTypeFolder] = &I_dir_10px, [ArchiveFileTypeUnknown] = &I_unknown_10px, + [ArchiveFileTypeLoading] = &I_unknown_10px, // TODO loading icon }; void archive_browser_set_callback( @@ -49,7 +50,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { string_init_set_str(menu[2], "Rename"); string_init_set_str(menu[3], "Delete"); - ArchiveFile_t* selected = files_array_get(model->files, model->idx); + ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); if(!archive_is_known_app(selected->type)) { string_set_str(menu[0], "---"); @@ -58,6 +59,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { } else { if(model->tab_idx == ArchiveTabFavorites) { string_set_str(menu[2], "Move"); + string_set_str(menu[3], "---"); } else if(selected->is_app) { string_set_str(menu[2], "---"); } @@ -100,36 +102,44 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) { furi_assert(model); size_t array_size = files_array_size(model->files); - bool scrollbar = array_size > 4; + bool scrollbar = model->item_cnt > 4; - for(size_t i = 0; i < MIN(array_size, MENU_ITEMS); ++i) { + for(size_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) { string_t str_buff; char cstr_buff[MAX_NAME_LEN]; - size_t idx = CLAMP(i + model->list_offset, array_size, 0); - uint8_t x_offset = (model->move_fav && model->idx == idx) ? MOVE_OFFSET : 0; + size_t idx = CLAMP(i + model->list_offset, model->item_cnt, 0); + uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0; - ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); + ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading; + + if(archive_is_item_in_array(model, idx)) { + ArchiveFile_t* file = + files_array_get(model->files, CLAMP(idx - model->array_offset, array_size - 1, 0)); + strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1); + archive_trim_file_path(cstr_buff, archive_is_known_app(file->type)); + string_init_set_str(str_buff, cstr_buff); + file_type = file->type; + } else { + string_init_set_str(str_buff, "---"); + } - strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1); - archive_trim_file_path(cstr_buff, archive_is_known_app(file->type)); - string_init_set_str(str_buff, cstr_buff); elements_string_fit_width( canvas, str_buff, (scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX) - x_offset); - if(model->idx == idx) { + if(model->item_idx == idx) { archive_draw_frame(canvas, i, scrollbar, model->move_fav); } else { canvas_set_color(canvas, ColorBlack); } - canvas_draw_icon( - canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]); + canvas_draw_icon(canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]); canvas_draw_str(canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); + string_clear(str_buff); } if(scrollbar) { - elements_scrollbar_pos(canvas, 126, 15, 49, model->idx, array_size); + elements_scrollbar_pos(canvas, 126, 15, 49, model->item_idx, model->item_cnt); } if(model->menu) { @@ -173,13 +183,13 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m canvas_set_color(canvas, ColorBlack); } -void archive_view_render(Canvas* canvas, void* model) { - ArchiveBrowserViewModel* m = model; +void archive_view_render(Canvas* canvas, void* mdl) { + ArchiveBrowserViewModel* model = mdl; - archive_render_status_bar(canvas, model); + archive_render_status_bar(canvas, mdl); - if(files_array_size(m->files)) { - draw_list(canvas, m); + if(model->item_cnt > 0) { + draw_list(canvas, model); } else { canvas_draw_str_aligned( canvas, GUI_DISPLAY_WIDTH / 2, 40, AlignCenter, AlignCenter, "Empty"); @@ -191,6 +201,26 @@ View* archive_browser_get_view(ArchiveBrowserView* browser) { return browser->view; } +static bool is_file_list_load_required(ArchiveBrowserViewModel* model) { + size_t array_size = files_array_size(model->files); + + if((model->list_loading) || (array_size >= model->item_cnt)) { + return false; + } + + if((model->array_offset > 0) && + (model->item_idx < (model->array_offset + FILE_LIST_BUF_LEN / 4))) { + return true; + } + + if(((model->array_offset + array_size) < model->item_cnt) && + (model->item_idx > (model->array_offset + array_size - FILE_LIST_BUF_LEN / 4))) { + return true; + } + + return false; +} + bool archive_view_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); @@ -247,22 +277,28 @@ bool archive_view_input(InputEvent* event, void* context) { } } - if(event->key == InputKeyUp || event->key == InputKeyDown) { + if((event->key == InputKeyUp || event->key == InputKeyDown) && + (event->type == InputTypeShort || event->type == InputTypeRepeat)) { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { - uint16_t num_elements = (uint16_t)files_array_size(model->files); - if((event->type == InputTypeShort || event->type == InputTypeRepeat)) { - if(event->key == InputKeyUp) { - model->idx = ((model->idx - 1) + num_elements) % num_elements; - if(move_fav_mode) { - browser->callback(ArchiveBrowserEventFavMoveUp, browser->context); - } - } else if(event->key == InputKeyDown) { - model->idx = (model->idx + 1) % num_elements; - if(move_fav_mode) { - browser->callback( - ArchiveBrowserEventFavMoveDown, browser->context); - } + if(event->key == InputKeyUp) { + model->item_idx = + ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; + if(is_file_list_load_required(model)) { + model->list_loading = true; + browser->callback(ArchiveBrowserEventLoadPrevItems, browser->context); + } + if(move_fav_mode) { + browser->callback(ArchiveBrowserEventFavMoveUp, browser->context); + } + } else if(event->key == InputKeyDown) { + model->item_idx = (model->item_idx + 1) % model->item_cnt; + if(is_file_list_load_required(model)) { + model->list_loading = true; + browser->callback(ArchiveBrowserEventLoadNextItems, browser->context); + } + if(move_fav_mode) { + browser->callback(ArchiveBrowserEventFavMoveDown, browser->context); } } @@ -317,6 +353,7 @@ ArchiveBrowserView* browser_alloc() { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_init(model->files); + idx_last_array_init(model->idx_last); return true; }); @@ -329,6 +366,7 @@ void browser_free(ArchiveBrowserView* browser) { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_clear(model->files); + idx_last_array_clear(model->idx_last); return false; }); diff --git a/applications/archive/views/archive_browser_view.h b/applications/archive/views/archive_browser_view.h index 9fc2cdf0..bec8fe2d 100644 --- a/applications/archive/views/archive_browser_view.h +++ b/applications/archive/views/archive_browser_view.h @@ -14,7 +14,6 @@ #define MAX_EXT_LEN 6 #define FRAME_HEIGHT 12 #define MENU_ITEMS 4 -#define MAX_DEPTH 32 #define MOVE_OFFSET 5 typedef enum { @@ -37,12 +36,18 @@ typedef enum { ArchiveBrowserEventFileMenuPin, ArchiveBrowserEventFileMenuAction, ArchiveBrowserEventFileMenuDelete, + ArchiveBrowserEventEnterDir, + ArchiveBrowserEventFavMoveUp, ArchiveBrowserEventFavMoveDown, ArchiveBrowserEventEnterFavMove, ArchiveBrowserEventExitFavMove, ArchiveBrowserEventSaveFavMove, + + ArchiveBrowserEventLoadPrevItems, + ArchiveBrowserEventLoadNextItems, + ArchiveBrowserEventExit, } ArchiveBrowserEvent; @@ -71,21 +76,23 @@ struct ArchiveBrowserView { string_t path; }; +ARRAY_DEF(idx_last_array, int32_t) + typedef struct { ArchiveTabEnum tab_idx; ArchiveTabEnum last_tab; files_array_t files; + idx_last_array_t idx_last; uint8_t menu_idx; bool move_fav; bool menu; + bool list_loading; - uint16_t idx; - uint16_t last_idx; - uint16_t list_offset; - uint16_t last_offset; - uint8_t depth; - + uint32_t item_cnt; + int32_t item_idx; + int32_t array_offset; + int32_t list_offset; } ArchiveBrowserViewModel; void archive_browser_set_callback( diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/firmware/targets/f7/furi_hal/furi_hal_crypto.c index c34eb735..3cb0e735 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crypto.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crypto.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -182,6 +183,10 @@ static void crypto_enable() { static void crypto_disable() { CLEAR_BIT(AES1->CR, AES_CR_EN); + FURI_CRITICAL_ENTER(); + LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_AES1); + LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1); + FURI_CRITICAL_EXIT(); } static void crypto_key_init(uint32_t* key, uint32_t* iv) { From 321f36d11377cf184ee3daeddbfb2a1daf9433ae Mon Sep 17 00:00:00 2001 From: Dmitry Pavlov Date: Wed, 6 Apr 2022 21:34:51 +0300 Subject: [PATCH 09/12] [FL-2403] Changed (Name and save) buttons name (#1094) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../ibutton/scene/ibutton_scene_readed_key_menu.cpp | 6 +++--- applications/lfrfid/scene/lfrfid_app_scene_readed_menu.cpp | 6 +++--- applications/notification/notification_messages.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp index 19eec4e2..02d540a2 100644 --- a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp @@ -4,7 +4,7 @@ typedef enum { SubmenuIndexWrite, SubmenuIndexEmulate, - SubmenuIndexNameAndSave, + SubmenuIndexSave, SubmenuIndexReadNewKey, } SubmenuIndex; @@ -26,7 +26,7 @@ void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) { if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); } - submenu_add_item(submenu, "Name and save", SubmenuIndexNameAndSave, submenu_callback, app); + submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app); submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); submenu_add_item(submenu, "Read new key", SubmenuIndexReadNewKey, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); @@ -46,7 +46,7 @@ bool iButtonSceneReadedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) { case SubmenuIndexEmulate: app->switch_to_next_scene(iButtonApp::Scene::SceneEmulate); break; - case SubmenuIndexNameAndSave: + case SubmenuIndexSave: app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName); break; case SubmenuIndexReadNewKey: diff --git a/applications/lfrfid/scene/lfrfid_app_scene_readed_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_readed_menu.cpp index e5ffe562..9b0a6d8a 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_readed_menu.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_readed_menu.cpp @@ -2,7 +2,7 @@ typedef enum { SubmenuWrite, - SubmenuNameAndSave, + SubmenuSave, SubmenuEmulate, } SubmenuIndex; @@ -10,7 +10,7 @@ void LfRfidAppSceneReadedMenu::on_enter(LfRfidApp* app, bool need_restore) { auto submenu = app->view_controller.get(); submenu->add_item("Write", SubmenuWrite, submenu_callback, app); - submenu->add_item("Name and Save", SubmenuNameAndSave, submenu_callback, app); + submenu->add_item("Save", SubmenuSave, submenu_callback, app); submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); if(need_restore) { @@ -29,7 +29,7 @@ bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) case SubmenuWrite: app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); break; - case SubmenuNameAndSave: + case SubmenuSave: app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); break; case SubmenuEmulate: diff --git a/applications/notification/notification_messages.c b/applications/notification/notification_messages.c index 44b005d1..3934f5d0 100644 --- a/applications/notification/notification_messages.c +++ b/applications/notification/notification_messages.c @@ -436,4 +436,4 @@ const NotificationSequence sequence_audiovisual_alert = { &message_sound_off, &message_vibro_off, NULL, -}; +}; \ No newline at end of file From 02b9cf90d5cc54f1b7ba3d7950460a460769a56c Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:47:47 +0400 Subject: [PATCH 10/12] [FL-2431, FL-2419] SubGhz: bugfixes (#1098) * [FL-2431] SubGhz: fix Restart with an error (HardFault), while maintaining the RAW signal. * Stream: fix adding maximum string length to arguments * [FL-2419] SubGhz: fix flipper hang/Fatal Error when running edited Sub-GHz file. * SubGhz: remove replace strcpy with strncpy, smaller text buffer and canary * SubGhz: log key loading before load happen, rollback only rx message handling Co-authored-by: Aleksandr Kutuzov --- applications/storage/storage.h | 4 +++- applications/storage/storage_external_api.c | 6 ++--- .../subghz/scenes/subghz_scene_delete.c | 2 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 2 +- .../subghz/scenes/subghz_scene_save_name.c | 8 +++---- applications/subghz/subghz.c | 6 ++++- applications/subghz/subghz_i.c | 24 ++++++++++++------- applications/subghz/subghz_i.h | 8 +++---- lib/subghz/subghz_keystore.c | 3 ++- lib/toolbox/stream/file_stream.c | 2 +- 11 files changed, 41 insertions(+), 26 deletions(-) mode change 100755 => 100644 applications/subghz/subghz_i.c diff --git a/applications/storage/storage.h b/applications/storage/storage.h index 1ff832e6..d5eb87d3 100644 --- a/applications/storage/storage.h +++ b/applications/storage/storage.h @@ -297,13 +297,15 @@ bool storage_simply_mkdir(Storage* storage, const char* path); * @param filename * @param fileextension * @param nextfilename return name + * @param max_len max len name */ void storage_get_next_filename( Storage* storage, const char* dirname, const char* filename, const char* fileextension, - string_t nextfilename); + string_t nextfilename, + uint8_t max_len); #ifdef __cplusplus } diff --git a/applications/storage/storage_external_api.c b/applications/storage/storage_external_api.c index c6aa2714..8e39c08b 100644 --- a/applications/storage/storage_external_api.c +++ b/applications/storage/storage_external_api.c @@ -556,7 +556,8 @@ void storage_get_next_filename( const char* dirname, const char* filename, const char* fileextension, - string_t nextfilename) { + string_t nextfilename, + uint8_t max_len) { string_t temp_str; uint16_t num = 0; @@ -566,8 +567,7 @@ void storage_get_next_filename( num++; string_printf(temp_str, "%s/%s%d%s", dirname, filename, num, fileextension); } - - if(num) { + if(num && (max_len > strlen(filename))) { string_printf(nextfilename, "%s%d", filename, num); } else { string_printf(nextfilename, "%s", filename); diff --git a/applications/subghz/scenes/subghz_scene_delete.c b/applications/subghz/scenes/subghz_scene_delete.c index fa020648..dee16114 100644 --- a/applications/subghz/scenes/subghz_scene_delete.c +++ b/applications/subghz/scenes/subghz_scene_delete.c @@ -49,7 +49,7 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneDelete) { - strcpy(subghz->file_name_tmp, subghz->file_name); + strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); if(subghz_delete_file(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); } else { diff --git a/applications/subghz/scenes/subghz_scene_delete_raw.c b/applications/subghz/scenes/subghz_scene_delete_raw.c index 74ad75ce..df57926c 100644 --- a/applications/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/subghz/scenes/subghz_scene_delete_raw.c @@ -56,7 +56,7 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneDeleteRAW) { - strcpy(subghz->file_name_tmp, subghz->file_name); + strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); if(subghz_delete_file(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); } else { diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index 67e4df8f..d50d5626 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -24,7 +24,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { } path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); - strcpy(subghz->file_name, string_get_cstr(temp_str)); + strncpy(subghz->file_name, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); ret = true; } while(false); diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index 6f552ff9..0edee9ee 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -22,10 +22,10 @@ void subghz_scene_save_name_on_enter(void* context) { //highlighting the entire filename by default dev_name_empty = true; } else { - strcpy(subghz->file_name_tmp, subghz->file_name); + strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { - subghz_get_next_name_file(subghz); + subghz_get_next_name_file(subghz, SUBGHZ_MAX_LEN_NAME); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == SubGhzCustomEventManagerSetRAW) { dev_name_empty = true; @@ -39,7 +39,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name, - 22, //Max len name + SUBGHZ_MAX_LEN_NAME + 1, // buffer size dev_name_empty); ValidatorIsFile* validator_is_file = @@ -52,7 +52,7 @@ void subghz_scene_save_name_on_enter(void* context) { bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeBack) { - strcpy(subghz->file_name, subghz->file_name_tmp); + strncpy(subghz->file_name, subghz->file_name_tmp, SUBGHZ_MAX_LEN_NAME); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index a6c6e24f..3320db48 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -296,6 +296,10 @@ void subghz_free(SubGhz* subghz) { furi_record_close("notification"); subghz->notifications = NULL; + // About birds + furi_assert(subghz->file_name[SUBGHZ_MAX_LEN_NAME] == 0); + furi_assert(subghz->file_name_tmp[SUBGHZ_MAX_LEN_NAME] == 0); + // The rest free(subghz); } @@ -315,7 +319,7 @@ int32_t subghz_app(void* p) { string_init(filename); path_extract_filename_no_ext(p, filename); - strcpy(subghz->file_name, string_get_cstr(filename)); + strncpy(subghz->file_name, string_get_cstr(filename), SUBGHZ_MAX_LEN_NAME); string_clear(filename); if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { //Load Raw TX diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c old mode 100755 new mode 100644 index 01ecebe8..db1a4315 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -208,7 +208,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); - uint32_t version; + uint32_t temp_data32; do { stream_clean(fff_data_stream); @@ -217,25 +217,30 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { break; } - if(!flipper_format_read_header(fff_data_file, temp_str, &version)) { + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { FURI_LOG_E(TAG, "Missing or incorrect header"); break; } if(((!strcmp(string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || (!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && - version == SUBGHZ_KEY_FILE_VERSION) { + temp_data32 == SUBGHZ_KEY_FILE_VERSION) { } else { FURI_LOG_E(TAG, "Type or version mismatch"); break; } - if(!flipper_format_read_uint32( - fff_data_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { + if(!flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&temp_data32, 1)) { FURI_LOG_E(TAG, "Missing Frequency"); break; } + if(!furi_hal_subghz_is_frequency_valid(temp_data32)) { + FURI_LOG_E(TAG, "Frequency not supported"); + break; + } + subghz->txrx->frequency = temp_data32; + if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; @@ -267,6 +272,9 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { if(subghz->txrx->decoder_result) { subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, subghz->txrx->fff_data); + } else { + FURI_LOG_E(TAG, "Protocol not found"); + break; } loaded = true; @@ -283,7 +291,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { return loaded; } -bool subghz_get_next_name_file(SubGhz* subghz) { +bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open("storage"); @@ -294,9 +302,9 @@ bool subghz_get_next_name_file(SubGhz* subghz) { if(strcmp(subghz->file_name, "")) { //get the name of the next free file storage_get_next_filename( - storage, SUBGHZ_RAW_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str); + storage, SUBGHZ_RAW_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str, max_len); - strcpy(subghz->file_name, string_get_cstr(temp_str)); + strncpy(subghz->file_name, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); res = true; } diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index efb3eafa..65e8b3e3 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -33,7 +33,7 @@ #include -#define SUBGHZ_TEXT_STORE_SIZE 40 +#define SUBGHZ_MAX_LEN_NAME 21 extern const char* const subghz_frequencies_text[]; extern const uint32_t subghz_frequencies[]; @@ -115,8 +115,8 @@ struct SubGhz { TextInput* text_input; Widget* widget; DialogsApp* dialogs; - char file_name[SUBGHZ_TEXT_STORE_SIZE + 1]; - char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1]; + char file_name[SUBGHZ_MAX_LEN_NAME + 1]; + char file_name_tmp[SUBGHZ_MAX_LEN_NAME + 1]; SubGhzNotificationState state_notifications; SubGhzViewReceiver* subghz_receiver; @@ -156,7 +156,7 @@ void subghz_sleep(SubGhz* subghz); bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); void subghz_tx_stop(SubGhz* subghz); bool subghz_key_load(SubGhz* subghz, const char* file_path); -bool subghz_get_next_name_file(SubGhz* subghz); +bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, diff --git a/lib/subghz/subghz_keystore.c b/lib/subghz/subghz_keystore.c index d0efc6a0..af953f95 100644 --- a/lib/subghz/subghz_keystore.c +++ b/lib/subghz/subghz_keystore.c @@ -187,6 +187,8 @@ bool subghz_keystore_load(SubGhzKeystore* instance, const char* file_name) { string_t filetype; string_init(filetype); + FURI_LOG_I(TAG, "Loading keystore %s", file_name); + Storage* storage = furi_record_open("storage"); FlipperFormat* flipper_format = flipper_format_file_alloc(storage); @@ -224,7 +226,6 @@ bool subghz_keystore_load(SubGhzKeystore* instance, const char* file_name) { FURI_LOG_E(TAG, "Unknown encryption"); break; } - FURI_LOG_I(TAG, "Loading keystore %s", file_name); } while(0); flipper_format_free(flipper_format); diff --git a/lib/toolbox/stream/file_stream.c b/lib/toolbox/stream/file_stream.c index f38ae898..340cb61a 100644 --- a/lib/toolbox/stream/file_stream.c +++ b/lib/toolbox/stream/file_stream.c @@ -176,7 +176,7 @@ static bool file_stream_delete_and_insert( string_t scratch_name; string_t tmp_name; string_init(tmp_name); - storage_get_next_filename(_stream->storage, "/any", ".scratch", ".pad", tmp_name); + storage_get_next_filename(_stream->storage, "/any", ".scratch", ".pad", tmp_name, 255); string_init_printf(scratch_name, "/any/%s.pad", string_get_cstr(tmp_name)); string_clear(tmp_name); From d63589034221afdd1fc69ac979777a6811878024 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Thu, 7 Apr 2022 18:00:45 +0300 Subject: [PATCH 11/12] [FL-2297, FL-2289] Power info command, Validator fixes (#1097) * Power info command, validator fixes * strdup in validator, fix memory leak * furi_hal_crypto fixed again * FuriHal: limit ARR and CC in speaker hal * FuriHal: LL_TIM_DisableAllOutputs in speaker stop * Rpc: fix memory leak in screen streaming * Get rid of crypto_enable/crypto_disable Co-authored-by: Aleksandr Kutuzov --- .../archive/scenes/archive_scene_rename.c | 4 +- applications/gui/modules/validators.c | 16 ++++- applications/gui/modules/validators.h | 6 +- .../ibutton/scene/ibutton_scene_save_name.cpp | 2 +- .../scene/infrared_app_scene_edit_rename.cpp | 4 +- .../scene/lfrfid_app_scene_save_name.cpp | 2 +- applications/nfc/scenes/nfc_scene_save_name.c | 2 +- applications/power/power_cli.c | 14 +++++ applications/rpc/rpc_cli.c | 5 ++ applications/rpc/rpc_gui.c | 11 ++++ applications/rpc/rpc_system.c | 57 ++++++++++++++--- .../subghz/scenes/subghz_scene_save_name.c | 6 +- applications/subghz/subghz_i.c | 12 ++-- assets/compiled/flipper.pb.h | 26 +++++++- assets/compiled/protobuf_version.h | 2 +- assets/compiled/storage.pb.c | 6 ++ assets/compiled/storage.pb.h | 30 +++++++++ assets/compiled/system.pb.c | 9 +++ assets/compiled/system.pb.h | 47 ++++++++++++++ assets/protobuf | 2 +- .../targets/f7/furi_hal/furi_hal_crypto.c | 58 +++++++++++------ firmware/targets/f7/furi_hal/furi_hal_power.c | 62 +++++++++++++++++++ .../targets/f7/furi_hal/furi_hal_speaker.c | 21 +++++-- .../targets/furi_hal_include/furi_hal_power.h | 23 +++++++ 24 files changed, 372 insertions(+), 55 deletions(-) diff --git a/applications/archive/scenes/archive_scene_rename.c b/applications/archive/scenes/archive_scene_rename.c index 9e573801..e0c4ba6c 100644 --- a/applications/archive/scenes/archive_scene_rename.c +++ b/applications/archive/scenes/archive_scene_rename.c @@ -31,8 +31,8 @@ void archive_scene_rename_on_enter(void* context) { MAX_TEXT_INPUT_LEN, false); - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(archive_get_path(archive->browser), archive->file_extension); + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + archive_get_path(archive->browser), archive->file_extension, NULL); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); diff --git a/applications/gui/modules/validators.c b/applications/gui/modules/validators.c index df0be729..242dbe68 100644 --- a/applications/gui/modules/validators.c +++ b/applications/gui/modules/validators.c @@ -5,11 +5,19 @@ struct ValidatorIsFile { const char* app_path_folder; const char* app_extension; + char* current_name; }; bool validator_is_file_callback(const char* text, string_t error, void* context) { furi_assert(context); ValidatorIsFile* instance = context; + + if(instance->current_name != NULL) { + if(strcmp(instance->current_name, text) == 0) { + return true; + } + } + bool ret = true; string_t path; string_init_printf(path, "%s/%s%s", instance->app_path_folder, text, instance->app_extension); @@ -26,17 +34,21 @@ bool validator_is_file_callback(const char* text, string_t error, void* context) return ret; } -ValidatorIsFile* - validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension) { +ValidatorIsFile* validator_is_file_alloc_init( + const char* app_path_folder, + const char* app_extension, + const char* current_name) { ValidatorIsFile* instance = malloc(sizeof(ValidatorIsFile)); instance->app_path_folder = app_path_folder; instance->app_extension = app_extension; + instance->current_name = strdup(current_name); return instance; } void validator_is_file_free(ValidatorIsFile* instance) { furi_assert(instance); + free(instance->current_name); free(instance); } diff --git a/applications/gui/modules/validators.h b/applications/gui/modules/validators.h index f62064b6..3a834a8a 100644 --- a/applications/gui/modules/validators.h +++ b/applications/gui/modules/validators.h @@ -8,8 +8,10 @@ extern "C" { #endif typedef struct ValidatorIsFile ValidatorIsFile; -ValidatorIsFile* - validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension); +ValidatorIsFile* validator_is_file_alloc_init( + const char* app_path_folder, + const char* app_extension, + const char* current_name); void validator_is_file_free(ValidatorIsFile* instance); diff --git a/applications/ibutton/scene/ibutton_scene_save_name.cpp b/applications/ibutton/scene/ibutton_scene_save_name.cpp index 94ca45d4..9a7ab846 100644 --- a/applications/ibutton/scene/ibutton_scene_save_name.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_name.cpp @@ -35,7 +35,7 @@ void iButtonSceneSaveName::on_enter(iButtonApp* app) { key_name_empty); ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(app->app_folder, app->app_extension); + validator_is_file_alloc_init(app->app_folder, app->app_extension, key_name); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput); diff --git a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp b/applications/infrared/scene/infrared_app_scene_edit_rename.cpp index 4b3578fa..0bdd90ac 100644 --- a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp +++ b/applications/infrared/scene/infrared_app_scene_edit_rename.cpp @@ -21,8 +21,8 @@ void InfraredAppSceneEditRename::on_enter(InfraredApp* app) { enter_name_length = InfraredAppRemoteManager::max_remote_name_length; text_input_set_header_text(text_input, "Name the remote"); - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(app->infrared_directory, app->infrared_extension); + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + app->infrared_directory, app->infrared_extension, remote_name.c_str()); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp index e5fee4fe..c2ad5dd1 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp @@ -22,7 +22,7 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) { key_name_empty); ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(app->app_folder, app->app_extension); + validator_is_file_alloc_init(app->app_folder, app->app_extension, key_name); text_input->set_validator(validator_is_file_callback, validator_is_file); app->view_controller.switch_to(); diff --git a/applications/nfc/scenes/nfc_scene_save_name.c b/applications/nfc/scenes/nfc_scene_save_name.c index f239baa8..aa05c8a6 100755 --- a/applications/nfc/scenes/nfc_scene_save_name.c +++ b/applications/nfc/scenes/nfc_scene_save_name.c @@ -30,7 +30,7 @@ void nfc_scene_save_name_on_enter(void* context) { dev_name_empty); ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(NFC_APP_FOLDER, NFC_APP_EXTENSION); + validator_is_file_alloc_init(NFC_APP_FOLDER, NFC_APP_EXTENSION, nfc->dev->dev_name); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); diff --git a/applications/power/power_cli.c b/applications/power/power_cli.c index f65fb095..110318ac 100644 --- a/applications/power/power_cli.c +++ b/applications/power/power_cli.c @@ -20,6 +20,14 @@ void power_cli_reboot2dfu(Cli* cli, string_t args) { power_reboot(PowerBootModeDfu); } +static void power_cli_info_callback(const char* key, const char* value, bool last, void* context) { + printf("%-24s: %s\r\n", key, value); +} + +void power_cli_info(Cli* cli, string_t args) { + furi_hal_power_info_get(power_cli_info_callback, NULL); +} + void power_cli_debug(Cli* cli, string_t args) { furi_hal_power_dump_state(); } @@ -52,6 +60,7 @@ static void power_cli_command_print_usage() { printf("\toff\t - shutdown power\r\n"); printf("\treboot\t - reboot\r\n"); printf("\treboot2dfu\t - reboot to dfu bootloader\r\n"); + printf("\tinfo\t - show power info\r\n"); printf("\tdebug\t - show debug information\r\n"); printf("\t5v <0 or 1>\t - enable or disable 5v ext\r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { @@ -84,6 +93,11 @@ void power_cli(Cli* cli, string_t args, void* context) { break; } + if(string_cmp_str(cmd, "info") == 0) { + power_cli_info(cli, args); + break; + } + if(string_cmp_str(cmd, "debug") == 0) { power_cli_debug(cli, args); break; diff --git a/applications/rpc/rpc_cli.c b/applications/rpc/rpc_cli.c index 849ef361..fd1f6e7f 100644 --- a/applications/rpc/rpc_cli.c +++ b/applications/rpc/rpc_cli.c @@ -4,6 +4,8 @@ #include #include +#define TAG "RpcCli" + typedef struct { Cli* cli; bool session_close_request; @@ -38,6 +40,9 @@ static void rpc_session_terminated_callback(void* context) { void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) { Rpc* rpc = context; + uint32_t mem_before = memmgr_get_free_heap(); + FURI_LOG_D(TAG, "Free memory %d", mem_before); + furi_hal_usb_lock(); RpcSession* rpc_session = rpc_session_open(rpc); if(rpc_session == NULL) { diff --git a/applications/rpc/rpc_gui.c b/applications/rpc/rpc_gui.c index 3a4e21f0..84051bff 100644 --- a/applications/rpc/rpc_gui.c +++ b/applications/rpc/rpc_gui.c @@ -346,8 +346,19 @@ void rpc_system_gui_free(void* context) { } if(rpc_gui->is_streaming) { + rpc_gui->is_streaming = false; + // Remove GUI framebuffer callback gui_remove_framebuffer_callback( rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); + // Stop and release worker thread + osThreadFlagsSet( + furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit); + furi_thread_join(rpc_gui->transmit_thread); + furi_thread_free(rpc_gui->transmit_thread); + // Release frame + pb_release(&PB_Main_msg, rpc_gui->transmit_frame); + free(rpc_gui->transmit_frame); + rpc_gui->transmit_frame = NULL; } furi_record_close("gui"); free(rpc_gui); diff --git a/applications/rpc/rpc_system.c b/applications/rpc/rpc_system.c index 9884e30a..f3a8242a 100644 --- a/applications/rpc/rpc_system.c +++ b/applications/rpc/rpc_system.c @@ -6,6 +6,11 @@ #include "rpc_i.h" +typedef struct { + RpcSession* session; + PB_Main* response; +} RpcSystemContext; + static void rpc_system_system_ping_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_system_ping_request_tag); @@ -55,11 +60,6 @@ static void rpc_system_system_reboot_process(const PB_Main* request, void* conte } } -typedef struct { - RpcSession* session; - PB_Main* response; -} RpcSystemSystemDeviceInfoContext; - static void rpc_system_system_device_info_callback( const char* key, const char* value, @@ -67,7 +67,7 @@ static void rpc_system_system_device_info_callback( void* context) { furi_assert(key); furi_assert(value); - RpcSystemSystemDeviceInfoContext* ctx = context; + RpcSystemContext* ctx = context; char* str_key = strdup(key); char* str_value = strdup(value); @@ -91,7 +91,7 @@ static void rpc_system_system_device_info_process(const PB_Main* request, void* response->which_content = PB_Main_system_device_info_response_tag; response->command_status = PB_CommandStatus_OK; - RpcSystemSystemDeviceInfoContext device_info_context = { + RpcSystemContext device_info_context = { .session = session, .response = response, }; @@ -202,6 +202,46 @@ static void rpc_system_system_protobuf_version_process(const PB_Main* request, v free(response); } +static void rpc_system_system_power_info_callback( + const char* key, + const char* value, + bool last, + void* context) { + furi_assert(key); + furi_assert(value); + RpcSystemContext* ctx = context; + + char* str_key = strdup(key); + char* str_value = strdup(value); + + ctx->response->has_next = !last; + ctx->response->content.system_device_info_response.key = str_key; + ctx->response->content.system_device_info_response.value = str_value; + + rpc_send_and_release(ctx->session, ctx->response); +} + +static void rpc_system_system_get_power_info_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_system_power_info_request_tag); + + RpcSession* session = (RpcSession*)context; + furi_assert(session); + + PB_Main* response = malloc(sizeof(PB_Main)); + response->command_id = request->command_id; + response->which_content = PB_Main_system_power_info_response_tag; + response->command_status = PB_CommandStatus_OK; + + RpcSystemContext power_info_context = { + .session = session, + .response = response, + }; + furi_hal_power_info_get(rpc_system_system_power_info_callback, &power_info_context); + + free(response); +} + void* rpc_system_system_alloc(RpcSession* session) { RpcHandler rpc_handler = { .message_handler = NULL, @@ -233,5 +273,8 @@ void* rpc_system_system_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_system_system_protobuf_version_process; rpc_add_handler(session, PB_Main_system_protobuf_version_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_system_get_power_info_process; + rpc_add_handler(session, PB_Main_system_power_info_request_tag, &rpc_handler); + return NULL; } diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index 0edee9ee..539eb166 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -42,8 +42,10 @@ void subghz_scene_save_name_on_enter(void* context) { SUBGHZ_MAX_LEN_NAME + 1, // buffer size dev_name_empty); - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION); + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + SUBGHZ_APP_FOLDER, + SUBGHZ_APP_EXTENSION, + (dev_name_empty) ? (NULL) : (subghz->file_name_tmp)); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index db1a4315..8f7f2cc6 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -400,12 +400,14 @@ bool subghz_rename_file(SubGhz* subghz) { string_init_printf( new_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); - FS_Error fs_result = - storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path)); + if(string_cmp(old_path, new_path) != 0) { + FS_Error fs_result = + storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path)); - if(fs_result != FSE_OK) { - dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory"); - ret = false; + if(fs_result != FSE_OK) { + dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory"); + ret = false; + } } string_clear(old_path); diff --git a/assets/compiled/flipper.pb.h b/assets/compiled/flipper.pb.h index 5f283889..88548bea 100644 --- a/assets/compiled/flipper.pb.h +++ b/assets/compiled/flipper.pb.h @@ -98,6 +98,11 @@ typedef struct _PB_Main { PB_System_PlayAudiovisualAlertRequest system_play_audiovisual_alert_request; PB_System_ProtobufVersionRequest system_protobuf_version_request; PB_System_ProtobufVersionResponse system_protobuf_version_response; + PB_System_UpdateRequest system_update_request; + PB_Storage_BackupCreateRequest storage_backup_create_request; + PB_Storage_BackupRestoreRequest storage_backup_restore_request; + PB_System_PowerInfoRequest system_power_info_request; + PB_System_PowerInfoResponse system_power_info_response; } content; } PB_Main; @@ -161,6 +166,11 @@ extern "C" { #define PB_Main_system_play_audiovisual_alert_request_tag 38 #define PB_Main_system_protobuf_version_request_tag 39 #define PB_Main_system_protobuf_version_response_tag 40 +#define PB_Main_system_update_request_tag 41 +#define PB_Main_storage_backup_create_request_tag 42 +#define PB_Main_storage_backup_restore_request_tag 43 +#define PB_Main_system_power_info_request_tag 44 +#define PB_Main_system_power_info_response_tag 45 /* Struct field encoding specification for nanopb */ #define PB_Empty_FIELDLIST(X, a) \ @@ -213,7 +223,12 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,system_get_datetime_response,content X(a, STATIC, ONEOF, MSG_W_CB, (content,system_set_datetime_request,content.system_set_datetime_request), 37) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,system_play_audiovisual_alert_request,content.system_play_audiovisual_alert_request), 38) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,system_protobuf_version_request,content.system_protobuf_version_request), 39) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_protobuf_version_response,content.system_protobuf_version_response), 40) +X(a, STATIC, ONEOF, MSG_W_CB, (content,system_protobuf_version_response,content.system_protobuf_version_response), 40) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,system_update_request,content.system_update_request), 41) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_create_request,content.storage_backup_create_request), 42) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_restore_request,content.storage_backup_restore_request), 43) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_request,content.system_power_info_request), 44) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_response,content.system_power_info_response), 45) #define PB_Main_CALLBACK NULL #define PB_Main_DEFAULT NULL #define PB_Main_content_empty_MSGTYPE PB_Empty @@ -253,6 +268,11 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,system_protobuf_version_response,con #define PB_Main_content_system_play_audiovisual_alert_request_MSGTYPE PB_System_PlayAudiovisualAlertRequest #define PB_Main_content_system_protobuf_version_request_MSGTYPE PB_System_ProtobufVersionRequest #define PB_Main_content_system_protobuf_version_response_MSGTYPE PB_System_ProtobufVersionResponse +#define PB_Main_content_system_update_request_MSGTYPE PB_System_UpdateRequest +#define PB_Main_content_storage_backup_create_request_MSGTYPE PB_Storage_BackupCreateRequest +#define PB_Main_content_storage_backup_restore_request_MSGTYPE PB_Storage_BackupRestoreRequest +#define PB_Main_content_system_power_info_request_MSGTYPE PB_System_PowerInfoRequest +#define PB_Main_content_system_power_info_response_MSGTYPE PB_System_PowerInfoResponse extern const pb_msgdesc_t PB_Empty_msg; extern const pb_msgdesc_t PB_StopSession_msg; @@ -266,9 +286,9 @@ extern const pb_msgdesc_t PB_Main_msg; /* Maximum encoded size of messages (where known) */ #define PB_Empty_size 0 #define PB_StopSession_size 0 -#if defined(PB_System_PingRequest_size) && defined(PB_System_PingResponse_size) && defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) && defined(PB_Gui_StartVirtualDisplayRequest_size) && defined(PB_Storage_InfoRequest_size) && defined(PB_Storage_RenameRequest_size) && defined(PB_System_DeviceInfoResponse_size) +#if defined(PB_System_PingRequest_size) && defined(PB_System_PingResponse_size) && defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) && defined(PB_Gui_StartVirtualDisplayRequest_size) && defined(PB_Storage_InfoRequest_size) && defined(PB_Storage_RenameRequest_size) && defined(PB_System_DeviceInfoResponse_size) && defined(PB_System_UpdateRequest_size) && defined(PB_Storage_BackupCreateRequest_size) && defined(PB_Storage_BackupRestoreRequest_size) && defined(PB_System_PowerInfoResponse_size) #define PB_Main_size (10 + sizeof(union PB_Main_content_size_union)) -union PB_Main_content_size_union {char f5[(6 + PB_System_PingRequest_size)]; char f6[(6 + PB_System_PingResponse_size)]; char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f26[(7 + PB_Gui_StartVirtualDisplayRequest_size)]; char f28[(7 + PB_Storage_InfoRequest_size)]; char f30[(7 + PB_Storage_RenameRequest_size)]; char f33[(7 + PB_System_DeviceInfoResponse_size)]; char f0[36];}; +union PB_Main_content_size_union {char f5[(6 + PB_System_PingRequest_size)]; char f6[(6 + PB_System_PingResponse_size)]; char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f26[(7 + PB_Gui_StartVirtualDisplayRequest_size)]; char f28[(7 + PB_Storage_InfoRequest_size)]; char f30[(7 + PB_Storage_RenameRequest_size)]; char f33[(7 + PB_System_DeviceInfoResponse_size)]; char f41[(7 + PB_System_UpdateRequest_size)]; char f42[(7 + PB_Storage_BackupCreateRequest_size)]; char f43[(7 + PB_Storage_BackupRestoreRequest_size)]; char f45[(7 + PB_System_PowerInfoResponse_size)]; char f0[36];}; #endif #ifdef __cplusplus diff --git a/assets/compiled/protobuf_version.h b/assets/compiled/protobuf_version.h index 19d3f1ea..53e0b73b 100644 --- a/assets/compiled/protobuf_version.h +++ b/assets/compiled/protobuf_version.h @@ -1,3 +1,3 @@ #pragma once #define PROTOBUF_MAJOR_VERSION 0 -#define PROTOBUF_MINOR_VERSION 3 +#define PROTOBUF_MINOR_VERSION 5 diff --git a/assets/compiled/storage.pb.c b/assets/compiled/storage.pb.c index 9db544cb..244b273d 100644 --- a/assets/compiled/storage.pb.c +++ b/assets/compiled/storage.pb.c @@ -51,5 +51,11 @@ PB_BIND(PB_Storage_Md5sumResponse, PB_Storage_Md5sumResponse, AUTO) PB_BIND(PB_Storage_RenameRequest, PB_Storage_RenameRequest, AUTO) +PB_BIND(PB_Storage_BackupCreateRequest, PB_Storage_BackupCreateRequest, AUTO) + + +PB_BIND(PB_Storage_BackupRestoreRequest, PB_Storage_BackupRestoreRequest, AUTO) + + diff --git a/assets/compiled/storage.pb.h b/assets/compiled/storage.pb.h index 8a86c937..9b31dc31 100644 --- a/assets/compiled/storage.pb.h +++ b/assets/compiled/storage.pb.h @@ -16,6 +16,14 @@ typedef enum _PB_Storage_File_FileType { } PB_Storage_File_FileType; /* Struct definitions */ +typedef struct _PB_Storage_BackupCreateRequest { + char *archive_path; +} PB_Storage_BackupCreateRequest; + +typedef struct _PB_Storage_BackupRestoreRequest { + char *archive_path; +} PB_Storage_BackupRestoreRequest; + typedef struct _PB_Storage_InfoRequest { char *path; } PB_Storage_InfoRequest; @@ -114,6 +122,8 @@ extern "C" { #define PB_Storage_Md5sumRequest_init_default {NULL} #define PB_Storage_Md5sumResponse_init_default {""} #define PB_Storage_RenameRequest_init_default {NULL, NULL} +#define PB_Storage_BackupCreateRequest_init_default {NULL} +#define PB_Storage_BackupRestoreRequest_init_default {NULL} #define PB_Storage_File_init_zero {_PB_Storage_File_FileType_MIN, NULL, 0, NULL} #define PB_Storage_InfoRequest_init_zero {NULL} #define PB_Storage_InfoResponse_init_zero {0, 0} @@ -129,8 +139,12 @@ extern "C" { #define PB_Storage_Md5sumRequest_init_zero {NULL} #define PB_Storage_Md5sumResponse_init_zero {""} #define PB_Storage_RenameRequest_init_zero {NULL, NULL} +#define PB_Storage_BackupCreateRequest_init_zero {NULL} +#define PB_Storage_BackupRestoreRequest_init_zero {NULL} /* Field tags (for use in manual encoding/decoding) */ +#define PB_Storage_BackupCreateRequest_archive_path_tag 1 +#define PB_Storage_BackupRestoreRequest_archive_path_tag 1 #define PB_Storage_InfoRequest_path_tag 1 #define PB_Storage_ListRequest_path_tag 1 #define PB_Storage_Md5sumRequest_path_tag 1 @@ -241,6 +255,16 @@ X(a, POINTER, SINGULAR, STRING, new_path, 2) #define PB_Storage_RenameRequest_CALLBACK NULL #define PB_Storage_RenameRequest_DEFAULT NULL +#define PB_Storage_BackupCreateRequest_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, STRING, archive_path, 1) +#define PB_Storage_BackupCreateRequest_CALLBACK NULL +#define PB_Storage_BackupCreateRequest_DEFAULT NULL + +#define PB_Storage_BackupRestoreRequest_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, STRING, archive_path, 1) +#define PB_Storage_BackupRestoreRequest_CALLBACK NULL +#define PB_Storage_BackupRestoreRequest_DEFAULT NULL + extern const pb_msgdesc_t PB_Storage_File_msg; extern const pb_msgdesc_t PB_Storage_InfoRequest_msg; extern const pb_msgdesc_t PB_Storage_InfoResponse_msg; @@ -256,6 +280,8 @@ extern const pb_msgdesc_t PB_Storage_MkdirRequest_msg; extern const pb_msgdesc_t PB_Storage_Md5sumRequest_msg; extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg; extern const pb_msgdesc_t PB_Storage_RenameRequest_msg; +extern const pb_msgdesc_t PB_Storage_BackupCreateRequest_msg; +extern const pb_msgdesc_t PB_Storage_BackupRestoreRequest_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_Storage_File_fields &PB_Storage_File_msg @@ -273,6 +299,8 @@ extern const pb_msgdesc_t PB_Storage_RenameRequest_msg; #define PB_Storage_Md5sumRequest_fields &PB_Storage_Md5sumRequest_msg #define PB_Storage_Md5sumResponse_fields &PB_Storage_Md5sumResponse_msg #define PB_Storage_RenameRequest_fields &PB_Storage_RenameRequest_msg +#define PB_Storage_BackupCreateRequest_fields &PB_Storage_BackupCreateRequest_msg +#define PB_Storage_BackupRestoreRequest_fields &PB_Storage_BackupRestoreRequest_msg /* Maximum encoded size of messages (where known) */ /* PB_Storage_File_size depends on runtime parameters */ @@ -288,6 +316,8 @@ extern const pb_msgdesc_t PB_Storage_RenameRequest_msg; /* PB_Storage_MkdirRequest_size depends on runtime parameters */ /* PB_Storage_Md5sumRequest_size depends on runtime parameters */ /* PB_Storage_RenameRequest_size depends on runtime parameters */ +/* PB_Storage_BackupCreateRequest_size depends on runtime parameters */ +/* PB_Storage_BackupRestoreRequest_size depends on runtime parameters */ #define PB_Storage_InfoResponse_size 22 #define PB_Storage_Md5sumResponse_size 34 diff --git a/assets/compiled/system.pb.c b/assets/compiled/system.pb.c index 8f2a37ae..45ab3a01 100644 --- a/assets/compiled/system.pb.c +++ b/assets/compiled/system.pb.c @@ -45,5 +45,14 @@ PB_BIND(PB_System_ProtobufVersionRequest, PB_System_ProtobufVersionRequest, AUTO PB_BIND(PB_System_ProtobufVersionResponse, PB_System_ProtobufVersionResponse, AUTO) +PB_BIND(PB_System_UpdateRequest, PB_System_UpdateRequest, AUTO) + + +PB_BIND(PB_System_PowerInfoRequest, PB_System_PowerInfoRequest, AUTO) + + +PB_BIND(PB_System_PowerInfoResponse, PB_System_PowerInfoResponse, AUTO) + + diff --git a/assets/compiled/system.pb.h b/assets/compiled/system.pb.h index 93c32b22..0932c6fb 100644 --- a/assets/compiled/system.pb.h +++ b/assets/compiled/system.pb.h @@ -45,10 +45,23 @@ typedef struct _PB_System_PlayAudiovisualAlertRequest { char dummy_field; } PB_System_PlayAudiovisualAlertRequest; +typedef struct _PB_System_PowerInfoRequest { + char dummy_field; +} PB_System_PowerInfoRequest; + +typedef struct _PB_System_PowerInfoResponse { + char *key; + char *value; +} PB_System_PowerInfoResponse; + typedef struct _PB_System_ProtobufVersionRequest { char dummy_field; } PB_System_ProtobufVersionRequest; +typedef struct _PB_System_UpdateRequest { + char *update_folder; +} PB_System_UpdateRequest; + typedef struct _PB_System_DateTime { /* Time */ uint8_t hour; /* *< Hour in 24H format: 0-23 */ @@ -105,6 +118,9 @@ extern "C" { #define PB_System_PlayAudiovisualAlertRequest_init_default {0} #define PB_System_ProtobufVersionRequest_init_default {0} #define PB_System_ProtobufVersionResponse_init_default {0, 0} +#define PB_System_UpdateRequest_init_default {NULL} +#define PB_System_PowerInfoRequest_init_default {0} +#define PB_System_PowerInfoResponse_init_default {NULL, NULL} #define PB_System_PingRequest_init_zero {NULL} #define PB_System_PingResponse_init_zero {NULL} #define PB_System_RebootRequest_init_zero {_PB_System_RebootRequest_RebootMode_MIN} @@ -118,12 +134,18 @@ extern "C" { #define PB_System_PlayAudiovisualAlertRequest_init_zero {0} #define PB_System_ProtobufVersionRequest_init_zero {0} #define PB_System_ProtobufVersionResponse_init_zero {0, 0} +#define PB_System_UpdateRequest_init_zero {NULL} +#define PB_System_PowerInfoRequest_init_zero {0} +#define PB_System_PowerInfoResponse_init_zero {NULL, NULL} /* Field tags (for use in manual encoding/decoding) */ #define PB_System_DeviceInfoResponse_key_tag 1 #define PB_System_DeviceInfoResponse_value_tag 2 #define PB_System_PingRequest_data_tag 1 #define PB_System_PingResponse_data_tag 1 +#define PB_System_PowerInfoResponse_key_tag 1 +#define PB_System_PowerInfoResponse_value_tag 2 +#define PB_System_UpdateRequest_update_folder_tag 1 #define PB_System_DateTime_hour_tag 1 #define PB_System_DateTime_minute_tag 2 #define PB_System_DateTime_second_tag 3 @@ -213,6 +235,22 @@ X(a, STATIC, SINGULAR, UINT32, minor, 2) #define PB_System_ProtobufVersionResponse_CALLBACK NULL #define PB_System_ProtobufVersionResponse_DEFAULT NULL +#define PB_System_UpdateRequest_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, STRING, update_folder, 1) +#define PB_System_UpdateRequest_CALLBACK NULL +#define PB_System_UpdateRequest_DEFAULT NULL + +#define PB_System_PowerInfoRequest_FIELDLIST(X, a) \ + +#define PB_System_PowerInfoRequest_CALLBACK NULL +#define PB_System_PowerInfoRequest_DEFAULT NULL + +#define PB_System_PowerInfoResponse_FIELDLIST(X, a) \ +X(a, POINTER, SINGULAR, STRING, key, 1) \ +X(a, POINTER, SINGULAR, STRING, value, 2) +#define PB_System_PowerInfoResponse_CALLBACK NULL +#define PB_System_PowerInfoResponse_DEFAULT NULL + extern const pb_msgdesc_t PB_System_PingRequest_msg; extern const pb_msgdesc_t PB_System_PingResponse_msg; extern const pb_msgdesc_t PB_System_RebootRequest_msg; @@ -226,6 +264,9 @@ extern const pb_msgdesc_t PB_System_DateTime_msg; extern const pb_msgdesc_t PB_System_PlayAudiovisualAlertRequest_msg; extern const pb_msgdesc_t PB_System_ProtobufVersionRequest_msg; extern const pb_msgdesc_t PB_System_ProtobufVersionResponse_msg; +extern const pb_msgdesc_t PB_System_UpdateRequest_msg; +extern const pb_msgdesc_t PB_System_PowerInfoRequest_msg; +extern const pb_msgdesc_t PB_System_PowerInfoResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_System_PingRequest_fields &PB_System_PingRequest_msg @@ -241,17 +282,23 @@ extern const pb_msgdesc_t PB_System_ProtobufVersionResponse_msg; #define PB_System_PlayAudiovisualAlertRequest_fields &PB_System_PlayAudiovisualAlertRequest_msg #define PB_System_ProtobufVersionRequest_fields &PB_System_ProtobufVersionRequest_msg #define PB_System_ProtobufVersionResponse_fields &PB_System_ProtobufVersionResponse_msg +#define PB_System_UpdateRequest_fields &PB_System_UpdateRequest_msg +#define PB_System_PowerInfoRequest_fields &PB_System_PowerInfoRequest_msg +#define PB_System_PowerInfoResponse_fields &PB_System_PowerInfoResponse_msg /* Maximum encoded size of messages (where known) */ /* PB_System_PingRequest_size depends on runtime parameters */ /* PB_System_PingResponse_size depends on runtime parameters */ /* PB_System_DeviceInfoResponse_size depends on runtime parameters */ +/* PB_System_UpdateRequest_size depends on runtime parameters */ +/* PB_System_PowerInfoResponse_size depends on runtime parameters */ #define PB_System_DateTime_size 22 #define PB_System_DeviceInfoRequest_size 0 #define PB_System_FactoryResetRequest_size 0 #define PB_System_GetDateTimeRequest_size 0 #define PB_System_GetDateTimeResponse_size 24 #define PB_System_PlayAudiovisualAlertRequest_size 0 +#define PB_System_PowerInfoRequest_size 0 #define PB_System_ProtobufVersionRequest_size 0 #define PB_System_ProtobufVersionResponse_size 12 #define PB_System_RebootRequest_size 2 diff --git a/assets/protobuf b/assets/protobuf index cd11b029..0403ae1b 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit cd11b029ac21462ea8a7615126d0a29e087c2908 +Subproject commit 0403ae1ba7a4501274da54b3aa6274f76fdd090c diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/firmware/targets/f7/furi_hal/furi_hal_crypto.c index 3cb0e735..2164ebc3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crypto.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crypto.c @@ -15,13 +15,16 @@ #define CRYPTO_TIMEOUT (1000) #define CRYPTO_MODE_ENCRYPT 0U +#define CRYPTO_MODE_INIT (AES_CR_MODE_0) #define CRYPTO_MODE_DECRYPT (AES_CR_MODE_1) #define CRYPTO_MODE_DECRYPT_INIT (AES_CR_MODE_0 | AES_CR_MODE_1) + #define CRYPTO_DATATYPE_32B 0U #define CRYPTO_KEYSIZE_256B (AES_CR_KEYSIZE) #define CRYPTO_AES_CBC (AES_CR_CHMOD_0) static osMutexId_t furi_hal_crypto_mutex = NULL; +static bool furi_hal_crypto_mode_init_done = false; static const uint8_t enclave_signature_iv[ENCLAVE_FACTORY_KEY_SLOTS][16] = { {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, @@ -177,20 +180,8 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { return (shci_state == SHCI_Success); } -static void crypto_enable() { - SET_BIT(AES1->CR, AES_CR_EN); -} - -static void crypto_disable() { - CLEAR_BIT(AES1->CR, AES_CR_EN); - FURI_CRITICAL_ENTER(); - LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_AES1); - LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1); - FURI_CRITICAL_EXIT(); -} - static void crypto_key_init(uint32_t* key, uint32_t* iv) { - crypto_disable(); + CLEAR_BIT(AES1->CR, AES_CR_EN); MODIFY_REG( AES1->CR, AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD, @@ -254,12 +245,13 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { return false; } + furi_hal_crypto_mode_init_done = false; crypto_key_init(NULL, (uint32_t*)iv); if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { return true; } else { - crypto_disable(); + CLEAR_BIT(AES1->CR, AES_CR_EN); furi_check(osMutexRelease(furi_hal_crypto_mutex) == osOK); return false; } @@ -270,9 +262,16 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) { return false; } - crypto_disable(); + CLEAR_BIT(AES1->CR, AES_CR_EN); SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); + furi_assert(shci_state == SHCI_Success); + + FURI_CRITICAL_ENTER(); + LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_AES1); + LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1); + FURI_CRITICAL_EXIT(); + furi_check(osMutexRelease(furi_hal_crypto_mutex) == osOK); return (shci_state == SHCI_Success); } @@ -280,7 +279,7 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) { bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) { bool state = false; - crypto_enable(); + SET_BIT(AES1->CR, AES_CR_EN); MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_ENCRYPT); @@ -295,7 +294,7 @@ bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) } } - crypto_disable(); + CLEAR_BIT(AES1->CR, AES_CR_EN); return state; } @@ -303,9 +302,28 @@ bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size) { bool state = false; - MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_DECRYPT_INIT); + if(!furi_hal_crypto_mode_init_done) { + MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_INIT); - crypto_enable(); + SET_BIT(AES1->CR, AES_CR_EN); + + uint32_t countdown = CRYPTO_TIMEOUT; + while(!READ_BIT(AES1->SR, AES_SR_CCF)) { + if(LL_SYSTICK_IsActiveCounterFlag()) { + countdown--; + } + if(countdown == 0) { + return false; + } + } + + SET_BIT(AES1->CR, AES_CR_CCFC); + + furi_hal_crypto_mode_init_done = true; + } + + MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_DECRYPT); + SET_BIT(AES1->CR, AES_CR_EN); for(size_t i = 0; i < size; i += CRYPTO_BLK_LEN) { size_t blk_len = size - i; @@ -318,7 +336,7 @@ bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size) } } - crypto_disable(); + CLEAR_BIT(AES1->CR, AES_CR_EN); return state; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index ec30656e..e5060536 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -239,6 +239,13 @@ uint32_t furi_hal_power_get_battery_full_capacity() { return ret; } +uint32_t furi_hal_power_get_battery_design_capacity() { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + uint32_t ret = bq27220_get_design_capacity(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + return ret; +} + float furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) { float ret = 0.0f; @@ -399,3 +406,58 @@ void furi_hal_power_suppress_charge_exit() { furi_hal_i2c_release(&furi_hal_i2c_handle_power); } } + +void furi_hal_power_info_get(FuriHalPowerInfoCallback out, void* context) { + furi_assert(out); + + string_t value; + string_init(value); + + // Power Info version + out("power_info_major", "1", false, context); + out("power_info_minor", "0", false, context); + + uint8_t charge = furi_hal_power_get_pct(); + + string_printf(value, "%u", charge); + out("charge_level", string_get_cstr(value), false, context); + + if(furi_hal_power_is_charging()) { + if(charge < 100) { + string_printf(value, "charging"); + } else { + string_printf(value, "charged"); + } + } else { + string_printf(value, "discharging"); + } + out("charge_state", string_get_cstr(value), false, context); + + uint16_t voltage = + (uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f); + string_printf(value, "%u", voltage); + out("battery_voltage", string_get_cstr(value), false, context); + + int16_t current = + (int16_t)(furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge) * 1000.f); + string_printf(value, "%d", current); + out("battery_current", string_get_cstr(value), false, context); + + int16_t temperature = (int16_t)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge); + string_printf(value, "%d", temperature); + out("gauge_temp", string_get_cstr(value), false, context); + + string_printf(value, "%u", furi_hal_power_get_bat_health_pct()); + out("battery_health", string_get_cstr(value), false, context); + + string_printf(value, "%u", furi_hal_power_get_battery_remaining_capacity()); + out("capacity_remain", string_get_cstr(value), false, context); + + string_printf(value, "%u", furi_hal_power_get_battery_full_capacity()); + out("capacity_full", string_get_cstr(value), false, context); + + string_printf(value, "%u", furi_hal_power_get_battery_design_capacity()); + out("capacity_design", string_get_cstr(value), true, context); + + string_clear(value); +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_speaker.c b/firmware/targets/f7/furi_hal/furi_hal_speaker.c index 80c69a08..298574d8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_speaker.c +++ b/firmware/targets/f7/furi_hal/furi_hal_speaker.c @@ -25,21 +25,32 @@ void furi_hal_speaker_start(float frequency, float volume) { if(volume > 1) volume = 1; volume = volume * volume * volume; + uint32_t autoreload = (SystemCoreClock / FURI_HAL_SPEAKER_PRESCALER / frequency) - 1; + if(autoreload < 2) { + autoreload = 2; + } else if(autoreload > UINT16_MAX) { + autoreload = UINT16_MAX; + } + LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = FURI_HAL_SPEAKER_PRESCALER - 1; - TIM_InitStruct.Autoreload = ((SystemCoreClock / FURI_HAL_SPEAKER_PRESCALER) / frequency) - 1; + TIM_InitStruct.Autoreload = autoreload; LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct); #ifdef FURI_HAL_SPEAKER_NEW_VOLUME - uint16_t compare_value = volume * FURI_HAL_SPEAKER_MAX_VOLUME; - uint16_t clip_value = volume * TIM_InitStruct.Autoreload / 2; + uint32_t compare_value = volume * FURI_HAL_SPEAKER_MAX_VOLUME; + uint32_t clip_value = volume * TIM_InitStruct.Autoreload / 2; if(compare_value > clip_value) { compare_value = clip_value; } #else - uint16_t compare_value = volume * TIM_InitStruct.Autoreload / 2; + uint32_t compare_value = volume * autoreload / 2; #endif + if(compare_value == 0) { + compare_value = 1; + } + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; @@ -51,6 +62,6 @@ void furi_hal_speaker_start(float frequency, float volume) { } void furi_hal_speaker_stop() { - LL_TIM_CC_DisableChannel(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL); + LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER); LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER); } diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 3f5a0020..c55e3804 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -113,6 +113,12 @@ uint32_t furi_hal_power_get_battery_remaining_capacity(); */ uint32_t furi_hal_power_get_battery_full_capacity(); +/** Get battery capacity in mAh from battery profile + * + * @return capacity in mAh + */ +uint32_t furi_hal_power_get_battery_design_capacity(); + /** Get battery voltage in V * * @param ic FuriHalPowerIc to get measurment @@ -171,6 +177,23 @@ void furi_hal_power_suppress_charge_enter(); */ void furi_hal_power_suppress_charge_exit(); +/** Callback type called by furi_hal_power_info_get every time another key-value pair of information is ready + * + * @param key[in] power information type identifier + * @param value[in] power information value + * @param last[in] whether the passed key-value pair is the last one + * @param context[in] to pass to callback + */ +typedef void ( + *FuriHalPowerInfoCallback)(const char* key, const char* value, bool last, void* context); + +/** Get power information + * + * @param[in] callback callback to provide with new data + * @param[in] context context to pass to callback + */ +void furi_hal_power_info_get(FuriHalPowerInfoCallback callback, void* context); + #ifdef __cplusplus } #endif From 435205de331d7d589e3549b021ee02640df83e83 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 7 Apr 2022 19:48:07 +0400 Subject: [PATCH 12/12] [FL-2427] SubGhz: fix Sub-Ghz RAW not working in Japan region (#1099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/subghz/subghz_i.c | 37 +++++++++++++++++++++++++++++++++- applications/subghz/subghz_i.h | 1 + 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 8f7f2cc6..80d7a52c 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -197,6 +197,22 @@ void subghz_tx_stop(SubGhz* subghz) { notification_message(subghz->notifications, &sequence_reset_red); } +void subghz_dialog_message_show_only_rx(SubGhz* subghz) { + DialogsApp* dialogs = subghz->dialogs; + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_text( + message, + "This frequency can\nonly be used for RX\nin your region", + 38, + 23, + AlignCenter, + AlignCenter); + dialog_message_set_icon(message, &I_DolphinFirstStart7_61x51, 67, 12); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_show(dialogs, message); + dialog_message_free(message); +} + bool subghz_key_load(SubGhz* subghz, const char* file_path) { furi_assert(subghz); furi_assert(file_path); @@ -205,6 +221,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); + uint8_t err = 1; bool loaded = false; string_t temp_str; string_init(temp_str); @@ -239,6 +256,12 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { FURI_LOG_E(TAG, "Frequency not supported"); break; } + + if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { + FURI_LOG_E(TAG, "This frequency can only be used for RX in your region"); + err = 2; + break; + } subghz->txrx->frequency = temp_data32; if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { @@ -281,7 +304,19 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { } while(0); if(!loaded) { - dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); + switch(err) { + case 1: + dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); + break; + + case 2: + subghz_dialog_message_show_only_rx(subghz); + break; + + default: + furi_crash(NULL); + break; + } } string_clear(temp_str); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 65e8b3e3..bfa80df3 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -155,6 +155,7 @@ void subghz_rx_end(SubGhz* subghz); void subghz_sleep(SubGhz* subghz); bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); void subghz_tx_stop(SubGhz* subghz); +void subghz_dialog_message_show_only_rx(SubGhz* subghz); bool subghz_key_load(SubGhz* subghz, const char* file_path); bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file(