rfal_st25tb.c 17 KB

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