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

Merge magspoof from https://github.com/zacharyweiss/magspoof_flipper

Willy-JL 1 год назад
Родитель
Сommit
6bac51db64

+ 1 - 1
magspoof/application.fam

@@ -17,7 +17,7 @@ App(
     fap_category="GPIO",
     fap_icon_assets="icons",
     fap_icon_assets_symbol="mag",
-    fap_version=(0, 7),  # major, minor
+    fap_version=(0, 8),  # major, minor
     fap_description="Enables wireless transmission of magstripe data",
     fap_author="Zachary Weiss",
     fap_weburl="https://github.com/zacharyweiss/magspoof_flipper",

+ 36 - 26
magspoof/helpers/mag_helpers.c

@@ -5,6 +5,7 @@
 #define ZERO_PREFIX 25 // n zeros prefix
 #define ZERO_BETWEEN 53 // n zeros between tracks
 #define ZERO_SUFFIX 25 // n zeros suffix
+#define REPEAT_DELAY_MS 50
 
 // bits per char on a given track
 const uint8_t bitlen[] = {7, 5, 5};
@@ -331,40 +332,49 @@ void mag_spoof(Mag* mag) {
 
     if(!tx_init(state)) return;
 
-    FURI_CRITICAL_ENTER();
-    for(uint16_t i = 0; i < (ZERO_PREFIX * 2); i++) {
-        // is this right?
-        if(!!(i % 2)) bit ^= 1;
-        play_halfbit(bit, state);
-        furi_delay_us(state->us_clock);
-    }
+    uint8_t i = 0;
+    do {
+        FURI_CRITICAL_ENTER();
+        for(uint16_t i = 0; i < (ZERO_PREFIX * 2); i++) {
+            // is this right?
+            if(!!(i % 2)) bit ^= 1;
+            play_halfbit(bit, state);
+            furi_delay_us(state->us_clock);
+        }
+
+        if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateOne))
+            play_track((uint8_t*)bits_t1_manchester, bits_t1_count, state, false);
 
-    if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateOne))
-        play_track((uint8_t*)bits_t1_manchester, bits_t1_count, state, false);
+        if((state->track == MagTrackStateOneAndTwo))
+            for(uint16_t i = 0; i < (ZERO_BETWEEN * 2); i++) {
+                if(!!(i % 2)) bit ^= 1;
+                play_halfbit(bit, state);
+                furi_delay_us(state->us_clock);
+            }
 
-    if((state->track == MagTrackStateOneAndTwo))
-        for(uint16_t i = 0; i < (ZERO_BETWEEN * 2); i++) {
+        if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateTwo))
+            play_track(
+                (uint8_t*)bits_t2_manchester,
+                bits_t2_count,
+                state,
+                (state->reverse == MagReverseStateOn));
+
+        if((state->track == MagTrackStateThree))
+            play_track((uint8_t*)bits_t3_manchester, bits_t3_count, state, false);
+
+        for(uint16_t i = 0; i < (ZERO_SUFFIX * 2); i++) {
             if(!!(i % 2)) bit ^= 1;
             play_halfbit(bit, state);
             furi_delay_us(state->us_clock);
         }
+        FURI_CRITICAL_EXIT();
 
-    if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateTwo))
-        play_track(
-            (uint8_t*)bits_t2_manchester,
-            bits_t2_count,
-            state,
-            (state->reverse == MagReverseStateOn));
-
-    if((state->track == MagTrackStateThree))
-        play_track((uint8_t*)bits_t3_manchester, bits_t3_count, state, false);
+        i++;
+        FURI_LOG_D(
+            TAG, "TX %u (n_repeats: %u, repeat_mode: %u)", i, state->n_repeats, state->repeat_mode);
+        furi_delay_ms(REPEAT_DELAY_MS);
 
-    for(uint16_t i = 0; i < (ZERO_SUFFIX * 2); i++) {
-        if(!!(i % 2)) bit ^= 1;
-        play_halfbit(bit, state);
-        furi_delay_us(state->us_clock);
-    }
-    FURI_CRITICAL_EXIT();
+    } while((i < state->n_repeats) && state->repeat_mode);
 
     free(data1);
     free(data2);

+ 2 - 0
magspoof/helpers/mag_types.h

@@ -46,6 +46,8 @@ typedef enum {
 #define MAG_STATE_DEFAULT_PIN_OUTPUT MagPinA6
 #define MAG_STATE_DEFAULT_PIN_ENABLE MagPinA4
 #define MAG_STATE_DEFAULT_ALLOW_UART false
+#define MAG_STATE_DEFAULT_N_REPEATS 3
+#define MAG_STATE_DEFAULT_REPEAT_MODE true
 
 typedef enum {
     MagViewSubmenu,

+ 14 - 6
magspoof/mag_state.c

@@ -53,12 +53,15 @@ bool mag_state_load(MagState* out_state) {
             if(tmp != MAG_STATE_VER) break;
 
             if(!flipper_format_read_uint32(file, "pin_input", &tmp, 1)) break;
-            state.pin_input = tmp;
+            state.pin_input = (MagPin)tmp;
             if(!flipper_format_read_uint32(file, "pin_output", &tmp, 1)) break;
-            state.pin_output = tmp;
+            state.pin_output = (MagPin)tmp;
             if(!flipper_format_read_uint32(file, "pin_enable", &tmp, 1)) break;
-            state.pin_enable = tmp;
+            state.pin_enable = (MagPin)tmp;
             if(!flipper_format_read_bool(file, "allow_uart", &state.allow_uart, 1)) break;
+            if(!flipper_format_read_uint32(file, "n_repeats", &tmp, 1)) break;
+            state.n_repeats = (uint8_t)tmp;
+            if(!flipper_format_read_bool(file, "repeat_mode", &state.repeat_mode, 1)) break;
 
             loaded_from_file = true;
         } while(0);
@@ -76,6 +79,8 @@ bool mag_state_load(MagState* out_state) {
 
     if(!loaded_from_file) {
         state.allow_uart = MAG_STATE_DEFAULT_ALLOW_UART;
+        state.n_repeats = MAG_STATE_DEFAULT_N_REPEATS;
+        state.repeat_mode = MAG_STATE_DEFAULT_REPEAT_MODE;
     }
 
     // set defaults we don't save
@@ -102,13 +107,16 @@ void mag_state_save(MagState* state) {
         if(!flipper_format_file_open_always(file, MAG_STATE_PATH)) break;
         if(!flipper_format_write_header_cstr(file, MAG_STATE_HEADER, MAG_STATE_VER)) break;
 
-        tmp = state->pin_input;
+        tmp = (uint32_t)state->pin_input;
         if(!flipper_format_write_uint32(file, "pin_input", &tmp, 1)) break;
-        tmp = state->pin_output;
+        tmp = (uint32_t)state->pin_output;
         if(!flipper_format_write_uint32(file, "pin_output", &tmp, 1)) break;
-        tmp = state->pin_enable;
+        tmp = (uint32_t)state->pin_enable;
         if(!flipper_format_write_uint32(file, "pin_enable", &tmp, 1)) break;
         if(!flipper_format_write_bool(file, "allow_uart", &state->allow_uart, 1)) break;
+        tmp = (uint32_t)state->n_repeats;
+        if(!flipper_format_write_uint32(file, "n_repeats", &tmp, 1)) break;
+        if(!flipper_format_write_bool(file, "repeat_mode", &state->repeat_mode, 1)) break;
 
     } while(0);
     flipper_format_free(file);

+ 3 - 1
magspoof/mag_state.h

@@ -14,7 +14,7 @@
 #include "helpers/mag_types.h"
 
 #define MAG_STATE_HEADER "Mag State"
-#define MAG_STATE_VER 1
+#define MAG_STATE_VER 2
 #define MAG_STATE_DIR STORAGE_APP_DATA_PATH_PREFIX
 #define MAG_STATE_PATH MAG_STATE_DIR "/mag_state.txt"
 
@@ -29,6 +29,8 @@ typedef struct {
     MagPin pin_enable;
     bool allow_uart;
     bool is_debug;
+    uint8_t n_repeats;
+    bool repeat_mode;
 } MagState;
 
 const GpioPin* mag_state_enum_to_pin(MagPin pin);

+ 32 - 9
magspoof/scenes/mag_scene_emulate_config.c

@@ -3,11 +3,12 @@
 #define TAG "MagSceneEmulateConfig"
 
 enum MagEmulateConfigIndex {
-    MagEmulateConfigIndexTx,
+    MagEmulateConfigIndexClock,
     MagEmulateConfigIndexTrack,
     MagEmulateConfigIndexReverse,
-    MagEmulateConfigIndexClock,
-    MagEmulateConfigIndexInterpacket,
+    MagEmulateConfigIndexRepeat,
+    MagEmulateConfigIndexTx,
+    // MagEmulateConfigIndexInterpacket,
 };
 
 #define TX_COUNT 7
@@ -163,6 +164,14 @@ static void mag_scene_emulate_config_set_reverse(VariableItem* item) {
     }
 };
 
+static void mag_scene_emulate_config_set_repeat_mode(VariableItem* item) {
+    Mag* mag = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, reverse_text[index]);
+
+    mag->state.repeat_mode = (bool)index;
+}
+
 static void mag_scene_emulate_config_set_clock(VariableItem* item) {
     Mag* mag = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
@@ -190,7 +199,7 @@ void mag_scene_emulate_config_on_enter(void* context) {
     item = variable_item_list_add(
         mag->variable_item_list, "Clock:", CLOCK_COUNT, mag_scene_emulate_config_set_clock, mag);
     value_index = value_index_uint32(mag->state.us_clock, clock_value, CLOCK_COUNT);
-    scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
+    // scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, clock_text[value_index]);
 
@@ -198,7 +207,7 @@ void mag_scene_emulate_config_on_enter(void* context) {
     item = variable_item_list_add(
         mag->variable_item_list, "Track:", TRACK_COUNT, mag_scene_emulate_config_set_track, mag);
     value_index = value_index_uint32(mag->state.track, track_value, TRACK_COUNT);
-    scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
+    //scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, track_text[value_index]);
 
@@ -211,7 +220,19 @@ void mag_scene_emulate_config_on_enter(void* context) {
         mag_scene_emulate_config_set_reverse,
         mag);
     value_index = value_index_uint32(mag->state.reverse, reverse_value, REVERSE_COUNT);
-    scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
+    //scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, reverse_text[value_index]);
+
+    // Repeated TX
+    item = variable_item_list_add(
+        mag->variable_item_list,
+        "Repeat:",
+        REVERSE_COUNT,
+        mag_scene_emulate_config_set_repeat_mode,
+        mag);
+    value_index = (uint32_t)mag->state.repeat_mode;
+    //scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, reverse_text[value_index]);
 
@@ -222,7 +243,7 @@ void mag_scene_emulate_config_on_enter(void* context) {
         item = variable_item_list_add(
             mag->variable_item_list, "TX via:", TX_COUNT, mag_scene_emulate_config_set_tx, mag);
         value_index = value_index_uint32(mag->state.tx, tx_value, TX_COUNT);
-        scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
+        //scene_manager_set_scene_state(mag->scene_manager, MagSceneEmulateConfig, (uint32_t)item);
         variable_item_set_current_value_index(item, value_index);
         variable_item_set_current_value_text(item, tx_text[value_index]);
 #ifdef FW_ORIGIN_Official
@@ -245,6 +266,10 @@ void mag_scene_emulate_config_on_enter(void* context) {
     variable_item_set_current_value_text(item, interpacket_text[value_index]);*/
     UNUSED(mag_scene_emulate_config_set_interpacket);
 
+    variable_item_list_set_selected_item(
+        mag->variable_item_list,
+        scene_manager_get_scene_state(mag->scene_manager, MagSceneEmulateConfig));
+
     view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewVariableItemList);
 }
 
@@ -264,6 +289,4 @@ void mag_scene_emulate_config_on_exit(void* context) {
     Mag* mag = context;
     variable_item_list_set_selected_item(mag->variable_item_list, 0);
     variable_item_list_reset(mag->variable_item_list);
-    // mag_last_settings_save?
-    // scene_manager_set_scene_state? Using subghz_scene_reciever_config as framework/inspo
 }

+ 117 - 1
magspoof/scenes/mag_scene_settings.c

@@ -8,6 +8,8 @@ enum VarItemListIndex {
     VarItemListIndexPinInput,
     VarItemListIndexPinOutput,
     VarItemListIndexPinEnable,
+    VarItemListIndexNRepeats,
+    VarItemListIndexRepeatModeOn,
 #ifndef FW_ORIGIN_Official
     VarItemListIndexAllowUART,
 #endif
@@ -27,6 +29,38 @@ const uint8_t GPIO_COUNT = COUNT_OF(gpio);
 // static const char* uart_pins[] = {[DapUartTypeUSART1] = "13,14", [DapUartTypeLPUART1] = "15,16"};
 // static const char* uart_swap[] = {[DapUartTXRXNormal] = "No", [DapUartTXRXSwap] = "Yes"};
 
+#define N_REPEATS_COUNT 10
+const char* const n_repeats_text[N_REPEATS_COUNT] = {
+    "2",
+    "3",
+    "4",
+    "5",
+    "6",
+    "7",
+    "8",
+    "9",
+    "10",
+    "20",
+};
+const uint32_t n_repeats_value[N_REPEATS_COUNT] = {
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    20,
+};
+
+#define OFF_ON_COUNT 2
+const char* const off_on_text[OFF_ON_COUNT] = {
+    "OFF",
+    "ON",
+};
+
 void mag_scene_settings_var_item_list_callback(void* context, uint32_t index) {
     Mag* mag = context;
     view_dispatcher_send_custom_event(mag->view_dispatcher, index);
@@ -53,6 +87,55 @@ static void mag_scene_settings_set_gpio_enable(VariableItem* item) {
     mag_scene_settings_set_gpio(item, &mag->state.pin_enable);
 };
 
+static void mag_scene_settings_set_n_repeats(VariableItem* item) {
+    Mag* mag = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, n_repeats_text[index]);
+    mag->state.n_repeats = n_repeats_value[index];
+}
+
+static void mag_scene_settings_set_bool(VariableItem* item, bool* bool_out) {
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, off_on_text[index]);
+    *bool_out = (bool)index;
+}
+
+static void mag_scene_settings_set_repeat_mode(VariableItem* item) {
+    Mag* mag = variable_item_get_context(item);
+    mag_scene_settings_set_bool(item, &mag->state.repeat_mode);
+}
+
+/*
+static void mag_scene_settings_set_allow_uart(VariableItem* item) {
+    Mag* mag = variable_item_get_context(item);
+
+    bool rising = !(mag->state.allow_uart);
+    // trigger dialog only on rising change
+    if(rising) {
+        DialogMessage* msg = dialog_message_alloc();
+        dialog_message_set_header(msg, "UART MSR", 64, 0, AlignCenter, AlignTop);
+        dialog_message_set_buttons(msg, "No", NULL, "Yes");
+        dialog_message_set_text(
+            msg,
+            "This option requires a\nUART-compatible mag reader.\nIs it installed?\n",
+            64,
+            32,
+            AlignCenter,
+            AlignCenter);
+        DialogMessageButton res = dialog_message_show(furi_record_open(RECORD_DIALOGS), msg);
+        if(res != DialogMessageButtonRight) {
+            // if not "Yes", reset index
+            variable_item_set_current_value_index(item, (uint32_t)mag->state.allow_uart);
+        }
+        dialog_message_free(msg);
+        furi_record_close(RECORD_DIALOGS);
+    }
+
+    // set value & text based on current varitem index
+    mag_scene_settings_set_bool(item, &mag->state.allow_uart);
+}
+*/
+
 static void mag_pin_variable_item_list_add(
     Mag* mag,
     const char* label,
@@ -64,9 +147,30 @@ static void mag_pin_variable_item_list_add(
     variable_item_set_current_value_text(item, gpio[pin]);
 }
 
+static void mag_bool_variable_item_list_add(
+    Mag* mag,
+    const char* label,
+    bool value,
+    VariableItemChangeCallback change_callback) {
+    VariableItem* item =
+        variable_item_list_add(mag->variable_item_list, label, OFF_ON_COUNT, change_callback, mag);
+    uint32_t value_index = (uint32_t)value;
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, off_on_text[value_index]);
+}
+
 void mag_scene_settings_on_enter(void* context) {
     Mag* mag = context;
     VariableItemList* var_item_list = mag->variable_item_list;
+    VariableItem* item;
+    uint32_t value_index;
+
+    // reload state in the event temporary changes have been
+    // made on the emulate config screen
+    // only changes made in this scene should be saved, and this scene
+    // should always represent the saved settings, not the transient ones for
+    // a given emulation.
+    mag_state_load(&mag->state);
 
     mag_pin_variable_item_list_add(
         mag, "Input pin:", mag->state.pin_input, mag_scene_settings_set_gpio_input);
@@ -75,11 +179,23 @@ void mag_scene_settings_on_enter(void* context) {
     mag_pin_variable_item_list_add(
         mag, "Enable pin:", mag->state.pin_enable, mag_scene_settings_set_gpio_enable);
 
+    mag_bool_variable_item_list_add(
+        mag, "Repeat default:", mag->state.repeat_mode, mag_scene_settings_set_repeat_mode);
+
+    item = variable_item_list_add(
+        var_item_list, "# repeats: ", N_REPEATS_COUNT, mag_scene_settings_set_n_repeats, mag);
+    value_index = value_index_uint32(mag->state.n_repeats, n_repeats_value, N_REPEATS_COUNT);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, n_repeats_text[value_index]);
+
 #ifndef FW_ORIGIN_Official
-    VariableItem* item = variable_item_list_add(var_item_list, "UART MSR: ", 1, NULL, mag);
+    item = variable_item_list_add(var_item_list, "UART MSR: ", 1, NULL, mag);
     variable_item_set_current_value_text(item, mag->state.allow_uart ? "ON" : "OFF");
 #endif
 
+    //mag_bool_variable_item_list_add(
+    //    mag, "UART MSR:", mag->state.allow_uart, mag_scene_settings_set_allow_uart);
+
     variable_item_list_set_enter_callback(
         var_item_list, mag_scene_settings_var_item_list_callback, mag);