mag_helpers.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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_hal_gpio_write(GPIO_PIN_ENABLE, 1);
  86. furi_delay_ms(500);
  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. // Please forgive the mess. This was a bug battlezone. Will clean up over the weekend
  129. // So many stupid things done here, many learnings lol
  130. //FURI_LOG_D(TAG, "%d", strlen(track_data));
  131. //FURI_LOG_D(TAG, "%d", strlen(track_data) * bitlen[track_index]);
  132. // convert track data to bits
  133. for(uint8_t j = 0; track_data[j] != '\0'; j++) {
  134. crc = 1;
  135. tmp = track_data[j] - sublen[track_index];
  136. for(uint8_t k = 0; k < bitlen[track_index] - 1; k++) {
  137. crc ^= tmp & 1;
  138. lrc ^= (tmp & 1) << k;
  139. bit_array[i] = tmp & 1;
  140. //FURI_LOG_D(
  141. // TAG, "i, j, k: %d %d %d char %s bit %d", i, j, k, &track_data[j], bit_array[i]);
  142. i++;
  143. tmp >>= 1;
  144. }
  145. bit_array[i] = crc;
  146. //FURI_LOG_D(TAG, "i, j: %d %d char %s bit %d", i, j, &track_data[j], bit_array[i]);
  147. i++;
  148. }
  149. FURI_LOG_D(TAG, "LRC");
  150. // finish calculating final "byte" (LRC)
  151. tmp = lrc;
  152. crc = 1;
  153. for(uint8_t j = 0; j < bitlen[track_index] - 1; j++) {
  154. crc ^= tmp & 1;
  155. bit_array[i] = tmp & 1;
  156. //FURI_LOG_D(TAG, "i, j: %d %d bit %d", i, j, bit_array[i]);
  157. i++;
  158. tmp >>= 1;
  159. }
  160. bit_array[i] = crc;
  161. //FURI_LOG_D(TAG, "i: %d bit %d", i, bit_array[i]);
  162. i++;
  163. // My makeshift end sentinel. All other values 0/1
  164. bit_array[i] = 2;
  165. //FURI_LOG_D(TAG, "i: %d bit %d", i, bit_array[i]);
  166. i++;
  167. // Log the output (messy but works)
  168. //char output[500] = {0x0};
  169. /*FuriString* tmp_str;
  170. tmp_str = furi_string_alloc();
  171. for(uint8_t j = 0; bit_array[j] != 2; j++) {
  172. furi_string_cat_printf(tmp_str, "%d", (bit_array[j] & 1));
  173. //strcat(output, furi_string_get_cstr(tmp_str));
  174. }
  175. FURI_LOG_D(TAG, "Track %d: %s", (track_index + 1), track_data);
  176. FURI_LOG_D(TAG, "Track %d: %s", (track_index + 1), furi_string_get_cstr(tmp_str));*/
  177. //furi_string_free(tmp_str);
  178. }
  179. void mag_spoof(Mag* mag) {
  180. MagSetting* setting = mag->setting;
  181. // precompute tracks (WIP; ignores reverse and 3rd track)
  182. // likely will be reworked to antirez's bitmap method anyway...
  183. const char* data1 = furi_string_get_cstr(mag->mag_dev->dev_data.track[0].str);
  184. const char* data2 = furi_string_get_cstr(mag->mag_dev->dev_data.track[1].str);
  185. uint8_t bit_array1[2 * (strlen(data1) * bitlen[0]) + 1];
  186. uint8_t bit_array2[2 * (strlen(data2) * bitlen[1]) + 1];
  187. track_to_bits(bit_array1, data1, 0);
  188. track_to_bits(bit_array2, data2, 1);
  189. bool spoofed = false;
  190. do {
  191. // Initialize configured TX method
  192. if(!tx_init(setting)) break;
  193. // Critical timing section (need to eliminate ifs? does this impact timing?)
  194. FURI_CRITICAL_ENTER();
  195. // Prefix of zeros
  196. for(uint16_t i = 0; i < ZERO_PREFIX; i++) {
  197. if(!play_bit(0, setting)) break;
  198. }
  199. // Track 1
  200. if((setting->track == MagTrackStateAll) || (setting->track == MagTrackStateOne)) {
  201. for(uint16_t i = 0; bit_array1[i] != 2; i++) {
  202. if(!play_bit((bit_array1[i] & 1), setting)) break;
  203. }
  204. }
  205. // Zeros between tracks
  206. if(setting->track == MagTrackStateAll) {
  207. for(uint16_t i = 0; i < ZERO_BETWEEN; i++) {
  208. if(!play_bit(0, setting)) break;
  209. }
  210. }
  211. // Track 2 (TODO: Reverse track)
  212. if((setting->track == MagTrackStateAll) || (setting->track == MagTrackStateTwo)) {
  213. for(uint16_t i = 0; bit_array2[i] != 2; i++) {
  214. if(!play_bit((bit_array2[i] & 1), setting)) break;
  215. }
  216. }
  217. // Suffix of zeros
  218. for(uint16_t i = 0; i < ZERO_SUFFIX; i++) {
  219. if(!play_bit(0, setting)) break;
  220. }
  221. FURI_CRITICAL_EXIT();
  222. // Reset configured TX method
  223. if(!tx_reset(setting)) break;
  224. spoofed = true;
  225. } while(0);
  226. UNUSED(spoofed);
  227. /*if(!spoofed) {
  228. // error handling?
  229. // cleanup?
  230. }*/
  231. }
  232. //// @antirez's code from protoview for bitmapping. May want to refactor to use this...
  233. /* Set the 'bitpos' bit to value 'val', in the specified bitmap
  234. * 'b' of len 'blen'.
  235. * Out of range bits will silently be discarded. */
  236. void set_bit(uint8_t* b, uint32_t blen, uint32_t bitpos, bool val) {
  237. uint32_t byte = bitpos / 8;
  238. uint32_t bit = bitpos & 7;
  239. if(byte >= blen) return;
  240. if(val)
  241. b[byte] |= 1 << bit;
  242. else
  243. b[byte] &= ~(1 << bit);
  244. }
  245. /* Get the bit 'bitpos' of the bitmap 'b' of 'blen' bytes.
  246. * Out of range bits return false (not bit set). */
  247. bool get_bit(uint8_t* b, uint32_t blen, uint32_t bitpos) {
  248. uint32_t byte = bitpos / 8;
  249. uint32_t bit = bitpos & 7;
  250. if(byte >= blen) return 0;
  251. return (b[byte] & (1 << bit)) != 0;
  252. }
  253. /*uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s, uint32_t idx, uint32_t count, uint32_t rate) {
  254. if (rate == 0) return 0; // We can't perform the conversion.
  255. uint32_t bitpos = 0;
  256. for (uint32_t j = 0; j < count; j++) {
  257. uint32_t dur;
  258. bool level;
  259. raw_samples_get(s, j+idx, &level, &dur);
  260. uint32_t numbits = dur / rate; // full bits that surely fit.
  261. uint32_t rest = dur % rate; // How much we are left with.
  262. if (rest > rate/2) numbits++; // There is another one.
  263. while(numbits--) set_bit(b,blen,bitpos++,s[j].level);
  264. }
  265. return bitpos;
  266. }*/