diff --git a/applications/ibutton/ibutton-app.cpp b/applications/ibutton/ibutton-app.cpp old mode 100755 new mode 100644 index 111ac31b..cf29d884 --- a/applications/ibutton/ibutton-app.cpp +++ b/applications/ibutton/ibutton-app.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include const char* iButtonApp::app_folder = "ibutton"; const char* iButtonApp::app_extension = ".ibtn"; @@ -217,7 +217,7 @@ void iButtonApp::generate_random_name(char* name, uint8_t max_name_size) { // file managment bool iButtonApp::save_key(const char* key_name) { - FileWorker file_worker; + FileWorkerCpp file_worker; string_t key_file_name; bool result = false; @@ -274,7 +274,7 @@ bool iButtonApp::save_key(const char* key_name) { } bool iButtonApp::load_key_data(string_t key_path) { - FileWorker file_worker; + FileWorkerCpp file_worker; // Open key file 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 result = false; - FileWorker file_worker; + FileWorkerCpp file_worker; // Input events and views are managed by file_select bool res = file_worker.file_select( @@ -369,7 +369,7 @@ bool iButtonApp::load_key() { bool iButtonApp::delete_key() { string_t file_name; 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); result = file_worker.remove(string_get_cstr(file_name)); diff --git a/applications/lfrfid/helpers/key-info.cpp b/applications/lfrfid/helpers/key-info.cpp index c6feac81..a6da4af2 100644 --- a/applications/lfrfid/helpers/key-info.cpp +++ b/applications/lfrfid/helpers/key-info.cpp @@ -1,4 +1,5 @@ #include "key-info.h" +#include const char* lfrfid_key_get_type_string(LfrfidKeyType type) { switch(type) { @@ -16,6 +17,22 @@ const char* lfrfid_key_get_type_string(LfrfidKeyType type) { 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) { switch(type) { case LfrfidKeyType::KeyEM4100: diff --git a/applications/lfrfid/helpers/key-info.h b/applications/lfrfid/helpers/key-info.h index 7d376d72..b069f98c 100644 --- a/applications/lfrfid/helpers/key-info.h +++ b/applications/lfrfid/helpers/key-info.h @@ -11,4 +11,5 @@ enum class LfrfidKeyType : uint8_t { }; 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); \ No newline at end of file diff --git a/applications/lfrfid/helpers/rfid-key.cpp b/applications/lfrfid/helpers/rfid-key.cpp index 948f58db..8e3e3db6 100644 --- a/applications/lfrfid/helpers/rfid-key.cpp +++ b/applications/lfrfid/helpers/rfid-key.cpp @@ -1,12 +1,9 @@ #include "rfid-key.h" #include +#include RfidKey::RfidKey() { - data.fill(0); - - for(uint8_t i = 0; i < (LFRFID_KEY_NAME_SIZE + 1); i++) { - name[i] = 0; - } + clear(); } RfidKey::~RfidKey() { @@ -16,18 +13,22 @@ void RfidKey::set_type(LfrfidKeyType _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()); for(uint8_t i = 0; i < _data_size; i++) { data[i] = _data[i]; } } +void RfidKey::set_name(const char* _name) { + strlcpy(name, _name, get_name_length()); +} + LfrfidKeyType RfidKey::get_type() { return type; } -uint8_t* RfidKey::get_data() { +const uint8_t* RfidKey::get_data() { return &data[0]; } @@ -42,3 +43,23 @@ const uint8_t RfidKey::get_type_data_count() { char* RfidKey::get_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; +} diff --git a/applications/lfrfid/helpers/rfid-key.h b/applications/lfrfid/helpers/rfid-key.h index c0510911..779ca479 100644 --- a/applications/lfrfid/helpers/rfid-key.h +++ b/applications/lfrfid/helpers/rfid-key.h @@ -8,15 +8,17 @@ public: ~RfidKey(); 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(); - uint8_t* get_data(); - + const uint8_t* get_data(); const char* get_type_text(); const uint8_t get_type_data_count(); - char* get_name(); + uint8_t get_name_length(); + void clear(); + RfidKey& operator=(const RfidKey& rhs); private: std::array data; diff --git a/applications/lfrfid/helpers/rfid-writer.cpp b/applications/lfrfid/helpers/rfid-writer.cpp index 16155921..f9a6ad68 100644 --- a/applications/lfrfid/helpers/rfid-writer.cpp +++ b/applications/lfrfid/helpers/rfid-writer.cpp @@ -111,7 +111,7 @@ void RfidWriter::write_reset() { 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; uint64_t em_encoded_data; em_card.encode(em_data, 5, reinterpret_cast(&em_encoded_data), sizeof(uint64_t)); @@ -125,7 +125,7 @@ void RfidWriter::write_em(uint8_t em_data[5]) { __enable_irq(); } -void RfidWriter::write_hid(uint8_t hid_data[3]) { +void RfidWriter::write_hid(const uint8_t hid_data[3]) { ProtocolHID10301 hid_card; uint32_t card_data[3]; hid_card.encode(hid_data, 3, reinterpret_cast(&card_data), sizeof(card_data) * 3); diff --git a/applications/lfrfid/helpers/rfid-writer.h b/applications/lfrfid/helpers/rfid-writer.h index ec982a38..cfbc1c5d 100644 --- a/applications/lfrfid/helpers/rfid-writer.h +++ b/applications/lfrfid/helpers/rfid-writer.h @@ -7,8 +7,8 @@ public: ~RfidWriter(); void start(); void stop(); - void write_em(uint8_t em_data[5]); - void write_hid(uint8_t hid_data[3]); + void write_em(const uint8_t em_data[5]); + void write_hid(const uint8_t hid_data[3]); private: void write_gap(uint32_t gap_time); diff --git a/applications/lfrfid/lfrfid-app-launcher.cpp b/applications/lfrfid/lfrfid-app-launcher.cpp index afdb8b5d..2d0e6725 100644 --- a/applications/lfrfid/lfrfid-app-launcher.cpp +++ b/applications/lfrfid/lfrfid-app-launcher.cpp @@ -1,9 +1,9 @@ #include "lfrfid-app.h" // app enter function -extern "C" int32_t lfrfid_app(void* p) { +extern "C" int32_t lfrfid_app(void* args) { LfRfidApp* app = new LfRfidApp(); - app->run(); + app->run(args); delete app; return 0; diff --git a/applications/lfrfid/lfrfid-app.cpp b/applications/lfrfid/lfrfid-app.cpp index d7a89e52..8fd0354e 100644 --- a/applications/lfrfid/lfrfid-app.cpp +++ b/applications/lfrfid/lfrfid-app.cpp @@ -7,6 +7,20 @@ #include "scene/lfrfid-app-scene-write-success.h" #include "scene/lfrfid-app-scene-emulate.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 +#include + +const char* LfRfidApp::app_folder = "lfrfid"; +const char* LfRfidApp::app_extension = ".rfid"; LfRfidApp::LfRfidApp() : scene_controller{this} @@ -24,14 +38,156 @@ LfRfidApp::~LfRfidApp() { api_hal_power_insomnia_exit(); } -void LfRfidApp::run() { - scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); - scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); - scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); - scene_controller.add_scene(SceneType::ReadedMenu, new LfRfidAppSceneReadedMenu()); - scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite()); - scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); - scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); - scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName()); - scene_controller.process(100); +void LfRfidApp::run(void* _args) { + const char* args = reinterpret_cast(_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::Read, new LfRfidAppSceneRead()); + scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); + scene_controller.add_scene(SceneType::ReadedMenu, new LfRfidAppSceneReadedMenu()); + scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite()); + scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); + scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); + 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); + } +} + +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); } \ No newline at end of file diff --git a/applications/lfrfid/lfrfid-app.h b/applications/lfrfid/lfrfid-app.h index f2c66fef..823c81ff 100644 --- a/applications/lfrfid/lfrfid-app.h +++ b/applications/lfrfid/lfrfid-app.h @@ -38,6 +38,14 @@ public: WriteSuccess, Emulate, SaveName, + SaveSuccess, + SelectKey, + SavedKeyMenu, + SaveData, + SaveType, + SavedInfo, + DeleteConfirm, + DeleteSuccess, }; class Event { @@ -63,5 +71,18 @@ public: RfidWorker worker; 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(); }; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.cpp b/applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.cpp new file mode 100644 index 00000000..64ebbeb5 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.cpp @@ -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(); + + auto button = container->add(); + button->set_type(ButtonElement::Type::Left, "Back"); + button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback); + + button = container->add(); + button->set_type(ButtonElement::Type::Right, "Delete"); + button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback); + + auto line_1 = container->add(); + auto line_2 = container->add(); + auto line_3 = container->add(); + auto line_4 = container->add(); + + 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(); +} + +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()->clean(); + string_clear(string_data); + string_clear(string_decrypted); + string_clear(string_header); +} + +void LfRfidAppSceneDeleteConfirm::back_callback(void* context) { + LfRfidApp* app = static_cast(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(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Next; + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.h b/applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.h new file mode 100644 index 00000000..1771e5dc --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-delete-confirm.h @@ -0,0 +1,17 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneDeleteConfirm : public GenericScene { +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; +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-delete-success.cpp b/applications/lfrfid/scene/lfrfid-app-scene-delete-success.cpp new file mode 100644 index 00000000..c494d96c --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-delete-success.cpp @@ -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(); + + 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(); +} + +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()->clean(); +} + +void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Back; + app->view_controller.send_event(&event); +} \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-delete-success.h b/applications/lfrfid/scene/lfrfid-app-scene-delete-success.h new file mode 100644 index 00000000..dff00f0f --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-delete-success.h @@ -0,0 +1,12 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneDeleteSuccess : public GenericScene { +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); +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-emulate.cpp b/applications/lfrfid/scene/lfrfid-app-scene-emulate.cpp index b8e49915..bb33a655 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-emulate.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-emulate.cpp @@ -3,7 +3,7 @@ void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool need_restore) { 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++) { 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(); - popup->set_header("Emulating", 90, 34, AlignCenter, AlignTop); - popup->set_text(string_get_cstr(data_string), 90, 48, AlignCenter, AlignTop); + popup->set_header("LF emulating", 89, 30, 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); app->view_controller.switch_to(); diff --git a/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp b/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp index b339cbd2..02158de0 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp @@ -32,7 +32,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { auto line_2_value = container->add(); auto line_3_value = container->add(); - uint8_t* data = app->worker.key.get_data(); + const uint8_t* data = app->worker.key.get_data(); switch(app->worker.key.get_type()) { case LfrfidKeyType::KeyEM4100: diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-data.cpp b/applications/lfrfid/scene/lfrfid-app-scene-save-data.cpp new file mode 100644 index 00000000..947287f6 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-data.cpp @@ -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(); + 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(); +} + +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()->clean(); +} + +void LfRfidAppSceneSaveData::save_callback(void* context, uint8_t* bytes, uint8_t bytes_count) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Next; + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-data.h b/applications/lfrfid/scene/lfrfid-app-scene-save-data.h new file mode 100644 index 00000000..3ea758f3 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-data.h @@ -0,0 +1,33 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneSaveData : public GenericScene { +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, + }; +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-name.cpp b/applications/lfrfid/scene/lfrfid-app-scene-save-name.cpp index 1a5122c2..f751f061 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-save-name.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-name.cpp @@ -14,7 +14,7 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) { text_input->set_header_text("Name the card"); 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(); } @@ -23,14 +23,18 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool consumed = false; if(event->type == LfRfidApp::EventType::Next) { - /*if(app->save_key(app->get_text_store())) { - app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess); + if(strlen(app->worker.key.get_name())) { + 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 { - app->search_and_switch_to_previous_scene( - {iButtonApp::Scene::SceneReadedKeyMenu, - iButtonApp::Scene::SceneSavedKeyMenu, - iButtonApp::Scene::SceneAddType}); - }*/ + app->scene_controller.search_and_switch_to_previous_scene( + {LfRfidApp::SceneType::ReadedMenu}); + } } return consumed; diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-success.cpp b/applications/lfrfid/scene/lfrfid-app-scene-save-success.cpp new file mode 100644 index 00000000..32a1193d --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-success.cpp @@ -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(); + + 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(); +} + +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()->clean(); +} + +void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Back; + app->view_controller.send_event(&event); +} \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-success.h b/applications/lfrfid/scene/lfrfid-app-scene-save-success.h new file mode 100644 index 00000000..e0635ba6 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-success.h @@ -0,0 +1,12 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneSaveSuccess : public GenericScene { +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); +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-type.cpp b/applications/lfrfid/scene/lfrfid-app-scene-save-type.cpp new file mode 100644 index 00000000..bba5e94f --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-type.cpp @@ -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(); + + for(uint8_t i = 0; i <= static_cast(LfrfidKeyType::KeyI40134); i++) { + submenu->add_item( + lfrfid_key_get_type_string(static_cast(i)), i, submenu_callback, app); + } + + if(need_restore) { + submenu->set_selected_item(submenu_item_selected); + } + + app->view_controller.switch_to(); + + // 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(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()->clean(); +} + +void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + + event.type = LfRfidApp::EventType::MenuSelected; + event.payload.menu_index = index; + + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid-app-scene-save-type.h b/applications/lfrfid/scene/lfrfid-app-scene-save-type.h new file mode 100644 index 00000000..0fbf5239 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-save-type.h @@ -0,0 +1,13 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneSaveType : public GenericScene { +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; +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-saved-info.cpp b/applications/lfrfid/scene/lfrfid-app-scene-saved-info.cpp new file mode 100644 index 00000000..68180f98 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-saved-info.cpp @@ -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(); + + auto button = container->add(); + button->set_type(ButtonElement::Type::Left, "Back"); + button->set_callback(app, LfRfidAppSceneSavedInfo::back_callback); + + auto line_1 = container->add(); + auto line_2 = container->add(); + auto line_3 = container->add(); + auto line_4 = container->add(); + + 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(); +} + +bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) { + bool consumed = false; + + return consumed; +} + +void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { + app->view_controller.get()->clean(); + string_clear(string_data); + string_clear(string_decrypted); +} + +void LfRfidAppSceneSavedInfo::back_callback(void* context) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + event.type = LfRfidApp::EventType::Back; + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid-app-scene-saved-info.h b/applications/lfrfid/scene/lfrfid-app-scene-saved-info.h new file mode 100644 index 00000000..129ab9ee --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-saved-info.h @@ -0,0 +1,15 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneSavedInfo : public GenericScene { +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; +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.cpp b/applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.cpp new file mode 100644 index 00000000..4c7bc15d --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.cpp @@ -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(); + + 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(); +} + +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()->clean(); +} + +void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { + LfRfidApp* app = static_cast(context); + LfRfidApp::Event event; + + event.type = LfRfidApp::EventType::MenuSelected; + event.payload.menu_index = index; + + app->view_controller.send_event(&event); +} diff --git a/applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.h b/applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.h new file mode 100644 index 00000000..2891034c --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-saved-key-menu.h @@ -0,0 +1,13 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneSavedKeyMenu : public GenericScene { +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; +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-select-key.cpp b/applications/lfrfid/scene/lfrfid-app-scene-select-key.cpp new file mode 100644 index 00000000..83f7c497 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-select-key.cpp @@ -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) { +} \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-select-key.h b/applications/lfrfid/scene/lfrfid-app-scene-select-key.h new file mode 100644 index 00000000..a404b3c8 --- /dev/null +++ b/applications/lfrfid/scene/lfrfid-app-scene-select-key.h @@ -0,0 +1,9 @@ +#pragma once +#include "../lfrfid-app.h" + +class LfRfidAppSceneSelectKey : public GenericScene { +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; +}; \ No newline at end of file diff --git a/applications/lfrfid/scene/lfrfid-app-scene-start.cpp b/applications/lfrfid/scene/lfrfid-app-scene-start.cpp index 7446a63c..40b4e73c 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-start.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-start.cpp @@ -16,7 +16,11 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { if(need_restore) { submenu->set_selected_item(submenu_item_selected); } + app->view_controller.switch_to(); + + // clear key + app->worker.key.clear(); } 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); break; case SubmenuSaved: + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SelectKey); break; case SubmenuAddManually: + app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType); break; } consumed = true; diff --git a/applications/lfrfid/scene/lfrfid-app-scene-write.cpp b/applications/lfrfid/scene/lfrfid-app-scene-write.cpp index 607e8565..2e485044 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-write.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-write.cpp @@ -4,7 +4,7 @@ void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool need_restore) { card_not_supported = false; 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++) { 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(); - popup->set_header("Writing", 90, 34, AlignCenter, AlignTop); - popup->set_text(string_get_cstr(data_string), 90, 48, AlignCenter, AlignTop); + popup->set_header("LF writing", 89, 30, 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); app->view_controller.switch_to(); diff --git a/lib/app-scened-template/file-worker-cpp.cpp b/lib/app-scened-template/file-worker-cpp.cpp new file mode 100644 index 00000000..22912002 --- /dev/null +++ b/lib/app-scened-template/file-worker-cpp.cpp @@ -0,0 +1,68 @@ +#include "file-worker-cpp.h" +#include + +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); +} \ No newline at end of file diff --git a/lib/app-scened-template/file-worker-cpp.h b/lib/app-scened-template/file-worker-cpp.h new file mode 100644 index 00000000..b7a6f7e0 --- /dev/null +++ b/lib/app-scened-template/file-worker-cpp.h @@ -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; +}; diff --git a/lib/app-scened-template/file-worker.c b/lib/app-scened-template/file-worker.c new file mode 100644 index 00000000..c85f751a --- /dev/null +++ b/lib/app-scened-template/file-worker.c @@ -0,0 +1,280 @@ +#include "file-worker.h" +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/lib/app-scened-template/file-worker.cpp b/lib/app-scened-template/file-worker.cpp deleted file mode 100644 index 9873d3ad..00000000 --- a/lib/app-scened-template/file-worker.cpp +++ /dev/null @@ -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(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; -} \ No newline at end of file diff --git a/lib/app-scened-template/file-worker.h b/lib/app-scened-template/file-worker.h index 73de3c05..4831743b 100644 --- a/lib/app-scened-template/file-worker.h +++ b/lib/app-scened-template/file-worker.h @@ -1,151 +1,170 @@ #pragma once -#include "record-controller.hpp" -#include -#include #include +#include + +#ifdef __cplusplus +extern "C" { +#endif /** * @brief File operations helper class. * Automatically opens API records, shows error message on error. */ -class FileWorker { -public: - FileWorker(bool silent = false); - ~FileWorker(); +typedef struct FileWorker FileWorker; - RecordController fs_api; - RecordController 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 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 free FileWorker + * + * @param file_worker + */ +void file_worker_free(FileWorker* file_worker); - /** - * @brief Close file - * - * @return true on success - */ - bool close(); +/** + * @brief Open file + * + * @param file_worker FileWorker instance + * @param filename + * @param access_mode + * @param open_mode + * @return true on success + */ +bool file_worker_open( + FileWorker* file_worker, + const char* filename, + FS_AccessMode access_mode, + FS_OpenMode open_mode); - /** - * @brief Creates a directory. Doesn't show error if directory exist. - * - * @param dirname - * @return true on success - */ - bool mkdir(const char* dirname); +/** + * @brief Close file + * + * @param file_worker FileWorker instance + * @return true on success + */ +bool file_worker_close(FileWorker* file_worker); - /** - * @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 Creates a directory. Doesn't show error if directory exist. + * + * @param file_worker FileWorker instance + * @param dirname + * @return true on success + */ +bool file_worker_mkdir(FileWorker* file_worker, const char* dirname); - /** - * @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 Removes the file. Doesn't show error if file doesn't exist. + * + * @param file_worker FileWorker instance + * @param filename + * @return true on success + */ +bool file_worker_remove(FileWorker* file_worker, const char* filename); - /** - * @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 from a file. + * + * @param file_worker FileWorker instance + * @param buffer + * @param bytes_to_read + * @return true on success + */ +bool file_worker_read(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read); - /** - * @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 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 file_worker FileWorker instance + * @param result + * @param separator + * @return true on success + */ +bool file_worker_read_until(FileWorker* file_worker, string_t result, char separator); - /** - * @brief Read seek pointer value - * - * @param position - * @return true on success - */ - bool tell(uint64_t* position); +/** + * @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 bytes_to_read + * @return true on success + */ +bool file_worker_read_hex(FileWorker* file_worker, uint8_t* buffer, uint16_t bytes_to_read); - /** - * @brief Set seek pointer value - * - * @param position - * @param from_start - * @return true on success - */ - bool seek(uint64_t position, bool from_start); +/** + * @brief Read seek pointer value + * + * @param file_worker FileWorker instance + * @param position + * @return true on success + */ +bool file_worker_tell(FileWorker* file_worker, uint64_t* position); - /** - * @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 Set seek pointer value + * + * @param file_worker FileWorker instance + * @param position + * @param from_start + * @return true on success + */ +bool file_worker_seek(FileWorker* file_worker, uint64_t position, bool from_start); - /** - * @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 Write data to file. + * + * @param file_worker FileWorker instance + * @param buffer + * @param bytes_to_write + * @return true on success + */ +bool file_worker_write(FileWorker* file_worker, const void* buffer, uint16_t bytes_to_write); - /** - * @brief Show system file error message - * - * @param error_text - */ - void show_error(const char* error_text); +/** + * @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 bytes_to_write + * @return true on success + */ +bool file_worker_write_hex(FileWorker* file_worker, const uint8_t* buffer, uint16_t bytes_to_write); - /** - * @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); +/** + * @brief Show system file error message + * + * @param file_worker FileWorker instance + * @param error_text + */ +void file_worker_show_error(FileWorker* file_worker, const char* error_text); -private: - File file; - bool silent; +/** + * @brief Show system file select widget + * + * @param file_worker FileWorker instance + * @param path + * @param extension + * @param result + * @param result_size + * @param selected_filename + * @return true if file was selected + */ +bool file_worker_file_select( + FileWorker* file_worker, + const char* path, + const char* extension, + char* result, + uint8_t result_size, + char* selected_filename); - 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); -}; +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/app-scened-template/scene-controller.hpp b/lib/app-scened-template/scene-controller.hpp index 362edbe9..9784daff 100644 --- a/lib/app-scened-template/scene-controller.hpp +++ b/lib/app-scened-template/scene-controller.hpp @@ -2,7 +2,7 @@ #include #include -#define GENERIC_SCENE_ENUM_VALUES Uninitalized, Exit, Start +#define GENERIC_SCENE_ENUM_VALUES Exit, Start #define GENERIC_EVENT_ENUM_VALUES Tick, Back /** @@ -54,22 +54,85 @@ public: * * @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& scene_index_list) { - auto previous_scene_index = TApp::SceneType::Start; + 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; } } } - switch_to_scene(previous_scene_index, true); + if(result) { + switch_to_scene(previous_scene_index, true); + } + + return result; + } + + bool search_and_switch_to_another_scene( + const std::initializer_list& 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& 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; } /** @@ -77,12 +140,14 @@ public: * * @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; bool consumed; bool exit = false; - current_scene_index = TApp::SceneType::Start; + current_scene_index = start_scene_index; scenes[current_scene_index]->on_enter(app, false); while(!exit) { @@ -124,7 +189,7 @@ public: */ SceneController(TApp* app_pointer) { app = app_pointer; - current_scene_index = TApp::SceneType::Uninitalized; + current_scene_index = TApp::SceneType::Exit; } /** diff --git a/lib/args/args.c b/lib/args/args.c index 59344a08..462d23f4 100644 --- a/lib/args/args.c +++ b/lib/args/args.c @@ -1,4 +1,5 @@ #include "args.h" +#include "hex.h" size_t args_get_first_word_length(string_t 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; } -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) { uint8_t hi_nibble_value = 0; uint8_t low_nibble_value = 0; bool result = false; - if(args_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(hi_nibble, &hi_nibble_value)) { + if(hex_char_to_hex_nibble(low_nibble, &low_nibble_value)) { result = true; *byte = (hi_nibble_value << 4) | low_nibble_value; } diff --git a/lib/args/args.h b/lib/args/args.h index 699e2faa..0e701ac2 100644 --- a/lib/args/args.h +++ b/lib/args/args.h @@ -46,15 +46,6 @@ size_t args_get_first_word_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 * diff --git a/lib/args/hex.c b/lib/args/hex.c new file mode 100644 index 00000000..cc869beb --- /dev/null +++ b/lib/args/hex.c @@ -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; + } +} \ No newline at end of file diff --git a/lib/args/hex.h b/lib/args/hex.h new file mode 100644 index 00000000..2c5d8404 --- /dev/null +++ b/lib/args/hex.h @@ -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 \ No newline at end of file diff --git a/lib/args/path.c b/lib/args/path.c new file mode 100644 index 00000000..07318801 --- /dev/null +++ b/lib/args/path.c @@ -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); +} diff --git a/lib/args/path.h b/lib/args/path.h new file mode 100644 index 00000000..fbcf6349 --- /dev/null +++ b/lib/args/path.h @@ -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 \ No newline at end of file diff --git a/lib/lib.mk b/lib/lib.mk index 58cb1741..687e82db 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -105,5 +105,6 @@ C_SOURCES += $(wildcard $(LIB_DIR)/fl_subghz/*/*.c) #scened app template lib 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) \ No newline at end of file