Просмотр исходного кода

Added historical spoofing implementation to the hardcoded emulation test ground

Zachary Weiss 3 лет назад
Родитель
Сommit
ef1cb1b638
1 измененных файлов с 167 добавлено и 4 удалено
  1. 167 4
      scenes/mag_scene_emulate_test.c

+ 167 - 4
scenes/mag_scene_emulate_test.c

@@ -1,20 +1,183 @@
 #include "../mag_i.h"
 
+#define PIN_A 0
+#define PIN_B 1 // currently unused
+#define CLOCK_US 250 // typically set between 200-500us
+
+uint8_t magspoof_bit_dir = 0;
+
+void mag_scene_emulate_test_dialog_callback(DialogExResult result, void* context) {
+    Mag* mag = context;
+
+    view_dispatcher_send_custom_event(mag->view_dispatcher, result);
+}
+
+void gpio_item_set_rfid_pin(uint8_t index, bool level) {
+    if(index == 0) {
+        furi_hal_gpio_write(&gpio_rfid_carrier_out, level);
+        // A7 GPIO pin for debugging purposes
+        //furi_hal_gpio_write(&gpio_ext_pa7, level);
+    }
+}
+
+static void play_bit(uint8_t send_bit) {
+    magspoof_bit_dir ^= 1;
+    gpio_item_set_rfid_pin(PIN_A, magspoof_bit_dir);
+    // PIN_B goes unused in current LF modulation.
+    // Leaving legacy here in event we attempt downstream modulation,
+    // rather than just modulating RFID_OUT upstream for signal forming
+    gpio_item_set_rfid_pin(PIN_B, !magspoof_bit_dir);
+    furi_delay_us(CLOCK_US);
+
+    if(send_bit) {
+        magspoof_bit_dir ^= 1;
+        gpio_item_set_rfid_pin(PIN_A, magspoof_bit_dir);
+        gpio_item_set_rfid_pin(PIN_B, !magspoof_bit_dir);
+    }
+    furi_delay_us(CLOCK_US);
+}
+
+static void mag_spoof(FuriString* track_str, uint8_t track) {
+    furi_hal_power_enable_otg();
+
+    size_t from;
+    size_t to;
+
+    // TODO ';' in first track case
+    if(track == 0) {
+        from = furi_string_search_char(track_str, '%');
+        to = furi_string_search_char(track_str, '?', from);
+    } else if(track == 1) {
+        from = furi_string_search_char(track_str, ';');
+        to = furi_string_search_char(track_str, '?', from);
+    } else {
+        from = 0;
+        to = furi_string_size(track_str);
+    }
+    if(from >= to) {
+        return;
+    }
+    furi_string_mid(track_str, from, to - from + 1);
+
+    const char* data = furi_string_get_cstr(track_str);
+
+    printf("%s", data);
+
+    furi_hal_ibutton_start_drive();
+    furi_hal_ibutton_pin_low();
+
+    // this doesn't seem to make a difference, leaving it in
+    furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_write(&gpio_rfid_data_in, false);
+
+    // false->ground RFID antenna; true->don't ground
+    // skotopes (RFID dev) say normally you'd want RFID_PULL in high for signal forming, while modulating RFID_OUT
+    // dunaevai135 had it low in their old code. Leaving low, as it doesn't seem to make a difference on my janky antenna
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
+
+    furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+
+    // A7 GPIO pin for debugging purposes
+    //furi_hal_gpio_init(&gpio_ext_pa7, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+
+    furi_delay_ms(300);
+
+    FURI_CRITICAL_ENTER();
+
+    const uint8_t bitlen[] = {7, 5, 5};
+    const int sublen[] = {32, 48, 48};
+    int tmp, crc, lrc = 0;
+    magspoof_bit_dir = 0;
+
+    // First put out a bunch of leading zeros.
+    for(uint8_t i = 0; i < 25; i++) {
+        play_bit(0);
+    }
+
+    for(uint8_t i = 0; data[i] != '\0'; i++) {
+        crc = 1;
+        tmp = data[i] - sublen[track];
+
+        for(uint8_t j = 0; j < bitlen[track] - 1; j++) {
+            crc ^= tmp & 1;
+            lrc ^= (tmp & 1) << j;
+            play_bit(tmp & 1);
+            tmp >>= 1;
+        }
+        play_bit(crc);
+    }
+
+    // finish calculating and send last "byte" (LRC)
+    tmp = lrc;
+    crc = 1;
+    for(uint8_t j = 0; j < bitlen[track] - 1; j++) {
+        crc ^= tmp & 1;
+        play_bit(tmp & 1);
+        tmp >>= 1;
+    }
+    play_bit(crc);
+
+    // finish with 0's
+    for(uint8_t i = 0; i < 5 * 5; i++) {
+        play_bit(0);
+    }
+
+    gpio_item_set_rfid_pin(PIN_A, 0);
+    gpio_item_set_rfid_pin(PIN_B, 0);
+
+    FURI_CRITICAL_EXIT();
+
+    furi_hal_rfid_pins_reset();
+    furi_hal_power_disable_otg();
+}
+
 void mag_scene_emulate_test_on_enter(void* context) {
     Mag* mag = context;
-    UNUSED(mag);
+    Widget* widget = mag->widget;
+
+    FuriString* tmp_string;
+    tmp_string = furi_string_alloc();
+
+    widget_add_button_element(widget, GuiButtonTypeLeft, "Back", mag_widget_callback, mag);
+    widget_add_button_element(widget, GuiButtonTypeCenter, "Emulate", mag_widget_callback, mag);
+
+    furi_string_printf(tmp_string, "Emulate?");
+    widget_add_string_element(
+        widget, 64, 0, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp_string));
+    furi_string_reset(tmp_string);
+
+    view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewWidget);
+    furi_string_free(tmp_string);
 }
 
 bool mag_scene_emulate_test_on_event(void* context, SceneManagerEvent event) {
     Mag* mag = context;
-    UNUSED(mag);
-    UNUSED(event);
+    SceneManager* scene_manager = mag->scene_manager;
     bool consumed = false;
 
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == DialogExResultCenter) {
+            consumed = true;
+
+            // Hardcoding a test string for the time being, while we debug/improve LF RFID TX
+            FuriString* v = furi_string_alloc();
+            furi_string_set_str(
+                v,
+                "%B123456781234567^LASTNAME/FIRST^YYMMSSSDDDDDDDDDDDDDDDDDDDDDDDDD?;1234567812?");
+            mag_spoof(v, 0);
+            furi_string_free(v);
+        } else if(event.event == GuiButtonTypeLeft) {
+            consumed = true;
+
+            scene_manager_previous_scene(scene_manager);
+        }
+    }
+
     return consumed;
 }
 
 void mag_scene_emulate_test_on_exit(void* context) {
     Mag* mag = context;
-    UNUSED(mag);
+    widget_reset(mag->widget);
 }