[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>
This commit is contained in:
		
							parent
							
								
									6375f21cf5
								
							
						
					
					
						commit
						5309bfae41
					
				| @ -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 | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
| @ -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)); |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
| }; |  | ||||||
| @ -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,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(); |     SdCard_Api* get_sd_ex_api(); | ||||||
|     uint8_t get_stored_key_index(); |     FS_Api* get_fs_api(); | ||||||
|     void set_stored_key_index(uint8_t index); |     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(); | ||||||
| }; | }; | ||||||
| @ -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() { | ||||||
| } | } | ||||||
|  | |||||||
| @ -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: | ||||||
|  | |||||||
| @ -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(); |             iButtonKey* key = app->get_key(); | ||||||
|             store->remove_key(app->get_stored_key_index()); |             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); |                 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(); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -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; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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(); | ||||||
| 
 |         File key_file; | ||||||
|         store->set_key_type(key_index, key->get_key_type()); |         string_t key_file_name; | ||||||
|         store->set_key_name(key_index, app->get_text_store()); |         string_init_set_str(key_file_name, "ibutton/"); | ||||||
|         store->set_key_data(key_index, key->get_data(), key->get_size()); |         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; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -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); |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
| }; |  | ||||||
| @ -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: |         case SubmenuIndexSaved: { | ||||||
|             app->switch_to_next_scene(iButtonApp::Scene::SceneSavedList); |             bool res = app->get_sd_ex_api()->file_select( | ||||||
|             break; |                 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; | ||||||
|  | |||||||
| @ -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; |                         sd_app->sd_app_state = SdAppStateFileSelect; | ||||||
|  |                         view_holder_start(sd_app->view_holder); | ||||||
|  |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     SdAppFileSelectResultEvent retval = {.result = false}; |                     SdAppFileSelectResultEvent retval = {.result = false}; | ||||||
|                     furi_check( |                     furi_check( | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich