rfal_nfcv.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. /******************************************************************************
  2. * \attention
  3. *
  4. * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
  5. *
  6. * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
  7. * You may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at:
  9. *
  10. * www.st.com/myliberty
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
  15. * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. *
  20. ******************************************************************************/
  21. /*
  22. * PROJECT: ST25R391x firmware
  23. * Revision:
  24. * LANGUAGE: ISO C99
  25. */
  26. /*! \file rfal_nfcv.c
  27. *
  28. * \author Gustavo Patricio
  29. *
  30. * \brief Implementation of NFC-V Poller (ISO15693) device
  31. *
  32. * The definitions and helpers methods provided by this module are
  33. * aligned with NFC-V (ISO15693)
  34. *
  35. * The definitions and helpers methods provided by this module
  36. * are aligned with NFC-V Digital 2.1
  37. *
  38. */
  39. /*
  40. ******************************************************************************
  41. * INCLUDES
  42. ******************************************************************************
  43. */
  44. #include "../include/rfal_nfcv.h"
  45. #include "../utils.h"
  46. /*
  47. ******************************************************************************
  48. * ENABLE SWITCH
  49. ******************************************************************************
  50. */
  51. #ifndef RFAL_FEATURE_NFCV
  52. #define RFAL_FEATURE_NFCV false /* NFC-V module configuration missing. Disabled by default */
  53. #endif
  54. #if RFAL_FEATURE_NFCV
  55. /*
  56. ******************************************************************************
  57. * GLOBAL DEFINES
  58. ******************************************************************************
  59. */
  60. #define RFAL_NFCV_INV_REQ_FLAG \
  61. 0x06U /*!< INVENTORY_REQ INV_FLAG Digital 2.1 9.6.1 */
  62. #define RFAL_NFCV_MASKVAL_MAX_LEN \
  63. 8U /*!< Mask value max length: 64 bits (UID length) */
  64. #define RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN \
  65. 64U /*!< Mask value max length in 1 Slot mode in bits Digital 2.1 9.6.1.6 */
  66. #define RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN \
  67. 60U /*!< Mask value max length in 16 Slot mode in bits Digital 2.1 9.6.1.6 */
  68. #define RFAL_NFCV_MAX_SLOTS \
  69. 16U /*!< NFC-V max number of Slots */
  70. #define RFAL_NFCV_INV_REQ_HEADER_LEN \
  71. 3U /*!< INVENTORY_REQ header length (INV_FLAG, CMD, MASK_LEN) */
  72. #define RFAL_NFCV_INV_RES_LEN \
  73. 10U /*!< INVENTORY_RES length */
  74. #define RFAL_NFCV_WR_MUL_REQ_HEADER_LEN \
  75. 4U /*!< Write Multiple header length (INV_FLAG, CMD, [UID], BNo, Bno) */
  76. #define RFAL_NFCV_CMD_LEN \
  77. 1U /*!< Commandbyte length */
  78. #define RFAL_NFCV_FLAG_POS \
  79. 0U /*!< Flag byte position */
  80. #define RFAL_NFCV_FLAG_LEN \
  81. 1U /*!< Flag byte length */
  82. #define RFAL_NFCV_DATASTART_POS \
  83. 1U /*!< Position of start of data */
  84. #define RFAL_NFCV_DSFI_LEN \
  85. 1U /*!< DSFID length */
  86. #define RFAL_NFCV_SLPREQ_REQ_FLAG \
  87. 0x22U /*!< SLPV_REQ request flags Digital 2.0 (Candidate) 9.7.1.1 */
  88. #define RFAL_NFCV_RES_FLAG_NOERROR \
  89. 0x00U /*!< RES_FLAG indicating no error (checked during activation) */
  90. #define RFAL_NFCV_MAX_COLL_SUPPORTED \
  91. 16U /*!< Maximum number of collisions supported by the Anticollision loop */
  92. #define RFAL_NFCV_FDT_MAX \
  93. rfalConvMsTo1fc(20) /*!< Maximum Wait time FDTV,EOF and MAX2 Digital 2.1 B.5*/
  94. #define RFAL_NFCV_FDT_MAX1 \
  95. 4394U /*!< Read alike command FWT FDTV,LISTEN,MAX1 Digital 2.0 B.5 */
  96. /*! Time from special frame to EOF
  97. * ISO15693 2009 10.4.2 : 20ms
  98. * NFC Forum defines Digital 2.0 9.7.4 : FDTV,EOF = [10 ; 20]ms
  99. */
  100. #define RFAL_NFCV_FDT_EOF 20U
  101. /*! Time between slots - ISO 15693 defines t3min depending on modulation depth and data rate.
  102. * With only high-bitrate supported, AM modulation and a length of 12 bytes (96bits) for INV_RES we get:
  103. * - ISO t3min = 96/26 ms + 300us = 4 ms
  104. * - NFC Forum defines FDTV,INVENT_NORES = (4394 + 2048)/fc. Digital 2.0 B.5*/
  105. #define RFAL_NFCV_FDT_V_INVENT_NORES 4U
  106. /*
  107. ******************************************************************************
  108. * GLOBAL MACROS
  109. ******************************************************************************
  110. */
  111. /*! Checks if a valid INVENTORY_RES is valid Digital 2.2 9.6.2.1 & 9.6.2.3 */
  112. #define rfalNfcvCheckInvRes(f, l) \
  113. (((l) == rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN)) && \
  114. ((f) == RFAL_NFCV_RES_FLAG_NOERROR))
  115. /*
  116. ******************************************************************************
  117. * GLOBAL TYPES
  118. ******************************************************************************
  119. */
  120. /*! NFC-V INVENTORY_REQ format Digital 2.0 9.6.1 */
  121. typedef struct {
  122. uint8_t INV_FLAG; /*!< Inventory Flags */
  123. uint8_t CMD; /*!< Command code: 01h */
  124. uint8_t MASK_LEN; /*!< Mask Value Length */
  125. uint8_t MASK_VALUE[RFAL_NFCV_MASKVAL_MAX_LEN]; /*!< Mask Value */
  126. } rfalNfcvInventoryReq;
  127. /*! NFC-V SLP_REQ format Digital 2.0 (Candidate) 9.7.1 */
  128. typedef struct {
  129. uint8_t REQ_FLAG; /*!< Request Flags */
  130. uint8_t CMD; /*!< Command code: 02h */
  131. uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value */
  132. } rfalNfcvSlpvReq;
  133. /*! Container for a collision found during Anticollision loop */
  134. typedef struct {
  135. uint8_t maskLen;
  136. uint8_t maskVal[RFAL_NFCV_MASKVAL_MAX_LEN];
  137. } rfalNfcvCollision;
  138. /*
  139. ******************************************************************************
  140. * LOCAL FUNCTION PROTOTYPES
  141. ******************************************************************************
  142. */
  143. static ReturnCode rfalNfcvParseError(uint8_t err);
  144. /*
  145. ******************************************************************************
  146. * LOCAL VARIABLES
  147. ******************************************************************************
  148. */
  149. /*
  150. ******************************************************************************
  151. * LOCAL FUNCTIONS
  152. ******************************************************************************
  153. */
  154. /*******************************************************************************/
  155. static ReturnCode rfalNfcvParseError(uint8_t err) {
  156. switch(err) {
  157. case RFAL_NFCV_ERROR_CMD_NOT_SUPPORTED:
  158. case RFAL_NFCV_ERROR_OPTION_NOT_SUPPORTED:
  159. return ERR_NOTSUPP;
  160. case RFAL_NFCV_ERROR_CMD_NOT_RECOGNIZED:
  161. return ERR_PROTO;
  162. case RFAL_NFCV_ERROR_WRITE_FAILED:
  163. return ERR_WRITE;
  164. default:
  165. return ERR_REQUEST;
  166. }
  167. }
  168. /*
  169. ******************************************************************************
  170. * GLOBAL FUNCTIONS
  171. ******************************************************************************
  172. */
  173. /*******************************************************************************/
  174. ReturnCode rfalNfcvPollerInitialize(void) {
  175. ReturnCode ret;
  176. EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCV, RFAL_BR_26p48, RFAL_BR_26p48));
  177. rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
  178. rfalSetGT(RFAL_GT_NFCV);
  179. rfalSetFDTListen(RFAL_FDT_LISTEN_NFCV_POLLER);
  180. rfalSetFDTPoll(RFAL_FDT_POLL_NFCV_POLLER);
  181. return ERR_NONE;
  182. }
  183. /*******************************************************************************/
  184. ReturnCode rfalNfcvPollerCheckPresence(rfalNfcvInventoryRes* invRes) {
  185. ReturnCode ret;
  186. /* INVENTORY_REQ with 1 slot and no Mask Activity 2.0 (Candidate) 9.2.3.32 */
  187. ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, invRes, NULL);
  188. if((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_FRAMING) ||
  189. (ret == ERR_PROTO)) {
  190. ret = ERR_NONE;
  191. }
  192. return ret;
  193. }
  194. /*******************************************************************************/
  195. ReturnCode rfalNfcvPollerInventory(
  196. rfalNfcvNumSlots nSlots,
  197. uint8_t maskLen,
  198. const uint8_t* maskVal,
  199. rfalNfcvInventoryRes* invRes,
  200. uint16_t* rcvdLen) {
  201. ReturnCode ret;
  202. rfalNfcvInventoryReq invReq;
  203. uint16_t rxLen;
  204. if(((maskVal == NULL) && (maskLen != 0U)) || (invRes == NULL)) {
  205. return ERR_PARAM;
  206. }
  207. invReq.INV_FLAG = (RFAL_NFCV_INV_REQ_FLAG | (uint8_t)nSlots);
  208. invReq.CMD = RFAL_NFCV_CMD_INVENTORY;
  209. invReq.MASK_LEN = (uint8_t)MIN(
  210. maskLen,
  211. ((nSlots == RFAL_NFCV_NUM_SLOTS_1) ?
  212. RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN :
  213. RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN)); /* Digital 2.0 9.6.1.6 */
  214. if((rfalConvBitsToBytes(invReq.MASK_LEN) > 0U) && (maskVal != NULL)) /* MISRA 21.18 & 1.3 */
  215. {
  216. ST_MEMCPY(invReq.MASK_VALUE, maskVal, rfalConvBitsToBytes(invReq.MASK_LEN));
  217. }
  218. ret = rfalISO15693TransceiveAnticollisionFrame(
  219. (uint8_t*)&invReq,
  220. (uint8_t)(RFAL_NFCV_INV_REQ_HEADER_LEN + rfalConvBitsToBytes(invReq.MASK_LEN)),
  221. (uint8_t*)invRes,
  222. sizeof(rfalNfcvInventoryRes),
  223. &rxLen);
  224. /* Check for optional output parameter */
  225. if(rcvdLen != NULL) {
  226. *rcvdLen = rxLen;
  227. }
  228. if(ret == ERR_NONE) {
  229. /* Check for valid INVENTORY_RES Digital 2.2 9.6.2.1 & 9.6.2.3 */
  230. if(!rfalNfcvCheckInvRes(invRes->RES_FLAG, rxLen)) {
  231. return ERR_PROTO;
  232. }
  233. }
  234. return ret;
  235. }
  236. /*******************************************************************************/
  237. ReturnCode rfalNfcvPollerCollisionResolution(
  238. rfalComplianceMode compMode,
  239. uint8_t devLimit,
  240. rfalNfcvListenDevice* nfcvDevList,
  241. uint8_t* devCnt) {
  242. ReturnCode ret;
  243. uint8_t slotNum;
  244. uint16_t rcvdLen;
  245. uint8_t colIt;
  246. uint8_t colCnt;
  247. uint8_t colPos;
  248. bool colPending;
  249. rfalNfcvCollision colFound[RFAL_NFCV_MAX_COLL_SUPPORTED];
  250. if((nfcvDevList == NULL) || (devCnt == NULL)) {
  251. return ERR_PARAM;
  252. }
  253. /* Initialize parameters */
  254. *devCnt = 0;
  255. colIt = 0;
  256. colCnt = 0;
  257. colPending = false;
  258. ST_MEMSET(colFound, 0x00, (sizeof(rfalNfcvCollision) * RFAL_NFCV_MAX_COLL_SUPPORTED));
  259. if(devLimit > 0U) /* MISRA 21.18 */
  260. {
  261. ST_MEMSET(nfcvDevList, 0x00, (sizeof(rfalNfcvListenDevice) * devLimit));
  262. }
  263. NO_WARNING(
  264. colPending); /* colPending is not exposed externally, in future it might become exposed/ouput parameter */
  265. if(compMode == RFAL_COMPLIANCE_MODE_NFC) {
  266. /* Send INVENTORY_REQ with one slot Activity 2.1 9.3.7.1 (Symbol 0) */
  267. ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &nfcvDevList->InvRes, NULL);
  268. if(ret == ERR_TIMEOUT) /* Exit if no device found Activity 2.1 9.3.7.2 (Symbol 1) */
  269. {
  270. return ERR_NONE;
  271. }
  272. if(ret ==
  273. ERR_NONE) /* Device found without transmission error/collision Activity 2.1 9.3.7.3 (Symbol 2) */
  274. {
  275. (*devCnt)++;
  276. return ERR_NONE;
  277. }
  278. /* A Collision has been identified Activity 2.1 9.3.7.4 (Symbol 3) */
  279. colPending = true;
  280. colCnt = 1;
  281. /* Check if the Collision Resolution is set to perform only Collision detection Activity 2.1 9.3.7.5 (Symbol 4)*/
  282. if(devLimit == 0U) {
  283. return ERR_RF_COLLISION;
  284. }
  285. platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
  286. /*******************************************************************************/
  287. /* Collisions pending, Anticollision loop must be executed */
  288. /*******************************************************************************/
  289. } else {
  290. /* Advance to 16 slots below without mask. Will give a good chance to identify multiple cards */
  291. colPending = true;
  292. colCnt = 1;
  293. }
  294. /* Execute until all collisions are resolved Activity 2.1 9.3.7.18 (Symbol 17) */
  295. do {
  296. /* Activity 2.1 9.3.7.7 (Symbol 6 / 7) */
  297. colPending = false;
  298. slotNum = 0;
  299. do {
  300. if(slotNum == 0U) {
  301. /* Send INVENTORY_REQ with 16 slots Activity 2.1 9.3.7.9 (Symbol 8) */
  302. ret = rfalNfcvPollerInventory(
  303. RFAL_NFCV_NUM_SLOTS_16,
  304. colFound[colIt].maskLen,
  305. colFound[colIt].maskVal,
  306. &nfcvDevList[(*devCnt)].InvRes,
  307. &rcvdLen);
  308. } else {
  309. ret = rfalISO15693TransceiveEOFAnticollision(
  310. (uint8_t*)&nfcvDevList[(*devCnt)].InvRes,
  311. sizeof(rfalNfcvInventoryRes),
  312. &rcvdLen);
  313. }
  314. slotNum++;
  315. /*******************************************************************************/
  316. if(ret != ERR_TIMEOUT) {
  317. if(rcvdLen <
  318. rfalConvBytesToBits(
  319. RFAL_NFCV_INV_RES_LEN +
  320. RFAL_NFCV_CRC_LEN)) { /* If only a partial frame was received make sure the FDT_V_INVENT_NORES is fulfilled */
  321. platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
  322. }
  323. /* Check if response is a correct frame (no TxRx error) Activity 2.1 9.3.7.11 (Symbol 10)*/
  324. if((ret == ERR_NONE) || (ret == ERR_PROTO)) {
  325. /* Check if the device found is already on the list and its response is a valid INVENTORY_RES */
  326. if(rfalNfcvCheckInvRes(nfcvDevList[(*devCnt)].InvRes.RES_FLAG, rcvdLen)) {
  327. /* Activity 2.1 9.3.7.12 (Symbol 11) */
  328. (*devCnt)++;
  329. }
  330. } else /* Treat everything else as collision */
  331. {
  332. /* Activity 2.1 9.3.7.17 (Symbol 16) */
  333. colPending = true;
  334. /*******************************************************************************/
  335. /* Ensure that this collision still fits on the container */
  336. if(colCnt < RFAL_NFCV_MAX_COLL_SUPPORTED) {
  337. /* Store this collision on the container to be resolved later */
  338. /* Activity 2.1 9.3.7.17 (Symbol 16): add the collision information
  339. * (MASK_VAL + SN) to the list containing the collision information */
  340. ST_MEMCPY(
  341. colFound[colCnt].maskVal, colFound[colIt].maskVal, RFAL_NFCV_UID_LEN);
  342. colPos = colFound[colIt].maskLen;
  343. colFound[colCnt].maskVal[(colPos / RFAL_BITS_IN_BYTE)] &=
  344. (uint8_t)((1U << (colPos % RFAL_BITS_IN_BYTE)) - 1U);
  345. colFound[colCnt].maskVal[(colPos / RFAL_BITS_IN_BYTE)] |=
  346. (uint8_t)((slotNum - 1U) << (colPos % RFAL_BITS_IN_BYTE));
  347. colFound[colCnt].maskVal[((colPos / RFAL_BITS_IN_BYTE) + 1U)] =
  348. (uint8_t)((slotNum - 1U) >>
  349. (RFAL_BITS_IN_BYTE - (colPos % RFAL_BITS_IN_BYTE)));
  350. colFound[colCnt].maskLen = (colFound[colIt].maskLen + 4U);
  351. colCnt++;
  352. }
  353. }
  354. } else {
  355. /* Timeout */
  356. platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
  357. }
  358. /* Check if devices found have reached device limit Activity 2.1 9.3.7.13 (Symbol 12) */
  359. if(*devCnt >= devLimit) {
  360. return ERR_NONE;
  361. }
  362. } while(slotNum < RFAL_NFCV_MAX_SLOTS); /* Slot loop */
  363. colIt++;
  364. } while(colIt < colCnt); /* Collisions found loop */
  365. return ERR_NONE;
  366. }
  367. /*******************************************************************************/
  368. ReturnCode rfalNfcvPollerSleepCollisionResolution(
  369. uint8_t devLimit,
  370. rfalNfcvListenDevice* nfcvDevList,
  371. uint8_t* devCnt) {
  372. uint8_t tmpDevCnt;
  373. ReturnCode ret;
  374. uint8_t i;
  375. if((nfcvDevList == NULL) || (devCnt == NULL)) {
  376. return ERR_PARAM;
  377. }
  378. *devCnt = 0;
  379. do {
  380. tmpDevCnt = 0;
  381. ret = rfalNfcvPollerCollisionResolution(
  382. RFAL_COMPLIANCE_MODE_ISO, (devLimit - *devCnt), &nfcvDevList[*devCnt], &tmpDevCnt);
  383. for(i = *devCnt; i < (*devCnt + tmpDevCnt); i++) {
  384. rfalNfcvPollerSleep(0x00, nfcvDevList[i].InvRes.UID);
  385. nfcvDevList[i].isSleep = true;
  386. }
  387. *devCnt += tmpDevCnt;
  388. } while((ret == ERR_NONE) && (tmpDevCnt > 0U) && (*devCnt < devLimit));
  389. return ret;
  390. }
  391. /*******************************************************************************/
  392. ReturnCode rfalNfcvPollerSleep(uint8_t flags, const uint8_t* uid) {
  393. ReturnCode ret;
  394. rfalNfcvSlpvReq slpReq;
  395. uint8_t rxBuf; /* dummy buffer, just to perform Rx */
  396. if(uid == NULL) {
  397. return ERR_PARAM;
  398. }
  399. /* Compute SLPV_REQ */
  400. slpReq.REQ_FLAG =
  401. (flags |
  402. (uint8_t)
  403. RFAL_NFCV_REQ_FLAG_ADDRESS); /* Should be with UID according Digital 2.0 (Candidate) 9.7.1.1 */
  404. slpReq.CMD = RFAL_NFCV_CMD_SLPV;
  405. ST_MEMCPY(slpReq.UID, uid, RFAL_NFCV_UID_LEN);
  406. /* NFC Forum device SHALL wait at least FDTVpp to consider the SLPV acknowledged (FDTVpp = FDTVpoll) Digital 2.0 (Candidate) 9.7 9.8.2 */
  407. ret = rfalTransceiveBlockingTxRx(
  408. (uint8_t*)&slpReq,
  409. sizeof(rfalNfcvSlpvReq),
  410. &rxBuf,
  411. sizeof(rxBuf),
  412. NULL,
  413. RFAL_TXRX_FLAGS_DEFAULT,
  414. RFAL_NFCV_FDT_MAX1);
  415. if(ret != ERR_TIMEOUT) {
  416. return ret;
  417. }
  418. return ERR_NONE;
  419. }
  420. /*******************************************************************************/
  421. ReturnCode rfalNfcvPollerSelect(uint8_t flags, const uint8_t* uid) {
  422. uint16_t rcvLen;
  423. rfalNfcvGenericRes res;
  424. if(uid == NULL) {
  425. return ERR_PARAM;
  426. }
  427. return rfalNfcvPollerTransceiveReq(
  428. RFAL_NFCV_CMD_SELECT,
  429. flags,
  430. RFAL_NFCV_PARAM_SKIP,
  431. uid,
  432. NULL,
  433. 0U,
  434. (uint8_t*)&res,
  435. sizeof(rfalNfcvGenericRes),
  436. &rcvLen);
  437. }
  438. /*******************************************************************************/
  439. ReturnCode rfalNfcvPollerReadSingleBlock(
  440. uint8_t flags,
  441. const uint8_t* uid,
  442. uint8_t blockNum,
  443. uint8_t* rxBuf,
  444. uint16_t rxBufLen,
  445. uint16_t* rcvLen) {
  446. uint8_t bn;
  447. bn = blockNum;
  448. return rfalNfcvPollerTransceiveReq(
  449. RFAL_NFCV_CMD_READ_SINGLE_BLOCK,
  450. flags,
  451. RFAL_NFCV_PARAM_SKIP,
  452. uid,
  453. &bn,
  454. sizeof(uint8_t),
  455. rxBuf,
  456. rxBufLen,
  457. rcvLen);
  458. }
  459. /*******************************************************************************/
  460. ReturnCode rfalNfcvPollerWriteSingleBlock(
  461. uint8_t flags,
  462. const uint8_t* uid,
  463. uint8_t blockNum,
  464. const uint8_t* wrData,
  465. uint8_t blockLen) {
  466. uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
  467. uint8_t dataLen;
  468. uint16_t rcvLen;
  469. rfalNfcvGenericRes res;
  470. /* Check for valid parameters */
  471. if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL)) {
  472. return ERR_PARAM;
  473. }
  474. dataLen = 0U;
  475. /* Compute Request Data */
  476. data[dataLen++] = blockNum; /* Set Block Number (8 bits) */
  477. ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
  478. dataLen += blockLen;
  479. return rfalNfcvPollerTransceiveReq(
  480. RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK,
  481. flags,
  482. RFAL_NFCV_PARAM_SKIP,
  483. uid,
  484. data,
  485. dataLen,
  486. (uint8_t*)&res,
  487. sizeof(rfalNfcvGenericRes),
  488. &rcvLen);
  489. }
  490. /*******************************************************************************/
  491. ReturnCode rfalNfcvPollerLockBlock(uint8_t flags, const uint8_t* uid, uint8_t blockNum) {
  492. uint16_t rcvLen;
  493. rfalNfcvGenericRes res;
  494. uint8_t bn;
  495. bn = blockNum;
  496. return rfalNfcvPollerTransceiveReq(
  497. RFAL_NFCV_CMD_LOCK_BLOCK,
  498. flags,
  499. RFAL_NFCV_PARAM_SKIP,
  500. uid,
  501. &bn,
  502. sizeof(uint8_t),
  503. (uint8_t*)&res,
  504. sizeof(rfalNfcvGenericRes),
  505. &rcvLen);
  506. }
  507. /*******************************************************************************/
  508. ReturnCode rfalNfcvPollerReadMultipleBlocks(
  509. uint8_t flags,
  510. const uint8_t* uid,
  511. uint8_t firstBlockNum,
  512. uint8_t numOfBlocks,
  513. uint8_t* rxBuf,
  514. uint16_t rxBufLen,
  515. uint16_t* rcvLen) {
  516. uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)];
  517. uint8_t dataLen;
  518. dataLen = 0U;
  519. /* Compute Request Data */
  520. data[dataLen++] = firstBlockNum; /* Set first Block Number */
  521. data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
  522. return rfalNfcvPollerTransceiveReq(
  523. RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS,
  524. flags,
  525. RFAL_NFCV_PARAM_SKIP,
  526. uid,
  527. data,
  528. dataLen,
  529. rxBuf,
  530. rxBufLen,
  531. rcvLen);
  532. }
  533. /*******************************************************************************/
  534. ReturnCode rfalNfcvPollerWriteMultipleBlocks(
  535. uint8_t flags,
  536. const uint8_t* uid,
  537. uint8_t firstBlockNum,
  538. uint8_t numOfBlocks,
  539. uint8_t* txBuf,
  540. uint16_t txBufLen,
  541. uint8_t blockLen,
  542. const uint8_t* wrData,
  543. uint16_t wrDataLen) {
  544. ReturnCode ret;
  545. uint16_t rcvLen;
  546. uint16_t reqLen;
  547. rfalNfcvGenericRes res;
  548. uint16_t msgIt;
  549. /* Calculate required buffer length */
  550. reqLen = (uint16_t)((uid != NULL) ?
  551. (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) :
  552. (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
  553. if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
  554. ((((uint16_t)numOfBlocks) * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U) ||
  555. (wrData == NULL)) {
  556. return ERR_PARAM;
  557. }
  558. msgIt = 0;
  559. /* Compute Request Command */
  560. txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
  561. txBuf[msgIt++] = RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS;
  562. /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
  563. if(uid != NULL) {
  564. txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
  565. ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
  566. msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
  567. }
  568. txBuf[msgIt++] = firstBlockNum;
  569. txBuf[msgIt++] = (numOfBlocks - 1U);
  570. if(wrDataLen > 0U) /* MISRA 21.18 */
  571. {
  572. ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
  573. msgIt += wrDataLen;
  574. }
  575. /* Transceive Command */
  576. ret = rfalTransceiveBlockingTxRx(
  577. txBuf,
  578. msgIt,
  579. (uint8_t*)&res,
  580. sizeof(rfalNfcvGenericRes),
  581. &rcvLen,
  582. RFAL_TXRX_FLAGS_DEFAULT,
  583. RFAL_NFCV_FDT_MAX);
  584. if(ret != ERR_NONE) {
  585. return ret;
  586. }
  587. /* Check if the response minimum length has been received */
  588. if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
  589. return ERR_PROTO;
  590. }
  591. /* Check if an error has been signalled */
  592. if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
  593. return rfalNfcvParseError(*res.data);
  594. }
  595. return ERR_NONE;
  596. }
  597. /*******************************************************************************/
  598. ReturnCode rfalNfcvPollerExtendedReadSingleBlock(
  599. uint8_t flags,
  600. const uint8_t* uid,
  601. uint16_t blockNum,
  602. uint8_t* rxBuf,
  603. uint16_t rxBufLen,
  604. uint16_t* rcvLen) {
  605. uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
  606. uint8_t dataLen;
  607. dataLen = 0U;
  608. /* Compute Request Data */
  609. data[dataLen++] = (uint8_t)
  610. blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
  611. data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
  612. return rfalNfcvPollerTransceiveReq(
  613. RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK,
  614. flags,
  615. RFAL_NFCV_PARAM_SKIP,
  616. uid,
  617. data,
  618. dataLen,
  619. rxBuf,
  620. rxBufLen,
  621. rcvLen);
  622. }
  623. /*******************************************************************************/
  624. ReturnCode rfalNfcvPollerExtendedWriteSingleBlock(
  625. uint8_t flags,
  626. const uint8_t* uid,
  627. uint16_t blockNum,
  628. const uint8_t* wrData,
  629. uint8_t blockLen) {
  630. uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
  631. uint8_t dataLen;
  632. uint16_t rcvLen;
  633. rfalNfcvGenericRes res;
  634. /* Check for valid parameters */
  635. if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN)) {
  636. return ERR_PARAM;
  637. }
  638. dataLen = 0U;
  639. /* Compute Request Data */
  640. data[dataLen++] = (uint8_t)
  641. blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
  642. data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
  643. ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
  644. dataLen += blockLen;
  645. return rfalNfcvPollerTransceiveReq(
  646. RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK,
  647. flags,
  648. RFAL_NFCV_PARAM_SKIP,
  649. uid,
  650. data,
  651. dataLen,
  652. (uint8_t*)&res,
  653. sizeof(rfalNfcvGenericRes),
  654. &rcvLen);
  655. }
  656. /*******************************************************************************/
  657. ReturnCode
  658. rfalNfcvPollerExtendedLockSingleBlock(uint8_t flags, const uint8_t* uid, uint16_t blockNum) {
  659. uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
  660. uint8_t dataLen;
  661. uint16_t rcvLen;
  662. rfalNfcvGenericRes res;
  663. dataLen = 0U;
  664. /* Compute Request Data */
  665. data[dataLen++] = (uint8_t)
  666. blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
  667. data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
  668. return rfalNfcvPollerTransceiveReq(
  669. RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK,
  670. flags,
  671. RFAL_NFCV_PARAM_SKIP,
  672. uid,
  673. data,
  674. dataLen,
  675. (uint8_t*)&res,
  676. sizeof(rfalNfcvGenericRes),
  677. &rcvLen);
  678. }
  679. /*******************************************************************************/
  680. ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks(
  681. uint8_t flags,
  682. const uint8_t* uid,
  683. uint16_t firstBlockNum,
  684. uint16_t numOfBlocks,
  685. uint8_t* rxBuf,
  686. uint16_t rxBufLen,
  687. uint16_t* rcvLen) {
  688. uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)];
  689. uint8_t dataLen;
  690. dataLen = 0U;
  691. /* Compute Request Data */
  692. data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU);
  693. data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU);
  694. data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU);
  695. data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU);
  696. return rfalNfcvPollerTransceiveReq(
  697. RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK,
  698. flags,
  699. RFAL_NFCV_PARAM_SKIP,
  700. uid,
  701. data,
  702. dataLen,
  703. rxBuf,
  704. rxBufLen,
  705. rcvLen);
  706. }
  707. /*******************************************************************************/
  708. ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks(
  709. uint8_t flags,
  710. const uint8_t* uid,
  711. uint16_t firstBlockNum,
  712. uint16_t numOfBlocks,
  713. uint8_t* txBuf,
  714. uint16_t txBufLen,
  715. uint8_t blockLen,
  716. const uint8_t* wrData,
  717. uint16_t wrDataLen) {
  718. ReturnCode ret;
  719. uint16_t rcvLen;
  720. uint16_t reqLen;
  721. rfalNfcvGenericRes res;
  722. uint16_t msgIt;
  723. uint16_t nBlocks;
  724. /* Calculate required buffer length */
  725. reqLen =
  726. ((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) :
  727. (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
  728. if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
  729. (((uint16_t)numOfBlocks * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U)) {
  730. return ERR_PARAM;
  731. }
  732. msgIt = 0;
  733. nBlocks = (numOfBlocks - 1U);
  734. /* Compute Request Command */
  735. txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
  736. txBuf[msgIt++] = RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK;
  737. /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
  738. if(uid != NULL) {
  739. txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
  740. ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
  741. msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
  742. }
  743. txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 0) & 0xFFU);
  744. txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 8) & 0xFFU);
  745. txBuf[msgIt++] = (uint8_t)((nBlocks >> 0) & 0xFFU);
  746. txBuf[msgIt++] = (uint8_t)((nBlocks >> 8) & 0xFFU);
  747. if(wrDataLen > 0U) /* MISRA 21.18 */
  748. {
  749. ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
  750. msgIt += wrDataLen;
  751. }
  752. /* Transceive Command */
  753. ret = rfalTransceiveBlockingTxRx(
  754. txBuf,
  755. msgIt,
  756. (uint8_t*)&res,
  757. sizeof(rfalNfcvGenericRes),
  758. &rcvLen,
  759. RFAL_TXRX_FLAGS_DEFAULT,
  760. RFAL_NFCV_FDT_MAX);
  761. if(ret != ERR_NONE) {
  762. return ret;
  763. }
  764. /* Check if the response minimum length has been received */
  765. if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
  766. return ERR_PROTO;
  767. }
  768. /* Check if an error has been signalled */
  769. if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
  770. return rfalNfcvParseError(*res.data);
  771. }
  772. return ERR_NONE;
  773. }
  774. /*******************************************************************************/
  775. ReturnCode rfalNfcvPollerGetSystemInformation(
  776. uint8_t flags,
  777. const uint8_t* uid,
  778. uint8_t* rxBuf,
  779. uint16_t rxBufLen,
  780. uint16_t* rcvLen) {
  781. return rfalNfcvPollerTransceiveReq(
  782. RFAL_NFCV_CMD_GET_SYS_INFO,
  783. flags,
  784. RFAL_NFCV_PARAM_SKIP,
  785. uid,
  786. NULL,
  787. 0U,
  788. rxBuf,
  789. rxBufLen,
  790. rcvLen);
  791. }
  792. /*******************************************************************************/
  793. ReturnCode rfalNfcvPollerExtendedGetSystemInformation(
  794. uint8_t flags,
  795. const uint8_t* uid,
  796. uint8_t requestField,
  797. uint8_t* rxBuf,
  798. uint16_t rxBufLen,
  799. uint16_t* rcvLen) {
  800. return rfalNfcvPollerTransceiveReq(
  801. RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO,
  802. flags,
  803. requestField,
  804. uid,
  805. NULL,
  806. 0U,
  807. rxBuf,
  808. rxBufLen,
  809. rcvLen);
  810. }
  811. /*******************************************************************************/
  812. ReturnCode rfalNfcvPollerTransceiveReq(
  813. uint8_t cmd,
  814. uint8_t flags,
  815. uint8_t param,
  816. const uint8_t* uid,
  817. const uint8_t* data,
  818. uint16_t dataLen,
  819. uint8_t* rxBuf,
  820. uint16_t rxBufLen,
  821. uint16_t* rcvLen) {
  822. ReturnCode ret;
  823. rfalNfcvGenericReq req;
  824. uint8_t msgIt;
  825. rfalBitRate rxBR;
  826. bool fastMode;
  827. msgIt = 0;
  828. fastMode = false;
  829. /* Check for valid parameters */
  830. if((rxBuf == NULL) || (rcvLen == NULL) || ((dataLen > 0U) && (data == NULL)) ||
  831. (dataLen > ((uid != NULL) ? RFAL_NFCV_MAX_GEN_DATA_LEN :
  832. (RFAL_NFCV_MAX_GEN_DATA_LEN - RFAL_NFCV_UID_LEN)))) {
  833. return ERR_PARAM;
  834. }
  835. /* Check if the command is an ST's Fast command */
  836. if((cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK) ||
  837. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK) ||
  838. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS) ||
  839. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS) ||
  840. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) ||
  841. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH) ||
  842. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE) ||
  843. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION) ||
  844. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION)) {
  845. /* Store current Rx bit rate and move to fast mode */
  846. rfalGetBitRate(NULL, &rxBR);
  847. rfalSetBitRate(RFAL_BR_KEEP, RFAL_BR_52p97);
  848. fastMode = true;
  849. }
  850. /* Compute Request Command */
  851. req.REQ_FLAG = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
  852. req.CMD = cmd;
  853. /* Prepend parameter on ceratin proprietary requests: IC Manuf, Parameters */
  854. if(param != RFAL_NFCV_PARAM_SKIP) {
  855. req.payload.data[msgIt++] = param;
  856. }
  857. /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
  858. if(uid != NULL) {
  859. req.REQ_FLAG |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
  860. ST_MEMCPY(&req.payload.data[msgIt], uid, RFAL_NFCV_UID_LEN);
  861. msgIt += RFAL_NFCV_UID_LEN;
  862. }
  863. if(dataLen > 0U) {
  864. ST_MEMCPY(&req.payload.data[msgIt], data, dataLen);
  865. msgIt += (uint8_t)dataLen;
  866. }
  867. /* Transceive Command */
  868. ret = rfalTransceiveBlockingTxRx(
  869. (uint8_t*)&req,
  870. (RFAL_NFCV_CMD_LEN + RFAL_NFCV_FLAG_LEN + (uint16_t)msgIt),
  871. rxBuf,
  872. rxBufLen,
  873. rcvLen,
  874. RFAL_TXRX_FLAGS_DEFAULT,
  875. RFAL_NFCV_FDT_MAX);
  876. /* If the Option Flag is set in certain commands an EOF needs to be sent after 20ms to retrieve the VICC response ISO15693-3 2009 10.4.2 & 10.4.3 & 10.4.5 */
  877. if(((flags & (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION) != 0U) &&
  878. ((cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK) ||
  879. (cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS) ||
  880. (cmd == (uint8_t)RFAL_NFCV_CMD_LOCK_BLOCK) ||
  881. (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK) ||
  882. (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK) ||
  883. (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK))) {
  884. ret = rfalISO15693TransceiveEOF(rxBuf, (uint8_t)rxBufLen, rcvLen);
  885. }
  886. /* Restore Rx BitRate */
  887. if(fastMode) {
  888. rfalSetBitRate(RFAL_BR_KEEP, rxBR);
  889. }
  890. if(ret != ERR_NONE) {
  891. return ret;
  892. }
  893. /* Check if the response minimum length has been received */
  894. if((*rcvLen) < (uint8_t)RFAL_NFCV_FLAG_LEN) {
  895. return ERR_PROTO;
  896. }
  897. /* Check if an error has been signalled */
  898. if((rxBuf[RFAL_NFCV_FLAG_POS] & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
  899. return rfalNfcvParseError(rxBuf[RFAL_NFCV_DATASTART_POS]);
  900. }
  901. return ERR_NONE;
  902. }
  903. #endif /* RFAL_FEATURE_NFCV */