MX 2 سال پیش
والد
کامیت
37f80b1da4

+ 1 - 1
non_catalog_apps/wiegand/application.fam

@@ -9,6 +9,6 @@ App(
     fap_category="GPIO",
     fap_author="@jamisonderek",
     fap_weburl="https://github.com/jamisonderek/flipper-zero-tutorials/tree/main/gpio",
-    fap_version="1.0",
+    fap_version="1.2",
     fap_description="This application can be used to test Wiegand readers and keypads",
 )

+ 2 - 2
non_catalog_apps/wiegand/scenes/wiegand_instructions.c

@@ -10,6 +10,7 @@ void wiegand_instructions_scene_on_enter(void* context) {
         15,
         128,
         40,
+        "Version 1.2\n"
         "Only use on devices you own!\n"
         "Connect D0 (Green) to pin A4\n"
         "Connect D1 (White) to pin A7\n"
@@ -37,7 +38,6 @@ void wiegand_instructions_scene_on_enter(void* context) {
         "Connect pin A4 to drain of\n"
         "mosfet for D0. Connect\n"
         "source of mosfet for D0 to\n"
-        "GND.\n"
-        );
+        "GND.\n");
     view_dispatcher_switch_to_view(app->view_dispatcher, WiegandWidgetView);
 }

+ 9 - 0
non_catalog_apps/wiegand/scenes/wiegand_main_menu.c

@@ -15,6 +15,9 @@ void wiegand_menu_callback(void* context, uint32_t index) {
     case WiegandMainMenuRead:
         event = WiegandMainMenuReadEvent;
         break;
+    case WiegandMainMenuScan:
+        event = WiegandMainMenuScanEvent;
+        break;
     case WiegandMainMenuLoad:
         event = WiegandMainMenuLoadEvent;
         break;
@@ -36,6 +39,8 @@ void wiegand_main_menu_scene_on_enter(void* context) {
     submenu_add_item(
         app->submenu, "Instructions", WiegandMainMenuInstructions, wiegand_menu_callback, app);
     submenu_add_item(app->submenu, "Read", WiegandMainMenuRead, wiegand_menu_callback, app);
+    submenu_add_item(
+        app->submenu, "Scan w/AutoSave", WiegandMainMenuScan, wiegand_menu_callback, app);
     submenu_add_item(app->submenu, "Load", WiegandMainMenuLoad, wiegand_menu_callback, app);
     view_dispatcher_switch_to_view(app->view_dispatcher, WiegandSubmenuView);
 }
@@ -53,6 +58,10 @@ bool wiegand_main_menu_scene_on_event(void* context, SceneManagerEvent event) {
             scene_manager_next_scene(app->scene_manager, WiegandReadScene);
             consumed = true;
             break;
+        case WiegandMainMenuScanEvent:
+            scene_manager_next_scene(app->scene_manager, WiegandScanScene);
+            consumed = true;
+            break;
         case WiegandMainMenuLoadEvent:
             scene_manager_next_scene(app->scene_manager, WiegandLoadScene);
             consumed = true;

+ 138 - 0
non_catalog_apps/wiegand/scenes/wiegand_scan.c

@@ -0,0 +1,138 @@
+#include "../wiegand.h"
+
+FuriTimer* timer = NULL;
+
+static void wiegand_scan_isr_d0(void* context) {
+    UNUSED(context);
+    uint32_t time = DWT->CYCCNT;
+    bool rise = furi_hal_gpio_read(pinD0);
+
+    data[bit_count] = 0;
+
+    if(rise) {
+        data_rise[bit_count] = time;
+        if(bit_count < MAX_BITS) {
+            bit_count++;
+        }
+    } else {
+        data_fall[bit_count] = time;
+    }
+}
+
+static void wiegand_scan_isr_d1(void* context) {
+    UNUSED(context);
+    uint32_t time = DWT->CYCCNT;
+    bool rise = furi_hal_gpio_read(pinD1);
+
+    data[bit_count] = 1;
+
+    if(rise) {
+        data_rise[bit_count] = time;
+        if(bit_count < MAX_BITS) {
+            bit_count++;
+        }
+    } else {
+        data_fall[bit_count] = time;
+    }
+}
+
+static void wiegand_start_scan(void* context) {
+    UNUSED(context);
+    data_saved = false;
+    bit_count = 0;
+    furi_hal_gpio_init_simple(pinD0, GpioModeInterruptRiseFall);
+    furi_hal_gpio_init_simple(pinD1, GpioModeInterruptRiseFall);
+    furi_hal_gpio_add_int_callback(pinD0, wiegand_scan_isr_d0, NULL);
+    furi_hal_gpio_add_int_callback(pinD1, wiegand_scan_isr_d1, NULL);
+    furi_timer_start(timer, 100);
+}
+
+static void wiegand_stop_scan(void* context) {
+    UNUSED(context);
+    furi_hal_gpio_remove_int_callback(pinD0);
+    furi_hal_gpio_remove_int_callback(pinD1);
+    furi_hal_gpio_init_simple(pinD0, GpioModeAnalog);
+    furi_hal_gpio_init_simple(pinD1, GpioModeAnalog);
+    furi_timer_stop(timer);
+}
+
+static void wiegand_scan_found(void* context) {
+    App* app = context;
+
+    FuriHalRtcDateTime datetime;
+    furi_hal_rtc_get_datetime(&datetime);
+    snprintf(
+        app->file_name,
+        25,
+        "%02d%02d%02d_%02d%02d%02d",
+        datetime.year,
+        datetime.month,
+        datetime.day,
+        datetime.hour,
+        datetime.minute,
+        datetime.second);
+    furi_hal_vibro_on(true);
+    furi_delay_ms(50);
+    furi_hal_vibro_on(false);
+    furi_delay_ms(50);
+    wiegand_save(app);
+    furi_hal_vibro_on(true);
+    furi_delay_ms(50);
+    furi_hal_vibro_on(false);
+    furi_delay_ms(1000);
+    wiegand_start_scan(app);
+}
+
+static void wiegand_scan_timer_callback(void* context) {
+    App* app = context;
+    uint32_t duration = DWT->CYCCNT;
+    const uint32_t one_millisecond = 64000;
+
+    if(bit_count == 0) {
+        return;
+    }
+
+    duration -= data_fall[bit_count - 1];
+
+    bool found = false;
+    FURI_CRITICAL_ENTER();
+    if(duration > 25 * one_millisecond) {
+        if(bit_count == 4 || bit_count == 8 || bit_count == 24 || bit_count == 26 ||
+           bit_count == 32 || bit_count == 34 || bit_count == 37 || bit_count == 40 ||
+           bit_count == 48) {
+            wiegand_stop_scan(app);
+            found = true;
+        } else {
+            // No data, clear
+            bit_count = 0;
+        }
+    }
+    FURI_CRITICAL_EXIT();
+
+    if(found) {
+        wiegand_scan_found(app);
+    }
+}
+
+void wiegand_scan_scene_on_enter(void* context) {
+    App* app = context;
+    timer = furi_timer_alloc(wiegand_scan_timer_callback, FuriTimerTypePeriodic, app);
+    widget_reset(app->widget);
+    widget_add_string_element(app->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Scan Wiegand");
+    widget_add_string_element(
+        app->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, "Files saved automatically.");
+    widget_add_string_element(
+        app->widget, 0, 30, AlignLeft, AlignTop, FontSecondary, "Vibrates on detection.");
+    widget_add_string_element(
+        app->widget, 0, 45, AlignLeft, AlignTop, FontSecondary, "D0/Green/A4");
+    widget_add_string_element(
+        app->widget, 0, 53, AlignLeft, AlignTop, FontSecondary, "D1/White/A7");
+    wiegand_start_scan(app);
+    view_dispatcher_switch_to_view(app->view_dispatcher, WiegandWidgetView);
+}
+
+void wiegand_scan_scene_on_exit(void* context) {
+    App* app = context;
+    wiegand_stop_scan(app);
+    furi_timer_free(timer);
+}

+ 3 - 0
non_catalog_apps/wiegand/wiegand.c

@@ -23,6 +23,7 @@ void (*const basic_scenes_scene_on_enter_handlers[])(void*) = {
     wiegand_main_menu_scene_on_enter,
     wiegand_instructions_scene_on_enter,
     wiegand_read_scene_on_enter,
+    wiegand_scan_scene_on_enter,
     wiegand_data_scene_on_enter,
     wiegand_save_scene_on_enter,
     wiegand_load_scene_on_enter,
@@ -32,6 +33,7 @@ bool (*const basic_scenes_scene_on_event_handlers[])(void*, SceneManagerEvent) =
     wiegand_main_menu_scene_on_event,
     wiegand_empty_scene_on_event, // instructions
     wiegand_empty_scene_on_event, // read
+    wiegand_empty_scene_on_event, // scan
     wiegand_data_scene_on_event,
     wiegand_save_scene_on_event,
     wiegand_empty_scene_on_event, // load
@@ -41,6 +43,7 @@ void (*const basic_scenes_scene_on_exit_handlers[])(void*) = {
     wiegand_empty_scene_on_exit, // main_menu
     wiegand_empty_scene_on_exit, // instructions
     wiegand_read_scene_on_exit,
+    wiegand_scan_scene_on_exit,
     wiegand_empty_scene_on_exit, // data
     wiegand_empty_scene_on_exit, // save
     wiegand_empty_scene_on_exit, // load

+ 8 - 0
non_catalog_apps/wiegand/wiegand.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <furi.h>
+#include <furi_hal.h>
 #include <gui/gui.h>
 #include <gui/view_dispatcher.h>
 #include <gui/scene_manager.h>
@@ -37,6 +38,7 @@ typedef enum {
     WiegandMainMenuScene,
     WiegandInstructionsScene,
     WiegandReadScene,
+    WiegandScanScene,
     WiegandDataScene,
     WiegandSaveScene,
     WiegandLoadScene,
@@ -64,6 +66,7 @@ typedef struct App {
 typedef enum {
     WiegandMainMenuInstructions,
     WiegandMainMenuRead,
+    WiegandMainMenuScan,
     WiegandMainMenuLoad,
 } WiegandMainMenuSceneIndex;
 
@@ -71,6 +74,7 @@ typedef enum {
     WiegandMainMenuUnknownEvent,
     WiegandMainMenuInstructionsEvent,
     WiegandMainMenuReadEvent,
+    WiegandMainMenuScanEvent,
     WiegandMainMenuLoadEvent,
 } WiegandMainMenuEvent;
 
@@ -119,6 +123,10 @@ void wiegand_load_scene_on_enter(void* context);
 bool wiegand_custom_callback(void* context, uint32_t custom_event);
 bool wiegand_back_event_callback(void* context);
 
+void wiegand_scan_scene_on_enter(void* context);
+//bool wiegand_scan_scene_on_event(void* context, SceneManagerEvent event);
+void wiegand_scan_scene_on_exit(void* context);
+
 // Methods with no implementation.
 bool wiegand_empty_scene_on_event(void* context, SceneManagerEvent event);
 void wiegand_empty_scene_on_exit(void* _ctx);