[FL-2432], [FL-2487] Rework bt keys load and save (#1139)

* bt keys: rework load and save with saved_struct
* bt: rename bt keys storage functions
* furi_hal_nfc: allow context switch during emilation
* bt settings: rework with saved struct
* infrared: replace file worker with dialogs and storage
* Core, Loader: fix thread allocation tracking, much better, so wow.

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
gornekich 2022-04-21 18:36:53 +03:00 committed by GitHub
parent df66f4f6ba
commit 7c692a9f36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 112 additions and 134 deletions

View File

@ -320,7 +320,7 @@ int32_t bt_srv() {
Bt* bt = bt_alloc(); Bt* bt = bt_alloc();
// Read keys // Read keys
if(!bt_load_key_storage(bt)) { if(!bt_keys_storage_load(bt)) {
FURI_LOG_W(TAG, "Failed to load bonding keys"); FURI_LOG_W(TAG, "Failed to load bonding keys");
} }
@ -365,11 +365,11 @@ int32_t bt_srv() {
// Display PIN code // Display PIN code
bt_pin_code_show(bt, message.data.pin_code); bt_pin_code_show(bt, message.data.pin_code);
} else if(message.type == BtMessageTypeKeysStorageUpdated) { } else if(message.type == BtMessageTypeKeysStorageUpdated) {
bt_save_key_storage(bt); bt_keys_storage_save(bt);
} else if(message.type == BtMessageTypeSetProfile) { } else if(message.type == BtMessageTypeSetProfile) {
bt_change_profile(bt, &message); bt_change_profile(bt, &message);
} else if(message.type == BtMessageTypeForgetBondedDevices) { } else if(message.type == BtMessageTypeForgetBondedDevices) {
bt_delete_key_storage(bt); bt_keys_storage_delete(bt);
} }
} }
return 0; return 0;

View File

@ -1,46 +1,47 @@
#include "bt_keys_storage.h" #include "bt_keys_storage.h"
#include <furi.h> #include <furi.h>
#include <file_worker.h> #include <lib/toolbox/saved_struct.h>
#define BT_KEYS_STORAGE_TAG "bt keys storage"
#define BT_KEYS_STORAGE_PATH "/int/bt.keys" #define BT_KEYS_STORAGE_PATH "/int/bt.keys"
#define BT_KEYS_STORAGE_VERSION (0)
#define BT_KEYS_STORAGE_MAGIC (0x18)
bool bt_load_key_storage(Bt* bt) { bool bt_keys_storage_load(Bt* bt) {
furi_assert(bt); furi_assert(bt);
bool file_loaded = false; bool file_loaded = false;
furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size);
FileWorker* file_worker = file_worker_alloc(true); furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size);
if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { furi_hal_bt_nvm_sram_sem_acquire();
furi_hal_bt_nvm_sram_sem_acquire(); file_loaded = saved_struct_load(
if(file_worker_read(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { BT_KEYS_STORAGE_PATH,
file_loaded = true; bt->bt_keys_addr_start,
} bt->bt_keys_size,
furi_hal_bt_nvm_sram_sem_release(); BT_KEYS_STORAGE_MAGIC,
} BT_KEYS_STORAGE_VERSION);
file_worker_free(file_worker); furi_hal_bt_nvm_sram_sem_release();
return file_loaded; return file_loaded;
} }
bool bt_save_key_storage(Bt* bt) { bool bt_keys_storage_save(Bt* bt) {
furi_assert(bt); furi_assert(bt);
furi_assert(bt->bt_keys_addr_start); furi_assert(bt->bt_keys_addr_start);
bool file_saved = false; bool file_saved = false;
FileWorker* file_worker = file_worker_alloc(true);
if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { furi_hal_bt_nvm_sram_sem_acquire();
furi_hal_bt_nvm_sram_sem_acquire(); file_saved = saved_struct_save(
if(file_worker_write(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { BT_KEYS_STORAGE_PATH,
file_saved = true; bt->bt_keys_addr_start,
} bt->bt_keys_size,
furi_hal_bt_nvm_sram_sem_release(); BT_KEYS_STORAGE_MAGIC,
} BT_KEYS_STORAGE_VERSION);
file_worker_free(file_worker); furi_hal_bt_nvm_sram_sem_release();
return file_saved; return file_saved;
} }
bool bt_delete_key_storage(Bt* bt) { bool bt_keys_storage_delete(Bt* bt) {
furi_assert(bt); furi_assert(bt);
bool delete_succeed = false; bool delete_succeed = false;
bool bt_is_active = furi_hal_bt_is_active(); bool bt_is_active = furi_hal_bt_is_active();

View File

@ -2,8 +2,8 @@
#include "bt_i.h" #include "bt_i.h"
bool bt_load_key_storage(Bt* bt); bool bt_keys_storage_load(Bt* bt);
bool bt_save_key_storage(Bt* bt); bool bt_keys_storage_save(Bt* bt);
bool bt_delete_key_storage(Bt* bt); bool bt_keys_storage_delete(Bt* bt);

View File

@ -1,50 +1,22 @@
#include "bt_settings.h" #include "bt_settings.h"
#include <furi.h>
#include <file_worker.h>
#define TAG "BtSettings" #include <furi.h>
#include <lib/toolbox/saved_struct.h>
#define BT_SETTINGS_PATH "/int/bt.settings" #define BT_SETTINGS_PATH "/int/bt.settings"
#define BT_SETTINGS_VERSION (0)
#define BT_SETTINGS_MAGIC (0x19)
bool bt_settings_load(BtSettings* bt_settings) { bool bt_settings_load(BtSettings* bt_settings) {
furi_assert(bt_settings); furi_assert(bt_settings);
bool file_loaded = false;
BtSettings settings = {};
FURI_LOG_I(TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); return saved_struct_load(
FileWorker* file_worker = file_worker_alloc(true); BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION);
if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
if(file_worker_read(file_worker, &settings, sizeof(settings))) {
file_loaded = true;
}
}
file_worker_free(file_worker);
if(file_loaded) {
FURI_LOG_I(TAG, "Settings load success");
if(settings.version != BT_SETTINGS_VERSION) {
FURI_LOG_E(TAG, "Settings version mismatch");
} else {
osKernelLock();
*bt_settings = settings;
osKernelUnlock();
}
} else {
FURI_LOG_E(TAG, "Settings load failed");
}
return file_loaded;
} }
bool bt_settings_save(BtSettings* bt_settings) { bool bt_settings_save(BtSettings* bt_settings) {
furi_assert(bt_settings); furi_assert(bt_settings);
bool result = false;
FileWorker* file_worker = file_worker_alloc(true); return saved_struct_save(
if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION);
if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) {
FURI_LOG_I(TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH);
result = true;
}
}
file_worker_free(file_worker);
return result;
} }

View File

@ -3,10 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define BT_SETTINGS_VERSION (0)
typedef struct { typedef struct {
uint8_t version;
bool enabled; bool enabled;
} BtSettings; } BtSettings;

View File

@ -49,12 +49,14 @@ int32_t InfraredApp::run(void* args) {
InfraredApp::InfraredApp() { InfraredApp::InfraredApp() {
furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size());
notification = static_cast<NotificationApp*>(furi_record_open("notification")); notification = static_cast<NotificationApp*>(furi_record_open("notification"));
dialogs = static_cast<DialogsApp*>(furi_record_open("dialogs"));
infrared_worker = infrared_worker_alloc(); infrared_worker = infrared_worker_alloc();
} }
InfraredApp::~InfraredApp() { InfraredApp::~InfraredApp() {
infrared_worker_free(infrared_worker); infrared_worker_free(infrared_worker);
furi_record_close("notification"); furi_record_close("notification");
furi_record_close("dialogs");
for(auto& [key, scene] : scenes) delete scene; for(auto& [key, scene] : scenes) delete scene;
} }
@ -248,6 +250,10 @@ void InfraredApp::notify_blink_green() {
notification_message(notification, &sequence); notification_message(notification, &sequence);
} }
DialogsApp* InfraredApp::get_dialogs() {
return dialogs;
}
void InfraredApp::notify_green_on() { void InfraredApp::notify_green_on() {
notification_message(notification, &sequence_set_only_green_255); notification_message(notification, &sequence_set_only_green_255);
} }

View File

@ -9,6 +9,7 @@
#include <forward_list> #include <forward_list>
#include <stdint.h> #include <stdint.h>
#include <notification/notification_messages.h> #include <notification/notification_messages.h>
#include <dialogs/dialogs.h>
#include <infrared_worker.h> #include <infrared_worker.h>
#include "scene/infrared_app_scene.h" #include "scene/infrared_app_scene.h"
@ -228,6 +229,9 @@ public:
/** Blink green light */ /** Blink green light */
void notify_blink_green(); void notify_blink_green();
/** Get Dialogs instance */
DialogsApp* get_dialogs();
/** Text input callback /** Text input callback
* *
* @param context - context to pass to callback * @param context - context to pass to callback
@ -286,6 +290,8 @@ private:
/** Notification instance */ /** Notification instance */
NotificationApp* notification; NotificationApp* notification;
/** Dialogs instance */
DialogsApp* dialogs;
/** View manager instance */ /** View manager instance */
InfraredAppViewManager view_manager; InfraredAppViewManager view_manager;
/** Remote manager instance */ /** Remote manager instance */

View File

@ -5,7 +5,6 @@
#include <memory> #include <memory>
#include <m-string.h> #include <m-string.h>
#include <furi.h> #include <furi.h>
#include <file_worker_cpp.h>
void InfraredAppBruteForce::add_record(int index, const char* name) { void InfraredAppBruteForce::add_record(int index, const char* name) {
records[name].index = index; records[name].index = index;

View File

@ -1,4 +1,3 @@
#include <file_worker_cpp.h>
#include <flipper_format/flipper_format.h> #include <flipper_format/flipper_format.h>
#include "infrared_app_remote_manager.h" #include "infrared_app_remote_manager.h"
#include "infrared/helpers/infrared_parser.h" #include "infrared/helpers/infrared_parser.h"
@ -22,26 +21,34 @@ std::string InfraredAppRemoteManager::make_full_name(
} }
std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) { std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) {
bool exist = true; std::string result_name;
FileWorkerCpp file_worker; Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
if(!file_worker.is_file_exist( FS_Error error = storage_common_stat(
make_full_name(InfraredApp::infrared_directory, name).c_str(), &exist)) { storage, make_full_name(InfraredApp::infrared_directory, name).c_str(), NULL);
return std::string();
} else if(!exist) { if(error == FSE_NOT_EXIST) {
return name; result_name = name;
} else if(error != FSE_OK) {
result_name = std::string();
} else {
/* if suggested name is occupied, try another one (name2, name3, etc) */
uint32_t i = 1;
std::string new_name;
do {
new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i));
error = storage_common_stat(storage, new_name.c_str(), NULL);
} while(error == FSE_OK);
if(error == FSE_NOT_EXIST) {
result_name = name + std::to_string(i);
} else {
result_name = std::string();
}
} }
/* if suggested name is occupied, try another one (name2, name3, etc) */ furi_record_close("storage");
uint32_t i = 1; return result_name;
bool file_worker_result = false;
std::string new_name;
do {
new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i));
file_worker_result = file_worker.is_file_exist(new_name.c_str(), &exist);
} while(file_worker_result && exist);
return !exist ? name + std::to_string(i) : std::string();
} }
bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) { bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) {
@ -84,12 +91,14 @@ const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index)
} }
bool InfraredAppRemoteManager::delete_remote() { bool InfraredAppRemoteManager::delete_remote() {
bool result; Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
FileWorkerCpp file_worker;
result = file_worker.remove(make_full_name(remote->path, remote->name).c_str());
FS_Error error =
storage_common_remove(storage, make_full_name(remote->path, remote->name).c_str());
reset_remote(); reset_remote();
return result;
furi_record_close("storage");
return (error == FSE_OK || error == FSE_NOT_EXIST);
} }
void InfraredAppRemoteManager::reset_remote() { void InfraredAppRemoteManager::reset_remote() {
@ -129,14 +138,15 @@ bool InfraredAppRemoteManager::rename_remote(const char* str) {
return false; return false;
} }
FileWorkerCpp file_worker; Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
std::string old_filename = make_full_name(remote->path, remote->name); std::string old_filename = make_full_name(remote->path, remote->name);
std::string new_filename = make_full_name(remote->path, new_name); std::string new_filename = make_full_name(remote->path, new_name);
bool result = file_worker.rename(old_filename.c_str(), new_filename.c_str()); FS_Error error = storage_common_rename(storage, old_filename.c_str(), new_filename.c_str());
remote->name = new_name; remote->name = new_name;
return result; furi_record_close("storage");
return (error == FSE_OK || error == FSE_EXIST);
} }
bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) { bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) {
@ -155,11 +165,10 @@ size_t InfraredAppRemoteManager::get_number_of_buttons() {
bool InfraredAppRemoteManager::store(void) { bool InfraredAppRemoteManager::store(void) {
bool result = false; bool result = false;
FileWorkerCpp file_worker;
if(!file_worker.mkdir(InfraredApp::infrared_directory)) return false;
Storage* storage = static_cast<Storage*>(furi_record_open("storage")); Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
if(!storage_simply_mkdir(storage, InfraredApp::infrared_directory)) return false;
FlipperFormat* ff = flipper_format_file_alloc(storage); FlipperFormat* ff = flipper_format_file_alloc(storage);
FURI_LOG_I( FURI_LOG_I(

View File

@ -1,5 +1,4 @@
#include <gui/modules/dialog_ex.h> #include <gui/modules/dialog_ex.h>
#include <file_worker_cpp.h>
#include <memory> #include <memory>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
@ -88,13 +87,8 @@ bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent*
break; break;
case DialogExResultRight: { case DialogExResultRight: {
consumed = true; consumed = true;
FileWorkerCpp file_worker;
if(!button_pressed) { if(!button_pressed) {
if(file_worker.check_errors()) { app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName);
app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName);
} else {
app->switch_to_previous_scene();
}
} }
break; break;
} }

View File

@ -1,12 +1,10 @@
#include "../infrared_app.h" #include "../infrared_app.h"
#include "infrared/infrared_app_event.h" #include "infrared/infrared_app_event.h"
#include <text_store.h> #include <text_store.h>
#include <file_worker_cpp.h>
void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) {
furi_assert(app); furi_assert(app);
FileWorkerCpp file_worker;
bool result = false; bool result = false;
bool file_select_result; bool file_select_result;
auto remote_manager = app->get_remote_manager(); auto remote_manager = app->get_remote_manager();
@ -15,13 +13,15 @@ void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) {
last_selected_remote.size() ? last_selected_remote.c_str() : nullptr; last_selected_remote.size() ? last_selected_remote.c_str() : nullptr;
auto filename_ts = auto filename_ts =
std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length); std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length);
DialogsApp* dialogs = app->get_dialogs();
InfraredAppViewManager* view_manager = app->get_view_manager(); InfraredAppViewManager* view_manager = app->get_view_manager();
ButtonMenu* button_menu = view_manager->get_button_menu(); ButtonMenu* button_menu = view_manager->get_button_menu();
button_menu_reset(button_menu); button_menu_reset(button_menu);
view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu);
file_select_result = file_worker.file_select( file_select_result = dialog_file_select_show(
dialogs,
InfraredApp::infrared_directory, InfraredApp::infrared_directory,
InfraredApp::infrared_extension, InfraredApp::infrared_extension,
filename_ts->text, filename_ts->text,

View File

@ -239,26 +239,11 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
event.type = LoaderEventTypeApplicationStarted; event.type = LoaderEventTypeApplicationStarted;
furi_pubsub_publish(loader_instance->pubsub, &event); furi_pubsub_publish(loader_instance->pubsub, &event);
furi_hal_power_insomnia_enter(); furi_hal_power_insomnia_enter();
// Snapshot current memory usage
instance->free_heap_size = memmgr_get_free_heap();
} else if(thread_state == FuriThreadStateStopped) { } else if(thread_state == FuriThreadStateStopped) {
/*
* Current Leak Sanitizer assumes that memory is allocated and freed
* inside one thread. Timers are allocated in one task, but freed in
* Timer-Task thread, and xTimerDelete() just put command to queue.
* To avoid some bad cases there are few fixes:
* 1) delay for Timer to process commands
* 2) there are 'heap diff' which shows difference in heap before task
* started and after task completed. In process of leakage monitoring
* both values should be taken into account.
*/
furi_hal_delay_ms(20);
int heap_diff = instance->free_heap_size - memmgr_get_free_heap();
FURI_LOG_I( FURI_LOG_I(
TAG, TAG,
"Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", "Application thread stopped. Free heap: %d. Thread allocation balance: %d.",
heap_diff, memmgr_get_free_heap(),
furi_thread_get_heap_size(instance->application_thread)); furi_thread_get_heap_size(instance->application_thread));
if(loader_instance->application_arguments) { if(loader_instance->application_arguments) {

View File

@ -30,7 +30,6 @@ struct Loader {
Submenu* debug_menu; Submenu* debug_menu;
Submenu* settings_menu; Submenu* settings_menu;
size_t free_heap_size;
volatile uint8_t lock_count; volatile uint8_t lock_count;
FuriPubSub* pubsub; FuriPubSub* pubsub;

View File

@ -171,7 +171,16 @@ size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) {
!MemmgrHeapAllocDict_end_p(alloc_dict_it); !MemmgrHeapAllocDict_end_p(alloc_dict_it);
MemmgrHeapAllocDict_next(alloc_dict_it)) { MemmgrHeapAllocDict_next(alloc_dict_it)) {
MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it);
leftovers += data->value; if(data->key != 0) {
uint8_t* puc = (uint8_t*)data->key;
puc -= xHeapStructSize;
BlockLink_t* pxLink = (void*)puc;
if((pxLink->xBlockSize & xBlockAllocatedBit) != 0 &&
pxLink->pxNextFreeBlock == NULL) {
leftovers += data->value;
}
}
} }
} }
memmgr_heap_thread_trace_depth--; memmgr_heap_thread_trace_depth--;

View File

@ -45,6 +45,7 @@ static void furi_thread_body(void* context) {
thread->ret = thread->callback(thread->context); thread->ret = thread->callback(thread->context);
if(thread->heap_trace_enabled == true) { if(thread->heap_trace_enabled == true) {
osDelay(33);
thread->heap_size = memmgr_heap_get_thread_memory(thread_id); thread->heap_size = memmgr_heap_get_thread_memory(thread_id);
memmgr_heap_disable_thread_trace(thread_id); memmgr_heap_disable_thread_trace(thread_id);
} }

View File

@ -230,7 +230,7 @@ bool furi_hal_nfc_listen(
rfalNfcDeactivate(true); rfalNfcDeactivate(true);
return false; return false;
} }
osThreadYield(); osDelay(1);
} }
return true; return true;
} }
@ -498,7 +498,7 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
} else { } else {
start = DWT->CYCCNT; start = DWT->CYCCNT;
} }
osThreadYield(); osDelay(1);
} }
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {