Просмотр исходного кода

[FL-1061] iButton save and load from sd card (#394)

* SD App: fix queue adresses
* sd-filesystem: fix making path on file select event
* ibutton: add key reading from sd card
* ibutton: save ibutton key to sd card
* ibutton: add deleting keys from sd card
* ibutton: remove KeyStore from application
* ibutton: make directory if necessary on key save

Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
gornekich 4 лет назад
Родитель
Сommit
5309bfae41

+ 1 - 1
applications/applications.c

@@ -177,7 +177,7 @@ const FlipperApplication FLIPPER_APPS[] = {
 #endif
 #endif
 
 
 #ifdef BUILD_IBUTTON
 #ifdef BUILD_IBUTTON
-    {.app = app_ibutton, .name = "iButton", .stack_size = 1024, .icon = A_iButton_14},
+    {.app = app_ibutton, .name = "iButton", .stack_size = 4096, .icon = A_iButton_14},
 #endif
 #endif
 
 
 #ifdef BUILD_GPIO_DEMO
 #ifdef BUILD_GPIO_DEMO

+ 8 - 4
applications/gui/modules/file_select.c

@@ -96,6 +96,9 @@ static bool file_select_input_callback(InputEvent* event, void* context) {
                     return true;
                     return true;
                 });
                 });
             consumed = true;
             consumed = true;
+            if(!file_select_fill_strings(file_select)) {
+                file_select->callback(false, file_select->context);
+            }
         } else if(event->key == InputKeyDown) {
         } else if(event->key == InputKeyDown) {
             with_view_model(
             with_view_model(
                 file_select->view, (FileSelectModel * model) {
                 file_select->view, (FileSelectModel * model) {
@@ -121,6 +124,9 @@ static bool file_select_input_callback(InputEvent* event, void* context) {
                     return true;
                     return true;
                 });
                 });
             consumed = true;
             consumed = true;
+            if(!file_select_fill_strings(file_select)) {
+                file_select->callback(false, file_select->context);
+            }
         } else if(event->key == InputKeyOk) {
         } else if(event->key == InputKeyOk) {
             if(file_select->callback != NULL) {
             if(file_select->callback != NULL) {
                 const char* result;
                 const char* result;
@@ -138,10 +144,6 @@ static bool file_select_input_callback(InputEvent* event, void* context) {
             }
             }
             consumed = true;
             consumed = true;
         }
         }
-
-        if(!file_select_fill_strings(file_select)) {
-            file_select->callback(false, file_select->context);
-        }
     }
     }
 
 
     return consumed;
     return consumed;
@@ -207,6 +209,8 @@ void file_select_set_api(FileSelect* file_select, FS_Api* fs_api) {
 }
 }
 
 
 void file_select_set_callback(FileSelect* file_select, FileSelectCallback callback, void* context) {
 void file_select_set_callback(FileSelect* file_select, FileSelectCallback callback, void* context) {
+    file_select->context = context;
+    file_select->callback = callback;
 }
 }
 
 
 void file_select_set_filter(FileSelect* file_select, const char* path, const char* extension) {
 void file_select_set_filter(FileSelect* file_select, const char* path, const char* extension) {

+ 0 - 69
applications/ibutton/helpers/key-store.cpp

@@ -1,69 +0,0 @@
-#include "key-store.h"
-#include <furi.h>
-
-uint16_t KeyStore::get_key_count() {
-    return store.size();
-}
-
-uint8_t KeyStore::add_key() {
-    store.push_back(iButtonKey());
-    return get_key_count() - 1;
-}
-
-void KeyStore::set_key_type(uint8_t index, iButtonKeyType type) {
-    iButtonKey* key = get_key(index);
-    key->set_type(type);
-}
-
-void KeyStore::set_key_name(uint8_t index, char* name) {
-    iButtonKey* key = get_key(index);
-    char* orphan = strdup(name);
-    key->set_name(orphan);
-}
-
-void KeyStore::set_key_data(uint8_t index, uint8_t* data, uint8_t data_size) {
-    iButtonKey* key = get_key(index);
-    key->set_data(data, data_size);
-}
-
-iButtonKeyType KeyStore::get_key_type(uint8_t index) {
-    iButtonKey* key = get_key(index);
-    return key->get_key_type();
-}
-
-const char* KeyStore::get_key_name(uint8_t index) {
-    iButtonKey* key = get_key(index);
-    return key->get_name();
-}
-
-uint8_t* KeyStore::get_key_data(uint8_t index) {
-    iButtonKey* key = get_key(index);
-    return key->get_data();
-}
-
-void KeyStore::remove_key(uint8_t index) {
-    furi_check(index >= 0);
-    furi_check(index < get_key_count());
-    auto item = std::next(store.begin(), index);
-    store.erase(item);
-}
-
-KeyStore::KeyStore() {
-    store.push_back(iButtonKey(
-        iButtonKeyType::KeyDallas, "Dallas_1", 0x01, 0x41, 0xCE, 0x67, 0x0F, 0x00, 0x00, 0xB6));
-    store.push_back(iButtonKey(
-        iButtonKeyType::KeyDallas, "Dallas_2", 0x01, 0xFD, 0x0E, 0x84, 0x01, 0x00, 0x00, 0xDB));
-    store.push_back(iButtonKey(
-        iButtonKeyType::KeyCyfral, "Cyfral_1", 0xA6, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
-    store.push_back(iButtonKey(
-        iButtonKeyType::KeyMetakom, "Metakom_1", 0xB1, 0x2E, 0x47, 0xB2, 0x00, 0x00, 0x00, 0x00));
-}
-
-KeyStore::~KeyStore() {
-}
-
-iButtonKey* KeyStore::get_key(uint8_t index) {
-    furi_check(index >= 0);
-    furi_check(index < get_key_count());
-    return &(*std::next(store.begin(), index));
-}

+ 0 - 29
applications/ibutton/helpers/key-store.h

@@ -1,29 +0,0 @@
-#pragma once
-#include <stdint.h>
-#include <list>
-#include "key-info.h"
-#include "../ibutton-key.h"
-
-class KeyStore {
-public:
-    uint16_t get_key_count();
-
-    uint8_t add_key();
-
-    void set_key_type(uint8_t index, iButtonKeyType type);
-    void set_key_name(uint8_t index, char* name);
-    void set_key_data(uint8_t index, uint8_t* data, uint8_t data_size);
-
-    iButtonKeyType get_key_type(uint8_t index);
-    const char* get_key_name(uint8_t index);
-    uint8_t* get_key_data(uint8_t index);
-
-    void remove_key(uint8_t index);
-
-    KeyStore();
-    ~KeyStore();
-
-private:
-    std::list<iButtonKey> store;
-    iButtonKey* get_key(uint8_t index);
-};

+ 20 - 12
applications/ibutton/ibutton-app.cpp

@@ -28,12 +28,16 @@ iButtonApp::iButtonApp() {
     api_hal_power_insomnia_enter();
     api_hal_power_insomnia_enter();
 
 
     key_worker = new KeyWorker(&ibutton_gpio);
     key_worker = new KeyWorker(&ibutton_gpio);
+    sd_ex_api = static_cast<SdCard_Api*>(furi_record_open("sdcard-ex"));
+    fs_api = static_cast<FS_Api*>(furi_record_open("sdcard"));
 
 
     // we need random
     // we need random
     srand(DWT->CYCCNT);
     srand(DWT->CYCCNT);
 }
 }
 
 
 iButtonApp::~iButtonApp() {
 iButtonApp::~iButtonApp() {
+    furi_record_close("sdcard-ex");
+    furi_record_close("sdcard");
     api_hal_power_insomnia_exit();
     api_hal_power_insomnia_exit();
 }
 }
 
 
@@ -107,6 +111,22 @@ iButtonKey* iButtonApp::get_key() {
     return &key;
     return &key;
 }
 }
 
 
+SdCard_Api* iButtonApp::get_sd_ex_api() {
+    return sd_ex_api;
+}
+
+FS_Api* iButtonApp::get_fs_api() {
+    return fs_api;
+}
+
+char* iButtonApp::get_file_name() {
+    return file_name;
+}
+
+uint8_t iButtonApp::get_file_name_size() {
+    return file_name_size;
+}
+
 void iButtonApp::notify_init() {
 void iButtonApp::notify_init() {
     // TODO open record
     // TODO open record
     const GpioPin* vibro_record = &vibro_gpio;
     const GpioPin* vibro_record = &vibro_gpio;
@@ -193,18 +213,6 @@ uint8_t iButtonApp::get_text_store_size() {
     return text_store_size;
     return text_store_size;
 }
 }
 
 
-KeyStore* iButtonApp::get_key_store() {
-    return &store;
-}
-
-uint8_t iButtonApp::get_stored_key_index() {
-    return key_index;
-}
-
-void iButtonApp::set_stored_key_index(uint8_t _index) {
-    key_index = _index;
-}
-
 void iButtonApp::generate_random_name(char* name, uint8_t max_name_size) {
 void iButtonApp::generate_random_name(char* name, uint8_t max_name_size) {
     const uint8_t prefix_size = 9;
     const uint8_t prefix_size = 9;
     const char* prefix[prefix_size] = {
     const char* prefix[prefix_size] = {

+ 12 - 10
applications/ibutton/ibutton-app.h

@@ -12,7 +12,6 @@
 #include "scene/ibutton-scene-readed-key-menu.h"
 #include "scene/ibutton-scene-readed-key-menu.h"
 #include "scene/ibutton-scene-write.h"
 #include "scene/ibutton-scene-write.h"
 #include "scene/ibutton-scene-write-success.h"
 #include "scene/ibutton-scene-write-success.h"
-#include "scene/ibutton-scene-saved.h"
 #include "scene/ibutton-scene-saved-key-menu.h"
 #include "scene/ibutton-scene-saved-key-menu.h"
 #include "scene/ibutton-scene-delete-confirm.h"
 #include "scene/ibutton-scene-delete-confirm.h"
 #include "scene/ibutton-scene-delete-success.h"
 #include "scene/ibutton-scene-delete-success.h"
@@ -23,9 +22,11 @@
 #include "scene/ibutton-scene-add-type.h"
 #include "scene/ibutton-scene-add-type.h"
 #include "scene/ibutton-scene-add-value.h"
 #include "scene/ibutton-scene-add-value.h"
 
 
-#include "helpers/key-store.h"
 #include "helpers/key-worker.h"
 #include "helpers/key-worker.h"
 
 
+#include <sd-card-api.h>
+#include <filesystem-api.h>
+
 #include "one_wire_master.h"
 #include "one_wire_master.h"
 #include "maxim_crc.h"
 #include "maxim_crc.h"
 #include "ibutton-key.h"
 #include "ibutton-key.h"
@@ -48,7 +49,6 @@ public:
         SceneWrite,
         SceneWrite,
         SceneWriteSuccess,
         SceneWriteSuccess,
         SceneEmulate,
         SceneEmulate,
-        SceneSavedList,
         SceneSavedKeyMenu,
         SceneSavedKeyMenu,
         SceneDeleteConfirm,
         SceneDeleteConfirm,
         SceneDeleteSuccess,
         SceneDeleteSuccess,
@@ -88,9 +88,10 @@ public:
     char* get_text_store();
     char* get_text_store();
     uint8_t get_text_store_size();
     uint8_t get_text_store_size();
 
 
-    KeyStore* get_key_store();
-    uint8_t get_stored_key_index();
-    void set_stored_key_index(uint8_t index);
+    SdCard_Api* get_sd_ex_api();
+    FS_Api* get_fs_api();
+    char* get_file_name();
+    uint8_t get_file_name_size();
 
 
     void generate_random_name(char* name, uint8_t max_name_size);
     void generate_random_name(char* name, uint8_t max_name_size);
 
 
@@ -109,7 +110,6 @@ private:
         {Scene::SceneWrite, new iButtonSceneWrite()},
         {Scene::SceneWrite, new iButtonSceneWrite()},
         {Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()},
         {Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()},
         {Scene::SceneEmulate, new iButtonSceneEmulate()},
         {Scene::SceneEmulate, new iButtonSceneEmulate()},
-        {Scene::SceneSavedList, new iButtonSceneSavedList()},
         {Scene::SceneSavedKeyMenu, new iButtonSceneSavedKeyMenu()},
         {Scene::SceneSavedKeyMenu, new iButtonSceneSavedKeyMenu()},
         {Scene::SceneDeleteConfirm, new iButtonSceneDeleteConfirm()},
         {Scene::SceneDeleteConfirm, new iButtonSceneDeleteConfirm()},
         {Scene::SceneDeleteSuccess, new iButtonSceneDeleteSuccess()},
         {Scene::SceneDeleteSuccess, new iButtonSceneDeleteSuccess()},
@@ -123,12 +123,14 @@ private:
     KeyWorker* key_worker;
     KeyWorker* key_worker;
 
 
     iButtonKey key;
     iButtonKey key;
-    uint8_t key_index = 0;
+
+    SdCard_Api* sd_ex_api;
+    FS_Api* fs_api;
+    static const uint8_t file_name_size = 100;
+    char file_name[file_name_size];
 
 
     static const uint8_t text_store_size = 128;
     static const uint8_t text_store_size = 128;
     char text_store[text_store_size + 1];
     char text_store[text_store_size + 1];
 
 
-    KeyStore store;
-
     void notify_init();
     void notify_init();
 };
 };

+ 0 - 23
applications/ibutton/ibutton-key.cpp

@@ -51,28 +51,5 @@ iButtonKeyType iButtonKey::get_key_type() {
     return type;
     return type;
 }
 }
 
 
-iButtonKey::iButtonKey(
-    iButtonKeyType _type,
-    const char* _name,
-    uint8_t d0,
-    uint8_t d1,
-    uint8_t d2,
-    uint8_t d3,
-    uint8_t d4,
-    uint8_t d5,
-    uint8_t d6,
-    uint8_t d7) {
-    type = _type;
-    name = _name;
-    data[0] = d0;
-    data[1] = d1;
-    data[2] = d2;
-    data[3] = d3;
-    data[4] = d4;
-    data[5] = d5;
-    data[6] = d6;
-    data[7] = d7;
-}
-
 iButtonKey::iButtonKey() {
 iButtonKey::iButtonKey() {
 }
 }

+ 0 - 13
applications/ibutton/ibutton-key.h

@@ -16,19 +16,6 @@ public:
     void set_type(iButtonKeyType key_type);
     void set_type(iButtonKeyType key_type);
     iButtonKeyType get_key_type();
     iButtonKeyType get_key_type();
 
 
-    // temporary constructor for KeyStore mockup
-    iButtonKey(
-        iButtonKeyType type,
-        const char* name,
-        uint8_t d0,
-        uint8_t d1,
-        uint8_t d2,
-        uint8_t d3,
-        uint8_t d4,
-        uint8_t d5,
-        uint8_t d6,
-        uint8_t d7);
-
     iButtonKey();
     iButtonKey();
 
 
 private:
 private:

+ 13 - 4
applications/ibutton/scene/ibutton-scene-delete-confirm.cpp

@@ -55,10 +55,19 @@ bool iButtonSceneDeleteConfirm::on_event(iButtonApp* app, iButtonEvent* event) {
 
 
     if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
     if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
         if(event->payload.dialog_result == DialogExResultRight) {
         if(event->payload.dialog_result == DialogExResultRight) {
-            KeyStore* store = app->get_key_store();
-            store->remove_key(app->get_stored_key_index());
-
-            app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteSuccess);
+            iButtonKey* key = app->get_key();
+            string_t key_file_name;
+            string_init_set_str(key_file_name, "ibutton/");
+            string_cat_str(key_file_name, key->get_name());
+            bool res =
+                (app->get_fs_api()->common.remove(string_get_cstr(key_file_name)) == FSE_OK);
+            string_clear(key_file_name);
+            if(res) {
+                app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteSuccess);
+            } else {
+                // TODO error file path
+                // app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteFail);
+            }
         } else {
         } else {
             app->switch_to_previous_scene();
             app->switch_to_previous_scene();
         }
         }

+ 1 - 1
applications/ibutton/scene/ibutton-scene-delete-success.cpp

@@ -25,7 +25,7 @@ bool iButtonSceneDeleteSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
     bool consumed = false;
     bool consumed = false;
 
 
     if(event->type == iButtonEvent::Type::EventTypeBack) {
     if(event->type == iButtonEvent::Type::EventTypeBack) {
-        app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneSavedList});
+        app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart});
         consumed = true;
         consumed = true;
     }
     }
 
 

+ 17 - 7
applications/ibutton/scene/ibutton-scene-save-name.cpp

@@ -4,6 +4,7 @@
 #include "../ibutton-event.h"
 #include "../ibutton-event.h"
 #include "../ibutton-key.h"
 #include "../ibutton-key.h"
 #include <callback-connector.h>
 #include <callback-connector.h>
+#include <filesystem-api.h>
 
 
 void iButtonSceneSaveName::on_enter(iButtonApp* app) {
 void iButtonSceneSaveName::on_enter(iButtonApp* app) {
     iButtonAppViewManager* view_manager = app->get_view_manager();
     iButtonAppViewManager* view_manager = app->get_view_manager();
@@ -28,14 +29,23 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
     bool consumed = false;
     bool consumed = false;
 
 
     if(event->type == iButtonEvent::Type::EventTypeTextEditResult) {
     if(event->type == iButtonEvent::Type::EventTypeTextEditResult) {
-        KeyStore* store = app->get_key_store();
-        uint8_t key_index = store->add_key();
         iButtonKey* key = app->get_key();
         iButtonKey* key = app->get_key();
-
-        store->set_key_type(key_index, key->get_key_type());
-        store->set_key_name(key_index, app->get_text_store());
-        store->set_key_data(key_index, key->get_data(), key->get_size());
-
+        File key_file;
+        string_t key_file_name;
+        string_init_set_str(key_file_name, "ibutton/");
+        string_cat_str(key_file_name, app->get_text_store());
+        uint8_t key_data[IBUTTON_KEY_SIZE + 1];
+        key_data[0] = static_cast<uint8_t>(key->get_key_type());
+        memcpy(key_data + 1, key->get_data(), IBUTTON_KEY_SIZE);
+        // Create ibutton directory if necessary
+        app->get_fs_api()->common.mkdir("ibutton");
+        bool res = app->get_fs_api()->file.open(
+            &key_file, string_get_cstr(key_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS);
+        if(res) {
+            res = app->get_fs_api()->file.write(&key_file, key_data, IBUTTON_KEY_SIZE + 1);
+            res = app->get_fs_api()->file.close(&key_file);
+        }
+        string_clear(key_file_name);
         app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess);
         app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess);
         consumed = true;
         consumed = true;
     }
     }

+ 0 - 62
applications/ibutton/scene/ibutton-scene-saved.cpp

@@ -1,62 +0,0 @@
-#include "ibutton-scene-saved.h"
-#include "../ibutton-app.h"
-#include "../ibutton-view-manager.h"
-#include "../ibutton-event.h"
-#include <callback-connector.h>
-
-void iButtonSceneSavedList::on_enter(iButtonApp* app) {
-    iButtonAppViewManager* view_manager = app->get_view_manager();
-    Submenu* submenu = view_manager->get_submenu();
-    auto callback = cbc::obtain_connector(this, &iButtonSceneSavedList::submenu_callback);
-
-    KeyStore* store = app->get_key_store();
-
-    if(store->get_key_count() > 0) {
-        for(uint8_t i = 0; i < store->get_key_count(); i++) {
-            submenu_add_item(submenu, store->get_key_name(i), i, callback, app);
-        }
-    } else {
-        submenu_add_item(submenu, "Empty", 0, NULL, NULL);
-    }
-
-    view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
-}
-
-bool iButtonSceneSavedList::on_event(iButtonApp* app, iButtonEvent* event) {
-    bool consumed = false;
-
-    if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
-        uint8_t key_index = event->payload.menu_index;
-
-        // store data
-        iButtonKey* stored_key_data = app->get_key();
-        KeyStore* store = app->get_key_store();
-
-        app->set_stored_key_index(key_index);
-        stored_key_data->set_name(store->get_key_name(key_index));
-        stored_key_data->set_type(store->get_key_type(key_index));
-        stored_key_data->set_data(store->get_key_data(key_index), stored_key_data->get_size());
-
-        app->switch_to_next_scene(iButtonApp::Scene::SceneSavedKeyMenu);
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void iButtonSceneSavedList::on_exit(iButtonApp* app) {
-    iButtonAppViewManager* view = app->get_view_manager();
-    Submenu* submenu = view->get_submenu();
-
-    submenu_clean(submenu);
-}
-
-void iButtonSceneSavedList::submenu_callback(void* context, uint32_t index) {
-    iButtonApp* app = static_cast<iButtonApp*>(context);
-    iButtonEvent event;
-
-    event.type = iButtonEvent::Type::EventTypeMenuSelected;
-    event.payload.menu_index = index;
-
-    app->get_view_manager()->send_event(&event);
-}

+ 0 - 12
applications/ibutton/scene/ibutton-scene-saved.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "ibutton-scene-generic.h"
-
-class iButtonSceneSavedList : public iButtonScene {
-public:
-    void on_enter(iButtonApp* app) final;
-    bool on_event(iButtonApp* app, iButtonEvent* event) final;
-    void on_exit(iButtonApp* app) final;
-
-private:
-    void submenu_callback(void* context, uint32_t index);
-};

+ 35 - 3
applications/ibutton/scene/ibutton-scene-start.cpp

@@ -3,6 +3,7 @@
 #include "../ibutton-view-manager.h"
 #include "../ibutton-view-manager.h"
 #include "../ibutton-event.h"
 #include "../ibutton-event.h"
 #include <callback-connector.h>
 #include <callback-connector.h>
+#include <filesystem-api.h>
 
 
 typedef enum {
 typedef enum {
     SubmenuIndexRead,
     SubmenuIndexRead,
@@ -30,9 +31,40 @@ bool iButtonSceneStart::on_event(iButtonApp* app, iButtonEvent* event) {
         case SubmenuIndexRead:
         case SubmenuIndexRead:
             app->switch_to_next_scene(iButtonApp::Scene::SceneRead);
             app->switch_to_next_scene(iButtonApp::Scene::SceneRead);
             break;
             break;
-        case SubmenuIndexSaved:
-            app->switch_to_next_scene(iButtonApp::Scene::SceneSavedList);
-            break;
+        case SubmenuIndexSaved: {
+            bool res = app->get_sd_ex_api()->file_select(
+                app->get_sd_ex_api()->context,
+                "ibutton",
+                "*",
+                app->get_file_name(),
+                app->get_file_name_size());
+            if(res) {
+                string_t key_str;
+                string_init_set_str(key_str, "ibutton/");
+                string_cat_str(key_str, app->get_file_name());
+                File key_file;
+                uint8_t key_data[IBUTTON_KEY_SIZE + 1] = {};
+                // Read data from file
+                // TODO handle false return
+                res = app->get_fs_api()->file.open(
+                    &key_file, string_get_cstr(key_str), FSAM_READ, FSOM_OPEN_EXISTING);
+                res = app->get_fs_api()->file.read(&key_file, key_data, IBUTTON_KEY_SIZE + 1);
+                res = app->get_fs_api()->file.close(&key_file);
+                string_clear(key_str);
+                // Set key
+                iButtonKeyType key_type = static_cast<iButtonKeyType>(key_data[0]);
+                if(key_type > iButtonKeyType::KeyMetakom) {
+                    app->switch_to_next_scene(iButtonApp::Scene::SceneStart);
+                }
+                app->get_key()->set_name(app->get_file_name());
+                app->get_key()->set_type(key_type);
+                app->get_key()->set_data(key_data + 1, IBUTTON_KEY_SIZE);
+                app->switch_to_next_scene(iButtonApp::Scene::SceneSavedKeyMenu);
+            } else {
+                // TODO add error scene
+                app->switch_to_next_scene(iButtonApp::Scene::SceneStart);
+            }
+        }; break;
         case SubmenuIndexAdd:
         case SubmenuIndexAdd:
             app->switch_to_next_scene(iButtonApp::Scene::SceneAddType);
             app->switch_to_next_scene(iButtonApp::Scene::SceneAddType);
             break;
             break;

+ 25 - 6
applications/sd-filesystem/sd-filesystem.c

@@ -325,7 +325,7 @@ bool app_sd_make_path(const char* path) {
 
 
     if(*path) {
     if(*path) {
         char* file_path = strdup(path);
         char* file_path = strdup(path);
-
+        // Make parent directories
         for(char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
         for(char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
             *p = '\0';
             *p = '\0';
             SDError result = f_mkdir(file_path);
             SDError result = f_mkdir(file_path);
@@ -339,6 +339,14 @@ bool app_sd_make_path(const char* path) {
             }
             }
             *p = '/';
             *p = '/';
         }
         }
+        // Make origin directory
+        SDError result = f_mkdir(file_path);
+        if(result != SD_OK) {
+            if(result != SD_EXIST) {
+                free(file_path);
+                return false;
+            }
+        }
 
 
         free(file_path);
         free(file_path);
     }
     }
@@ -393,7 +401,7 @@ bool sd_api_file_select(
     SdAppFileSelectResultEvent event;
     SdAppFileSelectResultEvent event;
     while(1) {
     while(1) {
         osStatus_t event_status =
         osStatus_t event_status =
-            osMessageQueueGet(sd_app->event_queue, &event, NULL, osWaitForever);
+            osMessageQueueGet(return_event_queue, &event, NULL, osWaitForever);
         if(event_status == osOK) {
         if(event_status == osOK) {
             retval = event.result;
             retval = event.result;
             break;
             break;
@@ -697,7 +705,7 @@ int32_t sd_filesystem(void* p) {
                 case SdAppStateFileSelect: {
                 case SdAppStateFileSelect: {
                     SdAppFileSelectResultEvent retval = {.result = true};
                     SdAppFileSelectResultEvent retval = {.result = true};
                     furi_check(
                     furi_check(
-                        osMessageQueuePut(event.result_receiver, &retval, 0, osWaitForever) ==
+                        osMessageQueuePut(sd_app->result_receiver, &retval, 0, osWaitForever) ==
                         osOK);
                         osOK);
                     app_reset_state(sd_app);
                     app_reset_state(sd_app);
                 }; break;
                 }; break;
@@ -712,7 +720,7 @@ int32_t sd_filesystem(void* p) {
                 case SdAppStateFileSelect: {
                 case SdAppStateFileSelect: {
                     SdAppFileSelectResultEvent retval = {.result = false};
                     SdAppFileSelectResultEvent retval = {.result = false};
                     furi_check(
                     furi_check(
-                        osMessageQueuePut(event.result_receiver, &retval, 0, osWaitForever) ==
+                        osMessageQueuePut(sd_app->result_receiver, &retval, 0, osWaitForever) ==
                         osOK);
                         osOK);
                     app_reset_state(sd_app);
                     app_reset_state(sd_app);
                 }; break;
                 }; break;
@@ -799,8 +807,12 @@ int32_t sd_filesystem(void* p) {
                 break;
                 break;
             case SdAppEventTypeFileSelect:
             case SdAppEventTypeFileSelect:
                 if(!app_sd_make_path(event.payload.file_select_data.path)) {
                 if(!app_sd_make_path(event.payload.file_select_data.path)) {
+                    SdAppFileSelectResultEvent retval = {.result = false};
+                    furi_check(
+                        osMessageQueuePut(sd_app->result_receiver, &retval, 0, osWaitForever) ==
+                        osOK);
+                    app_reset_state(sd_app);
                 }
                 }
-
                 if(try_to_alloc_view_holder(sd_app, gui)) {
                 if(try_to_alloc_view_holder(sd_app, gui)) {
                     sd_app->result_receiver = event.result_receiver;
                     sd_app->result_receiver = event.result_receiver;
                     FileSelect* file_select = alloc_and_attach_file_select(sd_app);
                     FileSelect* file_select = alloc_and_attach_file_select(sd_app);
@@ -814,8 +826,15 @@ int32_t sd_filesystem(void* p) {
                         event.payload.file_select_data.result,
                         event.payload.file_select_data.result,
                         event.payload.file_select_data.result_size);
                         event.payload.file_select_data.result_size);
                     if(!file_select_init(file_select)) {
                     if(!file_select_init(file_select)) {
+                        SdAppFileSelectResultEvent retval = {.result = false};
+                        furi_check(
+                            osMessageQueuePut(
+                                sd_app->result_receiver, &retval, 0, osWaitForever) == osOK);
+                        app_reset_state(sd_app);
+                    } else {
+                        sd_app->sd_app_state = SdAppStateFileSelect;
+                        view_holder_start(sd_app->view_holder);
                     }
                     }
-                    sd_app->sd_app_state = SdAppStateFileSelect;
                 } else {
                 } else {
                     SdAppFileSelectResultEvent retval = {.result = false};
                     SdAppFileSelectResultEvent retval = {.result = false};
                     furi_check(
                     furi_check(