mag_helpers.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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
  157. char output[100] = {0x0};
  158. //FURI_LOG_D(TAG, "%s", bit_array);
  159. FuriString* tmp_str;
  160. tmp_str = furi_string_alloc();
  161. for(uint8_t j = 0; bit_array[j] != 2; j++) {
  162. furi_string_printf(tmp_str, "%d", (bit_array[j] & 1));
  163. strcat(output, furi_string_get_cstr(tmp_str));
  164. }
  165. FURI_LOG_D(TAG, "Track %d: %s", (track_index + 1), output);
  166. furi_string_free(tmp_str);
  167. //bool is_correct_length = (i == (strlen(track_data) * bitlen[track_index]));
  168. //furi_assert(is_correct_length);
  169. }
  170. void mag_spoof(Mag* mag) {
  171. MagSetting* setting = mag->setting;
  172. // precompute tracks (WIP; ignores reverse and 3rd track)
  173. // likely will be reworked to Samy's bitmap method anyway...
  174. const char* data1 = furi_string_get_cstr(mag->mag_dev->dev_data.track[0].str);
  175. const char* data2 = furi_string_get_cstr(mag->mag_dev->dev_data.track[1].str);
  176. uint8_t bit_array1[(strlen(data1) * bitlen[0]) + 1];
  177. uint8_t bit_array2[(strlen(data2) * bitlen[1]) + 1];
  178. track_to_bits(bit_array1, data1, 0);
  179. track_to_bits(bit_array2, data2, 1);
  180. bool spoofed = false;
  181. do {
  182. // Initialize configured TX method
  183. if(!tx_init(setting)) break;
  184. // Critical timing section (need to eliminate ifs? does this impact timing?)
  185. FURI_CRITICAL_ENTER();
  186. // Prefix of zeros
  187. for(uint8_t i = 0; i < ZERO_PREFIX; i++) {
  188. if(!play_bit(0, setting)) break;
  189. }
  190. // Track 1
  191. if((setting->track == MagTrackStateAll) || (setting->track == MagTrackStateOne)) {
  192. for(uint8_t i = 0; bit_array1[i] != 2; i++) {
  193. if(!play_bit((bit_array1[i] & 1), setting)) break;
  194. }
  195. }
  196. // Zeros between tracks
  197. if(setting->track == MagTrackStateAll) {
  198. for(uint8_t i = 0; i < ZERO_BETWEEN; i++) {
  199. if(!play_bit(0, setting)) break;
  200. }
  201. }
  202. // Track 2 (TODO: Reverse track)
  203. if((setting->track == MagTrackStateAll) || (setting->track == MagTrackStateTwo)) {
  204. for(uint8_t i = 0; bit_array2[i] != 2; i++) {
  205. if(!play_bit((bit_array2[i] & 1), setting)) break;
  206. }
  207. }
  208. // Suffix of zeros
  209. for(uint8_t i = 0; i < ZERO_SUFFIX; i++) {
  210. if(!play_bit(0, setting)) break;
  211. }
  212. FURI_CRITICAL_EXIT();
  213. // Reset configured TX method
  214. if(!tx_reset(setting)) break;
  215. spoofed = true;
  216. } while(0);
  217. UNUSED(spoofed);
  218. /*if(!spoofed) {
  219. // error handling?
  220. // cleanup?
  221. }*/
  222. }
  223. //// @antirez's code from protoview for bitmapping. May want to refactor to use this...
  224. /* Set the 'bitpos' bit to value 'val', in the specified bitmap
  225. * 'b' of len 'blen'.
  226. * Out of range bits will silently be discarded. */
  227. void set_bit(uint8_t* b, uint32_t blen, uint32_t bitpos, bool val) {
  228. uint32_t byte = bitpos / 8;
  229. uint32_t bit = bitpos & 7;
  230. if(byte >= blen) return;
  231. if(val)
  232. b[byte] |= 1 << bit;
  233. else
  234. b[byte] &= ~(1 << bit);
  235. }
  236. /* Get the bit 'bitpos' of the bitmap 'b' of 'blen' bytes.
  237. * Out of range bits return false (not bit set). */
  238. bool get_bit(uint8_t* b, uint32_t blen, uint32_t bitpos) {
  239. uint32_t byte = bitpos / 8;
  240. uint32_t bit = bitpos & 7;
  241. if(byte >= blen) return 0;
  242. return (b[byte] & (1 << bit)) != 0;
  243. }
  244. /*uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s, uint32_t idx, uint32_t count, uint32_t rate) {
  245. if (rate == 0) return 0; // We can't perform the conversion.
  246. uint32_t bitpos = 0;
  247. for (uint32_t j = 0; j < count; j++) {
  248. uint32_t dur;
  249. bool level;
  250. raw_samples_get(s, j+idx, &level, &dur);
  251. uint32_t numbits = dur / rate; // full bits that surely fit.
  252. uint32_t rest = dur % rate; // How much we are left with.
  253. if (rest > rate/2) numbits++; // There is another one.
  254. while(numbits--) set_bit(b,blen,bitpos++,s[j].level);
  255. }
  256. return bitpos;
  257. }*/