• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010-2014 NXP Semiconductors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * TML Implementation.
19  */
20 
21 #include <phDal4Nfc_messageQueueLib.h>
22 #include <phNxpLog.h>
23 #include <phNxpNciHal_utils.h>
24 #include <phOsalNfc_Timer.h>
25 #include <phTmlNfc.h>
26 #include <phTmlNfc_i2c.h>
27 
28 /*
29  * Duration of Timer to wait after sending an Nci packet
30  */
31 #define PHTMLNFC_MAXTIME_RETRANSMIT (200U)
32 #define MAX_WRITE_RETRY_COUNT 0x03
33 /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 */
34 static uint8_t bCurrentRetryCount = (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
35 
36 /* Value to reset variables of TML  */
37 #define PH_TMLNFC_RESET_VALUE (0x00)
38 
39 /* Indicates a Initial or offset value */
40 #define PH_TMLNFC_VALUE_ONE (0x01)
41 
42 /* Initialize Context structure pointer used to access context structure */
43 phTmlNfc_Context_t* gpphTmlNfc_Context = NULL;
44 /* Local Function prototypes */
45 static NFCSTATUS phTmlNfc_StartThread(void);
46 static void phTmlNfc_ReadDeferredCb(void* pParams);
47 static void phTmlNfc_WriteDeferredCb(void* pParams);
48 static void * phTmlNfc_TmlThread(void* pParam);
49 static void * phTmlNfc_TmlWriterThread(void* pParam);
50 static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext);
51 static NFCSTATUS phTmlNfc_InitiateTimer(void);
52 
53 /* Function definitions */
54 
55 /*******************************************************************************
56 **
57 ** Function         phTmlNfc_Init
58 **
59 ** Description      Provides initialization of TML layer and hardware interface
60 **                  Configures given hardware interface and sends handle to the
61 **                  caller
62 **
63 ** Parameters       pConfig - TML configuration details as provided by the upper
64 **                            layer
65 **
66 ** Returns          NFC status:
67 **                  NFCSTATUS_SUCCESS - initialization successful
68 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
69 **                                                invalid
70 **                  NFCSTATUS_FAILED - initialization failed (for example,
71 **                                     unable to open hardware interface)
72 **                  NFCSTATUS_INVALID_DEVICE - device has not been opened or has
73 **                                             been disconnected
74 **
75 *******************************************************************************/
phTmlNfc_Init(pphTmlNfc_Config_t pConfig)76 NFCSTATUS phTmlNfc_Init(pphTmlNfc_Config_t pConfig) {
77   NFCSTATUS wInitStatus = NFCSTATUS_SUCCESS;
78 
79   /* Check if TML layer is already Initialized */
80   if (NULL != gpphTmlNfc_Context) {
81     /* TML initialization is already completed */
82     wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_ALREADY_INITIALISED);
83   }
84   /* Validate Input parameters */
85   else if ((NULL == pConfig) ||
86            (PH_TMLNFC_RESET_VALUE == pConfig->dwGetMsgThreadId)) {
87     /*Parameters passed to TML init are wrong */
88     wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
89   } else {
90     /* Allocate memory for TML context */
91     gpphTmlNfc_Context = (phTmlNfc_Context_t *)malloc(sizeof(phTmlNfc_Context_t));
92 
93     if (NULL == gpphTmlNfc_Context) {
94       wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
95     } else {
96       /* Initialise all the internal TML variables */
97       memset(gpphTmlNfc_Context, PH_TMLNFC_RESET_VALUE,
98              sizeof(phTmlNfc_Context_t));
99       /* Make sure that the thread runs once it is created */
100       gpphTmlNfc_Context->bThreadDone = 1;
101 
102       /* Open the device file to which data is read/written */
103       wInitStatus = phTmlNfc_i2c_open_and_configure(
104           pConfig, &(gpphTmlNfc_Context->pDevHandle));
105 
106       if (NFCSTATUS_SUCCESS != wInitStatus) {
107         wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_DEVICE);
108         gpphTmlNfc_Context->pDevHandle = NULL;
109       } else {
110         gpphTmlNfc_Context->tReadInfo.bEnable = 0;
111         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
112         gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
113         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
114         if (pthread_mutex_init(&gpphTmlNfc_Context->readInfoUpdateMutex,
115                                NULL) == -1) {
116           wInitStatus = NFCSTATUS_FAILED;
117         } else if (0 != sem_init(&gpphTmlNfc_Context->rxSemaphore, 0, 0)) {
118           wInitStatus = NFCSTATUS_FAILED;
119         } else if (0 != sem_init(&gpphTmlNfc_Context->txSemaphore, 0, 0)) {
120           wInitStatus = NFCSTATUS_FAILED;
121         } else if (0 != sem_init(&gpphTmlNfc_Context->postMsgSemaphore, 0, 0)) {
122           wInitStatus = NFCSTATUS_FAILED;
123         } else {
124           sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
125           /* Start TML thread (to handle write and read operations) */
126           if (NFCSTATUS_SUCCESS != phTmlNfc_StartThread()) {
127             wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
128           } else {
129             /* Create Timer used for Retransmission of NCI packets */
130             gpphTmlNfc_Context->dwTimerId = phOsalNfc_Timer_Create();
131             if (PH_OSALNFC_TIMER_ID_INVALID != gpphTmlNfc_Context->dwTimerId) {
132               /* Store the Thread Identifier to which Message is to be posted */
133               gpphTmlNfc_Context->dwCallbackThreadId =
134                   pConfig->dwGetMsgThreadId;
135               /* Enable retransmission of Nci packet & set retry count to
136                * default */
137               gpphTmlNfc_Context->eConfig = phTmlNfc_e_DisableRetrans;
138               /* Retry Count = Standby Recovery time of NFCC / Retransmission
139                * time + 1 */
140               gpphTmlNfc_Context->bRetryCount =
141                   (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
142               gpphTmlNfc_Context->bWriteCbInvoked = false;
143             } else {
144               wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
145             }
146           }
147         }
148       }
149     }
150   }
151   /* Clean up all the TML resources if any error */
152   if (NFCSTATUS_SUCCESS != wInitStatus) {
153     /* Clear all handles and memory locations initialized during init */
154     phTmlNfc_CleanUp();
155   }
156 
157   return wInitStatus;
158 }
159 
160 /*******************************************************************************
161 **
162 ** Function         phTmlNfc_ConfigNciPktReTx
163 **
164 ** Description      Provides Enable/Disable Retransmission of NCI packets
165 **                  Needed in case of Timeout between Transmission and Reception
166 **                  of NCI packets. Retransmission can be enabled only if
167 **                  standby mode is enabled
168 **
169 ** Parameters       eConfig - values from phTmlNfc_ConfigRetrans_t
170 **                  bRetryCount - Number of times Nci packets shall be
171 **                                retransmitted (default = 3)
172 **
173 ** Returns          None
174 **
175 *******************************************************************************/
phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration,uint8_t bRetryCounter)176 void phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration,
177                                uint8_t bRetryCounter) {
178   /* Enable/Disable Retransmission */
179 
180   gpphTmlNfc_Context->eConfig = eConfiguration;
181   if (phTmlNfc_e_EnableRetrans == eConfiguration) {
182     /* Check whether Retry counter passed is valid */
183     if (0 != bRetryCounter) {
184       gpphTmlNfc_Context->bRetryCount = bRetryCounter;
185     }
186     /* Set retry counter to its default value */
187     else {
188       /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1
189        */
190       gpphTmlNfc_Context->bRetryCount =
191           (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
192     }
193   }
194 
195   return;
196 }
197 
198 /*******************************************************************************
199 **
200 ** Function         phTmlNfc_StartThread
201 **
202 ** Description      Initializes comport, reader and writer threads
203 **
204 ** Parameters       None
205 **
206 ** Returns          NFC status:
207 **                  NFCSTATUS_SUCCESS - threads initialized successfully
208 **                  NFCSTATUS_FAILED - initialization failed due to system error
209 **
210 *******************************************************************************/
phTmlNfc_StartThread(void)211 static NFCSTATUS phTmlNfc_StartThread(void) {
212   NFCSTATUS wStartStatus = NFCSTATUS_SUCCESS;
213   void* h_threadsEvent = 0x00;
214   int pthread_create_status = 0;
215 
216   /* Create Reader and Writer threads */
217   pthread_create_status =
218       pthread_create(&gpphTmlNfc_Context->readerThread, NULL,
219                      &phTmlNfc_TmlThread, (void*)h_threadsEvent);
220   if (0 != pthread_create_status) {
221     wStartStatus = NFCSTATUS_FAILED;
222   } else {
223     /*Start Writer Thread*/
224     pthread_create_status =
225         pthread_create(&gpphTmlNfc_Context->writerThread, NULL,
226                        &phTmlNfc_TmlWriterThread, (void*)h_threadsEvent);
227     if (0 != pthread_create_status) {
228       wStartStatus = NFCSTATUS_FAILED;
229     }
230   }
231 
232   return wStartStatus;
233 }
234 
235 /*******************************************************************************
236 **
237 ** Function         phTmlNfc_ReTxTimerCb
238 **
239 ** Description      This is the timer callback function after timer expiration.
240 **
241 ** Parameters       dwThreadId  - id of the thread posting message
242 **                  pContext    - context provided by upper layer
243 **
244 ** Returns          None
245 **
246 *******************************************************************************/
phTmlNfc_ReTxTimerCb(uint32_t dwTimerId,void * pContext)247 static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext) {
248   if ((gpphTmlNfc_Context->dwTimerId == dwTimerId) && (NULL == pContext)) {
249     /* If Retry Count has reached its limit,Retransmit Nci
250        packet */
251     if (0 == bCurrentRetryCount) {
252       /* Since the count has reached its limit,return from timer callback
253          Upper layer Timeout would have happened */
254     } else {
255       bCurrentRetryCount--;
256       gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
257       gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
258     }
259     sem_post(&gpphTmlNfc_Context->txSemaphore);
260   }
261 
262   return;
263 }
264 
265 /*******************************************************************************
266 **
267 ** Function         phTmlNfc_InitiateTimer
268 **
269 ** Description      Start a timer for Tx and Rx thread.
270 **
271 ** Parameters       void
272 **
273 ** Returns          NFC status
274 **
275 *******************************************************************************/
phTmlNfc_InitiateTimer(void)276 static NFCSTATUS phTmlNfc_InitiateTimer(void) {
277   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
278 
279   /* Start Timer once Nci packet is sent */
280   wStatus = phOsalNfc_Timer_Start(gpphTmlNfc_Context->dwTimerId,
281                                   (uint32_t)PHTMLNFC_MAXTIME_RETRANSMIT,
282                                   phTmlNfc_ReTxTimerCb, NULL);
283 
284   return wStatus;
285 }
286 
287 /*******************************************************************************
288 **
289 ** Function         phTmlNfc_TmlThread
290 **
291 ** Description      Read the data from the lower layer driver
292 **
293 ** Parameters       pParam  - parameters for Writer thread function
294 **
295 ** Returns          None
296 **
297 *******************************************************************************/
phTmlNfc_TmlThread(void * pParam)298 static void * phTmlNfc_TmlThread(void* pParam) {
299   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
300   int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
301   uint8_t temp[260];
302   /* Transaction info buffer to be passed to Callback Thread */
303   static phTmlNfc_TransactInfo_t tTransactionInfo;
304   /* Structure containing Tml callback function and parameters to be invoked
305      by the callback thread */
306   static phLibNfc_DeferredCall_t tDeferredInfo;
307   /* Initialize Message structure to post message onto Callback Thread */
308   static phLibNfc_Message_t tMsg;
309   UNUSED(pParam);
310   NXPLOG_TML_D("PN54X - Tml Reader Thread Started................\n");
311 
312   /* Writer thread loop shall be running till shutdown is invoked */
313   while (gpphTmlNfc_Context->bThreadDone) {
314     /* If Tml write is requested */
315     /* Set the variable to success initially */
316     wStatus = NFCSTATUS_SUCCESS;
317     sem_wait(&gpphTmlNfc_Context->rxSemaphore);
318 
319     /* If Tml read is requested */
320     if (1 == gpphTmlNfc_Context->tReadInfo.bEnable) {
321       NXPLOG_TML_D("PN54X - Read requested.....\n");
322       /* Set the variable to success initially */
323       wStatus = NFCSTATUS_SUCCESS;
324 
325       /* Variable to fetch the actual number of bytes read */
326       dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
327 
328       /* Read the data from the file onto the buffer */
329       if (NULL != gpphTmlNfc_Context->pDevHandle) {
330         NXPLOG_TML_D("PN54X - Invoking I2C Read.....\n");
331         dwNoBytesWrRd =
332             phTmlNfc_i2c_read(gpphTmlNfc_Context->pDevHandle, temp, 260);
333 
334         if (-1 == dwNoBytesWrRd) {
335           NXPLOG_TML_E("PN54X - Error in I2C Read.....\n");
336           sem_post(&gpphTmlNfc_Context->rxSemaphore);
337         } else if (dwNoBytesWrRd > 260) {
338           NXPLOG_TML_E("Numer of bytes read exceeds the limit 260.....\n");
339           sem_post(&gpphTmlNfc_Context->rxSemaphore);
340         } else {
341           pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
342           memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd);
343 
344           NXPLOG_TML_D("PN54X - I2C Read successful.....\n");
345           /* This has to be reset only after a successful read */
346           gpphTmlNfc_Context->tReadInfo.bEnable = 0;
347           if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
348               (0x00 != (gpphTmlNfc_Context->tReadInfo.pBuffer[0] & 0xE0))) {
349             NXPLOG_TML_D("PN54X - Retransmission timer stopped.....\n");
350             /* Stop Timer to prevent Retransmission */
351             uint32_t timerStatus =
352                 phOsalNfc_Timer_Stop(gpphTmlNfc_Context->dwTimerId);
353             if (NFCSTATUS_SUCCESS != timerStatus) {
354               NXPLOG_TML_E("PN54X - timer stopped returned failure.....\n");
355             } else {
356               gpphTmlNfc_Context->bWriteCbInvoked = false;
357             }
358           }
359           if (gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
360             NXPLOG_TML_D("Delay Read if write thread is busy");
361             usleep(2000); /*2ms delay to give prio to write complete */
362           }
363           /* Update the actual number of bytes read including header */
364           gpphTmlNfc_Context->tReadInfo.wLength = (uint16_t)(dwNoBytesWrRd);
365           phNxpNciHal_print_packet("RECV",
366                                    gpphTmlNfc_Context->tReadInfo.pBuffer,
367                                    gpphTmlNfc_Context->tReadInfo.wLength);
368 
369           dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
370 
371           /* Fill the Transaction info structure to be passed to Callback
372            * Function */
373           tTransactionInfo.wStatus = wStatus;
374           tTransactionInfo.pBuff = gpphTmlNfc_Context->tReadInfo.pBuffer;
375           /* Actual number of bytes read is filled in the structure */
376           tTransactionInfo.wLength = gpphTmlNfc_Context->tReadInfo.wLength;
377 
378           /* Read operation completed successfully. Post a Message onto Callback
379            * Thread*/
380           /* Prepare the message to be posted on User thread */
381           tDeferredInfo.pCallback = &phTmlNfc_ReadDeferredCb;
382           tDeferredInfo.pParameter = &tTransactionInfo;
383           tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
384           tMsg.pMsgData = &tDeferredInfo;
385           tMsg.Size = sizeof(tDeferredInfo);
386           pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex);
387           NXPLOG_TML_D("PN54X - Posting read message.....\n");
388           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
389         }
390       } else {
391         NXPLOG_TML_D("PN54X -gpphTmlNfc_Context->pDevHandle is NULL");
392       }
393     } else {
394       NXPLOG_TML_D("PN54X - read request NOT enabled");
395       usleep(10 * 1000);
396     }
397   } /* End of While loop */
398 
399   return NULL;
400 }
401 
402 /*******************************************************************************
403 **
404 ** Function         phTmlNfc_TmlWriterThread
405 **
406 ** Description      Writes the requested data onto the lower layer driver
407 **
408 ** Parameters       pParam  - context provided by upper layer
409 **
410 ** Returns          None
411 **
412 *******************************************************************************/
phTmlNfc_TmlWriterThread(void * pParam)413 static void * phTmlNfc_TmlWriterThread(void* pParam) {
414   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
415   int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
416   /* Transaction info buffer to be passed to Callback Thread */
417   static phTmlNfc_TransactInfo_t tTransactionInfo;
418   /* Structure containing Tml callback function and parameters to be invoked
419      by the callback thread */
420   static phLibNfc_DeferredCall_t tDeferredInfo;
421   /* Initialize Message structure to post message onto Callback Thread */
422   static phLibNfc_Message_t tMsg;
423   /* In case of I2C Write Retry */
424   static uint16_t retry_cnt;
425   UNUSED(pParam);
426   NXPLOG_TML_D("PN54X - Tml Writer Thread Started................\n");
427 
428   /* Writer thread loop shall be running till shutdown is invoked */
429   while (gpphTmlNfc_Context->bThreadDone) {
430     NXPLOG_TML_D("PN54X - Tml Writer Thread Running................\n");
431     sem_wait(&gpphTmlNfc_Context->txSemaphore);
432     /* If Tml write is requested */
433     if (1 == gpphTmlNfc_Context->tWriteInfo.bEnable) {
434       NXPLOG_TML_D("PN54X - Write requested.....\n");
435       /* Set the variable to success initially */
436       wStatus = NFCSTATUS_SUCCESS;
437       if (NULL != gpphTmlNfc_Context->pDevHandle) {
438       retry:
439         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
440         /* Variable to fetch the actual number of bytes written */
441         dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
442         /* Write the data in the buffer onto the file */
443         NXPLOG_TML_D("PN54X - Invoking I2C Write.....\n");
444         dwNoBytesWrRd =
445             phTmlNfc_i2c_write(gpphTmlNfc_Context->pDevHandle,
446                                gpphTmlNfc_Context->tWriteInfo.pBuffer,
447                                gpphTmlNfc_Context->tWriteInfo.wLength);
448 
449         /* Try I2C Write Five Times, if it fails : Raju */
450         if (-1 == dwNoBytesWrRd) {
451           if (getDownloadFlag() == true) {
452             if (retry_cnt++ < MAX_WRITE_RETRY_COUNT) {
453               NXPLOG_TML_D("PN54X - Error in I2C Write  - Retry 0x%x",
454                               retry_cnt);
455               // Add a 10 ms delay to ensure NFCC is not still in stand by mode.
456               usleep(10 * 1000);
457               goto retry;
458             }
459           }
460           NXPLOG_TML_D("PN54X - Error in I2C Write.....\n");
461           wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
462         } else {
463           phNxpNciHal_print_packet("SEND",
464                                    gpphTmlNfc_Context->tWriteInfo.pBuffer,
465                                    gpphTmlNfc_Context->tWriteInfo.wLength);
466         }
467         retry_cnt = 0;
468         if (NFCSTATUS_SUCCESS == wStatus) {
469           NXPLOG_TML_D("PN54X - I2C Write successful.....\n");
470           dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE;
471         }
472         /* Fill the Transaction info structure to be passed to Callback Function
473          */
474         tTransactionInfo.wStatus = wStatus;
475         tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer;
476         /* Actual number of bytes written is filled in the structure */
477         tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd;
478 
479         /* Prepare the message to be posted on the User thread */
480         tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb;
481         tDeferredInfo.pParameter = &tTransactionInfo;
482         /* Write operation completed successfully. Post a Message onto Callback
483          * Thread*/
484         tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
485         tMsg.pMsgData = &tDeferredInfo;
486         tMsg.Size = sizeof(tDeferredInfo);
487 
488         /* Check whether Retransmission needs to be started,
489          * If yes, Post message only if
490          * case 1. Message is not posted &&
491          * case 11. Write status is success ||
492          * case 12. Last retry of write is also failure
493          */
494         if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
495             (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
496           if (gpphTmlNfc_Context->bWriteCbInvoked == false) {
497             if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) {
498               NXPLOG_TML_D("PN54X - Posting Write message.....\n");
499               phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId,
500                                     &tMsg);
501               gpphTmlNfc_Context->bWriteCbInvoked = true;
502             }
503           }
504         } else {
505           NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n");
506           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
507         }
508       } else {
509         NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL");
510       }
511 
512       /* If Data packet is sent, then NO retransmission */
513       if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
514           (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
515         NXPLOG_TML_D("PN54X - Starting timer for Retransmission case");
516         wStatus = phTmlNfc_InitiateTimer();
517         if (NFCSTATUS_SUCCESS != wStatus) {
518           /* Reset Variables used for Retransmission */
519           NXPLOG_TML_D("PN54X - Retransmission timer initiate failed");
520           gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
521           bCurrentRetryCount = 0;
522         }
523       }
524     } else {
525       NXPLOG_TML_D("PN54X - Write request NOT enabled");
526       usleep(10000);
527     }
528 
529   } /* End of While loop */
530 
531   return NULL;
532 }
533 
534 /*******************************************************************************
535 **
536 ** Function         phTmlNfc_CleanUp
537 **
538 ** Description      Clears all handles opened during TML initialization
539 **
540 ** Parameters       None
541 **
542 ** Returns          None
543 **
544 *******************************************************************************/
phTmlNfc_CleanUp(void)545 void phTmlNfc_CleanUp(void) {
546   if (NULL == gpphTmlNfc_Context) {
547     return;
548   }
549   if (NULL != gpphTmlNfc_Context->pDevHandle) {
550     (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
551     gpphTmlNfc_Context->bThreadDone = 0;
552   }
553   sem_destroy(&gpphTmlNfc_Context->rxSemaphore);
554   sem_destroy(&gpphTmlNfc_Context->txSemaphore);
555   sem_destroy(&gpphTmlNfc_Context->postMsgSemaphore);
556   phTmlNfc_i2c_close(gpphTmlNfc_Context->pDevHandle);
557   gpphTmlNfc_Context->pDevHandle = NULL;
558   /* Clear memory allocated for storing Context variables */
559   free((void*)gpphTmlNfc_Context);
560   /* Set the pointer to NULL to indicate De-Initialization */
561   gpphTmlNfc_Context = NULL;
562 
563   return;
564 }
565 
566 /*******************************************************************************
567 **
568 ** Function         phTmlNfc_Shutdown
569 **
570 ** Description      Uninitializes TML layer and hardware interface
571 **
572 ** Parameters       None
573 **
574 ** Returns          NFC status:
575 **                  NFCSTATUS_SUCCESS - TML configuration released successfully
576 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
577 **                                                invalid
578 **                  NFCSTATUS_FAILED - un-initialization failed (example: unable
579 **                                     to close interface)
580 **
581 *******************************************************************************/
phTmlNfc_Shutdown(void)582 NFCSTATUS phTmlNfc_Shutdown(void) {
583   NFCSTATUS wShutdownStatus = NFCSTATUS_SUCCESS;
584 
585   /* Check whether TML is Initialized */
586   if (NULL != gpphTmlNfc_Context) {
587     /* Reset thread variable to terminate the thread */
588     gpphTmlNfc_Context->bThreadDone = 0;
589     usleep(1000);
590     /* Clear All the resources allocated during initialization */
591     sem_post(&gpphTmlNfc_Context->rxSemaphore);
592     usleep(1000);
593     sem_post(&gpphTmlNfc_Context->txSemaphore);
594     usleep(1000);
595     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
596     usleep(1000);
597     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
598     usleep(1000);
599     pthread_mutex_destroy(&gpphTmlNfc_Context->readInfoUpdateMutex);
600     if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) {
601       NXPLOG_TML_E("Fail to kill reader thread!");
602     }
603     if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) {
604       NXPLOG_TML_E("Fail to kill writer thread!");
605     }
606     NXPLOG_TML_D("bThreadDone == 0");
607 
608   } else {
609     wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
610   }
611 
612   return wShutdownStatus;
613 }
614 
615 /*******************************************************************************
616 **
617 ** Function         phTmlNfc_Write
618 **
619 ** Description      Asynchronously writes given data block to hardware
620 **                  interface/driver. Enables writer thread if there are no
621 **                  write requests pending. Returns successfully once writer
622 **                  thread completes write operation. Notifies upper layer using
623 **                  callback mechanism.
624 **
625 **                  NOTE:
626 **                  * it is important to post a message with id
627 **                    PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data
628 **                    has been written to PN54X
629 **                  * if CRC needs to be computed, then input buffer should be
630 **                    capable to store two more bytes apart from length of
631 **                    packet
632 **
633 ** Parameters       pBuffer - data to be sent
634 **                  wLength - length of data buffer
635 **                  pTmlWriteComplete - pointer to the function to be invoked
636 **                                      upon completion
637 **                  pContext - context provided by upper layer
638 **
639 ** Returns          NFC status:
640 **                  NFCSTATUS_PENDING - command is yet to be processed
641 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
642 **                                                invalid
643 **                  NFCSTATUS_BUSY - write request is already in progress
644 **
645 *******************************************************************************/
phTmlNfc_Write(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,void * pContext)646 NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength,
647                          pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,
648                          void* pContext) {
649   NFCSTATUS wWriteStatus;
650 
651   /* Check whether TML is Initialized */
652 
653   if (NULL != gpphTmlNfc_Context) {
654     if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) &&
655         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) {
656       if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
657         /* Setting the flag marks beginning of a Write Operation */
658         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
659         /* Copy the buffer, length and Callback function,
660            This shall be utilized while invoking the Callback function in thread
661            */
662         gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer;
663         gpphTmlNfc_Context->tWriteInfo.wLength = wLength;
664         gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete;
665         gpphTmlNfc_Context->tWriteInfo.pContext = pContext;
666 
667         wWriteStatus = NFCSTATUS_PENDING;
668         // FIXME: If retry is going on. Stop the retry thread/timer
669         if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) {
670           /* Set retry count to default value */
671           // FIXME: If the timer expired there, and meanwhile we have created
672           // a new request. The expired timer will think that retry is still
673           // ongoing.
674           bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount;
675           gpphTmlNfc_Context->bWriteCbInvoked = false;
676         }
677         /* Set event to invoke Writer Thread */
678         gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
679         sem_post(&gpphTmlNfc_Context->txSemaphore);
680       } else {
681         wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
682       }
683     } else {
684       wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
685     }
686   } else {
687     wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
688   }
689 
690   return wWriteStatus;
691 }
692 
693 /*******************************************************************************
694 **
695 ** Function         phTmlNfc_UpdateReadCompleteCallback
696 **
697 ** Description      Updates the callback to be invoked after read completed
698 **
699 ** Parameters       pTmlReadComplete - pointer to the function to be invoked
700 **                                     upon completion of read operation
701 **
702 ** Returns          NFC status:
703 **                  NFCSTATUS_SUCCESS - if TmlNfc context available
704 **                  NFCSTATUS_FAILED - otherwise
705 **
706 *******************************************************************************/
phTmlNfc_UpdateReadCompleteCallback(pphTmlNfc_TransactCompletionCb_t pTmlReadComplete)707 NFCSTATUS phTmlNfc_UpdateReadCompleteCallback (
708     pphTmlNfc_TransactCompletionCb_t pTmlReadComplete) {
709   NFCSTATUS wStatus = NFCSTATUS_FAILED;
710   if ((NULL != gpphTmlNfc_Context) && (NULL != pTmlReadComplete)) {
711     gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
712     wStatus = NFCSTATUS_SUCCESS;
713   }
714   return wStatus;
715 }
716 
717 /*******************************************************************************
718 **
719 ** Function         phTmlNfc_Read
720 **
721 ** Description      Asynchronously reads data from the driver
722 **                  Number of bytes to be read and buffer are passed by upper
723 **                  layer.
724 **                  Enables reader thread if there are no read requests pending
725 **                  Returns successfully once read operation is completed
726 **                  Notifies upper layer using callback mechanism
727 **
728 ** Parameters       pBuffer - location to send read data to the upper layer via
729 **                            callback
730 **                  wLength - length of read data buffer passed by upper layer
731 **                  pTmlReadComplete - pointer to the function to be invoked
732 **                                     upon completion of read operation
733 **                  pContext - context provided by upper layer
734 **
735 ** Returns          NFC status:
736 **                  NFCSTATUS_PENDING - command is yet to be processed
737 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
738 **                                                invalid
739 **                  NFCSTATUS_BUSY - read request is already in progress
740 **
741 *******************************************************************************/
phTmlNfc_Read(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,void * pContext)742 NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength,
743                         pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,
744                         void* pContext) {
745   NFCSTATUS wReadStatus;
746 
747   /* Check whether TML is Initialized */
748   if (NULL != gpphTmlNfc_Context) {
749     if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) &&
750         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) {
751       if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) {
752         pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
753         /* Setting the flag marks beginning of a Read Operation */
754         gpphTmlNfc_Context->tReadInfo.bThreadBusy = true;
755         /* Copy the buffer, length and Callback function,
756            This shall be utilized while invoking the Callback function in thread
757            */
758         gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer;
759         gpphTmlNfc_Context->tReadInfo.wLength = wLength;
760         gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
761         gpphTmlNfc_Context->tReadInfo.pContext = pContext;
762         wReadStatus = NFCSTATUS_PENDING;
763 
764         /* Set event to invoke Reader Thread */
765         gpphTmlNfc_Context->tReadInfo.bEnable = 1;
766         pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex);
767 
768         sem_post(&gpphTmlNfc_Context->rxSemaphore);
769       } else {
770         wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
771       }
772     } else {
773       wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
774     }
775   } else {
776     wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
777   }
778 
779   return wReadStatus;
780 }
781 
782 /*******************************************************************************
783 **
784 ** Function         phTmlNfc_ReadAbort
785 **
786 ** Description      Aborts pending read request (if any)
787 **
788 ** Parameters       None
789 **
790 ** Returns          NFC status:
791 **                  NFCSTATUS_SUCCESS - ongoing read operation aborted
792 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
793 **                                                invalid
794 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
795 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read
796 **                                                        operation
797 **
798 *******************************************************************************/
phTmlNfc_ReadAbort(void)799 NFCSTATUS phTmlNfc_ReadAbort(void) {
800   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
801   gpphTmlNfc_Context->tReadInfo.bEnable = 0;
802 
803   /*Reset the flag to accept another Read Request */
804   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
805   wStatus = NFCSTATUS_SUCCESS;
806 
807   return wStatus;
808 }
809 
810 /*******************************************************************************
811 **
812 ** Function         phTmlNfc_WriteAbort
813 **
814 ** Description      Aborts pending write request (if any)
815 **
816 ** Parameters       None
817 **
818 ** Returns          NFC status:
819 **                  NFCSTATUS_SUCCESS - ongoing write operation aborted
820 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
821 **                                                invalid
822 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
823 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel write
824 **                                                        operation
825 **
826 *******************************************************************************/
phTmlNfc_WriteAbort(void)827 NFCSTATUS phTmlNfc_WriteAbort(void) {
828   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
829 
830   gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
831   /* Stop if any retransmission is in progress */
832   bCurrentRetryCount = 0;
833 
834   /* Reset the flag to accept another Write Request */
835   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
836   wStatus = NFCSTATUS_SUCCESS;
837 
838   return wStatus;
839 }
840 
841 /*******************************************************************************
842 **
843 ** Function         phTmlNfc_IoCtl
844 **
845 ** Description      Resets device when insisted by upper layer
846 **                  Number of bytes to be read and buffer are passed by upper
847 **                  layer
848 **                  Enables reader thread if there are no read requests pending
849 **                  Returns successfully once read operation is completed
850 **                  Notifies upper layer using callback mechanism
851 **
852 ** Parameters       eControlCode       - control code for a specific operation
853 **
854 ** Returns          NFC status:
855 **                  NFCSTATUS_SUCCESS  - ioctl command completed successfully
856 **                  NFCSTATUS_FAILED   - ioctl command request failed
857 **
858 *******************************************************************************/
phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode)859 NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) {
860   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
861 
862   if (NULL == gpphTmlNfc_Context) {
863     wStatus = NFCSTATUS_FAILED;
864   } else {
865     switch (eControlCode) {
866       case phTmlNfc_e_ResetDevice: {
867         /*Reset PN54X*/
868         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
869         usleep(100 * 1000);
870         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
871         usleep(100 * 1000);
872         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
873         break;
874       }
875       case phTmlNfc_e_EnableNormalMode: {
876         /*Reset PN54X*/
877         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
878         usleep(10 * 1000);
879         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
880         usleep(100 * 1000);
881         break;
882       }
883       case phTmlNfc_e_EnableDownloadMode: {
884         phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0);
885         (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2);
886         usleep(100 * 1000);
887         break;
888       }
889       default: {
890         wStatus = NFCSTATUS_INVALID_PARAMETER;
891         break;
892       }
893     }
894   }
895 
896   return wStatus;
897 }
898 
899 /*******************************************************************************
900 **
901 ** Function         phTmlNfc_DeferredCall
902 **
903 ** Description      Posts message on upper layer thread
904 **                  upon successful read or write operation
905 **
906 ** Parameters       dwThreadId  - id of the thread posting message
907 **                  ptWorkerMsg - message to be posted
908 **
909 ** Returns          None
910 **
911 *******************************************************************************/
phTmlNfc_DeferredCall(uintptr_t dwThreadId,phLibNfc_Message_t * ptWorkerMsg)912 void phTmlNfc_DeferredCall(uintptr_t dwThreadId,
913                            phLibNfc_Message_t* ptWorkerMsg) {
914   intptr_t bPostStatus;
915   UNUSED(dwThreadId);
916   /* Post message on the user thread to invoke the callback function */
917   sem_wait(&gpphTmlNfc_Context->postMsgSemaphore);
918   bPostStatus =
919       phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0);
920   sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
921 }
922 
923 /*******************************************************************************
924 **
925 ** Function         phTmlNfc_ReadDeferredCb
926 **
927 ** Description      Read thread call back function
928 **
929 ** Parameters       pParams - context provided by upper layer
930 **
931 ** Returns          None
932 **
933 *******************************************************************************/
phTmlNfc_ReadDeferredCb(void * pParams)934 static void phTmlNfc_ReadDeferredCb(void* pParams) {
935   /* Transaction info buffer to be passed to Callback Function */
936   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
937 
938   /* Reset the flag to accept another Read Request */
939   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
940   gpphTmlNfc_Context->tReadInfo.pThread_Callback(
941       gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo);
942 
943   return;
944 }
945 
946 /*******************************************************************************
947 **
948 ** Function         phTmlNfc_WriteDeferredCb
949 **
950 ** Description      Write thread call back function
951 **
952 ** Parameters       pParams - context provided by upper layer
953 **
954 ** Returns          None
955 **
956 *******************************************************************************/
phTmlNfc_WriteDeferredCb(void * pParams)957 static void phTmlNfc_WriteDeferredCb(void* pParams) {
958   /* Transaction info buffer to be passed to Callback Function */
959   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
960 
961   /* Reset the flag to accept another Write Request */
962   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
963   gpphTmlNfc_Context->tWriteInfo.pThread_Callback(
964       gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo);
965 
966   return;
967 }
968 
phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result)969 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
970   fragmentation_enabled = result;
971 }
972 
phTmlNfc_get_fragmentation_enabled()973 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
974   return fragmentation_enabled;
975 }
976 
977 /*******************************************************************************
978 **
979 ** Function         phTmlNfc_Shutdown_CleanUp
980 **
981 ** Description      wrapper function  for shutdown  and cleanup of resources
982 **
983 ** Parameters       None
984 **
985 ** Returns          NFCSTATUS
986 **
987 *******************************************************************************/
phTmlNfc_Shutdown_CleanUp()988 NFCSTATUS phTmlNfc_Shutdown_CleanUp() {
989   NFCSTATUS wShutdownStatus = phTmlNfc_Shutdown();
990   phTmlNfc_CleanUp();
991   return wShutdownStatus;
992 }
993