MX 2 лет назад
Родитель
Сommit
2134820040

+ 31 - 4
non_catalog_apps/wiegand/README.md

@@ -1,10 +1,33 @@
 # Wiegand
 # Wiegand
 
 
-This application supports W4, W8, W24, W26, W32, W34, W37 and W40 formats.
+This application supports W4, W8, W24, W26, W32, W34, W37, W40 and W48 formats.
 
 
-This application can be used to test Wiegand readers and keypads. It can
-save the data to a file, and can load and replay the data. Timings are
-measured and displayed; which can be used to help debug Wiegand readers.
+This application can be used to test Wiegand readers and keypads. It can save the data to a file, and can load and replay the data. Timings are measured and displayed; which can be used to help debug Wiegand readers.
+
+
+## Wiring
+The D0 and D1 wires of the Wiegand must be about 1K or higher for the Flipper to be able to effectively pull them down to ground.  If the line has a lower resistance, like 100 ohms, then you need to add MOSFETs to help pull the lines low.  The following [YouTube video](https://youtu.be/OVyd3ffnZ0M) is a demonstration of how to correctly wire the device.  
+
+In all configurations:
+- Pin A7 goes to your Wiegand D1 (white) wire.
+- Pin A4 goes to your Wiegand D0 (green) wire.
+- Pin GND goes to your Wiegand GND (black) wire.
+This is sufficient for reading signals with both this application and the Debug Accessor application.
+
+If the pull-up resistors on your card reader are less than 1K, you also need the following:
+- Two additional MOSFETs are required.  I used IRF540 (but perhaps IRL540 would be better?)
+- Two additional Pull-down resitors are required.  I used 5K, but 4.7K would be fine as well.
+- I'm still learning, but perhaps a MOSFET driver / optocoupler would provide even more protection to the Flipper GPIO pins?  Use this circuit at your own risk.  :)
+
+Here is how you wire up the MOSFET and the pull-down resistors:
+- The source pin of each MOSFET connects to ground.
+- The gate pin connects to one side of a resistor.  The other side of the resistor goes to ground.
+- For the MOSFET used for D1:
+  - The gate pin of the MOSFET for D1 goes to pin A6 on the Flipper. (It should also already be connected to the pull-down resistor)
+  - The drain pin of the MOSFET for D1 goes to pin A7 on the Flipper.
+- For the MOSFET used for D0:
+  - The gate pin of the MOSFET for D0 goes to pin B3 on the Flipper. (It should also already be connected to the pull-down resistor)
+  - The drain pin of the MOSFET for D0 goes to pin A4 on the Flipper.
 
 
 ## W4: 4-bit Wiegand
 ## W4: 4-bit Wiegand
 
 
@@ -24,6 +47,10 @@ This is a 26-bit format used by many readers. The first bit is an even parity bi
 
 
 This is similar to W26, but without the leading and trailing parity bits. The first 8 bits are the facility code. The next 16 bits are the card number. The application will display the facility code and card number.
 This is similar to W26, but without the leading and trailing parity bits. The first 8 bits are the facility code. The next 16 bits are the card number. The application will display the facility code and card number.
 
 
+## W48: 48-bit Wiegand
+
+This is HID 48 bit Corporate 1000 - H2004064 format.  The first bit is odd parity 2 (based on bits 2-48).  The next bit is even parity (based on 4-5,7-8,10-11,...,46-47).  Then 22 bit company code.  Then 23 bit card id. Then odd parity 1 (based on 3-4,6-7,9-10,...,45-46).  
+
 ## W32/W34/W37/W40: 32/34/37/40-bit Wiegand
 ## W32/W34/W37/W40: 32/34/37/40-bit Wiegand
 
 
 These formats are not very standardized, so the application will not try to interpret the data. You can modify the wiegand_data.c file to add your own interpretation.
 These formats are not very standardized, so the application will not try to interpret the data. You can modify the wiegand_data.c file to add your own interpretation.

+ 44 - 0
non_catalog_apps/wiegand/scenes/wiegand_data.c

@@ -53,18 +53,27 @@ void wiegand_add_info_26bit(FuriString* buffer) {
     furi_string_cat_printf(buffer, "\nFacility: 0x");
     furi_string_cat_printf(buffer, "\nFacility: 0x");
     int code = 0;
     int code = 0;
     int count = 0;
     int count = 0;
+    uint32_t dec = 0;
     for(int i = 1; i < 25; i++) {
     for(int i = 1; i < 25; i++) {
         code = code << 1;
         code = code << 1;
+        dec = dec << 1;
         code |= data[i] ? 1 : 0;
         code |= data[i] ? 1 : 0;
+        dec |= data[i] ? 1 : 0;
         if(++count % 4 == 0) {
         if(++count % 4 == 0) {
             furi_string_cat_printf(buffer, "%X", code);
             furi_string_cat_printf(buffer, "%X", code);
             code = 0;
             code = 0;
         }
         }
+
+        if(i == 8) {
+            furi_string_cat_printf(buffer, " (%ld)", dec);
+            dec = 0;
+        }
         // Parity, then 8 bit facility code, then id.
         // Parity, then 8 bit facility code, then id.
         if(i == 9) {
         if(i == 9) {
             furi_string_cat_printf(buffer, "\nId: 0x");
             furi_string_cat_printf(buffer, "\nId: 0x");
         }
         }
     }
     }
+    furi_string_cat_printf(buffer, " (%ld)", dec);
 
 
     if(data[13]) {
     if(data[13]) {
         parity = 1;
         parity = 1;
@@ -91,18 +100,51 @@ void wiegand_add_info_24bit(FuriString* buffer) {
     furi_string_cat_printf(buffer, "\nFacility: 0x");
     furi_string_cat_printf(buffer, "\nFacility: 0x");
     int code = 0;
     int code = 0;
     int count = 0;
     int count = 0;
+    uint32_t dec = 0;
     for(int i = 0; i < 24; i++) {
     for(int i = 0; i < 24; i++) {
         code = code << 1;
         code = code << 1;
+        dec = dec << 1;
         code |= data[i] ? 1 : 0;
         code |= data[i] ? 1 : 0;
+        dec |= data[i] ? 1 : 0;
         if(++count % 4 == 0) {
         if(++count % 4 == 0) {
             furi_string_cat_printf(buffer, "%X", code);
             furi_string_cat_printf(buffer, "%X", code);
             code = 0;
             code = 0;
         }
         }
         // The first 8 bits are facility code, then comes id.
         // The first 8 bits are facility code, then comes id.
         if(i == 8) {
         if(i == 8) {
+            furi_string_cat_printf(buffer, " (%ld)", dec);
+            dec = 0;
             furi_string_cat_printf(buffer, "\nId: 0x");
             furi_string_cat_printf(buffer, "\nId: 0x");
         }
         }
     }
     }
+    furi_string_cat_printf(buffer, " (%ld)", dec);
+}
+
+void wiegand_add_info_48bit(FuriString* buffer) {
+    // We assume this is HID 48 bit Corporate 1000 - H2004064 format.
+    // The first bit is odd parity 2 (based on bits 2-48).
+    // The next bit is even parity (based on 4-5,7-8,10-11,...,46-47).
+    // Then 22 bit company code.
+    // Then 23 bit card id.
+    /// Then odd parity 1 (based on 3-4,6-7,9-10,...,45-46).
+
+    // 22 bits company code (bits 3-24; data[2..23])
+    uint32_t code = 0;
+    for(int i = 2; i <= 23; i++) {
+        code = code << 1;
+        code |= data[i] ? 1 : 0;
+    }
+    furi_string_cat_printf(buffer, "\nCompany: %lX (%ld)", code, code);
+
+    // 23 bit card id (bits 25-47; data[24..46]).
+    code = 0;
+    for(int i = 24; i <= 46; i++) {
+        code = code << 1;
+        code |= data[i] ? 1 : 0;
+    }
+    furi_string_cat_printf(buffer, "\nCard: %lX (%ld)", code, code);
+
+    // TODO: Add the 3 parity checks.
 }
 }
 
 
 void wiegand_add_info(FuriString* buffer) {
 void wiegand_add_info(FuriString* buffer) {
@@ -113,6 +155,8 @@ void wiegand_add_info(FuriString* buffer) {
         wiegand_add_info_26bit(buffer);
         wiegand_add_info_26bit(buffer);
     } else if(bit_count == 24) {
     } else if(bit_count == 24) {
         wiegand_add_info_24bit(buffer);
         wiegand_add_info_24bit(buffer);
+    } else if(bit_count == 48) {
+        wiegand_add_info_48bit(buffer);
     }
     }
     furi_string_push_back(buffer, '\n');
     furi_string_push_back(buffer, '\n');
 }
 }

+ 17 - 1
non_catalog_apps/wiegand/scenes/wiegand_instructions.c

@@ -14,6 +14,7 @@ void wiegand_instructions_scene_on_enter(void* context) {
         "Connect D0 (Green) to pin A4\n"
         "Connect D0 (Green) to pin A4\n"
         "Connect D1 (White) to pin A7\n"
         "Connect D1 (White) to pin A7\n"
         "Connect GND (Black) to GND\n"
         "Connect GND (Black) to GND\n"
+        "\nOption 1 (no mosfet):\n"
         "Add a 10K inline resistor on D0\n"
         "Add a 10K inline resistor on D0\n"
         "between keypad and door.\n"
         "between keypad and door.\n"
         "Connect Flipper on door\n"
         "Connect Flipper on door\n"
@@ -22,6 +23,21 @@ void wiegand_instructions_scene_on_enter(void* context) {
         "door. Connect Flipper on\n"
         "door. Connect Flipper on\n"
         "door side. Do not inturrupt\n"
         "door side. Do not inturrupt\n"
         "the D0/D1 connections while\n"
         "the D0/D1 connections while\n"
-        "adding the resistors.");
+        "adding the resistors."
+        "\n\nOption 2 (mosfet):\n"
+        "Connect pin A6 to gate of\n"
+        "mosfet for D1. Connect 5K\n"
+        "resistor from gate to GND.\n"
+        "Connect pin A7 to drain of\n"
+        "mosfet for D1. Connect source\n"
+        "of mosfet for D1 to GND.\n"
+        "Connect pin B3 to gate of\n"
+        "mosfet for D0. Connect 5K\n"
+        "resistor from gate to GND.\n"
+        "Connect pin A4 to drain of\n"
+        "mosfet for D0. Connect\n"
+        "source of mosfet for D0 to\n"
+        "GND.\n"
+        );
     view_dispatcher_switch_to_view(app->view_dispatcher, WiegandWidgetView);
     view_dispatcher_switch_to_view(app->view_dispatcher, WiegandWidgetView);
 }
 }

+ 14 - 4
non_catalog_apps/wiegand/scenes/wiegand_play.c

@@ -24,8 +24,12 @@ void wiegand_play() {
 
 
     furi_hal_gpio_write(pinD0, true);
     furi_hal_gpio_write(pinD0, true);
     furi_hal_gpio_init(pinD0, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedVeryHigh);
     furi_hal_gpio_init(pinD0, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(pinD0mosfet, false);
+    furi_hal_gpio_init(pinD0mosfet, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
     furi_hal_gpio_write(pinD1, true);
     furi_hal_gpio_write(pinD1, true);
     furi_hal_gpio_init(pinD1, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedVeryHigh);
     furi_hal_gpio_init(pinD1, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedVeryHigh);
+    furi_hal_gpio_write(pinD1mosfet, false);
+    furi_hal_gpio_init(pinD1mosfet, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
 
 
     single_vibro();
     single_vibro();
     furi_delay_ms(500);
     furi_delay_ms(500);
@@ -33,18 +37,24 @@ void wiegand_play() {
     int j = 0;
     int j = 0;
     for(int i = 0; i < bit_count; i++) {
     for(int i = 0; i < bit_count; i++) {
         if(data[i]) {
         if(data[i]) {
-            furi_hal_gpio_write(pinD1, false);
+            furi_hal_gpio_write(pinD1mosfet, true); // Activate the mosfet to ground wire
+            furi_hal_gpio_write(pinD1, false); // Ground the open-drain wire
             furi_delay_us(delays[j++]);
             furi_delay_us(delays[j++]);
-            furi_hal_gpio_write(pinD1, true);
+            furi_hal_gpio_write(pinD1, true); // Float the wire
+            furi_hal_gpio_write(pinD1mosfet, false); // Deactivate the mosfet
             furi_delay_us(delays[j++]);
             furi_delay_us(delays[j++]);
         } else {
         } else {
-            furi_hal_gpio_write(pinD0, false);
+            furi_hal_gpio_write(pinD0mosfet, true); // Activate the mosfet to ground wire
+            furi_hal_gpio_write(pinD0, false); // Ground the open-drain wire
             furi_delay_us(delays[j++]);
             furi_delay_us(delays[j++]);
-            furi_hal_gpio_write(pinD0, true);
+            furi_hal_gpio_write(pinD0, true); // Float the wire
+            furi_hal_gpio_write(pinD0mosfet, false); // Deactivate the mosfet
             furi_delay_us(delays[j++]);
             furi_delay_us(delays[j++]);
         }
         }
     }
     }
 
 
     furi_hal_gpio_init_simple(pinD0, GpioModeAnalog);
     furi_hal_gpio_init_simple(pinD0, GpioModeAnalog);
     furi_hal_gpio_init_simple(pinD1, GpioModeAnalog);
     furi_hal_gpio_init_simple(pinD1, GpioModeAnalog);
+    furi_hal_gpio_init_simple(pinD0mosfet, GpioModeAnalog);
+    furi_hal_gpio_init_simple(pinD1mosfet, GpioModeAnalog);
 }
 }

+ 2 - 1
non_catalog_apps/wiegand/scenes/wiegand_read.c

@@ -68,7 +68,8 @@ void wiegand_timer_callback(void* context) {
     FURI_CRITICAL_ENTER();
     FURI_CRITICAL_ENTER();
     if(duration > 25 * one_millisecond) {
     if(duration > 25 * one_millisecond) {
         if(bit_count == 4 || bit_count == 8 || bit_count == 24 || bit_count == 26 ||
         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 == 32 || bit_count == 34 || bit_count == 37 || bit_count == 40 ||
+           bit_count == 48) {
             wiegand_stop_read(app);
             wiegand_stop_read(app);
             scene_manager_next_scene(app->scene_manager, WiegandDataScene);
             scene_manager_next_scene(app->scene_manager, WiegandDataScene);
         } else {
         } else {

+ 2 - 0
non_catalog_apps/wiegand/wiegand.c

@@ -1,7 +1,9 @@
 #include "wiegand.h"
 #include "wiegand.h"
 
 
 const GpioPin* const pinD0 = &gpio_ext_pa4;
 const GpioPin* const pinD0 = &gpio_ext_pa4;
+const GpioPin* const pinD0mosfet = &gpio_ext_pb3;
 const GpioPin* const pinD1 = &gpio_ext_pa7;
 const GpioPin* const pinD1 = &gpio_ext_pa7;
+const GpioPin* const pinD1mosfet = &gpio_ext_pa6;
 volatile int bit_count = 0;
 volatile int bit_count = 0;
 volatile bool data[MAX_BITS];
 volatile bool data[MAX_BITS];
 volatile uint32_t data_fall[MAX_BITS];
 volatile uint32_t data_fall[MAX_BITS];

+ 3 - 1
non_catalog_apps/wiegand/wiegand.h

@@ -14,9 +14,11 @@
 #include <storage/storage.h>
 #include <storage/storage.h>
 
 
 extern const GpioPin* const pinD0;
 extern const GpioPin* const pinD0;
+extern const GpioPin* const pinD0mosfet;
 extern const GpioPin* const pinD1;
 extern const GpioPin* const pinD1;
+extern const GpioPin* const pinD1mosfet;
 extern volatile int bit_count;
 extern volatile int bit_count;
-#define MAX_BITS 42
+#define MAX_BITS 48
 extern volatile bool data[];
 extern volatile bool data[];
 extern volatile uint32_t data_fall[];
 extern volatile uint32_t data_fall[];
 extern volatile uint32_t data_rise[];
 extern volatile uint32_t data_rise[];