rfal_st25tb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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_st25tb.c
  27. *
  28. * \author Gustavo Patricio
  29. *
  30. * \brief Implementation of ST25TB interface
  31. *
  32. */
  33. /*
  34. ******************************************************************************
  35. * INCLUDES
  36. ******************************************************************************
  37. */
  38. #include "rfal_st25tb.h"
  39. #include "utils.h"
  40. /*
  41. ******************************************************************************
  42. * ENABLE SWITCH
  43. ******************************************************************************
  44. */
  45. #ifndef RFAL_FEATURE_ST25TB
  46. #define RFAL_FEATURE_ST25TB false /* ST25TB module configuration missing. Disabled by default */
  47. #endif
  48. #if RFAL_FEATURE_ST25TB
  49. /*
  50. ******************************************************************************
  51. * GLOBAL DEFINES
  52. ******************************************************************************
  53. */
  54. #define RFAL_ST25TB_CMD_LEN 1U /*!< ST25TB length of a command */
  55. #define RFAL_ST25TB_SLOTS 16U /*!< ST25TB number of slots */
  56. #define RFAL_ST25TB_SLOTNUM_MASK 0x0FU /*!< ST25TB Slot Number bit mask on SlotMarker */
  57. #define RFAL_ST25TB_SLOTNUM_SHIFT 4U /*!< ST25TB Slot Number shift on SlotMarker */
  58. #define RFAL_ST25TB_INITIATE_CMD1 0x06U /*!< ST25TB Initiate command byte1 */
  59. #define RFAL_ST25TB_INITIATE_CMD2 0x00U /*!< ST25TB Initiate command byte2 */
  60. #define RFAL_ST25TB_PCALL_CMD1 0x06U /*!< ST25TB Pcall16 command byte1 */
  61. #define RFAL_ST25TB_PCALL_CMD2 0x04U /*!< ST25TB Pcall16 command byte2 */
  62. #define RFAL_ST25TB_SELECT_CMD 0x0EU /*!< ST25TB Select command */
  63. #define RFAL_ST25TB_GET_UID_CMD 0x0BU /*!< ST25TB Get UID command */
  64. #define RFAL_ST25TB_COMPLETION_CMD 0x0FU /*!< ST25TB Completion command */
  65. #define RFAL_ST25TB_RESET_INV_CMD 0x0CU /*!< ST25TB Reset to Inventory command */
  66. #define RFAL_ST25TB_READ_BLOCK_CMD 0x08U /*!< ST25TB Read Block command */
  67. #define RFAL_ST25TB_WRITE_BLOCK_CMD 0x09U /*!< ST25TB Write Block command */
  68. #define RFAL_ST25TB_T0 2157U /*!< ST25TB t0 159 us ST25TB RF characteristics */
  69. #define RFAL_ST25TB_T1 2048U /*!< ST25TB t1 151 us ST25TB RF characteristics */
  70. #define RFAL_ST25TB_FWT (RFAL_ST25TB_T0 + RFAL_ST25TB_T1) /*!< ST25TB FWT = T0 + T1 */
  71. #define RFAL_ST25TB_TW rfalConvMsTo1fc(7U) /*!< ST25TB TW : Programming time for write max 7ms */
  72. /*
  73. ******************************************************************************
  74. * GLOBAL MACROS
  75. ******************************************************************************
  76. */
  77. /*
  78. ******************************************************************************
  79. * GLOBAL TYPES
  80. ******************************************************************************
  81. */
  82. /*! Initiate Request */
  83. typedef struct
  84. {
  85. uint8_t cmd1; /*!< Initiate Request cmd1: 0x06 */
  86. uint8_t cmd2; /*!< Initiate Request cmd2: 0x00 */
  87. } rfalSt25tbInitiateReq;
  88. /*! Pcall16 Request */
  89. typedef struct
  90. {
  91. uint8_t cmd1; /*!< Pcal16 Request cmd1: 0x06 */
  92. uint8_t cmd2; /*!< Pcal16 Request cmd2: 0x04 */
  93. } rfalSt25tbPcallReq;
  94. /*! Select Request */
  95. typedef struct
  96. {
  97. uint8_t cmd; /*!< Select Request cmd: 0x0E */
  98. uint8_t chipId; /*!< Chip ID */
  99. } rfalSt25tbSelectReq;
  100. /*! Read Block Request */
  101. typedef struct
  102. {
  103. uint8_t cmd; /*!< Select Request cmd: 0x08 */
  104. uint8_t address; /*!< Block address */
  105. } rfalSt25tbReadBlockReq;
  106. /*! Write Block Request */
  107. typedef struct
  108. {
  109. uint8_t cmd; /*!< Select Request cmd: 0x09 */
  110. uint8_t address; /*!< Block address */
  111. rfalSt25tbBlock data; /*!< Block Data */
  112. } rfalSt25tbWriteBlockReq;
  113. /*
  114. ******************************************************************************
  115. * LOCAL FUNCTION PROTOTYPES
  116. ******************************************************************************
  117. */
  118. /*!
  119. *****************************************************************************
  120. * \brief ST25TB Poller Do Collision Resolution
  121. *
  122. * This method performs ST25TB Collision resolution loop for each slot
  123. *
  124. * \param[in] devLimit : device limit value, and size st25tbDevList
  125. * \param[out] st25tbDevList : ST35TB listener device info
  126. * \param[out] devCnt : Devices found counter
  127. *
  128. * \return colPending : true if a collision was detected
  129. *****************************************************************************
  130. */
  131. static bool rfalSt25tbPollerDoCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt );
  132. /*
  133. ******************************************************************************
  134. * LOCAL FUNCTION PROTOTYPES
  135. ******************************************************************************
  136. */
  137. static bool rfalSt25tbPollerDoCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt )
  138. {
  139. uint8_t i;
  140. uint8_t chipId;
  141. ReturnCode ret;
  142. bool col;
  143. col = false;
  144. for(i = 0; i < RFAL_ST25TB_SLOTS; i++)
  145. {
  146. platformDelay(1); /* Wait t2: Answer to new request delay */
  147. if( i==0U )
  148. {
  149. /* Step 2: Send Pcall16 */
  150. ret = rfalSt25tbPollerPcall( &chipId );
  151. }
  152. else
  153. {
  154. /* Step 3-17: Send Pcall16 */
  155. ret = rfalSt25tbPollerSlotMarker( i, &chipId );
  156. }
  157. if( ret == ERR_NONE )
  158. {
  159. /* Found another device */
  160. st25tbDevList[*devCnt].chipID = chipId;
  161. st25tbDevList[*devCnt].isDeselected = false;
  162. /* Select Device, retrieve its UID */
  163. ret = rfalSt25tbPollerSelect( chipId );
  164. /* By Selecting this device, the previous gets Deselected */
  165. if( (*devCnt) > 0U )
  166. {
  167. st25tbDevList[(*devCnt)-1U].isDeselected = true;
  168. }
  169. if( ERR_NONE == ret )
  170. {
  171. rfalSt25tbPollerGetUID( &st25tbDevList[*devCnt].UID );
  172. }
  173. if( ERR_NONE == ret )
  174. {
  175. (*devCnt)++;
  176. }
  177. }
  178. else if( (ret == ERR_CRC) || (ret == ERR_FRAMING) )
  179. {
  180. col = true;
  181. }
  182. else
  183. {
  184. /* MISRA 15.7 - Empty else */
  185. }
  186. if( *devCnt >= devLimit )
  187. {
  188. break;
  189. }
  190. }
  191. return col;
  192. }
  193. /*
  194. ******************************************************************************
  195. * LOCAL VARIABLES
  196. ******************************************************************************
  197. */
  198. /*
  199. ******************************************************************************
  200. * GLOBAL FUNCTIONS
  201. ******************************************************************************
  202. */
  203. /*******************************************************************************/
  204. ReturnCode rfalSt25tbPollerInitialize( void )
  205. {
  206. return rfalNfcbPollerInitialize();
  207. }
  208. /*******************************************************************************/
  209. ReturnCode rfalSt25tbPollerCheckPresence( uint8_t *chipId )
  210. {
  211. ReturnCode ret;
  212. uint8_t chipIdRes;
  213. chipIdRes = 0x00;
  214. /* Send Initiate Request */
  215. ret = rfalSt25tbPollerInitiate( &chipIdRes );
  216. /* Check if a transmission error was detected */
  217. if( (ret == ERR_CRC) || (ret == ERR_FRAMING) )
  218. {
  219. return ERR_NONE;
  220. }
  221. /* Copy chip ID if requested */
  222. if( chipId != NULL )
  223. {
  224. *chipId = chipIdRes;
  225. }
  226. return ret;
  227. }
  228. /*******************************************************************************/
  229. ReturnCode rfalSt25tbPollerInitiate( uint8_t *chipId )
  230. {
  231. ReturnCode ret;
  232. uint16_t rxLen;
  233. rfalSt25tbInitiateReq initiateReq;
  234. uint8_t rxBuf[RFAL_ST25TB_CHIP_ID_LEN + RFAL_ST25TB_CRC_LEN]; /* In case we receive less data that CRC, RF layer will not remove the CRC from buffer */
  235. /* Compute Initiate Request */
  236. initiateReq.cmd1 = RFAL_ST25TB_INITIATE_CMD1;
  237. initiateReq.cmd2 = RFAL_ST25TB_INITIATE_CMD2;
  238. /* Send Initiate Request */
  239. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&initiateReq, sizeof(rfalSt25tbInitiateReq), (uint8_t*)rxBuf, sizeof(rxBuf), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  240. /* Check for valid Select Response */
  241. if( (ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN) )
  242. {
  243. return ERR_PROTO;
  244. }
  245. /* Copy chip ID if requested */
  246. if( chipId != NULL )
  247. {
  248. *chipId = *rxBuf;
  249. }
  250. return ret;
  251. }
  252. /*******************************************************************************/
  253. ReturnCode rfalSt25tbPollerPcall( uint8_t *chipId )
  254. {
  255. ReturnCode ret;
  256. uint16_t rxLen;
  257. rfalSt25tbPcallReq pcallReq;
  258. /* Compute Pcal16 Request */
  259. pcallReq.cmd1 = RFAL_ST25TB_PCALL_CMD1;
  260. pcallReq.cmd2 = RFAL_ST25TB_PCALL_CMD2;
  261. /* Send Pcal16 Request */
  262. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&pcallReq, sizeof(rfalSt25tbPcallReq), (uint8_t*)chipId, RFAL_ST25TB_CHIP_ID_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  263. /* Check for valid Select Response */
  264. if( (ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN) )
  265. {
  266. return ERR_PROTO;
  267. }
  268. return ret;
  269. }
  270. /*******************************************************************************/
  271. ReturnCode rfalSt25tbPollerSlotMarker( uint8_t slotNum, uint8_t *chipIdRes )
  272. {
  273. ReturnCode ret;
  274. uint16_t rxLen;
  275. uint8_t slotMarker;
  276. if( (slotNum == 0U) || (slotNum > 15U) )
  277. {
  278. return ERR_PARAM;
  279. }
  280. /* Compute SlotMarker */
  281. slotMarker = ( ((slotNum & RFAL_ST25TB_SLOTNUM_MASK) << RFAL_ST25TB_SLOTNUM_SHIFT) | RFAL_ST25TB_PCALL_CMD1 );
  282. /* Send SlotMarker */
  283. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&slotMarker, RFAL_ST25TB_CMD_LEN, (uint8_t*)chipIdRes, RFAL_ST25TB_CHIP_ID_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  284. /* Check for valid ChipID Response */
  285. if( (ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN) )
  286. {
  287. return ERR_PROTO;
  288. }
  289. return ret;
  290. }
  291. /*******************************************************************************/
  292. ReturnCode rfalSt25tbPollerSelect( uint8_t chipId )
  293. {
  294. ReturnCode ret;
  295. uint16_t rxLen;
  296. rfalSt25tbSelectReq selectReq;
  297. uint8_t chipIdRes;
  298. /* Compute Select Request */
  299. selectReq.cmd = RFAL_ST25TB_SELECT_CMD;
  300. selectReq.chipId = chipId;
  301. /* Send Select Request */
  302. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&selectReq, sizeof(rfalSt25tbSelectReq), (uint8_t*)&chipIdRes, RFAL_ST25TB_CHIP_ID_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  303. /* Check for valid Select Response */
  304. if( (ret == ERR_NONE) && ((rxLen != RFAL_ST25TB_CHIP_ID_LEN) || (chipIdRes != chipId)) )
  305. {
  306. return ERR_PROTO;
  307. }
  308. return ret;
  309. }
  310. /*******************************************************************************/
  311. ReturnCode rfalSt25tbPollerGetUID( rfalSt25tbUID *UID )
  312. {
  313. ReturnCode ret;
  314. uint16_t rxLen;
  315. uint8_t getUidReq;
  316. /* Compute Get UID Request */
  317. getUidReq = RFAL_ST25TB_GET_UID_CMD;
  318. /* Send Select Request */
  319. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&getUidReq, RFAL_ST25TB_CMD_LEN, (uint8_t*)UID, sizeof(rfalSt25tbUID), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  320. /* Check for valid UID Response */
  321. if( (ret == ERR_NONE) && (rxLen != RFAL_ST25TB_UID_LEN) )
  322. {
  323. return ERR_PROTO;
  324. }
  325. return ret;
  326. }
  327. /*******************************************************************************/
  328. ReturnCode rfalSt25tbPollerCollisionResolution( uint8_t devLimit, rfalSt25tbListenDevice *st25tbDevList, uint8_t *devCnt )
  329. {
  330. uint8_t chipId;
  331. ReturnCode ret;
  332. bool detected; /* collision or device was detected */
  333. if( (st25tbDevList == NULL) || (devCnt == NULL) || (devLimit == 0U) )
  334. {
  335. return ERR_PARAM;
  336. }
  337. *devCnt = 0;
  338. /* Step 1: Send Initiate */
  339. ret = rfalSt25tbPollerInitiate( &chipId );
  340. if( ret == ERR_NONE )
  341. {
  342. /* If only 1 answer is detected */
  343. st25tbDevList[*devCnt].chipID = chipId;
  344. st25tbDevList[*devCnt].isDeselected = false;
  345. /* Retrieve its UID and keep it Selected*/
  346. ret = rfalSt25tbPollerSelect( chipId );
  347. if( ERR_NONE == ret )
  348. {
  349. ret = rfalSt25tbPollerGetUID( &st25tbDevList[*devCnt].UID );
  350. }
  351. if( ERR_NONE == ret )
  352. {
  353. (*devCnt)++;
  354. }
  355. }
  356. /* Always proceed to Pcall16 anticollision as phase differences of tags can lead to no tag recognized, even if there is one */
  357. if( *devCnt < devLimit )
  358. {
  359. /* Multiple device responses */
  360. do
  361. {
  362. detected = rfalSt25tbPollerDoCollisionResolution( devLimit, st25tbDevList, devCnt );
  363. }
  364. while( (detected == true) && (*devCnt < devLimit) );
  365. }
  366. return ERR_NONE;
  367. }
  368. /*******************************************************************************/
  369. ReturnCode rfalSt25tbPollerReadBlock( uint8_t blockAddress, rfalSt25tbBlock *blockData )
  370. {
  371. ReturnCode ret;
  372. uint16_t rxLen;
  373. rfalSt25tbReadBlockReq readBlockReq;
  374. /* Compute Read Block Request */
  375. readBlockReq.cmd = RFAL_ST25TB_READ_BLOCK_CMD;
  376. readBlockReq.address = blockAddress;
  377. /* Send Read Block Request */
  378. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&readBlockReq, sizeof(rfalSt25tbReadBlockReq), (uint8_t*)blockData, sizeof(rfalSt25tbBlock), &rxLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  379. /* Check for valid UID Response */
  380. if( (ret == ERR_NONE) && (rxLen != RFAL_ST25TB_BLOCK_LEN) )
  381. {
  382. return ERR_PROTO;
  383. }
  384. return ret;
  385. }
  386. /*******************************************************************************/
  387. ReturnCode rfalSt25tbPollerWriteBlock( uint8_t blockAddress, const rfalSt25tbBlock *blockData )
  388. {
  389. ReturnCode ret;
  390. uint16_t rxLen;
  391. rfalSt25tbWriteBlockReq writeBlockReq;
  392. rfalSt25tbBlock tmpBlockData;
  393. /* Compute Write Block Request */
  394. writeBlockReq.cmd = RFAL_ST25TB_WRITE_BLOCK_CMD;
  395. writeBlockReq.address = blockAddress;
  396. ST_MEMCPY( &writeBlockReq.data, blockData, RFAL_ST25TB_BLOCK_LEN );
  397. /* Send Write Block Request */
  398. ret = rfalTransceiveBlockingTxRx( (uint8_t*)&writeBlockReq, sizeof(rfalSt25tbWriteBlockReq), tmpBlockData, RFAL_ST25TB_BLOCK_LEN, &rxLen, RFAL_TXRX_FLAGS_DEFAULT, (RFAL_ST25TB_FWT + RFAL_ST25TB_TW) );
  399. /* Check if there was any error besides timeout */
  400. if( ret != ERR_TIMEOUT )
  401. {
  402. /* Check if an unexpected answer was received */
  403. if( ret == ERR_NONE )
  404. {
  405. return ERR_PROTO;
  406. }
  407. /* Check whether a transmission error occurred */
  408. if( (ret != ERR_CRC) && (ret != ERR_FRAMING) && (ret != ERR_NOMEM) && (ret != ERR_RF_COLLISION) )
  409. {
  410. return ret;
  411. }
  412. /* If a transmission error occurred (maybe noise while commiting data) wait maximum programming time and verify data afterwards */
  413. rfalSetGT( (RFAL_ST25TB_FWT + RFAL_ST25TB_TW) );
  414. rfalFieldOnAndStartGT();
  415. }
  416. ret = rfalSt25tbPollerReadBlock(blockAddress, &tmpBlockData);
  417. if( ret == ERR_NONE )
  418. {
  419. if( ST_BYTECMP( &tmpBlockData, blockData, RFAL_ST25TB_BLOCK_LEN ) == 0 )
  420. {
  421. return ERR_NONE;
  422. }
  423. return ERR_PROTO;
  424. }
  425. return ret;
  426. }
  427. /*******************************************************************************/
  428. ReturnCode rfalSt25tbPollerCompletion( void )
  429. {
  430. uint8_t completionReq;
  431. /* Compute Completion Request */
  432. completionReq = RFAL_ST25TB_COMPLETION_CMD;
  433. /* Send Completion Request, no response is expected */
  434. return rfalTransceiveBlockingTxRx( (uint8_t*)&completionReq, RFAL_ST25TB_CMD_LEN, NULL, 0, NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  435. }
  436. /*******************************************************************************/
  437. ReturnCode rfalSt25tbPollerResetToInventory( void )
  438. {
  439. uint8_t resetInvReq;
  440. /* Compute Completion Request */
  441. resetInvReq = RFAL_ST25TB_RESET_INV_CMD;
  442. /* Send Completion Request, no response is expected */
  443. return rfalTransceiveBlockingTxRx( (uint8_t*)&resetInvReq, RFAL_ST25TB_CMD_LEN, NULL, 0, NULL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_ST25TB_FWT );
  444. }
  445. #endif /* RFAL_FEATURE_ST25TB */