metroflip_scene_metromoney.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include <flipper_application.h>
  2. #include "../metroflip_i.h"
  3. #include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
  4. #include <nfc/protocols/mf_classic/mf_classic.h>
  5. #include <nfc/protocols/mf_classic/mf_classic_poller.h>
  6. #include <dolphin/dolphin.h>
  7. #include <bit_lib.h>
  8. #include <furi_hal.h>
  9. #include <nfc/nfc.h>
  10. #include <nfc/nfc_device.h>
  11. #include <nfc/nfc_listener.h>
  12. #define TAG "Metroflip:Scene:Metromoney"
  13. static bool metromoney_parse(const NfcDevice* device, const MfClassicData* data, Metroflip* app) {
  14. furi_assert(device);
  15. bool parsed = false;
  16. do {
  17. // Verify key
  18. const uint8_t ticket_sector_number = 1;
  19. const uint8_t ticket_block_number = 1;
  20. const MfClassicSectorTrailer* sec_tr =
  21. mf_classic_get_sector_trailer_by_sector(data, ticket_sector_number);
  22. const uint64_t key =
  23. bit_lib_bytes_to_num_be(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data));
  24. if(key != metromoney_1k_keys[ticket_sector_number].a) break;
  25. FURI_LOG_I(TAG, "passed key check");
  26. // Parse data
  27. const uint8_t start_block_num =
  28. mf_classic_get_first_block_num_of_sector(ticket_sector_number);
  29. const uint8_t* block_start_ptr =
  30. &data->block[start_block_num + ticket_block_number].data[0];
  31. uint32_t balance = bit_lib_bytes_to_num_le(block_start_ptr, 4) - 100;
  32. uint32_t balance_lari = balance / 100;
  33. uint8_t balance_tetri = balance % 100;
  34. size_t uid_len = 0;
  35. const uint8_t* uid = mf_classic_get_uid(data, &uid_len);
  36. uint32_t card_number = bit_lib_bytes_to_num_le(uid, 4);
  37. strncpy(app->card_type, "Metromoney", sizeof(app->card_type));
  38. app->balance_lari = balance_lari;
  39. app->balance_tetri = balance_tetri;
  40. app->card_number = card_number;
  41. parsed = true;
  42. } while(false);
  43. return parsed;
  44. }
  45. static NfcCommand
  46. metroflip_scene_metromoney_poller_callback(NfcGenericEvent event, void* context) {
  47. furi_assert(context);
  48. furi_assert(event.event_data);
  49. furi_assert(event.protocol == NfcProtocolMfClassic);
  50. NfcCommand command = NfcCommandContinue;
  51. const MfClassicPollerEvent* mfc_event = event.event_data;
  52. Metroflip* app = context;
  53. if(mfc_event->type == MfClassicPollerEventTypeCardDetected) {
  54. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventCardDetected);
  55. command = NfcCommandContinue;
  56. } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) {
  57. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventCardLost);
  58. app->sec_num = 0;
  59. command = NfcCommandStop;
  60. } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) {
  61. mfc_event->data->poller_mode.mode = MfClassicPollerModeRead;
  62. } else if(mfc_event->type == MfClassicPollerEventTypeRequestReadSector) {
  63. MfClassicKey key = {0};
  64. bit_lib_num_to_bytes_be(metromoney_1k_keys[app->sec_num].a, COUNT_OF(key.data), key.data);
  65. MfClassicKeyType key_type = MfClassicKeyTypeA;
  66. mfc_event->data->read_sector_request_data.sector_num = app->sec_num;
  67. mfc_event->data->read_sector_request_data.key = key;
  68. mfc_event->data->read_sector_request_data.key_type = key_type;
  69. mfc_event->data->read_sector_request_data.key_provided = true;
  70. if(app->sec_num == 16) {
  71. mfc_event->data->read_sector_request_data.key_provided = false;
  72. app->sec_num = 0;
  73. }
  74. app->sec_num++;
  75. } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
  76. nfc_device_set_data(
  77. app->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(app->poller));
  78. const MfClassicData* mfc_data = nfc_device_get_data(app->nfc_device, NfcProtocolMfClassic);
  79. metromoney_parse(app->nfc_device, mfc_data, app);
  80. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventPollerSuccess);
  81. command = NfcCommandStop;
  82. metroflip_app_blink_stop(app);
  83. } else if(mfc_event->type == MfClassicPollerEventTypeFail) {
  84. FURI_LOG_I(TAG, "fail");
  85. command = NfcCommandStop;
  86. }
  87. return command;
  88. }
  89. void metroflip_scene_metromoney_on_enter(void* context) {
  90. Metroflip* app = context;
  91. dolphin_deed(DolphinDeedNfcRead);
  92. app->sec_num = 0;
  93. // Setup view
  94. Popup* popup = app->popup;
  95. popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop);
  96. popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
  97. // Start worker
  98. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup);
  99. nfc_scanner_alloc(app->nfc);
  100. app->poller = nfc_poller_alloc(app->nfc, NfcProtocolMfClassic);
  101. nfc_poller_start(app->poller, metroflip_scene_metromoney_poller_callback, app);
  102. metroflip_app_blink_start(app);
  103. }
  104. bool metroflip_scene_metromoney_on_event(void* context, SceneManagerEvent event) {
  105. Metroflip* app = context;
  106. bool consumed = false;
  107. if(event.type == SceneManagerEventTypeCustom) {
  108. if(event.event == MetroflipCustomEventCardDetected) {
  109. Popup* popup = app->popup;
  110. popup_set_header(popup, "DON'T\nMOVE", 68, 30, AlignLeft, AlignTop);
  111. consumed = true;
  112. } else if(event.event == MetroflipCustomEventCardLost) {
  113. Popup* popup = app->popup;
  114. popup_set_header(popup, "Card \n lost", 68, 30, AlignLeft, AlignTop);
  115. consumed = true;
  116. } else if(event.event == MetroflipCustomEventWrongCard) {
  117. Popup* popup = app->popup;
  118. popup_set_header(popup, "WRONG \n CARD", 68, 30, AlignLeft, AlignTop);
  119. consumed = true;
  120. } else if(event.event == MetroflipCustomEventPollerFail) {
  121. Popup* popup = app->popup;
  122. popup_set_header(popup, "Failed", 68, 30, AlignLeft, AlignTop);
  123. consumed = true;
  124. } else if(event.event == MetroflipCustomEventPollerSuccess) {
  125. scene_manager_next_scene(app->scene_manager, MetroflipSceneReadSuccess);
  126. consumed = true;
  127. }
  128. } else if(event.type == SceneManagerEventTypeBack) {
  129. scene_manager_search_and_switch_to_previous_scene(app->scene_manager, MetroflipSceneStart);
  130. consumed = true;
  131. }
  132. return consumed;
  133. }
  134. void metroflip_scene_metromoney_on_exit(void* context) {
  135. Metroflip* app = context;
  136. widget_reset(app->widget);
  137. if(app->poller) {
  138. nfc_poller_stop(app->poller);
  139. nfc_poller_free(app->poller);
  140. }
  141. // Clear view
  142. popup_reset(app->popup);
  143. metroflip_app_blink_stop(app);
  144. }