mag_helpers.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include "mag_helpers.h"
  2. #define TAG "MagHelpers"
  3. #define GPIO_PIN_A &gpio_ext_pa6
  4. #define GPIO_PIN_B &gpio_ext_pa7
  5. #define GPIO_PIN_ENABLE &gpio_ext_pa4
  6. #define RFID_PIN_OUT &gpio_rfid_carrier_out
  7. #define ZERO_PREFIX 25 // n zeros prefix
  8. #define ZERO_BETWEEN 53 // n zeros between tracks
  9. #define ZERO_SUFFIX 25 // n zeros suffix
  10. // bits per char on a given track
  11. const uint8_t bitlen[] = {7, 5, 5};
  12. // char offset by track
  13. const int sublen[] = {32, 48, 48};
  14. uint8_t bit_dir = 0;
  15. void play_bit_rfid(uint8_t send_bit, MagSetting* setting) {
  16. // internal TX over RFID coil
  17. bit_dir ^= 1;
  18. furi_hal_gpio_write(RFID_PIN_OUT, bit_dir);
  19. furi_delay_us(setting->us_clock);
  20. if(send_bit) {
  21. bit_dir ^= 1;
  22. furi_hal_gpio_write(RFID_PIN_OUT, bit_dir);
  23. }
  24. furi_delay_us(setting->us_clock);
  25. furi_delay_us(setting->us_interpacket);
  26. }
  27. void play_bit_gpio(uint8_t send_bit, MagSetting* setting) {
  28. // external TX over motor driver wired to PIN_A and PIN_B
  29. bit_dir ^= 1;
  30. furi_hal_gpio_write(GPIO_PIN_A, bit_dir);
  31. furi_hal_gpio_write(GPIO_PIN_B, !bit_dir);
  32. furi_delay_us(setting->us_clock);
  33. if(send_bit) {
  34. bit_dir ^= 1;
  35. furi_hal_gpio_write(GPIO_PIN_A, bit_dir);
  36. furi_hal_gpio_write(GPIO_PIN_B, !bit_dir);
  37. }
  38. furi_delay_us(setting->us_clock);
  39. furi_delay_us(setting->us_interpacket);
  40. }
  41. bool play_bit(uint8_t send_bit, MagSetting* setting) {
  42. // Initialize configured TX method
  43. switch(setting->tx) {
  44. case MagTxStateRFID:
  45. play_bit_rfid(send_bit, setting);
  46. break;
  47. case MagTxStateGPIOA6A7:
  48. play_bit_gpio(send_bit, setting);
  49. break;
  50. default:
  51. return false;
  52. }
  53. return true;
  54. }
  55. void tx_init_rfid() {
  56. // initialize RFID system for TX
  57. furi_hal_power_enable_otg();
  58. furi_hal_ibutton_start_drive();
  59. furi_hal_ibutton_pin_low();
  60. // Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed setting
  61. // this doesn't seem to make a difference, leaving it in
  62. furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  63. furi_hal_gpio_write(&gpio_rfid_data_in, false);
  64. // false->ground RFID antenna; true->don't ground
  65. // skotopes (RFID dev) say normally you'd want RFID_PULL in high for signal forming, while modulating RFID_OUT
  66. // dunaevai135 had it low in their old code. Leaving low, as it doesn't seem to make a difference on my janky antenna
  67. furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  68. furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
  69. furi_hal_gpio_init(RFID_PIN_OUT, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  70. // confirm this delay is needed / sufficient? legacy from hackathon...
  71. furi_delay_ms(300);
  72. }
  73. void tx_reset_rfid() {
  74. // reset RFID system
  75. furi_hal_gpio_write(RFID_PIN_OUT, 0);
  76. furi_hal_rfid_pins_reset();
  77. furi_hal_power_disable_otg();
  78. }
  79. void tx_init_gpio() {
  80. furi_hal_power_enable_otg();
  81. // gpio_item_configure_all_pins(GpioModeOutputPushPull);
  82. furi_hal_gpio_init(GPIO_PIN_A, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  83. furi_hal_gpio_init(GPIO_PIN_B, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  84. furi_hal_gpio_init(GPIO_PIN_ENABLE, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  85. furi_delay_ms(300);
  86. furi_hal_gpio_write(GPIO_PIN_ENABLE, 1);
  87. }
  88. void tx_reset_gpio() {
  89. furi_hal_gpio_write(GPIO_PIN_A, 0);
  90. furi_hal_gpio_write(GPIO_PIN_B, 0);
  91. furi_hal_gpio_write(GPIO_PIN_ENABLE, 0);
  92. // set back to analog output mode?
  93. //gpio_item_configure_all_pins(GpioModeAnalog);
  94. furi_hal_power_disable_otg();
  95. }
  96. bool tx_init(MagSetting* setting) {
  97. // Initialize configured TX method
  98. switch(setting->tx) {
  99. case MagTxStateRFID:
  100. tx_init_rfid();
  101. break;
  102. case MagTxStateGPIOA6A7:
  103. tx_init_gpio();
  104. break;
  105. default:
  106. return false;
  107. }
  108. return true;
  109. }
  110. bool tx_reset(MagSetting* setting) {
  111. // Reset configured TX method
  112. switch(setting->tx) {
  113. case MagTxStateRFID:
  114. tx_reset_rfid();
  115. break;
  116. case MagTxStateGPIOA6A7:
  117. tx_reset_gpio();
  118. break;
  119. default:
  120. return false;
  121. }
  122. return true;
  123. }
  124. void track_to_bits(uint8_t* bit_array, const char* track_data, uint8_t track_index) {
  125. // convert individual track to bits
  126. int tmp, crc, lrc = 0;
  127. int i = 0;
  128. // convert track data to bits
  129. for(uint8_t j = 0; track_data[i] != '\0'; j++) {
  130. crc = 1;
  131. tmp = track_data[j] - sublen[track_index];
  132. for(uint8_t k = 0; k < bitlen[track_index] - 1; k++) {
  133. crc ^= tmp & 1;
  134. lrc ^= (tmp & 1) << k;
  135. bit_array[i] = tmp & 1;
  136. i++;
  137. tmp >>= 1;
  138. }
  139. bit_array[i] = crc;
  140. i++;
  141. }
  142. // finish calculating final "byte" (LRC)
  143. tmp = lrc;
  144. crc = 1;
  145. for(uint8_t j = 0; j < bitlen[track_index] - 1; j++) {
  146. crc ^= tmp & 1;
  147. bit_array[i] = tmp & 1;
  148. i++;
  149. tmp >>= 1;
  150. }
  151. bit_array[i] = crc;
  152. i++;
  153. // My makeshift end sentinel. All other values 0/1
  154. bit_array[i] = 2;
  155. i++;
  156. // Log the output (messy but works)
  157. char output[100] = {0x0};
  158. FuriString* tmp_str;
  159. tmp_str = furi_string_alloc();
  160. for(uint8_t j = 0; bit_array[j] != 2; j++) {
  161. furi_string_printf(tmp_str, "%d", (bit_array[j] & 1));
  162. strcat(output, furi_string_get_cstr(tmp_str));
  163. }
  164. FURI_LOG_D(TAG, "Track %d: %s", (track_index + 1), output);
  165. furi_string_free(tmp_str);
  166. }
  167. void mag_spoof(Mag* mag) {
  168. MagSetting* setting = mag->setting;
  169. // precompute tracks (WIP; ignores reverse and 3rd track)
  170. // likely will be reworked to antirez's bitmap method anyway...
  171. const char* data1 = furi_string_get_cstr(mag->mag_dev->dev_data.track[0].str);
  172. const char* data2 = furi_string_get_cstr(mag->mag_dev->dev_data.track[1].str);
  173. uint8_t bit_array1[(strlen(data1) * bitlen[0]) + 1];
  174. uint8_t bit_array2[(strlen(data2) * bitlen[1]) + 1];
  175. track_to_bits(bit_array1, data1, 0);
  176. track_to_bits(bit_array2, data2, 1);
  177. bool spoofed = false;
  178. do {
  179. // Initialize configured TX method
  180. if(!tx_init(setting)) break;
  181. // Critical timing section (need to eliminate ifs? does this impact timing?)
  182. FURI_CRITICAL_ENTER();
  183. // Prefix of zeros
  184. for(uint8_t i = 0; i < ZERO_PREFIX; i++) {
  185. if(!play_bit(0, setting)) break;
  186. }
  187. // Track 1
  188. if((setting->track == MagTrackStateAll) || (setting->track == MagTrackStateOne)) {
  189. for(uint8_t i = 0; bit_array1[i] != 2; i++) {
  190. if(!play_bit((bit_array1[i] & 1), setting)) break;
  191. }
  192. }
  193. // Zeros between tracks
  194. if(setting->track == MagTrackStateAll) {
  195. for(uint8_t i = 0; i < ZERO_BETWEEN; i++) {
  196. if(!play_bit(0, setting)) break;
  197. }
  198. }
  199. // Track 2 (TODO: Reverse track)
  200. if((setting->track == MagTrackStateAll) || (setting->track == MagTrackStateTwo)) {
  201. for(uint8_t i = 0; bit_array2[i] != 2; i++) {
  202. if(!play_bit((bit_array2[i] & 1), setting)) break;
  203. }
  204. }
  205. // Suffix of zeros
  206. for(uint8_t i = 0; i < ZERO_SUFFIX; i++) {
  207. if(!play_bit(0, setting)) break;
  208. }
  209. FURI_CRITICAL_EXIT();
  210. // Reset configured TX method
  211. if(!tx_reset(setting)) break;
  212. spoofed = true;
  213. } while(0);
  214. UNUSED(spoofed);
  215. /*if(!spoofed) {
  216. // error handling?
  217. // cleanup?
  218. }*/
  219. }
  220. //// @antirez's code from protoview for bitmapping. May want to refactor to use this...
  221. /* Set the 'bitpos' bit to value 'val', in the specified bitmap
  222. * 'b' of len 'blen'.
  223. * Out of range bits will silently be discarded. */
  224. void set_bit(uint8_t* b, uint32_t blen, uint32_t bitpos, bool val) {
  225. uint32_t byte = bitpos / 8;
  226. uint32_t bit = bitpos & 7;
  227. if(byte >= blen) return;
  228. if(val)
  229. b[byte] |= 1 << bit;
  230. else
  231. b[byte] &= ~(1 << bit);
  232. }
  233. /* Get the bit 'bitpos' of the bitmap 'b' of 'blen' bytes.
  234. * Out of range bits return false (not bit set). */
  235. bool get_bit(uint8_t* b, uint32_t blen, uint32_t bitpos) {
  236. uint32_t byte = bitpos / 8;
  237. uint32_t bit = bitpos & 7;
  238. if(byte >= blen) return 0;
  239. return (b[byte] & (1 << bit)) != 0;
  240. }
  241. /*uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s, uint32_t idx, uint32_t count, uint32_t rate) {
  242. if (rate == 0) return 0; // We can't perform the conversion.
  243. uint32_t bitpos = 0;
  244. for (uint32_t j = 0; j < count; j++) {
  245. uint32_t dur;
  246. bool level;
  247. raw_samples_get(s, j+idx, &level, &dur);
  248. uint32_t numbits = dur / rate; // full bits that surely fit.
  249. uint32_t rest = dur % rate; // How much we are left with.
  250. if (rest > rate/2) numbits++; // There is another one.
  251. while(numbits--) set_bit(b,blen,bitpos++,s[j].level);
  252. }
  253. return bitpos;
  254. }*/