all_in_one.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #include "nfc_supported_card.h"
  2. #include "all_in_one.h"
  3. #include <gui/modules/widget.h>
  4. #include <nfc_worker_i.h>
  5. #include "furi_hal.h"
  6. #define ALL_IN_ONE_LAYOUT_UNKNOWN 0
  7. #define ALL_IN_ONE_LAYOUT_A 1
  8. #define ALL_IN_ONE_LAYOUT_D 2
  9. #define ALL_IN_ONE_LAYOUT_E2 3
  10. #define ALL_IN_ONE_LAYOUT_E3 4
  11. #define ALL_IN_ONE_LAYOUT_E5 5
  12. #define ALL_IN_ONE_LAYOUT_2 6
  13. uint8_t all_in_one_get_layout(NfcDeviceData* dev_data) {
  14. // I absolutely hate what's about to happen here.
  15. // Switch on the second half of the third byte of page 5
  16. FURI_LOG_I("all_in_one", "Layout byte: %02x", dev_data->mf_ul_data.data[(4 * 5) + 2]);
  17. FURI_LOG_I(
  18. "all_in_one", "Layout half-byte: %02x", dev_data->mf_ul_data.data[(4 * 5) + 3] & 0x0F);
  19. switch(dev_data->mf_ul_data.data[(4 * 5) + 2] & 0x0F) {
  20. // If it is A, the layout type is a type A layout
  21. case 0x0A:
  22. return ALL_IN_ONE_LAYOUT_A;
  23. case 0x0D:
  24. return ALL_IN_ONE_LAYOUT_D;
  25. case 0x02:
  26. return ALL_IN_ONE_LAYOUT_2;
  27. default:
  28. FURI_LOG_I(
  29. "all_in_one",
  30. "Unknown layout type: %d",
  31. dev_data->mf_ul_data.data[(4 * 5) + 2] & 0x0F);
  32. return ALL_IN_ONE_LAYOUT_UNKNOWN;
  33. }
  34. }
  35. bool all_in_one_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
  36. UNUSED(nfc_worker);
  37. // If this is a all_in_one pass, first 2 bytes of page 4 are 0x45 0xD9
  38. MfUltralightReader reader = {};
  39. MfUltralightData data = {};
  40. if(!mf_ul_read_card(tx_rx, &reader, &data)) {
  41. return false;
  42. } else {
  43. if(data.data[4 * 4] == 0x45 && data.data[4 * 4 + 1] == 0xD9) {
  44. FURI_LOG_I("all_in_one", "Pass verified");
  45. return true;
  46. }
  47. }
  48. return false;
  49. }
  50. bool all_in_one_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
  51. MfUltralightReader reader = {};
  52. MfUltralightData data = {};
  53. if(!mf_ul_read_card(tx_rx, &reader, &data)) {
  54. return false;
  55. } else {
  56. memcpy(&nfc_worker->dev_data->mf_ul_data, &data, sizeof(data));
  57. FURI_LOG_I("all_in_one", "Card read");
  58. return true;
  59. }
  60. }
  61. bool all_in_one_parser_parse(NfcDeviceData* dev_data) {
  62. if(dev_data->mf_ul_data.data[4 * 4] != 0x45 || dev_data->mf_ul_data.data[4 * 4 + 1] != 0xD9) {
  63. FURI_LOG_I("all_in_one", "Pass not verified");
  64. return false;
  65. }
  66. // If the layout is a then the ride count is stored in the first byte of page 8
  67. uint8_t ride_count = 0;
  68. uint32_t serial = 0;
  69. if(all_in_one_get_layout(dev_data) == ALL_IN_ONE_LAYOUT_A) {
  70. ride_count = dev_data->mf_ul_data.data[4 * 8];
  71. } else if(all_in_one_get_layout(dev_data) == ALL_IN_ONE_LAYOUT_D) {
  72. // If the layout is D, the ride count is stored in the second byte of page 9
  73. ride_count = dev_data->mf_ul_data.data[4 * 9 + 1];
  74. // I hate this with a burning passion.
  75. // The number starts at the second half of the third byte on page 4, and is 32 bits long
  76. // So we get the second half of the third byte, then bytes 4-6, and then the first half of the 7th byte
  77. // B8 17 A2 A4 BD becomes 81 7A 2A 4B
  78. serial = (dev_data->mf_ul_data.data[4 * 4 + 2] & 0x0F) << 28 |
  79. dev_data->mf_ul_data.data[4 * 4 + 3] << 20 |
  80. dev_data->mf_ul_data.data[4 * 4 + 4] << 12 |
  81. dev_data->mf_ul_data.data[4 * 4 + 5] << 4 |
  82. (dev_data->mf_ul_data.data[4 * 4 + 6] >> 4);
  83. } else {
  84. FURI_LOG_I("all_in_one", "Unknown layout: %d", all_in_one_get_layout(dev_data));
  85. ride_count = 137;
  86. }
  87. // I hate this with a burning passion.
  88. // The number starts at the second half of the third byte on page 4, and is 32 bits long
  89. // So we get the second half of the third byte, then bytes 4-6, and then the first half of the 7th byte
  90. // B8 17 A2 A4 BD becomes 81 7A 2A 4B
  91. serial =
  92. (dev_data->mf_ul_data.data[4 * 4 + 2] & 0x0F) << 28 |
  93. dev_data->mf_ul_data.data[4 * 4 + 3] << 20 | dev_data->mf_ul_data.data[4 * 4 + 4] << 12 |
  94. dev_data->mf_ul_data.data[4 * 4 + 5] << 4 | (dev_data->mf_ul_data.data[4 * 4 + 6] >> 4);
  95. // Format string for rides count
  96. furi_string_printf(
  97. dev_data->parsed_data, "\e#All-In-One\nNumber: %lu\nRides left: %u", serial, ride_count);
  98. return true;
  99. }