nfc.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. #include "nfc.h"
  2. #include <assert.h>
  3. #include <flipper.h>
  4. #include <gui/gui.h>
  5. #include <gui/widget.h>
  6. #include <gui/canvas.h>
  7. #include <menu/menu.h>
  8. #include <menu/menu_item.h>
  9. #include <rfal_analogConfig.h>
  10. #include <rfal_rf.h>
  11. #include <rfal_nfc.h>
  12. #include <rfal_nfca.h>
  13. #include "dispatcher.h"
  14. typedef enum {
  15. MessageTypeBase,
  16. } NfcMessageType;
  17. typedef struct {
  18. Message base;
  19. void* data;
  20. } NfcMessage;
  21. struct Nfc {
  22. Dispatcher* dispatcher;
  23. Widget* widget;
  24. MenuItem* menu;
  25. FuriRecordSubscriber* gui_record;
  26. FuriRecordSubscriber* menu_record;
  27. rfalNfcDiscoverParam* disParams;
  28. uint32_t ret;
  29. osThreadAttr_t worker_attr;
  30. osThreadId_t worker;
  31. uint8_t devCnt;
  32. uint8_t ticker;
  33. char* current;
  34. };
  35. #define EXAMPLE_NFCA_DEVICES 5
  36. void nfc_worker_task(void* context) {
  37. Nfc* nfc = context;
  38. ReturnCode err;
  39. rfalNfcaSensRes sensRes;
  40. rfalNfcaSelRes selRes;
  41. rfalNfcaListenDevice nfcaDevList[EXAMPLE_NFCA_DEVICES];
  42. uint8_t devCnt;
  43. uint8_t devIt;
  44. rfalLowPowerModeStop();
  45. while(widget_is_enabled(nfc->widget)) {
  46. rfalFieldOff();
  47. platformDelay(1000);
  48. nfc->ticker += 1;
  49. nfc->current = "Not detected";
  50. nfc->devCnt = 0;
  51. rfalNfcaPollerInitialize();
  52. rfalFieldOnAndStartGT();
  53. nfc->ret = err = rfalNfcaPollerTechnologyDetection(RFAL_COMPLIANCE_MODE_NFC, &sensRes);
  54. if(err == ERR_NONE) {
  55. err = rfalNfcaPollerFullCollisionResolution(
  56. RFAL_COMPLIANCE_MODE_NFC, EXAMPLE_NFCA_DEVICES, nfcaDevList, &devCnt);
  57. nfc->devCnt = devCnt;
  58. if((err == ERR_NONE) && (devCnt > 0)) {
  59. platformLog("NFC-A device(s) found %d\r\n", devCnt);
  60. devIt = 0;
  61. if(nfcaDevList[devIt].isSleep) {
  62. err = rfalNfcaPollerCheckPresence(
  63. RFAL_14443A_SHORTFRAME_CMD_WUPA, &sensRes); /* Wake up all cards */
  64. if(err != ERR_NONE) {
  65. continue;
  66. }
  67. err = rfalNfcaPollerSelect(
  68. nfcaDevList[devIt].nfcId1,
  69. nfcaDevList[devIt].nfcId1Len,
  70. &selRes); /* Select specific device */
  71. if(err != ERR_NONE) {
  72. continue;
  73. }
  74. }
  75. switch(nfcaDevList[devIt].type) {
  76. case RFAL_NFCA_T1T:
  77. /* No further activation needed for a T1T (RID already performed)*/
  78. platformLog(
  79. "NFC-A T1T device found \r\n"); /* NFC-A T1T device found, NFCID/UID is contained in: t1tRidRes.uid */
  80. nfc->current = "NFC-A T1T";
  81. /* Following communications shall be performed using:
  82. * - Non blocking: rfalStartTransceive() + rfalGetTransceiveState()
  83. * - Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx() */
  84. break;
  85. case RFAL_NFCA_T2T:
  86. /* No specific activation needed for a T2T */
  87. platformLog(
  88. "NFC-A T2T device found \r\n"); /* NFC-A T2T device found, NFCID/UID is contained in: nfcaDev.nfcid */
  89. nfc->current = "NFC-A T2T";
  90. /* Following communications shall be performed using:
  91. * - Non blocking: rfalStartTransceive() + rfalGetTransceiveState()
  92. * - Blocking: rfalTransceiveBlockingTx() + rfalTransceiveBlockingRx() or rfalTransceiveBlockingTxRx() */
  93. break;
  94. case RFAL_NFCA_T4T:
  95. platformLog(
  96. "NFC-A T4T (ISO-DEP) device found \r\n"); /* NFC-A T4T device found, NFCID/UID is contained in: nfcaDev.nfcid */
  97. nfc->current = "NFC-A T4T";
  98. /* Activation should continue using rfalIsoDepPollAHandleActivation(), see exampleRfalPoller.c */
  99. break;
  100. case RFAL_NFCA_T4T_NFCDEP: /* Device supports T4T and NFC-DEP */
  101. case RFAL_NFCA_NFCDEP: /* Device supports NFC-DEP */
  102. platformLog(
  103. "NFC-A P2P (NFC-DEP) device found \r\n"); /* NFC-A P2P device found, NFCID/UID is contained in: nfcaDev.nfcid */
  104. nfc->current = "NFC-A P2P";
  105. /* Activation should continue using rfalNfcDepInitiatorHandleActivation(), see exampleRfalPoller.c */
  106. break;
  107. }
  108. rfalNfcaPollerSleep(); /* Put device to sleep / HLTA (useless as the field will be turned off anyhow) */
  109. }
  110. }
  111. widget_update(nfc->widget);
  112. }
  113. rfalFieldOff();
  114. rfalLowPowerModeStart();
  115. nfc->ret = ERR_NONE;
  116. nfc->worker = NULL;
  117. osThreadExit();
  118. }
  119. void nfc_draw_callback(CanvasApi* canvas, void* context) {
  120. assert(context);
  121. Nfc* nfc = context;
  122. dispatcher_lock(nfc->dispatcher);
  123. canvas->clear(canvas);
  124. canvas->set_color(canvas, ColorBlack);
  125. canvas->set_font(canvas, FontPrimary);
  126. canvas->draw_str(canvas, 2, 16, "NFC Active");
  127. char status[128 / 8];
  128. snprintf(status, sizeof(status), "S:%lu T:%d D:%d", nfc->ret, nfc->ticker, nfc->devCnt);
  129. canvas->draw_str(canvas, 2, 32, status);
  130. canvas->draw_str(canvas, 2, 46, nfc->current);
  131. dispatcher_unlock(nfc->dispatcher);
  132. }
  133. void nfc_input_callback(InputEvent* event, void* context) {
  134. assert(context);
  135. Nfc* nfc = context;
  136. if(!event->state) return;
  137. widget_enabled_set(nfc->widget, false);
  138. }
  139. void nfc_test_callback(void* context) {
  140. assert(context);
  141. Nfc* nfc = context;
  142. dispatcher_lock(nfc->dispatcher);
  143. if(nfc->ret == ERR_NONE && !nfc->worker) {
  144. widget_enabled_set(nfc->widget, true);
  145. nfc->worker = osThreadNew(nfc_worker_task, nfc, &nfc->worker_attr);
  146. }
  147. dispatcher_unlock(nfc->dispatcher);
  148. }
  149. void nfc_read_callback(void* context) {
  150. assert(context);
  151. Nfc* nfc = context;
  152. (void)nfc;
  153. }
  154. void nfc_write_callback(void* context) {
  155. assert(context);
  156. Nfc* nfc = context;
  157. (void)nfc;
  158. }
  159. void nfc_bridge_callback(void* context) {
  160. assert(context);
  161. Nfc* nfc = context;
  162. (void)nfc;
  163. }
  164. Nfc* nfc_alloc() {
  165. Nfc* nfc = furi_alloc(sizeof(Nfc));
  166. assert(nfc);
  167. nfc->dispatcher = dispatcher_alloc(32, sizeof(NfcMessage));
  168. nfc->widget = widget_alloc();
  169. widget_draw_callback_set(nfc->widget, nfc_draw_callback, nfc);
  170. widget_input_callback_set(nfc->widget, nfc_input_callback, nfc);
  171. nfc->menu = menu_item_alloc_menu("NFC", NULL);
  172. menu_item_subitem_add(
  173. nfc->menu, menu_item_alloc_function("Test", NULL, nfc_test_callback, nfc));
  174. menu_item_subitem_add(
  175. nfc->menu, menu_item_alloc_function("Read", NULL, nfc_read_callback, nfc));
  176. menu_item_subitem_add(
  177. nfc->menu, menu_item_alloc_function("Write", NULL, nfc_write_callback, nfc));
  178. menu_item_subitem_add(
  179. nfc->menu, menu_item_alloc_function("Brdige", NULL, nfc_bridge_callback, nfc));
  180. nfc->gui_record = furi_open_deprecated("gui", false, false, NULL, NULL, NULL);
  181. assert(nfc->gui_record);
  182. nfc->menu_record = furi_open_deprecated("menu", false, false, NULL, NULL, NULL);
  183. assert(nfc->menu_record);
  184. nfc->worker_attr.name = "nfc_worker";
  185. // nfc->worker_attr.attr_bits = osThreadJoinable;
  186. nfc->worker_attr.stack_size = 4096;
  187. return nfc;
  188. }
  189. void nfc_task(void* p) {
  190. Nfc* nfc = nfc_alloc();
  191. GuiApi* gui = furi_take(nfc->gui_record);
  192. assert(gui);
  193. widget_enabled_set(nfc->widget, false);
  194. gui->add_widget(gui, nfc->widget, WidgetLayerFullscreen);
  195. furi_commit(nfc->gui_record);
  196. Menu* menu = furi_take(nfc->menu_record);
  197. assert(menu);
  198. menu_item_add(menu, nfc->menu);
  199. furi_commit(nfc->menu_record);
  200. if(!furi_create_deprecated("nfc", nfc, sizeof(nfc))) {
  201. printf("[nfc_task] cannot create the menu record\n");
  202. furiac_exit(NULL);
  203. }
  204. furiac_ready();
  205. nfc->ret = rfalNfcInitialize();
  206. rfalLowPowerModeStart();
  207. NfcMessage message;
  208. while(1) {
  209. dispatcher_recieve(nfc->dispatcher, (Message*)&message);
  210. if(message.base.type == MessageTypeExit) {
  211. break;
  212. }
  213. }
  214. }