metroflip_scene_ravkav.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include "../metroflip_i.h"
  2. #include <dolphin/dolphin.h>
  3. #include <nfc/protocols/iso14443_4b/iso14443_4b_poller.h>
  4. #define Metroflip_POLLER_MAX_BUFFER_SIZE 1024
  5. #define TAG "Metroflip:Scene:RavKav"
  6. uint8_t apdu_success[] = {0x90, 0x00};
  7. uint8_t apdu_file_not_found[] = {0x6a, 0x82};
  8. // balance
  9. uint8_t select_balance_file[] = {0x94, 0xA4, 0x00, 0x00, 0x02, 0x20, 0x2A, 0x00};
  10. uint8_t read_balance[] = {0x94, 0xb2, 0x01, 0x04, 0x1D};
  11. static NfcCommand metroflip_scene_ravkav_poller_callback(NfcGenericEvent event, void* context) {
  12. furi_assert(event.protocol == NfcProtocolIso14443_4b);
  13. NfcCommand next_command = NfcCommandContinue;
  14. MetroflipPollerEventType stage = MetroflipPollerEventTypeStart;
  15. Metroflip* app = context;
  16. const Iso14443_4bPollerEvent* iso14443_4b_event = event.event_data;
  17. Iso14443_4bPoller* iso14443_4b_poller = event.instance;
  18. BitBuffer* tx_buffer = bit_buffer_alloc(Metroflip_POLLER_MAX_BUFFER_SIZE);
  19. BitBuffer* rx_buffer = bit_buffer_alloc(Metroflip_POLLER_MAX_BUFFER_SIZE);
  20. if(iso14443_4b_event->type == Iso14443_4bPollerEventTypeReady) {
  21. if(stage == MetroflipPollerEventTypeStart) {
  22. nfc_device_set_data(
  23. app->nfc_device, NfcProtocolIso14443_4b, nfc_poller_get_data(app->poller));
  24. Iso14443_4bError error;
  25. size_t response_length = 0;
  26. do {
  27. // Select file of balance
  28. bit_buffer_append_bytes(
  29. tx_buffer, select_balance_file, sizeof(select_balance_file));
  30. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  31. if(error != Iso14443_4bErrorNone) {
  32. FURI_LOG_I(TAG, "Select File: iso14443_4b_poller_send_block error %d", error);
  33. stage = MetroflipPollerEventTypeFail;
  34. view_dispatcher_send_custom_event(
  35. app->view_dispatcher, MetroflipCustomEventPollerFail);
  36. break;
  37. }
  38. // Check the response after selecting file
  39. response_length = bit_buffer_get_size_bytes(rx_buffer);
  40. if(bit_buffer_get_byte(rx_buffer, response_length - 2) != apdu_success[0] ||
  41. bit_buffer_get_byte(rx_buffer, response_length - 1) != apdu_success[1]) {
  42. FURI_LOG_I(
  43. TAG,
  44. "Select file failed: %02x%02x",
  45. bit_buffer_get_byte(rx_buffer, response_length - 2),
  46. bit_buffer_get_byte(rx_buffer, response_length - 1));
  47. stage = MetroflipPollerEventTypeFail;
  48. view_dispatcher_send_custom_event(
  49. app->view_dispatcher, MetroflipCustomEventPollerFileNotFound);
  50. break;
  51. }
  52. // Now send the read command
  53. bit_buffer_reset(tx_buffer);
  54. bit_buffer_append_bytes(tx_buffer, read_balance, sizeof(read_balance));
  55. error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  56. if(error != Iso14443_4bErrorNone) {
  57. FURI_LOG_I(TAG, "Read File: iso14443_4b_poller_send_block error %d", error);
  58. stage = MetroflipPollerEventTypeFail;
  59. view_dispatcher_send_custom_event(
  60. app->view_dispatcher, MetroflipCustomEventPollerFail);
  61. break;
  62. }
  63. // Check the response after reading the file
  64. response_length = bit_buffer_get_size_bytes(rx_buffer);
  65. if(bit_buffer_get_byte(rx_buffer, response_length - 2) != apdu_success[0] ||
  66. bit_buffer_get_byte(rx_buffer, response_length - 1) != apdu_success[1]) {
  67. FURI_LOG_I(
  68. TAG,
  69. "Read file failed: %02x%02x",
  70. bit_buffer_get_byte(rx_buffer, response_length - 2),
  71. bit_buffer_get_byte(rx_buffer, response_length - 1));
  72. stage = MetroflipPollerEventTypeFail;
  73. view_dispatcher_send_custom_event(
  74. app->view_dispatcher, MetroflipCustomEventPollerFileNotFound);
  75. break;
  76. }
  77. // Process the response data
  78. if(response_length < 3) {
  79. FURI_LOG_I(TAG, "Response too short: %d bytes", response_length);
  80. stage = MetroflipPollerEventTypeFail;
  81. view_dispatcher_send_custom_event(
  82. app->view_dispatcher, MetroflipCustomEventPollerFail);
  83. break;
  84. }
  85. uint32_t value = 0;
  86. for(uint8_t i = 0; i < 3; i++) {
  87. value = (value << 8) | bit_buffer_get_byte(rx_buffer, i);
  88. }
  89. float result = value / 100.0f;
  90. app->value = result;
  91. strcpy(app->currency, "ILS");
  92. FURI_LOG_I(TAG, "Value: %.2f %s", (double)app->value, app->currency);
  93. strncpy(app->card_type, "Rav-Kav", sizeof(app->card_type));
  94. // Send success event
  95. view_dispatcher_send_custom_event(
  96. app->view_dispatcher, MetroflipCustomEventPollerSuccess);
  97. stage = MetroflipPollerEventTypeSuccess;
  98. next_command = NfcCommandStop;
  99. } while(false);
  100. if(stage != MetroflipPollerEventTypeSuccess) {
  101. next_command = NfcCommandStop;
  102. }
  103. }
  104. }
  105. bit_buffer_free(tx_buffer);
  106. bit_buffer_free(rx_buffer);
  107. return next_command;
  108. }
  109. void metroflip_scene_ravkav_on_enter(void* context) {
  110. Metroflip* app = context;
  111. dolphin_deed(DolphinDeedNfcRead);
  112. // Setup view
  113. Popup* popup = app->popup;
  114. popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop);
  115. popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
  116. // Start worker
  117. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup);
  118. nfc_scanner_alloc(app->nfc);
  119. app->poller = nfc_poller_alloc(app->nfc, NfcProtocolIso14443_4b);
  120. nfc_poller_start(app->poller, metroflip_scene_ravkav_poller_callback, app);
  121. metroflip_app_blink_start(app);
  122. }
  123. bool metroflip_scene_ravkav_on_event(void* context, SceneManagerEvent event) {
  124. Metroflip* app = context;
  125. bool consumed = false;
  126. if(event.type == SceneManagerEventTypeCustom) {
  127. if(event.event == MetroflipCustomEventPollerSuccess) {
  128. scene_manager_next_scene(app->scene_manager, MetroflipSceneReadSuccess);
  129. consumed = true;
  130. } else if(event.event == MetroflipPollerEventTypeCardDetect) {
  131. Popup* popup = app->popup;
  132. popup_set_header(popup, "Scanning..", 68, 30, AlignLeft, AlignTop);
  133. consumed = true;
  134. } else if(event.event == MetroflipCustomEventPollerFileNotFound) {
  135. Popup* popup = app->popup;
  136. popup_set_header(popup, "No\nRecord\nFile", 68, 30, AlignLeft, AlignTop);
  137. consumed = true;
  138. }
  139. } else if(event.type == SceneManagerEventTypeBack) {
  140. scene_manager_search_and_switch_to_previous_scene(app->scene_manager, MetroflipSceneStart);
  141. consumed = true;
  142. }
  143. return consumed;
  144. }
  145. void metroflip_scene_ravkav_on_exit(void* context) {
  146. Metroflip* app = context;
  147. if(app->poller) {
  148. nfc_poller_stop(app->poller);
  149. nfc_poller_free(app->poller);
  150. }
  151. metroflip_app_blink_stop(app);
  152. // Clear view
  153. popup_reset(app->popup);
  154. //metroflip_app_blink_stop(app);
  155. }