C++程序  |  1028行  |  39.79 KB

/*
 * 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 <phTmlNfc.h>
#include <phOsalNfc_Timer.h>
#include <phNxpLog.h>
#include <phDal4Nfc_messageQueueLib.h>
#include <phTmlNfc_i2c.h>
#include <phNxpNciHal_utils.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;
phTmlNfc_i2cfragmentation_t fragmentation_enabled = I2C_FRAGMENATATION_DISABLED;
/* 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 = 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(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;
    uint32_t dwEvent;
    int pthread_create_status = 0;

    /* Create Reader and Writer threads */
    pthread_create_status = pthread_create(&gpphTmlNfc_Context->readerThread,NULL,(void *)&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,(void *)&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
                {
                    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);
                    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;
}

/*******************************************************************************
**
** 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);
                            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 (FALSE == gpphTmlNfc_Context->bWriteCbInvoked)
                    {
                        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;
}

/*******************************************************************************
**
** Function         phTmlNfc_CleanUp
**
** Description      Clears all handles opened during TML initialization
**
** Parameters       None
**
** Returns          None
**
*******************************************************************************/
static void phTmlNfc_CleanUp(void)
{
    NFCSTATUS wRetval = NFCSTATUS_SUCCESS;

    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);
        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_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)
            {
                /* 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;
                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;
}