mag_scene_emulate_test.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #include "../mag_i.h"
  2. #define PIN_A 0
  3. #define PIN_B 1 // currently unused
  4. #define CLOCK_US 250 // typically set between 200-500us
  5. uint8_t magspoof_bit_dir = 0;
  6. void mag_scene_emulate_test_dialog_callback(DialogExResult result, void* context) {
  7. Mag* mag = context;
  8. view_dispatcher_send_custom_event(mag->view_dispatcher, result);
  9. }
  10. void gpio_item_set_rfid_pin(uint8_t index, bool level) {
  11. if(index == 0) {
  12. furi_hal_gpio_write(&gpio_rfid_carrier_out, level);
  13. // A7 GPIO pin for debugging purposes
  14. //furi_hal_gpio_write(&gpio_ext_pa7, level);
  15. }
  16. }
  17. static void play_bit(uint8_t send_bit) {
  18. magspoof_bit_dir ^= 1;
  19. gpio_item_set_rfid_pin(PIN_A, magspoof_bit_dir);
  20. // PIN_B goes unused in current LF modulation.
  21. // Leaving legacy here in event we attempt downstream modulation,
  22. // rather than just modulating RFID_OUT upstream for signal forming
  23. gpio_item_set_rfid_pin(PIN_B, !magspoof_bit_dir);
  24. furi_delay_us(CLOCK_US);
  25. if(send_bit) {
  26. magspoof_bit_dir ^= 1;
  27. gpio_item_set_rfid_pin(PIN_A, magspoof_bit_dir);
  28. gpio_item_set_rfid_pin(PIN_B, !magspoof_bit_dir);
  29. }
  30. furi_delay_us(CLOCK_US);
  31. }
  32. static void mag_spoof(FuriString* track_str, uint8_t track) {
  33. furi_hal_power_enable_otg();
  34. size_t from;
  35. size_t to;
  36. // TODO ';' in first track case
  37. if(track == 0) {
  38. from = furi_string_search_char(track_str, '%');
  39. to = furi_string_search_char(track_str, '?', from);
  40. } else if(track == 1) {
  41. from = furi_string_search_char(track_str, ';');
  42. to = furi_string_search_char(track_str, '?', from);
  43. } else {
  44. from = 0;
  45. to = furi_string_size(track_str);
  46. }
  47. if(from >= to) {
  48. return;
  49. }
  50. furi_string_mid(track_str, from, to - from + 1);
  51. const char* data = furi_string_get_cstr(track_str);
  52. printf("%s", data);
  53. furi_hal_ibutton_start_drive();
  54. furi_hal_ibutton_pin_low();
  55. // this doesn't seem to make a difference, leaving it in
  56. furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  57. furi_hal_gpio_write(&gpio_rfid_data_in, false);
  58. // false->ground RFID antenna; true->don't ground
  59. // skotopes (RFID dev) say normally you'd want RFID_PULL in high for signal forming, while modulating RFID_OUT
  60. // dunaevai135 had it low in their old code. Leaving low, as it doesn't seem to make a difference on my janky antenna
  61. furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  62. furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
  63. furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  64. // A7 GPIO pin for debugging purposes
  65. //furi_hal_gpio_init(&gpio_ext_pa7, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  66. furi_delay_ms(300);
  67. FURI_CRITICAL_ENTER();
  68. const uint8_t bitlen[] = {7, 5, 5};
  69. const int sublen[] = {32, 48, 48};
  70. int tmp, crc, lrc = 0;
  71. magspoof_bit_dir = 0;
  72. // First put out a bunch of leading zeros.
  73. for(uint8_t i = 0; i < 25; i++) {
  74. play_bit(0);
  75. }
  76. for(uint8_t i = 0; data[i] != '\0'; i++) {
  77. crc = 1;
  78. tmp = data[i] - sublen[track];
  79. for(uint8_t j = 0; j < bitlen[track] - 1; j++) {
  80. crc ^= tmp & 1;
  81. lrc ^= (tmp & 1) << j;
  82. play_bit(tmp & 1);
  83. tmp >>= 1;
  84. }
  85. play_bit(crc);
  86. }
  87. // finish calculating and send last "byte" (LRC)
  88. tmp = lrc;
  89. crc = 1;
  90. for(uint8_t j = 0; j < bitlen[track] - 1; j++) {
  91. crc ^= tmp & 1;
  92. play_bit(tmp & 1);
  93. tmp >>= 1;
  94. }
  95. play_bit(crc);
  96. // finish with 0's
  97. for(uint8_t i = 0; i < 5 * 5; i++) {
  98. play_bit(0);
  99. }
  100. gpio_item_set_rfid_pin(PIN_A, 0);
  101. gpio_item_set_rfid_pin(PIN_B, 0);
  102. FURI_CRITICAL_EXIT();
  103. furi_hal_rfid_pins_reset();
  104. furi_hal_power_disable_otg();
  105. }
  106. void mag_scene_emulate_test_on_enter(void* context) {
  107. Mag* mag = context;
  108. Widget* widget = mag->widget;
  109. FuriString* tmp_string;
  110. tmp_string = furi_string_alloc();
  111. widget_add_button_element(widget, GuiButtonTypeLeft, "Back", mag_widget_callback, mag);
  112. widget_add_button_element(widget, GuiButtonTypeCenter, "Emulate", mag_widget_callback, mag);
  113. furi_string_printf(tmp_string, "Emulate?");
  114. widget_add_string_element(
  115. widget, 64, 0, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp_string));
  116. furi_string_reset(tmp_string);
  117. view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewWidget);
  118. furi_string_free(tmp_string);
  119. }
  120. bool mag_scene_emulate_test_on_event(void* context, SceneManagerEvent event) {
  121. Mag* mag = context;
  122. SceneManager* scene_manager = mag->scene_manager;
  123. bool consumed = false;
  124. if(event.type == SceneManagerEventTypeCustom) {
  125. if(event.event == DialogExResultCenter) {
  126. consumed = true;
  127. // Hardcoding a test string for the time being, while we debug/improve LF RFID TX
  128. FuriString* v = furi_string_alloc();
  129. furi_string_set_str(
  130. v,
  131. "%B123456781234567^LASTNAME/FIRST^YYMMSSSDDDDDDDDDDDDDDDDDDDDDDDDD?;1234567812?");
  132. mag_spoof(v, 0);
  133. furi_string_free(v);
  134. } else if(event.event == GuiButtonTypeLeft) {
  135. consumed = true;
  136. scene_manager_previous_scene(scene_manager);
  137. }
  138. }
  139. return consumed;
  140. }
  141. void mag_scene_emulate_test_on_exit(void* context) {
  142. Mag* mag = context;
  143. widget_reset(mag->widget);
  144. }