metroflip_scene_troika.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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 "../api/mosgortrans/mosgortrans_util.h"
  7. #include <dolphin/dolphin.h>
  8. #include <bit_lib.h>
  9. #include <furi_hal.h>
  10. #include <nfc/nfc.h>
  11. #include <nfc/nfc_device.h>
  12. #include <nfc/nfc_listener.h>
  13. #define TAG "Metroflip:Scene:Troika"
  14. static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) {
  15. bool success = true;
  16. if(type == MfClassicType1k) {
  17. config->data_sector = 11;
  18. config->keys = troika_1k_keys;
  19. } else if(type == MfClassicType4k) {
  20. config->data_sector = 8; // Further testing needed
  21. config->keys = troika_4k_keys;
  22. } else {
  23. success = false;
  24. }
  25. return success;
  26. }
  27. static bool troika_parse(FuriString* parsed_data, const MfClassicData* data) {
  28. bool parsed = false;
  29. do {
  30. // Verify card type
  31. TroikaCardConfig cfg = {};
  32. if(!troika_get_card_config(&cfg, data->type)) break;
  33. // Verify key
  34. const MfClassicSectorTrailer* sec_tr =
  35. mf_classic_get_sector_trailer_by_sector(data, cfg.data_sector);
  36. const uint64_t key =
  37. bit_lib_bytes_to_num_be(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data));
  38. if(key != cfg.keys[cfg.data_sector].a) break;
  39. FuriString* metro_result = furi_string_alloc();
  40. FuriString* ground_result = furi_string_alloc();
  41. FuriString* tat_result = furi_string_alloc();
  42. bool is_metro_data_present =
  43. mosgortrans_parse_transport_block(&data->block[32], metro_result);
  44. bool is_ground_data_present =
  45. mosgortrans_parse_transport_block(&data->block[28], ground_result);
  46. bool is_tat_data_present = mosgortrans_parse_transport_block(&data->block[16], tat_result);
  47. furi_string_cat_printf(parsed_data, "\e#Troyka card\n");
  48. if(is_metro_data_present && !furi_string_empty(metro_result)) {
  49. render_section_header(parsed_data, "Metro", 22, 21);
  50. furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(metro_result));
  51. }
  52. if(is_ground_data_present && !furi_string_empty(ground_result)) {
  53. render_section_header(parsed_data, "Ediny", 22, 22);
  54. furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(ground_result));
  55. }
  56. if(is_tat_data_present && !furi_string_empty(tat_result)) {
  57. render_section_header(parsed_data, "TAT", 24, 23);
  58. furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(tat_result));
  59. }
  60. furi_string_free(tat_result);
  61. furi_string_free(ground_result);
  62. furi_string_free(metro_result);
  63. parsed = is_metro_data_present || is_ground_data_present || is_tat_data_present;
  64. } while(false);
  65. return parsed;
  66. }
  67. bool checked = false;
  68. static NfcCommand metroflip_scene_troika_poller_callback(NfcGenericEvent event, void* context) {
  69. furi_assert(context);
  70. furi_assert(event.event_data);
  71. furi_assert(event.protocol == NfcProtocolMfClassic);
  72. NfcCommand command = NfcCommandContinue;
  73. const MfClassicPollerEvent* mfc_event = event.event_data;
  74. Metroflip* app = context;
  75. if(mfc_event->type == MfClassicPollerEventTypeCardDetected) {
  76. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventCardDetected);
  77. command = NfcCommandContinue;
  78. } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) {
  79. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventCardLost);
  80. app->sec_num = 0;
  81. command = NfcCommandStop;
  82. } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) {
  83. mfc_event->data->poller_mode.mode = MfClassicPollerModeRead;
  84. } else if(mfc_event->type == MfClassicPollerEventTypeRequestReadSector) {
  85. MfClassicKey key = {0};
  86. MfClassicKeyType key_type = MfClassicKeyTypeA;
  87. bit_lib_num_to_bytes_be(troika_1k_keys[app->sec_num].a, COUNT_OF(key.data), key.data);
  88. if(!checked) {
  89. mfc_event->data->read_sector_request_data.sector_num = app->sec_num;
  90. mfc_event->data->read_sector_request_data.key = key;
  91. mfc_event->data->read_sector_request_data.key_type = key_type;
  92. mfc_event->data->read_sector_request_data.key_provided = true;
  93. app->sec_num++;
  94. checked = true;
  95. }
  96. nfc_device_set_data(
  97. app->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(app->poller));
  98. const MfClassicData* mfc_data = nfc_device_get_data(app->nfc_device, NfcProtocolMfClassic);
  99. if(mfc_data->type == MfClassicType1k) {
  100. bit_lib_num_to_bytes_be(troika_1k_keys[app->sec_num].a, COUNT_OF(key.data), key.data);
  101. mfc_event->data->read_sector_request_data.sector_num = app->sec_num;
  102. mfc_event->data->read_sector_request_data.key = key;
  103. mfc_event->data->read_sector_request_data.key_type = key_type;
  104. mfc_event->data->read_sector_request_data.key_provided = true;
  105. if(app->sec_num == 16) {
  106. mfc_event->data->read_sector_request_data.key_provided = false;
  107. app->sec_num = 0;
  108. }
  109. app->sec_num++;
  110. } else if(mfc_data->type == MfClassicType4k) {
  111. bit_lib_num_to_bytes_be(troika_4k_keys[app->sec_num].a, COUNT_OF(key.data), key.data);
  112. mfc_event->data->read_sector_request_data.sector_num = app->sec_num;
  113. mfc_event->data->read_sector_request_data.key = key;
  114. mfc_event->data->read_sector_request_data.key_type = key_type;
  115. mfc_event->data->read_sector_request_data.key_provided = true;
  116. if(app->sec_num == 40) {
  117. mfc_event->data->read_sector_request_data.key_provided = false;
  118. app->sec_num = 0;
  119. }
  120. app->sec_num++;
  121. }
  122. } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
  123. const MfClassicData* mfc_data = nfc_device_get_data(app->nfc_device, NfcProtocolMfClassic);
  124. FuriString* parsed_data = furi_string_alloc();
  125. Widget* widget = app->widget;
  126. if(!troika_parse(parsed_data, mfc_data)) {
  127. furi_string_reset(app->text_box_store);
  128. FURI_LOG_I(TAG, "Unknown card type");
  129. furi_string_printf(parsed_data, "\e#Unknown card\n");
  130. }
  131. widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));
  132. widget_add_button_element(
  133. widget, GuiButtonTypeRight, "Exit", metroflip_exit_widget_callback, app);
  134. furi_string_free(parsed_data);
  135. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewWidget);
  136. metroflip_app_blink_stop(app);
  137. command = NfcCommandStop;
  138. } else if(mfc_event->type == MfClassicPollerEventTypeFail) {
  139. FURI_LOG_I(TAG, "fail");
  140. command = NfcCommandStop;
  141. }
  142. return command;
  143. }
  144. void metroflip_scene_troika_on_enter(void* context) {
  145. Metroflip* app = context;
  146. dolphin_deed(DolphinDeedNfcRead);
  147. app->sec_num = 0;
  148. // Setup view
  149. Popup* popup = app->popup;
  150. popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop);
  151. popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
  152. // Start worker
  153. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup);
  154. nfc_scanner_alloc(app->nfc);
  155. app->poller = nfc_poller_alloc(app->nfc, NfcProtocolMfClassic);
  156. nfc_poller_start(app->poller, metroflip_scene_troika_poller_callback, app);
  157. metroflip_app_blink_start(app);
  158. }
  159. bool metroflip_scene_troika_on_event(void* context, SceneManagerEvent event) {
  160. Metroflip* app = context;
  161. bool consumed = false;
  162. if(event.type == SceneManagerEventTypeCustom) {
  163. if(event.event == MetroflipCustomEventCardDetected) {
  164. Popup* popup = app->popup;
  165. popup_set_header(popup, "DON'T\nMOVE", 68, 30, AlignLeft, AlignTop);
  166. consumed = true;
  167. } else if(event.event == MetroflipCustomEventCardLost) {
  168. Popup* popup = app->popup;
  169. popup_set_header(popup, "Card \n lost", 68, 30, AlignLeft, AlignTop);
  170. consumed = true;
  171. } else if(event.event == MetroflipCustomEventWrongCard) {
  172. Popup* popup = app->popup;
  173. popup_set_header(popup, "WRONG \n CARD", 68, 30, AlignLeft, AlignTop);
  174. consumed = true;
  175. } else if(event.event == MetroflipCustomEventPollerFail) {
  176. Popup* popup = app->popup;
  177. popup_set_header(popup, "Failed", 68, 30, AlignLeft, AlignTop);
  178. consumed = true;
  179. } else if(event.event == MetroflipCustomEventPollerSuccess) {
  180. scene_manager_next_scene(app->scene_manager, MetroflipSceneReadSuccess);
  181. consumed = true;
  182. }
  183. } else if(event.type == SceneManagerEventTypeBack) {
  184. scene_manager_search_and_switch_to_previous_scene(app->scene_manager, MetroflipSceneStart);
  185. consumed = true;
  186. }
  187. return consumed;
  188. }
  189. void metroflip_scene_troika_on_exit(void* context) {
  190. Metroflip* app = context;
  191. widget_reset(app->widget);
  192. if(app->poller) {
  193. nfc_poller_stop(app->poller);
  194. nfc_poller_free(app->poller);
  195. }
  196. // Clear view
  197. popup_reset(app->popup);
  198. metroflip_app_blink_stop(app);
  199. }