nfc.c 9.3 KB

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