| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- #include "../mag_i.h"
- #define PIN_A 0
- #define PIN_B 1 // currently unused
- #define CLOCK_US 240 // typically set between 200-500us
- #define TEST_STR "%B123456781234567^LASTNAME/FIRST^YYMMSSSDDDDDDDDDDDDDDDDDDDDDDDDD?;1234567812?"
- // TODO: better way of setting temp test str,
- // text wrapping on screen? (Will be relevant for any loaded data too)
- uint8_t magspoof_bit_dir = 0;
- const char *test_str = TEST_STR;
- 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();
- // Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed setting
- // 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);
- // TODO: initialize pins on scene enter, perhaps, so as to avoid this delay each time the button is pressed?
- // Also, why is such a long delay needed?
- furi_delay_ms(300);
- // prevents interrupts &c. from impacting critical timings
- 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);
- // end critical timing section
- 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;
- 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, GuiButtonTypeRight, "Emulate", mag_widget_callback, mag);
- //furi_string_printf(tmp_string, test_str);
- //widget_add_string_element(
- // widget, 64, 0, AlignLeft, AlignTop, FontSecondary, 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;
- SceneManager *scene_manager = mag->scene_manager;
- bool consumed = false;
- if (event.type == SceneManagerEventTypeCustom) {
- if (event.event == GuiButtonTypeRight) {
- 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, test_str);
- // blink led while spoofing
- notification_message(mag->notifications, &sequence_blink_start_magenta);
- mag_spoof(v, 0);
- notification_message(mag->notifications, &sequence_blink_stop);
- 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;
- widget_reset(mag->widget);
- }
|