From 6bbd7d560c10f526e938d1bd6c81b0c0098ead62 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 13 Apr 2024 20:12:13 -0700 Subject: [PATCH 01/11] Builds --- application.fam | 9 +++++++++ plugin_interface.h | 19 +++++++++++++++++++ plugin_wiegand.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 plugin_interface.h create mode 100644 plugin_wiegand.c diff --git a/application.fam b/application.fam index 985ff33..d7c6eda 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_interface.h b/plugin_interface.h new file mode 100644 index 0000000..0e5ca51 --- /dev/null +++ b/plugin_interface.h @@ -0,0 +1,19 @@ +/** + * @file plugin_interface.h + * @brief Example plugin interface. + * + * Common interface between a plugin and host application + */ +#pragma once + +#include +#include + +#define PLUGIN_APP_ID "plugin_wiegand" +#define PLUGIN_API_VERSION 1 + +typedef struct { + const char* name; + int (*count)(uint8_t, uint64_t); + int (*description)(uint8_t, uint64_t, size_t); +} PluginWiegand; diff --git a/plugin_wiegand.c b/plugin_wiegand.c new file mode 100644 index 0000000..69e271f --- /dev/null +++ b/plugin_wiegand.c @@ -0,0 +1,37 @@ + +#include "plugin_interface.h" + +#include + +static int wiegand_format_count(uint8_t bit_length, uint64_t bits) { + UNUSED(bit_length); + UNUSED(bits); + return 1337; +} + +static int wiegand_format_description(uint8_t bit_length, uint64_t bits, size_t index) { + UNUSED(bit_length); + UNUSED(bits); + UNUSED(index); + + return 0; +} + +/* Actual implementation of app<>plugin interface */ +static const PluginWiegand plugin_wiegand = { + .name = "Plugin Wiegand", + .count = &wiegand_format_count, + .description = &wiegand_format_description, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor plugin_wiegand_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &plugin_wiegand, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* plugin_wiegand_ep(void) { + return &plugin_wiegand_descriptor; +} From 0802b594ce62e5f689781b9ea8a3928613ecd536 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 13 Apr 2024 20:21:32 -0700 Subject: [PATCH 02/11] loads plugin --- seader.c | 13 +++++++++++++ seader_i.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/seader.c b/seader.c index 3451fa1..ce220a1 100644 --- a/seader.c +++ b/seader.c @@ -85,6 +85,17 @@ Seader* seader_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); + + 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); + } + return seader; } @@ -144,6 +155,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..1108664 100644 --- a/seader_i.h +++ b/seader_i.h @@ -40,6 +40,11 @@ #include #include +#include "plugin_interface.h" +#include +#include +#include + #include "protocol/picopass_poller.h" #include "scenes/seader_scene.h" @@ -110,6 +115,8 @@ struct Seader { PicopassPoller* picopass_poller; NfcDevice* nfc_device; + + PluginManager* plugin_manager; }; struct SeaderPollerContainer { From 8b3fb5881721c3ef71864919241241da4f30644a Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 13 Apr 2024 21:25:11 -0700 Subject: [PATCH 03/11] Add textbox --- seader.c | 11 +++++++++++ seader_i.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/seader.c b/seader.c index ce220a1..1b4f5a8 100644 --- a/seader.c +++ b/seader.c @@ -80,6 +80,12 @@ 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( @@ -133,6 +139,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); diff --git a/seader_i.h b/seader_i.h index 1108664..19248b1 100644 --- a/seader_i.h +++ b/seader_i.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -108,6 +109,7 @@ struct Seader { Popup* popup; Loading* loading; TextInput* text_input; + TextBox* text_box; Widget* widget; Nfc* nfc; @@ -117,6 +119,7 @@ struct Seader { NfcDevice* nfc_device; PluginManager* plugin_manager; + PluginWiegand* plugin_wiegand; }; struct SeaderPollerContainer { @@ -129,6 +132,7 @@ typedef enum { SeaderViewPopup, SeaderViewLoading, SeaderViewTextInput, + SeaderViewTextBox, SeaderViewWidget, SeaderViewUart, } SeaderView; From 93cd7eab04b6d249eace22d838438c412a4189ea Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 13 Apr 2024 21:32:35 -0700 Subject: [PATCH 04/11] scene to show parsed formats --- plugin_interface.h | 3 ++- plugin_wiegand.c | 11 +++++--- scenes/seader_scene_card_menu.c | 19 +++++++++++++ scenes/seader_scene_config.h | 1 + scenes/seader_scene_formats.c | 47 +++++++++++++++++++++++++++++++++ seader.c | 10 +++++++ 6 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 scenes/seader_scene_formats.c diff --git a/plugin_interface.h b/plugin_interface.h index 0e5ca51..714b245 100644 --- a/plugin_interface.h +++ b/plugin_interface.h @@ -8,6 +8,7 @@ #include #include +#include #define PLUGIN_APP_ID "plugin_wiegand" #define PLUGIN_API_VERSION 1 @@ -15,5 +16,5 @@ typedef struct { const char* name; int (*count)(uint8_t, uint64_t); - int (*description)(uint8_t, uint64_t, size_t); + void (*description)(uint8_t, uint64_t, size_t, FuriString*); } PluginWiegand; diff --git a/plugin_wiegand.c b/plugin_wiegand.c index 69e271f..6e2b86d 100644 --- a/plugin_wiegand.c +++ b/plugin_wiegand.c @@ -6,15 +6,18 @@ static int wiegand_format_count(uint8_t bit_length, uint64_t bits) { UNUSED(bit_length); UNUSED(bits); - return 1337; + return 0; } -static int wiegand_format_description(uint8_t bit_length, uint64_t bits, size_t index) { +static void wiegand_format_description( + uint8_t bit_length, + uint64_t bits, + size_t index, + FuriString* description) { UNUSED(bit_length); UNUSED(bits); UNUSED(index); - - return 0; + UNUSED(description); } /* Actual implementation of app<>plugin interface */ diff --git a/scenes/seader_scene_card_menu.c b/scenes/seader_scene_card_menu.c index 7cd6c58..813a47a 100644 --- a/scenes/seader_scene_card_menu.c +++ b/scenes/seader_scene_card_menu.c @@ -6,6 +6,7 @@ enum SubmenuIndex { SubmenuIndexSaveRFID, SubmenuIndexSaveSR, SubmenuIndexSaveMFC, + SubmenuIndexParse, }; void seader_scene_card_menu_submenu_callback(void* context, uint32_t index) { @@ -17,6 +18,7 @@ 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; submenu_add_item( @@ -44,6 +46,18 @@ void seader_scene_card_menu_on_enter(void* context) { submenu_add_item( submenu, "Save MFC", SubmenuIndexSaveMFC, seader_scene_card_menu_submenu_callback, seader); + 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_set_selected_item( seader->submenu, scene_manager_get_scene_state(seader->scene_manager, SeaderSceneCardMenu)); @@ -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 1b4f5a8..eb9010e 100644 --- a/seader.c +++ b/seader.c @@ -94,12 +94,22 @@ Seader* seader_alloc() { 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_APP_ID) == 0) { + // Have to cast to drop "const" qualifier + seader->plugin_wiegand = (PluginWiegand*)plugin; + } + } } return seader; From f736e8d085ebb843ffd5207c9bc608eeb4524145 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 13 Apr 2024 21:51:25 -0700 Subject: [PATCH 05/11] fix plugin check --- plugin_wiegand.c | 9 ++++++--- seader.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/plugin_wiegand.c b/plugin_wiegand.c index 6e2b86d..bc84299 100644 --- a/plugin_wiegand.c +++ b/plugin_wiegand.c @@ -6,7 +6,9 @@ static int wiegand_format_count(uint8_t bit_length, uint64_t bits) { UNUSED(bit_length); UNUSED(bits); - return 0; + + FURI_LOG_I(PLUGIN_APP_ID, "count"); + return 1; } static void wiegand_format_description( @@ -14,10 +16,11 @@ static void wiegand_format_description( uint64_t bits, size_t index, FuriString* description) { + FURI_LOG_I(PLUGIN_APP_ID, "description %d", index); UNUSED(bit_length); UNUSED(bits); - UNUSED(index); - UNUSED(description); + + furi_string_cat_printf(description, "[%i] FC: CN:", index); } /* Actual implementation of app<>plugin interface */ diff --git a/seader.c b/seader.c index eb9010e..4cbd777 100644 --- a/seader.c +++ b/seader.c @@ -105,7 +105,7 @@ Seader* seader_alloc() { 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_APP_ID) == 0) { + if(strcmp(plugin->name, "Plugin Wiegand") == 0) { // Have to cast to drop "const" qualifier seader->plugin_wiegand = (PluginWiegand*)plugin; } From f90748930394869b1482211f86b8201a6c8fbd16 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 14 Apr 2024 13:25:53 -0700 Subject: [PATCH 06/11] H10301 parsing --- plugin_wiegand.c | 67 ++++++++++++++++++++++++++++++++- scenes/seader_scene_card_menu.c | 26 ++++++------- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/plugin_wiegand.c b/plugin_wiegand.c index bc84299..947665f 100644 --- a/plugin_wiegand.c +++ b/plugin_wiegand.c @@ -1,14 +1,70 @@ #include "plugin_interface.h" +#include #include +/* + * Huge thanks to the proxmark codebase: + * https://github.com/RfidResearchGroup/proxmark3/blob/master/client/src/wiegand_formats.c + */ + +static int wiegand_h10301_parse(uint8_t bit_length, uint64_t bits, FuriString* description) { + UNUSED(description); + UNUSED(bits); + UNUSED(bit_length); + + if(bit_length != 26) { + return 0; + } + + //E XXXX XXXX XXXX + //XXXX XXXX XXXX O + uint32_t eBitMask = 0x02000000; + uint32_t oBitMask = 0x00000001; + uint32_t eParityMask = 0x01FFE000; + uint32_t oParityMask = 0x00001FFE; + uint8_t eBit = (eBitMask & bits) >> 25; + uint8_t oBit = (oBitMask & bits) >> 0; + + bool eParity = bit_lib_test_parity_32((bits & eParityMask) >> 13, BitLibParityEven) && + eBit == 1; + bool oParity = bit_lib_test_parity_32((bits & oParityMask) >> 1, BitLibParityOdd) && oBit == 1; + + FURI_LOG_D( + PLUGIN_APP_ID, + "eBit: %d, oBit: %d, eParity: %d, oParity: %d", + eBit, + oBit, + eParity, + oParity); + + if(eParity && oParity) { + uint32_t cnMask = 0x1FFFE; + uint16_t cn = ((bits & cnMask) >> 1); + + uint32_t fcMask = 0x1FE0000; + uint16_t fc = ((bits & fcMask) >> 17); + + furi_string_cat_printf(description, "H10301\nFC: %d CN: %d\n", fc, cn); + return 1; + } + + return 0; +} + static int wiegand_format_count(uint8_t bit_length, uint64_t bits) { UNUSED(bit_length); UNUSED(bits); + int count = 0; + FuriString* ignore = furi_string_alloc(); - FURI_LOG_I(PLUGIN_APP_ID, "count"); - return 1; + count += wiegand_h10301_parse(bit_length, bits, ignore); + + furi_string_free(ignore); + + FURI_LOG_I(PLUGIN_APP_ID, "count: %i", count); + return count; } static void wiegand_format_description( @@ -20,6 +76,13 @@ static void wiegand_format_description( UNUSED(bit_length); UNUSED(bits); + size_t i = 0; + + i += wiegand_h10301_parse(bit_length, bits, description); + if(i - 1 == index) { + return; + } + furi_string_cat_printf(description, "[%i] FC: CN:", index); } diff --git a/scenes/seader_scene_card_menu.c b/scenes/seader_scene_card_menu.c index 813a47a..f10c3bd 100644 --- a/scenes/seader_scene_card_menu.c +++ b/scenes/seader_scene_card_menu.c @@ -1,12 +1,12 @@ #include "../seader_i.h" enum SubmenuIndex { + SubmenuIndexParse, SubmenuIndexSave, SubmenuIndexSavePicopass, SubmenuIndexSaveRFID, SubmenuIndexSaveSR, SubmenuIndexSaveMFC, - SubmenuIndexParse, }; void seader_scene_card_menu_submenu_callback(void* context, uint32_t index) { @@ -21,6 +21,18 @@ void seader_scene_card_menu_on_enter(void* context) { 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( @@ -46,18 +58,6 @@ void seader_scene_card_menu_on_enter(void* context) { submenu_add_item( submenu, "Save MFC", SubmenuIndexSaveMFC, seader_scene_card_menu_submenu_callback, seader); - 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_set_selected_item( seader->submenu, scene_manager_get_scene_state(seader->scene_manager, SeaderSceneCardMenu)); From 4aeb5f46149417e158352b9b977152fc8f8fcc40 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 14 Apr 2024 14:43:22 -0700 Subject: [PATCH 07/11] add C1k35s --- plugin_wiegand.c | 53 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/plugin_wiegand.c b/plugin_wiegand.c index 947665f..51d6973 100644 --- a/plugin_wiegand.c +++ b/plugin_wiegand.c @@ -9,11 +9,51 @@ * https://github.com/RfidResearchGroup/proxmark3/blob/master/client/src/wiegand_formats.c */ -static int wiegand_h10301_parse(uint8_t bit_length, uint64_t bits, FuriString* description) { - UNUSED(description); - UNUSED(bits); - UNUSED(bit_length); +// Structure for packed wiegand messages +// Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom) +typedef struct { + uint8_t Length; // Number of encoded bits in wiegand message (excluding headers and preamble) + uint32_t Top; // Bits in x<<64 positions + uint32_t Mid; // Bits in x<<32 positions + uint32_t Bot; // Lowest ordinal positions +} wiegand_message_t; +static inline uint8_t oddparity32(uint32_t x) { + return bit_lib_test_parity_32(x, BitLibParityOdd); +} + +static inline uint8_t evenparity32(uint32_t x) { + return bit_lib_test_parity_32(x, BitLibParityEven); +} + +static int wiegand_C1k35s_parse(uint8_t bit_length, uint64_t bits, FuriString* description) { + if(bit_length != 35) { + return 0; + } + + wiegand_message_t value; + value.Mid = bits >> 32; + value.Bot = bits; + wiegand_message_t* packed = &value; + + uint32_t cn = (packed->Bot >> 1) & 0x000FFFFF; + uint32_t fc = ((packed->Mid & 1) << 11) | ((packed->Bot >> 21)); + bool valid = (evenparity32((packed->Mid & 0x1) ^ (packed->Bot & 0xB6DB6DB6)) == + ((packed->Mid >> 1) & 1)) && + (oddparity32((packed->Mid & 0x3) ^ (packed->Bot & 0x6DB6DB6C)) == + ((packed->Bot >> 0) & 1)) && + (oddparity32((packed->Mid & 0x3) ^ (packed->Bot & 0xFFFFFFFF)) == + ((packed->Mid >> 2) & 1)); + + if(valid) { + furi_string_cat_printf(description, "C1k35s\nFC: %ld CN: %ld\n", fc, cn); + return 1; + } + + return 0; +} + +static int wiegand_h10301_parse(uint8_t bit_length, uint64_t bits, FuriString* description) { if(bit_length != 26) { return 0; } @@ -60,6 +100,7 @@ static int wiegand_format_count(uint8_t bit_length, uint64_t bits) { FuriString* ignore = furi_string_alloc(); count += wiegand_h10301_parse(bit_length, bits, ignore); + count += wiegand_C1k35s_parse(bit_length, bits, ignore); furi_string_free(ignore); @@ -82,6 +123,10 @@ static void wiegand_format_description( if(i - 1 == index) { return; } + i += wiegand_C1k35s_parse(bit_length, bits, description); + if(i - 1 == index) { + return; + } furi_string_cat_printf(description, "[%i] FC: CN:", index); } From 0cb6383f1b3deb93cff5ec0f9923620349126a62 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 14 Apr 2024 17:03:24 -0700 Subject: [PATCH 08/11] Move plugin to folder --- application.fam | 4 ++-- plugin_interface.h => plugin/interface.h | 0 plugin_wiegand.c => plugin/wiegand.c | 2 +- seader_i.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename plugin_interface.h => plugin/interface.h (100%) rename plugin_wiegand.c => plugin/wiegand.c (99%) diff --git a/application.fam b/application.fam index d7c6eda..84e8c72 100644 --- a/application.fam +++ b/application.fam @@ -14,7 +14,7 @@ App( sources=[ "*.c", "aeabi_uldivmod.sx", - "!plugin*.c", + "!plugin/*.c", ], fap_icon="icons/logo.png", fap_category="NFC", @@ -46,5 +46,5 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="plugin_wiegand_ep", requires=["seader"], - sources=["plugin_wiegand.c"], + sources=["plugin/wiegand.c"], ) diff --git a/plugin_interface.h b/plugin/interface.h similarity index 100% rename from plugin_interface.h rename to plugin/interface.h diff --git a/plugin_wiegand.c b/plugin/wiegand.c similarity index 99% rename from plugin_wiegand.c rename to plugin/wiegand.c index 51d6973..424d40d 100644 --- a/plugin_wiegand.c +++ b/plugin/wiegand.c @@ -1,5 +1,5 @@ -#include "plugin_interface.h" +#include "interface.h" #include #include diff --git a/seader_i.h b/seader_i.h index 19248b1..2cd5b80 100644 --- a/seader_i.h +++ b/seader_i.h @@ -41,7 +41,7 @@ #include #include -#include "plugin_interface.h" +#include "plugin/interface.h" #include #include #include From aaf3e2259d2719c99218705f304848dc8d36c5c6 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 14 Apr 2024 17:13:09 -0700 Subject: [PATCH 09/11] Move plugin to git submodule --- .gitmodules | 3 + plugin | 1 + plugin/interface.h | 20 ------ plugin/wiegand.c | 151 --------------------------------------------- 4 files changed, 4 insertions(+), 171 deletions(-) create mode 100644 .gitmodules create mode 160000 plugin delete mode 100644 plugin/interface.h delete mode 100644 plugin/wiegand.c diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6e50bf8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "plugin"] + path = plugin + url = git@gitlab.com:bettse/flipper-wiegand-plugin.git 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/plugin/interface.h b/plugin/interface.h deleted file mode 100644 index 714b245..0000000 --- a/plugin/interface.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file plugin_interface.h - * @brief Example plugin interface. - * - * Common interface between a plugin and host application - */ -#pragma once - -#include -#include -#include - -#define PLUGIN_APP_ID "plugin_wiegand" -#define PLUGIN_API_VERSION 1 - -typedef struct { - const char* name; - int (*count)(uint8_t, uint64_t); - void (*description)(uint8_t, uint64_t, size_t, FuriString*); -} PluginWiegand; diff --git a/plugin/wiegand.c b/plugin/wiegand.c deleted file mode 100644 index 424d40d..0000000 --- a/plugin/wiegand.c +++ /dev/null @@ -1,151 +0,0 @@ - -#include "interface.h" - -#include -#include - -/* - * Huge thanks to the proxmark codebase: - * https://github.com/RfidResearchGroup/proxmark3/blob/master/client/src/wiegand_formats.c - */ - -// Structure for packed wiegand messages -// Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom) -typedef struct { - uint8_t Length; // Number of encoded bits in wiegand message (excluding headers and preamble) - uint32_t Top; // Bits in x<<64 positions - uint32_t Mid; // Bits in x<<32 positions - uint32_t Bot; // Lowest ordinal positions -} wiegand_message_t; - -static inline uint8_t oddparity32(uint32_t x) { - return bit_lib_test_parity_32(x, BitLibParityOdd); -} - -static inline uint8_t evenparity32(uint32_t x) { - return bit_lib_test_parity_32(x, BitLibParityEven); -} - -static int wiegand_C1k35s_parse(uint8_t bit_length, uint64_t bits, FuriString* description) { - if(bit_length != 35) { - return 0; - } - - wiegand_message_t value; - value.Mid = bits >> 32; - value.Bot = bits; - wiegand_message_t* packed = &value; - - uint32_t cn = (packed->Bot >> 1) & 0x000FFFFF; - uint32_t fc = ((packed->Mid & 1) << 11) | ((packed->Bot >> 21)); - bool valid = (evenparity32((packed->Mid & 0x1) ^ (packed->Bot & 0xB6DB6DB6)) == - ((packed->Mid >> 1) & 1)) && - (oddparity32((packed->Mid & 0x3) ^ (packed->Bot & 0x6DB6DB6C)) == - ((packed->Bot >> 0) & 1)) && - (oddparity32((packed->Mid & 0x3) ^ (packed->Bot & 0xFFFFFFFF)) == - ((packed->Mid >> 2) & 1)); - - if(valid) { - furi_string_cat_printf(description, "C1k35s\nFC: %ld CN: %ld\n", fc, cn); - return 1; - } - - return 0; -} - -static int wiegand_h10301_parse(uint8_t bit_length, uint64_t bits, FuriString* description) { - if(bit_length != 26) { - return 0; - } - - //E XXXX XXXX XXXX - //XXXX XXXX XXXX O - uint32_t eBitMask = 0x02000000; - uint32_t oBitMask = 0x00000001; - uint32_t eParityMask = 0x01FFE000; - uint32_t oParityMask = 0x00001FFE; - uint8_t eBit = (eBitMask & bits) >> 25; - uint8_t oBit = (oBitMask & bits) >> 0; - - bool eParity = bit_lib_test_parity_32((bits & eParityMask) >> 13, BitLibParityEven) && - eBit == 1; - bool oParity = bit_lib_test_parity_32((bits & oParityMask) >> 1, BitLibParityOdd) && oBit == 1; - - FURI_LOG_D( - PLUGIN_APP_ID, - "eBit: %d, oBit: %d, eParity: %d, oParity: %d", - eBit, - oBit, - eParity, - oParity); - - if(eParity && oParity) { - uint32_t cnMask = 0x1FFFE; - uint16_t cn = ((bits & cnMask) >> 1); - - uint32_t fcMask = 0x1FE0000; - uint16_t fc = ((bits & fcMask) >> 17); - - furi_string_cat_printf(description, "H10301\nFC: %d CN: %d\n", fc, cn); - return 1; - } - - return 0; -} - -static int wiegand_format_count(uint8_t bit_length, uint64_t bits) { - UNUSED(bit_length); - UNUSED(bits); - int count = 0; - FuriString* ignore = furi_string_alloc(); - - count += wiegand_h10301_parse(bit_length, bits, ignore); - count += wiegand_C1k35s_parse(bit_length, bits, ignore); - - furi_string_free(ignore); - - FURI_LOG_I(PLUGIN_APP_ID, "count: %i", count); - return count; -} - -static void wiegand_format_description( - uint8_t bit_length, - uint64_t bits, - size_t index, - FuriString* description) { - FURI_LOG_I(PLUGIN_APP_ID, "description %d", index); - UNUSED(bit_length); - UNUSED(bits); - - size_t i = 0; - - i += wiegand_h10301_parse(bit_length, bits, description); - if(i - 1 == index) { - return; - } - i += wiegand_C1k35s_parse(bit_length, bits, description); - if(i - 1 == index) { - return; - } - - furi_string_cat_printf(description, "[%i] FC: CN:", index); -} - -/* Actual implementation of app<>plugin interface */ -static const PluginWiegand plugin_wiegand = { - .name = "Plugin Wiegand", - .count = &wiegand_format_count, - .description = &wiegand_format_description, -}; - -/* Plugin descriptor to comply with basic plugin specification */ -static const FlipperAppPluginDescriptor plugin_wiegand_descriptor = { - .appid = PLUGIN_APP_ID, - .ep_api_version = PLUGIN_API_VERSION, - .entry_point = &plugin_wiegand, -}; - -/* Plugin entry point - must return a pointer to const descriptor */ -const FlipperAppPluginDescriptor* plugin_wiegand_ep(void) { - return &plugin_wiegand_descriptor; -} From 124549cae4138e442db26661261d4ff675f0c6f4 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 14 Apr 2024 17:17:20 -0700 Subject: [PATCH 10/11] Add submodule to git workflow checkout --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) 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 From 877cf035bd7fd6dc026bae9903d691d27a271e2a Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 14 Apr 2024 17:22:04 -0700 Subject: [PATCH 11/11] Change submodule to http --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 6e50bf8..e691db8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "plugin"] path = plugin - url = git@gitlab.com:bettse/flipper-wiegand-plugin.git + url = https://gitlab.com/bettse/flipper-wiegand-plugin.git