rfal_nfcv.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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 "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) >> (RFAL_BITS_IN_BYTE - (colPos % RFAL_BITS_IN_BYTE)));
  349. colFound[colCnt].maskLen = (colFound[colIt].maskLen + 4U);
  350. colCnt++;
  351. }
  352. }
  353. } else {
  354. /* Timeout */
  355. platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
  356. }
  357. /* Check if devices found have reached device limit Activity 2.1 9.3.7.13 (Symbol 12) */
  358. if(*devCnt >= devLimit) {
  359. return ERR_NONE;
  360. }
  361. } while(slotNum < RFAL_NFCV_MAX_SLOTS); /* Slot loop */
  362. colIt++;
  363. } while(colIt < colCnt); /* Collisions found loop */
  364. return ERR_NONE;
  365. }
  366. /*******************************************************************************/
  367. ReturnCode rfalNfcvPollerSleepCollisionResolution(
  368. uint8_t devLimit,
  369. rfalNfcvListenDevice* nfcvDevList,
  370. uint8_t* devCnt) {
  371. uint8_t tmpDevCnt;
  372. ReturnCode ret;
  373. uint8_t i;
  374. if((nfcvDevList == NULL) || (devCnt == NULL)) {
  375. return ERR_PARAM;
  376. }
  377. *devCnt = 0;
  378. do {
  379. tmpDevCnt = 0;
  380. ret = rfalNfcvPollerCollisionResolution(
  381. RFAL_COMPLIANCE_MODE_ISO, (devLimit - *devCnt), &nfcvDevList[*devCnt], &tmpDevCnt);
  382. for(i = *devCnt; i < (*devCnt + tmpDevCnt); i++) {
  383. rfalNfcvPollerSleep(0x00, nfcvDevList[i].InvRes.UID);
  384. nfcvDevList[i].isSleep = true;
  385. }
  386. *devCnt += tmpDevCnt;
  387. } while((ret == ERR_NONE) && (tmpDevCnt > 0U) && (*devCnt < devLimit));
  388. return ret;
  389. }
  390. /*******************************************************************************/
  391. ReturnCode rfalNfcvPollerSleep(uint8_t flags, const uint8_t* uid) {
  392. ReturnCode ret;
  393. rfalNfcvSlpvReq slpReq;
  394. uint8_t rxBuf; /* dummy buffer, just to perform Rx */
  395. if(uid == NULL) {
  396. return ERR_PARAM;
  397. }
  398. /* Compute SLPV_REQ */
  399. slpReq.REQ_FLAG =
  400. (flags |
  401. (uint8_t)
  402. RFAL_NFCV_REQ_FLAG_ADDRESS); /* Should be with UID according Digital 2.0 (Candidate) 9.7.1.1 */
  403. slpReq.CMD = RFAL_NFCV_CMD_SLPV;
  404. ST_MEMCPY(slpReq.UID, uid, RFAL_NFCV_UID_LEN);
  405. /* NFC Forum device SHALL wait at least FDTVpp to consider the SLPV acknowledged (FDTVpp = FDTVpoll) Digital 2.0 (Candidate) 9.7 9.8.2 */
  406. ret = rfalTransceiveBlockingTxRx(
  407. (uint8_t*)&slpReq,
  408. sizeof(rfalNfcvSlpvReq),
  409. &rxBuf,
  410. sizeof(rxBuf),
  411. NULL,
  412. RFAL_TXRX_FLAGS_DEFAULT,
  413. RFAL_NFCV_FDT_MAX1);
  414. if(ret != ERR_TIMEOUT) {
  415. return ret;
  416. }
  417. return ERR_NONE;
  418. }
  419. /*******************************************************************************/
  420. ReturnCode rfalNfcvPollerSelect(uint8_t flags, const uint8_t* uid) {
  421. uint16_t rcvLen;
  422. rfalNfcvGenericRes res;
  423. if(uid == NULL) {
  424. return ERR_PARAM;
  425. }
  426. return rfalNfcvPollerTransceiveReq(
  427. RFAL_NFCV_CMD_SELECT,
  428. flags,
  429. RFAL_NFCV_PARAM_SKIP,
  430. uid,
  431. NULL,
  432. 0U,
  433. (uint8_t*)&res,
  434. sizeof(rfalNfcvGenericRes),
  435. &rcvLen);
  436. }
  437. /*******************************************************************************/
  438. ReturnCode rfalNfcvPollerReadSingleBlock(
  439. uint8_t flags,
  440. const uint8_t* uid,
  441. uint8_t blockNum,
  442. uint8_t* rxBuf,
  443. uint16_t rxBufLen,
  444. uint16_t* rcvLen) {
  445. uint8_t bn;
  446. bn = blockNum;
  447. return rfalNfcvPollerTransceiveReq(
  448. RFAL_NFCV_CMD_READ_SINGLE_BLOCK,
  449. flags,
  450. RFAL_NFCV_PARAM_SKIP,
  451. uid,
  452. &bn,
  453. sizeof(uint8_t),
  454. rxBuf,
  455. rxBufLen,
  456. rcvLen);
  457. }
  458. /*******************************************************************************/
  459. ReturnCode rfalNfcvPollerWriteSingleBlock(
  460. uint8_t flags,
  461. const uint8_t* uid,
  462. uint8_t blockNum,
  463. const uint8_t* wrData,
  464. uint8_t blockLen) {
  465. uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
  466. uint8_t dataLen;
  467. uint16_t rcvLen;
  468. rfalNfcvGenericRes res;
  469. /* Check for valid parameters */
  470. if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL)) {
  471. return ERR_PARAM;
  472. }
  473. dataLen = 0U;
  474. /* Compute Request Data */
  475. data[dataLen++] = blockNum; /* Set Block Number (8 bits) */
  476. ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
  477. dataLen += blockLen;
  478. return rfalNfcvPollerTransceiveReq(
  479. RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK,
  480. flags,
  481. RFAL_NFCV_PARAM_SKIP,
  482. uid,
  483. data,
  484. dataLen,
  485. (uint8_t*)&res,
  486. sizeof(rfalNfcvGenericRes),
  487. &rcvLen);
  488. }
  489. /*******************************************************************************/
  490. ReturnCode rfalNfcvPollerLockBlock(uint8_t flags, const uint8_t* uid, uint8_t blockNum) {
  491. uint16_t rcvLen;
  492. rfalNfcvGenericRes res;
  493. uint8_t bn;
  494. bn = blockNum;
  495. return rfalNfcvPollerTransceiveReq(
  496. RFAL_NFCV_CMD_LOCK_BLOCK,
  497. flags,
  498. RFAL_NFCV_PARAM_SKIP,
  499. uid,
  500. &bn,
  501. sizeof(uint8_t),
  502. (uint8_t*)&res,
  503. sizeof(rfalNfcvGenericRes),
  504. &rcvLen);
  505. }
  506. /*******************************************************************************/
  507. ReturnCode rfalNfcvPollerReadMultipleBlocks(
  508. uint8_t flags,
  509. const uint8_t* uid,
  510. uint8_t firstBlockNum,
  511. uint8_t numOfBlocks,
  512. uint8_t* rxBuf,
  513. uint16_t rxBufLen,
  514. uint16_t* rcvLen) {
  515. uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)];
  516. uint8_t dataLen;
  517. dataLen = 0U;
  518. /* Compute Request Data */
  519. data[dataLen++] = firstBlockNum; /* Set first Block Number */
  520. data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
  521. return rfalNfcvPollerTransceiveReq(
  522. RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS,
  523. flags,
  524. RFAL_NFCV_PARAM_SKIP,
  525. uid,
  526. data,
  527. dataLen,
  528. rxBuf,
  529. rxBufLen,
  530. rcvLen);
  531. }
  532. /*******************************************************************************/
  533. ReturnCode rfalNfcvPollerWriteMultipleBlocks(
  534. uint8_t flags,
  535. const uint8_t* uid,
  536. uint8_t firstBlockNum,
  537. uint8_t numOfBlocks,
  538. uint8_t* txBuf,
  539. uint16_t txBufLen,
  540. uint8_t blockLen,
  541. const uint8_t* wrData,
  542. uint16_t wrDataLen) {
  543. ReturnCode ret;
  544. uint16_t rcvLen;
  545. uint16_t reqLen;
  546. rfalNfcvGenericRes res;
  547. uint16_t msgIt;
  548. /* Calculate required buffer length */
  549. reqLen =
  550. (uint16_t)((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) : (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
  551. if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
  552. ((((uint16_t)numOfBlocks) * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U) ||
  553. (wrData == NULL)) {
  554. return ERR_PARAM;
  555. }
  556. msgIt = 0;
  557. /* Compute Request Command */
  558. txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
  559. txBuf[msgIt++] = RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS;
  560. /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
  561. if(uid != NULL) {
  562. txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
  563. ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
  564. msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
  565. }
  566. txBuf[msgIt++] = firstBlockNum;
  567. txBuf[msgIt++] = (numOfBlocks - 1U);
  568. if(wrDataLen > 0U) /* MISRA 21.18 */
  569. {
  570. ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
  571. msgIt += wrDataLen;
  572. }
  573. /* Transceive Command */
  574. ret = rfalTransceiveBlockingTxRx(
  575. txBuf,
  576. msgIt,
  577. (uint8_t*)&res,
  578. sizeof(rfalNfcvGenericRes),
  579. &rcvLen,
  580. RFAL_TXRX_FLAGS_DEFAULT,
  581. RFAL_NFCV_FDT_MAX);
  582. if(ret != ERR_NONE) {
  583. return ret;
  584. }
  585. /* Check if the response minimum length has been received */
  586. if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
  587. return ERR_PROTO;
  588. }
  589. /* Check if an error has been signalled */
  590. if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
  591. return rfalNfcvParseError(*res.data);
  592. }
  593. return ERR_NONE;
  594. }
  595. /*******************************************************************************/
  596. ReturnCode rfalNfcvPollerExtendedReadSingleBlock(
  597. uint8_t flags,
  598. const uint8_t* uid,
  599. uint16_t blockNum,
  600. uint8_t* rxBuf,
  601. uint16_t rxBufLen,
  602. uint16_t* rcvLen) {
  603. uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
  604. uint8_t dataLen;
  605. dataLen = 0U;
  606. /* Compute Request Data */
  607. data[dataLen++] = (uint8_t)
  608. 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. */
  609. data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
  610. return rfalNfcvPollerTransceiveReq(
  611. RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK,
  612. flags,
  613. RFAL_NFCV_PARAM_SKIP,
  614. uid,
  615. data,
  616. dataLen,
  617. rxBuf,
  618. rxBufLen,
  619. rcvLen);
  620. }
  621. /*******************************************************************************/
  622. ReturnCode rfalNfcvPollerExtendedWriteSingleBlock(
  623. uint8_t flags,
  624. const uint8_t* uid,
  625. uint16_t blockNum,
  626. const uint8_t* wrData,
  627. uint8_t blockLen) {
  628. uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
  629. uint8_t dataLen;
  630. uint16_t rcvLen;
  631. rfalNfcvGenericRes res;
  632. /* Check for valid parameters */
  633. if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN)) {
  634. return ERR_PARAM;
  635. }
  636. dataLen = 0U;
  637. /* Compute Request Data */
  638. data[dataLen++] = (uint8_t)
  639. 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. */
  640. data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
  641. ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
  642. dataLen += blockLen;
  643. return rfalNfcvPollerTransceiveReq(
  644. RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK,
  645. flags,
  646. RFAL_NFCV_PARAM_SKIP,
  647. uid,
  648. data,
  649. dataLen,
  650. (uint8_t*)&res,
  651. sizeof(rfalNfcvGenericRes),
  652. &rcvLen);
  653. }
  654. /*******************************************************************************/
  655. ReturnCode
  656. rfalNfcvPollerExtendedLockSingleBlock(uint8_t flags, const uint8_t* uid, uint16_t blockNum) {
  657. uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
  658. uint8_t dataLen;
  659. uint16_t rcvLen;
  660. rfalNfcvGenericRes res;
  661. dataLen = 0U;
  662. /* Compute Request Data */
  663. data[dataLen++] = (uint8_t)
  664. 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. */
  665. data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
  666. return rfalNfcvPollerTransceiveReq(
  667. RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK,
  668. flags,
  669. RFAL_NFCV_PARAM_SKIP,
  670. uid,
  671. data,
  672. dataLen,
  673. (uint8_t*)&res,
  674. sizeof(rfalNfcvGenericRes),
  675. &rcvLen);
  676. }
  677. /*******************************************************************************/
  678. ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks(
  679. uint8_t flags,
  680. const uint8_t* uid,
  681. uint16_t firstBlockNum,
  682. uint16_t numOfBlocks,
  683. uint8_t* rxBuf,
  684. uint16_t rxBufLen,
  685. uint16_t* rcvLen) {
  686. uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)];
  687. uint8_t dataLen;
  688. dataLen = 0U;
  689. /* Compute Request Data */
  690. data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU);
  691. data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU);
  692. data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU);
  693. data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU);
  694. return rfalNfcvPollerTransceiveReq(
  695. RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK,
  696. flags,
  697. RFAL_NFCV_PARAM_SKIP,
  698. uid,
  699. data,
  700. dataLen,
  701. rxBuf,
  702. rxBufLen,
  703. rcvLen);
  704. }
  705. /*******************************************************************************/
  706. ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks(
  707. uint8_t flags,
  708. const uint8_t* uid,
  709. uint16_t firstBlockNum,
  710. uint16_t numOfBlocks,
  711. uint8_t* txBuf,
  712. uint16_t txBufLen,
  713. uint8_t blockLen,
  714. const uint8_t* wrData,
  715. uint16_t wrDataLen) {
  716. ReturnCode ret;
  717. uint16_t rcvLen;
  718. uint16_t reqLen;
  719. rfalNfcvGenericRes res;
  720. uint16_t msgIt;
  721. uint16_t nBlocks;
  722. /* Calculate required buffer length */
  723. reqLen =
  724. ((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) :
  725. (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
  726. if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
  727. (((uint16_t)numOfBlocks * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U)) {
  728. return ERR_PARAM;
  729. }
  730. msgIt = 0;
  731. nBlocks = (numOfBlocks - 1U);
  732. /* Compute Request Command */
  733. txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
  734. txBuf[msgIt++] = RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK;
  735. /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
  736. if(uid != NULL) {
  737. txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
  738. ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
  739. msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
  740. }
  741. txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 0) & 0xFFU);
  742. txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 8) & 0xFFU);
  743. txBuf[msgIt++] = (uint8_t)((nBlocks >> 0) & 0xFFU);
  744. txBuf[msgIt++] = (uint8_t)((nBlocks >> 8) & 0xFFU);
  745. if(wrDataLen > 0U) /* MISRA 21.18 */
  746. {
  747. ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
  748. msgIt += wrDataLen;
  749. }
  750. /* Transceive Command */
  751. ret = rfalTransceiveBlockingTxRx(
  752. txBuf,
  753. msgIt,
  754. (uint8_t*)&res,
  755. sizeof(rfalNfcvGenericRes),
  756. &rcvLen,
  757. RFAL_TXRX_FLAGS_DEFAULT,
  758. RFAL_NFCV_FDT_MAX);
  759. if(ret != ERR_NONE) {
  760. return ret;
  761. }
  762. /* Check if the response minimum length has been received */
  763. if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
  764. return ERR_PROTO;
  765. }
  766. /* Check if an error has been signalled */
  767. if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
  768. return rfalNfcvParseError(*res.data);
  769. }
  770. return ERR_NONE;
  771. }
  772. /*******************************************************************************/
  773. ReturnCode rfalNfcvPollerGetSystemInformation(
  774. uint8_t flags,
  775. const uint8_t* uid,
  776. uint8_t* rxBuf,
  777. uint16_t rxBufLen,
  778. uint16_t* rcvLen) {
  779. return rfalNfcvPollerTransceiveReq(
  780. RFAL_NFCV_CMD_GET_SYS_INFO,
  781. flags,
  782. RFAL_NFCV_PARAM_SKIP,
  783. uid,
  784. NULL,
  785. 0U,
  786. rxBuf,
  787. rxBufLen,
  788. rcvLen);
  789. }
  790. /*******************************************************************************/
  791. ReturnCode rfalNfcvPollerExtendedGetSystemInformation(
  792. uint8_t flags,
  793. const uint8_t* uid,
  794. uint8_t requestField,
  795. uint8_t* rxBuf,
  796. uint16_t rxBufLen,
  797. uint16_t* rcvLen) {
  798. return rfalNfcvPollerTransceiveReq(
  799. RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO,
  800. flags,
  801. requestField,
  802. uid,
  803. NULL,
  804. 0U,
  805. rxBuf,
  806. rxBufLen,
  807. rcvLen);
  808. }
  809. /*******************************************************************************/
  810. ReturnCode rfalNfcvPollerTransceiveReq(
  811. uint8_t cmd,
  812. uint8_t flags,
  813. uint8_t param,
  814. const uint8_t* uid,
  815. const uint8_t* data,
  816. uint16_t dataLen,
  817. uint8_t* rxBuf,
  818. uint16_t rxBufLen,
  819. uint16_t* rcvLen) {
  820. ReturnCode ret;
  821. rfalNfcvGenericReq req;
  822. uint8_t msgIt;
  823. rfalBitRate rxBR;
  824. bool fastMode;
  825. msgIt = 0;
  826. fastMode = false;
  827. /* Check for valid parameters */
  828. if((rxBuf == NULL) || (rcvLen == NULL) || ((dataLen > 0U) && (data == NULL)) ||
  829. (dataLen > ((uid != NULL) ? RFAL_NFCV_MAX_GEN_DATA_LEN :
  830. (RFAL_NFCV_MAX_GEN_DATA_LEN - RFAL_NFCV_UID_LEN)))) {
  831. return ERR_PARAM;
  832. }
  833. /* Check if the command is an ST's Fast command */
  834. if((cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK) ||
  835. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK) ||
  836. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS) ||
  837. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS) ||
  838. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) ||
  839. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH) ||
  840. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE) ||
  841. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION) ||
  842. (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION)) {
  843. /* Store current Rx bit rate and move to fast mode */
  844. rfalGetBitRate(NULL, &rxBR);
  845. rfalSetBitRate(RFAL_BR_KEEP, RFAL_BR_52p97);
  846. fastMode = true;
  847. }
  848. /* Compute Request Command */
  849. req.REQ_FLAG = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
  850. req.CMD = cmd;
  851. /* Prepend parameter on ceratin proprietary requests: IC Manuf, Parameters */
  852. if(param != RFAL_NFCV_PARAM_SKIP) {
  853. req.payload.data[msgIt++] = param;
  854. }
  855. /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
  856. if(uid != NULL) {
  857. req.REQ_FLAG |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
  858. ST_MEMCPY(&req.payload.data[msgIt], uid, RFAL_NFCV_UID_LEN);
  859. msgIt += RFAL_NFCV_UID_LEN;
  860. }
  861. if(dataLen > 0U) {
  862. ST_MEMCPY(&req.payload.data[msgIt], data, dataLen);
  863. msgIt += (uint8_t)dataLen;
  864. }
  865. /* Transceive Command */
  866. ret = rfalTransceiveBlockingTxRx(
  867. (uint8_t*)&req,
  868. (RFAL_NFCV_CMD_LEN + RFAL_NFCV_FLAG_LEN + (uint16_t)msgIt),
  869. rxBuf,
  870. rxBufLen,
  871. rcvLen,
  872. RFAL_TXRX_FLAGS_DEFAULT,
  873. RFAL_NFCV_FDT_MAX);
  874. /* 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 */
  875. if(((flags & (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION) != 0U) &&
  876. ((cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK) ||
  877. (cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS) ||
  878. (cmd == (uint8_t)RFAL_NFCV_CMD_LOCK_BLOCK) ||
  879. (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK) ||
  880. (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK) ||
  881. (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK))) {
  882. ret = rfalISO15693TransceiveEOF(rxBuf, (uint8_t)rxBufLen, rcvLen);
  883. }
  884. /* Restore Rx BitRate */
  885. if(fastMode) {
  886. rfalSetBitRate(RFAL_BR_KEEP, rxBR);
  887. }
  888. if(ret != ERR_NONE) {
  889. return ret;
  890. }
  891. /* Check if the response minimum length has been received */
  892. if((*rcvLen) < (uint8_t)RFAL_NFCV_FLAG_LEN) {
  893. return ERR_PROTO;
  894. }
  895. /* Check if an error has been signalled */
  896. if((rxBuf[RFAL_NFCV_FLAG_POS] & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
  897. return rfalNfcvParseError(rxBuf[RFAL_NFCV_DATASTART_POS]);
  898. }
  899. return ERR_NONE;
  900. }
  901. #endif /* RFAL_FEATURE_NFCV */