/*
* 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
/* 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_CleanUp(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];
/* 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");
sem_post(&gpphTmlNfc_Context->rxSemaphore);
} else if (dwNoBytesWrRd > 260) {
NXPLOG_TML_E("Numer of bytes read exceeds the limit 260.....\n");
sem_post(&gpphTmlNfc_Context->rxSemaphore);
} else {
pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd);
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_NCIHAL_E("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_E("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
**
*******************************************************************************/
static 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");
phTmlNfc_CleanUp();
} 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;
}