[FL-1371] New LF-RFID app. Second encounter. (#547)
* File worker: file operations helper. * Notification app: removed yield * File worker: write operations, calls to system file widgets * App ibutton: use file worker * Lfrfid: generic key loading, add path helper and hex conversion to lib * FileWorker: plain C verison * FileWorker: add to lib.mk * FileWorker: add to C sources, instead of CPP * Lfrfid: save scene * App lfrfid: add key scene, saved key menu * App lfrfid: saved key info scene * App lfrfid: delete key scene
This commit is contained in:
		
							parent
							
								
									e8211226f3
								
							
						
					
					
						commit
						7a13391b2b
					
				
							
								
								
									
										10
									
								
								applications/ibutton/ibutton-app.cpp
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/ibutton/ibutton-app.cpp
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -2,7 +2,7 @@ | |||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| #include <callback-connector.h> | #include <callback-connector.h> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include <file-worker.h> | #include <file-worker-cpp.h> | ||||||
| 
 | 
 | ||||||
| const char* iButtonApp::app_folder = "ibutton"; | const char* iButtonApp::app_folder = "ibutton"; | ||||||
| const char* iButtonApp::app_extension = ".ibtn"; | const char* iButtonApp::app_extension = ".ibtn"; | ||||||
| @ -217,7 +217,7 @@ void iButtonApp::generate_random_name(char* name, uint8_t max_name_size) { | |||||||
| 
 | 
 | ||||||
| // file managment
 | // file managment
 | ||||||
| bool iButtonApp::save_key(const char* key_name) { | bool iButtonApp::save_key(const char* key_name) { | ||||||
|     FileWorker file_worker; |     FileWorkerCpp file_worker; | ||||||
|     string_t key_file_name; |     string_t key_file_name; | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
| @ -274,7 +274,7 @@ bool iButtonApp::save_key(const char* key_name) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool iButtonApp::load_key_data(string_t key_path) { | bool iButtonApp::load_key_data(string_t key_path) { | ||||||
|     FileWorker file_worker; |     FileWorkerCpp file_worker; | ||||||
| 
 | 
 | ||||||
|     // Open key file
 |     // Open key file
 | ||||||
|     if(!file_worker.open(string_get_cstr(key_path), FSAM_READ, FSOM_OPEN_EXISTING)) { |     if(!file_worker.open(string_get_cstr(key_path), FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
| @ -344,7 +344,7 @@ bool iButtonApp::load_key(const char* key_name) { | |||||||
| 
 | 
 | ||||||
| bool iButtonApp::load_key() { | bool iButtonApp::load_key() { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     FileWorker file_worker; |     FileWorkerCpp file_worker; | ||||||
| 
 | 
 | ||||||
|     // Input events and views are managed by file_select
 |     // Input events and views are managed by file_select
 | ||||||
|     bool res = file_worker.file_select( |     bool res = file_worker.file_select( | ||||||
| @ -369,7 +369,7 @@ bool iButtonApp::load_key() { | |||||||
| bool iButtonApp::delete_key() { | bool iButtonApp::delete_key() { | ||||||
|     string_t file_name; |     string_t file_name; | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     FileWorker file_worker; |     FileWorkerCpp file_worker; | ||||||
| 
 | 
 | ||||||
|     string_init_printf(file_name, "%s/%s%s", app_folder, get_key()->get_name(), app_extension); |     string_init_printf(file_name, "%s/%s%s", app_folder, get_key()->get_name(), app_extension); | ||||||
|     result = file_worker.remove(string_get_cstr(file_name)); |     result = file_worker.remove(string_get_cstr(file_name)); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "key-info.h" | #include "key-info.h" | ||||||
|  | #include <string.h> | ||||||
| 
 | 
 | ||||||
| const char* lfrfid_key_get_type_string(LfrfidKeyType type) { | const char* lfrfid_key_get_type_string(LfrfidKeyType type) { | ||||||
|     switch(type) { |     switch(type) { | ||||||
| @ -16,6 +17,22 @@ const char* lfrfid_key_get_type_string(LfrfidKeyType type) { | |||||||
|     return "Unknown"; |     return "Unknown"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type) { | ||||||
|  |     bool result = true; | ||||||
|  | 
 | ||||||
|  |     if(strcmp("EM4100", string) == 0) { | ||||||
|  |         *type = LfrfidKeyType::KeyEM4100; | ||||||
|  |     } else if(strcmp("H10301", string) == 0) { | ||||||
|  |         *type = LfrfidKeyType::KeyH10301; | ||||||
|  |     } else if(strcmp("I40134", string) == 0) { | ||||||
|  |         *type = LfrfidKeyType::KeyI40134; | ||||||
|  |     } else { | ||||||
|  |         result = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type) { | uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type) { | ||||||
|     switch(type) { |     switch(type) { | ||||||
|     case LfrfidKeyType::KeyEM4100: |     case LfrfidKeyType::KeyEM4100: | ||||||
|  | |||||||
| @ -11,4 +11,5 @@ enum class LfrfidKeyType : uint8_t { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const char* lfrfid_key_get_type_string(LfrfidKeyType type); | const char* lfrfid_key_get_type_string(LfrfidKeyType type); | ||||||
|  | bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type); | ||||||
| uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type); | uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type); | ||||||
| @ -1,12 +1,9 @@ | |||||||
| #include "rfid-key.h" | #include "rfid-key.h" | ||||||
| #include <furi/check.h> | #include <furi/check.h> | ||||||
|  | #include <string.h> | ||||||
| 
 | 
 | ||||||
| RfidKey::RfidKey() { | RfidKey::RfidKey() { | ||||||
|     data.fill(0); |     clear(); | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < (LFRFID_KEY_NAME_SIZE + 1); i++) { |  | ||||||
|         name[i] = 0; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RfidKey::~RfidKey() { | RfidKey::~RfidKey() { | ||||||
| @ -16,18 +13,22 @@ void RfidKey::set_type(LfrfidKeyType _type) { | |||||||
|     type = _type; |     type = _type; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RfidKey::set_data(uint8_t* _data, const uint8_t _data_size) { | void RfidKey::set_data(const uint8_t* _data, const uint8_t _data_size) { | ||||||
|     furi_assert(_data_size <= data.size()); |     furi_assert(_data_size <= data.size()); | ||||||
|     for(uint8_t i = 0; i < _data_size; i++) { |     for(uint8_t i = 0; i < _data_size; i++) { | ||||||
|         data[i] = _data[i]; |         data[i] = _data[i]; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void RfidKey::set_name(const char* _name) { | ||||||
|  |     strlcpy(name, _name, get_name_length()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| LfrfidKeyType RfidKey::get_type() { | LfrfidKeyType RfidKey::get_type() { | ||||||
|     return type; |     return type; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t* RfidKey::get_data() { | const uint8_t* RfidKey::get_data() { | ||||||
|     return &data[0]; |     return &data[0]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -42,3 +43,23 @@ const uint8_t RfidKey::get_type_data_count() { | |||||||
| char* RfidKey::get_name() { | char* RfidKey::get_name() { | ||||||
|     return name; |     return name; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | uint8_t RfidKey::get_name_length() { | ||||||
|  |     return LFRFID_KEY_NAME_SIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidKey::clear() { | ||||||
|  |     set_name(""); | ||||||
|  |     set_type(LfrfidKeyType::KeyEM4100); | ||||||
|  |     data.fill(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RfidKey& RfidKey::operator=(const RfidKey& rhs) { | ||||||
|  |     if(this == &rhs) return *this; | ||||||
|  | 
 | ||||||
|  |     set_type(rhs.type); | ||||||
|  |     set_name(rhs.name); | ||||||
|  |     set_data(&rhs.data[0], get_type_data_count()); | ||||||
|  | 
 | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  | |||||||
| @ -8,15 +8,17 @@ public: | |||||||
|     ~RfidKey(); |     ~RfidKey(); | ||||||
| 
 | 
 | ||||||
|     void set_type(LfrfidKeyType type); |     void set_type(LfrfidKeyType type); | ||||||
|     void set_data(uint8_t* data, const uint8_t data_size); |     void set_data(const uint8_t* data, const uint8_t data_size); | ||||||
|  |     void set_name(const char* name); | ||||||
| 
 | 
 | ||||||
|     LfrfidKeyType get_type(); |     LfrfidKeyType get_type(); | ||||||
|     uint8_t* get_data(); |     const uint8_t* get_data(); | ||||||
| 
 |  | ||||||
|     const char* get_type_text(); |     const char* get_type_text(); | ||||||
|     const uint8_t get_type_data_count(); |     const uint8_t get_type_data_count(); | ||||||
| 
 |  | ||||||
|     char* get_name(); |     char* get_name(); | ||||||
|  |     uint8_t get_name_length(); | ||||||
|  |     void clear(); | ||||||
|  |     RfidKey& operator=(const RfidKey& rhs); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::array<uint8_t, LFRFID_KEY_SIZE> data; |     std::array<uint8_t, LFRFID_KEY_SIZE> data; | ||||||
|  | |||||||
| @ -111,7 +111,7 @@ void RfidWriter::write_reset() { | |||||||
|     write_bit(0); |     write_bit(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RfidWriter::write_em(uint8_t em_data[5]) { | void RfidWriter::write_em(const uint8_t em_data[5]) { | ||||||
|     ProtocolEMMarin em_card; |     ProtocolEMMarin em_card; | ||||||
|     uint64_t em_encoded_data; |     uint64_t em_encoded_data; | ||||||
|     em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t)); |     em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t)); | ||||||
| @ -125,7 +125,7 @@ void RfidWriter::write_em(uint8_t em_data[5]) { | |||||||
|     __enable_irq(); |     __enable_irq(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RfidWriter::write_hid(uint8_t hid_data[3]) { | void RfidWriter::write_hid(const uint8_t hid_data[3]) { | ||||||
|     ProtocolHID10301 hid_card; |     ProtocolHID10301 hid_card; | ||||||
|     uint32_t card_data[3]; |     uint32_t card_data[3]; | ||||||
|     hid_card.encode(hid_data, 3, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3); |     hid_card.encode(hid_data, 3, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3); | ||||||
|  | |||||||
| @ -7,8 +7,8 @@ public: | |||||||
|     ~RfidWriter(); |     ~RfidWriter(); | ||||||
|     void start(); |     void start(); | ||||||
|     void stop(); |     void stop(); | ||||||
|     void write_em(uint8_t em_data[5]); |     void write_em(const uint8_t em_data[5]); | ||||||
|     void write_hid(uint8_t hid_data[3]); |     void write_hid(const uint8_t hid_data[3]); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void write_gap(uint32_t gap_time); |     void write_gap(uint32_t gap_time); | ||||||
|  | |||||||
| @ -1,9 +1,9 @@ | |||||||
| #include "lfrfid-app.h" | #include "lfrfid-app.h" | ||||||
| 
 | 
 | ||||||
| // app enter function
 | // app enter function
 | ||||||
| extern "C" int32_t lfrfid_app(void* p) { | extern "C" int32_t lfrfid_app(void* args) { | ||||||
|     LfRfidApp* app = new LfRfidApp(); |     LfRfidApp* app = new LfRfidApp(); | ||||||
|     app->run(); |     app->run(args); | ||||||
|     delete app; |     delete app; | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
|  | |||||||
| @ -7,6 +7,20 @@ | |||||||
| #include "scene/lfrfid-app-scene-write-success.h" | #include "scene/lfrfid-app-scene-write-success.h" | ||||||
| #include "scene/lfrfid-app-scene-emulate.h" | #include "scene/lfrfid-app-scene-emulate.h" | ||||||
| #include "scene/lfrfid-app-scene-save-name.h" | #include "scene/lfrfid-app-scene-save-name.h" | ||||||
|  | #include "scene/lfrfid-app-scene-save-success.h" | ||||||
|  | #include "scene/lfrfid-app-scene-select-key.h" | ||||||
|  | #include "scene/lfrfid-app-scene-saved-key-menu.h" | ||||||
|  | #include "scene/lfrfid-app-scene-save-data.h" | ||||||
|  | #include "scene/lfrfid-app-scene-save-type.h" | ||||||
|  | #include "scene/lfrfid-app-scene-saved-info.h" | ||||||
|  | #include "scene/lfrfid-app-scene-delete-confirm.h" | ||||||
|  | #include "scene/lfrfid-app-scene-delete-success.h" | ||||||
|  | 
 | ||||||
|  | #include <file-worker-cpp.h> | ||||||
|  | #include <path.h> | ||||||
|  | 
 | ||||||
|  | const char* LfRfidApp::app_folder = "lfrfid"; | ||||||
|  | const char* LfRfidApp::app_extension = ".rfid"; | ||||||
| 
 | 
 | ||||||
| LfRfidApp::LfRfidApp() | LfRfidApp::LfRfidApp() | ||||||
|     : scene_controller{this} |     : scene_controller{this} | ||||||
| @ -24,7 +38,14 @@ LfRfidApp::~LfRfidApp() { | |||||||
|     api_hal_power_insomnia_exit(); |     api_hal_power_insomnia_exit(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LfRfidApp::run() { | void LfRfidApp::run(void* _args) { | ||||||
|  |     const char* args = reinterpret_cast<const char*>(_args); | ||||||
|  | 
 | ||||||
|  |     if(strlen(args)) { | ||||||
|  |         load_key_data(args, &worker.key); | ||||||
|  |         scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); | ||||||
|  |         scene_controller.process(100, SceneType::Emulate); | ||||||
|  |     } else { | ||||||
|         scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); |         scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); | ||||||
|         scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); |         scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); | ||||||
|         scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); |         scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); | ||||||
| @ -33,5 +54,140 @@ void LfRfidApp::run() { | |||||||
|         scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); |         scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); | ||||||
|         scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); |         scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); | ||||||
|         scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName()); |         scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName()); | ||||||
|  |         scene_controller.add_scene(SceneType::SaveSuccess, new LfRfidAppSceneSaveSuccess()); | ||||||
|  |         scene_controller.add_scene(SceneType::SelectKey, new LfRfidAppSceneSelectKey()); | ||||||
|  |         scene_controller.add_scene(SceneType::SavedKeyMenu, new LfRfidAppSceneSavedKeyMenu()); | ||||||
|  |         scene_controller.add_scene(SceneType::SaveData, new LfRfidAppSceneSaveData()); | ||||||
|  |         scene_controller.add_scene(SceneType::SaveType, new LfRfidAppSceneSaveType()); | ||||||
|  |         scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo()); | ||||||
|  |         scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm()); | ||||||
|  |         scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess()); | ||||||
|         scene_controller.process(100); |         scene_controller.process(100); | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidApp::save_key(RfidKey* key) { | ||||||
|  |     string_t file_name; | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     make_app_folder(); | ||||||
|  | 
 | ||||||
|  |     string_init_printf(file_name, "%s/%s%s", app_folder, key->get_name(), app_extension); | ||||||
|  |     result = save_key_data(string_get_cstr(file_name), key); | ||||||
|  |     string_clear(file_name); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidApp::load_key_from_file_select(bool need_restore) { | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  |     TextStore* filename_ts = new TextStore(64); | ||||||
|  |     bool result; | ||||||
|  | 
 | ||||||
|  |     if(need_restore) { | ||||||
|  |         result = file_worker.file_select( | ||||||
|  |             app_folder, | ||||||
|  |             app_extension, | ||||||
|  |             filename_ts->text, | ||||||
|  |             filename_ts->text_size, | ||||||
|  |             worker.key.get_name()); | ||||||
|  |     } else { | ||||||
|  |         result = file_worker.file_select( | ||||||
|  |             app_folder, app_extension, filename_ts->text, filename_ts->text_size, NULL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(result) { | ||||||
|  |         string_t key_str; | ||||||
|  |         string_init_printf(key_str, "%s/%s%s", app_folder, filename_ts->text, app_extension); | ||||||
|  |         result = load_key_data(string_get_cstr(key_str), &worker.key); | ||||||
|  |         string_clear(key_str); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     delete filename_ts; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidApp::delete_key(RfidKey* key) { | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  |     string_t file_name; | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     string_init_printf(file_name, "%s/%s%s", app_folder, key->get_name(), app_extension); | ||||||
|  |     result = file_worker.remove(string_get_cstr(file_name)); | ||||||
|  |     string_clear(file_name); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidApp::load_key_data(const char* path, RfidKey* key) { | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     bool res = file_worker.open(path, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
|  | 
 | ||||||
|  |     if(res) { | ||||||
|  |         string_t str_result; | ||||||
|  |         string_init(str_result); | ||||||
|  | 
 | ||||||
|  |         do { | ||||||
|  |             RfidKey loaded_key; | ||||||
|  |             LfrfidKeyType loaded_type; | ||||||
|  | 
 | ||||||
|  |             // load type
 | ||||||
|  |             if(!file_worker.read_until(str_result, ' ')) break; | ||||||
|  |             if(!lfrfid_key_get_string_type(string_get_cstr(str_result), &loaded_type)) { | ||||||
|  |                 file_worker.show_error("Cannot parse\nfile"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             loaded_key.set_type(loaded_type); | ||||||
|  | 
 | ||||||
|  |             // load data
 | ||||||
|  |             uint8_t tmp_data[loaded_key.get_type_data_count()]; | ||||||
|  |             if(!file_worker.read_hex(tmp_data, loaded_key.get_type_data_count())) break; | ||||||
|  |             loaded_key.set_data(tmp_data, loaded_key.get_type_data_count()); | ||||||
|  | 
 | ||||||
|  |             *key = loaded_key; | ||||||
|  |             result = true; | ||||||
|  |         } while(0); | ||||||
|  | 
 | ||||||
|  |         // load name
 | ||||||
|  |         path_extract_filename_no_ext(path, str_result); | ||||||
|  |         key->set_name(string_get_cstr(str_result)); | ||||||
|  | 
 | ||||||
|  |         string_clear(str_result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     file_worker.close(); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidApp::save_key_data(const char* path, RfidKey* key) { | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     bool res = file_worker.open(path, FSAM_WRITE, FSOM_CREATE_ALWAYS); | ||||||
|  | 
 | ||||||
|  |     if(res) { | ||||||
|  |         do { | ||||||
|  |             // type header
 | ||||||
|  |             const char* key_type = lfrfid_key_get_type_string(key->get_type()); | ||||||
|  |             char delimeter = ' '; | ||||||
|  | 
 | ||||||
|  |             if(!file_worker.write(key_type, strlen(key_type))) break; | ||||||
|  |             if(!file_worker.write(&delimeter)) break; | ||||||
|  |             if(!file_worker.write_hex(key->get_data(), key->get_type_data_count())) break; | ||||||
|  | 
 | ||||||
|  |             result = true; | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     file_worker.close(); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidApp::make_app_folder() { | ||||||
|  |     FileWorkerCpp file_worker; | ||||||
|  |     file_worker.mkdir(app_folder); | ||||||
|  | } | ||||||
| @ -38,6 +38,14 @@ public: | |||||||
|         WriteSuccess, |         WriteSuccess, | ||||||
|         Emulate, |         Emulate, | ||||||
|         SaveName, |         SaveName, | ||||||
|  |         SaveSuccess, | ||||||
|  |         SelectKey, | ||||||
|  |         SavedKeyMenu, | ||||||
|  |         SaveData, | ||||||
|  |         SaveType, | ||||||
|  |         SavedInfo, | ||||||
|  |         DeleteConfirm, | ||||||
|  |         DeleteSuccess, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     class Event { |     class Event { | ||||||
| @ -63,5 +71,18 @@ public: | |||||||
|     RfidWorker worker; |     RfidWorker worker; | ||||||
| 
 | 
 | ||||||
|     TextStore text_store; |     TextStore text_store; | ||||||
|     void run(); | 
 | ||||||
|  |     void run(void* args); | ||||||
|  | 
 | ||||||
|  |     static const char* app_folder; | ||||||
|  |     static const char* app_extension; | ||||||
|  | 
 | ||||||
|  |     bool save_key(RfidKey* key); | ||||||
|  |     bool load_key_from_file_select(bool need_restore); | ||||||
|  |     bool delete_key(RfidKey* key); | ||||||
|  | 
 | ||||||
|  |     bool load_key_data(const char* path, RfidKey* key); | ||||||
|  |     bool save_key_data(const char* path, RfidKey* key); | ||||||
|  | 
 | ||||||
|  |     void make_app_folder(); | ||||||
| }; | }; | ||||||
| @ -0,0 +1,99 @@ | |||||||
|  | #include "lfrfid-app-scene-delete-confirm.h" | ||||||
|  | #include "../view/elements/button-element.h" | ||||||
|  | #include "../view/elements/icon-element.h" | ||||||
|  | #include "../view/elements/string-element.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     string_init(string_data); | ||||||
|  |     string_init(string_decrypted); | ||||||
|  |     string_init(string_header); | ||||||
|  | 
 | ||||||
|  |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
|  | 
 | ||||||
|  |     auto button = container->add<ButtonElement>(); | ||||||
|  |     button->set_type(ButtonElement::Type::Left, "Back"); | ||||||
|  |     button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback); | ||||||
|  | 
 | ||||||
|  |     button = container->add<ButtonElement>(); | ||||||
|  |     button->set_type(ButtonElement::Type::Right, "Delete"); | ||||||
|  |     button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback); | ||||||
|  | 
 | ||||||
|  |     auto line_1 = container->add<StringElement>(); | ||||||
|  |     auto line_2 = container->add<StringElement>(); | ||||||
|  |     auto line_3 = container->add<StringElement>(); | ||||||
|  |     auto line_4 = container->add<StringElement>(); | ||||||
|  | 
 | ||||||
|  |     RfidKey& key = app->worker.key; | ||||||
|  |     const uint8_t* data = key.get_data(); | ||||||
|  | 
 | ||||||
|  |     for(uint8_t i = 0; i < key.get_type_data_count(); i++) { | ||||||
|  |         if(i != 0) { | ||||||
|  |             string_cat_printf(string_data, " "); | ||||||
|  |         } | ||||||
|  |         string_cat_printf(string_data, "%02X", data[i]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_printf(string_header, "Delete %s?", key.get_name()); | ||||||
|  |     line_1->set_text( | ||||||
|  |         string_get_cstr(string_header), 64, 19, AlignCenter, AlignBottom, FontPrimary); | ||||||
|  |     line_2->set_text( | ||||||
|  |         string_get_cstr(string_data), 64, 29, AlignCenter, AlignBottom, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     switch(key.get_type()) { | ||||||
|  |     case LfrfidKeyType::KeyEM4100: | ||||||
|  |         string_printf( | ||||||
|  |             string_decrypted, "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); | ||||||
|  | 
 | ||||||
|  |         break; | ||||||
|  |     case LfrfidKeyType::KeyH10301: | ||||||
|  |     case LfrfidKeyType::KeyI40134: | ||||||
|  |         string_printf( | ||||||
|  |             string_decrypted, "FC: %u    ID: %u", data[0], (uint16_t)((data[1] << 8) | (data[2]))); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     line_3->set_text( | ||||||
|  |         string_get_cstr(string_decrypted), 64, 39, AlignCenter, AlignBottom, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     line_4->set_text( | ||||||
|  |         lfrfid_key_get_type_string(key.get_type()), | ||||||
|  |         64, | ||||||
|  |         49, | ||||||
|  |         AlignCenter, | ||||||
|  |         AlignBottom, | ||||||
|  |         FontSecondary); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<ContainerVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|  |         app->delete_key(&app->worker.key); | ||||||
|  |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|  |     string_clear(string_data); | ||||||
|  |     string_clear(string_decrypted); | ||||||
|  |     string_clear(string_header); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteConfirm::back_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Back; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteConfirm::delete_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Next; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneDeleteConfirm : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void back_callback(void* context); | ||||||
|  |     static void delete_callback(void* context); | ||||||
|  | 
 | ||||||
|  |     string_t string_header; | ||||||
|  |     string_t string_data; | ||||||
|  |     string_t string_decrypted; | ||||||
|  | }; | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | #include "lfrfid-app-scene-delete-success.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
|  | 
 | ||||||
|  |     popup->set_icon(0, 2, I_DolphinMafia_115x62); | ||||||
|  |     popup->set_text("Deleted", 83, 19, AlignLeft, AlignBottom); | ||||||
|  |     popup->set_context(app); | ||||||
|  |     popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback); | ||||||
|  |     popup->set_timeout(1500); | ||||||
|  |     popup->enable_timeout(); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<PopupVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneDeleteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::Back) { | ||||||
|  |         app->scene_controller.search_and_switch_to_previous_scene( | ||||||
|  |             {LfRfidApp::SceneType::SelectKey}); | ||||||
|  | 
 | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteSuccess::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Back; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								applications/lfrfid/scene/lfrfid-app-scene-delete-success.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/lfrfid/scene/lfrfid-app-scene-delete-success.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneDeleteSuccess : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void timeout_callback(void* context); | ||||||
|  | }; | ||||||
| @ -3,7 +3,7 @@ | |||||||
| void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool need_restore) { | void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|     string_init(data_string); |     string_init(data_string); | ||||||
| 
 | 
 | ||||||
|     uint8_t* data = app->worker.key.get_data(); |     const uint8_t* data = app->worker.key.get_data(); | ||||||
| 
 | 
 | ||||||
|     for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { |     for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { | ||||||
|         string_cat_printf(data_string, "%02X", data[i]); |         string_cat_printf(data_string, "%02X", data[i]); | ||||||
| @ -11,8 +11,12 @@ void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
| 
 | 
 | ||||||
|     auto popup = app->view_controller.get<PopupVM>(); |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     popup->set_header("Emulating", 90, 34, AlignCenter, AlignTop); |     popup->set_header("LF emulating", 89, 30, AlignCenter, AlignTop); | ||||||
|     popup->set_text(string_get_cstr(data_string), 90, 48, AlignCenter, AlignTop); |     if(strlen(app->worker.key.get_name())) { | ||||||
|  |         popup->set_text(app->worker.key.get_name(), 89, 43, AlignCenter, AlignTop); | ||||||
|  |     } else { | ||||||
|  |         popup->set_text(string_get_cstr(data_string), 89, 43, AlignCenter, AlignTop); | ||||||
|  |     } | ||||||
|     popup->set_icon(0, 4, I_RFIDDolphinSend_98x60); |     popup->set_icon(0, 4, I_RFIDDolphinSend_98x60); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<PopupVM>(); |     app->view_controller.switch_to<PopupVM>(); | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     auto line_2_value = container->add<StringElement>(); |     auto line_2_value = container->add<StringElement>(); | ||||||
|     auto line_3_value = container->add<StringElement>(); |     auto line_3_value = container->add<StringElement>(); | ||||||
| 
 | 
 | ||||||
|     uint8_t* data = app->worker.key.get_data(); |     const uint8_t* data = app->worker.key.get_data(); | ||||||
| 
 | 
 | ||||||
|     switch(app->worker.key.get_type()) { |     switch(app->worker.key.get_type()) { | ||||||
|     case LfrfidKeyType::KeyEM4100: |     case LfrfidKeyType::KeyEM4100: | ||||||
|  | |||||||
							
								
								
									
										58
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-data.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-data.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | #include "lfrfid-app-scene-save-data.h" | ||||||
|  | 
 | ||||||
|  | static void print_buffer(const uint8_t* buffer) { | ||||||
|  |     for(uint8_t i = 0; i < LFRFID_KEY_SIZE; i++) { | ||||||
|  |         printf("%02X", buffer[i]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     auto byte_input = app->view_controller.get<ByteInputVM>(); | ||||||
|  |     RfidKey& key = app->worker.key; | ||||||
|  | 
 | ||||||
|  |     printf("k: "); | ||||||
|  |     print_buffer(key.get_data()); | ||||||
|  |     printf(" o: "); | ||||||
|  |     print_buffer(old_key_data); | ||||||
|  |     printf(" n: "); | ||||||
|  |     print_buffer(new_key_data); | ||||||
|  |     printf("\r\n"); | ||||||
|  |     if(need_restore) printf("restored\r\n"); | ||||||
|  | 
 | ||||||
|  |     if(need_restore) { | ||||||
|  |         key.set_data(old_key_data, key.get_type_data_count()); | ||||||
|  |     } else { | ||||||
|  |         memcpy(old_key_data, key.get_data(), key.get_type_data_count()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     memcpy(new_key_data, key.get_data(), key.get_type_data_count()); | ||||||
|  |     byte_input->set_header_text("Enter the data in hex"); | ||||||
|  | 
 | ||||||
|  |     byte_input->set_result_callback( | ||||||
|  |         save_callback, NULL, app, new_key_data, app->worker.key.get_type_data_count()); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<ByteInputVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  |     RfidKey& key = app->worker.key; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|  |         key.set_data(new_key_data, key.get_type_data_count()); | ||||||
|  |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveData::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<ByteInputVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveData::save_callback(void* context, uint8_t* bytes, uint8_t bytes_count) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Next; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-data.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneSaveData : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void save_callback(void* context, uint8_t* bytes, uint8_t bytes_count); | ||||||
|  |     uint8_t old_key_data[LFRFID_KEY_SIZE] = { | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |         0xAA, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     uint8_t new_key_data[LFRFID_KEY_SIZE] = { | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |         0xBB, | ||||||
|  |     }; | ||||||
|  | }; | ||||||
| @ -14,7 +14,7 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     text_input->set_header_text("Name the card"); |     text_input->set_header_text("Name the card"); | ||||||
| 
 | 
 | ||||||
|     text_input->set_result_callback( |     text_input->set_result_callback( | ||||||
|         save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE); |         save_callback, app, app->text_store.text, app->worker.key.get_name_length()); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<TextInputVM>(); |     app->view_controller.switch_to<TextInputVM>(); | ||||||
| } | } | ||||||
| @ -23,14 +23,18 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::Next) { |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|         /*if(app->save_key(app->get_text_store())) {
 |         if(strlen(app->worker.key.get_name())) { | ||||||
|             app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess); |             app->delete_key(&app->worker.key); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         app->worker.key.set_name(app->text_store.text); | ||||||
|  | 
 | ||||||
|  |         if(app->save_key(&app->worker.key)) { | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); | ||||||
|         } else { |         } else { | ||||||
|             app->search_and_switch_to_previous_scene( |             app->scene_controller.search_and_switch_to_previous_scene( | ||||||
|                 {iButtonApp::Scene::SceneReadedKeyMenu, |                 {LfRfidApp::SceneType::ReadedMenu}); | ||||||
|                  iButtonApp::Scene::SceneSavedKeyMenu, |         } | ||||||
|                  iButtonApp::Scene::SceneAddType}); |  | ||||||
|         }*/ |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-success.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-success.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | #include "lfrfid-app-scene-save-success.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
|  | 
 | ||||||
|  |     popup->set_icon(32, 5, I_DolphinNice_96x59); | ||||||
|  |     popup->set_text("Saved!", 13, 22, AlignLeft, AlignBottom); | ||||||
|  |     popup->set_context(app); | ||||||
|  |     popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback); | ||||||
|  |     popup->set_timeout(1500); | ||||||
|  |     popup->enable_timeout(); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<PopupVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::Back) { | ||||||
|  |         bool result = app->scene_controller.has_previous_scene( | ||||||
|  |             {LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey}); | ||||||
|  | 
 | ||||||
|  |         if(result) { | ||||||
|  |             app->scene_controller.search_and_switch_to_previous_scene( | ||||||
|  |                 {LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey}); | ||||||
|  |         } else { | ||||||
|  |             app->scene_controller.search_and_switch_to_another_scene( | ||||||
|  |                 {LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveSuccess::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Back; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-success.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-success.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneSaveSuccess : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void timeout_callback(void* context); | ||||||
|  | }; | ||||||
							
								
								
									
										46
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-type.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-type.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | #include "lfrfid-app-scene-save-type.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     auto submenu = app->view_controller.get<SubmenuVM>(); | ||||||
|  | 
 | ||||||
|  |     for(uint8_t i = 0; i <= static_cast<uint8_t>(LfrfidKeyType::KeyI40134); i++) { | ||||||
|  |         submenu->add_item( | ||||||
|  |             lfrfid_key_get_type_string(static_cast<LfrfidKeyType>(i)), i, submenu_callback, app); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(need_restore) { | ||||||
|  |         submenu->set_selected_item(submenu_item_selected); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
|  | 
 | ||||||
|  |     // clear key name
 | ||||||
|  |     app->worker.key.set_name(""); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|  |         submenu_item_selected = event->payload.menu_index; | ||||||
|  |         app->worker.key.set_type(static_cast<LfrfidKeyType>(event->payload.menu_index)); | ||||||
|  |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<SubmenuVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  | 
 | ||||||
|  |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|  |     event.payload.menu_index = index; | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-type.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								applications/lfrfid/scene/lfrfid-app-scene-save-type.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneSaveType : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void submenu_callback(void* context, uint32_t index); | ||||||
|  |     uint32_t submenu_item_selected = 0; | ||||||
|  | }; | ||||||
							
								
								
									
										77
									
								
								applications/lfrfid/scene/lfrfid-app-scene-saved-info.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								applications/lfrfid/scene/lfrfid-app-scene-saved-info.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | #include "lfrfid-app-scene-saved-info.h" | ||||||
|  | #include "../view/elements/button-element.h" | ||||||
|  | #include "../view/elements/icon-element.h" | ||||||
|  | #include "../view/elements/string-element.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     string_init(string_data); | ||||||
|  |     string_init(string_decrypted); | ||||||
|  | 
 | ||||||
|  |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
|  | 
 | ||||||
|  |     auto button = container->add<ButtonElement>(); | ||||||
|  |     button->set_type(ButtonElement::Type::Left, "Back"); | ||||||
|  |     button->set_callback(app, LfRfidAppSceneSavedInfo::back_callback); | ||||||
|  | 
 | ||||||
|  |     auto line_1 = container->add<StringElement>(); | ||||||
|  |     auto line_2 = container->add<StringElement>(); | ||||||
|  |     auto line_3 = container->add<StringElement>(); | ||||||
|  |     auto line_4 = container->add<StringElement>(); | ||||||
|  | 
 | ||||||
|  |     RfidKey& key = app->worker.key; | ||||||
|  |     const uint8_t* data = key.get_data(); | ||||||
|  | 
 | ||||||
|  |     for(uint8_t i = 0; i < key.get_type_data_count(); i++) { | ||||||
|  |         if(i != 0) { | ||||||
|  |             string_cat_printf(string_data, " "); | ||||||
|  |         } | ||||||
|  |         string_cat_printf(string_data, "%02X", data[i]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     line_1->set_text(key.get_name(), 64, 17, AlignCenter, AlignBottom, FontSecondary); | ||||||
|  |     line_2->set_text(string_get_cstr(string_data), 64, 29, AlignCenter, AlignBottom, FontPrimary); | ||||||
|  | 
 | ||||||
|  |     switch(key.get_type()) { | ||||||
|  |     case LfrfidKeyType::KeyEM4100: | ||||||
|  |         string_printf( | ||||||
|  |             string_decrypted, "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); | ||||||
|  | 
 | ||||||
|  |         break; | ||||||
|  |     case LfrfidKeyType::KeyH10301: | ||||||
|  |     case LfrfidKeyType::KeyI40134: | ||||||
|  |         string_printf( | ||||||
|  |             string_decrypted, "FC: %u    ID: %u", data[0], (uint16_t)((data[1] << 8) | (data[2]))); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     line_3->set_text( | ||||||
|  |         string_get_cstr(string_decrypted), 64, 39, AlignCenter, AlignBottom, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     line_4->set_text( | ||||||
|  |         lfrfid_key_get_type_string(key.get_type()), | ||||||
|  |         64, | ||||||
|  |         49, | ||||||
|  |         AlignCenter, | ||||||
|  |         AlignBottom, | ||||||
|  |         FontSecondary); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<ContainerVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|  |     string_clear(string_data); | ||||||
|  |     string_clear(string_decrypted); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSavedInfo::back_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Back; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								applications/lfrfid/scene/lfrfid-app-scene-saved-info.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								applications/lfrfid/scene/lfrfid-app-scene-saved-info.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneSavedInfo : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void back_callback(void* context); | ||||||
|  | 
 | ||||||
|  |     string_t string_data; | ||||||
|  |     string_t string_decrypted; | ||||||
|  | }; | ||||||
| @ -0,0 +1,67 @@ | |||||||
|  | #include "lfrfid-app-scene-saved-key-menu.h" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubmenuEmulate, | ||||||
|  |     SubmenuWrite, | ||||||
|  |     SubmenuEdit, | ||||||
|  |     SubmenuDelete, | ||||||
|  |     SubmenuInfo, | ||||||
|  | } SubmenuIndex; | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSavedKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     auto submenu = app->view_controller.get<SubmenuVM>(); | ||||||
|  | 
 | ||||||
|  |     submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); | ||||||
|  |     submenu->add_item("Write", SubmenuWrite, submenu_callback, app); | ||||||
|  |     submenu->add_item("Edit", SubmenuEdit, submenu_callback, app); | ||||||
|  |     submenu->add_item("Delete", SubmenuDelete, submenu_callback, app); | ||||||
|  |     submenu->add_item("Info", SubmenuInfo, submenu_callback, app); | ||||||
|  | 
 | ||||||
|  |     if(need_restore) { | ||||||
|  |         submenu->set_selected_item(submenu_item_selected); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneSavedKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|  |         submenu_item_selected = event->payload.menu_index; | ||||||
|  |         switch(event->payload.menu_index) { | ||||||
|  |         case SubmenuEmulate: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); | ||||||
|  |             break; | ||||||
|  |         case SubmenuWrite: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); | ||||||
|  |             break; | ||||||
|  |         case SubmenuEdit: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); | ||||||
|  |             break; | ||||||
|  |         case SubmenuDelete: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteConfirm); | ||||||
|  |             break; | ||||||
|  |         case SubmenuInfo: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedInfo); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSavedKeyMenu::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<SubmenuVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  | 
 | ||||||
|  |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|  |     event.payload.menu_index = index; | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneSavedKeyMenu : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void submenu_callback(void* context, uint32_t index); | ||||||
|  |     uint32_t submenu_item_selected = 0; | ||||||
|  | }; | ||||||
							
								
								
									
										18
									
								
								applications/lfrfid/scene/lfrfid-app-scene-select-key.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								applications/lfrfid/scene/lfrfid-app-scene-select-key.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | #include "lfrfid-app-scene-select-key.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSelectKey::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     if(app->load_key_from_file_select(need_restore)) { | ||||||
|  |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedKeyMenu); | ||||||
|  |     } else { | ||||||
|  |         app->scene_controller.switch_to_previous_scene(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneSelectKey::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneSelectKey::on_exit(LfRfidApp* app) { | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								applications/lfrfid/scene/lfrfid-app-scene-select-key.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								applications/lfrfid/scene/lfrfid-app-scene-select-key.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid-app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneSelectKey : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | }; | ||||||
| @ -16,7 +16,11 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     if(need_restore) { |     if(need_restore) { | ||||||
|         submenu->set_selected_item(submenu_item_selected); |         submenu->set_selected_item(submenu_item_selected); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     app->view_controller.switch_to<SubmenuVM>(); |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
|  | 
 | ||||||
|  |     // clear key
 | ||||||
|  |     app->worker.key.clear(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
| @ -29,8 +33,10 @@ bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); | ||||||
|             break; |             break; | ||||||
|         case SubmenuSaved: |         case SubmenuSaved: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SelectKey); | ||||||
|             break; |             break; | ||||||
|         case SubmenuAddManually: |         case SubmenuAddManually: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         consumed = true; |         consumed = true; | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     card_not_supported = false; |     card_not_supported = false; | ||||||
|     string_init(data_string); |     string_init(data_string); | ||||||
| 
 | 
 | ||||||
|     uint8_t* data = app->worker.key.get_data(); |     const uint8_t* data = app->worker.key.get_data(); | ||||||
| 
 | 
 | ||||||
|     for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { |     for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { | ||||||
|         string_cat_printf(data_string, "%02X", data[i]); |         string_cat_printf(data_string, "%02X", data[i]); | ||||||
| @ -12,8 +12,12 @@ void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
| 
 | 
 | ||||||
|     auto popup = app->view_controller.get<PopupVM>(); |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     popup->set_header("Writing", 90, 34, AlignCenter, AlignTop); |     popup->set_header("LF writing", 89, 30, AlignCenter, AlignTop); | ||||||
|     popup->set_text(string_get_cstr(data_string), 90, 48, AlignCenter, AlignTop); |     if(strlen(app->worker.key.get_name())) { | ||||||
|  |         popup->set_text(app->worker.key.get_name(), 89, 43, AlignCenter, AlignTop); | ||||||
|  |     } else { | ||||||
|  |         popup->set_text(string_get_cstr(data_string), 89, 43, AlignCenter, AlignTop); | ||||||
|  |     } | ||||||
|     popup->set_icon(0, 4, I_RFIDDolphinSend_98x60); |     popup->set_icon(0, 4, I_RFIDDolphinSend_98x60); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<PopupVM>(); |     app->view_controller.switch_to<PopupVM>(); | ||||||
|  | |||||||
							
								
								
									
										68
									
								
								lib/app-scened-template/file-worker-cpp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/app-scened-template/file-worker-cpp.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | #include "file-worker-cpp.h" | ||||||
|  | #include <hex.h> | ||||||
|  | 
 | ||||||
|  | FileWorkerCpp::FileWorkerCpp(bool _silent) { | ||||||
|  |     file_worker = file_worker_alloc(_silent); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FileWorkerCpp::~FileWorkerCpp() { | ||||||
|  |     file_worker_free(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::open(const char* filename, FS_AccessMode access_mode, FS_OpenMode open_mode) { | ||||||
|  |     return file_worker_open(file_worker, filename, access_mode, open_mode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::close() { | ||||||
|  |     return file_worker_close(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::mkdir(const char* dirname) { | ||||||
|  |     return file_worker_mkdir(file_worker, dirname); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::remove(const char* filename) { | ||||||
|  |     return file_worker_remove(file_worker, filename); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::read(void* buffer, uint16_t bytes_to_read) { | ||||||
|  |     return file_worker_read(file_worker, buffer, bytes_to_read); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::read_until(string_t str_result, char separator) { | ||||||
|  |     return file_worker_read_until(file_worker, str_result, separator); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::read_hex(uint8_t* buffer, uint16_t bytes_to_read) { | ||||||
|  |     return file_worker_read_hex(file_worker, buffer, bytes_to_read); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::tell(uint64_t* position) { | ||||||
|  |     return file_worker_tell(file_worker, position); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::seek(uint64_t position, bool from_start) { | ||||||
|  |     return file_worker_seek(file_worker, position, from_start); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::write(const void* buffer, uint16_t bytes_to_write) { | ||||||
|  |     return file_worker_write(file_worker, buffer, bytes_to_write); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::write_hex(const uint8_t* buffer, uint16_t bytes_to_write) { | ||||||
|  |     return file_worker_write_hex(file_worker, buffer, bytes_to_write); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void FileWorkerCpp::show_error(const char* error_text) { | ||||||
|  |     file_worker_show_error(file_worker, error_text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool FileWorkerCpp::file_select( | ||||||
|  |     const char* path, | ||||||
|  |     const char* extension, | ||||||
|  |     char* result, | ||||||
|  |     uint8_t result_size, | ||||||
|  |     char* selected_filename) { | ||||||
|  |     return file_worker_file_select( | ||||||
|  |         file_worker, path, extension, result, result_size, selected_filename); | ||||||
|  | } | ||||||
							
								
								
									
										135
									
								
								lib/app-scened-template/file-worker-cpp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								lib/app-scened-template/file-worker-cpp.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "file-worker.h" | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief File operations helper class. | ||||||
|  |  * Automatically opens API records, shows error message on error. | ||||||
|  |  */ | ||||||
|  | class FileWorkerCpp { | ||||||
|  | public: | ||||||
|  |     FileWorkerCpp(bool silent = false); | ||||||
|  |     ~FileWorkerCpp(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Open file | ||||||
|  |      *  | ||||||
|  |      * @param filename  | ||||||
|  |      * @param access_mode  | ||||||
|  |      * @param open_mode  | ||||||
|  |      * @return true on success | ||||||
|  |      */ | ||||||
|  |     bool open(const char* filename, FS_AccessMode access_mode, FS_OpenMode open_mode); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Close file | ||||||
|  |      *  | ||||||
|  |      * @return true on success | ||||||
|  |      */ | ||||||
|  |     bool close(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Creates a directory. Doesn't show error if directory exist.  | ||||||
|  |      *  | ||||||
|  |      * @param dirname  | ||||||
|  |      * @return true on success | ||||||
|  |      */ | ||||||
|  |     bool mkdir(const char* dirname); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Removes the file. Doesn't show error if file doesn't exist. | ||||||
|  |      *  | ||||||
|  |      * @param filename  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool remove(const char* filename); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Reads data from a file. | ||||||
|  |      *  | ||||||
|  |      * @param buffer  | ||||||
|  |      * @param bytes_to_read  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool read(void* buffer, uint16_t bytes_to_read = 1); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Reads data from a file until separator or EOF is found.  | ||||||
|  |      * Moves seek pointer to the next symbol after the separator. The separator is not included in the result. | ||||||
|  |      *  | ||||||
|  |      * @param result  | ||||||
|  |      * @param separator  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool read_until(string_t result, char separator = '\n'); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Reads data in hexadecimal space-delimited format. For example "AF FF" in a file - [175, 255] in a read buffer. | ||||||
|  |      *  | ||||||
|  |      * @param buffer  | ||||||
|  |      * @param bytes_to_read  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool read_hex(uint8_t* buffer, uint16_t bytes_to_read = 1); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Read seek pointer value | ||||||
|  |      *  | ||||||
|  |      * @param position  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool tell(uint64_t* position); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Set seek pointer value | ||||||
|  |      *  | ||||||
|  |      * @param position  | ||||||
|  |      * @param from_start  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool seek(uint64_t position, bool from_start); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Write data to file. | ||||||
|  |      *  | ||||||
|  |      * @param buffer  | ||||||
|  |      * @param bytes_to_write  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool write(const void* buffer, uint16_t bytes_to_write = 1); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Write data to file in hexadecimal space-delimited format. For example [175, 255] in a write buffer - "AF FF" in a file. | ||||||
|  |      *  | ||||||
|  |      * @param buffer  | ||||||
|  |      * @param bytes_to_write  | ||||||
|  |      * @return true on success   | ||||||
|  |      */ | ||||||
|  |     bool write_hex(const uint8_t* buffer, uint16_t bytes_to_write = 1); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Show system file error message | ||||||
|  |      *  | ||||||
|  |      * @param error_text  | ||||||
|  |      */ | ||||||
|  |     void show_error(const char* error_text); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Show system file select widget | ||||||
|  |      *  | ||||||
|  |      * @param path  | ||||||
|  |      * @param extension  | ||||||
|  |      * @param result  | ||||||
|  |      * @param result_size  | ||||||
|  |      * @param selected_filename  | ||||||
|  |      * @return true if file was selected | ||||||
|  |      */ | ||||||
|  |     bool file_select( | ||||||
|  |         const char* path, | ||||||
|  |         const char* extension, | ||||||
|  |         char* result, | ||||||
|  |         uint8_t result_size, | ||||||
|  |         char* selected_filename); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     FileWorker* file_worker; | ||||||
|  | }; | ||||||
							
								
								
									
										280
									
								
								lib/app-scened-template/file-worker.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								lib/app-scened-template/file-worker.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,280 @@ | |||||||
|  | #include "file-worker.h" | ||||||
|  | #include <hex.h> | ||||||
|  | #include <sd-card-api.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | struct FileWorker { | ||||||
|  |     FS_Api* fs_api; | ||||||
|  |     SdCard_Api* sd_ex_api; | ||||||
|  |     bool silent; | ||||||
|  |     File file; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | bool file_worker_check_common_errors(FileWorker* file_worker); | ||||||
|  | void file_worker_show_error_internal(FileWorker* file_worker, const char* error_text); | ||||||
|  | bool file_worker_read_internal(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read); | ||||||
|  | bool file_worker_write_internal( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     const void* buffer, | ||||||
|  |     uint16_t bytes_to_write); | ||||||
|  | bool file_worker_tell_internal(FileWorker* file_worker, uint64_t* position); | ||||||
|  | bool file_worker_seek_internal(FileWorker* file_worker, uint64_t position, bool from_start); | ||||||
|  | 
 | ||||||
|  | FileWorker* file_worker_alloc(bool _silent) { | ||||||
|  |     FileWorker* file_worker = malloc(sizeof(FileWorker)); | ||||||
|  |     file_worker->silent = _silent; | ||||||
|  |     file_worker->fs_api = furi_record_open("sdcard"); | ||||||
|  |     file_worker->sd_ex_api = furi_record_open("sdcard-ex"); | ||||||
|  | 
 | ||||||
|  |     return file_worker; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void file_worker_free(FileWorker* file_worker) { | ||||||
|  |     furi_record_close("sdcard"); | ||||||
|  |     furi_record_close("sdcard-ex"); | ||||||
|  |     free(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_open( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     const char* filename, | ||||||
|  |     FS_AccessMode access_mode, | ||||||
|  |     FS_OpenMode open_mode) { | ||||||
|  |     bool result = | ||||||
|  |         file_worker->fs_api->file.open(&file_worker->file, filename, access_mode, open_mode); | ||||||
|  | 
 | ||||||
|  |     if(!result) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot open\nfile"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_close(FileWorker* file_worker) { | ||||||
|  |     file_worker->fs_api->file.close(&file_worker->file); | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_mkdir(FileWorker* file_worker, const char* dirname) { | ||||||
|  |     FS_Error fs_result = file_worker->fs_api->common.mkdir(dirname); | ||||||
|  | 
 | ||||||
|  |     if(fs_result != FSE_OK && fs_result != FSE_EXIST) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot create\nfolder"); | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_remove(FileWorker* file_worker, const char* filename) { | ||||||
|  |     FS_Error fs_result = file_worker->fs_api->common.remove(filename); | ||||||
|  |     if(fs_result != FSE_OK && fs_result != FSE_NOT_EXIST) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot remove\nold file"); | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_read(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read) { | ||||||
|  |     if(!file_worker_read_internal(file_worker, buffer, bytes_to_read)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_read_until(FileWorker* file_worker, string_t str_result, char separator) { | ||||||
|  |     string_clean(str_result); | ||||||
|  |     const uint8_t buffer_size = 32; | ||||||
|  |     uint8_t buffer[buffer_size]; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         uint16_t read_count = | ||||||
|  |             file_worker->fs_api->file.read(&file_worker->file, buffer, buffer_size); | ||||||
|  |         if(file_worker->file.error_id != FSE_OK) { | ||||||
|  |             file_worker_show_error_internal(file_worker, "Cannot read\nfile"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool result = false; | ||||||
|  |         for(uint16_t i = 0; i < read_count; i++) { | ||||||
|  |             if(buffer[i] == separator) { | ||||||
|  |                 uint64_t position; | ||||||
|  |                 if(!file_worker_tell_internal(file_worker, &position)) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 position = position - read_count + i + 1; | ||||||
|  | 
 | ||||||
|  |                 if(!file_worker_seek_internal(file_worker, position, true)) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 result = true; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 string_push_back(str_result, buffer[i]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(result || read_count == 0) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } while(true); | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_read_hex(FileWorker* file_worker, uint8_t* buffer, uint16_t bytes_to_read) { | ||||||
|  |     uint8_t hi_nibble_value, low_nibble_value; | ||||||
|  |     uint8_t text[2]; | ||||||
|  | 
 | ||||||
|  |     for(uint8_t i = 0; i < bytes_to_read; i++) { | ||||||
|  |         if(i != 0) { | ||||||
|  |             // space
 | ||||||
|  |             if(!file_worker_read_internal(file_worker, text, 1)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // actual data
 | ||||||
|  |         if(!file_worker_read_internal(file_worker, text, 2)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // convert hex value to byte
 | ||||||
|  |         if(hex_char_to_hex_nibble(text[0], &hi_nibble_value) && | ||||||
|  |            hex_char_to_hex_nibble(text[1], &low_nibble_value)) { | ||||||
|  |             buffer[i] = (hi_nibble_value << 4) | low_nibble_value; | ||||||
|  |         } else { | ||||||
|  |             file_worker_show_error_internal(file_worker, "Cannot parse\nfile"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_tell(FileWorker* file_worker, uint64_t* position) { | ||||||
|  |     if(!file_worker_tell_internal(file_worker, position)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_seek(FileWorker* file_worker, uint64_t position, bool from_start) { | ||||||
|  |     if(!file_worker_seek_internal(file_worker, position, from_start)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_write(FileWorker* file_worker, const void* buffer, uint16_t bytes_to_write) { | ||||||
|  |     if(!file_worker_write_internal(file_worker, buffer, bytes_to_write)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_write_hex(FileWorker* file_worker, const uint8_t* buffer, uint16_t bytes_to_write) { | ||||||
|  |     const uint8_t byte_text_size = 3; | ||||||
|  |     char byte_text[byte_text_size]; | ||||||
|  | 
 | ||||||
|  |     for(uint8_t i = 0; i < bytes_to_write; i++) { | ||||||
|  |         sniprintf(byte_text, byte_text_size, "%02X", buffer[i]); | ||||||
|  | 
 | ||||||
|  |         if(i != 0) { | ||||||
|  |             // space
 | ||||||
|  |             const char* space = " "; | ||||||
|  |             if(!file_worker_write_internal(file_worker, space, 1)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!file_worker_write_internal(file_worker, byte_text, 2)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return file_worker_check_common_errors(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void file_worker_show_error(FileWorker* file_worker, const char* error_text) { | ||||||
|  |     file_worker->sd_ex_api->show_error(file_worker->sd_ex_api->context, error_text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_file_select( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     const char* path, | ||||||
|  |     const char* extension, | ||||||
|  |     char* result, | ||||||
|  |     uint8_t result_size, | ||||||
|  |     char* selected_filename) { | ||||||
|  |     return file_worker->sd_ex_api->file_select( | ||||||
|  |         file_worker->sd_ex_api->context, path, extension, result, result_size, selected_filename); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_check_common_errors(FileWorker* file_worker) { | ||||||
|  |     file_worker->sd_ex_api->check_error(file_worker->sd_ex_api->context); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void file_worker_show_error_internal(FileWorker* file_worker, const char* error_text) { | ||||||
|  |     if(!file_worker->silent) { | ||||||
|  |         file_worker_show_error(file_worker, error_text); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_read_internal(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read) { | ||||||
|  |     uint16_t read_count = | ||||||
|  |         file_worker->fs_api->file.read(&file_worker->file, buffer, bytes_to_read); | ||||||
|  | 
 | ||||||
|  |     if(file_worker->file.error_id != FSE_OK || read_count != bytes_to_read) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot read\nfile"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_write_internal( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     const void* buffer, | ||||||
|  |     uint16_t bytes_to_write) { | ||||||
|  |     uint16_t write_count = | ||||||
|  |         file_worker->fs_api->file.write(&file_worker->file, buffer, bytes_to_write); | ||||||
|  | 
 | ||||||
|  |     if(file_worker->file.error_id != FSE_OK || write_count != bytes_to_write) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot write\nto file"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_tell_internal(FileWorker* file_worker, uint64_t* position) { | ||||||
|  |     *position = file_worker->fs_api->file.tell(&file_worker->file); | ||||||
|  | 
 | ||||||
|  |     if(file_worker->file.error_id != FSE_OK) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot tell\nfile offset"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool file_worker_seek_internal(FileWorker* file_worker, uint64_t position, bool from_start) { | ||||||
|  |     file_worker->fs_api->file.seek(&file_worker->file, position, from_start); | ||||||
|  |     if(file_worker->file.error_id != FSE_OK) { | ||||||
|  |         file_worker_show_error_internal(file_worker, "Cannot seek\nfile"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
| @ -1,237 +0,0 @@ | |||||||
| #include "file-worker.h" |  | ||||||
| 
 |  | ||||||
| FileWorker::FileWorker(bool _silent) |  | ||||||
|     : fs_api{"sdcard"} |  | ||||||
|     , sd_ex_api{"sdcard-ex"} { |  | ||||||
|     silent = _silent; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| FileWorker::~FileWorker() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::open(const char* filename, FS_AccessMode access_mode, FS_OpenMode open_mode) { |  | ||||||
|     bool result = fs_api.get()->file.open(&file, filename, access_mode, open_mode); |  | ||||||
| 
 |  | ||||||
|     if(!result) { |  | ||||||
|         show_error_internal("Cannot open\nfile"); |  | ||||||
|         close(); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::close() { |  | ||||||
|     fs_api.get()->file.close(&file); |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::mkdir(const char* dirname) { |  | ||||||
|     FS_Error fs_result = fs_api.get()->common.mkdir(dirname); |  | ||||||
| 
 |  | ||||||
|     if(fs_result != FSE_OK && fs_result != FSE_EXIST) { |  | ||||||
|         show_error_internal("Cannot create\nfolder"); |  | ||||||
|         return false; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::remove(const char* filename) { |  | ||||||
|     FS_Error fs_result = fs_api.get()->common.remove(filename); |  | ||||||
|     if(fs_result != FSE_OK && fs_result != FSE_NOT_EXIST) { |  | ||||||
|         show_error_internal("Cannot remove\nold file"); |  | ||||||
|         return false; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::read(void* buffer, uint16_t bytes_to_read) { |  | ||||||
|     if(!read_internal(buffer, bytes_to_read)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::read_until(string_t str_result, char separator) { |  | ||||||
|     string_clean(str_result); |  | ||||||
|     const uint8_t buffer_size = 32; |  | ||||||
|     uint8_t buffer[buffer_size]; |  | ||||||
| 
 |  | ||||||
|     do { |  | ||||||
|         uint16_t read_count = fs_api.get()->file.read(&file, buffer, buffer_size); |  | ||||||
|         if(file.error_id != FSE_OK) { |  | ||||||
|             show_error_internal("Cannot read\nfile"); |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         bool result = false; |  | ||||||
|         for(uint16_t i = 0; i < read_count; i++) { |  | ||||||
|             if(buffer[i] == separator) { |  | ||||||
|                 uint64_t position; |  | ||||||
|                 if(!tell_internal(&position)) { |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 position = position - read_count + i + 1; |  | ||||||
| 
 |  | ||||||
|                 if(!seek_internal(position, true)) { |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 result = true; |  | ||||||
|                 break; |  | ||||||
|             } else { |  | ||||||
|                 string_push_back(str_result, buffer[i]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(result || read_count == 0) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } while(true); |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::read_hex(uint8_t* buffer, uint16_t bytes_to_read) { |  | ||||||
|     uint8_t text[2]; |  | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < bytes_to_read; i++) { |  | ||||||
|         if(i != 0) { |  | ||||||
|             // space
 |  | ||||||
|             if(!read_internal(text, 1)) { |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // actual data
 |  | ||||||
|         if(!read_internal(text, 2)) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // convert hex value to byte
 |  | ||||||
|         buffer[i] = strtol(reinterpret_cast<char*>(text), NULL, 16); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::tell(uint64_t* position) { |  | ||||||
|     if(!tell_internal(position)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::seek(uint64_t position, bool from_start) { |  | ||||||
|     if(!seek_internal(position, from_start)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::write(const void* buffer, uint16_t bytes_to_write) { |  | ||||||
|     if(!write_internal(buffer, bytes_to_write)) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::write_hex(const uint8_t* buffer, uint16_t bytes_to_write) { |  | ||||||
|     const uint8_t byte_text_size = 3; |  | ||||||
|     char byte_text[byte_text_size]; |  | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < bytes_to_write; i++) { |  | ||||||
|         sniprintf(byte_text, byte_text_size, "%02X", buffer[i]); |  | ||||||
| 
 |  | ||||||
|         if(i != 0) { |  | ||||||
|             // space
 |  | ||||||
|             const char* space = " "; |  | ||||||
|             if(!write_internal(space, 1)) { |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!write_internal(byte_text, 2)) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return check_common_errors(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void FileWorker::show_error(const char* error_text) { |  | ||||||
|     sd_ex_api.get()->show_error(sd_ex_api.get()->context, error_text); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::file_select( |  | ||||||
|     const char* path, |  | ||||||
|     const char* extension, |  | ||||||
|     char* result, |  | ||||||
|     uint8_t result_size, |  | ||||||
|     char* selected_filename) { |  | ||||||
|     return sd_ex_api.get()->file_select( |  | ||||||
|         sd_ex_api.get()->context, path, extension, result, result_size, selected_filename); |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::check_common_errors() { |  | ||||||
|     sd_ex_api.get()->check_error(sd_ex_api.get()->context); |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void FileWorker::show_error_internal(const char* error_text) { |  | ||||||
|     if(!silent) { |  | ||||||
|         show_error(error_text); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::read_internal(void* buffer, uint16_t bytes_to_read) { |  | ||||||
|     uint16_t read_count = fs_api.get()->file.read(&file, buffer, bytes_to_read); |  | ||||||
| 
 |  | ||||||
|     if(file.error_id != FSE_OK || read_count != bytes_to_read) { |  | ||||||
|         show_error_internal("Cannot read\nfile"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::write_internal(const void* buffer, uint16_t bytes_to_write) { |  | ||||||
|     uint16_t write_count = fs_api.get()->file.write(&file, buffer, bytes_to_write); |  | ||||||
| 
 |  | ||||||
|     if(file.error_id != FSE_OK || write_count != bytes_to_write) { |  | ||||||
|         show_error_internal("Cannot write\nto file"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::tell_internal(uint64_t* position) { |  | ||||||
|     *position = fs_api.get()->file.tell(&file); |  | ||||||
| 
 |  | ||||||
|     if(file.error_id != FSE_OK) { |  | ||||||
|         show_error_internal("Cannot tell\nfile offset"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool FileWorker::seek_internal(uint64_t position, bool from_start) { |  | ||||||
|     fs_api.get()->file.seek(&file, position, from_start); |  | ||||||
|     if(file.error_id != FSE_OK) { |  | ||||||
|         show_error_internal("Cannot seek\nfile"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| @ -1,127 +1,155 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "record-controller.hpp" |  | ||||||
| #include <sd-card-api.h> |  | ||||||
| #include <filesystem-api.h> |  | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
|  | #include <filesystem-api.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief File operations helper class. |  * @brief File operations helper class. | ||||||
|  * Automatically opens API records, shows error message on error. |  * Automatically opens API records, shows error message on error. | ||||||
|  */ |  */ | ||||||
| class FileWorker { | typedef struct FileWorker FileWorker; | ||||||
| public: |  | ||||||
|     FileWorker(bool silent = false); |  | ||||||
|     ~FileWorker(); |  | ||||||
| 
 | 
 | ||||||
|     RecordController<FS_Api> fs_api; | /**
 | ||||||
|     RecordController<SdCard_Api> sd_ex_api; |  * @brief Allocate FileWorker | ||||||
|  |  *  | ||||||
|  |  * @param silent do not show errors except from file_worker_show_error fn | ||||||
|  |  * @return FileWorker*  | ||||||
|  |  */ | ||||||
|  | FileWorker* file_worker_alloc(bool silent); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief free FileWorker | ||||||
|  |  *  | ||||||
|  |  * @param file_worker  | ||||||
|  |  */ | ||||||
|  | void file_worker_free(FileWorker* file_worker); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Open file |  * @brief Open file | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param filename  |  * @param filename  | ||||||
|  * @param access_mode  |  * @param access_mode  | ||||||
|  * @param open_mode  |  * @param open_mode  | ||||||
|  * @return true on success |  * @return true on success | ||||||
|  */ |  */ | ||||||
|     bool open(const char* filename, FS_AccessMode access_mode, FS_OpenMode open_mode); | bool file_worker_open( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     const char* filename, | ||||||
|  |     FS_AccessMode access_mode, | ||||||
|  |     FS_OpenMode open_mode); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Close file |  * @brief Close file | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @return true on success |  * @return true on success | ||||||
|  */ |  */ | ||||||
|     bool close(); | bool file_worker_close(FileWorker* file_worker); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Creates a directory. Doesn't show error if directory exist.  |  * @brief Creates a directory. Doesn't show error if directory exist.  | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param dirname  |  * @param dirname  | ||||||
|  * @return true on success |  * @return true on success | ||||||
|  */ |  */ | ||||||
|     bool mkdir(const char* dirname); | bool file_worker_mkdir(FileWorker* file_worker, const char* dirname); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Removes the file. Doesn't show error if file doesn't exist. |  * @brief Removes the file. Doesn't show error if file doesn't exist. | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param filename  |  * @param filename  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool remove(const char* filename); | bool file_worker_remove(FileWorker* file_worker, const char* filename); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Reads data from a file. |  * @brief Reads data from a file. | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param buffer  |  * @param buffer  | ||||||
|  * @param bytes_to_read  |  * @param bytes_to_read  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool read(void* buffer, uint16_t bytes_to_read = 1); | bool file_worker_read(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Reads data from a file until separator or EOF is found.  |  * @brief Reads data from a file until separator or EOF is found.  | ||||||
|  * Moves seek pointer to the next symbol after the separator. The separator is not included in the result. |  * Moves seek pointer to the next symbol after the separator. The separator is not included in the result. | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param result  |  * @param result  | ||||||
|  * @param separator  |  * @param separator  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool read_until(string_t result, char separator = '\n'); | bool file_worker_read_until(FileWorker* file_worker, string_t result, char separator); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Reads data in hexadecimal space-delimited format. For example "AF FF" in a file - [175, 255] in a read buffer. |  * @brief Reads data in hexadecimal space-delimited format. For example "AF FF" in a file - [175, 255] in a read buffer. | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param buffer  |  * @param buffer  | ||||||
|  * @param bytes_to_read  |  * @param bytes_to_read  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool read_hex(uint8_t* buffer, uint16_t bytes_to_read = 1); | bool file_worker_read_hex(FileWorker* file_worker, uint8_t* buffer, uint16_t bytes_to_read); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Read seek pointer value |  * @brief Read seek pointer value | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param position  |  * @param position  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool tell(uint64_t* position); | bool file_worker_tell(FileWorker* file_worker, uint64_t* position); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Set seek pointer value |  * @brief Set seek pointer value | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param position  |  * @param position  | ||||||
|  * @param from_start  |  * @param from_start  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool seek(uint64_t position, bool from_start); | bool file_worker_seek(FileWorker* file_worker, uint64_t position, bool from_start); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Write data to file. |  * @brief Write data to file. | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param buffer  |  * @param buffer  | ||||||
|  * @param bytes_to_write  |  * @param bytes_to_write  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool write(const void* buffer, uint16_t bytes_to_write = 1); | bool file_worker_write(FileWorker* file_worker, const void* buffer, uint16_t bytes_to_write); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Write data to file in hexadecimal space-delimited format. For example [175, 255] in a write buffer - "AF FF" in a file. |  * @brief Write data to file in hexadecimal space-delimited format. For example [175, 255] in a write buffer - "AF FF" in a file. | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param buffer  |  * @param buffer  | ||||||
|  * @param bytes_to_write  |  * @param bytes_to_write  | ||||||
|  * @return true on success   |  * @return true on success   | ||||||
|  */ |  */ | ||||||
|     bool write_hex(const uint8_t* buffer, uint16_t bytes_to_write = 1); | bool file_worker_write_hex(FileWorker* file_worker, const uint8_t* buffer, uint16_t bytes_to_write); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Show system file error message |  * @brief Show system file error message | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param error_text  |  * @param error_text  | ||||||
|  */ |  */ | ||||||
|     void show_error(const char* error_text); | void file_worker_show_error(FileWorker* file_worker, const char* error_text); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @brief Show system file select widget |  * @brief Show system file select widget | ||||||
|  *  |  *  | ||||||
|  |  * @param file_worker FileWorker instance  | ||||||
|  * @param path  |  * @param path  | ||||||
|  * @param extension  |  * @param extension  | ||||||
|  * @param result  |  * @param result  | ||||||
| @ -129,23 +157,14 @@ public: | |||||||
|  * @param selected_filename  |  * @param selected_filename  | ||||||
|  * @return true if file was selected |  * @return true if file was selected | ||||||
|  */ |  */ | ||||||
|     bool file_select( | bool file_worker_file_select( | ||||||
|  |     FileWorker* file_worker, | ||||||
|     const char* path, |     const char* path, | ||||||
|     const char* extension, |     const char* extension, | ||||||
|     char* result, |     char* result, | ||||||
|     uint8_t result_size, |     uint8_t result_size, | ||||||
|     char* selected_filename); |     char* selected_filename); | ||||||
| 
 | 
 | ||||||
| private: | #ifdef __cplusplus | ||||||
|     File file; | } | ||||||
|     bool silent; | #endif | ||||||
| 
 |  | ||||||
|     bool check_common_errors(); |  | ||||||
| 
 |  | ||||||
|     void show_error_internal(const char* error_text); |  | ||||||
| 
 |  | ||||||
|     bool read_internal(void* buffer, uint16_t bytes_to_read = 1); |  | ||||||
|     bool write_internal(const void* buffer, uint16_t bytes_to_write = 1); |  | ||||||
|     bool tell_internal(uint64_t* position); |  | ||||||
|     bool seek_internal(uint64_t position, bool from_start); |  | ||||||
| }; |  | ||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <forward_list> | #include <forward_list> | ||||||
| #include <initializer_list> | #include <initializer_list> | ||||||
| 
 | 
 | ||||||
| #define GENERIC_SCENE_ENUM_VALUES Uninitalized, Exit, Start | #define GENERIC_SCENE_ENUM_VALUES Exit, Start | ||||||
| #define GENERIC_EVENT_ENUM_VALUES Tick, Back | #define GENERIC_EVENT_ENUM_VALUES Tick, Back | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -54,35 +54,100 @@ public: | |||||||
|      *  |      *  | ||||||
|      * @param scene_index_list list of scene indexes to which you want to switch |      * @param scene_index_list list of scene indexes to which you want to switch | ||||||
|      */ |      */ | ||||||
|     void search_and_switch_to_previous_scene( |     bool search_and_switch_to_previous_scene( | ||||||
|         const std::initializer_list<typename TApp::SceneType>& scene_index_list) { |         const std::initializer_list<typename TApp::SceneType>& scene_index_list) { | ||||||
|         auto previous_scene_index = TApp::SceneType::Start; |         auto previous_scene_index = TApp::SceneType::Exit; | ||||||
|         bool scene_found = false; |         bool scene_found = false; | ||||||
|  |         bool result = false; | ||||||
| 
 | 
 | ||||||
|         while(!scene_found) { |         while(!scene_found) { | ||||||
|             previous_scene_index = get_previous_scene_index(); |             previous_scene_index = get_previous_scene_index(); | ||||||
|             for(const auto& element : scene_index_list) { |             for(const auto& element : scene_index_list) { | ||||||
|                 if(previous_scene_index == element) { |                 if(previous_scene_index == element) { | ||||||
|  |                     scene_found = true; | ||||||
|  |                     result = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(previous_scene_index == TApp::SceneType::Exit) { | ||||||
|                     scene_found = true; |                     scene_found = true; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if(result) { | ||||||
|             switch_to_scene(previous_scene_index, true); |             switch_to_scene(previous_scene_index, true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool search_and_switch_to_another_scene( | ||||||
|  |         const std::initializer_list<typename TApp::SceneType>& scene_index_list, | ||||||
|  |         typename TApp::SceneType scene_index) { | ||||||
|  |         auto previous_scene_index = TApp::SceneType::Exit; | ||||||
|  |         bool scene_found = false; | ||||||
|  |         bool result = false; | ||||||
|  | 
 | ||||||
|  |         while(!scene_found) { | ||||||
|  |             previous_scene_index = get_previous_scene_index(); | ||||||
|  |             for(const auto& element : scene_index_list) { | ||||||
|  |                 if(previous_scene_index == element) { | ||||||
|  |                     scene_found = true; | ||||||
|  |                     result = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(previous_scene_index == TApp::SceneType::Exit) { | ||||||
|  |                     scene_found = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(result) { | ||||||
|  |             switch_to_scene(scene_index, true); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool | ||||||
|  |     has_previous_scene(const std::initializer_list<typename TApp::SceneType>& scene_index_list) { | ||||||
|  |         bool result = false; | ||||||
|  | 
 | ||||||
|  |         for(auto const& previous_element : previous_scenes_list) { | ||||||
|  |             for(const auto& element : scene_index_list) { | ||||||
|  |                 if(previous_element == element) { | ||||||
|  |                     result = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(previous_element == TApp::SceneType::Exit) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(result) break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * @brief Start application main cycle |      * @brief Start application main cycle | ||||||
|      *  |      *  | ||||||
|      * @param tick_length_ms tick event length in milliseconds |      * @param tick_length_ms tick event length in milliseconds | ||||||
|      */ |      */ | ||||||
|     void process(uint32_t tick_length_ms = 100) { |     void process( | ||||||
|  |         uint32_t tick_length_ms = 100, | ||||||
|  |         typename TApp::SceneType start_scene_index = TApp::SceneType::Start) { | ||||||
|         typename TApp::Event event; |         typename TApp::Event event; | ||||||
|         bool consumed; |         bool consumed; | ||||||
|         bool exit = false; |         bool exit = false; | ||||||
| 
 | 
 | ||||||
|         current_scene_index = TApp::SceneType::Start; |         current_scene_index = start_scene_index; | ||||||
|         scenes[current_scene_index]->on_enter(app, false); |         scenes[current_scene_index]->on_enter(app, false); | ||||||
| 
 | 
 | ||||||
|         while(!exit) { |         while(!exit) { | ||||||
| @ -124,7 +189,7 @@ public: | |||||||
|      */ |      */ | ||||||
|     SceneController(TApp* app_pointer) { |     SceneController(TApp* app_pointer) { | ||||||
|         app = app_pointer; |         app = app_pointer; | ||||||
|         current_scene_index = TApp::SceneType::Uninitalized; |         current_scene_index = TApp::SceneType::Exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "args.h" | #include "args.h" | ||||||
|  | #include "hex.h" | ||||||
| 
 | 
 | ||||||
| size_t args_get_first_word_length(string_t args) { | size_t args_get_first_word_length(string_t args) { | ||||||
|     size_t ws = string_search_char(args, ' '); |     size_t ws = string_search_char(args, ' '); | ||||||
| @ -27,28 +28,13 @@ bool args_read_string_and_trim(string_t args, string_t word) { | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool args_char_to_hex_nibble(char c, uint8_t* nibble) { |  | ||||||
|     if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { |  | ||||||
|         if((c >= '0' && c <= '9')) { |  | ||||||
|             *nibble = c - '0'; |  | ||||||
|         } else if((c >= 'A' && c <= 'F')) { |  | ||||||
|             *nibble = c - 'A' + 10; |  | ||||||
|         } else { |  | ||||||
|             *nibble = c - 'a' + 10; |  | ||||||
|         } |  | ||||||
|         return true; |  | ||||||
|     } else { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool args_char_to_hex(char hi_nibble, char low_nibble, uint8_t* byte) { | bool args_char_to_hex(char hi_nibble, char low_nibble, uint8_t* byte) { | ||||||
|     uint8_t hi_nibble_value = 0; |     uint8_t hi_nibble_value = 0; | ||||||
|     uint8_t low_nibble_value = 0; |     uint8_t low_nibble_value = 0; | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     if(args_char_to_hex_nibble(hi_nibble, &hi_nibble_value)) { |     if(hex_char_to_hex_nibble(hi_nibble, &hi_nibble_value)) { | ||||||
|         if(args_char_to_hex_nibble(low_nibble, &low_nibble_value)) { |         if(hex_char_to_hex_nibble(low_nibble, &low_nibble_value)) { | ||||||
|             result = true; |             result = true; | ||||||
|             *byte = (hi_nibble_value << 4) | low_nibble_value; |             *byte = (hi_nibble_value << 4) | low_nibble_value; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -46,15 +46,6 @@ size_t args_get_first_word_length(string_t args); | |||||||
|  */ |  */ | ||||||
| size_t args_length(string_t args); | size_t args_length(string_t args); | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * @brief Convert ASCII hex value to nibble  |  | ||||||
|  *  |  | ||||||
|  * @param c ASCII character |  | ||||||
|  * @param nibble nibble pointer, output |  | ||||||
|  * @return bool conversion status |  | ||||||
|  */ |  | ||||||
| bool args_char_to_hex_nibble(char c, uint8_t* nibble); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * @brief Convert ASCII hex values to byte |  * @brief Convert ASCII hex values to byte | ||||||
|  *  |  *  | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								lib/args/hex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/args/hex.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | #include "hex.h" | ||||||
|  | 
 | ||||||
|  | bool hex_char_to_hex_nibble(char c, uint8_t* nibble) { | ||||||
|  |     if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { | ||||||
|  |         if((c >= '0' && c <= '9')) { | ||||||
|  |             *nibble = c - '0'; | ||||||
|  |         } else if((c >= 'A' && c <= 'F')) { | ||||||
|  |             *nibble = c - 'A' + 10; | ||||||
|  |         } else { | ||||||
|  |             *nibble = c - 'a' + 10; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								lib/args/hex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lib/args/hex.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "stdint.h" | ||||||
|  | #include "stdbool.h" | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Convert ASCII hex value to nibble  | ||||||
|  |  *  | ||||||
|  |  * @param c ASCII character | ||||||
|  |  * @param nibble nibble pointer, output | ||||||
|  |  * @return bool conversion status | ||||||
|  |  */ | ||||||
|  | bool hex_char_to_hex_nibble(char c, uint8_t* nibble); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										20
									
								
								lib/args/path.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lib/args/path.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #include "path.h" | ||||||
|  | 
 | ||||||
|  | void path_extract_filename_no_ext(const char* path, string_t filename) { | ||||||
|  |     string_set(filename, path); | ||||||
|  | 
 | ||||||
|  |     size_t start_position = string_search_rchar(filename, '/'); | ||||||
|  |     size_t end_position = string_search_rchar(filename, '.'); | ||||||
|  | 
 | ||||||
|  |     if(start_position == STRING_FAILURE) { | ||||||
|  |         start_position = 0; | ||||||
|  |     } else { | ||||||
|  |         start_position += 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(end_position == STRING_FAILURE) { | ||||||
|  |         end_position = string_size(filename); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_mid(filename, start_position, end_position - start_position); | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								lib/args/path.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/args/path.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "m-string.h" | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Extract filename without extension from path. | ||||||
|  |  *  | ||||||
|  |  * @param path path string | ||||||
|  |  * @param filename output filename string. Must be initialized before. | ||||||
|  |  */ | ||||||
|  | void path_extract_filename_no_ext(const char* path, string_t filename); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -105,5 +105,6 @@ C_SOURCES		+= $(wildcard $(LIB_DIR)/fl_subghz/*/*.c) | |||||||
| 
 | 
 | ||||||
| #scened app template lib
 | #scened app template lib
 | ||||||
| CFLAGS			+= -I$(LIB_DIR)/app-scened-template | CFLAGS			+= -I$(LIB_DIR)/app-scened-template | ||||||
|  | C_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*.c) | ||||||
| CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*.cpp) | CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*.cpp) | ||||||
| CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*/*.cpp) | CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*/*.cpp) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG