diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 74cba2d..2563217 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + submodules: 'true' - name: Build with ufbt uses: flipperdevices/flipperzero-ufbt-action@v0.1.2 id: build-app diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e691db8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "plugin"] + path = plugin + url = https://gitlab.com/bettse/flipper-wiegand-plugin.git diff --git a/application.fam b/application.fam index 985ff33..84e8c72 100644 --- a/application.fam +++ b/application.fam @@ -14,6 +14,7 @@ App( sources=[ "*.c", "aeabi_uldivmod.sx", + "!plugin/*.c", ], fap_icon="icons/logo.png", fap_category="NFC", @@ -39,3 +40,11 @@ App( fap_weburl="https://seader.ericbetts.dev", fap_icon_assets="icons", ) + +App( + appid="plugin_wiegand", + apptype=FlipperAppType.PLUGIN, + entry_point="plugin_wiegand_ep", + requires=["seader"], + sources=["plugin/wiegand.c"], +) diff --git a/plugin b/plugin new file mode 160000 index 0000000..4353973 --- /dev/null +++ b/plugin @@ -0,0 +1 @@ +Subproject commit 4353973354f4e616b7e4b2ca4bc8d4d4eb0769f3 diff --git a/scenes/seader_scene_card_menu.c b/scenes/seader_scene_card_menu.c index 7cd6c58..f10c3bd 100644 --- a/scenes/seader_scene_card_menu.c +++ b/scenes/seader_scene_card_menu.c @@ -1,6 +1,7 @@ #include "../seader_i.h" enum SubmenuIndex { + SubmenuIndexParse, SubmenuIndexSave, SubmenuIndexSavePicopass, SubmenuIndexSaveRFID, @@ -17,8 +18,21 @@ void seader_scene_card_menu_submenu_callback(void* context, uint32_t index) { void seader_scene_card_menu_on_enter(void* context) { Seader* seader = context; SeaderCredential* credential = seader->credential; + PluginWiegand* plugin = seader->plugin_wiegand; Submenu* submenu = seader->submenu; + if(plugin) { + size_t format_count = plugin->count(credential->bit_length, credential->credential); + if(format_count > 0) { + submenu_add_item( + submenu, + "Parse", + SubmenuIndexParse, + seader_scene_card_menu_submenu_callback, + seader); + } + } + submenu_add_item( submenu, "Save", SubmenuIndexSave, seader_scene_card_menu_submenu_callback, seader); submenu_add_item( @@ -85,6 +99,11 @@ bool seader_scene_card_menu_on_event(void* context, SceneManagerEvent event) { seader->credential->save_format = SeaderCredentialSaveFormatMFC; scene_manager_next_scene(seader->scene_manager, SeaderSceneSaveName); consumed = true; + } else if(event.event == SubmenuIndexParse) { + scene_manager_set_scene_state( + seader->scene_manager, SeaderSceneCardMenu, SubmenuIndexParse); + scene_manager_next_scene(seader->scene_manager, SeaderSceneFormats); + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { consumed = scene_manager_search_and_switch_to_previous_scene( diff --git a/scenes/seader_scene_config.h b/scenes/seader_scene_config.h index 58914c1..86443dc 100644 --- a/scenes/seader_scene_config.h +++ b/scenes/seader_scene_config.h @@ -15,3 +15,4 @@ ADD_SCENE(seader, delete_success, DeleteSuccess) ADD_SCENE(seader, credential_info, CredentialInfo) ADD_SCENE(seader, sam_info, SamInfo) ADD_SCENE(seader, virtual_credential, VirtualCredential) +ADD_SCENE(seader, formats, Formats) diff --git a/scenes/seader_scene_formats.c b/scenes/seader_scene_formats.c new file mode 100644 index 0000000..f79ebc7 --- /dev/null +++ b/scenes/seader_scene_formats.c @@ -0,0 +1,47 @@ +#include "../seader_i.h" +#include + +void seader_scene_formats_on_enter(void* context) { + Seader* seader = context; + PluginWiegand* plugin = seader->plugin_wiegand; + SeaderCredential* credential = seader->credential; + + FuriString* str = seader->text_box_store; + furi_string_reset(str); + + if(plugin) { + FuriString* description = furi_string_alloc(); + size_t format_count = plugin->count(credential->bit_length, credential->credential); + for(size_t i = 0; i < format_count; i++) { + plugin->description(credential->bit_length, credential->credential, i, description); + + furi_string_cat_printf(str, "%s\n", furi_string_get_cstr(description)); + } + furi_string_free(description); + } + + text_box_set_font(seader->text_box, TextBoxFontHex); + text_box_set_text(seader->text_box, furi_string_get_cstr(seader->text_box_store)); + view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewTextBox); +} + +bool seader_scene_formats_on_event(void* context, SceneManagerEvent event) { + Seader* seader = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(seader->scene_manager); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(seader->scene_manager); + } + return consumed; +} + +void seader_scene_formats_on_exit(void* context) { + Seader* seader = context; + + // Clear views + text_box_reset(seader->text_box); +} diff --git a/seader.c b/seader.c index 3451fa1..4cbd777 100644 --- a/seader.c +++ b/seader.c @@ -80,11 +80,38 @@ Seader* seader_alloc() { view_dispatcher_add_view( seader->view_dispatcher, SeaderViewTextInput, text_input_get_view(seader->text_input)); + // TextBox + seader->text_box = text_box_alloc(); + view_dispatcher_add_view( + seader->view_dispatcher, SeaderViewTextBox, text_box_get_view(seader->text_box)); + seader->text_box_store = furi_string_alloc(); + // Custom Widget seader->widget = widget_alloc(); view_dispatcher_add_view( seader->view_dispatcher, SeaderViewWidget, widget_get_view(seader->widget)); + seader->plugin_manager = + plugin_manager_alloc(PLUGIN_APP_ID, PLUGIN_API_VERSION, firmware_api_interface); + + seader->plugin_wiegand = NULL; + if(plugin_manager_load_all(seader->plugin_manager, APP_DATA_PATH("plugins")) != + PluginManagerErrorNone) { + FURI_LOG_E(TAG, "Failed to load all libs"); + } else { + uint32_t plugin_count = plugin_manager_get_count(seader->plugin_manager); + FURI_LOG_I(TAG, "Loaded %lu plugin(s)", plugin_count); + + for(uint32_t i = 0; i < plugin_count; i++) { + const PluginWiegand* plugin = plugin_manager_get_ep(seader->plugin_manager, i); + FURI_LOG_I(TAG, "plugin name: %s", plugin->name); + if(strcmp(plugin->name, "Plugin Wiegand") == 0) { + // Have to cast to drop "const" qualifier + seader->plugin_wiegand = (PluginWiegand*)plugin; + } + } + } + return seader; } @@ -122,6 +149,11 @@ void seader_free(Seader* seader) { view_dispatcher_remove_view(seader->view_dispatcher, SeaderViewTextInput); text_input_free(seader->text_input); + // TextBox + view_dispatcher_remove_view(seader->view_dispatcher, SeaderViewTextBox); + text_box_free(seader->text_box); + furi_string_free(seader->text_box_store); + // Custom Widget view_dispatcher_remove_view(seader->view_dispatcher, SeaderViewWidget); widget_free(seader->widget); @@ -144,6 +176,8 @@ void seader_free(Seader* seader) { furi_record_close(RECORD_NOTIFICATION); seader->notifications = NULL; + plugin_manager_free(seader->plugin_manager); + free(seader); } diff --git a/seader_i.h b/seader_i.h index bf8b762..2cd5b80 100644 --- a/seader_i.h +++ b/seader_i.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,11 @@ #include #include +#include "plugin/interface.h" +#include +#include +#include + #include "protocol/picopass_poller.h" #include "scenes/seader_scene.h" @@ -103,6 +109,7 @@ struct Seader { Popup* popup; Loading* loading; TextInput* text_input; + TextBox* text_box; Widget* widget; Nfc* nfc; @@ -110,6 +117,9 @@ struct Seader { PicopassPoller* picopass_poller; NfcDevice* nfc_device; + + PluginManager* plugin_manager; + PluginWiegand* plugin_wiegand; }; struct SeaderPollerContainer { @@ -122,6 +132,7 @@ typedef enum { SeaderViewPopup, SeaderViewLoading, SeaderViewTextInput, + SeaderViewTextBox, SeaderViewWidget, SeaderViewUart, } SeaderView;