| /* |
| * Copyright (C) 2010-2014 NXP Semiconductors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * TML Implementation. |
| */ |
| |
| #include <phDal4Nfc_messageQueueLib.h> |
| #include <phNxpLog.h> |
| #include <phNxpNciHal_utils.h> |
| #include <phOsalNfc_Timer.h> |
| #include <phTmlNfc.h> |
| #include <phTmlNfc_i2c.h> |
| |
| /* |
| * Duration of Timer to wait after sending an Nci packet |
| */ |
| #define PHTMLNFC_MAXTIME_RETRANSMIT (200U) |
| #define MAX_WRITE_RETRY_COUNT 0x03 |
| #define MAX_READ_RETRY_DELAY_IN_MILLISEC (150U) |
| /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 */ |
| static uint8_t bCurrentRetryCount = (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1; |
| |
| /* Value to reset variables of TML */ |
| #define PH_TMLNFC_RESET_VALUE (0x00) |
| |
| /* Indicates a Initial or offset value */ |
| #define PH_TMLNFC_VALUE_ONE (0x01) |
| |
| /* Initialize Context structure pointer used to access context structure */ |
| phTmlNfc_Context_t* gpphTmlNfc_Context = NULL; |
| /* Local Function prototypes */ |
| static NFCSTATUS phTmlNfc_StartThread(void); |
| static void phTmlNfc_ReadDeferredCb(void* pParams); |
| static void phTmlNfc_WriteDeferredCb(void* pParams); |
| static void * phTmlNfc_TmlThread(void* pParam); |
| static void * phTmlNfc_TmlWriterThread(void* pParam); |
| static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext); |
| static NFCSTATUS phTmlNfc_InitiateTimer(void); |
| |
| /* Function definitions */ |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_Init |
| ** |
| ** Description Provides initialization of TML layer and hardware interface |
| ** Configures given hardware interface and sends handle to the |
| ** caller |
| ** |
| ** Parameters pConfig - TML configuration details as provided by the upper |
| ** layer |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - initialization successful |
| ** NFCSTATUS_INVALID_PARAMETER - at least one parameter is |
| ** invalid |
| ** NFCSTATUS_FAILED - initialization failed (for example, |
| ** unable to open hardware interface) |
| ** NFCSTATUS_INVALID_DEVICE - device has not been opened or has |
| ** been disconnected |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_Init(pphTmlNfc_Config_t pConfig) { |
| NFCSTATUS wInitStatus = NFCSTATUS_SUCCESS; |
| |
| /* Check if TML layer is already Initialized */ |
| if (NULL != gpphTmlNfc_Context) { |
| /* TML initialization is already completed */ |
| wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_ALREADY_INITIALISED); |
| } |
| /* Validate Input parameters */ |
| else if ((NULL == pConfig) || |
| (PH_TMLNFC_RESET_VALUE == pConfig->dwGetMsgThreadId)) { |
| /*Parameters passed to TML init are wrong */ |
| wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER); |
| } else { |
| /* Allocate memory for TML context */ |
| gpphTmlNfc_Context = (phTmlNfc_Context_t *)malloc(sizeof(phTmlNfc_Context_t)); |
| |
| if (NULL == gpphTmlNfc_Context) { |
| wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); |
| } else { |
| /* Initialise all the internal TML variables */ |
| memset(gpphTmlNfc_Context, PH_TMLNFC_RESET_VALUE, |
| sizeof(phTmlNfc_Context_t)); |
| /* Make sure that the thread runs once it is created */ |
| gpphTmlNfc_Context->bThreadDone = 1; |
| |
| /* Open the device file to which data is read/written */ |
| wInitStatus = phTmlNfc_i2c_open_and_configure( |
| pConfig, &(gpphTmlNfc_Context->pDevHandle)); |
| |
| if (NFCSTATUS_SUCCESS != wInitStatus) { |
| wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_DEVICE); |
| gpphTmlNfc_Context->pDevHandle = NULL; |
| } else { |
| gpphTmlNfc_Context->tReadInfo.bEnable = 0; |
| gpphTmlNfc_Context->tWriteInfo.bEnable = 0; |
| gpphTmlNfc_Context->tReadInfo.bThreadBusy = false; |
| gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false; |
| if (pthread_mutex_init(&gpphTmlNfc_Context->readInfoUpdateMutex, |
| NULL) == -1) { |
| wInitStatus = NFCSTATUS_FAILED; |
| } else if (0 != sem_init(&gpphTmlNfc_Context->rxSemaphore, 0, 0)) { |
| wInitStatus = NFCSTATUS_FAILED; |
| } else if (0 != sem_init(&gpphTmlNfc_Context->txSemaphore, 0, 0)) { |
| wInitStatus = NFCSTATUS_FAILED; |
| } else if (0 != sem_init(&gpphTmlNfc_Context->postMsgSemaphore, 0, 0)) { |
| wInitStatus = NFCSTATUS_FAILED; |
| } else { |
| sem_post(&gpphTmlNfc_Context->postMsgSemaphore); |
| /* Start TML thread (to handle write and read operations) */ |
| if (NFCSTATUS_SUCCESS != phTmlNfc_StartThread()) { |
| wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); |
| } else { |
| /* Create Timer used for Retransmission of NCI packets */ |
| gpphTmlNfc_Context->dwTimerId = phOsalNfc_Timer_Create(); |
| if (PH_OSALNFC_TIMER_ID_INVALID != gpphTmlNfc_Context->dwTimerId) { |
| /* Store the Thread Identifier to which Message is to be posted */ |
| gpphTmlNfc_Context->dwCallbackThreadId = |
| pConfig->dwGetMsgThreadId; |
| /* Enable retransmission of Nci packet & set retry count to |
| * default */ |
| gpphTmlNfc_Context->eConfig = phTmlNfc_e_DisableRetrans; |
| /* Retry Count = Standby Recovery time of NFCC / Retransmission |
| * time + 1 */ |
| gpphTmlNfc_Context->bRetryCount = |
| (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1; |
| gpphTmlNfc_Context->bWriteCbInvoked = false; |
| } else { |
| wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); |
| } |
| } |
| } |
| } |
| } |
| } |
| /* Clean up all the TML resources if any error */ |
| if (NFCSTATUS_SUCCESS != wInitStatus) { |
| /* Clear all handles and memory locations initialized during init */ |
| phTmlNfc_CleanUp(); |
| } |
| |
| return wInitStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_ConfigNciPktReTx |
| ** |
| ** Description Provides Enable/Disable Retransmission of NCI packets |
| ** Needed in case of Timeout between Transmission and Reception |
| ** of NCI packets. Retransmission can be enabled only if |
| ** standby mode is enabled |
| ** |
| ** Parameters eConfig - values from phTmlNfc_ConfigRetrans_t |
| ** bRetryCount - Number of times Nci packets shall be |
| ** retransmitted (default = 3) |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration, |
| uint8_t bRetryCounter) { |
| /* Enable/Disable Retransmission */ |
| |
| gpphTmlNfc_Context->eConfig = eConfiguration; |
| if (phTmlNfc_e_EnableRetrans == eConfiguration) { |
| /* Check whether Retry counter passed is valid */ |
| if (0 != bRetryCounter) { |
| gpphTmlNfc_Context->bRetryCount = bRetryCounter; |
| } |
| /* Set retry counter to its default value */ |
| else { |
| /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 |
| */ |
| gpphTmlNfc_Context->bRetryCount = |
| (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1; |
| } |
| } |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_StartThread |
| ** |
| ** Description Initializes comport, reader and writer threads |
| ** |
| ** Parameters None |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - threads initialized successfully |
| ** NFCSTATUS_FAILED - initialization failed due to system error |
| ** |
| *******************************************************************************/ |
| static NFCSTATUS phTmlNfc_StartThread(void) { |
| NFCSTATUS wStartStatus = NFCSTATUS_SUCCESS; |
| void* h_threadsEvent = 0x00; |
| int pthread_create_status = 0; |
| |
| /* Create Reader and Writer threads */ |
| pthread_create_status = |
| pthread_create(&gpphTmlNfc_Context->readerThread, NULL, |
| &phTmlNfc_TmlThread, (void*)h_threadsEvent); |
| if (0 != pthread_create_status) { |
| wStartStatus = NFCSTATUS_FAILED; |
| } else { |
| /*Start Writer Thread*/ |
| pthread_create_status = |
| pthread_create(&gpphTmlNfc_Context->writerThread, NULL, |
| &phTmlNfc_TmlWriterThread, (void*)h_threadsEvent); |
| if (0 != pthread_create_status) { |
| wStartStatus = NFCSTATUS_FAILED; |
| } |
| } |
| |
| return wStartStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_ReTxTimerCb |
| ** |
| ** Description This is the timer callback function after timer expiration. |
| ** |
| ** Parameters dwThreadId - id of the thread posting message |
| ** pContext - context provided by upper layer |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext) { |
| if ((gpphTmlNfc_Context->dwTimerId == dwTimerId) && (NULL == pContext)) { |
| /* If Retry Count has reached its limit,Retransmit Nci |
| packet */ |
| if (0 == bCurrentRetryCount) { |
| /* Since the count has reached its limit,return from timer callback |
| Upper layer Timeout would have happened */ |
| } else { |
| bCurrentRetryCount--; |
| gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true; |
| gpphTmlNfc_Context->tWriteInfo.bEnable = 1; |
| } |
| sem_post(&gpphTmlNfc_Context->txSemaphore); |
| } |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_InitiateTimer |
| ** |
| ** Description Start a timer for Tx and Rx thread. |
| ** |
| ** Parameters void |
| ** |
| ** Returns NFC status |
| ** |
| *******************************************************************************/ |
| static NFCSTATUS phTmlNfc_InitiateTimer(void) { |
| NFCSTATUS wStatus = NFCSTATUS_SUCCESS; |
| |
| /* Start Timer once Nci packet is sent */ |
| wStatus = phOsalNfc_Timer_Start(gpphTmlNfc_Context->dwTimerId, |
| (uint32_t)PHTMLNFC_MAXTIME_RETRANSMIT, |
| phTmlNfc_ReTxTimerCb, NULL); |
| |
| return wStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_TmlThread |
| ** |
| ** Description Read the data from the lower layer driver |
| ** |
| ** Parameters pParam - parameters for Writer thread function |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| static void * phTmlNfc_TmlThread(void* pParam) { |
| NFCSTATUS wStatus = NFCSTATUS_SUCCESS; |
| int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; |
| uint8_t temp[260]; |
| uint8_t readRetryDelay = 0; |
| /* Transaction info buffer to be passed to Callback Thread */ |
| static phTmlNfc_TransactInfo_t tTransactionInfo; |
| /* Structure containing Tml callback function and parameters to be invoked |
| by the callback thread */ |
| static phLibNfc_DeferredCall_t tDeferredInfo; |
| /* Initialize Message structure to post message onto Callback Thread */ |
| static phLibNfc_Message_t tMsg; |
| UNUSED(pParam); |
| NXPLOG_TML_D("PN54X - Tml Reader Thread Started................\n"); |
| |
| /* Writer thread loop shall be running till shutdown is invoked */ |
| while (gpphTmlNfc_Context->bThreadDone) { |
| /* If Tml write is requested */ |
| /* Set the variable to success initially */ |
| wStatus = NFCSTATUS_SUCCESS; |
| sem_wait(&gpphTmlNfc_Context->rxSemaphore); |
| |
| /* If Tml read is requested */ |
| if (1 == gpphTmlNfc_Context->tReadInfo.bEnable) { |
| NXPLOG_TML_D("PN54X - Read requested.....\n"); |
| /* Set the variable to success initially */ |
| wStatus = NFCSTATUS_SUCCESS; |
| |
| /* Variable to fetch the actual number of bytes read */ |
| dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; |
| |
| /* Read the data from the file onto the buffer */ |
| if (NULL != gpphTmlNfc_Context->pDevHandle) { |
| NXPLOG_TML_D("PN54X - Invoking I2C Read.....\n"); |
| dwNoBytesWrRd = |
| phTmlNfc_i2c_read(gpphTmlNfc_Context->pDevHandle, temp, 260); |
| |
| if (-1 == dwNoBytesWrRd) { |
| NXPLOG_TML_E("PN54X - Error in I2C Read.....\n"); |
| if (readRetryDelay < MAX_READ_RETRY_DELAY_IN_MILLISEC) { |
| /*sleep for 30/60/90/120/150 msec between each read trial incase of read error*/ |
| readRetryDelay += 30 ; |
| } |
| usleep(readRetryDelay * 1000); |
| sem_post(&gpphTmlNfc_Context->rxSemaphore); |
| } else if (dwNoBytesWrRd > 260) { |
| NXPLOG_TML_E("Numer of bytes read exceeds the limit 260.....\n"); |
| readRetryDelay = 0; |
| sem_post(&gpphTmlNfc_Context->rxSemaphore); |
| } else { |
| pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex); |
| memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd); |
| readRetryDelay =0; |
| |
| NXPLOG_TML_D("PN54X - I2C Read successful.....\n"); |
| /* This has to be reset only after a successful read */ |
| gpphTmlNfc_Context->tReadInfo.bEnable = 0; |
| if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) && |
| (0x00 != (gpphTmlNfc_Context->tReadInfo.pBuffer[0] & 0xE0))) { |
| NXPLOG_TML_D("PN54X - Retransmission timer stopped.....\n"); |
| /* Stop Timer to prevent Retransmission */ |
| uint32_t timerStatus = |
| phOsalNfc_Timer_Stop(gpphTmlNfc_Context->dwTimerId); |
| if (NFCSTATUS_SUCCESS != timerStatus) { |
| NXPLOG_TML_E("PN54X - timer stopped returned failure.....\n"); |
| } else { |
| gpphTmlNfc_Context->bWriteCbInvoked = false; |
| } |
| } |
| if (gpphTmlNfc_Context->tWriteInfo.bThreadBusy) { |
| NXPLOG_TML_D("Delay Read if write thread is busy"); |
| usleep(2000); /*2ms delay to give prio to write complete */ |
| } |
| /* Update the actual number of bytes read including header */ |
| gpphTmlNfc_Context->tReadInfo.wLength = (uint16_t)(dwNoBytesWrRd); |
| phNxpNciHal_print_packet("RECV", |
| gpphTmlNfc_Context->tReadInfo.pBuffer, |
| gpphTmlNfc_Context->tReadInfo.wLength); |
| |
| dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; |
| |
| /* Fill the Transaction info structure to be passed to Callback |
| * Function */ |
| tTransactionInfo.wStatus = wStatus; |
| tTransactionInfo.pBuff = gpphTmlNfc_Context->tReadInfo.pBuffer; |
| /* Actual number of bytes read is filled in the structure */ |
| tTransactionInfo.wLength = gpphTmlNfc_Context->tReadInfo.wLength; |
| |
| /* Read operation completed successfully. Post a Message onto Callback |
| * Thread*/ |
| /* Prepare the message to be posted on User thread */ |
| tDeferredInfo.pCallback = &phTmlNfc_ReadDeferredCb; |
| tDeferredInfo.pParameter = &tTransactionInfo; |
| tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; |
| tMsg.pMsgData = &tDeferredInfo; |
| tMsg.Size = sizeof(tDeferredInfo); |
| pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex); |
| NXPLOG_TML_D("PN54X - Posting read message.....\n"); |
| phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg); |
| } |
| } else { |
| NXPLOG_TML_D("PN54X -gpphTmlNfc_Context->pDevHandle is NULL"); |
| } |
| } else { |
| NXPLOG_TML_D("PN54X - read request NOT enabled"); |
| usleep(10 * 1000); |
| } |
| } /* End of While loop */ |
| |
| return NULL; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_TmlWriterThread |
| ** |
| ** Description Writes the requested data onto the lower layer driver |
| ** |
| ** Parameters pParam - context provided by upper layer |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| static void * phTmlNfc_TmlWriterThread(void* pParam) { |
| NFCSTATUS wStatus = NFCSTATUS_SUCCESS; |
| int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; |
| /* Transaction info buffer to be passed to Callback Thread */ |
| static phTmlNfc_TransactInfo_t tTransactionInfo; |
| /* Structure containing Tml callback function and parameters to be invoked |
| by the callback thread */ |
| static phLibNfc_DeferredCall_t tDeferredInfo; |
| /* Initialize Message structure to post message onto Callback Thread */ |
| static phLibNfc_Message_t tMsg; |
| /* In case of I2C Write Retry */ |
| static uint16_t retry_cnt; |
| UNUSED(pParam); |
| NXPLOG_TML_D("PN54X - Tml Writer Thread Started................\n"); |
| |
| /* Writer thread loop shall be running till shutdown is invoked */ |
| while (gpphTmlNfc_Context->bThreadDone) { |
| NXPLOG_TML_D("PN54X - Tml Writer Thread Running................\n"); |
| sem_wait(&gpphTmlNfc_Context->txSemaphore); |
| /* If Tml write is requested */ |
| if (1 == gpphTmlNfc_Context->tWriteInfo.bEnable) { |
| NXPLOG_TML_D("PN54X - Write requested.....\n"); |
| /* Set the variable to success initially */ |
| wStatus = NFCSTATUS_SUCCESS; |
| if (NULL != gpphTmlNfc_Context->pDevHandle) { |
| retry: |
| gpphTmlNfc_Context->tWriteInfo.bEnable = 0; |
| /* Variable to fetch the actual number of bytes written */ |
| dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; |
| /* Write the data in the buffer onto the file */ |
| NXPLOG_TML_D("PN54X - Invoking I2C Write.....\n"); |
| dwNoBytesWrRd = |
| phTmlNfc_i2c_write(gpphTmlNfc_Context->pDevHandle, |
| gpphTmlNfc_Context->tWriteInfo.pBuffer, |
| gpphTmlNfc_Context->tWriteInfo.wLength); |
| |
| /* Try I2C Write Five Times, if it fails : Raju */ |
| if (-1 == dwNoBytesWrRd) { |
| if (getDownloadFlag() == true) { |
| if (retry_cnt++ < MAX_WRITE_RETRY_COUNT) { |
| NXPLOG_TML_D("PN54X - Error in I2C Write - Retry 0x%x", |
| retry_cnt); |
| // Add a 10 ms delay to ensure NFCC is not still in stand by mode. |
| usleep(10 * 1000); |
| goto retry; |
| } |
| } |
| NXPLOG_TML_D("PN54X - Error in I2C Write.....\n"); |
| wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); |
| } else { |
| phNxpNciHal_print_packet("SEND", |
| gpphTmlNfc_Context->tWriteInfo.pBuffer, |
| gpphTmlNfc_Context->tWriteInfo.wLength); |
| } |
| retry_cnt = 0; |
| if (NFCSTATUS_SUCCESS == wStatus) { |
| NXPLOG_TML_D("PN54X - I2C Write successful.....\n"); |
| dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE; |
| } |
| /* Fill the Transaction info structure to be passed to Callback Function |
| */ |
| tTransactionInfo.wStatus = wStatus; |
| tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer; |
| /* Actual number of bytes written is filled in the structure */ |
| tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd; |
| |
| /* Prepare the message to be posted on the User thread */ |
| tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb; |
| tDeferredInfo.pParameter = &tTransactionInfo; |
| /* Write operation completed successfully. Post a Message onto Callback |
| * Thread*/ |
| tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; |
| tMsg.pMsgData = &tDeferredInfo; |
| tMsg.Size = sizeof(tDeferredInfo); |
| |
| /* Check whether Retransmission needs to be started, |
| * If yes, Post message only if |
| * case 1. Message is not posted && |
| * case 11. Write status is success || |
| * case 12. Last retry of write is also failure |
| */ |
| if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) && |
| (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) { |
| if (gpphTmlNfc_Context->bWriteCbInvoked == false) { |
| if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) { |
| NXPLOG_TML_D("PN54X - Posting Write message.....\n"); |
| phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, |
| &tMsg); |
| gpphTmlNfc_Context->bWriteCbInvoked = true; |
| } |
| } |
| } else { |
| NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n"); |
| phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg); |
| } |
| } else { |
| NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL"); |
| } |
| |
| /* If Data packet is sent, then NO retransmission */ |
| if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) && |
| (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) { |
| NXPLOG_TML_D("PN54X - Starting timer for Retransmission case"); |
| wStatus = phTmlNfc_InitiateTimer(); |
| if (NFCSTATUS_SUCCESS != wStatus) { |
| /* Reset Variables used for Retransmission */ |
| NXPLOG_TML_D("PN54X - Retransmission timer initiate failed"); |
| gpphTmlNfc_Context->tWriteInfo.bEnable = 0; |
| bCurrentRetryCount = 0; |
| } |
| } |
| } else { |
| NXPLOG_TML_D("PN54X - Write request NOT enabled"); |
| usleep(10000); |
| } |
| |
| } /* End of While loop */ |
| |
| return NULL; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_CleanUp |
| ** |
| ** Description Clears all handles opened during TML initialization |
| ** |
| ** Parameters None |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void phTmlNfc_CleanUp(void) { |
| if (NULL == gpphTmlNfc_Context) { |
| return; |
| } |
| if (NULL != gpphTmlNfc_Context->pDevHandle) { |
| (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0); |
| gpphTmlNfc_Context->bThreadDone = 0; |
| } |
| sem_destroy(&gpphTmlNfc_Context->rxSemaphore); |
| sem_destroy(&gpphTmlNfc_Context->txSemaphore); |
| sem_destroy(&gpphTmlNfc_Context->postMsgSemaphore); |
| phTmlNfc_i2c_close(gpphTmlNfc_Context->pDevHandle); |
| gpphTmlNfc_Context->pDevHandle = NULL; |
| /* Clear memory allocated for storing Context variables */ |
| free((void*)gpphTmlNfc_Context); |
| /* Set the pointer to NULL to indicate De-Initialization */ |
| gpphTmlNfc_Context = NULL; |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_Shutdown |
| ** |
| ** Description Uninitializes TML layer and hardware interface |
| ** |
| ** Parameters None |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - TML configuration released successfully |
| ** NFCSTATUS_INVALID_PARAMETER - at least one parameter is |
| ** invalid |
| ** NFCSTATUS_FAILED - un-initialization failed (example: unable |
| ** to close interface) |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_Shutdown(void) { |
| NFCSTATUS wShutdownStatus = NFCSTATUS_SUCCESS; |
| |
| /* Check whether TML is Initialized */ |
| if (NULL != gpphTmlNfc_Context) { |
| /* Reset thread variable to terminate the thread */ |
| gpphTmlNfc_Context->bThreadDone = 0; |
| usleep(1000); |
| /* Clear All the resources allocated during initialization */ |
| sem_post(&gpphTmlNfc_Context->rxSemaphore); |
| usleep(1000); |
| sem_post(&gpphTmlNfc_Context->txSemaphore); |
| usleep(1000); |
| sem_post(&gpphTmlNfc_Context->postMsgSemaphore); |
| usleep(1000); |
| sem_post(&gpphTmlNfc_Context->postMsgSemaphore); |
| usleep(1000); |
| pthread_mutex_destroy(&gpphTmlNfc_Context->readInfoUpdateMutex); |
| if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) { |
| NXPLOG_TML_E("Fail to kill reader thread!"); |
| } |
| if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) { |
| NXPLOG_TML_E("Fail to kill writer thread!"); |
| } |
| NXPLOG_TML_D("bThreadDone == 0"); |
| |
| } else { |
| wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED); |
| } |
| |
| return wShutdownStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_Write |
| ** |
| ** Description Asynchronously writes given data block to hardware |
| ** interface/driver. Enables writer thread if there are no |
| ** write requests pending. Returns successfully once writer |
| ** thread completes write operation. Notifies upper layer using |
| ** callback mechanism. |
| ** |
| ** NOTE: |
| ** * it is important to post a message with id |
| ** PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data |
| ** has been written to PN54X |
| ** * if CRC needs to be computed, then input buffer should be |
| ** capable to store two more bytes apart from length of |
| ** packet |
| ** |
| ** Parameters pBuffer - data to be sent |
| ** wLength - length of data buffer |
| ** pTmlWriteComplete - pointer to the function to be invoked |
| ** upon completion |
| ** pContext - context provided by upper layer |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_PENDING - command is yet to be processed |
| ** NFCSTATUS_INVALID_PARAMETER - at least one parameter is |
| ** invalid |
| ** NFCSTATUS_BUSY - write request is already in progress |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength, |
| pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete, |
| void* pContext) { |
| NFCSTATUS wWriteStatus; |
| |
| /* Check whether TML is Initialized */ |
| |
| if (NULL != gpphTmlNfc_Context) { |
| if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) && |
| (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) { |
| if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) { |
| /* Setting the flag marks beginning of a Write Operation */ |
| gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true; |
| /* Copy the buffer, length and Callback function, |
| This shall be utilized while invoking the Callback function in thread |
| */ |
| gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer; |
| gpphTmlNfc_Context->tWriteInfo.wLength = wLength; |
| gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete; |
| gpphTmlNfc_Context->tWriteInfo.pContext = pContext; |
| |
| wWriteStatus = NFCSTATUS_PENDING; |
| // FIXME: If retry is going on. Stop the retry thread/timer |
| if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) { |
| /* Set retry count to default value */ |
| // FIXME: If the timer expired there, and meanwhile we have created |
| // a new request. The expired timer will think that retry is still |
| // ongoing. |
| bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount; |
| gpphTmlNfc_Context->bWriteCbInvoked = false; |
| } |
| /* Set event to invoke Writer Thread */ |
| gpphTmlNfc_Context->tWriteInfo.bEnable = 1; |
| sem_post(&gpphTmlNfc_Context->txSemaphore); |
| } else { |
| wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY); |
| } |
| } else { |
| wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER); |
| } |
| } else { |
| wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED); |
| } |
| |
| return wWriteStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_UpdateReadCompleteCallback |
| ** |
| ** Description Updates the callback to be invoked after read completed |
| ** |
| ** Parameters pTmlReadComplete - pointer to the function to be invoked |
| ** upon completion of read operation |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - if TmlNfc context available |
| ** NFCSTATUS_FAILED - otherwise |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_UpdateReadCompleteCallback ( |
| pphTmlNfc_TransactCompletionCb_t pTmlReadComplete) { |
| NFCSTATUS wStatus = NFCSTATUS_FAILED; |
| if ((NULL != gpphTmlNfc_Context) && (NULL != pTmlReadComplete)) { |
| gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete; |
| wStatus = NFCSTATUS_SUCCESS; |
| } |
| return wStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_Read |
| ** |
| ** Description Asynchronously reads data from the driver |
| ** Number of bytes to be read and buffer are passed by upper |
| ** layer. |
| ** Enables reader thread if there are no read requests pending |
| ** Returns successfully once read operation is completed |
| ** Notifies upper layer using callback mechanism |
| ** |
| ** Parameters pBuffer - location to send read data to the upper layer via |
| ** callback |
| ** wLength - length of read data buffer passed by upper layer |
| ** pTmlReadComplete - pointer to the function to be invoked |
| ** upon completion of read operation |
| ** pContext - context provided by upper layer |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_PENDING - command is yet to be processed |
| ** NFCSTATUS_INVALID_PARAMETER - at least one parameter is |
| ** invalid |
| ** NFCSTATUS_BUSY - read request is already in progress |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength, |
| pphTmlNfc_TransactCompletionCb_t pTmlReadComplete, |
| void* pContext) { |
| NFCSTATUS wReadStatus; |
| |
| /* Check whether TML is Initialized */ |
| if (NULL != gpphTmlNfc_Context) { |
| if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) && |
| (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) { |
| if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) { |
| pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex); |
| /* Setting the flag marks beginning of a Read Operation */ |
| gpphTmlNfc_Context->tReadInfo.bThreadBusy = true; |
| /* Copy the buffer, length and Callback function, |
| This shall be utilized while invoking the Callback function in thread |
| */ |
| gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer; |
| gpphTmlNfc_Context->tReadInfo.wLength = wLength; |
| gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete; |
| gpphTmlNfc_Context->tReadInfo.pContext = pContext; |
| wReadStatus = NFCSTATUS_PENDING; |
| |
| /* Set event to invoke Reader Thread */ |
| gpphTmlNfc_Context->tReadInfo.bEnable = 1; |
| pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex); |
| |
| sem_post(&gpphTmlNfc_Context->rxSemaphore); |
| } else { |
| wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY); |
| } |
| } else { |
| wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER); |
| } |
| } else { |
| wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED); |
| } |
| |
| return wReadStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_ReadAbort |
| ** |
| ** Description Aborts pending read request (if any) |
| ** |
| ** Parameters None |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - ongoing read operation aborted |
| ** NFCSTATUS_INVALID_PARAMETER - at least one parameter is |
| ** invalid |
| ** NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized |
| ** NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read |
| ** operation |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_ReadAbort(void) { |
| NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER; |
| gpphTmlNfc_Context->tReadInfo.bEnable = 0; |
| |
| /*Reset the flag to accept another Read Request */ |
| gpphTmlNfc_Context->tReadInfo.bThreadBusy = false; |
| wStatus = NFCSTATUS_SUCCESS; |
| |
| return wStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_WriteAbort |
| ** |
| ** Description Aborts pending write request (if any) |
| ** |
| ** Parameters None |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - ongoing write operation aborted |
| ** NFCSTATUS_INVALID_PARAMETER - at least one parameter is |
| ** invalid |
| ** NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized |
| ** NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel write |
| ** operation |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_WriteAbort(void) { |
| NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER; |
| |
| gpphTmlNfc_Context->tWriteInfo.bEnable = 0; |
| /* Stop if any retransmission is in progress */ |
| bCurrentRetryCount = 0; |
| |
| /* Reset the flag to accept another Write Request */ |
| gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false; |
| wStatus = NFCSTATUS_SUCCESS; |
| |
| return wStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_IoCtl |
| ** |
| ** Description Resets device when insisted by upper layer |
| ** Number of bytes to be read and buffer are passed by upper |
| ** layer |
| ** Enables reader thread if there are no read requests pending |
| ** Returns successfully once read operation is completed |
| ** Notifies upper layer using callback mechanism |
| ** |
| ** Parameters eControlCode - control code for a specific operation |
| ** |
| ** Returns NFC status: |
| ** NFCSTATUS_SUCCESS - ioctl command completed successfully |
| ** NFCSTATUS_FAILED - ioctl command request failed |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) { |
| NFCSTATUS wStatus = NFCSTATUS_SUCCESS; |
| |
| if (NULL == gpphTmlNfc_Context) { |
| wStatus = NFCSTATUS_FAILED; |
| } else { |
| switch (eControlCode) { |
| case phTmlNfc_e_ResetDevice: { |
| /*Reset PN54X*/ |
| phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1); |
| usleep(100 * 1000); |
| phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0); |
| usleep(100 * 1000); |
| phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1); |
| break; |
| } |
| case phTmlNfc_e_EnableNormalMode: { |
| /*Reset PN54X*/ |
| phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0); |
| usleep(10 * 1000); |
| phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1); |
| usleep(100 * 1000); |
| break; |
| } |
| case phTmlNfc_e_EnableDownloadMode: { |
| phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0); |
| (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2); |
| usleep(100 * 1000); |
| break; |
| } |
| default: { |
| wStatus = NFCSTATUS_INVALID_PARAMETER; |
| break; |
| } |
| } |
| } |
| |
| return wStatus; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_DeferredCall |
| ** |
| ** Description Posts message on upper layer thread |
| ** upon successful read or write operation |
| ** |
| ** Parameters dwThreadId - id of the thread posting message |
| ** ptWorkerMsg - message to be posted |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void phTmlNfc_DeferredCall(uintptr_t dwThreadId, |
| phLibNfc_Message_t* ptWorkerMsg) { |
| intptr_t bPostStatus; |
| UNUSED(dwThreadId); |
| /* Post message on the user thread to invoke the callback function */ |
| sem_wait(&gpphTmlNfc_Context->postMsgSemaphore); |
| bPostStatus = |
| phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0); |
| sem_post(&gpphTmlNfc_Context->postMsgSemaphore); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_ReadDeferredCb |
| ** |
| ** Description Read thread call back function |
| ** |
| ** Parameters pParams - context provided by upper layer |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| static void phTmlNfc_ReadDeferredCb(void* pParams) { |
| /* Transaction info buffer to be passed to Callback Function */ |
| phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams; |
| |
| /* Reset the flag to accept another Read Request */ |
| gpphTmlNfc_Context->tReadInfo.bThreadBusy = false; |
| gpphTmlNfc_Context->tReadInfo.pThread_Callback( |
| gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo); |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_WriteDeferredCb |
| ** |
| ** Description Write thread call back function |
| ** |
| ** Parameters pParams - context provided by upper layer |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| static void phTmlNfc_WriteDeferredCb(void* pParams) { |
| /* Transaction info buffer to be passed to Callback Function */ |
| phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams; |
| |
| /* Reset the flag to accept another Write Request */ |
| gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false; |
| gpphTmlNfc_Context->tWriteInfo.pThread_Callback( |
| gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo); |
| |
| return; |
| } |
| |
| void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) { |
| fragmentation_enabled = result; |
| } |
| |
| phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() { |
| return fragmentation_enabled; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function phTmlNfc_Shutdown_CleanUp |
| ** |
| ** Description wrapper function for shutdown and cleanup of resources |
| ** |
| ** Parameters None |
| ** |
| ** Returns NFCSTATUS |
| ** |
| *******************************************************************************/ |
| NFCSTATUS phTmlNfc_Shutdown_CleanUp() { |
| NFCSTATUS wShutdownStatus = phTmlNfc_Shutdown(); |
| phTmlNfc_CleanUp(); |
| return wShutdownStatus; |
| } |