diff --git a/application.fam b/application.fam index 7d68ce32cbd..f51ffd2bf26 100644 --- a/application.fam +++ b/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", diff --git a/helpers/mag_helpers.c b/helpers/mag_helpers.c index 83bf6c322dc..762253c14d0 100644 --- a/helpers/mag_helpers.c +++ b/helpers/mag_helpers.c @@ -331,40 +331,47 @@ 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); - } - - 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++) { + 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 == MagTrackStateTwo)) - play_track( - (uint8_t*)bits_t2_manchester, - bits_t2_count, - state, - (state->reverse == MagReverseStateOn)); + if((state->track == MagTrackStateOneAndTwo) || (state->track == MagTrackStateOne)) + play_track((uint8_t*)bits_t1_manchester, bits_t1_count, state, false); - if((state->track == MagTrackStateThree)) - play_track((uint8_t*)bits_t3_manchester, bits_t3_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); + } - 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); + + 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(); + + i++; + FURI_LOG_D( + TAG, "TX %u (n_repeats: %u, repeat_mode: %u)", i, state->n_repeats, state->repeat_mode); + } while((i < state->n_repeats) && state->repeat_mode); free(data1); free(data2); diff --git a/helpers/mag_types.h b/helpers/mag_types.h index 898f876f82c..0d2593572af 100644 --- a/helpers/mag_types.h +++ b/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, diff --git a/mag_state.c b/mag_state.c index f1e4d89608b..13e051d0608 100644 --- a/mag_state.c +++ b/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); diff --git a/mag_state.h b/mag_state.h index b2e26623bfc..e7f1b8a3868 100644 --- a/mag_state.h +++ b/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); diff --git a/scenes/mag_scene_emulate_config.c b/scenes/mag_scene_emulate_config.c index 5c2e048f886..cd5106ab052 100644 --- a/scenes/mag_scene_emulate_config.c +++ b/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 } \ No newline at end of file diff --git a/scenes/mag_scene_settings.c b/scenes/mag_scene_settings.c index e920de34cd7..30b6e7a6b41 100644 --- a/scenes/mag_scene_settings.c +++ b/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);